test: restructure into unit / integration / spec layers + shared harness

Reorganize the flat 49-file test/ into three layers (jpm test recurses, so all
are still discovered):
- test/unit/        white-box component tests (reader, evaluator, types,
                    persistent-map, lazy-seq, macro, interop, compiler)
- test/integration/ cross-cutting + regression batteries (conformance, jank,
                    sci-bootstrap/runtime, features, systematic-coverage, api,
                    core, namespaces, ported clojure suites) and
   .../ports/       ported clojure/cljs test batches pending consolidation
- test/spec/        the behavioral contract (built out in following commits)
- test/support/harness.janet  shared defspec table runner (cases compared via
                    Jolt's own =, with a :throws sentinel) + expect= helpers

Files moved with git mv (history preserved) and import paths fixed for depth.
jpm test green. README Test section updated.

Next: build out test/spec/ to cover the public API area-by-area, mining the
integration batteries and filling gaps.
This commit is contained in:
Yogthos 2026-06-05 00:00:16 -04:00
parent 1898308926
commit 16428179fa
52 changed files with 185 additions and 86 deletions

View file

@ -1,5 +1,5 @@
(use ../src/jolt/api)
(use ../src/jolt/types)
(use ../../src/jolt/api)
(use ../../src/jolt/types)
(print "1: init creates context...")
(let [ctx (init)]

View file

@ -1,7 +1,7 @@
(use ../src/jolt/evaluator)
(use ../src/jolt/types)
(use ../src/jolt/reader)
(use ../src/jolt/api)
(use ../../src/jolt/evaluator)
(use ../../src/jolt/types)
(use ../../src/jolt/reader)
(use ../../src/jolt/api)
(def ctx (init))
(def source (slurp "/Users/yogthos/src/sci/src/sci/impl/macros.cljc"))

View file

@ -1,5 +1,5 @@
# Ported from clojure/test_clojure/atoms.clj + systematic atom tests
(use ../src/jolt/api)
(use ../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "Ported Atom Tests")

View file

@ -1,5 +1,5 @@
# Ported from clojure/test_clojure/control.clj
(use ../src/jolt/api)
(use ../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "Ported Control Tests")

View file

@ -1,5 +1,5 @@
# Ported from clojure/test_clojure/for.clj
(use ../src/jolt/api)
(use ../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "Ported For Tests")

View file

@ -1,5 +1,5 @@
# Ported from clojure/test_clojure/logic.clj
(use ../src/jolt/api)
(use ../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "Ported Logic Tests (from clojure/test-clojure/logic.clj)")

View file

@ -1,5 +1,5 @@
# Ported from clojure/test_clojure/macros.clj
(use ../src/jolt/api)
(use ../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "Ported Macros Tests")

View file

@ -12,7 +12,7 @@
# These pairs are hand-extracted from those files (and canonical idioms)
# until a minimal clojure.test lets us load the real files directly.
(use ../src/jolt/api)
(use ../../src/jolt/api)
(def cases
[

View file

@ -1,9 +1,9 @@
(use ../src/jolt/types)
(use ../src/jolt/pv)
(use ../src/jolt/plist)
(use ../src/jolt/reader)
(use ../src/jolt/evaluator)
(use ../src/jolt/core)
(use ../../src/jolt/types)
(use ../../src/jolt/pv)
(use ../../src/jolt/plist)
(use ../../src/jolt/reader)
(use ../../src/jolt/evaluator)
(use ../../src/jolt/core)
# Normalize jolt collection results to Janet tuples so Janet-level deep=/= can
# compare against tuple literals regardless of the (pvec/plist) representation.

View file

@ -1,7 +1,7 @@
# Regression tests mirroring clojure-features.clj, plus expanded coverage of
# related features. Each case asserts (= expected actual) evaluated inside Jolt
# (so comparisons use Jolt's own Clojure-semantics =). Run via `jpm test`.
(use ../src/jolt/api)
(use ../../src/jolt/api)
(var pass 0)
(def fails @[])

View file

@ -6,7 +6,7 @@
#
# Each jank pass-test is an assertion script ending in `:success`. We load it in
# a fresh context and count it as passing when it returns :success.
(use ../src/jolt/api)
(use ../../src/jolt/api)
(def jank-dir (string (os/getenv "HOME") "/src/jank/compiler+runtime/test/jank"))

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "Ported Logic Tests (from clojure/test-clojure/logic.clj)")

View file

@ -1,6 +1,6 @@
(use ../src/jolt/reader)
(use ../src/jolt/types)
(use ../src/jolt/evaluator)
(use ../../src/jolt/reader)
(use ../../src/jolt/types)
(use ../../src/jolt/evaluator)
# Helper: parse and eval in a fresh ctx
(defn eval-str [s]

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "CLJS Collections Ported Tests")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "CLJS Core Ported Tests")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 1 ===")
(print "1: core math...")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 10 ===")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 1 ===")
(print "1: core math...")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 1b ===")
(print "7: seq operations...")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 2 ===")
(print "12: atoms...")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 3 ===")
(print "16: destructuring...")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 3b ===")
(print "21: clojure.string...")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 4 ===")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 5 ===")
(print "22: destructuring...")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 6 ===")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 7 ===")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 8 ===")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "=== CLJS Ported Part 9 ===")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "CLJS Ported Tests")

