Import VX multicall utility and applets

This commit is contained in:
2026-03-16 22:06:27 -05:00
parent 9a477cd852
commit 696cb27313
201 changed files with 35660 additions and 0 deletions
+109
View File
@@ -0,0 +1,109 @@
#!/bin/sh
# tests/harness.sh - Minimal POSIX test harness for VX.
#
# Source this file at the top of each test script. It provides:
# check_exit CMD EXPECTED_EXIT -- assert exit code
# check_eq ACTUAL EXPECTED MSG -- assert string equality
# check_file ACTUAL_FILE EXPECTED_FILE MSG -- assert file equality
# check_grep PATTERN FILE MSG -- assert pattern in file
# pass / fail / summary
#
# The test script must call summary() at the end.
_pass=0
_fail=0
_harness_tmpdir=""
# Resolve VX binary: prefer $VX env var, else ../builddir/vx from script dir
if [ -z "$VX" ]; then
_script_dir="$(cd "$(dirname "$0")" && pwd)"
VX="${_script_dir}/../../builddir/vx"
fi
export VX
setup_tmpdir() {
_harness_tmpdir="$(mktemp -d)"
cd "$_harness_tmpdir" || exit 1
}
cleanup_tmpdir() {
if [ -n "$_harness_tmpdir" ] && [ -d "$_harness_tmpdir" ]; then
rm -rf "$_harness_tmpdir"
fi
}
pass() {
_pass=$((_pass + 1))
printf " PASS: %s\n" "$1"
}
fail() {
_fail=$((_fail + 1))
printf " FAIL: %s\n" "$1"
if [ -n "$2" ]; then
printf " %s\n" "$2"
fi
}
# check_exit "description" expected_exit command [args...]
check_exit() {
_desc="$1"; shift
_expect="$1"; shift
"$@" >/dev/null 2>&1
_got=$?
if [ "$_got" -eq "$_expect" ]; then
pass "$_desc"
else
fail "$_desc" "expected exit=$_expect, got exit=$_got"
fi
}
# check_output "description" "expected_stdout" command [args...]
check_output() {
_desc="$1"; shift
_expect="$1"; shift
_got="$("$@" 2>/dev/null)" || true
if [ "$_got" = "$_expect" ]; then
pass "$_desc"
else
fail "$_desc" "expected: $(printf '%s' "$_expect" | head -c 200), got: $(printf '%s' "$_got" | head -c 200)"
fi
}
# check_eq "got" "expected" "description"
check_eq() {
if [ "$1" = "$2" ]; then
pass "$3"
else
fail "$3" "expected: $(printf '%s' "$2" | head -c 200), got: $(printf '%s' "$1" | head -c 200)"
fi
}
# check_file actual_file expected_file "description"
check_file() {
if diff -q "$1" "$2" >/dev/null 2>&1; then
pass "$3"
else
fail "$3" "files differ: $1 vs $2"
fi
}
# check_grep pattern file "description"
check_grep() {
if grep -q "$1" "$2" 2>/dev/null; then
pass "$3"
else
fail "$3" "pattern '$1' not found in $2"
fi
}
summary() {
cleanup_tmpdir
_total=$((_pass + _fail))
echo ""
printf "%s: %d passed, %d failed (of %d)\n" "$_test_name" "$_pass" "$_fail" "$_total"
if [ "$_fail" -gt 0 ]; then
exit 1
fi
exit 0
}
+60
View File
@@ -0,0 +1,60 @@
#!/bin/sh
# tests/test_cmp.sh - Tests for cmp applet
_test_name="cmp"
. "$(dirname "$0")/harness.sh"
_srcdir="$(cd "$(dirname "$0")/../src/cmp/tests" && pwd)"
setup_tmpdir
CMP="$VX cmp"
echo "Running cmp tests..."
# --- basic: identical files ---
echo "0123456789abcdef" > a
cp a a_copy
check_exit "basic: identical files exit 0" 0 $CMP a a_copy
# --- basic: different files ---
echo "0123456789abcdeg" > b
check_exit "basic: different files exit 1" 1 $CMP a b
# --- stdin comparison ---
check_exit "special: cmp a - (stdin identical)" 0 sh -c "$CMP a - < a"
check_exit "special: cmp - a (stdin identical)" 0 sh -c "$CMP - a < a"
check_exit "special: cmp a - (stdin different)" 1 sh -c "$CMP a - < b"
check_exit "special: cmp - a (stdin different)" 1 sh -c "$CMP - a < b"
# --- silent mode ---
check_exit "silent: -s identical" 0 $CMP -s a a_copy
check_exit "silent: -s different" 1 $CMP -s a b
# --- byte offset skip ---
echo -n '1234567890' > skip_a
echo -n 'abc567890' > skip_b
check_exit "skip: -i 4:3 matches" 0 $CMP -s -i 4:3 skip_a skip_b
# --- limit (-n) ---
echo -n "aaaabbbb" > lim_a
echo -n "aaaaxxxx" > lim_b
check_exit "limit: -n 4 identical" 0 $CMP -s -n 4 lim_a lim_b
check_exit "limit: -n 5 different" 1 $CMP -s -n 5 lim_a lim_b
check_exit "limit: full different" 1 $CMP -s lim_a lim_b
# --- -b flag (print differing bytes) ---
echo -n "abcd" > a
echo -n "abdd" > b
_got="$($CMP -b a b 2>/dev/null)" || true
_exp="$(cat "$_srcdir/b_flag.out")"
check_eq "$_got" "$_exp" "bflag: -b output matches"
# --- -bl flags ---
_got="$($CMP -bl a b 2>/dev/null)" || true
_exp="$(cat "$_srcdir/bl_flag.out")"
check_eq "$_got" "$_exp" "blflag: -bl output matches"
# --- nonexistent file ---
$CMP a NOFILE >/dev/null 2>&1
_rc=$?
check_eq "$_rc" "2" "error: nonexistent file exits 2"
summary
+101
View File
@@ -0,0 +1,101 @@
#!/bin/sh
# tests/test_diff.sh - Tests for diff applet
_test_name="diff"
. "$(dirname "$0")/harness.sh"
_srcdir="$(cd "$(dirname "$0")/../src/diff/tests" && pwd)"
setup_tmpdir
DIFF="$VX diff"
echo "Running diff tests..."
# --- simple: normal, ed, unified, nreverse, brief, ignore-case, whitespace ---
check_exit "simple: normal diff" 1 \
$DIFF "$_srcdir/input1.in" "$_srcdir/input2.in"
_got="$($DIFF "$_srcdir/input1.in" "$_srcdir/input2.in" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/simple.out")"
check_eq "$_got" "$_exp" "simple: normal output matches"
_got="$($DIFF -e "$_srcdir/input1.in" "$_srcdir/input2.in" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/simple_e.out")"
check_eq "$_got" "$_exp" "simple: ed output matches"
_got="$($DIFF -u -L input1 -L input2 "$_srcdir/input1.in" "$_srcdir/input2.in" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/simple_u.out")"
check_eq "$_got" "$_exp" "simple: unified output matches"
_got="$($DIFF -n "$_srcdir/input1.in" "$_srcdir/input2.in" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/simple_n.out")"
check_eq "$_got" "$_exp" "simple: nreverse output matches"
# brief mode
$DIFF -q "$_srcdir/input1.in" "$_srcdir/input2.in" >/dev/null 2>&1
check_eq "$?" "1" "simple: brief exit 1 on different"
check_exit "simple: brief exit 0 on identical" 0 \
$DIFF -q "$_srcdir/input1.in" "$_srcdir/input1.in"
# ignore case
_got="$($DIFF -i "$_srcdir/input_c1.in" "$_srcdir/input_c2.in" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/simple_i.out")"
check_eq "$_got" "$_exp" "simple: ignore-case output matches"
# ignore whitespace
_got="$($DIFF -w "$_srcdir/input_c1.in" "$_srcdir/input_c2.in" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/simple_w.out")"
check_eq "$_got" "$_exp" "simple: ignore-whitespace output matches"
# ignore space changes
_got="$($DIFF -b "$_srcdir/input_c1.in" "$_srcdir/input_c2.in" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/simple_b.out")"
check_eq "$_got" "$_exp" "simple: space-change output matches"
# --- unified with function names ---
_got="$($DIFF -up -L input_c1.in -L input_c2.in "$_srcdir/input_c1.in" "$_srcdir/input_c2.in" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/unified_p.out")"
check_eq "$_got" "$_exp" "unified: -p output matches"
# --- strip trailing CR ---
printf 'a\nb\r\nc\n' > cr_a.in
printf 'a\r\nb\r\nc\r\n' > cr_b.in
check_exit "stripcr: identical after strip" 0 \
$DIFF -up --strip-trailing-cr -L a -L b cr_a.in cr_b.in
# --- -B (ignore blank lines) ---
printf "A\nB\n" > bflag_a
printf "A\n\nB\n" > bflag_b
check_exit "Bflag: ignore blank lines" 0 $DIFF -B bflag_a bflag_b
# --- -w (ignore all whitespace) ---
printf 'a b\n' > ws_a
printf 'a b\n' > ws_b
check_exit "whitespace: -qw identical" 0 $DIFF -qw ws_a ws_b
# --- side-by-side ---
printf "A\nB\nC\n" > sby_a
printf "D\nB\nE\n" > sby_b
$DIFF -y sby_a sby_b > sby_out 2>&1 || true
check_grep "B" sby_out "side-by-side: contains common line"
check_grep "|" sby_out "side-by-side: contains change marker"
# --- brief recursive ---
mkdir -p rA rB
echo 1 > rA/test-file
echo 2 > rB/test-file
_got="$($DIFF -rq rA rB 2>/dev/null)" || true
check_eq "$_got" "Files rA/test-file and rB/test-file differ" "brief: recursive diff"
# --- identical files ---
check_exit "identical: exit 0" 0 $DIFF "$_srcdir/input1.in" "$_srcdir/input1.in"
# --- Nflag: treat absent files as empty ---
printf "foo" > nflag_a
check_exit "Nflag: absent second file" 1 $DIFF -N nflag_a NOFILE
# --- conflicting format flags ---
printf "A\n" > cfmt_a
printf "B\n" > cfmt_b
check_exit "conflicting: -c -u exits 2" 2 $DIFF -c -u cfmt_a cfmt_b
summary
+81
View File
@@ -0,0 +1,81 @@
#!/bin/sh
# tests/test_diff3.sh - Tests for diff3 applet
_test_name="diff3"
. "$(dirname "$0")/harness.sh"
_srcdir="$(cd "$(dirname "$0")/../src/diff3/tests" && pwd)"
setup_tmpdir
DIFF3="$VX diff3"
echo "Running diff3 tests..."
# --- basic 3-way diff ---
_got="$($DIFF3 "$_srcdir/1.txt" "$_srcdir/2.txt" "$_srcdir/3.txt" 2>/dev/null)"
_exp="$(cat "$_srcdir/1.out")"
check_eq "$_got" "$_exp" "basic: default output"
# --- strip trailing CR ---
_got="$($DIFF3 --strip-trailing-cr "$_srcdir/1cr.txt" "$_srcdir/2.txt" "$_srcdir/3.txt" 2>/dev/null)"
_exp="$(cat "$_srcdir/1.out")"
check_eq "$_got" "$_exp" "stripcr: matches default output"
# --- -T flag ---
_got="$($DIFF3 -T "$_srcdir/1.txt" "$_srcdir/2.txt" "$_srcdir/3.txt" 2>/dev/null)"
_exp="$(cat "$_srcdir/1t.out")"
check_eq "$_got" "$_exp" "Tflag: initial tab output"
# --- -e (ed script) ---
_got="$($DIFF3 -e "$_srcdir/1.txt" "$_srcdir/2.txt" "$_srcdir/3.txt" 2>/dev/null)"
_exp="$(cat "$_srcdir/2.out")"
check_eq "$_got" "$_exp" "ed: -e output"
# --- -E (overlap ed script with labels) ---
_got="$($DIFF3 -E -L 1 -L 2 -L 3 "$_srcdir/1.txt" "$_srcdir/2.txt" "$_srcdir/3.txt" 2>/dev/null)"
_exp="$(cat "$_srcdir/3.out")"
check_eq "$_got" "$_exp" "overlap: -E output"
# --- -X (only overlapping changes) ---
_got="$($DIFF3 -X -L 1 -L 2 -L 3 "$_srcdir/1.txt" "$_srcdir/2.txt" "$_srcdir/3.txt" 2>/dev/null)"
_exp="$(cat "$_srcdir/4.out")"
check_eq "$_got" "$_exp" "Xflag: -X output"
# --- -x (only overlapping, no labels) ---
_got="$($DIFF3 -x "$_srcdir/1.txt" "$_srcdir/2.txt" "$_srcdir/3.txt" 2>/dev/null)"
_exp="$(cat "$_srcdir/5.out")"
check_eq "$_got" "$_exp" "xflag: -x output"
# --- -3 (ed script for file 3 changes only) ---
_got="$($DIFF3 -3 "$_srcdir/1.txt" "$_srcdir/2.txt" "$_srcdir/3.txt" 2>/dev/null)"
_exp="$(cat "$_srcdir/6.out")"
check_eq "$_got" "$_exp" "3flag: -3 output"
# --- -i (append w/q commands) ---
_got="$($DIFF3 -i "$_srcdir/1.txt" "$_srcdir/2.txt" "$_srcdir/3.txt" 2>/dev/null)"
_exp="$(cat "$_srcdir/7.out")"
check_eq "$_got" "$_exp" "iflag: -i output"
# --- -A (show all changes) ---
$DIFF3 -A -L 1 -L 2 -L 3 "$_srcdir/1.txt" "$_srcdir/2.txt" "$_srcdir/3.txt" > Aout 2>/dev/null
_rc=$?
check_eq "$_rc" "1" "Aflag: exits 1 on conflicts"
check_file Aout "$_srcdir/8.out" "Aflag: output matches"
# --- long ed script ---
_got="$($DIFF3 -e "$_srcdir/long-m.txt" "$_srcdir/long-o.txt" "$_srcdir/long-y.txt" 2>/dev/null)"
_exp="$(cat "$_srcdir/long-ed.out")"
check_eq "$_got" "$_exp" "long-ed: output matches"
# --- long A ---
$DIFF3 -A -L long-m.txt -L long-o.txt -L long-y.txt \
"$_srcdir/long-m.txt" "$_srcdir/long-o.txt" "$_srcdir/long-y.txt" > longAout 2>/dev/null
check_file longAout "$_srcdir/long-A.out" "long-A: output matches"
# --- merge ---
$DIFF3 -m -L 1 -L 2 -L 3 "$_srcdir/1.txt" "$_srcdir/2.txt" "$_srcdir/3.txt" > mergeout 2>/dev/null
check_file mergeout "$_srcdir/9.out" "merge: output matches"
$DIFF3 -m -L long-m.txt -L long-o.txt -L long-y.txt \
"$_srcdir/long-m.txt" "$_srcdir/long-o.txt" "$_srcdir/long-y.txt" > longmergeout 2>/dev/null
check_file longmergeout "$_srcdir/long-merge.out" "long-merge: output matches"
summary
+60
View File
@@ -0,0 +1,60 @@
#!/bin/sh
# tests/test_find.sh - Tests for find applet
_test_name="find"
. "$(dirname "$0")/harness.sh"
setup_tmpdir
FIND="$VX find"
echo "Running find tests..."
mkdir -p tree/sub
printf 'hello\n' > tree/a.txt
printf 'world!!' > tree/sub/b.c
ln -s ../a.txt tree/sub/link_to_a
chmod 754 tree/sub/b.c
a_count="$($FIND tree -name '*.txt' -type f | wc -l | tr -d ' ')"
check_eq "$a_count" "1" "basic: -name and -type"
out="$($FIND tree -maxdepth 1 -type d | sort)"
exp="$(printf '%s\n' tree tree/sub)"
check_eq "$out" "$exp" "maxdepth: top-level directories"
out="$($FIND tree/sub -name '*.c' -exec echo FOUND:{} ';')"
check_eq "$out" "FOUND:tree/sub/b.c" "exec: substitution works"
out="$($FIND tree/sub -name 'b.c' -printf '%f|%h|%p|%s|%m\n')"
check_eq "$out" "b.c|tree/sub|tree/sub/b.c|7|0754" "printf: common directives"
out="$($FIND tree/sub -name 'b.c' -printf '%TY-%Tm-%Td %TH:%TM\n')"
case "$out" in
????-??-??' '??:??) pass "printf: time fields" ;;
*) fail "printf: time fields" "got: $out" ;;
esac
out="$($FIND tree/sub -type l -printf '%l\n')"
check_eq "$out" "../a.txt" "printf: symlink target"
expected_printf="$(printf 'A\nB\tC')"
out="$($FIND tree/sub -name 'b.c' -printf 'A\nB\tC')"
check_eq "$out" "$expected_printf" "printf: backslash escapes"
fstype="$(stat -f -c '%T' . 2>/dev/null)"
if [ -n "$fstype" ]; then
out="$($FIND . -maxdepth 1 -fstype "$fstype" -name tree)"
check_eq "$out" "./tree" "fstype: current fs matches"
fi
mkdir daystart
printf 'y\n' > daystart/late_yesterday
if touch -d 'yesterday 23:59' daystart/late_yesterday 2>/dev/null; then
out="$($FIND daystart -daystart -name late_yesterday -mtime 1)"
check_eq "$out" "daystart/late_yesterday" "daystart: shifts boundary to start of day"
else
pass "daystart: touch -d unavailable (skip)"
fi
check_exit "exit: no path exits 1" 1 $FIND
summary
+171
View File
@@ -0,0 +1,171 @@
#!/bin/sh
# tests/test_grep.sh - Tests for grep/egrep/fgrep applets
_test_name="grep"
. "$(dirname "$0")/harness.sh"
setup_tmpdir
GREP="$VX grep"
EGREP="$VX egrep"
FGREP="$VX fgrep"
echo "Running grep tests..."
# --- create test files ---
cat > haystack.txt <<'EOF'
Hello World
hello world
HELLO WORLD
foo bar baz
The quick brown fox
jumps over the lazy dog
line with numbers 12345
another line here
foobar
EOF
cat > patterns.txt <<'EOF'
foo
bar
EOF
# --- basic match ---
_got="$($GREP 'Hello' haystack.txt)"
check_eq "$_got" "Hello World" "basic: literal match"
# --- case insensitive ---
_count="$($GREP -ic 'hello' haystack.txt)"
check_eq "$_count" "3" "iflag: case insensitive count"
# --- -v invert ---
_count="$($GREP -vic 'hello' haystack.txt | tr -d ' ')"
_total="$(wc -l < haystack.txt | tr -d ' ')"
_expect=$((${_total} - 3))
check_eq "$_count" "$_expect" "vflag: invert count"
# --- -n line numbers ---
_got="$($GREP -n 'foo bar' haystack.txt)"
check_eq "$_got" "4:foo bar baz" "nflag: line number"
# --- -c count ---
_got="$($GREP -c 'line' haystack.txt)"
check_eq "$_got" "2" "cflag: count lines"
# --- -l files-with-matches ---
_got="$($GREP -l 'Hello' haystack.txt)"
check_eq "$_got" "haystack.txt" "lflag: filename"
# --- -L files-without-match ---
echo "no match here" > other.txt
_got="$($GREP -L 'Hello' haystack.txt other.txt)"
check_eq "$_got" "other.txt" "Lflag: no-match filename"
# --- -w word match ---
_got="$($GREP -wc 'foo' haystack.txt)"
check_eq "$_got" "1" "wflag: word boundary (foo not foobar)"
# --- -x line match ---
_got="$($GREP -x 'foobar' haystack.txt)"
check_eq "$_got" "foobar" "xflag: exact line match"
# --- -o only matching ---
_got="$($GREP -o 'fox' haystack.txt)"
check_eq "$_got" "fox" "oflag: only matching part"
# --- -m max count ---
_got="$($GREP -m1 'line' haystack.txt)"
_count="$(printf '%s\n' "$_got" | wc -l | tr -d ' ')"
check_eq "$_count" "1" "mflag: max count 1"
# --- -e multiple patterns ---
_count="$($GREP -c -e 'Hello' -e 'quick' haystack.txt)"
check_eq "$_count" "2" "eflag: multiple patterns"
# --- -f pattern file ---
_count="$($GREP -c -f patterns.txt haystack.txt)"
check_eq "$_count" "2" "fflag: pattern file (foo, bar match 2 lines)"
# --- -q quiet mode ---
$GREP -q 'Hello' haystack.txt
check_eq "$?" "0" "qflag: quiet match exits 0"
$GREP -q 'NOMATCH_XYZ' haystack.txt
check_eq "$?" "1" "qflag: quiet no-match exits 1"
# --- -s suppress errors ---
$GREP -s 'test' nonexistent_file 2>err_out
_err="$(cat err_out)"
check_eq "$_err" "" "sflag: suppresses error messages"
# --- -b byte offset ---
_got="$($GREP -b 'foo bar' haystack.txt | cut -d: -f1)"
# "foo bar" is on line 4, after 3 lines + newlines
test -n "$_got"
check_eq "$?" "0" "bflag: byte offset present"
# --- -H / -h filename control ---
_got="$($GREP -H 'Hello' haystack.txt)"
echo "$_got" | grep -q '^haystack.txt:'
check_eq "$?" "0" "Hflag: filename shown"
_got="$($GREP -h 'Hello' haystack.txt)"
echo "$_got" | grep -qv ':'
check_eq "$?" "0" "hflag: no filename"
# --- extended regex (egrep / -E) ---
_got="$($GREP -Ec 'foo|quick' haystack.txt)"
check_eq "$_got" "3" "Eflag: extended regex"
_got="$($EGREP -c 'foo|quick' haystack.txt)"
check_eq "$_got" "3" "egrep: dispatch works"
# --- fixed strings (fgrep / -F) ---
_got="$($FGREP -c 'foo' haystack.txt)"
check_eq "$_got" "2" "fgrep: fixed strings"
# --- context: -A after ---
_count="$($GREP -A1 'quick' haystack.txt | wc -l | tr -d ' ')"
check_eq "$_count" "2" "Aflag: after context"
# --- context: -B before ---
_count="$($GREP -B1 'quick' haystack.txt | wc -l | tr -d ' ')"
check_eq "$_count" "2" "Bflag: before context"
# --- context: -C both ---
_count="$($GREP -C1 'quick' haystack.txt | wc -l | tr -d ' ')"
check_eq "$_count" "3" "Cflag: context both sides"
# --- stdin ---
_got="$(echo 'test line' | $GREP 'test')"
check_eq "$_got" "test line" "stdin: pipe works"
# --- exit codes ---
check_exit "exit: match returns 0" 0 $GREP -q 'Hello' haystack.txt
check_exit "exit: no match returns 1" 1 $GREP -q 'ZZZNOTFOUND' haystack.txt
check_exit "exit: error returns 2" 2 $GREP 'test' --bogus-flag 2>/dev/null
# --- recursive ---
mkdir -p subdir
echo "findme here" > subdir/nested.txt
_got="$($GREP -r 'findme' .)"
echo "$_got" | grep -q 'nested.txt'
check_eq "$?" "0" "rflag: recursive find"
# --- --include ---
echo "match" > inc_yes.c
echo "match" > inc_no.txt
_got="$($GREP -r --include='*.c' 'match' .)"
echo "$_got" | grep -q 'inc_yes.c'
check_eq "$?" "0" "include: *.c matches"
echo "$_got" | grep -q 'inc_no.txt'
check_eq "$?" "1" "include: *.txt excluded"
# --- --exclude ---
_got="$($GREP -r --exclude='*.txt' 'match' .)"
echo "$_got" | grep -q 'inc_yes.c'
check_eq "$?" "0" "exclude: *.c still matches"
# --- -z null data ---
printf 'aaa\0bbb\0ccc\0' > nulldata
_count="$($GREP -zc 'bbb' nulldata)"
check_eq "$_count" "1" "zflag: null-delimited"
summary
+105
View File
@@ -0,0 +1,105 @@
#!/bin/sh
# tests/test_gzip.sh - Tests for gzip/gunzip/zcat applets
_test_name="gzip"
. "$(dirname "$0")/harness.sh"
setup_tmpdir
GZIP_CMD="$VX gzip"
GUNZIP="$VX gunzip"
ZCAT="$VX zcat"
echo "Running gzip tests..."
# --- basic compression/decompression ---
printf 'Hello, World!\n' > hello.txt
cp hello.txt hello.orig
$GZIP_CMD hello.txt
check_exit "basic: compress creates .gz" 0 test -f hello.txt.gz
check_exit "basic: original removed" 1 test -f hello.txt
$GUNZIP hello.txt.gz
check_exit "basic: decompress creates original" 0 test -f hello.txt
check_file hello.txt hello.orig "basic: roundtrip matches"
# --- -k (keep) ---
cp hello.orig keeptest.txt
$GZIP_CMD -k keeptest.txt
check_exit "keep: .gz created" 0 test -f keeptest.txt.gz
check_exit "keep: original kept" 0 test -f keeptest.txt
# --- -c (stdout) ---
cp hello.orig stdout_test.txt
$GZIP_CMD -c stdout_test.txt > stdout_test.gz
check_exit "stdout: .gz created" 0 test -f stdout_test.gz
check_exit "stdout: original kept" 0 test -f stdout_test.txt
$GUNZIP -c stdout_test.gz > stdout_test_round.txt
check_file stdout_test_round.txt hello.orig "stdout: roundtrip matches"
# --- zcat ---
_got="$($ZCAT stdout_test.gz)"
_exp="$(cat hello.orig)"
check_eq "$_got" "$_exp" "zcat: output matches original"
# --- -d flag (decompress via gzip -d) ---
cp stdout_test.gz dtest.gz
$GZIP_CMD -d dtest.gz
check_exit "dflag: decompresses" 0 test -f dtest
check_file dtest hello.orig "dflag: output matches"
# --- -f (force overwrite) ---
cp hello.orig force_test.txt
$GZIP_CMD force_test.txt
cp hello.orig force_test.txt
$GZIP_CMD -f force_test.txt
check_exit "force: overwrites .gz" 0 test -f force_test.txt.gz
# --- -t (test integrity) ---
cp hello.orig ttest.txt
$GZIP_CMD ttest.txt
check_exit "test: valid gz passes" 0 $GZIP_CMD -t ttest.txt.gz
# corrupt the gzip header magic bytes
printf '\x00\x00' | dd of=ttest.txt.gz bs=1 seek=0 conv=notrunc 2>/dev/null
check_exit "test: corrupt gz fails" 1 $GZIP_CMD -t ttest.txt.gz
# --- -l (list) ---
cp hello.orig ltest.txt
$GZIP_CMD ltest.txt
$GZIP_CMD -l ltest.txt.gz > list_out 2>&1
_rc=$?
check_eq "$_rc" "0" "list: exits 0"
check_grep "compressed" list_out "list: prints header"
# --- -n (no name) ---
cp hello.orig ntest.txt
$GZIP_CMD -n ntest.txt
check_exit "nflag: compress succeeds" 0 test -f ntest.txt.gz
# --- -1 through -9 (compression levels) ---
for lvl in 1 9; do
cp hello.orig "level${lvl}.txt"
check_exit "level: -${lvl} compresses" 0 $GZIP_CMD "-${lvl}" "level${lvl}.txt"
done
# --- pipe mode (stdin/stdout) ---
$GZIP_CMD < hello.orig > pipe_test.gz
$GUNZIP < pipe_test.gz > pipe_test.txt
check_file pipe_test.txt hello.orig "pipe: stdin roundtrip"
# --- multiple files ---
printf 'aaa\n' > multi_a.txt
printf 'bbb\n' > multi_b.txt
$GZIP_CMD multi_a.txt multi_b.txt
check_exit "multi: a.gz exists" 0 test -f multi_a.txt.gz
check_exit "multi: b.gz exists" 0 test -f multi_b.txt.gz
# --- gunzip argv[0] dispatch ---
cp hello.orig gun_test.txt
$GZIP_CMD gun_test.txt
$GUNZIP gun_test.txt.gz
check_file gun_test.txt hello.orig "gunzip: dispatch works"
# --- exit codes ---
check_exit "exit: compress nonexistent fails" 1 $GZIP_CMD nonexistent_file_xyz
summary
+62
View File
@@ -0,0 +1,62 @@
#!/bin/sh
# tests/test_patch.sh - Tests for patch applet
_test_name="patch"
. "$(dirname "$0")/harness.sh"
_srcdir="$(cd "$(dirname "$0")/../src/patch/tests" && pwd)"
setup_tmpdir
PATCH="$VX patch"
echo "Running patch tests..."
# --- basic: apply unified diffs from various starting points ---
printf "a\nb\nc\nd\ne\nf\ng\nh\ni\n" > foo_full
printf "a\nb\nc\n" > foo_start
printf "g\nh\ni\n" > foo_end
printf "d\ne\nf\n" > foo_middle
$VX diff -u foo_start foo_full > foo_start2full.diff || true
$VX diff -u foo_end foo_full > foo_end2full.diff || true
$VX diff -u foo_middle foo_full > foo_mid2full.diff || true
# Each diff should be 12 lines (9 content lines + 3 header)
_lines=$(wc -l < foo_start2full.diff | tr -d ' ')
check_eq "$_lines" "12" "basic: start diff is 12 lines"
_lines=$(wc -l < foo_end2full.diff | tr -d ' ')
check_eq "$_lines" "12" "basic: end diff is 12 lines"
_lines=$(wc -l < foo_mid2full.diff | tr -d ' ')
check_eq "$_lines" "12" "basic: mid diff is 12 lines"
# Apply patches
$PATCH foo_start foo_start2full.diff -o foo_start2full >/dev/null 2>&1
check_exit "basic: apply start->full" 0 diff -q foo_start2full foo_full
$PATCH foo_end foo_end2full.diff -o foo_end2full >/dev/null 2>&1
check_exit "basic: apply end->full" 0 diff -q foo_end2full foo_full
$PATCH foo_middle foo_mid2full.diff -o foo_mid2full >/dev/null 2>&1
check_exit "basic: apply mid->full" 0 diff -q foo_mid2full foo_full
# --- limited context: PR74127 regression ---
check_exit "limited_ctx: bad diff rejected" 1 \
$PATCH -o _.out "$_srcdir/PR74127.in" "$_srcdir/PR74127-repro.diff"
check_exit "limited_ctx: good diff accepted" 0 \
$PATCH -o _.out "$_srcdir/PR74127.in" "$_srcdir/PR74127-good.diff"
# --- file creation ---
echo "x" > fc_foo
$VX diff -u /dev/null fc_foo > fc_foo.diff || true
rm fc_foo
$PATCH -s < fc_foo.diff >/dev/null 2>&1
check_exit "file_creation: creates file" 0 test -f fc_foo
# --- reverse removal ---
echo "x" > rev_foo
$VX diff -u /dev/null rev_foo > rev_foo.diff || true
$PATCH -Rs < rev_foo.diff >/dev/null 2>&1
check_exit "file_removal: file removed" 1 test -f rev_foo
summary
+71
View File
@@ -0,0 +1,71 @@
#!/bin/sh
# tests/test_sdiff.sh - Tests for sdiff applet
_test_name="sdiff"
. "$(dirname "$0")/harness.sh"
_srcdir="$(cd "$(dirname "$0")/../src/sdiff/tests" && pwd)"
setup_tmpdir
SDIFF="$VX sdiff"
echo "Running sdiff tests..."
# --- flags: -l, -s, -w ---
_got="$($SDIFF -l "$_srcdir/d_input1" "$_srcdir/d_input2" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/d_flags_l.out")"
check_eq "$_got" "$_exp" "flags: -l output matches"
_got="$($SDIFF -s "$_srcdir/d_input1" "$_srcdir/d_input2" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/d_flags_s.out")"
check_eq "$_got" "$_exp" "flags: -s output matches"
_got="$($SDIFF -w 125 "$_srcdir/d_input1" "$_srcdir/d_input2" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/d_flags_w.out")"
check_eq "$_got" "$_exp" "flags: -w output matches"
# --- same file ---
_got="$($SDIFF "$_srcdir/d_input1" "$_srcdir/d_input1" 2>/dev/null)"
_exp="$(cat "$_srcdir/d_same.out")"
check_eq "$_got" "$_exp" "same: identical file output matches"
# --- tabs ---
_got="$($SDIFF "$_srcdir/d_tabs1.in" "$_srcdir/d_tabs2.in" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/d_tabs.out")"
check_eq "$_got" "$_exp" "tabs: tab output matches"
# --- tabends ---
_got="$($SDIFF -w30 "$_srcdir/d_tabends.in" /dev/null 2>/dev/null)" || true
_exp="$(cat "$_srcdir/d_tabends_a.out")"
check_eq "$_got" "$_exp" "tabends: file vs null (a)"
_got="$($SDIFF -w30 /dev/null "$_srcdir/d_tabends.in" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/d_tabends_b.out")"
check_eq "$_got" "$_exp" "tabends: null vs file (b)"
_got="$($SDIFF -w19 "$_srcdir/d_tabends.in" /dev/null 2>/dev/null)" || true
_exp="$(cat "$_srcdir/d_tabends_c.out")"
check_eq "$_got" "$_exp" "tabends: narrow width (c)"
# --- oneline ---
_got="$($SDIFF /dev/null "$_srcdir/d_oneline.in" 2>/dev/null)" || true
_exp="$(cat "$_srcdir/d_oneline_a.out")"
check_eq "$_got" "$_exp" "oneline: null vs file"
_got="$($SDIFF "$_srcdir/d_oneline.in" /dev/null 2>/dev/null)" || true
_exp="$(cat "$_srcdir/d_oneline_b.out")"
check_eq "$_got" "$_exp" "oneline: file vs null"
# --- basic side-by-side ---
printf "A\nB\nC\n" > sby_a
printf "D\nB\nE\n" > sby_b
$SDIFF sby_a sby_b > sby_out 2>&1 || true
check_grep "|" sby_out "side-by-side: contains change marker"
check_grep "B" sby_out "side-by-side: contains common line"
# --- exit codes ---
printf "a\n" > ex_a
printf "b\n" > ex_b
cp ex_a ex_a2
check_exit "exit: identical files exit 0" 0 $SDIFF ex_a ex_a2
check_exit "exit: different files exit 1" 1 $SDIFF ex_a ex_b
summary
+77
View File
@@ -0,0 +1,77 @@
#!/bin/sh
# tests/test_which.sh - Tests for which applet
_test_name="which"
. "$(dirname "$0")/harness.sh"
setup_tmpdir
WHICH="$VX which"
echo "Running which tests..."
# --- basic: find a known binary ---
_got="$($WHICH sh 2>/dev/null)"
# sh should resolve to something in PATH
if [ -n "$_got" ] && [ -x "$_got" ]; then
pass "basic: finds sh"
else
fail "basic: finds sh" "got: $_got"
fi
# --- basic: nonexistent command ---
check_exit "basic: nonexistent exits 1" 1 $WHICH this_command_does_not_exist_xyz
# --- -s (silent) ---
_got="$($WHICH -s sh 2>/dev/null)"
check_eq "$_got" "" "silent: -s produces no output"
check_exit "silent: -s sh exits 0" 0 $WHICH -s sh
check_exit "silent: -s nonexistent exits 1" 1 $WHICH -s this_command_does_not_exist_xyz
# --- -a (all matches) ---
# Create a temp dir with a duplicate "testprog" and prepend it to PATH
mkdir -p bin1 bin2
printf '#!/bin/sh\n' > bin1/testprog
printf '#!/bin/sh\n' > bin2/testprog
chmod +x bin1/testprog bin2/testprog
_old_path="$PATH"
PATH="$(pwd)/bin1:$(pwd)/bin2:$PATH"
export PATH
# Without -a, should find exactly 1
_count="$($WHICH testprog 2>/dev/null | wc -l | tr -d ' ')"
check_eq "$_count" "1" "allpaths: default finds 1"
# With -a, should find at least 2
_count="$($WHICH -a testprog 2>/dev/null | wc -l | tr -d ' ')"
if [ "$_count" -ge 2 ]; then
pass "allpaths: -a finds multiple"
else
fail "allpaths: -a finds multiple" "got $_count matches"
fi
PATH="$_old_path"
export PATH
# --- multiple arguments ---
$WHICH sh cat > multi_out 2>/dev/null
_lines=$(wc -l < multi_out | tr -d ' ')
check_eq "$_lines" "2" "multi: two args produce two lines"
# --- absolute path passthrough ---
_got="$($WHICH /bin/sh 2>/dev/null)"
if [ "$_got" = "/bin/sh" ] || [ "$_got" = "" ]; then
# FreeBSD which passes through absolute paths if executable
if [ -x /bin/sh ]; then
check_eq "$_got" "/bin/sh" "absolute: /bin/sh passes through"
else
pass "absolute: /bin/sh not executable (skip)"
fi
else
fail "absolute: /bin/sh passes through" "got: $_got"
fi
# --- no args prints usage and exits 1 ---
$WHICH >/dev/null 2>&1
_rc=$?
check_eq "$_rc" "1" "usage: no args exits 1"
summary
+35
View File
@@ -0,0 +1,35 @@
#!/bin/sh
# tests/test_xargs.sh - Tests for xargs applet
_test_name="xargs"
. "$(dirname "$0")/harness.sh"
setup_tmpdir
XARGS="$VX xargs"
echo "Running xargs tests..."
out="$(printf 'a\nb\n' | $XARGS echo ITEM:)"
check_eq "$out" "ITEM: a b" "basic: appends stdin items"
out="$(printf 'a\nb\nc\n' | $XARGS -n 2 echo CHUNK:)"
check_eq "$out" "CHUNK: a b
CHUNK: c" "nflag: max args"
out="$(printf 'one\ntwo\n' | $XARGS -I '{}' echo X{}Y)"
check_eq "$out" "XoneY
XtwoY" "Iflag: replacement"
out="$(printf 'one\ntwo\n' | $XARGS -J '{}' echo PRE POST '{}')"
check_eq "$out" "PRE POST one two" "Jflag: replacement at custom position"
printf 'aa\0bb cc\0' > nul
out="$(cat nul | $XARGS -0 echo Z:)"
check_eq "$out" "Z: aa bb cc" "0flag: NUL-delimited input"
out="$(printf 'a\nb\n' | $XARGS -L 1 echo LINE:)"
check_eq "$out" "LINE: a
LINE: b" "Lflag: one line per command"
check_exit "exit: bad option exits 1" 1 $XARGS --definitely-not-a-real-option
summary