testmark-bash

lib.sh

#!/bin/bash
## Shared helpers for the testmark-bash tests.  Sourced, not executed.
## Sources the library, makes a scratch dir and cd's into it, and provides PASS/FAIL reporting.
## The helpers stay exact under the unusual settings test-caller-env.sh turns on:
## comparisons use `[ = ]`, which `nocasematch` doesn't touch.
# shellcheck disable=SC2034 # RESULT is read by the test scripts

set -euo pipefail

ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
TESTDATA=$ROOT/tests/testdata
# shellcheck source=lib/testmark.bash
source "$ROOT/lib/testmark.bash"

RESULT=0
work=$(mktemp -d)
exec {stderr}>&2
trap _exit EXIT
cd "$work"

## A nonzero exit with no FAIL row means the script died, maybe with the library's message in $work/err; this shows it before deleting $work.
## It writes to the saved stderr: a shell that dies inside a redirect runs this trap with the redirect still in place.
_exit() {
	local rc=$?
	if ((rc != 0 && RESULT == 0)) && [[ -s $work/err ]]; then
		>&"$stderr" printf 'died (exit %s); last captured stderr:\n%s\n' "$rc" "$(<"$work/err")"
	fi
	rm -rf "$work"
}

_pass() {
	printf 'PASS  %s\n' "$1"
}

_fail() {
	printf 'FAIL  %s\n' "$1"
	RESULT=1
}

## - @param $1 description
## - @param $2 got
## - @param $3 want
## - @stdout one PASS or FAIL line
## - @state RESULT -- set to 1 on failure
expect_eq() {
	if [ "$2" = "$3" ]; then
		_pass "$1"
	else
		_fail "$1"$'\n'"--- got:"$'\n'"$2"$'\n'"--- want:"$'\n'"$3"
	fi
}

## Runs a command that should fail, and checks it printed exactly the given error and nothing on stdout.
##
## - @param $1 description
## - @param $2 the expected stderr, without its final newline
## - @param $3... the command
expect_fail() {
	local rc=0
	"${@:3}" >"$work/out" 2>"$work/err" || rc=$?
	if [[ $rc == 0 ]]; then
		_fail "$1: succeeded; want a failure"
	else
		expect_eq "$1" "$(<"$work/err")$(<"$work/out")" "$2"
	fi
}

## Runs a command in this shell, so it can change state, and checks it succeeded with nothing on stderr.
##
## - @param $1 description
## - @param $2... the command
expect_ok() {
	local rc=0
	"${@:2}" 2>"$work/err" || rc=$?
	expect_eq "$1" "$rc $(<"$work/err")" "0 "
}

## Quotes bytes the way the conformance harnesses do: printable ASCII as is, escapes for the rest.
##
## - @param $1 bytes
## - @stdout the quoted string, without a newline
esc() {
	local LC_ALL=C s=$1 out='' c i
	for ((i = 0; i < ${#s}; i++)); do
		c=${s:i:1}
		case $c in
		'\') out+='\\' ;;
		'"') out+='\"' ;;
		$'\n') out+='\n' ;;
		$'\r') out+='\r' ;;
		$'\t') out+='\t' ;;
		[\ -~]) out+=$c ;;
		*)
			printf -v c '\\x%02x' "'$c"
			out+=$c
			;;
		esac
	done
	printf '"%s"' "$out"
}

## - @param $1 file
## - @stdout the file's bytes, exactly, quoted by `esc`
bytes() {
	local s
	IFS= read -r -d '' s <"$1" || : # 1 is end of file; the test files hold no NUL
	esc "$s"
}

## Prints every hunk of a parsed document: `hunk`, `info`, and `body` lines, values quoted by `esc`.
##
## - @param $1 handle
## - @stdout the dump
dump() {
	local names name body
	mapfile -t names < <(testmark_names "$1")
	for name in "${names[@]}"; do
		body=$(testmark_body "$1" "$name" && printf x) || return
		printf 'hunk %s\ninfo %s\nbody %s\n' "$(esc "$name")" "$(esc "$(testmark_info "$1" "$name")")" "$(esc "${body%x}")"
	done
}

## Parses FILE as handle "doc", and prints its dump, or "error: " and the error message.
## A successful parse that still wrote to stderr gets a "stderr: " line too.
##
## - @param $1 file
## - @stdout the dump or the error
dump_parse() {
	if testmark_parse doc "$1" 2>"$work/err"; then
		dump doc
		[[ ! -s $work/err ]] || printf 'stderr: %s\n' "$(<"$work/err")"
	else
		printf 'error: %s\n' "$(<"$work/err")"
	fi
}

## Parses a document given as a printf format, and checks its dump against the expected lines.
##
## - @param $1 case name
## - @param $2 document, as a printf format
## - @param $3... expected dump lines
parse_case() {
	printf -- "$2" >in.md
	dump_parse in.md >got # not in $(...), so a library bug that kills the shell kills this script too
	expect_eq "$1" "$(<got)" "$(printf '%s\n' "${@:3}")"
}

tests/lib.sh · 4.0 KiB · 4a4248cccf