Implementation:
misc/true.rs(12 lines)misc/false.rs(12 lines)misc/test.rs(615 lines) — also installed as[Tests:misc/tests/{true,false,test}/mod.rs(26 + 26 + 336 lines) Spec: POSIX.1-2024 (IEEE Std 1003.1-2024), Vol. 3 (XCU) §3 —false(p. 2920),test(pp. 3431–3436),true(pp. 3466–3467) Reference: mega-PDF~/tmp/POSIX.2024.pdf(no sliced tree available; same handicap as them4/make/calcaudits). Critical/Major-class findings behaviorally verified against./target/release/{test,true,false}. Date: 2026-06-13
This is the cleanest crate audited so far. true and false are textbook-conforming one-liners. test/[ implements the full POSIX.1-2024 primary set with the correct argument-count precedence algorithm (0/1/2/3/4/>4), the [ … ] bracket form, ! negation, and correct 0/1/>1 exit codes — all behaviorally verified. No Critical or Major conformance defects were found. The only real divergence is that the </> string operators compare by Unicode-scalar (byte) order instead of LC_COLLATE locale collation (the spec explicitly mandates collation). Everything else is informational: the removed -a/-o/(/) operators are still implemented as an extension (legal — POSIX leaves >4-argument behavior "unspecified"), and integer operands are bounded to i64 and reject leading blanks.
None.
None.
- #1 —
test</>ignoreLC_COLLATE; compare by byte/scalar order.misc/test.rs:274-275(eval_binary_struses Rusts1 < s2);LC_COLLATEis never read. Spec (Vol. 3 p. 3433): "s1 < s2True if s1 collates before s2 in the current locale" and (p. 3434) "LC_COLLATE— Determine the locale for the behavior of the>and<string comparison operators." Verified: underLC_ALL=en_US.UTF-8, glibc collatesa<B, buttest a \< Bexits 1 (false) because bytea(0x61) >B(0x42). DIVERGES. ✓ fixed (Phase 1) —</>now route throughlibc::strcoll. Root cause was deeper than the symptom:gettext-rs'ssetlocaledoes not establish the C library's global locale, somain()now also callslibc::setlocale(LC_ALL, "")(misc/test.rs). Regression tests assert C-locale byte order and best-efforten_US.UTF-8collation. - #2 — Removed operators
-a/-o/(/)are implemented inconsistently.misc/test.rs:362-494(ExprParser) supports-a,-o,!,(,)for the >4-argument path, but the 3-argument formstest x -a y/test x -o yreturnedsyntax error(exit 2). Spec APPLICATION USAGE (Vol. 3 p. 3435): "The-aand-obinary primaries and the'('and')'operators have been removed." Both behaviors fall in POSIX's "unspecified" zone, so neither is non-conforming — but the split was surprising. ✓ fixed (Phase 3) — made uniform: the 3- and 4-argument "otherwise unspecified" cases now fall back to a sharedeval_with_parserhelper, sotest x -a yand friends evaluate as the historical extension. Documented as a deliberate compatibility extension in the helper's doc comment. Genuinely malformed expressions (test a b c) still error. Tested intest_legacy_operators_uniform. - #3 — Integer operands are
i64-bounded and reject surrounding whitespace.misc/test.rs:230-250(eval_binary_intusesstr::parse::<i64>).test 99999999999999999999 -gt 1→integer expression expected(exit 2);test ' 5' -eq 5→ error. POSIX says only "integers … algebraically" with no stated bound, and historicaltesttolerates leading blanks. ✓ fixed (Phase 2) — addedparse_inthelper thattrim()s surrounding blanks before parsing; thei64bound is retained (overflow is still diagnosed, as in GNU). Tested intest_intops_operands. - #4 — Dead unreachable branch in
eval_unary.misc/test.rs:175-178printedunknown operatorand returned false, but every caller pre-checksparse_unary_op(...).is_some(), so theNonearm was unreachable. Code-quality only (CLAUDE.md forbids dead code), not a conformance issue. ✓ fixed (Phase 3) —eval_unarynow takes a parsed&UnaryOp; the two callers bind theSome(op)directly, eliminating the dead arm.
- SYNOPSIS / OPTIONS / OPERANDS CONFORMS —
true(no options, no operands).misc/true.rs:10-12. - DESCRIPTION / EXIT STATUS CONFORMS — "shall return with exit code zero." Calls
std::process::exit(0). Verifiedtrue,true foo bar,true --all exit 0. - Accepts and discards
--CONFORMS — spec (p. 3467 APPLICATION USAGE) requires only thattrue"accept, and discard, a first argument of--"; ignoring all argv satisfies this.misc/true.rs:10. - No
--help/--versionCONFORMS — correctly omits the GNU coreutils extension; POSIXtruetakes no options. - STDIN / STDOUT / STDERR / ENV / signals — all "Not used" / "Default"; trivially conforms.
- DESCRIPTION / EXIT STATUS CONFORMS — spec: "shall always exit with a value between 1 and 125, inclusive." Calls
std::process::exit(1). Verifiedfalse,false fooexit 1.misc/false.rs:10-12. - OPTIONS / OPERANDS / STDIN / STDOUT / STDERR / ENV CONFORMS — all "None." / "Not used."
- No options;
--not special CONFORMS — spec OPTIONS (p. 3432): "shall not recognize the--argument … No options shall be supported." Implementation never parses options (no clap). Verifiedtest -- = --→--treated as string, exit 0.misc/test.rs:584-605. -
[bracket form requires trailing]CONFORMS — basename of argv[0] selects[vstest; final]is required and stripped, not counted in the argument-count algorithm.misc/test.rs:587-600. Verified via symlink:[ -n x ]→ 0;[ -n x→missing closing bracket, exit 2.
-
-b,-c,-d,-e,-f,-p,-S,-sCONFORMS — file-type/size viametadata()(follows symlinks per spec).misc/test.rs:144-153. -
-g(SGID),-u(SUID) CONFORMS —mode() & 0o2000/0o4000.misc/test.rs:149,153. -
-h,-LCONFORMS — usesymlink_metadata()and do not follow the final symlink, exactly as the spec carves out.misc/test.rs:117-122. -
-r,-w,-xCONFORMS — uselibc::access()(effective-permission check per §1.1.1.4), not a mode-bit guess.misc/test.rs:124-133,105-111. -
-tCONFORMS — parses fd number,BorrowedFd::is_terminal(); non-numeric or invalid fd → false.misc/test.rs:160-170. -
-n,-zCONFORMS — string length non-zero / zero viais_empty().misc/test.rs:89-91. - Symlink-resolution rule CONFORMS — all primaries except
-h/-Lresolve symlinks (spec p. 3433).misc/test.rs:135-141.
-
-efCONFORMS — same(dev, ino).misc/test.rs:289-297. -
-nt,-otCONFORMS — including the "one side unresolvable" rules (newer-than true if p1 exists and p2 doesn't; older-than symmetric).misc/test.rs:299-323. -
=,!=CONFORMS — byte-exact string identity.misc/test.rs:272-273. -
<,>CONFORMS — ✓ fixed (#1): now collate vialibc::strcollunder the activeLC_COLLATE.misc/test.rs(strcollhelper +eval_binary_str). -
-eq,-ne,-lt,-gt,-ge,-leCONFORMS —i64algebraic comparison; non-integer operand → diagnostic + exit 2 (per "an error occurred").misc/test.rs:230-268. ✓ #3 fixed: surrounding blanks now trimmed viaparse_int.
- 0 args → false (1) CONFORMS.
misc/test.rs:499. Verified. - 1 arg → true iff
$1non-null CONFORMS.misc/test.rs:501-507. Verifiedtest x→0,test ''→1;test -n/test -f(1 arg) → true (operator-looking string is non-null). - 2 args CONFORMS —
! $2(true iff$2null) handled before unary-primary; unknown$1→unary operator expected, exit 2 (the spec's "unspecified" case).misc/test.rs:509-529. Verified! ''→0,! x→1,-q x→exit 2. - 3 args CONFORMS — binary primary checked first, then
!-negate-2-arg, then (legacy)( $2 ). Order matches spec bullets.misc/test.rs:531-549. Verified= = =→0,! = =→1 (binary wins),! -f /x→0. - 4 args CONFORMS —
! <3-arg>negation, then legacy( $2 $3 ).misc/test.rs:551-561. Verified. - 3/4/>4 args — extension in "unspecified" space CONFORMS. Recursive-descent
ExprParser(-o<-a<!< primary/()precedence, matching historicaltest) reached via the sharedeval_with_parserhelper from the 3-, 4-, and >4-argument paths. ✓ #2 fixed: uniform across all arities. Tested intest_expr_precedence.
-
LANG,LC_ALL,LC_CTYPE,LC_MESSAGES,NLSPATHCONFORMS —setlocale(LcAll, "")+textdomain/bind_textdomain_codeset; diagnostics go throughgettext.misc/test.rs:580-582. -
LC_COLLATECONFORMS — ✓ fixed (#1): now consulted viastrcollfor</>oncelibc::setlocale(LC_ALL, "")is called inmain(). -
LC_CTYPEbyte-vs-char CONFORMS in practice — only emptiness (-n/-z) and byte-exact=depend on it; both are correct on byte boundaries.
- STDIN not used CONFORMS — no read path.
- STDOUT not used CONFORMS — nothing written to stdout.
- STDERR diagnostics only CONFORMS — all error strings via
eprintln!(misc/test.rs:176,234,335,452,471,482,548,560,571,597,611), gettext-localized. - ASYNCHRONOUS EVENTS = Default CONFORMS — no handlers needed.
- 0 / 1 / >1 CONFORMS —
True→exit 0,False→exit 1,Error→exit 2.misc/test.rs:607-614. Verified across all batches (true expr→0, false expr→1, syntax/integer/unknown-operator errors→2).
Existing misc/tests/test/mod.rs (336 lines) covers a broad slice: -d -e -f -h -L -r -s -w -x -n -z -ef -eq -ne -lt -gt -ge -le = != < > -a -o, plus bracket form and !.
Coverage (all gaps now closed in Phase 4):
-
-b(block),-c(char),-S(socket),-p(FIFO) device-type primaries — ✓ added (test_char_device,test_block_device,test_fifo,test_socket) -
-g(SGID),-u(SUID) mode-bit primaries — ✓ added (test_setgid_setuid, with a graceful skip when the bit is stripped) -
-tterminal test (true and false fd cases) — ✓ added (test_terminal; non-tty/invalid/non-numeric fd cases) -
-nt/-ottimestamp comparison (both files exist; one missing) — ✓ added (test_newer_older, mtimes set viautimes) -
LC_COLLATEcollation behavior of</>— ✓ added (test_str_collation) - Integer overflow / leading-blank operand error paths (#3) — ✓ added (
test_intops_operands) -
>4-argumentExprParserprecedence (-atighter than-o,!, nested()) — ✓ added (test_expr_precedence) -
true/falseargument-discard (true --,false foo) — ✓ added (true_ignores_arguments,false_ignores_arguments)
- PR A — "test: locale-aware string collation" (#1): route
</>throughstrcoll/LC_COLLATE; add anen_US.UTF-8collation test (a < B). The one genuine conformance fix. - PR B — "test: integer operand robustness" (#3): trim surrounding blanks before
i64::parse; add overflow/whitespace tests. Optional. - PR C — "test: tidy legacy-operator handling + dead code" (#2, #4): decide on uniform vs compound-only
-a/-o/()acceptance and document it; remove the unreachableeval_unaryarm. - PR D — "test: fill coverage gaps": device/mode primaries (
-b -c -S -p -g -u),-t,-nt/-ot, andExprParserprecedence tests.
Status: all findings (#1–#4) and PR D coverage landed on branch misc-audit across four phases (collation → integer operands → uniform legacy operators + dead-code → coverage tests). All boxes above are ticked; misc test suite passes 37 tests with zero clippy warnings.
Audit method: full per-utility spec read from the mega-PDF (true/false/test sections), full implementation read, behavioral verification of every Minor finding against release binaries (collation, removed-operator split, integer bounds, exit codes, bracket form, argument-count algorithm). No code was modified.