diff options
Diffstat (limited to 'corebinutils/test/tests')
| -rw-r--r-- | corebinutils/test/tests/fd_helper.c | 111 | ||||
| -rw-r--r-- | corebinutils/test/tests/legacy_test.sh | 209 | ||||
| -rw-r--r-- | corebinutils/test/tests/test.sh | 479 |
3 files changed, 799 insertions, 0 deletions
diff --git a/corebinutils/test/tests/fd_helper.c b/corebinutils/test/tests/fd_helper.c new file mode 100644 index 0000000000..27d81f7164 --- /dev/null +++ b/corebinutils/test/tests/fd_helper.c @@ -0,0 +1,111 @@ +/* + +SPDX-License-Identifier: BSD-3-Clause + +Copyright (c) 2026 + Project Tick. All rights reserved. + +This code is derived from software contributed to Berkeley by +the Institute of Electrical and Electronics Engineers, Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +*/ + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void +die_errno(const char *what) +{ + fprintf(stderr, "fd_helper: %s: %s\n", what, strerror(errno)); + exit(126); +} + +static int +parse_fd(const char *text) +{ + char *end; + long value; + + errno = 0; + value = strtol(text, &end, 10); + if (end == text || *end != '\0' || errno == ERANGE || + value < 0 || value > INT_MAX) { + fprintf(stderr, "fd_helper: invalid file descriptor: %s\n", text); + exit(126); + } + return (int)value; +} + +int +main(int argc, char **argv) +{ + int fd; + int master_fd; + int slave_fd; + char *slave_name; + + if (argc < 4) { + fprintf(stderr, "usage: fd_helper fd program arg ...\n"); + return 126; + } + + fd = parse_fd(argv[1]); + + master_fd = posix_openpt(O_RDWR | O_NOCTTY); + if (master_fd < 0) + die_errno("posix_openpt"); + if (grantpt(master_fd) != 0) + die_errno("grantpt"); + if (unlockpt(master_fd) != 0) + die_errno("unlockpt"); + + slave_name = ptsname(master_fd); + if (slave_name == NULL) + die_errno("ptsname"); + + slave_fd = open(slave_name, O_RDWR | O_NOCTTY); + if (slave_fd < 0) + die_errno("open slave pty"); + + if (dup2(slave_fd, fd) < 0) + die_errno("dup2"); + + if (!isatty(fd)) + die_errno("isatty"); + + if (slave_fd != fd) + close(slave_fd); + close(master_fd); + + execv(argv[2], &argv[2]); + die_errno("execv"); +} diff --git a/corebinutils/test/tests/legacy_test.sh b/corebinutils/test/tests/legacy_test.sh new file mode 100644 index 0000000000..94f51aefba --- /dev/null +++ b/corebinutils/test/tests/legacy_test.sh @@ -0,0 +1,209 @@ +#!/bin/sh + +set -eu + +#- +# Copyright (c) June 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +# +# TEST.sh - check if test(1) or builtin test works +# + +# force a specified test program, e.g. `env TEST_BIN=/bin/test sh legacy_test.sh' +TEST_BIN=${TEST_BIN:-test} +FAILED=0 + +t () +{ + # $1 -> exit code + # $2 -> $test expression + + count=$((count+1)) + # check for syntax errors + if syntax=$(eval "\"$TEST_BIN\" $2" 2>&1); then + ret=0 + else + ret=$? + fi + if test -n "$syntax"; then + printf "not ok %s - (syntax error)\n" "$count $2" + FAILED=1 + elif [ "$ret" != "$1" ]; then + printf "not ok %s - (got $ret, expected $1)\n" "$count $2" + FAILED=1 + else + printf "ok %s\n" "$count $2" + fi +} + +count=0 +echo "1..130" + +t 0 'b = b' +t 0 'b == b' +t 1 'b != b' +t 0 '\( b = b \)' +t 0 '\( b == b \)' +t 1 '! \( b = b \)' +t 1 '! \( b == b \)' +t 1 '! -f /etc/passwd' + +t 0 '-h = -h' +t 0 '-o = -o' +t 1 '-f = h' +t 1 '-h = f' +t 1 '-o = f' +t 1 'f = -o' +t 0 '\( -h = -h \)' +t 1 '\( a = -h \)' +t 1 '\( -f = h \)' +t 0 '-h = -h -o a' +t 0 '\( -h = -h \) -o 1' +t 0 '-h = -h -o -h = -h' +t 0 '\( -h = -h \) -o \( -h = -h \)' +t 0 'roedelheim = roedelheim' +t 1 'potsdam = berlin-dahlem' + +t 0 '-d /' +t 0 '-d / -a a != b' +t 1 '-z "-z"' +t 0 '-n -n' + +t 0 '0' +t 0 '\( 0 \)' +t 0 '-E' +t 0 '-X -a -X' +t 0 '-XXX' +t 0 '\( -E \)' +t 0 'true -o X' +t 0 'true -o -X' +t 0 '\( \( \( a = a \) -o 1 \) -a 1 \) -a true' +t 1 '-h /' +t 0 '-r /' +t 1 '-w /' +t 0 '-x /bin/sh' +t 0 '-c /dev/null' +t 0 '-f /etc/passwd' +t 0 '-s /etc/passwd' + +t 1 '! \( 700 -le 1000 -a -n "1" -a "20" = "20" \)' +t 0 '100 -eq 100' +t 0 '100 -lt 200' +t 1 '1000 -lt 200' +t 0 '1000 -gt 200' +t 0 '1000 -ge 200' +t 0 '1000 -ge 1000' +t 1 '2 -ne 2' +t 0 '0 -eq 0' +t 1 '-5 -eq 5' +t 0 '\( 0 -eq 0 \)' +t 1 '1 -eq 0 -o a = a -a 1 -eq 0 -o a = aa' + +t 1 '"" -o ""' +t 1 '"" -a ""' +t 1 '"a" -a ""' +t 0 '"a" -a ! ""' +t 1 '""' +t 0 '! ""' + +t 0 '!' +t 0 '\(' +t 0 '\)' + +t 1 '\( = \)' +t 0 '\( != \)' +t 0 '\( ! \)' +t 0 '\( \( \)' +t 0 '\( \) \)' +t 0 '! = !' +t 1 '! != !' +t 1 '-n = \)' +t 0 '! != \)' +t 1 '! = a' +t 0 '! != -n' +t 0 '! -c /etc/passwd' + +t 1 '! = = =' +t 0 '! = = \)' +t 0 '! "" -o ""' +t 1 '! "x" -o ""' +t 1 '! "" -o "x"' +t 1 '! "x" -o "x"' +t 0 '\( -f /etc/passwd \)' +t 0 '\( ! "" \)' +t 1 '\( ! -e \)' + +t 0 '0 -eq 0 -a -d /' +t 0 '-s = "" -o "" = ""' +t 0 '"" = "" -o -s = ""' +t 1 '-s = "" -o -s = ""' +t 0 '-z x -o x = "#" -o x = x' +t 1 '-z y -o y = "#" -o y = x' +t 0 '0 -ne 0 -o ! -f /' +t 0 '1 -ne 0 -o ! -f /etc/passwd' +t 1 '0 -ne 0 -o ! -f /etc/passwd' + +t 0 '-n =' +t 1 '-z =' +t 1 '! =' +t 0 '-n -eq' +t 1 '-z -eq' +t 1 '! -eq' +t 0 '-n -a' +t 1 '-z -a' +t 1 '! -a' +t 0 '-n -o' +t 1 '-z -o' +t 1 '! -o' +t 1 '! -n =' +t 0 '! -z =' +t 0 '! ! =' +t 1 '! -n -eq' +t 0 '! -z -eq' +t 0 '! ! -eq' +t 1 '! -n -a' +t 0 '! -z -a' +t 0 '! ! -a' +t 1 '! -n -o' +t 0 '! -z -o' +t 0 '! ! -o' +t 0 '\( -n = \)' +t 1 '\( -z = \)' +t 1 '\( ! = \)' +t 0 '\( -n -eq \)' +t 1 '\( -z -eq \)' +t 1 '\( ! -eq \)' +t 0 '\( -n -a \)' +t 1 '\( -z -a \)' +t 1 '\( ! -a \)' +t 0 '\( -n -o \)' +t 1 '\( -z -o \)' +t 1 '\( ! -o \)' + +if [ "$FAILED" -ne 0 ]; then + exit 1 +fi + +printf '%s\n' "PASS" diff --git a/corebinutils/test/tests/test.sh b/corebinutils/test/tests/test.sh new file mode 100644 index 0000000000..debbbf81a1 --- /dev/null +++ b/corebinutils/test/tests/test.sh @@ -0,0 +1,479 @@ +#!/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" |
