Files
thunderheronightandClaude Opus 5.5 fccaf4afc6 Folder names without a trailing dot (NTFS refuses them)
Found moving the runs to an NTFS disk: the tour "Rundgang 12.10." (folder Rundgang-12.10.) was not copied.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:02:35 +02:00

97 lines
4.7 KiB
Python

"""Groups of scenes: one group per scene, suggestions, renaming, cleaning up together."""
import json
import pytest
from conftest import RUNS, server
import synth
def make_flat():
synth.make_room(RUNS, "Kitchen", "A", name="Kitchen", recording="2026-10-12_16-40-00_stereo.mp4")
synth.make_room(RUNS, "Hallway", "B", name="Hallway", recording="2026-10-12_16-43-00_stereo.mp4")
synth.make_room(RUNS, "Statue", "A", name="Statue", recording="2026-10-03_19-00-00_stereo.mp4")
def test_rooms_recorded_one_after_another_are_suggested(api):
make_flat()
# 25 minutes after the hallway: more than the 20 minutes that still count as one session
synth.make_room(RUNS, "Garden", "A", name="Garden", recording="2026-10-12_17-08-00_stereo.mp4")
status, r = api.get("/api/groups")
assert status == 200 and r["groups"] == []
assert sorted(r["suggestion"]["members"]) == ["Hallway", "Kitchen"] # not the statue from another day
assert r["suggestion"]["date"] == "2026-10-12"
assert api.post("/api/group/dismiss", {"key": r["suggestion"]["key"]})[0] == 200
assert api.get("/api/groups")[1]["suggestion"] is None
def test_a_group_with_its_scenes(api):
make_flat()
status, r = api.post("/api/group", {"name": "Example home", "members": "Kitchen,Hallway"})
assert status == 200 and r["slug"] == "Example-home"
g = api.get("/api/groups")[1]["groups"][0]
assert (g["name"], g["members"], g["result"]) == ("Example home", ["Kitchen", "Hallway"], None)
assert "Example-home" not in {s["slug"] for s in api.get("/api/scenes")[1]} # a group is not a scene
assert "Example-home" not in {u["slug"] for u in api.get("/api/unfinished")[1]}
def test_a_scene_can_only_be_in_one_group(api):
make_flat()
api.post("/api/group", {"name": "Home", "members": "Kitchen,Hallway"})
status, r = api.post("/api/group", {"name": "Other", "members": "Kitchen,Statue"})
assert status == 400 and r["error"]["code"] == "err.in_other_group"
assert api.post("/api/group", {"name": "Empty", "members": ""})[0] == 400
assert api.post("/api/group", {"name": "Ghost", "members": "Nope"})[0] == 400
def test_renaming_and_changing_a_group(api):
make_flat()
api.post("/api/group", {"name": "Home", "members": "Kitchen,Hallway"})
status, r = api.post("/api/group", {"slug": "Home", "name": "Old flat", "members": "Kitchen"})
assert status == 200 and r["slug"] == "Old-flat"
assert not (RUNS / "Home.ui.json").exists()
g = api.get("/api/groups")[1]["groups"][0]
assert (g["slug"], g["name"], g["members"]) == ("Old-flat", "Old flat", ["Kitchen"])
def test_renamed_and_deleted_scenes_follow_their_group(api):
make_flat()
api.post("/api/group", {"name": "Home", "members": "Kitchen,Hallway"})
api.post("/api/rename", {"slug": "Kitchen", "new": "Küche"})
assert json.loads((RUNS / "Home.ui.json").read_text())["members"] == ["Kueche", "Hallway"]
api.post("/api/delete", {"slug": "Hallway"})
assert json.loads((RUNS / "Home.ui.json").read_text())["members"] == ["Kueche"]
def test_cleaning_up_a_group_cleans_only_its_scenes(api):
make_flat()
for slug in ("Kitchen", "Hallway", "Statue"):
(RUNS / slug / "spirula" / "training").mkdir(parents=True)
(RUNS / slug / "spirula" / "training" / "x").write_bytes(b"x" * 1000)
api.post("/api/group", {"name": "Home", "members": "Kitchen,Hallway"})
assert api.post("/api/clean", {"slug": "Home", "what": "temp"})[0] == 200
assert not (RUNS / "Kitchen/spirula/training").exists() and not (RUNS / "Hallway/spirula/training").exists()
assert (RUNS / "Statue/spirula/training/x").exists()
def test_dissolving_a_group_keeps_its_scenes(api):
make_flat()
api.post("/api/group", {"name": "Home", "members": "Kitchen,Hallway"})
assert api.post("/api/delete", {"slug": "Home"})[0] == 200
assert api.get("/api/groups")[1]["groups"] == []
assert {"Kitchen", "Hallway", "Statue"} <= {s["slug"] for s in server.scenes()}
@pytest.mark.parametrize("name,slug", [("Rundgang 12.10.", "Rundgang-12.10"), ("Küche", "Kueche"),
("...", ""), (".hidden", "hidden"), ("Flur 2", "Flur-2")])
def test_folder_names_suit_every_file_system(name, slug):
"""No dot at the end: NTFS (e.g. runs on a Windows disk) refuses it, and the copy loses the tour."""
from splat_workshop import config
assert config.slugify(name) == slug
def test_a_tour_named_with_a_date_gets_a_folder_ntfs_accepts(api):
synth.make_room(RUNS, "Kitchen", "A", name="Kitchen")
synth.make_room(RUNS, "Hall", "B", name="Hall")
status, r = api.post("/api/group", {"name": "Tour 12.10.", "members": "Kitchen,Hall"})
assert status == 200 and r["slug"] == "Tour-12.10"