diff --git a/scripts/tests.sh b/scripts/tests.sh new file mode 100755 index 0000000..d59651d --- /dev/null +++ b/scripts/tests.sh @@ -0,0 +1,229 @@ +#!/usr/bin/env sh + +# Parts of a shell library {{{ +die() { + error "$1"; + if [ -n "$2" ]; then + exit "$2"; + else + exit 1; + fi +} + +print() { + # The direct usage is intended as `print` is rather lowlevel + # shellcheck disable=2059 + printf "$*"; +}; +println() { + # The direct usage is intended as `println` is rather lowlevel + # shellcheck disable=2059 + printf "$*\n"; +}; +eprint() { + >&2 print "$@"; +}; +eprintln() { + >&2 println "$@"; +}; + +if [ -n "$NO_COLOR" ];then + error() { + eprintln "==> ERROR:" "$*"; + }; + warning() { + eprintln "==> WARNING:" "$*"; + }; + debug() { + [ -n "$SHELL_LIBRARY_DEBUG" ] && eprintln "==> [Debug:]" "$*"; + }; + debug2() { + [ -n "$SHELL_LIBRARY_DEBUG" ] && eprintln " -> [Debug:]" "$*"; + }; + msg() { + eprintln "==>" "$*"; + }; + msg2() { + eprintln " ->" "$*"; + }; + prompt() { + eprint "..>" "$*"; + }; +else + # See https://stackoverflow.com/a/33206814 for ansi codes + error() { + eprintln "\033[1;91m==> ERROR:\033[0m" "\033[1;93m$*\033[0m"; + }; + warning() { + eprintln "\033[1;91m==> WARNING:\033[0m" "\033[1;93m$*\033[0m"; + }; + debug() { + [ -n "$SHELL_LIBRARY_DEBUG" ] && eprintln "\033[1;94m==> [Debug:]\033[0m" "\033[1;93m$*\033[0m"; + }; + debug2() { + [ -n "$SHELL_LIBRARY_DEBUG" ] && eprintln "\033[1;94m -> [Debug:]\033[0m" "\033[1;93m$*\033[0m"; + }; + msg() { + eprintln "\033[1;96m==>\033[0m" "\033[1;93m$*\033[0m"; + }; + msg2() { + eprintln "\033[1;96m ->\033[0m" "\033[1;93m$*\033[0m"; + }; + prompt() { + eprint "\033[1;96m..>\033[0m" "\033[1;93m$*\033[0m"; + }; +fi + +mktmp() { + ensure_tmp_dir; + mktemp -p "$SHELL_LIBRARY_TEMP_PREFIX_DIR"; +} + +ensure_tmp_dir() { + if ! [ -d "$SHELL_LIBRARY_TEMP_PREFIX_DIR" ];then + SHELL_LIBRARY_TEMP_PREFIX_DIR="$(mktemp -d)"; + fi +}; + +# A new version of tmp, which allows you to specify the commandline args as normal +# arguments +tmp() { + if echo "$1" | grep -E ' ' -q; then + warn "Detected an old version of tmp, as there are spaces in the input string!" + fi + + TEMP_DIR_WITH_DEL="$(mktmp)"; + "$@" 1> "$TEMP_DIR_WITH_DEL"; + echo "$TEMP_DIR_WITH_DEL"; +}; + +# Takes a path to search as argument. +# Also takes further arguments as names to search for. +# Prints the path to a file, if a file matching the given name is found. +search_dir_for_file() { + [ -d "$1" ] || die "Arg $1 is not a directory"; + directory="$1" && shift 1; + + while read -r dir_entry; do + dir_entry_count=$((dir_entry_count + 1)); + dir_entry_basename="$(basename "$dir_entry")"; + + for name in "$@";do + if [ "$name" = "$dir_entry_basename" ]; then + println "$dir_entry"; + fi + done + done < "$(tmp fd . "$directory" --type file --max-depth 1)" + print ""; +} + +# Returns the path to the directory which contains all the specified files: +# `search_upward_files file1 file2 file3` returns a path containing file1 ... +search_upward_files() { + directory="$(pwd)"; + final_directory=""; + output="$(mktmp)"; + while [ "$(wc -l < "$output")" = 0 ]; do + search_dir_for_file "$directory" "$@" > "$output"; + directory="$(dirname "$directory")"; + if [ "$directory" = "/" ]; then + warning "We bailed out, as there seems to be no directory containing $*"; + final_directory=""; + return; + fi + done + final_directory="$(dirname "$(head -n1 "$output")")"; + print "$final_directory"; +} +# }}} + + +help() { + cat << EOF +A test manager (for trixy integration tests) + +USAGE: + ./scripts/tests [OPTIONS] COMMAND + +OPTIONS: + --help | -h + Display this help and exit. + +COMMANDS: + update [TESTNAME] + Updates the 'expected.md' file of a test with TESTNAME, if + TESTNAME is blank, all tests are updated. + + new TESTNAME + Generates a new test from the '.template' directory and drops + you into an editor for the 'input.tri' file. + It will also generate the 'expected.md' file, after you close + the editor. + +ARGUMENTS: + TESTNAME | *([a-zA-Z0-9]) := [[ false ]] + The name of a test. + (The notation above is only really useful, when + the shell library is employed to generate + a completion script.) + +EOF +} + +ROOT_DIR="$(search_upward_files "Cargo.toml")"; + +new() { + test_name="$1"; + test_dir="$ROOT_DIR/tests/$test_name"; + + [ -d "$test_dir" ] && die "$test_dir already exists, refusing to override" + + cp --recursive "$ROOT_DIR/tests/.template" "$test_dir" + + sed --in-place "s|template|$test_name|g" "$test_dir/main.rs" + + editor="${EDITOR:-$VI}" + "$editor" "$test_dir/input.tri" + update "$test_name" +} + +update() { + test_name="$1" + test_dir="$ROOT_DIR/tests/$test_name"; + + if [ -n "$test_name" ]; then + cargo run --features build-binary -- \ + "$test_dir/input.tri" generate all --no-vendored \ + > "$test_dir/expected.md" + else + fd . "$ROOT_DIR/tests" --type directory --max-depth=1 --exec basename | while read -r dir; do + msg2 "Updating $dir.." + update "$dir" + done + fi +} + +for arg in "$@"; do + case "$arg" in + "--help" | "-h") + help; + exit 0; + ;; + esac +done + + +case "$1" in + "update") + shift 1; + [ -n "$1" ] && test_name="$1" + update "$test_name"; + ;; + "new") + shift 1; + test_name="$1"; + [ -z "$test_name" ] && die "You must specify a TESTNAME" + new "$test_name"; + ;; +esac +# vim: ft=sh