kit_sh_kit.sh (3630B)
1 # test/lib/kit_sh_kit.sh — the Type-K (scripted-shell) test kit. 2 # 3 # ONE source point for hand-written tool/driver tests. A K harness sources this 4 # file and renders verdicts via ONE OF TWO oracle modes, both recording through 5 # the single report layer (kit_sh_report.sh): 6 # 7 # mode G (golden transcript): loop cases/<name>.sh and call 8 # kit_scenario_case NAME SH EXPECTED — runs the case in a sandbox and 9 # diffs stdout+stderr vs <name>.expected. (ar/strip/objcopy/strings/ 10 # objdump/dbg.) kit_scenario_case lives in kit_sh_report.sh. 11 # mode P (procedural asserts): set up $work and call ok / run_ok / run_fail / 12 # contains / same_file / is_executable / assert_file_exists / 13 # check_mode. (cas/pkg/driver/windows-smokes.) These come from 14 # kit_sh_assert.sh and route through kit_pass/kit_fail/kit_skip. 15 # 16 # Either way: kit_report_init at the top, kit_summary LABEL + kit_exit at the end. 17 # No harness reimplements counters/summary. Mode-P suites are SERIAL by design 18 # (cas/pkg/driver share one $work and mutate fixtures), so the assert verbs do 19 # NOT participate in the corpus engine's parallel event-replay. 20 21 # The caller sets KIT_KIT_DIR to the test/lib directory before sourcing. (This 22 # kit is sourced by /bin/sh harnesses, where BASH_SOURCE is unavailable, so we 23 # do not self-resolve.) 24 : "${KIT_KIT_DIR:?kit_sh_kit.sh: caller must set KIT_KIT_DIR=<repo>/test/lib}" 25 . "$KIT_KIT_DIR/kit_sh_report.sh" # counters + verbs + kit_summary/kit_exit 26 . "$KIT_KIT_DIR/kit_sh_assert.sh" # mode-P procedural verbs (route through kit_*) 27 28 # check_mode NAME FILE EXPECTED_OCTAL : assert FILE's permission bits, portably 29 # (Darwin stat -f vs GNU stat -c). The stat invocation is the one host-specific 30 # bit; the verdict goes through kit_pass/kit_fail. 31 check_mode() { 32 kit_km_got= 33 if [ "$(uname -s 2>/dev/null)" = "Darwin" ]; then 34 kit_km_got=$(stat -f '%Lp' "$2" 2>/dev/null) 35 else 36 kit_km_got=$(stat -c '%a' "$2" 2>/dev/null) 37 fi 38 if [ "$kit_km_got" = "$3" ]; then kit_pass "$1" 39 else kit_fail "$1" "mode $kit_km_got want $3"; fi 40 } 41 42 # kit_scenario_case NAME SH EXPECTED [KEEP_DIR] : mode-G oracle. Run scenario 43 # script SH in a sandbox under $KIT_WORK and diff stdout+stderr against the 44 # golden EXPECTED. Records exactly one pass/fail/skip; honors a leading "SKIP" 45 # line when KIT_SCENARIO_SKIP=1. (ar/strip/objcopy/strings/objdump; dbg extends 46 # it with stdin/normalizer/xfail in its own migration.) 47 kit_scenario_case() { 48 kit_sc_name=$1 49 kit_sc_sh=$2 50 kit_sc_exp=$3 51 kit_sc_keep=${4:-} 52 kit_sc_tag=$(printf '%s' "$kit_sc_name" | tr / -) 53 kit_sc_actual="$KIT_WORK/$kit_sc_tag.actual" 54 55 if [ ! -e "$kit_sc_exp" ]; then 56 kit_fail "$kit_sc_name" "missing $(basename "$kit_sc_exp")" 57 return 58 fi 59 60 kit_sc_box="$KIT_WORK/$kit_sc_tag" 61 mkdir -p "$kit_sc_box" 62 ( cd "$kit_sc_box" && sh "$kit_sc_sh" ) > "$kit_sc_actual" 2>&1 63 kit_sc_rc=$? 64 65 if [ "${KIT_SCENARIO_SKIP:-0}" = "1" ] && [ "$kit_sc_rc" -eq 0 ] && 66 head -n1 "$kit_sc_actual" 2>/dev/null | grep -q '^SKIP'; then 67 kit_skip "$kit_sc_name" "$(head -n1 "$kit_sc_actual" | sed 's/^SKIP[: ]*//')" 68 return 69 fi 70 71 if [ "$kit_sc_rc" -ne 0 ]; then 72 kit_fail "$kit_sc_name" "script exit=$kit_sc_rc" 73 diff -u "$kit_sc_exp" "$kit_sc_actual" || true 74 return 75 fi 76 77 if diff -u "$kit_sc_exp" "$kit_sc_actual" >/dev/null 2>&1; then 78 kit_pass "$kit_sc_name" 79 else 80 kit_fail "$kit_sc_name" 81 diff -u "$kit_sc_exp" "$kit_sc_actual" || true 82 if [ -n "$kit_sc_keep" ]; then 83 cp "$kit_sc_actual" "$kit_sc_keep/$kit_sc_name.actual" 2>/dev/null || true 84 fi 85 fi 86 }