Validate the complete deterministic scripts/tests inventory before executing any test. Reject non-executable, unreadable, symlinked, malformed, and empty inventories explicitly, and cover the behavior with Bash 3.2-compatible regression fixtures.
- commit
- 3ad952a7cea1a75524a1b88886bb7764fcd4e174
- parent
- bb4cb785c453c30ae9245131ae9d154a9d0c0a34
- author
- Dami <dami.etoile@gmail.com>
| A | scripts/ | 61 | ++++++++++++++++++ |
| A | scripts/ | 99 | ++++++++++++++++++++++++++++++ |
| M | scripts/ | 4 | +- |
@@ -0,0 +1,61 @@
1+2+3+set -euo pipefail4+5+LC_ALL=C6+export LC_ALL7+8+test_dir="${1:-}"9+if [[ -z "$test_dir" ]]; then10+ printf 'usage: %s TEST_DIRECTORY\n' "${0##*/}" >&211+ exit 212+fi13+if [[ -L "$test_dir" || ! -d "$test_dir" ]]; then14+ printf 'shell test directory must be a real directory: %s\n' "$test_dir" >&215+ exit 116+fi17+if [[ ! -r "$test_dir" || ! -x "$test_dir" ]]; then18+ printf 'shell test directory must be readable and searchable: %s\n' "$test_dir" >&219+ exit 120+fi21+22+# Bash expands this array in LC_ALL=C order. dotglob makes a test such as23+# `.release-contract.sh` part of the same inventory, while nullglob lets us24+# diagnose an empty inventory instead of trying to execute a literal glob.25+shopt -s dotglob nullglob26+shell_tests=("$test_dir"/*.sh)27+shopt -u dotglob nullglob28+29+if (( ${#shell_tests[@]} == 0 )); then30+ printf 'no shell tests were discovered in: %s\n' "$test_dir" >&231+ exit 132+fi33+34+# Validate the complete inventory before running its first entry. This keeps a35+# malformed or non-executable test late in the sort order from producing a36+# partially successful gate.37+for shell_test in "${shell_tests[@]}"; do38+ printf 'shell_test_discovered=%s\n' "$shell_test"39+ if [[ "$shell_test" == *$'\n'* || "$shell_test" == *$'\r'* ]]; then40+ printf 'shell test path contains an unsafe line break: %q\n' "$shell_test" >&241+ exit 142+ fi43+ if [[ -L "$shell_test" || ! -f "$shell_test" ]]; then44+ printf 'shell test entry must be a regular, non-symlink file: %s\n' \45+ "$shell_test" >&246+ exit 147+ fi48+ if [[ ! -r "$shell_test" ]]; then49+ printf 'shell test entry is not readable: %s\n' "$shell_test" >&250+ exit 151+ fi52+ if [[ ! -x "$shell_test" ]]; then53+ printf 'shell test entry is not executable: %s\n' "$shell_test" >&254+ exit 155+ fi56+done57+58+for shell_test in "${shell_tests[@]}"; do59+ printf 'shell_test_start=%s\n' "$shell_test"60+ bash "$shell_test"61+done@@ -0,0 +1,99 @@
1+2+3+set -euo pipefail4+5+script_dir="$(CDPATH='' cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"6+repo_dir="$(CDPATH='' cd -- "$script_dir/../.." && pwd -P)"7+runner="$repo_dir/scripts/run-shell-tests.sh"8+temp_parent="${TMPDIR:-/tmp}"9+temp_parent="${temp_parent%/}"10+temp_root="$(mktemp -d "$temp_parent/goq-shell-test-discovery.XXXXXX")"11+12+cleanup() {13+ local status=$?14+ trap - EXIT INT TERM HUP15+ case "$temp_root" in16+ "$temp_parent"/goq-shell-test-discovery.??????) rm -rf -- "$temp_root" ;;17+ esac18+ exit "$status"19+}20+trap cleanup EXIT INT TERM HUP21+22+write_passing_test() {23+ local path="$1"24+ local marker="$2"25+ printf '%s\n' \26+ '#!/usr/bin/env bash' \27+ 'set -euo pipefail' \28+ "printf '%s\\n' '$marker' >>\"\$GOQ_TEST_MARKERS\"" \29+ >"$path"30+ chmod 0755 "$path"31+}32+33+assert_failed_with() {34+ local expected="$1"35+ local output_path="$2"36+ shift 237+38+ if "$@" >"$output_path" 2>&1; then39+ printf 'command unexpectedly succeeded: %s\n' "$*" >&240+ exit 141+ fi42+ if ! grep -Fq -- "$expected" "$output_path"; then43+ printf 'failure did not contain expected text: %s\n' "$expected" >&244+ sed -n '1,120p' "$output_path" >&245+ exit 146+ fi47+}48+49+ordered_dir="$temp_root/ordered"50+ordered_markers="$temp_root/ordered.markers"51+mkdir "$ordered_dir"52+write_passing_test "$ordered_dir/zeta.sh" zeta53+write_passing_test "$ordered_dir/.hidden.sh" hidden54+write_passing_test "$ordered_dir/alpha.sh" alpha55+GOQ_TEST_MARKERS="$ordered_markers" "$runner" "$ordered_dir" \56+ >"$temp_root/ordered.out"57+printf '%s\n' hidden alpha zeta >"$temp_root/ordered.expected"58+cmp "$temp_root/ordered.expected" "$ordered_markers"59+for expected_path in \60+ "$ordered_dir/.hidden.sh" \61+ "$ordered_dir/alpha.sh" \62+ "$ordered_dir/zeta.sh"63+do64+ grep -Fq "shell_test_discovered=$expected_path" "$temp_root/ordered.out"65+ grep -Fq "shell_test_start=$expected_path" "$temp_root/ordered.out"66+done67+68+nonexec_dir="$temp_root/nonexec"69+nonexec_markers="$temp_root/nonexec.markers"70+mkdir "$nonexec_dir"71+write_passing_test "$nonexec_dir/alpha.sh" should-not-run72+printf '%s\n' '#!/usr/bin/env bash' 'exit 0' >"$nonexec_dir/zeta.sh"73+chmod 0644 "$nonexec_dir/zeta.sh"74+assert_failed_with \75+ "shell test entry is not executable: $nonexec_dir/zeta.sh" \76+ "$temp_root/nonexec.out" \77+ env GOQ_TEST_MARKERS="$nonexec_markers" "$runner" "$nonexec_dir"78+grep -Fq "shell_test_discovered=$nonexec_dir/zeta.sh" "$temp_root/nonexec.out"79+[[ ! -e "$nonexec_markers" ]]80+81+symlink_dir="$temp_root/symlink"82+symlink_markers="$temp_root/symlink.markers"83+mkdir "$symlink_dir"84+write_passing_test "$symlink_dir/alpha.sh" should-not-run85+ln -s alpha.sh "$symlink_dir/zeta.sh"86+assert_failed_with \87+ "shell test entry must be a regular, non-symlink file: $symlink_dir/zeta.sh" \88+ "$temp_root/symlink.out" \89+ env GOQ_TEST_MARKERS="$symlink_markers" "$runner" "$symlink_dir"90+[[ ! -e "$symlink_markers" ]]91+92+empty_dir="$temp_root/empty"93+mkdir "$empty_dir"94+assert_failed_with \95+ "no shell tests were discovered in: $empty_dir" \96+ "$temp_root/empty.out" \97+ "$runner" "$empty_dir"98+99+printf 'shell_test_discovery_tests=ok\n'@@ -95,9 +95,7 @@ node --test portal/*.test.mjs
9595 9696 cargo build --locked -p sigil-host --bin sigil9797 find scripts -type f -name '*.sh' -exec shellcheck {} +98-while IFS= read -r script_test; do99- "$script_test"100-done < <(find scripts/tests -maxdepth 1 -type f -name '*.sh' -perm -u+x -print | sort)98+./scripts/run-shell-tests.sh scripts/tests10199 102100 host_dependencies="$(cargo tree --locked -p sigil-host --edges normal)"103101 if grep -Eiq '(^|[[:space:]├└│─])(tauri|wry|webkit)([[:space:]-]|$)' <<<"$host_dependencies"; then