package geospatial import ( "math" "testing" ) func TestCalculateBearing(t *testing.T) { calc := NewBearingCalculator(DefaultConfig()) tests := []struct { name string from Point to Point wantBearing float64 tolerance float64 }{ { name: "North", from: Point{Latitude: 52.5200, Longitude: 13.4050}, to: Point{Latitude: 52.5300, Longitude: 13.4050}, wantBearing: 0.0, // North tolerance: 5.0, }, { name: "East", from: Point{Latitude: 52.5200, Longitude: 13.4050}, to: Point{Latitude: 52.5200, Longitude: 13.4150}, wantBearing: 90.0, // East tolerance: 5.0, }, { name: "South", from: Point{Latitude: 52.5200, Longitude: 13.4050}, to: Point{Latitude: 52.5100, Longitude: 13.4050}, wantBearing: 180.0, // South tolerance: 5.0, }, { name: "West", from: Point{Latitude: 52.5200, Longitude: 13.4050}, to: Point{Latitude: 52.5200, Longitude: 13.3950}, wantBearing: 270.0, // West tolerance: 5.0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := calc.CalculateBearing(tt.from, tt.to) if err != nil { t.Fatalf("CalculateBearing() error = %v", err) } // Normalize bearing difference diff := math.Abs(got - tt.wantBearing) if diff > 180 { diff = 360 - diff } if diff > tt.tolerance { t.Errorf("CalculateBearing() = %v, want %v (tolerance: %v)", got, tt.wantBearing, tt.tolerance) } }) } } func TestCalculateBearingRadians(t *testing.T) { calc := NewBearingCalculator(DefaultConfig()) from := Point{Latitude: 52.5200, Longitude: 13.4050} to := Point{Latitude: 52.5300, Longitude: 13.4150} gotRad, err := calc.CalculateBearingRadians(from, to) if err != nil { t.Fatalf("CalculateBearingRadians() error = %v", err) } gotDeg, err := calc.CalculateBearing(from, to) if err != nil { t.Fatalf("CalculateBearing() error = %v", err) } expectedRad := gotDeg * math.Pi / 180 if math.Abs(gotRad-expectedRad) > 0.01 { t.Errorf("CalculateBearingRadians() = %v, expected %v (from degrees)", gotRad, expectedRad) } } func TestCalculateMidpoint(t *testing.T) { calc := NewBearingCalculator(DefaultConfig()) tests := []struct { name string p1 Point p2 Point wantLat float64 wantLon float64 tolerance float64 }{ { name: "Simple midpoint", p1: Point{Latitude: 50.0, Longitude: 10.0}, p2: Point{Latitude: 52.0, Longitude: 12.0}, wantLat: 51.0, wantLon: 11.0, tolerance: 0.1, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := calc.CalculateMidpoint(tt.p1, tt.p2) if err != nil { t.Fatalf("CalculateMidpoint() error = %v", err) } if math.Abs(got.Latitude-tt.wantLat) > tt.tolerance { t.Errorf("CalculateMidpoint() Latitude = %v, want %v", got.Latitude, tt.wantLat) } if math.Abs(got.Longitude-tt.wantLon) > tt.tolerance { t.Errorf("CalculateMidpoint() Longitude = %v, want %v", got.Longitude, tt.wantLon) } }) } } func TestCalculateDestination(t *testing.T) { calc := NewBearingCalculator(DefaultConfig()) origin := Point{Latitude: 52.5200, Longitude: 13.4050} bearing := 45.0 // Northeast distance := 10.0 // 10 km dest, err := calc.CalculateDestination(origin, bearing, distance) if err != nil { t.Fatalf("CalculateDestination() error = %v", err) } // Verify the destination is approximately northeast of origin if dest.Latitude <= origin.Latitude { t.Error("CalculateDestination() destination should be north of origin") } if dest.Longitude <= origin.Longitude { t.Error("CalculateDestination() destination should be east of origin") } // Verify distance is approximately correct distCalc := NewDistanceCalculator(DefaultConfig()) actualDist, err := distCalc.HaversineDistance(origin, dest) if err != nil { t.Fatalf("HaversineDistance() error = %v", err) } if math.Abs(actualDist-distance) > 0.5 { t.Errorf("CalculateDestination() distance = %v, want %v", actualDist, distance) } }