"""Tests for the Plan model: saving, reloading, and editing a masterplan.""" import json from tatami.classes import Group from tatami.plan import Plan from tatami.tatami_masterplan import assign_courses, get_after_party_group from conftest import make_participants def make_plan(n: int = 6) -> Plan: groups = [Group(members=[p]) for p in make_participants(n)] courses = ["starter", "main", "dessert"] * (n // 3) assign_courses(groups, courses) after_party = get_after_party_group("party street") return Plan( groups=groups, after_party_group=after_party, course_times={"starter": "18:30", "main": "20:00", "dessert": "22:00"}, organizer_contacts=[("Lars (Organizer)", "0151-23456789")], info_text="Welcome!", ) class TestPlanRoundTrip: def test_save_and_load_preserves_groups_and_hosts(self, tmp_path): plan = make_plan() path = tmp_path / "masterplan.json" plan.save(path) loaded = Plan.load(path) assert [g.uuid for g in loaded.groups] == [g.uuid for g in plan.groups] for original, reloaded in zip(plan.groups, loaded.groups): assert reloaded.course == original.course assert [h.uuid for h in reloaded.hosts] == [h.uuid for h in original.hosts] def test_load_resolves_live_host_objects_not_just_uuids(self, tmp_path): plan = make_plan() path = tmp_path / "masterplan.json" plan.save(path) loaded = Plan.load(path) group = loaded.groups[0] assert group.hosts is not None # Hosts are live Group objects (so .course etc. is accessible), not just ids. assert all(isinstance(h, Group) for h in group.hosts) assert {h.course for h in group.hosts} == {"starter", "main", "dessert"} def test_round_trip_is_idempotent(self, tmp_path): plan = make_plan() path = tmp_path / "masterplan.json" plan.save(path) first = json.loads(path.read_text()) Plan.load(path).save(path) second = json.loads(path.read_text()) assert first == second def test_carries_course_times_contacts_info_and_spreadsheet_id(self, tmp_path): plan = make_plan() plan.spreadsheet_id = "abc123" path = tmp_path / "masterplan.json" plan.save(path) loaded = Plan.load(path) assert loaded.course_times == plan.course_times assert loaded.organizer_contacts == plan.organizer_contacts assert loaded.info_text == plan.info_text assert loaded.spreadsheet_id == "abc123" def test_spreadsheet_id_defaults_to_none(self): assert make_plan().spreadsheet_id is None class TestPlanEditing: def test_editing_saved_json_changes_reloaded_plan(self, tmp_path): plan = make_plan() path = tmp_path / "masterplan.json" plan.save(path) data = json.loads(path.read_text()) data["spreadsheet_id"] = "edited-by-hand" data["groups"][0]["members"][0]["address"] = "New Address 1" path.write_text(json.dumps(data)) loaded = Plan.load(path) assert loaded.spreadsheet_id == "edited-by-hand" assert loaded.groups[0].members[0].address == "New Address 1" class TestPlanParticipants: def test_participants_property_collects_everyone_once(self): plan = make_plan() uuids = [p.uuid for p in plan.participants] assert len(uuids) == len(set(uuids)) member_uuids = {m.uuid for g in plan.groups for m in g.members} member_uuids.add(plan.after_party_group.main_member.uuid) assert set(uuids) == member_uuids