98 lines
5.2 KiB
Bash
Executable File
98 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# Red-first regression test for E7 (#1017 task 2): the confirm-check must bind
|
||
# "delivered" to WHETHER THE MESSAGE WAS SUBMITTED, not to which runtime's prompt
|
||
# glyph is present. A pi seat renders a U+2500 rule input box with no ❯/^>/│ >
|
||
# glyph; send-message.sh:118 locates the box only by glyph, so a genuinely
|
||
# delivered message on a glyphless REPL falsely reports exit 2 "may be UNDELIVERED",
|
||
# and the operator's rc=2-driven retry duplicates it.
|
||
#
|
||
# Parameterized on $SEND: RED against the shipping blob (B and D fail), GREEN
|
||
# against a candidate patch. No pi; no fake HOME; hermetic throwaway socket.
|
||
#
|
||
# Submission counting is EXACT and terminal-echo-independent: the fixture message
|
||
# is `echo <tok> >>SINK`; each real submission appends one line. wc -l SINK ==
|
||
# number of times the REPL actually executed the send. This does not depend on how
|
||
# many times the marker string is painted on screen.
|
||
set -u
|
||
SEND="${SEND:?set SEND=/path/to/send-message.sh}"
|
||
SOCKET="glyphagnostic-$$"
|
||
TMP="$(mktemp -d)"
|
||
tmux() { command tmux -L "$SOCKET" "$@"; }
|
||
cleanup() { command tmux -L "$SOCKET" kill-server 2>/dev/null; rm -rf "$TMP"; }
|
||
trap cleanup EXIT
|
||
pass=0; fail=0
|
||
ok() { printf 'ok %s\n' "$1"; pass=$((pass+1)); }
|
||
no() { printf 'FAIL %s -- %s\n' "$1" "$2"; fail=$((fail+1)); }
|
||
|
||
mk() { tmux new-session -d -s "$1" -x 120 -y 40 -c "$TMP" "PS1='$2' exec bash --noprofile --norc -i"; sleep 0.5; }
|
||
subs() { [ -f "$1" ] && wc -l <"$1" | tr -d ' ' || echo 0; } # exact submission count
|
||
|
||
echo "SEND=$SEND tmux $(command tmux -V | awk '{print $2}')"
|
||
|
||
# --- A (control): glyph box (❯) that submits => exit 0, exactly one submission.
|
||
mk ctl '❯ '
|
||
SINK="$TMP/sink.ctl"
|
||
out=$("$SEND" -L "$SOCKET" -t ctl -m "echo x >>'$SINK'" 2>"$TMP/e.ctl"); rc=$?; sleep 0.4
|
||
if [ "$rc" = 0 ] && [ "$(subs "$SINK")" = 1 ]; then
|
||
ok "control: ❯-box submits => exit 0, exactly one submission"
|
||
else no "control: ❯-box submits => exit 0, one submission" "rc=$rc subs=$(subs "$SINK") err=[$(cat "$TMP/e.ctl")]"; fi
|
||
|
||
# --- B (THE false-rc regression): glyphless U+2500 box that SUBMITS. Message lands
|
||
# (subs==1) yet shipping reports exit 2. Must be exit 0.
|
||
mk sub $'──────── \n'
|
||
SINK="$TMP/sink.sub"
|
||
out=$("$SEND" -L "$SOCKET" -t sub -m "echo x >>'$SINK'" 2>"$TMP/e.sub"); rc=$?; sleep 0.4
|
||
if [ "$rc" = 0 ] && [ "$(subs "$SINK")" = 1 ]; then
|
||
ok "glyphless: U+2500 box that submits => exit 0 (delivered, not 'UNDELIVERED')"
|
||
else no "glyphless: U+2500 box that submits => exit 0" \
|
||
"rc=$rc subs=$(subs "$SINK")(delivered=$([ "$(subs "$SINK")" -ge 1 ] && echo yes||echo no)) err=[$(cat "$TMP/e.sub")]"; fi
|
||
|
||
# --- D (duplicate arm): operator follows the rc=2 stderr and retries once. On the
|
||
# glyphless box, shipping => two submissions (the reported duplicate). The
|
||
# property: one logical send => exactly one submission. Same fix closes it.
|
||
mk dup $'──────── \n'
|
||
SINK="$TMP/sink.dup"
|
||
tries=0
|
||
for attempt in 1 2; do
|
||
tries=$((tries+1))
|
||
out=$("$SEND" -L "$SOCKET" -t dup -m "echo x >>'$SINK'" 2>/dev/null); rc=$?
|
||
sleep 0.4
|
||
[ "$rc" = 0 ] && break # operator stops retrying only when told delivered
|
||
done
|
||
if [ "$(subs "$SINK")" = 1 ]; then
|
||
ok "duplicate: one logical send (rc-driven retry) => exactly one submission (tries=$tries)"
|
||
else no "duplicate: one logical send => exactly one submission" "submissions=$(subs "$SINK") tries=$tries"; fi
|
||
|
||
# --- E (faithful hung managed TUI, NOT a cooked shell): raw/no-echo, paints nothing.
|
||
# A cooked `sleep infinity` echoes the paste via the kernel line discipline and
|
||
# false-passes a cursor-row fix that is correct on real seats (measured). So: raw.
|
||
mk_rawstuck() { tmux new-session -d -s "$1" -x 120 -y 40 -c "$TMP" \
|
||
"bash --noprofile --norc -c 'stty -echo -icanon min 1 time 0 2>/dev/null; exec sleep infinity'"; sleep 0.5; }
|
||
mk_rawstuck estuck
|
||
SINK="$TMP/sink.estuck"
|
||
out=$("$SEND" -L "$SOCKET" -t estuck -r 1 -m "this stuck draft was never submitted" 2>/dev/null); rc=$?
|
||
sleep 0.3
|
||
if [ "$rc" != 0 ] && [ "$(subs "$SINK")" = 0 ]; then
|
||
ok "raw/no-echo stuck TUI (not submitted) => non-zero (no false delivered)"
|
||
else no "raw stuck TUI must NOT report delivered" "rc=$rc subs=$(subs "$SINK")"; fi
|
||
|
||
# --- F (busy/queued branch, your BUSY-not-runtime finding): glyphless pane rendering the
|
||
# queued banner, never consuming. QUEUED_RE :113 fires before the glyph grep => rc=0.
|
||
mk_busy() { tmux new-session -d -s "$1" -x 120 -y 40 -c "$TMP" \
|
||
"bash --noprofile --norc -c 'printf \"Press up to edit queued messages\n\"; exec sleep infinity'"; sleep 0.5; }
|
||
mk_busy ebusy
|
||
SINK="$TMP/sink.ebusy"
|
||
out=$("$SEND" -L "$SOCKET" -t ebusy -m "echo x >>'$SINK'" 2>/dev/null); rc=$?; sleep 0.3
|
||
if [ "$rc" = 0 ]; then
|
||
ok "busy/queued-banner glyphless => exit 0 (queued is delivery; runtime owns custody)"
|
||
else no "busy/queued-banner must report delivered" "rc=$rc"; fi
|
||
|
||
# --- C (historical-bug guard): unresolvable target. No pane ever carried our draft
|
||
# => must fail, never infer delivered from absence of a glyph/snippet.
|
||
if out=$("$SEND" -L "$SOCKET" -t "nonexistent-$$" -m "echo x >>'$TMP/sink.wrong'" 2>/dev/null); then
|
||
no "wrong-pane: unresolvable target must NOT report success" "expected non-zero, got 0"
|
||
else ok "wrong-pane: unresolvable target => non-zero (no false delivered)"; fi
|
||
|
||
echo "---"; echo "pass=$pass fail=$fail"
|
||
[ "$fail" = 0 ]
|