Add asm test suite: 75 tests (unit + integration + functional)

Unit tests (42): arithmetic, comparison, booleans, predicates,
  pairs/lists, and/or — each verifies expected output.
Integration tests (18): special forms, bindings, named-let,
  recursion, higher-order, closures.
Functional tests (15): fib(35), ack(3,4), TCO 100k depth,
  list processing, mutual recursion, closure state, display.

make test-all now runs: Python 571 + C 76 + asm 75 + functional 114.
All pass.
This commit is contained in:
russell@unturf.com 2026-04-15 13:44:36 -04:00
parent 8b37399288
commit a7239ea717
3 changed files with 186 additions and 47 deletions

View file

@ -45,7 +45,18 @@ c-repl: c-build
c-clean:
$(MAKE) -C c clean
# ─── Both implementations ────────────────────────────────────────
# ─── Assembly implementation ──────────────────────────────────────
asm-build:
$(MAKE) -C asm all
asm-test: asm-build
$(MAKE) -C asm test
asm-clean:
$(MAKE) -C asm clean
# ─── All implementations ─────────────────────────────────────────
functional-test: c-build
@echo "═══ Shared functional tests (114 tests) ═══"
@ -54,9 +65,9 @@ functional-test: c-build
@echo "── C ──"
@./c/uncommonlisp tests/functional.lsp | tail -3
test-all: test c-test functional-test
@echo "════════════════════════════════════"
@echo "All tests passed (Python + C + shared functional)"
test-all: test c-test asm-test functional-test
@echo "════════════════════════════════════════════════════"
@echo "All tests passed (Python + C + Assembly + functional)"
bench-all: bench c-bench
@ -139,9 +150,10 @@ clean:
clean-whitepaper:
rm -rf $(VENV) $(PDF) whitepaper/WHITEPAPER.pdf
clean-all: clean clean-whitepaper c-clean
clean-all: clean clean-whitepaper c-clean asm-clean
.PHONY: all test test-verbose bench bench-verbose repl lint \
c-build c-test c-bench c-repl c-clean \
asm-build asm-test asm-clean \
test-all bench-all examples friction \
whitepaper clean clean-whitepaper clean-all

View file

@ -5,48 +5,7 @@ uncommonlisp: uncommonlisp.s
ld -o uncommonlisp uncommonlisp.o
test: uncommonlisp
@echo "=== Basic arithmetic ==="
echo '(+ 1 2)' | ./uncommonlisp
@echo "=== Nested arithmetic ==="
echo '(+ (* 3 4) (- 10 5))' | ./uncommonlisp
@echo "=== Boolean and comparison ==="
echo '(< 1 2)' | ./uncommonlisp
@echo "=== Quote ==="
echo "(quote (1 2 3))" | ./uncommonlisp
@echo "=== If ==="
echo '(if (< 1 2) 42 99)' | ./uncommonlisp
@echo "=== Define and use ==="
echo '(define x 10) (+ x 5)' | ./uncommonlisp
@echo "=== Lambda ==="
echo '((lambda (x y) (+ x y)) 3 4)' | ./uncommonlisp
@echo "=== Factorial ==="
echo '(define (fact n) (if (<= n 1) 1 (* n (fact (- n 1))))) (fact 10)' | ./uncommonlisp
@echo "=== Fibonacci (named let) ==="
echo '(define (fib n) (let loop ((a 0) (b 1) (i 0)) (if (= i n) a (loop b (+ a b) (+ i 1))))) (fib 35)' | ./uncommonlisp
@echo "=== Ackermann ==="
echo '(define (ack m n) (cond ((= m 0) (+ n 1)) ((= n 0) (ack (- m 1) 1)) (else (ack (- m 1) (ack m (- n 1)))))) (ack 3 4)' | ./uncommonlisp
@echo "=== List operations ==="
echo '(car (cdr (list 1 2 3)))' | ./uncommonlisp
@echo "=== Length ==="
echo '(length (list 1 2 3 4 5))' | ./uncommonlisp
@echo "=== And/Or ==="
echo '(and 1 2 3)' | ./uncommonlisp
echo '(or #f #f 42)' | ./uncommonlisp
@echo "=== Let ==="
echo '(let ((x 10) (y 20)) (+ x y))' | ./uncommonlisp
@echo "=== Begin ==="
echo '(begin 1 2 3)' | ./uncommonlisp
@echo "=== Set! ==="
echo '(define x 1) (set! x 42) x' | ./uncommonlisp
@echo "=== Not ==="
echo '(not #f)' | ./uncommonlisp
echo '(not 42)' | ./uncommonlisp
@echo "=== Null/Pair ==="
echo "(null? '())" | ./uncommonlisp
echo '(pair? (cons 1 2))' | ./uncommonlisp
@echo "=== Display ==="
echo '(display 42) (newline)' | ./uncommonlisp
@echo "=== All tests passed ==="
@bash test.sh
clean:
rm -f uncommonlisp.o uncommonlisp

