# shout Transcript-based shell integration test runner. Rust. ## Commands - `cargo test` — run tests (integration tests in `tests/shout.rs`) - `cargo build` — build the binary - `cargo run -- test [files...]` — run shout CLI - `-u, --update` — rewrite `.shout` files with actual output - `-k, --keep` — keep temp directories after run - `--clean-env` — start with empty environment - `--path ` — prepend to `$PATH` (repeatable) - `--timeout ` — per-command timeout (default `10s`) - `-t, --filter ` — only run files whose path contains `` - `-v, --verbose` — print each command as it runs - `--port-from ` — auto-assign `$PORT` starting from n (default `5400`) - `--parallel` — run files in parallel ## Architecture - `src/main.rs` — CLI entry point, arg parsing, file discovery, `run_one` orchestration - `src/parse.rs` — parses `.shout` files into `ShoutFile` (list of `Command`), also `parse_setup` - `src/run.rs` — executes commands via `/bin/sh`, captures output with sentinels - `src/matching.rs` — wildcard-aware output matching and diff generation - `src/format.rs` — evaluates pass/fail, formats failures and summary - `src/update.rs` — rewrites `.shout` files with actual output (`--update` mode) - `src/duration.rs` — parses duration strings (`10s`, `500ms`, `1m`) - `web/index.html` — web documentation page ## .shout file format - `$ ` prefix = command to execute - Lines between commands = expected output (stdout+stderr merged) - `...` on its own line = multi-line wildcard (matches zero or more lines) - `...` inline = matches any characters on that line - `[N]` on last line of expected output = assert exit code N - `[*]` = assert any non-zero exit code; default expects 0 - `$#` comment line = not executed, no output expected (e.g. `$# start the server`) - `#` after a command = comment (stripped); `#` in expected output is literal - `@env KEY=VALUE` before first command = set environment variable - `@teardown ` before first command = run command after all test commands - Runs regardless of pass/fail - Teardown failures produce warnings but don't affect test results - Can appear in both `.shout` files and setup files - `@setup path.shout` before first command = prepend commands (and `@env`) from another file - Setup files use a plain format: each line is a command (no `$ ` prefix), `#` lines are comments, blank lines ignored - Setup files can contain `@env`, `@teardown`, and `@def` directives but not `@setup` (no nesting) - User file `@env` overrides setup file `@env` - Setup command failures abort the test with an error - `@def name body` before first command = define a macro - If a command matches `name` exactly, `body` is substituted before execution - Backslash `\` at end of line continues the body onto the next line - Allowed in both `.shout` files and setup files - User file `@def` overrides setup file `@def` with the same name - Each file runs in a fresh temp dir with a single `/bin/sh` session - `$HOME` and `$SHOUT_DIR` are set to the temp dir automatically - `$SHOUT_SOURCE_DIR` is set to the directory containing the `.shout` file - `$SHOUT_PROJECT_DIR` is set to `cwd` where `shout` was invoked - stdout and stderr are merged (`exec 2>&1`) ## New feature checklist 1. `src/parse.rs` — update types (`Directive`, `ShoutFile`, `Command`) and both parsers (`parse` + `parse_setup`) 2. `src/main.rs` — wire up the parsed result in `run_one` (directive resolution, command merging, result handling) 3. `tests/*.shout` — integration test file exercising the feature end-to-end 4. `CLAUDE.md` — update `.shout file format` section 5. `README.md` — update Directives section 6. `web/index.html` — add or update a section on the website 7. Run `cargo test` to verify ## Style - Rust 2024 edition - No OOP — plain functions and structs/enums - Integration tests in `tests/shout.rs`, example `.shout` files in `tests/`