"""Tests for agenda.generate_booking_yaml.""" from dataclasses import dataclass from datetime import date from pathlib import Path import pytest import yaml from agenda import generate_booking_yaml @dataclass class FakeTrip: """Small stand-in for agenda.types.Trip in matching tests.""" start: date end: date | None def test_yaml_format_description_includes_train_spec() -> None: """Train prompt docs should come from personal-data-yaml.md.""" description = generate_booking_yaml.yaml_format_description( generate_booking_yaml.BOOKING_CONFIGS["train"] ) assert "## General Rules" in description assert "## Cross-File References" in description assert "## `trains.yaml`" in description assert "`operator`: booking/operator label" in description def test_build_prompt_uses_spec_and_keeps_trip_exclusion() -> None: """The generated prompt should use the documented schema.""" prompt = generate_booking_yaml.build_prompt( "Eurostar booking details", generate_booking_yaml.BOOKING_CONFIGS["train"], current_bookings="- operator: eurostar\n", ) assert "Use this YAML format specification" in prompt assert "## `trains.yaml`" in prompt assert 'Exclude the top-level "trip" key' in prompt assert "Eurostar booking details" in prompt def test_booking_text_from_args_fetches_url(monkeypatch: pytest.MonkeyPatch) -> None: """URL arguments should be fetched instead of reading stdin.""" monkeypatch.setattr( generate_booking_yaml, "url_to_booking_text", lambda url: f"fetched {url}", ) assert generate_booking_yaml.booking_text_from_args(["https://example.com"]) == ( "fetched https://example.com" ) def test_matching_trip_date_uses_built_trip_end( monkeypatch: pytest.MonkeyPatch, ) -> None: """Trip matching should use build_trip_list-derived end dates.""" monkeypatch.setattr( generate_booking_yaml, "build_trips", lambda data_dir: [ # noqa: ARG005 FakeTrip(date(2026, 2, 6), date(2026, 2, 9)), FakeTrip(date(2026, 3, 3), date(2026, 3, 5)), ], ) assert generate_booking_yaml.matching_trip_date( generate_booking_yaml.datetime_from_yaml_value("2026-02-08 12:00:00+01:00"), Path("/tmp/personal-data"), ) == date(2026, 2, 6) def test_matching_trip_date_falls_back_to_departure_date( monkeypatch: pytest.MonkeyPatch, ) -> None: """A booking outside known trips should use its first departure date.""" monkeypatch.setattr( generate_booking_yaml, "build_trips", lambda data_dir: [] # noqa: ARG005 ) assert generate_booking_yaml.matching_trip_date( generate_booking_yaml.datetime_from_yaml_value("2026-04-10 12:00:00+01:00"), Path("/tmp/personal-data"), ) == date(2026, 4, 10) def test_import_train_booking_adds_trip_and_inserts_chronologically( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: """Generated train bookings should be written into trains.yaml in order.""" (tmp_path / "trains.yaml").write_text("""- operator: early from: A to: B trip: 2026-02-01 depart: 2026-02-01 10:00:00+00:00 arrive: 2026-02-01 11:00:00+00:00 legs: [] - operator: late from: C to: D trip: 2026-02-10 depart: 2026-02-10 10:00:00+00:00 arrive: 2026-02-10 11:00:00+00:00 legs: [] """) monkeypatch.setattr( generate_booking_yaml, "matching_trip_date", lambda depart, data_dir: date(2026, 2, 6), ) count = generate_booking_yaml.import_booking_yaml( """- operator: eurostar from: London St Pancras to: Brussels Midi depart: 2026-02-06 15:04:00+00:00 arrive: 2026-02-06 18:12:00+01:00 legs: [] """, generate_booking_yaml.BOOKING_CONFIGS["train"], data_dir=tmp_path, ) written = yaml.safe_load((tmp_path / "trains.yaml").read_text()) assert count == 1 assert [item["operator"] for item in written] == ["early", "eurostar", "late"] assert written[1]["trip"] == date(2026, 2, 6) assert list(written[1]).index("trip") == 3 assert "\n\n- operator: eurostar\n" in (tmp_path / "trains.yaml").read_text() def test_import_flight_booking_adds_trip_and_inserts_chronologically( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: """Generated flight bookings should be written into flights.yaml in order.""" (tmp_path / "flights.yaml").write_text("""--- - booking_reference: OLD trip: 2026-02-01 flights: - depart: 2026-02-01 10:00:00+00:00 from: BRS to: AMS flight_number: '1' airline: U2 - booking_reference: NEWER trip: 2026-02-10 flights: - depart: 2026-02-10 10:00:00+00:00 from: BRS to: AMS flight_number: '2' airline: U2 """) monkeypatch.setattr( generate_booking_yaml, "matching_trip_date", lambda depart, data_dir: date(2026, 2, 6), ) count = generate_booking_yaml.import_booking_yaml( """booking_reference: MID flights: - depart: 2026-02-06 10:00:00+00:00 from: BRS to: AMS flight_number: '3' airline: U2 """, generate_booking_yaml.BOOKING_CONFIGS["flight"], data_dir=tmp_path, ) written = yaml.safe_load((tmp_path / "flights.yaml").read_text()) assert count == 1 assert [item["booking_reference"] for item in written] == ["OLD", "MID", "NEWER"] assert written[1]["trip"] == date(2026, 2, 6) assert list(written[1]).index("trip") == 1