#!/bin/sh set -eu ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) TEST_BIN=${TEST_BIN:-"$ROOT/out/test"} BRACKET_BIN=${BRACKET_BIN:-"$ROOT/out/["} FD_HELPER_BIN=${FD_HELPER_BIN:-"$ROOT/build/fd_helper"} SHELL_BIN=$(command -v sh) TMPDIR=${TMPDIR:-/tmp} WORKDIR=$(mktemp -d "$TMPDIR/test-test.XXXXXX") STDOUT_FILE="$WORKDIR/stdout" STDERR_FILE="$WORKDIR/stderr" LAST_STATUS=0 LAST_STDOUT= LAST_STDERR= export LC_ALL=C export TZ=UTC cleanup() { rm -rf "$WORKDIR" } trap cleanup EXIT INT TERM HUP fail() { printf 'FAIL: %s\n' "$1" >&2 exit 1 } assert_status() { name=$1 expected=$2 actual=$3 if [ "$expected" -ne "$actual" ]; then printf 'FAIL: %s\n' "$name" >&2 printf 'expected status: %s\n' "$expected" >&2 printf 'actual status: %s\n' "$actual" >&2 exit 1 fi } assert_eq() { name=$1 expected=$2 actual=$3 if [ "$expected" != "$actual" ]; then printf 'FAIL: %s\n' "$name" >&2 printf '%s\n' '--- expected ---' >&2 printf '%s\n' "$expected" >&2 printf '%s\n' '--- actual ---' >&2 printf '%s\n' "$actual" >&2 exit 1 fi } assert_empty() { name=$1 value=$2 if [ -n "$value" ]; then printf 'FAIL: %s\n' "$name" >&2 printf '%s\n' '--- expected empty ---' >&2 printf '%s\n' '--- actual ---' >&2 printf '%s\n' "$value" >&2 exit 1 fi } assert_contains() { name=$1 value=$2 pattern=$3 case $value in *"$pattern"*) ;; *) fail "$name" ;; esac } run_capture() { if "$@" >"$STDOUT_FILE" 2>"$STDERR_FILE"; then LAST_STATUS=0 else LAST_STATUS=$? fi LAST_STDOUT=$(cat "$STDOUT_FILE") LAST_STDERR=$(cat "$STDERR_FILE") } run_in_shell() { if sh -c "$1" >"$STDOUT_FILE" 2>"$STDERR_FILE"; then LAST_STATUS=0 else LAST_STATUS=$? fi LAST_STDOUT=$(cat "$STDOUT_FILE") LAST_STDERR=$(cat "$STDERR_FILE") } find_socket_path() { for candidate in \ /run/* /run/*/* /run/*/*/* \ /var/run/* /var/run/*/* /var/run/*/*/* \ /tmp/* /tmp/*/* /tmp/*/*/*; do if [ -S "$candidate" ]; then printf '%s\n' "$candidate" return 0 fi done return 1 } skip() { printf 'SKIP: %s\n' "$1" } [ -x "$TEST_BIN" ] || fail "missing binary: $TEST_BIN" [ -x "$BRACKET_BIN" ] || fail "missing bracket binary: $BRACKET_BIN" [ -x "$FD_HELPER_BIN" ] || fail "missing fd helper: $FD_HELPER_BIN" run_capture "$TEST_BIN" assert_status "no expression status" 1 "$LAST_STATUS" assert_empty "no expression stdout" "$LAST_STDOUT" assert_empty "no expression stderr" "$LAST_STDERR" run_capture "$TEST_BIN" "" assert_status "empty operand status" 1 "$LAST_STATUS" assert_empty "empty operand stdout" "$LAST_STDOUT" assert_empty "empty operand stderr" "$LAST_STDERR" run_capture "$TEST_BIN" value assert_status "single operand status" 0 "$LAST_STATUS" assert_empty "single operand stdout" "$LAST_STDOUT" assert_empty "single operand stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -n "" assert_status "string -n status" 1 "$LAST_STATUS" assert_empty "string -n stdout" "$LAST_STDOUT" assert_empty "string -n stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -z "" assert_status "string -z status" 0 "$LAST_STATUS" assert_empty "string -z stdout" "$LAST_STDOUT" assert_empty "string -z stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -h = -h assert_status "operator-like operand status" 0 "$LAST_STATUS" assert_empty "operator-like operand stdout" "$LAST_STDOUT" assert_empty "operator-like operand stderr" "$LAST_STDERR" run_capture "$TEST_BIN" alpha = alpha assert_status "string equality status" 0 "$LAST_STATUS" assert_empty "string equality stdout" "$LAST_STDOUT" assert_empty "string equality stderr" "$LAST_STDERR" run_capture "$TEST_BIN" alpha == alpha assert_status "string double equals status" 0 "$LAST_STATUS" assert_empty "string double equals stdout" "$LAST_STDOUT" assert_empty "string double equals stderr" "$LAST_STDERR" run_capture "$TEST_BIN" alpha '!=' beta assert_status "string inequality status" 0 "$LAST_STATUS" assert_empty "string inequality stdout" "$LAST_STDOUT" assert_empty "string inequality stderr" "$LAST_STDERR" run_capture "$TEST_BIN" alpha '<' beta assert_status "string less-than status" 0 "$LAST_STATUS" assert_empty "string less-than stdout" "$LAST_STDOUT" assert_empty "string less-than stderr" "$LAST_STDERR" run_capture "$TEST_BIN" beta '>' alpha assert_status "string greater-than status" 0 "$LAST_STATUS" assert_empty "string greater-than stdout" "$LAST_STDOUT" assert_empty "string greater-than stderr" "$LAST_STDERR" run_capture "$TEST_BIN" 100 -eq 100 assert_status "numeric eq status" 0 "$LAST_STATUS" assert_empty "numeric eq stdout" "$LAST_STDOUT" assert_empty "numeric eq stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -5 -lt 5 assert_status "numeric lt status" 0 "$LAST_STATUS" assert_empty "numeric lt stdout" "$LAST_STDOUT" assert_empty "numeric lt stderr" "$LAST_STDERR" run_capture "$TEST_BIN" 7 -ge 8 assert_status "numeric false status" 1 "$LAST_STATUS" assert_empty "numeric false stdout" "$LAST_STDOUT" assert_empty "numeric false stderr" "$LAST_STDERR" run_capture "$TEST_BIN" abc -eq 1 assert_status "bad number status" 2 "$LAST_STATUS" assert_empty "bad number stdout" "$LAST_STDOUT" assert_eq "bad number stderr" "test: abc: bad number" "$LAST_STDERR" run_capture "$TEST_BIN" 999999999999999999999999999999 -eq 1 assert_status "out of range status" 2 "$LAST_STATUS" assert_empty "out of range stdout" "$LAST_STDOUT" assert_eq "out of range stderr" "test: 999999999999999999999999999999: out of range" "$LAST_STDERR" run_capture "$TEST_BIN" '!' "" assert_status "bang empty status" 0 "$LAST_STATUS" assert_empty "bang empty stdout" "$LAST_STDOUT" assert_empty "bang empty stderr" "$LAST_STDERR" run_capture "$TEST_BIN" '!' assert_status "bare bang status" 0 "$LAST_STATUS" assert_empty "bare bang stdout" "$LAST_STDOUT" assert_empty "bare bang stderr" "$LAST_STDERR" run_capture "$TEST_BIN" '(' 0 -eq 0 ')' -a '(' 2 -gt 1 ')' assert_status "paren and status" 0 "$LAST_STATUS" assert_empty "paren and stdout" "$LAST_STDOUT" assert_empty "paren and stderr" "$LAST_STDERR" run_capture "$TEST_BIN" 1 -eq 0 -o a = a -a 1 -eq 0 -o a = aa assert_status "precedence status" 1 "$LAST_STATUS" assert_empty "precedence stdout" "$LAST_STDOUT" assert_empty "precedence stderr" "$LAST_STDERR" run_capture "$TEST_BIN" '(' 1 = 1 assert_status "closing paren error status" 2 "$LAST_STATUS" assert_empty "closing paren error stdout" "$LAST_STDOUT" assert_eq "closing paren error stderr" "test: closing paren expected" "$LAST_STDERR" run_capture "$TEST_BIN" 1 -eq assert_status "argument expected status" 2 "$LAST_STATUS" assert_empty "argument expected stdout" "$LAST_STDOUT" assert_eq "argument expected stderr" "test: -eq: argument expected" "$LAST_STDERR" run_capture "$TEST_BIN" one two assert_status "unexpected operator status" 2 "$LAST_STATUS" assert_empty "unexpected operator stdout" "$LAST_STDOUT" assert_eq "unexpected operator stderr" "test: two: unexpected operator" "$LAST_STDERR" REGULAR_FILE="$WORKDIR/regular" EMPTY_FILE="$WORKDIR/empty" EXECUTABLE_FILE="$WORKDIR/executable" PERM_FILE="$WORKDIR/no-perm" FIFO_PATH="$WORKDIR/fifo" LINK_PATH="$WORKDIR/link" HARDLINK_PATH="$WORKDIR/hardlink" DIR_PATH="$WORKDIR/dir" STICKY_DIR="$WORKDIR/sticky" OLDER_FILE="$WORKDIR/older" NEWER_FILE="$WORKDIR/newer" MODE_FILE="$WORKDIR/mode" printf 'payload\n' >"$REGULAR_FILE" : >"$EMPTY_FILE" printf '#!/bin/sh\nexit 0\n' >"$EXECUTABLE_FILE" chmod 0755 "$EXECUTABLE_FILE" : >"$PERM_FILE" chmod 0000 "$PERM_FILE" mkfifo "$FIFO_PATH" ln -s "$REGULAR_FILE" "$LINK_PATH" ln "$REGULAR_FILE" "$HARDLINK_PATH" mkdir "$DIR_PATH" mkdir "$STICKY_DIR" chmod 1777 "$STICKY_DIR" : >"$MODE_FILE" chmod 6755 "$MODE_FILE" : >"$OLDER_FILE" sleep 1 : >"$NEWER_FILE" run_capture "$TEST_BIN" -e "$REGULAR_FILE" assert_status "file exists status" 0 "$LAST_STATUS" assert_empty "file exists stdout" "$LAST_STDOUT" assert_empty "file exists stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -f "$REGULAR_FILE" assert_status "regular file status" 0 "$LAST_STATUS" assert_empty "regular file stdout" "$LAST_STDOUT" assert_empty "regular file stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -d "$DIR_PATH" assert_status "directory status" 0 "$LAST_STATUS" assert_empty "directory stdout" "$LAST_STDOUT" assert_empty "directory stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -s "$REGULAR_FILE" assert_status "size greater than zero status" 0 "$LAST_STATUS" assert_empty "size greater than zero stdout" "$LAST_STDOUT" assert_empty "size greater than zero stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -s "$EMPTY_FILE" assert_status "size zero status" 1 "$LAST_STATUS" assert_empty "size zero stdout" "$LAST_STDOUT" assert_empty "size zero stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -p "$FIFO_PATH" assert_status "fifo status" 0 "$LAST_STATUS" assert_empty "fifo stdout" "$LAST_STDOUT" assert_empty "fifo stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -L "$LINK_PATH" assert_status "symlink L status" 0 "$LAST_STATUS" assert_empty "symlink L stdout" "$LAST_STDOUT" assert_empty "symlink L stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -h "$LINK_PATH" assert_status "symlink h status" 0 "$LAST_STATUS" assert_empty "symlink h stdout" "$LAST_STDOUT" assert_empty "symlink h stderr" "$LAST_STDERR" SOCKET_PATH=$(find_socket_path || true) if [ -n "$SOCKET_PATH" ]; then run_capture "$TEST_BIN" -S "$SOCKET_PATH" assert_status "socket status" 0 "$LAST_STATUS" assert_empty "socket stdout" "$LAST_STDOUT" assert_empty "socket stderr" "$LAST_STDERR" else skip "socket positive test skipped because no UNIX socket path is visible" fi run_capture "$TEST_BIN" -O "$REGULAR_FILE" assert_status "owner matches euid status" 0 "$LAST_STATUS" assert_empty "owner matches euid stdout" "$LAST_STDOUT" assert_empty "owner matches euid stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -G "$REGULAR_FILE" assert_status "group matches egid status" 0 "$LAST_STATUS" assert_empty "group matches egid stdout" "$LAST_STDOUT" assert_empty "group matches egid stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -u "$MODE_FILE" assert_status "setuid bit status" 0 "$LAST_STATUS" assert_empty "setuid bit stdout" "$LAST_STDOUT" assert_empty "setuid bit stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -g "$MODE_FILE" assert_status "setgid bit status" 0 "$LAST_STATUS" assert_empty "setgid bit stdout" "$LAST_STDOUT" assert_empty "setgid bit stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -k "$STICKY_DIR" assert_status "sticky bit status" 0 "$LAST_STATUS" assert_empty "sticky bit stdout" "$LAST_STDOUT" assert_empty "sticky bit stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -r "$REGULAR_FILE" assert_status "readable status" 0 "$LAST_STATUS" assert_empty "readable stdout" "$LAST_STDOUT" assert_empty "readable stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -w "$REGULAR_FILE" assert_status "writable status" 0 "$LAST_STATUS" assert_empty "writable stdout" "$LAST_STDOUT" assert_empty "writable stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -x "$EXECUTABLE_FILE" assert_status "executable status" 0 "$LAST_STATUS" assert_empty "executable stdout" "$LAST_STDOUT" assert_empty "executable stderr" "$LAST_STDERR" if [ "$(id -u)" -ne 0 ]; then run_capture "$TEST_BIN" -r "$PERM_FILE" assert_status "unreadable status" 1 "$LAST_STATUS" assert_empty "unreadable stdout" "$LAST_STDOUT" assert_empty "unreadable stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -w "$PERM_FILE" assert_status "unwritable status" 1 "$LAST_STATUS" assert_empty "unwritable stdout" "$LAST_STDOUT" assert_empty "unwritable stderr" "$LAST_STDERR" else skip "permission-negative tests skipped for euid 0" fi run_capture "$TEST_BIN" "$NEWER_FILE" -nt "$OLDER_FILE" assert_status "newer-than status" 0 "$LAST_STATUS" assert_empty "newer-than stdout" "$LAST_STDOUT" assert_empty "newer-than stderr" "$LAST_STDERR" run_capture "$TEST_BIN" "$OLDER_FILE" -ot "$NEWER_FILE" assert_status "older-than status" 0 "$LAST_STATUS" assert_empty "older-than stdout" "$LAST_STDOUT" assert_empty "older-than stderr" "$LAST_STDERR" run_capture "$TEST_BIN" "$REGULAR_FILE" -ef "$HARDLINK_PATH" assert_status "same file status" 0 "$LAST_STATUS" assert_empty "same file stdout" "$LAST_STDOUT" assert_empty "same file stderr" "$LAST_STDERR" run_capture "$TEST_BIN" -c /dev/null assert_status "character device status" 0 "$LAST_STATUS" assert_empty "character device stdout" "$LAST_STDOUT" assert_empty "character device stderr" "$LAST_STDERR" BLOCK_DEVICE_FOUND= for candidate in /dev/* /dev/*/*; do if [ -b "$candidate" ]; then BLOCK_DEVICE_FOUND=$candidate break fi done if [ -n "${BLOCK_DEVICE_FOUND:-}" ]; then run_capture "$TEST_BIN" -b "$BLOCK_DEVICE_FOUND" assert_status "block device status" 0 "$LAST_STATUS" assert_empty "block device stdout" "$LAST_STDOUT" assert_empty "block device stderr" "$LAST_STDERR" else skip "block-device positive test skipped because no block device is visible" fi run_capture "$TEST_BIN" -t 99 assert_status "closed fd tty status" 1 "$LAST_STATUS" assert_empty "closed fd tty stdout" "$LAST_STDOUT" assert_empty "closed fd tty stderr" "$LAST_STDERR" run_capture "$FD_HELPER_BIN" 9 "$TEST_BIN" -t 9 case $LAST_STATUS in 0) assert_empty "pty fd tty stdout" "$LAST_STDOUT" assert_empty "pty fd tty stderr" "$LAST_STDERR" ;; 1) run_capture "$FD_HELPER_BIN" 9 "$SHELL_BIN" -c 'test -t 9' case $LAST_STATUS in 1) skip "pty-backed -t positive test skipped because shell test also reports non-tty" ;; 126) case $LAST_STDERR in *"posix_openpt"*|*"grantpt"*|*"unlockpt"*|*"ptsname"*|*"open slave pty"*|*"isatty"*) skip "pty-backed -t positive test skipped because PTY checks are blocked" ;; *) fail "pty helper unexpected failure: $LAST_STDERR" ;; esac ;; *) fail "pty fd tty status mismatch: test returned 1 but shell test -t returned $LAST_STATUS" ;; esac ;; 126) case $LAST_STDERR in *"posix_openpt"*|*"grantpt"*|*"unlockpt"*|*"ptsname"*|*"open slave pty"*|*"isatty"*) skip "pty-backed -t positive test skipped because PTY checks are blocked" ;; *) fail "pty helper unexpected failure: $LAST_STDERR" ;; esac ;; *) fail "pty helper unexpected status: $LAST_STATUS" ;; esac run_capture "$BRACKET_BIN" alpha = alpha ']' assert_status "bracket true status" 0 "$LAST_STATUS" assert_empty "bracket true stdout" "$LAST_STDOUT" assert_empty "bracket true stderr" "$LAST_STDERR" run_capture "$BRACKET_BIN" ']' assert_status "bracket empty expression status" 1 "$LAST_STATUS" assert_empty "bracket empty expression stdout" "$LAST_STDOUT" assert_empty "bracket empty expression stderr" "$LAST_STDERR" run_capture "$BRACKET_BIN" alpha = alpha assert_status "missing closing bracket status" 2 "$LAST_STATUS" assert_empty "missing closing bracket stdout" "$LAST_STDOUT" assert_eq "missing closing bracket stderr" "[: missing ']'" "$LAST_STDERR" run_in_shell "TEST_BIN='$TEST_BIN' sh '$ROOT/tests/legacy_test.sh'" assert_status "legacy suite status" 0 "$LAST_STATUS" assert_contains "legacy suite stdout" "$LAST_STDOUT" "1..130" assert_contains "legacy suite stdout" "$LAST_STDOUT" "PASS" assert_empty "legacy suite stderr" "$LAST_STDERR" printf '%s\n' "PASS"