View file

@ -1,6 +1,6 @@
(use ../src/jolt/api)
(use ../src/jolt/reader)
(use ../src/jolt/evaluator)
(use ../../../src/jolt/api)
(use ../../../src/jolt/reader)
(use ../../../src/jolt/evaluator)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))

View file

@ -1,5 +1,5 @@
# Phase 12: Protocol System Tests
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "35: defprotocol...")

View file

@ -1,6 +1,6 @@
(use ../src/jolt/api)
(use ../src/jolt/evaluator)
(use ../src/jolt/reader)
(use ../../../src/jolt/api)
(use ../../../src/jolt/evaluator)
(use ../../../src/jolt/reader)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(defn load-clj [ctx filepath]

View file

@ -1,5 +1,5 @@
# Phase 5: Multimethods + Hierarchy Tests
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
# 22. Hierarchy

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))

View file

@ -1,5 +1,5 @@
# Phase 6: Reader Extensions Tests
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "28: #inst tagged literal...")

View file

@ -1,5 +1,5 @@
# Phase 7: LazySeq + PersistentHashSet completion
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "32: lazy-seq...")

View file

@ -1,5 +1,5 @@
# Phase 8: Protocol System Tests
(use ../src/jolt/api)
(use ../../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "35: defprotocol...")

View file

@ -1,7 +1,7 @@
(use ../src/jolt/evaluator)
(use ../src/jolt/types)
(use ../src/jolt/reader)
(use ../src/jolt/api)
(use ../../src/jolt/evaluator)
(use ../../src/jolt/types)
(use ../../src/jolt/reader)
(use ../../src/jolt/api)
(def ctx (init))

View file

@ -1,7 +1,7 @@
(use ../src/jolt/evaluator)
(use ../src/jolt/types)
(use ../src/jolt/reader)
(use ../src/jolt/api)
(use ../../src/jolt/evaluator)
(use ../../src/jolt/types)
(use ../../src/jolt/reader)
(use ../../src/jolt/api)
(defn- load-stubs [ctx filepath]
(var s (slurp filepath))

View file

@ -1,5 +1,5 @@
# Systematic coverage tests for Clojure language features
(use ../src/jolt/api)
(use ../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "Systematic Coverage Tests")

View file

@ -0,0 +1,82 @@
# Shared test harness for Jolt.
#
# Two complementary styles:
#
# defspec — data-driven behavioral tables, for spec/ and integration batteries.
# Each case is ["label" expected actual] where `expected` and `actual` are
# Clojure source strings. Equality is checked with Jolt's own `=`, so it is
# representation-agnostic (a vector result compares equal to a vector
# literal regardless of the underlying Janet type). Use the :throws sentinel
# in the `expected` position to assert that `actual` raises an error.
#
# (defspec "clojure.core / seq"
# ["first of vector" "1" "(first [1 2 3])"]
# ["rest is a seq" "(2 3)" "(rest [1 2 3])"]
# ["nth out of range" :throws "(nth [1] 5)"])
#
# jeval / expect= / expect-throws — assertion helpers for white-box unit/ tests
# that probe a single component and want Janet-level assertions.
#
# A failing suite prints every failing behavior, then raises — so `jpm test`
# reports a non-zero exit and the offending behaviors are visible.
(use ../../src/jolt/api)
(defn jeval
"Evaluate a Clojure source string in a fresh context, normalizing persistent
vectors/lists to Janet tuples so results compare with `deep=`/tuple literals."
[s]
(normalize-pvecs (eval-string (init) s)))
(defn- show [s]
(let [r (protect (eval-string (init) s))]
(if (= (r 0) true)
(string/format "%q" (normalize-pvecs (r 1)))
(string "<error: " (r 1) ">"))))
(defn run-spec
"Run a data-driven behavioral suite. See `defspec`."
[suite cases]
(var pass 0)
(def fails @[])
(each case cases
(def label (in case 0))
(def expected (in case 1))
(def actual (in case 2))
(if (= expected :throws)
(let [r (protect (eval-string (init) actual))]
(if (= (r 0) false)
(++ pass)
(array/push fails [label "expected an error, got a value"])))
(let [r (protect (eval-string (init) (string "(= " expected " " actual ")")))]
(cond
(not= (r 0) true) (array/push fails [label (string "errored: " (r 1))])
(= (r 1) true) (++ pass)
(array/push fails [label (string "want " expected ", got " (show actual))])))))
(printf " %s: %d/%d" suite pass (length cases))
(each [l m] fails (printf " FAIL [%s] %s" l m))
(when (> (length fails) 0)
(error (string suite ": " (length fails) " failing behavior(s)")))
pass)
(defmacro defspec
"Define and immediately run a behavioral suite of [label expected actual] cases."
[suite & cases]
~(,run-spec ,suite [,;cases]))
# --- white-box assertion helpers (unit tests) ---
(defn expect=
"Assert that evaluating Clojure `s` yields `expected` (a Janet value, compared
with deep= after normalizing persistent collections to tuples)."
[expected s]
(let [got (jeval s)]
(assert (deep= expected got)
(string "expected " (string/format "%q" expected)
", got " (string/format "%q" got) " for: " s))))
(defn expect-throws
"Assert that evaluating Clojure `s` raises an error."
[s]
(let [r (protect (eval-string (init) s))]
(assert (= (r 0) false) (string "expected an error for: " s))))

