f9c185db
test(e2e): pin the title stack's count, and sweep the leg's residue
a73x 2026-08-15 20:02
Commit message
test/e2e.sh
| Old | New | ||
|---|---|---|---|
| @@ -787,6 +787,10 @@ cleanup() { | |||
| 787 | # the session runs. Spelled from $OUT rather than from a variable of its | 787 | # the session runs. Spelled from $OUT rather than from a variable of its |
| 788 | # own, for the reason the M12 controls above are. | 788 | # own, for the reason the M12 controls above are. |
| 789 | rm -f "$OUT.clip" "$OUT.clip.err" "$OUT.clip.log" "$OUT.clip.sh" | 789 | rm -f "$OUT.clip" "$OUT.clip.err" "$OUT.clip.log" "$OUT.clip.sh" |
| 790 | # The title leg's identical four. Its own rm_swept runs only on success, | ||
| 791 | # so without this line the residue survives exactly the runs where the | ||
| 792 | # leg failed and somebody is looking at it. | ||
| 793 | rm -f "$OUT.title" "$OUT.title.err" "$OUT.title.log" "$OUT.title.sh" | ||
| 790 | # ...and its other half: the paste capture and the file nvim wrote, which | 794 | # ...and its other half: the paste capture and the file nvim wrote, which |
| 791 | # IS that scenario's assertion rather than a log beside it. | 795 | # IS that scenario's assertion rather than a log beside it. |
| 792 | rm -f "$OUT.paste" "$OUT.paste.err" "$OUT.paste.log" "$OUT.pasted.txt" | 796 | rm -f "$OUT.paste" "$OUT.paste.err" "$OUT.paste.log" "$OUT.pasted.txt" |
| @@ -1036,6 +1040,18 @@ grep -q "transport command failed before a session started" "$OUT.dead" || { | |||
| 1036 | grep -q "is muxd installed on the host" "$OUT.dead" && { | 1040 | grep -q "is muxd installed on the host" "$OUT.dead" && { |
| 1037 | echo "e2e FAIL: old lostMsg wording still emitted alongside the new pin" | 1041 | echo "e2e FAIL: old lostMsg wording still emitted alongside the new pin" |
| 1038 | cat "$OUT.dead"; exit 1; } | 1042 | cat "$OUT.dead"; exit 1; } |
| 1043 | # Free ride on this capture, for a property with nothing to do with the exit | ||
| 1044 | # code: this client had NON-TTY stdin and died before any frame, so it is | ||
| 1045 | # the one place in the suite that proves mux does not push a title onto a | ||
| 1046 | # terminal it never took over. An unmatched push is a title stack that only | ||
| 1047 | # grows, and nothing later would pop it — the teardown never runs. | ||
| 1048 | # -F is load-bearing, not decoration: without it `[22;0t` is a malformed | ||
| 1049 | # bracket expression, grep EXITS 2 rather than 1, and `grep && { fail }` | ||
| 1050 | # reads an error as "not found" — an assertion that can never fire. Caught | ||
| 1051 | # by running this needle by hand against a capture known to contain it. | ||
| 1052 | grep -qaF "$(printf '\033[22;0t')" "$OUT.dead" && { | ||
| 1053 | echo "e2e FAIL: a client that entered nothing still pushed the title stack" | ||
| 1054 | cat -v "$OUT.dead"; exit 1; } | ||
| 1039 | 1055 | ||
| 1040 | # M13 spec amendment: a socket path past sun_path's 107 usable bytes is | 1056 | # M13 spec amendment: a socket path past sun_path's 107 usable bytes is |
| 1041 | # refused by name in both binaries, before either acts on it — the failure | 1057 | # refused by name in both binaries, before either acts on it — the failure |
| @@ -2788,6 +2804,9 @@ grep -qa 'TITLEDONE' "$OUT.title" || { | |||
| 2788 | # Terminator included, for the same reason as the clipboard needle: the | 2804 | # Terminator included, for the same reason as the clipboard needle: the |
| 2789 | # builder writes the escape whole or writes nothing, and a needle stopping | 2805 | # builder writes the escape whole or writes nothing, and a needle stopping |
| 2790 | # at the payload could not tell one from half of one. | 2806 | # at the payload could not tell one from half of one. |
| 2807 | # OSC **0**, deliberately, against a fixture that wrote OSC **2** — the | ||
| 2808 | # asymmetry is the instrument, and it is argued at the head of this leg. | ||
| 2809 | # Do not "fix" either side to match the other without reading that. | ||
| 2791 | TITLEESC=$(printf '\033]0;mux-e2e-title\007') | 2810 | TITLEESC=$(printf '\033]0;mux-e2e-title\007') |
| 2792 | grep -qaF "$TITLEESC" "$OUT.title" || { | 2811 | grep -qaF "$TITLEESC" "$OUT.title" || { |
| 2793 | echo "e2e FAIL: the window title never reached the host tty"; exit 1; } | 2812 | echo "e2e FAIL: the window title never reached the host tty"; exit 1; } |
| @@ -2796,18 +2815,33 @@ grep -qaF "$TITLEESC" "$OUT.title" || { | |||
| 2796 | # and popped once — and an unmatched pop does not restore a title, it pops | 2815 | # and popped once — and an unmatched pop does not restore a title, it pops |
| 2797 | # whatever the terminal had underneath, which is somebody else's. The | 2816 | # whatever the terminal had underneath, which is somebody else's. The |
| 2798 | # offsets say: pushed before mux set anything, popped after. | 2817 | # offsets say: pushed before mux set anything, popped after. |
| 2799 | title_off() { | 2818 | first_offset() { |
| 2800 | grep -aboF "$2" "$1" | head -1 | cut -d: -f1 | 2819 | grep -aboF "$2" "$1" | head -1 | cut -d: -f1 |
| 2801 | } | 2820 | } |
| 2802 | PUSH_AT=$(title_off "$OUT.title" "$(printf '\033[22;0t')") | 2821 | occurrences() { |
| 2803 | POP_AT=$(title_off "$OUT.title" "$(printf '\033[23;0t')") | 2822 | grep -aoF "$2" "$1" | wc -l |
| 2804 | SET_AT=$(title_off "$OUT.title" "$TITLEESC") | 2823 | } |
| 2824 | PUSH_ESC=$(printf '\033[22;0t') | ||
| 2825 | POP_ESC=$(printf '\033[23;0t') | ||
| 2826 | PUSH_AT=$(first_offset "$OUT.title" "$PUSH_ESC") | ||
| 2827 | POP_AT=$(first_offset "$OUT.title" "$POP_ESC") | ||
| 2828 | SET_AT=$(first_offset "$OUT.title" "$TITLEESC") | ||
| 2805 | [ -n "$PUSH_AT" ] || { echo "e2e FAIL: no title push on the host tty"; exit 1; } | 2829 | [ -n "$PUSH_AT" ] || { echo "e2e FAIL: no title push on the host tty"; exit 1; } |
| 2806 | [ -n "$POP_AT" ] || { echo "e2e FAIL: no title pop on the host tty (exit left it set)"; exit 1; } | 2830 | [ -n "$POP_AT" ] || { echo "e2e FAIL: no title pop on the host tty (exit left it set)"; exit 1; } |
| 2807 | [ "$PUSH_AT" -lt "$SET_AT" ] || { | 2831 | [ "$PUSH_AT" -lt "$SET_AT" ] || { |
| 2808 | echo "e2e FAIL: mux set the title at $SET_AT before pushing at $PUSH_AT"; exit 1; } | 2832 | echo "e2e FAIL: mux set the title at $SET_AT before pushing at $PUSH_AT"; exit 1; } |
| 2809 | [ "$SET_AT" -lt "$POP_AT" ] || { | 2833 | [ "$SET_AT" -lt "$POP_AT" ] || { |
| 2810 | echo "e2e FAIL: the title pop at $POP_AT came before the set at $SET_AT"; exit 1; } | 2834 | echo "e2e FAIL: the title pop at $POP_AT came before the set at $SET_AT"; exit 1; } |
| 2835 | # Exactly one of each, which order alone does not catch. A second push is a | ||
| 2836 | # stack this run leaves one deeper than it found it, and the argument that | ||
| 2837 | # it cannot happen — the reconnect path re-enters with alt_screen already | ||
| 2838 | # true (client.zig) — was prose with no test behind it until here. | ||
| 2839 | PUSH_N=$(occurrences "$OUT.title" "$PUSH_ESC") | ||
| 2840 | POP_N=$(occurrences "$OUT.title" "$POP_ESC") | ||
| 2841 | [ "$PUSH_N" -eq 1 ] || { | ||
| 2842 | echo "e2e FAIL: $PUSH_N title pushes on one run, want exactly 1"; exit 1; } | ||
| 2843 | [ "$POP_N" -eq 1 ] || { | ||
| 2844 | echo "e2e FAIL: $POP_N title pops on one run, want exactly 1"; exit 1; } | ||
| 2811 | rm_swept "$OUT.title" "$OUT.title.err" "$OUT.title.log" "$OUT.title.sh" | 2845 | rm_swept "$OUT.title" "$OUT.title.err" "$OUT.title.log" "$OUT.title.sh" |
| 2812 | ok "the window title reaches the host as OSC 0, pushed before and popped after" | 2846 | ok "the window title reaches the host as OSC 0, pushed before and popped after" |
| 2813 | 2847 | ||