CoolFace
Apppublic

blackopsrepl/vehicle-routing-python

sourceHugging Faceapache-2.0updated 9mo agoView on Hugging Face
2likes
test_timeline_fields.py216 linesDownload Raw Back to tests
1"""2Tests for timeline visualization fields in API serialization.3 4These tests verify that all fields required by the frontend timeline5visualizations (By vehicle, By visit tabs) are correctly serialized.6"""7from datetime import datetime, timedelta8from vehicle_routing.domain import (9    Location,10    Visit,11    Vehicle,12    VehicleRoutePlan,13)14from vehicle_routing.converters import (15    visit_to_model,16    vehicle_to_model,17    plan_to_model,18)19 20 21def create_test_location(lat: float = 43.77, lng: float = 11.25) -> Location:22    """Create a test location."""23    return Location(latitude=lat, longitude=lng)24 25 26def create_test_vehicle(27    departure_time: datetime = None,28    visits: list = None,29) -> Vehicle:30    """Create a test vehicle with optional visits."""31    if departure_time is None:32        departure_time = datetime(2024, 1, 1, 6, 0, 0)33    return Vehicle(34        id="1",35        name="Alpha",36        capacity=25,37        home_location=create_test_location(),38        departure_time=departure_time,39        visits=visits or [],40    )41 42 43def create_test_visit(44    vehicle: Vehicle = None,45    previous_visit: "Visit" = None,46    arrival_time: datetime = None,47) -> Visit:48    """Create a test visit."""49    visit = Visit(50        id="101",51        name="Test Customer",52        location=create_test_location(43.78, 11.26),53        demand=5,54        min_start_time=datetime(2024, 1, 1, 9, 0, 0),55        max_end_time=datetime(2024, 1, 1, 17, 0, 0),56        service_duration=timedelta(minutes=15),57        vehicle=vehicle,58        previous_visit=previous_visit,59        arrival_time=arrival_time,60    )61    return visit62 63 64def create_test_plan(vehicles: list = None, visits: list = None) -> VehicleRoutePlan:65    """Create a test route plan."""66    if vehicles is None:67        vehicles = [create_test_vehicle()]68    if visits is None:69        visits = []70    return VehicleRoutePlan(71        name="Test Plan",72        south_west_corner=create_test_location(43.75, 11.20),73        north_east_corner=create_test_location(43.80, 11.30),74        vehicles=vehicles,75        visits=visits,76    )77 78 79class TestVisitTimelineFields:80    """Tests for visit timeline serialization fields."""81 82    def test_unassigned_visit_has_null_timeline_fields(self):83        """Unassigned visits should have null timeline fields."""84        visit = create_test_visit(vehicle=None, arrival_time=None)85        model = visit_to_model(visit)86 87        assert model.arrival_time is None88        assert model.start_service_time is None89        assert model.departure_time is None90        assert model.driving_time_seconds_from_previous_standstill is None91 92    def test_assigned_visit_has_timeline_fields(self):93        """Assigned visits with arrival_time should have all timeline fields."""94        vehicle = create_test_vehicle()95        arrival = datetime(2024, 1, 1, 9, 30, 0)96        visit = create_test_visit(vehicle=vehicle, arrival_time=arrival)97        vehicle.visits = [visit]98 99        model = visit_to_model(visit)100 101        # arrival_time should be serialized102        assert model.arrival_time is not None103        assert model.arrival_time == "2024-01-01T09:30:00"104 105        # start_service_time = max(arrival_time, min_start_time)106        # Since arrival (09:30) > min_start (09:00), start_service = 09:30107        assert model.start_service_time is not None108        assert model.start_service_time == "2024-01-01T09:30:00"109 110        # departure_time = start_service_time + service_duration111        # = 09:30 + 15min = 09:45112        assert model.departure_time is not None113        assert model.departure_time == "2024-01-01T09:45:00"114 115        # driving_time_seconds should be calculated from vehicle home116        assert model.driving_time_seconds_from_previous_standstill is not None117 118    def test_early_arrival_uses_min_start_time(self):119        """When arrival is before min_start_time, start_service uses min_start_time."""120        vehicle = create_test_vehicle()121        # Arrive at 08:30, but min_start is 09:00122        early_arrival = datetime(2024, 1, 1, 8, 30, 0)123        visit = create_test_visit(vehicle=vehicle, arrival_time=early_arrival)124        vehicle.visits = [visit]125 126        model = visit_to_model(visit)127 128        # start_service_time should be min_start_time (09:00), not arrival (08:30)129        assert model.start_service_time == "2024-01-01T09:00:00"130 131        # departure should be min_start_time + service_duration = 09:15132        assert model.departure_time == "2024-01-01T09:15:00"133 134 135class TestVehicleTimelineFields:136    """Tests for vehicle timeline serialization fields."""137 138    def test_empty_vehicle_arrival_equals_departure(self):139        """Vehicle with no visits should have arrival_time = departure_time."""140        departure = datetime(2024, 1, 1, 6, 0, 0)141        vehicle = create_test_vehicle(departure_time=departure, visits=[])142 143        model = vehicle_to_model(vehicle)144 145        assert model.departure_time == "2024-01-01T06:00:00"146        assert model.arrival_time == "2024-01-01T06:00:00"147 148    def test_vehicle_with_visits_has_later_arrival(self):149        """Vehicle with visits should have arrival_time after last visit departure."""150        departure = datetime(2024, 1, 1, 6, 0, 0)151        vehicle = create_test_vehicle(departure_time=departure)152 153        # Create a visit assigned to this vehicle154        arrival = datetime(2024, 1, 1, 9, 30, 0)155        visit = create_test_visit(vehicle=vehicle, arrival_time=arrival)156        vehicle.visits = [visit]157 158        model = vehicle_to_model(vehicle)159 160        assert model.departure_time == "2024-01-01T06:00:00"161        # arrival_time should be > departure_time162        assert model.arrival_time is not None163        # arrival_time should be after visit departure + travel back to depot164 165 166class TestPlanTimelineFields:167    """Tests for route plan timeline window fields."""168 169    def test_plan_has_start_and_end_datetime(self):170        """Route plan should have startDateTime and endDateTime for timeline window."""171        departure = datetime(2024, 1, 1, 6, 0, 0)172        vehicle = create_test_vehicle(departure_time=departure)173        plan = create_test_plan(vehicles=[vehicle])174 175        model = plan_to_model(plan)176 177        # startDateTime should be earliest vehicle departure178        assert model.start_date_time is not None179        assert model.start_date_time == "2024-01-01T06:00:00"180 181        # endDateTime should be latest vehicle arrival182        # For empty vehicle, arrival = departure183        assert model.end_date_time is not None184        assert model.end_date_time == "2024-01-01T06:00:00"185 186    def test_plan_with_multiple_vehicles(self):187        """Plan timeline window should span all vehicles."""188        early_vehicle = create_test_vehicle(189            departure_time=datetime(2024, 1, 1, 5, 0, 0)190        )191        early_vehicle.id = "1"192        late_vehicle = create_test_vehicle(193            departure_time=datetime(2024, 1, 1, 8, 0, 0)194        )195        late_vehicle.id = "2"196 197        plan = create_test_plan(vehicles=[early_vehicle, late_vehicle])198        model = plan_to_model(plan)199 200        # startDateTime should be earliest departure (05:00)201        assert model.start_date_time == "2024-01-01T05:00:00"202 203        # endDateTime should be latest arrival204        # Both vehicles empty, so arrival = departure for each205        # Latest is late_vehicle at 08:00206        assert model.end_date_time == "2024-01-01T08:00:00"207 208    def test_empty_plan_has_null_datetimes(self):209        """Plan with no vehicles should have null datetime fields."""210        plan = create_test_plan(vehicles=[])211 212        model = plan_to_model(plan)213 214        assert model.start_date_time is None215        assert model.end_date_time is None216