fix(r3): fold heid's code review — equal stage widths, the axis guard, players, and tests that read the observable

The one drift: the separator was a border on B, making B's stage 1px
narrower than A's; it is now a 1px column gap, so the stages are the same
size to the pixel. Tests now read what the contract promises instead of a
proxy: the strip's ring order, the full bakeoff sequence, 1:1 and Fit by
geometry, the 900px break from both sides, A wrapping, each form naming its
own item, a sibling-prefix symlink, both reveals, the strip's flag, the back
arrow unlinked, a one-axis picture, a focused player, two videos with no
toggle. The contract names .cmp-cap, a press on a stage, INV-4's URL-driven
picker and the redirect branch's isinstance check. r3.toml gains ten rows.
This commit is contained in:
vh
2026-09-24 13:54:29 -07:00
parent 8c7fe77841
commit 23f1bdb41f
5 changed files with 213 additions and 26 deletions
+33 -3
View File
@@ -61,6 +61,11 @@ def test_compare_renders_the_pair(tmp_path):
assert "p.png" in label_a and "#1" in label_a, label_a
assert "r.png" in label_b and "#3" in label_b, label_b
assert _frames(body) == {"p.png": "A", "q.png": "", "r.png": "B", "s.png": ""}
assert list(_frames(body)) == ["p.png", "q.png", "r.png", "s.png"], "the strip is in RING order"
# each side's flag form names its OWN item
for key, rel in (("a", "p.png"), ("b", "r.png")):
form = re.search(r'data-region="flag-%s".*?</form>' % key, body, re.S).group(0)
assert f'name="target" value="{rel}"' in form, (key, form)
def _four(root: pathlib.Path) -> pathlib.Path:
@@ -103,9 +108,16 @@ def test_an_outside_symlink_in_the_ring_is_404(tmp_path):
outside.write_bytes(PNG)
(b / "zz-link.png").symlink_to(outside)
assert "zz-link.png" in review_chain(booth_items(b)), "the fixture must put it in the ring"
# a SIBLING whose name shares the booth's prefix is outside too (the
# containment check compares with the separator, never a bare prefix)
sib = tmp_path / "g-extra"
sib.mkdir()
(sib / "x.png").write_bytes(PNG)
(b / "zz-sib.png").symlink_to(sib / "x.png")
c = _client(tmp_path)
assert c.get("/b/g/compare?a=zz-link.png&b=p.png").status_code == 404
assert c.get("/b/g/compare?a=p.png&b=zz-link.png").status_code == 404
for rel in ("zz-link.png", "zz-sib.png"):
assert c.get(f"/b/g/compare?a={rel}&b=p.png").status_code == 404, rel
assert c.get(f"/b/g/compare?a=p.png&b={rel}").status_code == 404, rel
def test_a_look_records_both_seen(tmp_path):
@@ -144,6 +156,18 @@ def test_no_data_region_repeats(tmp_path):
assert _frames(body)["q.png"] == "AB", "a == b marks the one frame both ways"
def test_a_video_or_track_plays_in_its_own_stage_and_two_get_no_toggle(tmp_path):
"""C4: video and audio play in their own stage; the Fit | 1:1 toggle is
bound only when a side is a picture, so two videos get none."""
_booth(tmp_path, "g", {"a.webm": b"\x1aE\xdf\xa3", "b.mp3": b"ID3", "c.png": PNG})
c = _client(tmp_path)
body = c.get("/b/g/compare?a=a.webm&b=b.mp3").text
assert re.search(r'<video class="cmp-media"[^>]*src="a.webm"', body)
assert re.search(r'<audio class="cmp-media"[^>]*src="b.mp3"', body)
assert 'id="vtoggle"' not in body
assert 'id="vtoggle"' in c.get("/b/g/compare?a=a.webm&b=c.png").text
# ---- C3: stepping --------------------------------------------------------------
def _ring6(root: pathlib.Path) -> pathlib.Path:
@@ -170,6 +194,8 @@ def test_linked_steps_keep_the_distance_and_wrap(tmp_path):
assert _step(body, "both-next") == ("04.png", "07.png")
body = c.get("/b/g/compare?a=04.png&b=07.png").text
assert _step(body, "both-next") == ("05.png", "01.png")
body = c.get("/b/g/compare?a=07.png&b=02.png").text
assert _step(body, "both-next") == ("01.png", "04.png"), "A wraps as B does"
body = c.get("/b/g/compare?a=01.png&b=05.png").text
assert _step(body, "both-prev") == ("07.png", "04.png")
# each side on its own moves only itself, and wraps the same way
@@ -214,6 +240,8 @@ def test_view_state_rides_the_links(tmp_path):
frame = re.search(r'<a class="film-f[^"]*"\s+href="([^"]+)" data-rel="q.png"', body).group(1)
assert parse_qs(urlsplit(frame.replace("&amp;", "&")).query) == {
"a": ["q.png"], "b": ["r.png"], "side": ["a"], "link": ["0"]}
links = _compare_links(c.get("/b/g/compare?a=p.png&b=r.png&link=0").text)
assert links and all(h.endswith("&link=0") and "side=" not in h for h in links), links
for odd in ("side=z&link=maybe", "side=A&link=00", "side=&link="):
r = c.get(f"/b/g/compare?a=p.png&b=r.png&{odd}")
assert r.status_code == 200, odd
@@ -227,7 +255,9 @@ def test_view_state_rides_the_links(tmp_path):
def _flag(c: TestClient, form: dict, accept: str | None = None):
headers = {"accept": accept} if accept else {}
return c.post("/b/g/flag", data={"target": "q.png", "on": "1", **form}, headers=headers)
r = c.post("/b/g/flag", data={"target": "q.png", "on": "1", **form}, headers=headers)
assert r.status_code == (204 if accept else 303), (form, r.status_code)
return r
def test_a_flag_without_js_lands_on_the_same_pair(tmp_path):