From 9af0462d29745b27b304b72c82d4ccd325322656 Mon Sep 17 00:00:00 2001 From: Rootiest Date: Wed, 9 Sep 2026 15:41:39 -0400 Subject: [PATCH] test(config-settings): cover the empty state dump refusal The guard added in 208ad95 had no test. This is the failure worth covering, because it is the one that does not announce itself: with an empty dump every row renders as DEFAULT, indistinguishable from a config where nothing is set, so the user toggles from a false baseline. Reaching the guard needs a real terminal -- the isatty check sits in front of it -- so the case runs fish under a pty via python3's stdlib pty module, which this suite already depends on. An empty __config_settings_state is shadowed in to fake the failure. The pty reader's 15s deadline is load-bearing rather than defensive: if the guard regresses, config-settings does not fail, it opens the TUI and blocks on getch(), so an unbounded read would hang the suite instead of failing it. Verified both ways -- passes with the guard, and with the guard removed the deadline fires and the case fails with a legible excerpt rather than a screenful of escape sequences. --- tests/test-config-settings-tui.fish | 71 +++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/test-config-settings-tui.fish b/tests/test-config-settings-tui.fish index 7932884..8e4922c 100755 --- a/tests/test-config-settings-tui.fish +++ b/tests/test-config-settings-tui.fish @@ -53,4 +53,75 @@ function test_no_tty_is_refused_cleanly end check "no TTY is refused with a message, not a curses crash" true (test_no_tty_is_refused_cleanly; and echo true; or echo false) +# An empty state dump is the dangerous failure, because it is not one: the TUI +# would render every row as DEFAULT, which is indistinguishable from a config +# where nothing is set. The user would be looking at ON rows reported as OFF's +# neighbour and toggling from a false baseline. The launcher must refuse. +# +# Reaching that guard needs a real terminal -- the isatty check sits in front +# of it -- so this runs fish under a pty. python3 is already a hard +# prerequisite of this suite (see the header), so its stdlib pty module costs +# no new dependency; `script` would. +# +# The deadline is load-bearing, not belt-and-braces. If the guard regresses, +# config-settings does not fail -- it opens the TUI and blocks on getch(), +# so an unbounded read here would hang the suite instead of failing it. +set -l pty_runner ' +import os, pty, select, signal, sys, time +pid, fd = pty.fork() +if pid == 0: + os.execvp("fish", ["fish", "--no-config", "-c", sys.argv[1]]) +deadline, out = time.monotonic() + 15, b"" +while time.monotonic() < deadline: + if not select.select([fd], [], [], deadline - time.monotonic())[0]: + break + try: + chunk = os.read(fd, 65536) + except OSError: + break + if not chunk: + break + out += chunk +else: + out += b"\nTIMEOUT: the TUI opened and blocked on input\n" +try: + os.kill(pid, signal.SIGKILL) +except ProcessLookupError: + pass +os.waitpid(pid, 0) +sys.stdout.write(out.decode("utf-8", "replace")) +' + +function test_empty_state_dump_is_refused --argument-names runner + # Shadowing the autoloaded __config_settings_state with an empty function + # is what fakes the failure; a real dump always carries the taxonomy. + set -l cmd "set -p fish_function_path $repo_root/functions; + function __config_settings_state; end; + config-settings; + echo RC=\$status" + set -l out (python3 -c "$runner" "$cmd" | string collect) + + set -l failed 0 + if not string match -q '*produced no output*' -- $out + # A regression here means the TUI drew itself, so $out is a screenful + # of escape sequences. Strip them and keep a usable excerpt. + set -l seen (string replace -ra '\e\[[0-9;?]*[a-zA-Z]|\e[()][A-Z]' '' -- $out \ + | string join ' ' | string sub -l 120) + echo " expected the empty-dump refusal, got: $seen" + set failed 1 + end + if not string match -q '*RC=1*' -- $out + echo " expected exit status 1 from the refusal" + set failed 1 + end + # Guard the guard: if the pty were not a terminal we would be watching the + # isatty check fire and would learn nothing about the dump. + if string match -q '*needs a terminal*' -- $out + echo " the isatty guard fired -- the pty did not present a terminal" + set failed 1 + end + test $failed -eq 0 +end +check "an empty state dump is refused, not rendered as all-DEFAULT" true (test_empty_state_dump_is_refused "$pty_runner"; and echo true; or echo false) + report