vehicle-routing-python / tests /test_haversine.py
blackopsrepl's picture
Upload 36 files
08e15f1 verified
"""
Unit tests for the Haversine driving time calculator in Location class.
These tests verify that the driving time calculations correctly implement
the Haversine formula for great-circle distance on Earth.
"""
from vehicle_routing.domain import Location
class TestHaversineDrivingTime:
"""Tests for Location.driving_time_to() using Haversine formula."""
def test_same_location_returns_zero(self):
"""Same location should return 0 driving time."""
loc = Location(latitude=40.0, longitude=-75.0)
assert loc.driving_time_to(loc) == 0
def test_same_coordinates_returns_zero(self):
"""Two locations with same coordinates should return 0."""
loc1 = Location(latitude=40.0, longitude=-75.0)
loc2 = Location(latitude=40.0, longitude=-75.0)
assert loc1.driving_time_to(loc2) == 0
def test_symmetric_distance(self):
"""Distance from A to B should equal distance from B to A."""
loc1 = Location(latitude=0, longitude=0)
loc2 = Location(latitude=3, longitude=4)
assert loc1.driving_time_to(loc2) == loc2.driving_time_to(loc1)
def test_equator_one_degree_longitude(self):
"""
One degree of longitude at the equator is approximately 111.32 km.
At 50 km/h, this should take about 2.2 hours = 7920 seconds.
"""
loc1 = Location(latitude=0, longitude=0)
loc2 = Location(latitude=0, longitude=1)
driving_time = loc1.driving_time_to(loc2)
# Allow 5% tolerance for rounding
assert 7500 < driving_time < 8500, f"Expected ~8000, got {driving_time}"
def test_equator_one_degree_latitude(self):
"""
One degree of latitude is approximately 111.32 km everywhere.
At 50 km/h, this should take about 2.2 hours = 7920 seconds.
"""
loc1 = Location(latitude=0, longitude=0)
loc2 = Location(latitude=1, longitude=0)
driving_time = loc1.driving_time_to(loc2)
# Allow 5% tolerance for rounding
assert 7500 < driving_time < 8500, f"Expected ~8000, got {driving_time}"
def test_realistic_us_cities(self):
"""
Test driving time between realistic US city coordinates.
Philadelphia (39.95, -75.17) to New York (40.71, -74.01)
Distance is approximately 130 km, should take ~2.6 hours at 50 km/h.
"""
philadelphia = Location(latitude=39.95, longitude=-75.17)
new_york = Location(latitude=40.71, longitude=-74.01)
driving_time = philadelphia.driving_time_to(new_york)
# Expected: ~130 km / 50 km/h * 3600 = ~9360 seconds
# Allow reasonable tolerance
assert 8500 < driving_time < 10500, f"Expected ~9400, got {driving_time}"
def test_longer_distance(self):
"""
Test longer distance: Philadelphia to Hartford.
Distance is approximately 290 km.
"""
philadelphia = Location(latitude=39.95, longitude=-75.17)
hartford = Location(latitude=41.76, longitude=-72.68)
driving_time = philadelphia.driving_time_to(hartford)
# Expected: ~290 km / 50 km/h * 3600 = ~20880 seconds
# Allow reasonable tolerance
assert 19000 < driving_time < 23000, f"Expected ~21000, got {driving_time}"
def test_known_values_from_test_data(self):
"""
Verify the exact values used in constraint tests.
These values are calculated using the Haversine formula.
"""
LOCATION_1 = Location(latitude=0, longitude=0)
LOCATION_2 = Location(latitude=3, longitude=4)
LOCATION_3 = Location(latitude=-1, longitude=1)
# These exact values are used in test_constraints.py
assert LOCATION_1.driving_time_to(LOCATION_2) == 40018
assert LOCATION_2.driving_time_to(LOCATION_3) == 40025
assert LOCATION_1.driving_time_to(LOCATION_3) == 11322
def test_negative_coordinates(self):
"""Test with negative latitude and longitude (Southern/Western hemisphere)."""
loc1 = Location(latitude=-33.87, longitude=151.21) # Sydney
loc2 = Location(latitude=-37.81, longitude=144.96) # Melbourne
driving_time = loc1.driving_time_to(loc2)
# Distance is approximately 714 km
# Expected: ~714 km / 50 km/h * 3600 = ~51408 seconds
assert 48000 < driving_time < 55000, f"Expected ~51400, got {driving_time}"
def test_cross_hemisphere(self):
"""Test crossing equator."""
loc1 = Location(latitude=10, longitude=0)
loc2 = Location(latitude=-10, longitude=0)
driving_time = loc1.driving_time_to(loc2)
# 20 degrees of latitude = ~2226 km
# Expected: ~2226 km / 50 km/h * 3600 = ~160272 seconds
assert 155000 < driving_time < 165000, f"Expected ~160000, got {driving_time}"
def test_cross_antimeridian(self):
"""Test crossing the antimeridian (date line)."""
loc1 = Location(latitude=0, longitude=179)
loc2 = Location(latitude=0, longitude=-179)
driving_time = loc1.driving_time_to(loc2)
# 2 degrees at equator = ~222 km
# Expected: ~222 km / 50 km/h * 3600 = ~15984 seconds
assert 15000 < driving_time < 17000, f"Expected ~16000, got {driving_time}"
class TestHaversineInternalMethods:
"""Tests for internal Haversine calculation methods."""
def test_to_cartesian_equator_prime_meridian(self):
"""Test Cartesian conversion at equator/prime meridian intersection."""
loc = Location(latitude=0, longitude=0)
x, y, z = loc._to_cartesian()
# At (0, 0): x=0, y=0.5, z=0
assert abs(x - 0) < 0.001
assert abs(y - 0.5) < 0.001
assert abs(z - 0) < 0.001
def test_to_cartesian_north_pole(self):
"""Test Cartesian conversion at North Pole."""
loc = Location(latitude=90, longitude=0)
x, y, z = loc._to_cartesian()
# At North Pole: x=0, y=0, z=0.5
assert abs(x - 0) < 0.001
assert abs(y - 0) < 0.001
assert abs(z - 0.5) < 0.001
def test_meters_to_driving_seconds(self):
"""Test conversion from meters to driving seconds."""
# 50 km = 50000 m should take 1 hour = 3600 seconds at 50 km/h
seconds = Location._meters_to_driving_seconds(50000)
assert seconds == 3600
def test_meters_to_driving_seconds_zero(self):
"""Zero meters should return zero seconds."""
assert Location._meters_to_driving_seconds(0) == 0
def test_meters_to_driving_seconds_small(self):
"""Test small distances."""
# 1 km = 1000 m should take 72 seconds at 50 km/h
seconds = Location._meters_to_driving_seconds(1000)
assert seconds == 72