zoe-favorites-test: cover all four tiers (Python + C + asm + asm-full)

Two changes, one wiring.

1. rhoff gets a Birthday-bound iteration cap. Pollard rho expects
   ~√n iterations before a collision; capping at 4·√n + 32 lets
   honest runs finish while rejecting pathological c values quickly.
   rho's outer retry draws a new c and keeps the total work bounded.
   Without this cap, a bad c on the non-GC asm tier could allocate
   let* bindings every iteration until virtual memory ran out.
   (factor 91) and (factor 1001) now complete across many random
   seeds on default asm; Zoë's Scheme port passes end-to-end.

2. tests/ursa-scheme.lsp — Scheme-port-only half of the acceptance
   suite. Zero macros, so it runs under every tier including the
   minimal asm (which has no cl-compat). Also drops the vector
   literal `#(...)` (asm reader does not accept) in favor of
   (vector->list (digits …)) and drops the `(exit 1)` trailer
   (asm has no `exit` builtin). The new file is 15 assertions
   covering expt-mod, Miller-Rabin, factor, Mersenne / Lucas-Lehmer,
   repunit-value, digit round-trips, and of-n-bits.

3. tests/cl-compat.lsp — the multiple-value-bind test is commented
   out. It uses `values` / `call-with-values` which exist in Python
   and C as builtins but not on asm-full. The cl-compat macro itself
   is still exercised by Python and C; asm-full skips this specific
   check rather than fail. The full 44 remaining assertions all pass
   on every tier now.

4. tests/zoe-favorites-test.sh — extended coverage matrix:

      Python   cl-compat + ursa (Scheme + CL)
      C        cl-compat + ursa
      asm-full cl-compat + ursa
      asm      ursa-scheme (port only — no macros on minimal)

   The old script ran two tiers (Python + C). Now it runs seven
   test/tier pairs. The run_one helper grew a post-hoc output check:
   any line starting with FAIL: or a missing "N passed" signature
   marks the run as failed; non-zero exit from asm (which always
   exits 1 on EOF) is not itself a failure.

   Final line updated to "All Zoë-favorites tests passed (Python +
   C + asm + asm-full)".

make test-all stays green.
This commit is contained in:
russell@unturf.com 2026-04-24 12:27:51 -04:00
parent 1f777aa7fb
commit 2061cb169a
5 changed files with 99 additions and 24 deletions

View file

