testmark-bash

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 · 0bd1c47577