testcase.bash
## testcase.bash: the functions a case function of testmarktest_rule calls, to read hunks and give its outputs.
## Not sourced by testmark.bash: the runner sends this file's text into each case's own bash.
## They run under the case's `set -euo pipefail`, but may be called where errexit is ignored, so they check every status themselves.
## Their contract is documented with testmarktest_rule, in testmark.bash.
# shellcheck disable=SC2154 # _testcase_case, _testcase_index, and _testcase_blob are set by the case's script
testcase_read_myhunk() {
(($# == 1)) || {
>&2 echo "usage: testcase_read_myhunk NAME"
return 1
}
_testcase_read testcase_read_myhunk "$_testcase_case/$1"
}
testcase_read_anyhunk() {
(($# == 1)) || {
>&2 echo "usage: testcase_read_anyhunk NAME"
return 1
}
_testcase_read testcase_read_anyhunk "$1"
}
## Prints the body of hunk $2; $1 is the public function asking, for the message.
_testcase_read() {
local - LC_ALL=C IFS=$'\n' entry at
set -f
# Each index line is "NAME OFFSET LENGTH", and names hold no whitespace, so "NAME " starts exactly one line.
for entry in $_testcase_index; do
[[ $entry == "$2 "* ]] || continue
at=${entry#"$2 "}
printf '%s' "${_testcase_blob:${at% *}:${at#* }}"
return
done
>&2 printf '%s: no hunk named "%s"\n' "$1" "$2"
return 1
}
testcase_output() {
local LC_ALL=C body
(($# == 1)) || {
>&2 echo "usage: testcase_output NAME <OUTPUT"
return 1
}
[[ -n $1 && $1 != /* && $1 != *[[:space:]]* ]] || {
>&2 printf 'testcase_output: "%s" is not an output name: it names a hunk in the case, so it has no leading "/", and no whitespace\n' "$1"
return 1
}
# Status 0 means read stopped at a NUL, which no hunk can hold.
if IFS= read -r -d '' body; then
>&2 printf 'testcase_output: %s: output contains a NUL byte\n' "$1"
return 1
fi
printf 'o %d %s\n%s' "${#body}" "$1" "$body" >&3
}
testcase_withtmpdir() {
local dir
(($# == 0)) || {
>&2 echo "usage: testcase_withtmpdir"
return 1
}
dir=$(mktemp -d) || return 1
# shellcheck disable=SC2064 # expanded now, on purpose: the trap outlives this function's locals
trap "rm -rf -- $(printf %q "$dir")" EXIT
cd "$dir" || return 1
}
## Reads the case function's stdout and stderr to the end, then sends them to the runner as one frame.
## The end comes only once everything that could write to them has exited, so this frame is the last.
_testcase_stream() {
local LC_ALL=C stream
if IFS= read -r -d '' stream; then
while IFS= read -r -d '' _; do :; done
stream+=$'\ntestmark: the output contains a NUL byte\n'
fi
printf 's %d\n%s' "${#stream}" "$stream" >&3
}
lib/testmark/testcase.bash · 2.6 KiB · e556796862