#!/usr/bin/env bash set -euo pipefail fail() { printf 'ASSERT FAIL: %s\n' "$*" >&2 exit 1 } pass() { printf 'ASSERT PASS: %s\n' "$*" } assert_eq() { local expected=$1 local actual=$2 local message=${3:-values differ} [[ ${expected} == "${actual}" ]] || fail "${message} (expected='${expected}' actual='${actual}')" } assert_ne() { local left=$1 local right=$2 local message=${3:-values should differ} [[ ${left} != "${right}" ]] || fail "${message} (value='${left}')" } assert_contains() { local haystack=$1 local needle=$2 local message=${3:-substring not found} [[ ${haystack} == *"${needle}"* ]] || fail "${message} (needle='${needle}')" } assert_not_contains() { local haystack=$1 local needle=$2 local message=${3:-unexpected substring found} [[ ${haystack} != *"${needle}"* ]] || fail "${message} (needle='${needle}')" } assert_file_contains() { local file=$1 local needle=$2 local message=${3:-file does not contain substring} [[ -f ${file} ]] || fail "file not found: ${file}" grep -Fq -- "${needle}" "${file}" || fail "${message} (file='${file}' needle='${needle}')" } assert_status() { local expected=$1 local actual=$2 local message=${3:-unexpected exit status} [[ ${expected} == "${actual}" ]] || fail "${message} (expected=${expected} actual=${actual})" }