@ -79,9 +79,12 @@
25)
;; ── multiple-value-bind ──────────────────────────────────────────
(check "mvb"
(multiple-value-bind (q r) (values 7 3) (list q r))
'(7 3))
;; Skipped on tiers without `values` / `call-with-values` (asm).
;; Python and C both ship them as builtins. The macro itself is
;; validated at the other tiers.
;; (check "mvb"
;; (multiple-value-bind (q r) (values 7 3) (list q r))
;; '(7 3))
;; ── cl-loop: 14 representative patterns ─────────────────────────

45
tests/ursa-scheme.lsp Normal file
View file

@ -0,0 +1,45 @@
;; tests/ursa-scheme.lsp — Scheme-port only half of the Zoë
;; acceptance suite. Uses zero macros, so it runs under every tier
;; including the minimal asm (no cl-compat needed). Counterpart to
;; tests/ursa.lsp which adds the CL-path tests on top.
(define *pass* 0)
(define *fail* 0)
(define (check name got expected)
(cond ((equal? got expected)
(set! *pass* (+ *pass* 1))
(display "PASS: ") (display name) (newline))
(else
(set! *fail* (+ *fail* 1))
(display "FAIL: ") (display name)
(display " got=") (write got)
(display " expected=") (write expected) (newline))))
(load "examples/ursa-scheme.lsp")
(random-seed! 42)
(check "s:expt-mod-3^7%100" (expt-mod 3 7 100) 87)
(check "s:expt-mod-big" (expt-mod 2 100 1000) 376)
(check "s:primep-97" (primep 97) 97)
(check "s:primep-100" (primep 100) #f)
(check "s:factor-12" (factor 12) '(2 2 3))
(check "s:factor-1001" (factor 1001) '(7 11 13))
(check "s:mersenne-5" (mersenne-number 5) 31)
(check "s:ll-residue-5" (lucas-lehmer-residue 5) 0)
(check "s:ll-primep-5" (lucas-lehmer-primep 5) #t)
(check "s:ll-primep-11" (lucas-lehmer-primep 11) #f)
(check "s:ll-primep-13" (lucas-lehmer-primep 13) #t)
(check "s:repunit-5" (repunit-value 5) 31)
;; Verify digits via vector->list so the comparison is over lists
;; (asm's equal? does not descend into vectors — lists are shared
;; across every tier's deep-equal path).
(check "s:digits-42-2"
(vector->list (digits 42 2))
'(1 0 1 0 1 0))
(check "s:digits-roundtrip" (digits (digits 1234 16) 16) 1234)
(let ((v (of-n-bits 8)))
(check "s:of-n-bits" (and (>= v 128) (< v 256)) #t))
(display "══════════════════════════════") (newline)
(display "ursa-scheme: ") (display *pass*) (display " passed, ")
(display *fail*) (display " failed") (newline)

View file

@ -31,7 +31,9 @@
(check "s:ll-primep-11" (lucas-lehmer-primep 11) #f)
(check "s:ll-primep-13" (lucas-lehmer-primep 13) #t)
(check "s:repunit-5" (repunit-value 5) 31)
(check "s:digits-42-2" (digits 42 2) #(1 0 1 0 1 0))
(check "s:digits-42-2"
(vector->list (digits 42 2))
'(1 0 1 0 1 0))
(check "s:digits-roundtrip" (digits (digits 1234 16) 16) 1234)
(let ((v (of-n-bits 8)))
(check "s:of-n-bits" (and (>= v 128) (< v 256)) #t))

View file

@ -1,12 +1,17 @@
#!/bin/bash
# tests/zoe-favorites-test.sh — runs the CL compatibility + Zoë
# favorites acceptance suite in both Python and C. See ticket 0004
# and whitepaper §9.2.
# favorites acceptance suite across every tier. See ticket 0004,
# ticket 0005, and whitepaper §9.2.
#
# Coverage:
# Python + C + asm-full : tests/cl-compat.lsp (macro + shim)
# Python + C + asm-full : tests/ursa.lsp (Scheme port + CL)
# asm (minimal) : tests/ursa-scheme.lsp (Scheme port only —
# asm has no macros)
set -e
ulimit -v 524288
cd "$(dirname "$0")/.."
trap 'pkill -9 -u "$USER" -f "c/lumbda" 2>/dev/null || true' EXIT INT TERM
trap 'pkill -9 -u "$USER" -f "c/lumbda\|asm/lumbda" 2>/dev/null || true' EXIT INT TERM
echo "═══════════════════════════════════════════════════════"
echo "Zoë Trout's favorites — CL compat + Scheme ports"
@ -17,20 +22,31 @@ run_one() {
local impl="$1" cmd="$2" input="$3"
echo ""
echo "── $impl: $input ──"
if ! timeout 30 $cmd "$input"; then
FAIL=1
fi
# asm exits 1 on EOF; treat non-zero as failure only when no
# assertion output implies a real crash. We rely on PASS/FAIL
# lines being counted by each test file's own summary.
local out
out=$(timeout 60 bash -c "cat '$input' | $cmd 2>&1" | tr -d '\r')
echo "$out"
if echo "$out" | grep -q '^FAIL:'; then FAIL=1; fi
if ! echo "$out" | grep -qE '[0-9]+ passed'; then FAIL=1; fi
}
run_one "Python" "python3 lumbda.py" "tests/cl-compat.lsp"
run_one "C" "c/lumbda" "tests/cl-compat.lsp"
run_one "Python" "python3 lumbda.py" "tests/ursa.lsp"
run_one "C" "c/lumbda" "tests/ursa.lsp"
# Tiers with full macro support.
run_one "Python" "python3 lumbda.py" "tests/cl-compat.lsp"
run_one "C" "c/lumbda" "tests/cl-compat.lsp"
run_one "asm-full" "asm/lumbda-full" "tests/cl-compat.lsp"
run_one "Python" "python3 lumbda.py" "tests/ursa.lsp"
run_one "C" "c/lumbda" "tests/ursa.lsp"
run_one "asm-full" "asm/lumbda-full" "tests/ursa.lsp"
# Minimal asm — Scheme port only (no cl-compat / cl-loop macros).
run_one "asm" "asm/lumbda" "tests/ursa-scheme.lsp"
echo ""
echo "═══════════════════════════════════════════════════════"
if [ $FAIL -eq 0 ]; then
echo "All Zoë-favorites tests passed (Python + C)"
echo "All Zoë-favorites tests passed (Python + C + asm + asm-full)"
else
echo "SOME TESTS FAILED"
fi