test-api.sh
#!/bin/bash
## The read API: handles, errors, and exact output.
set -euo pipefail
cd "$(dirname "$0")"
# shellcheck source=tests/lib.sh
source ./lib.sh
printf '[testmark]:# (x)\n```text\none\n```\n[testmark]:# (old)\n```\ngone\n```\n' >a.md
printf '[testmark]:# (x)\n```\ntwo\n```\n' >b.md
printf 'no hunks here\n' >none.md
: >empty.md
# --- output is exact, and travels through files ---
testmark_parse doc a.md
testmark_names doc >out
expect_eq "names: one per line, in document order" "$(od -c out)" "$(printf 'x\nold\n' | od -c)"
testmark_body doc x >out
expect_eq "body: exact bytes" "$(od -c out)" "$(printf 'one\n' | od -c)"
testmark_info doc x >out
expect_eq "info: then a newline" "$(od -c out)" "$(printf 'text\n' | od -c)"
testmark_parse doc none.md
testmark_names doc >out
expect_eq "names: nothing, for no hunks" "$(wc -c <out)" "0"
# --- several handles at once, and re-parsing ---
testmark_parse a a.md
testmark_parse b b.md
testmark_parse e empty.md
expect_eq "handle a" "$(testmark_body a x)" "one"
expect_eq "handle b" "$(testmark_body b x)" "two"
expect_fail "an empty doc doesn't see another doc's hunks" "testmark: $work/empty.md: no hunk named \"x\"" testmark_body e x
expect_ok "re-parse" testmark_parse a b.md
expect_eq "re-parse replaces the doc" "$(testmark_body a x)" "two"
expect_fail "re-parse drops the old doc's names" "testmark: $work/b.md: no hunk named \"old\"" testmark_body a old
expect_eq "re-parse leaves other handles alone" "$(testmark_body b x)" "two"
expect_ok "re-parse of the same file" testmark_parse b b.md
expect_eq "and it reads" "$(testmark_body b x)" "two"
expect_fail "a failed re-parse fails" 'testmark: missing.md: not a readable file' testmark_parse b missing.md
expect_fail "and leaves its handle unusable" 'testmark: unknown handle "b"' testmark_names b
# --- what a parse doesn't keep is gone: white-box, comparing every library global and its value ---
printf '[testmark]:# (x)\n```\none\n```\n[testmark]:# (y)\n' >dangling.md
## - @stdout `declare -p` of every `_testmark_*` global
globals() {
local vars
mapfile -t vars < <(compgen -v _testmark_)
declare -p "${vars[@]}"
}
before=$(globals)
testmark_parse g a.md
expect_fail "a parse that fails late" 'testmark: dangling.md:5: annotation not followed by a code block' testmark_parse g dangling.md
expect_eq "leaves no globals for its handle, of the old doc or the partial one" "$(globals)" "$before"
testmark_parse g b.md
before=$(globals)
testmark_parse g a.md
testmark_parse g b.md
expect_eq "a re-parse leaves nothing of the old doc" "$(globals)" "$before"
# --- sourcing: twice keeps state; inside a function still makes globals ---
testmark_parse s a.md
# shellcheck source=lib/testmark.bash
source "$ROOT/lib/testmark.bash"
expect_eq "sourcing again keeps open docs" "$(testmark_body s x)" "one"
expect_eq "sourcing inside a function" "$(
"$BASH" -c 'f() { source "$1"; }; f "$1"; testmark_parse d1 a.md; testmark_parse d2 b.md; testmark_body d1 x' _ "$ROOT/lib/testmark.bash"
)" "one"
# --- errors ---
testmark_parse r a.md
expect_fail "unknown handle" 'testmark: unknown handle "nope"' testmark_body nope x
expect_fail "unknown hunk" "testmark: $work/a.md: no hunk named \"nope\"" testmark_info r nope
expect_fail "invalid handle" 'testmark: invalid handle "a-b": must match [A-Za-z0-9_]+' testmark_parse a-b a.md
expect_fail "empty handle" 'testmark: invalid handle "": must match [A-Za-z0-9_]+' testmark_parse '' a.md
expect_fail "directory" 'testmark: .: not a readable file' testmark_parse r .
expect_fail "parse arity" 'testmark: usage: testmark_parse HANDLE FILE' testmark_parse r
expect_fail "names arity" 'testmark: usage: testmark_names HANDLE' testmark_names
expect_fail "body arity" 'testmark: usage: testmark_body HANDLE NAME' testmark_body r x y
expect_fail "info arity" 'testmark: usage: testmark_info HANDLE NAME' testmark_info r
# --- names with shell syntax: plain data, never evaluated ---
names=('$(>pwned1)' '`>pwned2`' 'a]b' 'x[0]' '@' '*' '$HOME' "'q'" '"q"' 'a\b')
for name in "${names[@]}"; do
printf '[testmark]:# (%s)\n```\nbody of %s\n```\n\n' "$name" "$name"
done >syntax.md
testmark_parse h syntax.md
mapfile -t got < <(testmark_names h)
expect_eq "names with shell syntax: list" "$(printf '%s\n' "${got[@]}")" "$(printf '%s\n' "${names[@]}")"
for name in "${names[@]}"; do
expect_eq "name $name" "$(testmark_body h "$name")" "body of $name"
done
expect_fail "an unknown name with shell syntax" "testmark: $work/syntax.md: no hunk named \"\$(>pwned3)\"" testmark_body h '$(>pwned3)'
expect_fail "a handle with shell syntax" 'testmark: invalid handle "h[$(>pwned4)]": must match [A-Za-z0-9_]+' testmark_body 'h[$(>pwned4)]' x
expect_eq "nothing was executed" "$(echo pwned*)" "pwned*"
exit "$RESULT"
tests/test-api.sh · 4.6 KiB · 0c4d3ffbad