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) } }) } }