agenda/tests/test_busy.py
Edward Betts 29d5145b87 Refactor get_location_for_date to use trip data directly
Simplify the location tracking function by extracting travel data directly
from trip objects instead of requiring separate YAML file parameters.

Changes:
- Remove airport, train, and ferry location helper functions that required
  separate YAML data lookups
- Update get_location_for_date signature to only take target_date and trips
- Extract flight/train/ferry details directly from trip.travel items
- Use embedded airport/station/terminal objects from trip data
- Remove YAML file parsing from weekends function
- Update test calls to use new simplified signature

This eliminates duplicate data loading and simplifies the API while
maintaining all existing functionality.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-16 12:08:19 +02:00

215 lines
6.8 KiB
Python

from datetime import date, datetime
import agenda.busy
import agenda.travel as travel
import agenda.trip
import pytest
from agenda.busy import _parse_datetime_field
from agenda.event import Event
from web_view import app
@pytest.fixture(scope="session")
def app_context():
"""Set up Flask app context for tests."""
app.config["SERVER_NAME"] = "test"
with app.app_context():
yield
@pytest.fixture(scope="session")
def trips(app_context):
"""Load trip list once for all tests."""
return agenda.trip.build_trip_list()
@pytest.fixture(scope="session")
def travel_data(app_context):
"""Load travel data (bookings, accommodations, airports) once for all tests."""
data_dir = app.config["PERSONAL_DATA"]
return {
"bookings": travel.parse_yaml("flights", data_dir),
"accommodations": travel.parse_yaml("accommodation", data_dir),
"airports": travel.parse_yaml("airports", data_dir),
"data_dir": data_dir,
}
def test_weekend_location_consistency(app_context, trips, travel_data):
"""Test that weekend locations are consistent with events (free=home, events=away)."""
for year in range(2023, 2025):
start = date(2023, 1, 1)
busy_events = agenda.busy.get_busy_events(start, app.config, trips)
weekends = agenda.busy.weekends(
start, busy_events, trips, travel_data["data_dir"]
)
for weekend in weekends:
for day in "saturday", "sunday":
# When free (no events), should be home (None)
# When traveling (events), should be away (City name)
location_exists = bool(weekend[day + "_location"][0])
has_events = bool(weekend[day])
assert location_exists == has_events, (
f"Weekend {weekend['date']} {day}: "
f"location_exists={location_exists}, has_events={has_events}"
)
def test_specific_home_dates(travel_data):
"""Test specific dates that should return home (None)."""
trips = agenda.trip.build_trip_list()
home_dates = [
date(2023, 4, 29),
date(2025, 7, 1),
date(2023, 12, 2),
date(2023, 10, 7),
date(2023, 2, 18),
date(2025, 8, 2),
]
for test_date in home_dates:
location = agenda.busy.get_location_for_date(
test_date,
trips,
)
assert not location[
0
], f"Expected home (None) for {test_date}, got {location[0]}"
def test_specific_away_dates(travel_data):
"""Test specific dates that should return away locations."""
trips = agenda.trip.build_trip_list()
away_cases = [
(date(2025, 2, 15), "Hackettstown"),
]
for test_date, expected_city in away_cases:
location = agenda.busy.get_location_for_date(
test_date,
trips,
)
assert (
location[0] == expected_city
), f"Expected {expected_city} for {test_date}, got {location[0]}"
def test_get_location_for_date_basic(travel_data):
"""Test basic functionality of get_location_for_date function."""
trips = agenda.trip.build_trip_list()
test_date = date(2023, 1, 1)
location = agenda.busy.get_location_for_date(
test_date,
trips,
)
# Should return a tuple with (city|None, country)
assert isinstance(location, tuple)
assert len(location) == 2
assert location[1] is not None # Should always have a country
def test_busy_event_classification():
"""Test the busy_event function for different event types."""
# Busy event types
busy_events = [
Event(name="event", title="Test Event", date=date(2023, 1, 1)),
Event(
name="conference",
title="Test Conference",
date=date(2023, 1, 1),
going=True,
),
Event(name="accommodation", title="Hotel", date=date(2023, 1, 1)),
Event(name="transport", title="Flight", date=date(2023, 1, 1)),
]
for event in busy_events:
assert agenda.busy.busy_event(event), f"Event {event.name} should be busy"
# Non-busy events
non_busy_events = [
Event(
name="conference",
title="Test Conference",
date=date(2023, 1, 1),
going=False,
),
Event(name="other", title="Other Event", date=date(2023, 1, 1)),
Event(name="event", title="LHG Run Club", date=date(2023, 1, 1)),
Event(name="event", title="IA UK board meeting", date=date(2023, 1, 1)),
]
for event in non_busy_events:
assert not agenda.busy.busy_event(
event
), f"Event {event.name}/{event.title} should not be busy"
def test_parse_datetime_field():
"""Test the _parse_datetime_field helper function."""
# Test with datetime object
dt = datetime(2023, 1, 1, 12, 0, 0)
parsed_dt, parsed_date = _parse_datetime_field(dt)
assert parsed_dt == dt
assert parsed_date == date(2023, 1, 1)
# Test with ISO string
iso_string = "2023-01-01T12:00:00Z"
parsed_dt, parsed_date = _parse_datetime_field(iso_string)
assert parsed_date == date(2023, 1, 1)
assert parsed_dt.year == 2023
assert parsed_dt.month == 1
assert parsed_dt.day == 1
def test_get_busy_events(app_context, trips):
"""Test get_busy_events function."""
start_date = date(2023, 1, 1)
busy_events = agenda.busy.get_busy_events(start_date, app.config, trips)
# Should return a list
assert isinstance(busy_events, list)
# All events should be Event objects
for event in busy_events:
assert hasattr(event, "name")
assert hasattr(event, "as_date")
# Events should be sorted by date
dates = [event.as_date for event in busy_events]
assert dates == sorted(dates), "Events should be sorted by date"
def test_weekends_function(app_context, trips, travel_data):
"""Test the weekends function."""
start_date = date(2023, 1, 1)
busy_events = agenda.busy.get_busy_events(start_date, app.config, trips)
weekends = agenda.busy.weekends(
start_date, busy_events, trips, travel_data["data_dir"]
)
# Should return a list of weekend info
assert isinstance(weekends, list)
assert len(weekends) == 52 # Should return 52 weekends
# Each weekend should have the required keys
for weekend in weekends[:5]: # Check first 5 weekends
assert "date" in weekend
assert "saturday" in weekend
assert "sunday" in weekend
assert "saturday_location" in weekend
assert "sunday_location" in weekend
# Locations should be tuples
assert isinstance(weekend["saturday_location"], tuple)
assert isinstance(weekend["sunday_location"], tuple)
assert len(weekend["saturday_location"]) == 2
assert len(weekend["sunday_location"]) == 2