examples: test todos.sh with the runner; keep the hand-rolled loop as test-todos-alone.sh.
commit 8dfec622109024bd0898da235bdb4cf7f25202ff · parent e85d9b9d37
· browse this tree
Ximianth, 2026-10-24 14:38:19 UTC
The runner's version is a source line, the exercise function, a rule, and the run. Both feed todos.sh the input as /dev/stdin, so neither needs a temp dir or a sed to normalize it, and both check the same fixtures.
diff --git a/Makefile b/Makefile index 72d5216..cf4999f 100644 --- a/Makefile +++ b/Makefile @@ -30,3 +30,4 @@ check: ## Verify-only and fast; run by the pre-commit hook on every commit. test: ## Run all tests. tests/run.sh examples/test-todos.sh + examples/test-todos-alone.sh diff --git a/examples/test-todos-alone.sh b/examples/test-todos-alone.sh new file mode 100755 index 0000000..e7903c5 --- /dev/null +++ b/examples/test-todos-alone.sh @@ -0,0 +1,25 @@ +#!/bin/bash +## Checks todos.sh against every case in todos.md, as test-todos.sh does, but with the primitives instead of the runner. +## Run with TESTMARK_REGEN=1 to update todos.md to match what todos.sh does now; then review the change with `git diff`. +set -euo pipefail +cd "$(dirname "$0")" +source ../lib/testmark.bash + +testmark_parse doc todos.md +mapfile -t names < <(testmark_names doc) +fails=0 +for name in "${names[@]}"; do + case $name in + */input) + case=${name%/input} + if testmark_check doc "$case/output" < <(testmark_body doc "$name" | ./todos.sh /dev/stdin); then + echo "PASS $case" + else + echo "FAIL $case" + fails=$((fails + 1)) + fi + ;; + esac +done +testmark_write doc +((fails == 0)) diff --git a/examples/test-todos.sh b/examples/test-todos.sh index 61a3ceb..51f1d0c 100755 --- a/examples/test-todos.sh +++ b/examples/test-todos.sh @@ -1,29 +1,11 @@ #!/bin/bash ## Checks todos.sh against every case in todos.md. ## Run with TESTMARK_REGEN=1 to update todos.md to match what todos.sh does now; then review the change with `git diff`. -set -euo pipefail -cd "$(dirname "$0")" -source ../lib/testmark.bash +source "$(dirname "$0")/../lib/testmark.bash" -work=$(mktemp -d) -trap 'rm -rf "$work"' EXIT +exercise_todos() { + ./todos.sh /dev/stdin +} -testmark_parse doc todos.md -mapfile -t names < <(testmark_names doc) -fails=0 -for name in "${names[@]}"; do - case $name in - */input) - case=${name%/input} - testmark_body doc "$name" >"$work/notes.txt" - if testmark_check doc "$case/output" < <(./todos.sh "$work/notes.txt" | sed "s|$work|WORK|g"); then - echo "PASS $case" - else - echo "FAIL $case" - fails=$((fails + 1)) - fi - ;; - esac -done -testmark_write doc -((fails == 0)) +testmarktest_rule_basic '*/input' exercise_todos +testmarktest_run todos.md diff --git a/examples/todos.md b/examples/todos.md index 2d04c3c..4039dfa 100644 --- a/examples/todos.md +++ b/examples/todos.md @@ -5,7 +5,7 @@ todos.sh, by example Each case below is a pair of hunks: `CASE/input` is a file's content, and `CASE/output` is what `todos.sh` prints for that file. -`test-todos.sh` runs every case, with the file in a temporary directory whose path it replaces with `WORK`. +`test-todos.sh` runs every case, handing `todos.sh` the input as `/dev/stdin`. ### the basics @@ -22,8 +22,8 @@ Lines are numbered from one. [testmark]:# (basic/output) ```text -WORK/notes.txt:2:# TODO: handle spaces in names -WORK/notes.txt:4:# TODO: and newlines +/dev/stdin:2:# TODO: handle spaces in names +/dev/stdin:4:# TODO: and newlines ``` @@ -40,8 +40,8 @@ notes: [testmark]:# (verbatim/output) ```text -WORK/notes.txt:2: TODO: indented with a tab -WORK/notes.txt:3: \TODO: with a backslash +/dev/stdin:2: TODO: indented with a tab +/dev/stdin:3: \TODO: with a backslash ```