148 lines
4.6 KiB
Python
148 lines
4.6 KiB
Python
from __future__ import annotations
|
|
|
|
from app.journey import _filter_dominated_journeys
|
|
from app.journey_search import _rank_journeys, _select_diverse_journeys
|
|
|
|
|
|
def test_progressive_selection_keeps_fast_and_low_walk_transit_options():
|
|
fast_with_walk = _journey(
|
|
"fast",
|
|
arrival=30_000,
|
|
transfers=0,
|
|
legs=[
|
|
_leg("tram", "22", "A", "B"),
|
|
_leg("walk", "walk", "B", "Z", distance_m=1200),
|
|
],
|
|
)
|
|
slower_low_walk = _journey(
|
|
"low-walk",
|
|
arrival=31_200,
|
|
transfers=1,
|
|
legs=[
|
|
_leg("tram", "22", "A", "Hbf"),
|
|
_leg("bus", "34", "Hbf", "Y"),
|
|
_leg("walk", "walk", "Y", "Z", distance_m=120),
|
|
],
|
|
)
|
|
walk_only = _journey(
|
|
"walk-only",
|
|
arrival=30_900,
|
|
transfers=0,
|
|
legs=[_leg("walk", "walk", "A", "Z", distance_m=1800)],
|
|
)
|
|
|
|
ranked = _rank_journeys([slower_low_walk, walk_only, fast_with_walk], "recommended")
|
|
selected = _select_diverse_journeys(ranked, limit=3)
|
|
|
|
assert len(selected) <= 3
|
|
assert {journey["id"] for journey in selected} == {"fast", "low-walk", "walk-only"}
|
|
|
|
|
|
def test_progressive_selection_collapses_same_journey_from_duplicate_gtfs_feeds():
|
|
rnv = _journey(
|
|
"rnv",
|
|
arrival=29_820,
|
|
transfers=0,
|
|
legs=[
|
|
_leg("walk", "walk", "Jakob-Neu-Straße 2", "Eppelheim Rathaus", dataset_id=10, source_name=None),
|
|
_leg("tram", "RNV 22", "Eppelheim Rathaus", "Heidelberg Hbf", dataset_id=10, source_name="DE Verkehrsverbund Rhein-Neckar GTFS"),
|
|
],
|
|
)
|
|
delfi = _journey(
|
|
"delfi",
|
|
arrival=29_820,
|
|
transfers=0,
|
|
legs=[
|
|
_leg("walk", "walk", "Jakob-Neu-Straße 2", "Eppelheim Rathaus", dataset_id=4, source_name=None),
|
|
_leg("tram", "RNV 22", "Eppelheim Rathaus", "Heidelberg Hbf", dataset_id=4, source_name="DELFI / GTFS.de Germany", stop_count=8),
|
|
],
|
|
)
|
|
|
|
ranked = _rank_journeys([rnv, delfi], "recommended")
|
|
selected = _select_diverse_journeys(ranked, limit=3)
|
|
|
|
assert [journey["id"] for journey in selected] == ["delfi"]
|
|
|
|
|
|
def test_dominance_removes_only_slower_more_transfer_same_endpoint_options():
|
|
direct = _journey(
|
|
"direct",
|
|
arrival=30_000,
|
|
transfers=0,
|
|
legs=[
|
|
_leg("tram", "22", "A", "platform-a", canonical_to=500),
|
|
_leg("walk", "walk", "platform-a", "Z", distance_m=800),
|
|
],
|
|
)
|
|
faster_transfer = _journey(
|
|
"faster-transfer",
|
|
arrival=29_500,
|
|
transfers=1,
|
|
legs=[
|
|
_leg("bus", "34", "A", "X"),
|
|
_leg("tram", "5", "X", "platform-b", canonical_to=500),
|
|
_leg("walk", "walk", "platform-b", "Z", distance_m=800),
|
|
],
|
|
)
|
|
slower_transfer = _journey(
|
|
"slower-transfer",
|
|
arrival=31_000,
|
|
transfers=1,
|
|
legs=[
|
|
_leg("bus", "713", "A", "Y"),
|
|
_leg("tram", "22", "Y", "platform-c", canonical_to=500),
|
|
_leg("walk", "walk", "platform-c", "Z", distance_m=800),
|
|
],
|
|
)
|
|
|
|
filtered = _filter_dominated_journeys([slower_transfer, faster_transfer, direct])
|
|
|
|
assert {journey["id"] for journey in filtered} == {"direct", "faster-transfer"}
|
|
|
|
|
|
def _journey(journey_id: str, *, arrival: int, transfers: int, legs: list[dict]) -> dict:
|
|
departure = 28_800
|
|
return {
|
|
"id": journey_id,
|
|
"departure_seconds": departure,
|
|
"arrival_seconds": arrival,
|
|
"duration_seconds": arrival - departure,
|
|
"duration_minutes": (arrival - departure + 59) // 60,
|
|
"transfers": transfers,
|
|
"legs": legs,
|
|
}
|
|
|
|
|
|
def _leg(
|
|
mode: str,
|
|
route: str,
|
|
from_stop: str,
|
|
to_stop: str,
|
|
*,
|
|
distance_m: float = 0,
|
|
canonical_to: int | None = None,
|
|
dataset_id: int = 1,
|
|
source_name: str | None = "Test GTFS",
|
|
stop_count: int = 2,
|
|
) -> dict:
|
|
to_payload = {"stop_id": to_stop}
|
|
stops = [{"stop_id": from_stop}, {"stop_id": to_stop}]
|
|
if canonical_to is not None:
|
|
stops[-1]["canonical_stop"] = {"id": canonical_to}
|
|
return {
|
|
"dataset_id": dataset_id,
|
|
"source_name": source_name,
|
|
"mode": mode,
|
|
"route_id": route,
|
|
"route_ref": route,
|
|
"trip_id": f"{route}-trip" if mode != "walk" else None,
|
|
"from": {"stop_id": from_stop},
|
|
"to": to_payload,
|
|
"departure_time": "08:00:00",
|
|
"arrival_time": "08:10:00",
|
|
"distance_m": distance_m,
|
|
"stop_count": stop_count if mode != "walk" else None,
|
|
"intermediate_stop_count": max(0, stop_count - 2) if mode != "walk" else None,
|
|
"stops": stops,
|
|
}
|