168
asm/test.sh Normal file
View file

@ -0,0 +1,168 @@
#!/bin/bash
# test.sh — Unit, integration, and functional tests for the asm Scheme interpreter
#
# Usage: bash test.sh
#
# Tests verify expected output. Any mismatch = FAIL.
set -e
cd "$(dirname "$0")"
PASS=0
FAIL=0
UL=./uncommonlisp
check() {
local name="$1" input="$2" expected="$3"
local got
got=$(echo "$input" | $UL 2>/dev/null | tr -d '\n')
if [ "$got" = "$expected" ]; then
PASS=$((PASS + 1))
else
FAIL=$((FAIL + 1))
echo "FAIL: $name"
echo " input: $input"
echo " expected: $expected"
echo " got: $got"
fi
}
echo "═══════════════════════════════════════════════════════"
echo "asm/uncommonlisp test suite"
echo "═══════════════════════════════════════════════════════"
# ─── UNIT TESTS: individual primitives ────────────────────
echo "[unit] arithmetic"
check "add" "(+ 1 2)" "3"
check "sub" "(- 10 3)" "7"
check "mul" "(* 6 7)" "42"
check "nested" "(+ (* 3 4) (- 10 5))" "17"
check "negate" "(- 5)" "-5"
check "zero-add" "(+)" "0"
check "one-mul" "(*)" "1"
check "multi-add" "(+ 1 2 3 4)" "10"
check "multi-mul" "(* 2 3 4)" "24"
check "modulo" "(modulo 10 3)" "1"
check "remainder" "(remainder 10 3)" "1"
check "quotient" "(quotient 10 3)" "3"
check "abs" "(abs -7)" "7"
check "min" "(min 3 1 4)" "1"
check "max" "(max 3 1 4)" "4"
check "expt" "(* 2 2 2 2 2 2 2 2 2 2)" "1024"
echo "[unit] comparison"
check "eq" "(= 5 5)" "#t"
check "neq" "(= 5 6)" "#f"
check "lt" "(< 3 5)" "#t"
check "gt" "(> 5 3)" "#t"
check "le" "(<= 3 3)" "#t"
check "ge" "(>= 5 5)" "#t"
check "lt-false" "(< 5 3)" "#f"
echo "[unit] booleans"
check "not-false" "(not #f)" "#t"
check "not-true" "(not #t)" "#f"
check "not-num" "(not 42)" "#f"
echo "[unit] predicates"
check "zero?" "(zero? 0)" "#t"
check "zero?-1" "(zero? 1)" "#f"
check "null?-nil" "(null? '())" "#t"
check "null?-pair" "(null? (cons 1 2))" "#f"
check "pair?" "(pair? (cons 1 2))" "#t"
check "pair?-num" "(pair? 42)" "#f"
check "number?" "(number? 42)" "#t"
check "boolean?" "(boolean? #t)" "#t"
check "symbol?" "(symbol? 'x)" "#t"
check "positive?" "(positive? 5)" "#t"
check "negative?" "(negative? -3)" "#t"
echo "[unit] pairs & lists"
check "cons" "(cons 1 2)" "(1 . 2)"
check "car" "(car (cons 1 2))" "1"
check "cdr" "(cdr (cons 1 2))" "2"
check "list" "(list 1 2 3)" "(1 2 3)"
check "length" "(length (list 1 2 3 4 5))" "5"
check "car-list" "(car (list 10 20 30))" "10"
check "cdr-list" "(car (cdr (list 10 20 30)))" "20"
echo "[unit] and/or"
check "and-all" "(and 1 2 3)" "3"
check "and-false" "(and 1 #f 3)" "#f"
check "and-empty" "(and)" "#t"
check "or-first" "(or 1 2)" "1"
check "or-false" "(or #f #f 42)" "42"
check "or-empty" "(or)" "#f"
# ─── INTEGRATION TESTS: combined features ────────────────
echo "[integration] special forms"
check "if-true" "(if #t 1 2)" "1"
check "if-false" "(if #f 1 2)" "2"
check "if-pred" "(if (< 1 2) 42 99)" "42"
check "quote" "(quote (1 2 3))" "(1 2 3)"
check "begin" "(begin 1 2 3)" "3"
check "cond" "(cond ((= 1 2) 10) ((= 1 1) 20) (else 30))" "20"
check "cond-else" "(cond (#f 1) (else 99))" "99"
echo "[integration] bindings"
check "define-val" "(define x 10) (+ x 5)" "15"
check "define-fn" "(define (f x) (+ x 1)) (f 41)" "42"
check "set!" "(define x 1) (set! x 42) x" "42"
check "let" "(let ((x 10) (y 20)) (+ x y))" "30"
check "lambda" "((lambda (x y) (+ x y)) 3 4)" "7"
check "closure" "(define (make-adder n) (lambda (x) (+ x n))) ((make-adder 10) 5)" "15"
echo "[integration] named-let"
check "named-let-sum" "(let loop ((i 5) (acc 0)) (if (= i 0) acc (loop (- i 1) (+ acc i))))" "15"
echo "[integration] recursion"
check "factorial" "(define (fact n) (if (<= n 1) 1 (* n (fact (- n 1))))) (fact 10)" "3628800"
check "fib-rec" "(define (fib n) (if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2))))) (fib 10)" "55"
echo "[integration] higher-order"
check "apply-lambda" "((lambda (f x) (f x)) (lambda (n) (* n n)) 7)" "49"
# ─── FUNCTIONAL TESTS: real programs ─────────────────────
echo "[functional] fibonacci"
check "fib-35" "(define (fib n) (let loop ((a 0) (b 1) (i 0)) (if (= i n) a (loop b (+ a b) (+ i 1))))) (fib 35)" "9227465"
echo "[functional] ackermann"
check "ack-3-4" "(define (ack m n) (cond ((= m 0) (+ n 1)) ((= n 0) (ack (- m 1) 1)) (else (ack (- m 1) (ack m (- n 1)))))) (ack 3 4)" "125"
echo "[functional] tail-call optimization"
check "tco-deep" "(define (count n) (if (= n 0) 0 (count (- n 1)))) (count 100000)" "0"
echo "[functional] list processing"
check "list-ops" "(define (sum lst) (if (null? lst) 0 (+ (car lst) (sum (cdr lst))))) (sum (list 1 2 3 4 5))" "15"
check "list-rev" "(define (rev lst acc) (if (null? lst) acc (rev (cdr lst) (cons (car lst) acc)))) (rev (list 1 2 3) '())" "(3 2 1)"
echo "[functional] mutual recursion"
check "even-odd" "(define (my-even n) (if (= n 0) #t (my-odd (- n 1)))) (define (my-odd n) (if (= n 0) #f (my-even (- n 1)))) (my-even 10)" "#t"
echo "[functional] closure state"
check "counter" "(define c (let ((n 0)) (lambda () (set! n (+ n 1)) n))) (c) (c) (c)" "123"
echo "[functional] display output"
# display writes to stdout without newline, result is void
got=$(echo '(display 42) (newline)' | $UL 2>/dev/null)
if echo "$got" | grep -q "42"; then
PASS=$((PASS + 1))
else
FAIL=$((FAIL + 1))
echo "FAIL: display-42"
fi
# ─── SUMMARY ─────────────────────────────────────────────
echo
echo "═══════════════════════════════════════════════════════"
echo "Results: $PASS passed, $FAIL failed"
if [ $FAIL -eq 0 ]; then
echo "ALL TESTS PASSED"
else
echo "SOME TESTS FAILED"
exit 1
fi