14cf2f47
test: e2e — the healing leg pins the cut it restores, and names what it cannot
a73x 2026-08-28 19:53
Commit message
test/e2e_12_panes.sh
| Old | New | ||
|---|---|---|---|
| @@ -755,6 +755,16 @@ XDG_STATE_HOME="$LPHSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 \ | |||
| 755 | "$MUX" > "$OUT.lphpc1" 2>&1 <<'EOF' | 755 | "$MUX" > "$OUT.lphpc1" 2>&1 <<'EOF' |
| 756 | expect lph-survivor-0 20000 | 756 | expect lph-survivor-0 20000 |
| 757 | settle 700 20000 | 757 | settle 700 20000 |
| 758 | send \x1cr | ||
| 759 | settle 300 5000 | ||
| 760 | send l | ||
| 761 | settle 300 5000 | ||
| 762 | send l | ||
| 763 | settle 300 5000 | ||
| 764 | send l | ||
| 765 | settle 500 5000 | ||
| 766 | send \x1b | ||
| 767 | settle 500 5000 | ||
| 758 | send \x1cd | 768 | send \x1cd |
| 759 | waitexit 10000 | 769 | waitexit 10000 |
| 760 | EOF | 770 | EOF |
| @@ -802,20 +812,78 @@ set -e | |||
| 802 | echo "e2e FAIL: layout-heal: second ptyclient exited $RC:" | 812 | echo "e2e FAIL: layout-heal: second ptyclient exited $RC:" |
| 803 | cat "$OUT.lphpc2" "$OUT.lphcap2.err"; exit 1; } | 813 | cat "$OUT.lphpc2" "$OUT.lphcap2.err"; exit 1; } |
| 804 | # The wall must not have refused: the ptyclient exited 0 (checked above), | 814 | # The wall must not have refused: the ptyclient exited 0 (checked above), |
| 805 | # and stderr mentions no layout error. The survivor still reaches its | 815 | # and stderr mentions no layout error. |
| 806 | # session — tile 1 is the leaf the sidecar kept, and a marker typed there | 816 | # |
| 807 | # lands in the session that leaf names. | 817 | # The money assertion is that run 2's cut came from the SIDECAR and not |
| 818 | # from the aspect rule. At 80x24 the aspect rule cuts BESIDE — a vertical | ||
| 819 | # rail, a reverse-video column somewhere near 40, which run 1's capture | ||
| 820 | # has and this one must not. A restore that reported failure falls through | ||
| 821 | # to `setRootOrient(rootOrient(size))` and puts that rail back, so its | ||
| 822 | # absence is the heal having run AND won. | ||
| 823 | # | ||
| 824 | # What this leg does NOT claim, because the product does not do it — | ||
| 825 | # measured, with the sidecar read either side of the second run: | ||
| 826 | # | ||
| 827 | # saved by run 1: beside 0 / leaf 43 #0 / leaf 36 #b / focus 0 | ||
| 828 | # after the heal: stacked 0 / leaf 1 #0 / leaf 1 #c / focus 0 | ||
| 808 | # | 829 | # |
| 809 | # The focus is CHOSEN rather than inherited, and deliberately: where a | 830 | # * the survivor's WEIGHT does not survive (43 -> 1) and neither does the |
| 810 | # heal leaves the focus is the restore leg's claim, and that leg makes it | 831 | # container's ORIENTATION (beside -> stacked). Dropping the unmatched |
| 811 | # with no drift in the way. Here the drift is the subject, so the leg | 832 | # leaf collapses the two-child container to a bare leaf, and the |
| 812 | # names the tile it means. | 833 | # newcomer's `insert` then re-wraps that leaf in a fresh STACKED |
| 834 | # container with default weights (`layout.insert`'s root-is-a-leaf | ||
| 835 | # arm). A heal keeps WHICH tiles, never HOW they were cut. | ||
| 836 | # * the focus lands on the newcomer rather than the leaf the record | ||
| 837 | # names, which is why the marker below is typed at a tile this leg | ||
| 838 | # names with `\x1c1` instead of inheriting one. | ||
| 839 | # | ||
| 840 | # Both are defects, not design: a sidecar exists to remember a cut. They | ||
| 841 | # are reported, not fixed here. | ||
| 813 | grep -qi "layout" "$OUT.lphcap2.err" && { | 842 | grep -qi "layout" "$OUT.lphcap2.err" && { |
| 814 | echo "e2e FAIL: layout-heal: stderr mentions layout (heal was not silent):" | 843 | echo "e2e FAIL: layout-heal: stderr mentions layout (heal was not silent):" |
| 815 | cat "$OUT.lphcap2.err"; exit 1; } | 844 | cat "$OUT.lphcap2.err"; exit 1; } |
| 816 | # Two tiles: the survivor and the newcomer. The daemon has 0 and c, and | 845 | # Two tiles: the survivor and the newcomer. The daemon has 0 and c, and |
| 817 | # the tile the sidecar's surviving leaf carries is the one the marker | 846 | # the tile the sidecar's surviving leaf carries is the one the marker |
| 818 | # landed in. | 847 | # landed in. |
| 848 | # A rail is a CUP followed by reverse video; a BESIDE cut puts one in a | ||
| 849 | # column of its own, a stacked cut only ever at column 1 (the label bars). | ||
| 850 | # Spelled here rather than leaning on the earlier legs' copy: a variable | ||
| 851 | # an unrelated block happens to have left set is not an input. | ||
| 852 | _lph_re=$'\x1b\\[[0-9][0-9]*;[0-9][0-9]*H\x1b\\[7m' | ||
| 853 | _lph_cols() { | ||
| 854 | grep -ao "$_lph_re" "$1" | \ | ||
| 855 | sed 's/.*\x1b\[[0-9]*;\([0-9]*\)H\x1b\[7m/\1/' | sort -n | uniq | ||
| 856 | } | ||
| 857 | # Run 1 is the anchor: it really was cut beside and `lll` really moved the | ||
| 858 | # rail, so run 2's silence below is a difference and not an empty capture. | ||
| 859 | _lph_r1=$(_lph_cols "$OUT.lphcap1" | awk '$1 > 1' | tail -1) | ||
| 860 | [ -n "$_lph_r1" ] && [ "$_lph_r1" -ge 43 ] || { | ||
| 861 | echo "e2e FAIL: layout-heal: run 1's rail ended at column ${_lph_r1:-none}, want >= 43" | ||
| 862 | echo " — the resize this leg saves a tree for did not happen" | ||
| 863 | cat "$OUT.lphpc1"; exit 1; } | ||
| 864 | # What run 2 may NOT be is the aspect rule's own cut. Two shapes pass, and | ||
| 865 | # both of them are the sidecar's: | ||
| 866 | # | ||
| 867 | # * no vertical rail — today's heal, which drops the unmatched leaf, | ||
| 868 | # collapses the container and re-wraps STACKED (measured above). | ||
| 869 | # * a rail at the column run 1 dragged the boundary to (>= 43) — a heal | ||
| 870 | # that also kept the saved orientation and weights, which is the fix | ||
| 871 | # the note above says is owed. | ||
| 872 | # | ||
| 873 | # The aspect rule at 80x24 cuts beside down the middle, around column 40, | ||
| 874 | # and that is the one answer neither of those can produce. Asserting "no | ||
| 875 | # rail at all" instead would fail the improvement and blame the restore for | ||
| 876 | # not having run, which is the opposite of what would have happened. | ||
| 877 | _lph_r2=$(_lph_cols "$OUT.lphcap2" | awk '$1 > 1' | tail -1) | ||
| 878 | [ -z "$_lph_r2" ] || [ "$_lph_r2" -ge 43 ] || { | ||
| 879 | echo "e2e FAIL: layout-heal: run 2's vertical rail is at column $_lph_r2 — neither" | ||
| 880 | echo " the sidecar's own cut (>= 43, where run 1 left it) nor the bare" | ||
| 881 | echo " leaf a heal collapses to. The aspect rule cut this wall, so the" | ||
| 882 | echo " saved tree never reached it" | ||
| 883 | cat "$OUT.lphpc2"; exit 1; } | ||
| 884 | # ...and only now the bars, which the cut above is what makes readable: a | ||
| 885 | # stacked stripe is the full 80 columns, and a beside one is 39 — half a | ||
| 886 | # socket path, which `labelText` truncates before it reaches the `#c`. | ||
| 819 | grep -q -- "--sock $SOCK60#c \[up\]" "$OUT.lphcap2" || { | 887 | grep -q -- "--sock $SOCK60#c \[up\]" "$OUT.lphcap2" || { |
| 820 | echo "e2e FAIL: layout-heal: the newcomer never became a tile:" | 888 | echo "e2e FAIL: layout-heal: the newcomer never became a tile:" |
| 821 | cat "$OUT.lphpc2"; exit 1; } | 889 | cat "$OUT.lphpc2"; exit 1; } |