a73x

c36f3a11

test: a rendered wall says which chord reaches which tile

a73x   2026-08-25 19:33

Commit message
test: a rendered wall says which chord reaches which tile

Extends two existing legs rather than adding one: hydrate-create already
renders a three-tile stacked wall (the digits at rest), fullscreen already
types Ctrl-\ 2 (the marker moves, the digits do not). The render oracle
is the only witness — the daemon's grid has no bars in it.

src/wallview.zig
Old New
@@ -3416,23 +3416,34 @@ test "labelText: the state word survives truncation at every width" {
3416 // not the label's own length. 3416 // not the label's own length.
3417 const long = "x" ** 400; 3417 const long = "x" ** 400;
3418 3418
3419 // The markers are the ones a bar actually carries: three bytes with the
3420 // chord digit, four for tiles 10 and up. Every one of them comes out of
3421 // the label's cut, so the marker width is part of what this pins — a
3422 // two-byte marker exercises no bar that ships.
3423
3419 // Narrow: the label is cut, the bar fits the terminal, the state stays. 3424 // Narrow: the label is cut, the bar fits the terminal, the state stays.
3420 const narrow = labelText(&buf, 30, "> ", long, "up"); 3425 const narrow = labelText(&buf, 30, "1> ", long, "up");
3421 try std.testing.expect(std.mem.endsWith(u8, narrow, " [up]")); 3426 if (!std.mem.endsWith(u8, narrow, " [up]")) return error.OneDigitNarrowBarLostTheStateWord;
3422 try std.testing.expect(narrow.len <= 30); 3427 if (narrow.len > 30) return error.OneDigitNarrowBarOverranTheTerminal;
3428
3429 // The same width with the widest marker: the two extra bytes come off
3430 // the label, never off the state.
3431 const narrow2 = labelText(&buf, 30, "12 ", long, "up");
3432 if (!std.mem.endsWith(u8, narrow2, " [up]")) return error.TwoDigitNarrowBarLostTheStateWord;
3433 if (narrow2.len > 30) return error.TwoDigitNarrowBarOverranTheTerminal;
3423 3434
3424 // Wide: `cols` alone would have asked for more than `buf` holds, and the 3435 // Wide: `cols` alone would have asked for more than `buf` holds, and the
3425 // failed bufPrint used to hand back the buffer's undefined bytes — with 3436 // failed bufPrint used to hand back the buffer's undefined bytes — with
3426 // the state word among what was lost. 3437 // the state word among what was lost.
3427 const wide = labelText(&buf, 300, "> ", long, "reconnecting"); 3438 const wide = labelText(&buf, 300, "12> ", long, "reconnecting");
3428 try std.testing.expect(std.mem.endsWith(u8, wide, " [reconnecting]")); 3439 if (!std.mem.endsWith(u8, wide, " [reconnecting]")) return error.TwoDigitWideBarLostTheStateWord;
3429 try std.testing.expect(wide.len <= buf.len); 3440 if (wide.len > buf.len) return error.TwoDigitWideBarOverranItsBuffer;
3430 3441
3431 // Wider than `buf` with the longest status word a bar can carry: the 3442 // Wider than `buf` with the longest status word a bar can carry: the
3432 // bound that matters is `buf`'s, and it is not `cols`'. 3443 // bound that matters is `buf`'s, and it is not `cols`'.
3433 const widest = labelText(&buf, 400, " ", long, State.reconnecting.word()); 3444 const widest = labelText(&buf, 400, "12 ", long, State.reconnecting.word());
3434 try std.testing.expect(std.mem.endsWith(u8, widest, " [reconnecting]")); 3445 if (!std.mem.endsWith(u8, widest, " [reconnecting]")) return error.TwoDigitWidestBarLostTheStateWord;
3435 try std.testing.expect(widest.len <= buf.len); 3446 if (widest.len > buf.len) return error.TwoDigitWidestBarOverranItsBuffer;
3436 } 3447 }
3437 3448
3438 /// A wall of `n` tiles with none forgotten. 3449 /// A wall of `n` tiles with none forgotten.
test/e2e.sh
Old New
@@ -1493,7 +1493,7 @@ cleanup() {
1493 "$OUT.sb2cap" "$OUT.sb2cap.err" "$OUT.sb2pc" "$OUT.sb2stop" "$SOCK53" \ 1493 "$OUT.sb2cap" "$OUT.sb2cap.err" "$OUT.sb2pc" "$OUT.sb2stop" "$SOCK53" \
1494 "$OUT.fs.d" "$OUT.fsa" "$OUT.fsa.err" "$OUT.fsb" "$OUT.fsb.err" \ 1494 "$OUT.fs.d" "$OUT.fsa" "$OUT.fsa.err" "$OUT.fsb" "$OUT.fsb.err" \
1495 "$OUT.fscap" "$OUT.fscap.err" "$OUT.fspc" "$OUT.fsfa" "$OUT.fsfb" \ 1495 "$OUT.fscap" "$OUT.fscap.err" "$OUT.fspc" "$OUT.fsfa" "$OUT.fsfb" \
1496 "$OUT.fsstop" "$SOCK54" \ 1496 "$OUT.fsgrid" "$OUT.fsstop" "$SOCK54" \
1497 "$OUT.rsz.d" "$OUT.rszcap" "$OUT.rszcap.err" "$OUT.rszpc" \ 1497 "$OUT.rsz.d" "$OUT.rszcap" "$OUT.rszcap.err" "$OUT.rszpc" \
1498 "$OUT.rsza" "$OUT.rsza.err" "$OUT.rszb" "$OUT.rszb.err" \ 1498 "$OUT.rsza" "$OUT.rsza.err" "$OUT.rszb" "$OUT.rszb.err" \
1499 "$OUT.rszsta" "$OUT.rszstb" "$OUT.rszstop" "$SOCK55" \ 1499 "$OUT.rszsta" "$OUT.rszstb" "$OUT.rszstop" "$SOCK55" \
@@ -7863,6 +7863,21 @@ grep -q "fs-two" "$OUT.fsfb" || {
7863 grep -q "fs-two" "$OUT.fsfa" && { 7863 grep -q "fs-two" "$OUT.fsfa" && {
7864 echo "e2e FAIL: fullscreen: fs-two reached session a, which was hidden after the focus move:" 7864 echo "e2e FAIL: fullscreen: fs-two reached session a, which was hidden after the focus move:"
7865 cat "$OUT.fsfa"; exit 1; } 7865 cat "$OUT.fsfa"; exit 1; }
7866 # What the human saw after Ctrl-\ 2: the `>` moved and the digits did not.
7867 # A bar's digit is the chord that reaches that tile for its whole life, not
7868 # a count of who holds the focus — the render oracle is the only witness,
7869 # since the daemon's grid has no bars in it. The label is cut to the stripe
7870 # at 80 columns beside, so the marker and the head of the spelling are what
7871 # survive; the digit is what tells the two stripes apart.
7872 "$RENDER" --cols 80 --rows 24 < "$OUT.fscap" > "$OUT.fsgrid" || {
7873 echo "e2e FAIL: fullscreen: render oracle failed"
7874 cat "$OUT.fsgrid"; exit 1; }
7875 grep -q -- " 2> --sock" "$OUT.fsgrid" || {
7876 echo "e2e FAIL: fullscreen: Ctrl-\\ 2 did not leave the \`>\` on tile 2's digit:"
7877 cat "$OUT.fsgrid"; exit 1; }
7878 grep -q -- " 1 --sock" "$OUT.fsgrid" || {
7879 echo "e2e FAIL: fullscreen: tile 1 lost its digit or kept the \`>\`:"
7880 cat "$OUT.fsgrid"; exit 1; }
7866 assert_stopped "$SOCK54" "$D55PID" "fullscreen" "$OUT.fsstop" 7881 assert_stopped "$SOCK54" "$D55PID" "fullscreen" "$OUT.fsstop"
7867 D55PID="" 7882 D55PID=""
7868 ok "fullscreen gives the focused tile the terminal; focus follows; f restores" 7883 ok "fullscreen gives the focused tile the terminal; focus follows; f restores"
@@ -8640,6 +8655,19 @@ grep -q -- "#hyb \[up\]" "$OUT.hydgrid" || {
8640 grep -q -- "#hyghost \[refused\]" "$OUT.hydgrid" || { 8655 grep -q -- "#hyghost \[refused\]" "$OUT.hydgrid" || {
8641 echo "e2e FAIL: hydrate-create: the remote tile did not say [refused]:" 8656 echo "e2e FAIL: hydrate-create: the remote tile did not say [refused]:"
8642 cat "$OUT.hydgrid"; exit 1; } 8657 cat "$OUT.hydgrid"; exit 1; }
8658 # ...and each bar carries the chord that reaches it. Ctrl-\ 1-9 focuses by
8659 # POSITION while the bar named the session, and the two series disagree the
8660 # moment a tile is forgotten or a session dies. Tile 1 has the focus here,
8661 # so its digit carries the `>` and the other two the same-width blank.
8662 grep -q -- " 1> .*#hya \[up\]" "$OUT.hydgrid" || {
8663 echo "e2e FAIL: hydrate-create: the focused bar does not read \` 1> \`:"
8664 cat "$OUT.hydgrid"; exit 1; }
8665 grep -q -- " 2 .*#hyb \[up\]" "$OUT.hydgrid" || {
8666 echo "e2e FAIL: hydrate-create: the second tile's bar does not read \` 2 \`:"
8667 cat "$OUT.hydgrid"; exit 1; }
8668 grep -q -- " 3 .*#hyghost \[refused\]" "$OUT.hydgrid" || {
8669 echo "e2e FAIL: hydrate-create: a refused tile lost its chord digit:"
8670 cat "$OUT.hydgrid"; exit 1; }
8643 # The OTHER road a restored line takes: `Ctrl-\ w`. A no-argv `mux wall` 8671 # The OTHER road a restored line takes: `Ctrl-\ w`. A no-argv `mux wall`
8644 # runs the startup tile loop; the fold runs `hydrate()`, a different call 8672 # runs the startup tile loop; the fold runs `hydrate()`, a different call
8645 # site of the same rule, and the ruling covers both. Same daemon, same 8673 # site of the same rule, and the ruling covers both. Same daemon, same