docs/testing-practices.md
Ref: Size: 2.9 KiB History
# Testing rationale The prescriptive development rules live in [CLAUDE.md](../CLAUDE.md); this page records the failures that explain the testing rules there. - **Assert behavior, don't assume it. Mocks are assumptions.** Real binaries, PTYs and shells have caught failures that fixtures standing in for the product could never see. - **A fixture that holds a dimension constant is blind to that dimension.** Where a thing can be plural — sessions, tiles, dials, panes — the DEFAULT fixture is plural; where a thing has an origin, the default is off-origin. N=1 and offset=0 are extra cases, never the baseline. Three escapes in one week were each exactly this, and all three passed a green gate: session names aliased their neighbour's because every test held ONE session; a tile painted over the rail because `col_off` was 0 in every test body; the page's own rules went unpinned because no check executed the page. - **A harness assumption is Linux-only until it has run on both OSes.** The shell scripts are the part of this repo with no compiler behind them, and the e2e suite's first run on macOS was sixteen groups and ten of these. Ask questions through `test/os_oracle.sh` and add an arm rather than a branch in a group file. Three shapes bit hardest and are worth knowing by name. A backtick inside an UNQUOTED heredoc is a command substitution wherever it stands, comments included, and macOS ships programs a Linux box does not — a comment that quoted `expect` started `/usr/bin/expect`, which read the rest of the heredoc as its own script and hung the group for its whole budget. `$TMPDIR` on macOS is a per-user directory that ends in `/` and is nearly fifty characters long, so a path spelled from it fails a string compare against the same path normalised, and does not fit in a label bar. And BSD's `ps` and `wc` answer in a different shape from GNU's — a full path where Linux gives a basename, a padded count where Linux gives a bare number. - **Ask the OS about the OS, not the daemon.** A claim about a pid, an fd, a socket or a process tree is asserted against `/proc`, `ps`, or the shell's own `$$`. A daemon reporting on itself cannot catch itself being wrong — which is why `mux d upgrade`'s gate is a shell pid read off the grid. - A unit test that writes to stdout once wedged `zig build test` at 0 CPU: fd 1 is the test-runner protocol stream. The authoritative rule and the supported capture pattern are in [CLAUDE.md](../CLAUDE.md#working-rules). - A hand-run rig once left dozens of dead host entries because it used the user's XDG state and runtime directories. Use the wrapper described in [development commands](development.md#ad-hoc-reproductions-and-logs), or isolate custom sockets and state yourself. - Debug timings are dominated by ghostty's page-integrity checks. Performance claims belong to the ReleaseSafe throughput path documented in [CLAUDE.md](../CLAUDE.md#working-rules).