Files
interactive-env/tests/framework.sh
2026-03-10 00:14:14 -05:00

164 lines
4.0 KiB
Bash

#!/usr/bin/env bash
# Minimal test framework. Source this file; do not execute it directly.
#
# Globals maintained per-process:
# _PASS — count of passing assertions
# _FAIL — count of failing assertions
_PASS=0
_FAIL=0
# Color codes (self-contained; do not rely on colors.sh)
_R='\033[0;31m' # red
_G='\033[0;32m' # green
_Y='\033[1;33m' # yellow
_B='\033[1m' # bold
_D='\033[2m' # dim
_N='\033[0m' # reset
# suite <name>
# Print a section header for a group of related tests.
suite() {
printf "\n${_B}%s${_N}\n" "$1"
}
# pass / fail — low-level counters; prefer assert_* helpers instead
pass() {
_PASS=$((_PASS + 1))
printf " ${_G}${_N} %s\n" "$1"
}
fail() {
_FAIL=$((_FAIL + 1))
printf " ${_R}${_N} %s\n" "$1"
[[ -n "${2:-}" ]] && printf " expected: %s\n" "$2"
[[ -n "${3:-}" ]] && printf " got: %s\n" "${3:-<empty>}"
}
# ---------------------------------------------------------------------------
# Assertion helpers
# ---------------------------------------------------------------------------
assert_eq() {
local expected="$1" actual="$2" msg="${3:-assert_eq}"
if [[ "$expected" == "$actual" ]]; then
pass "$msg"
else
fail "$msg" "$expected" "$actual"
fi
}
assert_not_eq() {
local unexpected="$1" actual="$2" msg="${3:-assert_not_eq}"
if [[ "$unexpected" != "$actual" ]]; then
pass "$msg"
else
fail "$msg (expected values to differ)" "$unexpected" "$actual"
fi
}
assert_empty() {
local actual="$1" msg="${2:-assert_empty}"
if [[ -z "$actual" ]]; then
pass "$msg"
else
fail "$msg (expected empty)" "" "$actual"
fi
}
assert_not_empty() {
local actual="$1" msg="${2:-assert_not_empty}"
if [[ -n "$actual" ]]; then
pass "$msg"
else
fail "$msg (expected non-empty)"
fi
}
assert_contains() {
local needle="$1" haystack="$2" msg="${3:-assert_contains}"
if [[ "$haystack" == *"$needle"* ]]; then
pass "$msg"
else
fail "$msg" "*${needle}*" "$haystack"
fi
}
# assert_success <msg> <cmd> [args...]
# Passes when the command exits 0.
assert_success() {
local msg="$1"; shift
local rc=0
"$@" 2>/dev/null || rc=$?
if [[ $rc -eq 0 ]]; then
pass "$msg"
else
fail "$msg (expected exit 0, got $rc)"
fi
}
# assert_failure <msg> <cmd> [args...]
# Passes when the command exits non-zero.
assert_failure() {
local msg="$1"; shift
local rc=0
"$@" 2>/dev/null || rc=$?
if [[ $rc -ne 0 ]]; then
pass "$msg"
else
fail "$msg (expected non-zero exit)"
fi
}
assert_file_exists() {
local file="$1" msg="${2:-assert_file_exists}"
if [[ -f "$file" ]]; then
pass "$msg"
else
fail "$msg" "<file: $file>" "(not found)"
fi
}
assert_file_contains() {
local pattern="$1" file="$2" msg="${3:-assert_file_contains}"
if [[ ! -f "$file" ]]; then
fail "$msg (file not found: $file)"
return
fi
if grep -qF "$pattern" "$file"; then
pass "$msg"
else
fail "$msg" "$pattern" "(not found in $file)"
fi
}
assert_file_not_contains() {
local pattern="$1" file="$2" msg="${3:-assert_file_not_contains}"
if [[ ! -f "$file" ]]; then
fail "$msg (file not found: $file)"
return
fi
if ! grep -qF "$pattern" "$file"; then
pass "$msg"
else
fail "$msg" "(should not contain $pattern)" "(found in $file)"
fi
}
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
# print_summary
# Print pass/fail totals and exit 1 if any tests failed.
print_summary() {
local total=$((_PASS + _FAIL))
printf "\n"
if [[ $_FAIL -eq 0 ]]; then
printf "${_G}%d/%d passed${_N}\n" "$_PASS" "$total"
else
printf "${_R}%d failed${_N}, %d passed, %d total\n" "$_FAIL" "$_PASS" "$total"
fi
[[ $_FAIL -eq 0 ]]
}