Refactor tests: break down single test into focused, modular tests
- Add pytest fixtures for shared data to avoid reparsing YAML files - Split large test into specific test functions for better modularity - Add comprehensive test coverage for busy_event, location tracking, and helper functions - Improve test performance with session-scoped fixtures - Enable individual test execution with pytest -k 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
bdc94f3ebc
commit
f89d984623
|
@ -1,68 +1,223 @@
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime
|
||||||
|
|
||||||
import agenda.busy
|
import agenda.busy
|
||||||
import agenda.travel as travel
|
import agenda.travel as travel
|
||||||
import agenda.trip
|
import agenda.trip
|
||||||
|
import pytest
|
||||||
|
from agenda.busy import _parse_datetime_field
|
||||||
|
from agenda.event import Event
|
||||||
from web_view import app
|
from web_view import app
|
||||||
|
|
||||||
|
|
||||||
def test_get_location_for_date() -> None:
|
@pytest.fixture(scope="session")
|
||||||
|
def app_context():
|
||||||
|
"""Set up Flask app context for tests."""
|
||||||
app.config["SERVER_NAME"] = "test"
|
app.config["SERVER_NAME"] = "test"
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
today = datetime.now().date()
|
yield
|
||||||
trips = agenda.trip.build_trip_list()
|
|
||||||
|
|
||||||
data_dir = app.config["PERSONAL_DATA"]
|
|
||||||
|
|
||||||
# Parse YAML files once for the test
|
@pytest.fixture(scope="session")
|
||||||
bookings = travel.parse_yaml("flights", data_dir)
|
def trips(app_context):
|
||||||
accommodations = travel.parse_yaml("accommodation", data_dir)
|
"""Load trip list once for all tests."""
|
||||||
airports = travel.parse_yaml("airports", data_dir)
|
return agenda.trip.build_trip_list()
|
||||||
|
|
||||||
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, data_dir)
|
|
||||||
|
|
||||||
for weekend in weekends:
|
@pytest.fixture(scope="session")
|
||||||
for day in "saturday", "sunday":
|
def travel_data(app_context):
|
||||||
# When free (no events), should be home (None)
|
"""Load travel data (bookings, accommodations, airports) once for all tests."""
|
||||||
# When traveling (events), should be away (City name)
|
data_dir = app.config["PERSONAL_DATA"]
|
||||||
assert bool(weekend[day + "_location"][0]) == bool(weekend[day])
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
# Test some specific cases
|
|
||||||
april_29_location = agenda.busy.get_location_for_date(
|
def test_weekend_location_consistency(app_context, trips, travel_data):
|
||||||
date(2023, 4, 29), trips, bookings, accommodations, airports
|
"""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"]
|
||||||
)
|
)
|
||||||
assert not april_29_location[0] # Should be home (None)
|
|
||||||
|
|
||||||
l = agenda.busy.get_location_for_date(
|
for weekend in weekends:
|
||||||
date(2025, 2, 15), trips, bookings, accommodations, airports
|
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,
|
||||||
|
travel_data["bookings"],
|
||||||
|
travel_data["accommodations"],
|
||||||
|
travel_data["airports"],
|
||||||
)
|
)
|
||||||
assert l[0] == "Hackettstown"
|
assert not location[
|
||||||
|
0
|
||||||
|
], f"Expected home (None) for {test_date}, got {location[0]}"
|
||||||
|
|
||||||
l = agenda.busy.get_location_for_date(
|
|
||||||
date(2025, 7, 1), trips, bookings, accommodations, airports
|
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,
|
||||||
|
travel_data["bookings"],
|
||||||
|
travel_data["accommodations"],
|
||||||
|
travel_data["airports"],
|
||||||
)
|
)
|
||||||
assert not l[0]
|
assert (
|
||||||
|
location[0] == expected_city
|
||||||
|
), f"Expected {expected_city} for {test_date}, got {location[0]}"
|
||||||
|
|
||||||
l = agenda.busy.get_location_for_date(
|
|
||||||
date(2023, 12, 2), trips, bookings, accommodations, airports
|
|
||||||
)
|
|
||||||
assert not l[0]
|
|
||||||
|
|
||||||
l = agenda.busy.get_location_for_date(
|
def test_get_location_for_date_basic(travel_data):
|
||||||
date(2023, 10, 7), trips, bookings, accommodations, airports
|
"""Test basic functionality of get_location_for_date function."""
|
||||||
)
|
trips = agenda.trip.build_trip_list()
|
||||||
assert not l[0]
|
test_date = date(2023, 1, 1)
|
||||||
|
|
||||||
l = agenda.busy.get_location_for_date(
|
location = agenda.busy.get_location_for_date(
|
||||||
date(2023, 2, 18), trips, bookings, accommodations, airports
|
test_date,
|
||||||
)
|
trips,
|
||||||
assert not l[0]
|
travel_data["bookings"],
|
||||||
|
travel_data["accommodations"],
|
||||||
|
travel_data["airports"],
|
||||||
|
)
|
||||||
|
|
||||||
l = agenda.busy.get_location_for_date(
|
# Should return a tuple with (city|None, country)
|
||||||
date(2025, 8, 2), trips, bookings, accommodations, airports
|
assert isinstance(location, tuple)
|
||||||
)
|
assert len(location) == 2
|
||||||
assert not l[0]
|
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
|
||||||
|
|
Loading…
Reference in a new issue