kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

kit_sh_assert.sh (3122B)


      1 # test/lib/kit_sh_assert.sh — Type-K mode-P procedural assert verbs + the
      2 # CAS object/tree helpers shared by cas/ and pkg/.
      3 #
      4 # Sourced AFTER kit_sh_report.sh (kit_sh_kit.sh does this). The verbs route
      5 # through kit_pass/kit_fail/kit_skip so counting, summary, and exit are unified —
      6 # a harness calls kit_report_init at the top and kit_summary/kit_exit at the end,
      7 # never its own counters.
      8 #
      9 # Contract: the caller provides a writable scratch dir $work; per-check
     10 # .out/.err/.diag files are written under it. Mode-P suites are SERIAL (they
     11 # share one $work and mutate fixtures), so these verbs do not emit KIT_EV
     12 # events / participate in the corpus engine's parallel replay.
     13 
     14 # ---- result verbs (thin wrappers over the report layer) --------------------
     15 
     16 ok() { kit_pass "$1"; }
     17 
     18 # not_ok NAME [DIAGFILE] : record a failure; if DIAGFILE is given and non-empty,
     19 # show it indented after the FAIL line.
     20 not_ok() {
     21   kit_fail "$1"
     22   if [ "$#" -gt 1 ] && [ -s "$2" ]; then sed 's/^/    | /' "$2"; fi
     23 }
     24 
     25 skip_test() { kit_skip "$1" "${2:-}"; }
     26 
     27 # ---- command-result asserts ------------------------------------------------
     28 
     29 run_ok() {
     30   name=$1; shift
     31   if "$@" > "$work/$name.out" 2> "$work/$name.err"; then ok "$name"
     32   else not_ok "$name" "$work/$name.err"; fi
     33 }
     34 
     35 run_fail() {
     36   name=$1; shift
     37   if "$@" > "$work/$name.out" 2> "$work/$name.err"; then
     38     { echo "command unexpectedly succeeded"; sed 's/^/stdout: /' "$work/$name.out"; } > "$work/$name.diag"
     39     not_ok "$name" "$work/$name.diag"
     40   else ok "$name"; fi
     41 }
     42 
     43 # ---- content asserts -------------------------------------------------------
     44 
     45 contains() {
     46   name=$1; file=$2; needle=$3
     47   if grep -F "$needle" "$file" >/dev/null 2>&1; then ok "$name"
     48   else
     49     { printf 'missing text: %s\n' "$needle"; sed 's/^/file: /' "$file"; } > "$work/$name.diag"
     50     not_ok "$name" "$work/$name.diag"
     51   fi
     52 }
     53 
     54 same_file() {
     55   name=$1; want=$2; got=$3
     56   if cmp -s "$want" "$got"; then ok "$name"
     57   else
     58     { printf 'files differ:\n'; printf '  want: %s\n' "$want"; printf '  got:  %s\n' "$got"; } > "$work/$name.diag"
     59     not_ok "$name" "$work/$name.diag"
     60   fi
     61 }
     62 
     63 is_executable() {
     64   name=$1; file=$2
     65   if [ -x "$file" ]; then ok "$name"
     66   else echo "not executable: $file" > "$work/$name.diag"; not_ok "$name" "$work/$name.diag"; fi
     67 }
     68 
     69 assert_file_exists() {
     70   name=$1; file=$2
     71   if [ -f "$file" ]; then ok "$name"
     72   else echo "missing file: $file" > "$work/$name.diag"; not_ok "$name" "$work/$name.diag"; fi
     73 }
     74 
     75 # ---- CAS object/tree helpers (shared by cas + pkg) -------------------------
     76 
     77 first_hex_id() {
     78   sed -n 's/.*\([0-9a-fA-F]\{64\}\).*/\1/p' "$1" | sed -n '1p'
     79 }
     80 
     81 id_prefix() {
     82   printf '%.2s' "$1"
     83 }
     84 
     85 cas_object_path() {
     86   root=$1; kind=$2; id=$3
     87   prefix=$(id_prefix "$id")
     88   printf '%s/%s/%s/%s\n' "$root" "$kind" "$prefix" "$id"
     89 }
     90 
     91 tree_blob_for_path() {
     92   tree_file=$1; want=$2
     93   awk -v want="$want" '
     94     $0 == "[file]" { in_file = 1; path = ""; blob = ""; next }
     95     in_file && /^path = / { path = substr($0, 8); next }
     96     in_file && /^blob = / {
     97       blob = substr($0, 8);
     98       if (path == want) { print blob; exit; }
     99     }
    100   ' "$tree_file"
    101 }