turash/bugulma/backend/internal/geospatial/distance_calculator_test.go
Damir Mukimov 000eab4740
Major repository reorganization and missing backend endpoints implementation
Repository Structure:
- Move files from cluttered root directory into organized structure
- Create archive/ for archived data and scraper results
- Create bugulma/ for the complete application (frontend + backend)
- Create data/ for sample datasets and reference materials
- Create docs/ for comprehensive documentation structure
- Create scripts/ for utility scripts and API tools

Backend Implementation:
- Implement 3 missing backend endpoints identified in gap analysis:
  * GET /api/v1/organizations/{id}/matching/direct - Direct symbiosis matches
  * GET /api/v1/users/me/organizations - User organizations
  * POST /api/v1/proposals/{id}/status - Update proposal status
- Add complete proposal domain model, repository, and service layers
- Create database migration for proposals table
- Fix CLI server command registration issue

API Documentation:
- Add comprehensive proposals.md API documentation
- Update README.md with Users and Proposals API sections
- Document all request/response formats, error codes, and business rules

Code Quality:
- Follow existing Go backend architecture patterns
- Add proper error handling and validation
- Match frontend expected response schemas
- Maintain clean separation of concerns (handler -> service -> repository)
2025-11-25 06:01:16 +01:00

181 lines
4.5 KiB
Go

package geospatial
import (
"math"
"testing"
)
func TestHaversineDistance(t *testing.T) {
calc := NewDistanceCalculator(DefaultConfig())
tests := []struct {
name string
p1 Point
p2 Point
wantDist float64
tolerance float64
}{
{
name: "Same point",
p1: Point{Latitude: 52.5200, Longitude: 13.4050}, // Berlin
p2: Point{Latitude: 52.5200, Longitude: 13.4050},
wantDist: 0.0,
tolerance: 0.001,
},
{
name: "Berlin to Munich",
p1: Point{Latitude: 52.5200, Longitude: 13.4050}, // Berlin
p2: Point{Latitude: 48.1351, Longitude: 11.5820}, // Munich
wantDist: 504.0, // Approximately 504 km
tolerance: 5.0,
},
{
name: "Short distance",
p1: Point{Latitude: 52.5200, Longitude: 13.4050},
p2: Point{Latitude: 52.5300, Longitude: 13.4150},
wantDist: 1.3, // Approximately 1.3 km
tolerance: 0.1,
},
{
name: "Cross equator",
p1: Point{Latitude: 10.0, Longitude: 0.0},
p2: Point{Latitude: -10.0, Longitude: 0.0},
wantDist: 2220.0, // Approximately 2220 km
tolerance: 10.0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := calc.HaversineDistance(tt.p1, tt.p2)
if err != nil {
t.Fatalf("HaversineDistance() error = %v", err)
}
if math.Abs(got-tt.wantDist) > tt.tolerance {
t.Errorf("HaversineDistance() = %v, want %v (tolerance: %v)", got, tt.wantDist, tt.tolerance)
}
})
}
}
func TestHaversineDistance_InvalidPoints(t *testing.T) {
calc := NewDistanceCalculator(DefaultConfig())
tests := []struct {
name string
p1 Point
p2 Point
}{
{
name: "Invalid latitude - too high",
p1: Point{Latitude: 91.0, Longitude: 0.0},
p2: Point{Latitude: 52.5200, Longitude: 13.4050},
},
{
name: "Invalid latitude - too low",
p1: Point{Latitude: -91.0, Longitude: 0.0},
p2: Point{Latitude: 52.5200, Longitude: 13.4050},
},
{
name: "Invalid longitude - too high",
p1: Point{Latitude: 52.5200, Longitude: 181.0},
p2: Point{Latitude: 52.5200, Longitude: 13.4050},
},
{
name: "Invalid longitude - too low",
p1: Point{Latitude: 52.5200, Longitude: -181.0},
p2: Point{Latitude: 52.5200, Longitude: 13.4050},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := calc.HaversineDistance(tt.p1, tt.p2)
if err == nil {
t.Error("HaversineDistance() expected error for invalid point")
}
})
}
}
func TestVincentyDistance(t *testing.T) {
config := DefaultConfig()
config.UseEllipsoidalModel = true
calc := NewDistanceCalculator(config)
tests := []struct {
name string
p1 Point
p2 Point
wantDist float64
tolerance float64
}{
{
name: "Same point",
p1: Point{Latitude: 52.5200, Longitude: 13.4050},
p2: Point{Latitude: 52.5200, Longitude: 13.4050},
wantDist: 0.0,
tolerance: 0.001,
},
{
name: "Berlin to Munich",
p1: Point{Latitude: 52.5200, Longitude: 13.4050}, // Berlin
p2: Point{Latitude: 48.1351, Longitude: 11.5820}, // Munich
wantDist: 504.0, // Approximately 504 km
tolerance: 5.0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := calc.VincentyDistance(tt.p1, tt.p2)
if err != nil {
t.Fatalf("VincentyDistance() error = %v", err)
}
if math.Abs(got-tt.wantDist) > tt.tolerance {
t.Errorf("VincentyDistance() = %v, want %v (tolerance: %v)", got, tt.wantDist, tt.tolerance)
}
})
}
}
func TestCalculateDistance(t *testing.T) {
tests := []struct {
name string
method string
p1 Point
p2 Point
wantDist float64
tolerance float64
}{
{
name: "Haversine method",
method: "haversine",
p1: Point{Latitude: 52.5200, Longitude: 13.4050},
p2: Point{Latitude: 52.5300, Longitude: 13.4150},
wantDist: 1.3,
tolerance: 0.1,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config := DefaultConfig()
config.DefaultDistanceMethod = tt.method
calc := NewDistanceCalculator(config)
impl := calc.(*DistanceCalculatorImpl)
got, err := impl.CalculateDistance(tt.p1, tt.p2)
if err != nil {
t.Fatalf("CalculateDistance() error = %v", err)
}
if math.Abs(got-tt.wantDist) > tt.tolerance {
t.Errorf("CalculateDistance() = %v, want %v (tolerance: %v)", got, tt.wantDist, tt.tolerance)
}
})
}
}