View file

@ -3,8 +3,8 @@
# Core ops: const, do, if, def, fn, let, invoke
# Phase 2 adds: symbol classification with binding awareness
(use ../src/jolt/compiler)
(use ../src/jolt/reader)
(use ../../src/jolt/compiler)
(use ../../src/jolt/reader)
(defn compile-str [s]
(let [form (parse-string s)]
@ -98,7 +98,7 @@
# 9. Compile-and-eval round-trip (Phase 3)
# ============================================================
(print "9: compile-and-eval...")
(use ../src/jolt/core) # need core fns in scope for eval
(use ../../src/jolt/core) # need core fns in scope for eval
(defn compile-eval-str [s]
(let [form (parse-string s)]
@ -121,7 +121,7 @@
# 10. Compile flag in context (Phase 3)
# ============================================================
(print "10: compile flag...")
(use ../src/jolt/api)
(use ../../src/jolt/api)
# Without compile flag
(let [ctx (init)]
@ -146,7 +146,7 @@
# 11. Macro expansion (Phase 4)
# ============================================================
(print "11: macro expansion...")
(use ../src/jolt/api)
(use ../../src/jolt/api)
(let [ctx (init {:compile? true})]
# defn expands via compiler, produces Janet def
@ -175,7 +175,7 @@
# 12. throw, try, loop*/recur (Phase 5)
# ============================================================
(print "12: throw/try/loop...")
(use ../src/jolt/api)
(use ../../src/jolt/api)
(let [ctx (init {:compile? true})]
# throw/catch via compiler
@ -206,7 +206,7 @@
# 13. defn/def integration (Phase 0 fix)
# ============================================================
(print "13: defn/def integration...")
(use ../src/jolt/api)
(use ../../src/jolt/api)
(let [ctx (init {:compile? true})]
# defn produces a resolvable var
@ -228,7 +228,7 @@
# 14. Phase 1: ns accessors + ns form extensions
# ============================================================
(print "14: ns accessors...")
(use ../src/jolt/api)
(use ../../src/jolt/api)
(let [ctx (init)]
(eval-string ctx "(ns mytest.core)")
@ -255,7 +255,7 @@
# 17. Phase 3: Var system completion
# ============================================================
(print "17: var system...")
(use ../src/jolt/api)
(use ../../src/jolt/api)
(let [ctx (init)]
(eval-string ctx "(def x-var-test 42)")
@ -292,7 +292,7 @@
# 19. Phase 4: deftype
# ============================================================
(print "19: deftype...")
(use ../src/jolt/api)
(use ../../src/jolt/api)
(let [ctx (init)]
(eval-string ctx "(deftype Point [x y])")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "Eval Tests")

View file

@ -1,7 +1,7 @@
(use ../src/jolt/evaluator)
(use ../src/jolt/types)
(use ../src/jolt/reader)
(use ../src/jolt/api)
(use ../../src/jolt/evaluator)
(use ../../src/jolt/types)
(use ../../src/jolt/reader)
(use ../../src/jolt/api)
# Helper: create a Jolt symbol
(defn sym [name]

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "Janet Interop Tests")

View file

@ -1,4 +1,4 @@
(use ../src/jolt/api)
(use ../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))
(print "LazySeq Tests")

View file

@ -1,6 +1,6 @@
(use ../src/jolt/reader)
(use ../src/jolt/types)
(use ../src/jolt/evaluator)
(use ../../src/jolt/reader)
(use ../../src/jolt/types)
(use ../../src/jolt/evaluator)
# Helper: create a Jolt symbol
(defn sym [name]

View file

@ -1,7 +1,7 @@
# Phase 2: PersistentHashMap Tests
# Uses Clojure = (core-=) for PHM-aware comparison
(use ../src/jolt/api)
(use ../../src/jolt/api)
(defn ct-eval [ctx s] (normalize-pvecs (eval-string ctx s)))

View file

@ -1,4 +1,4 @@
(use ../src/jolt/reader)
(use ../../src/jolt/reader)
# Helper: create a symbol
(defn sym [name]

View file

@ -1,4 +1,4 @@
(use ../src/jolt/types)
(use ../../src/jolt/types)
# ============================================================
# Var tests