jolt/test/spec/state-spec.janet
Yogthos cf1fdfdb24 feat: run the real clojure.tools.logging (defmacro/syntax-quote/ns + host shims)
Pivot from a jolt reimplementation to running the upstream library verbatim.
Vendors the real clojure/tools/logging.clj; jolt provides the backend and the
host primitives it needs. Language features (broadly useful for real Clojure
libs), all covered in 3-mode conformance + spec suites:

- defmacro: multi-arity dispatch (jolt-q8l) and a docstring + attr-map + params
  head (jolt-qnr) — the 4-arity log macro and every level macro need these.
- syntax-quote resolves an alias-qualified symbol to its target ns (jolt-9av),
  so a macro template (impl/get-logger) resolves at the use site.
- the ns macro unwraps ^{:map} metadata on the ns name (jolt-8w2 workaround,
  matching def/defn/defmacro).
- a namespace object self-evaluates, so ~*ns* can be spliced into a template.

Host shims (ported from / modeled on clojure where applicable):
- clojure.string/trim-newline (ported, CharSequence interop -> count/subs)
- agent/send-off/send (minimal synchronous stubs; jolt has no thread pool/STM)
- clojure.lang.LockingTransaction/isRunning -> false
- a minimal clojure.pprint (pprint/with-pprint-dispatch/code-dispatch, for spy)
- clojure.tools.logging.impl: a jolt stderr LoggerFactory backend (the library's
  designed pluggable extension point)

docs/libraries.md lists tools.logging; grammar.ebnf metadata note clarified.
Conformance 355/355 x3 modes; full jpm test gate green.
2026-06-13 18:50:53 -04:00

48 lines
3 KiB
Text

# Specification: stateful reference types (atoms, volatiles, delays, promises).
(use ../support/harness)
(defspec "state / atoms"
["deref @" "0" "(let [a (atom 0)] @a)"]
["deref fn" "0" "(deref (atom 0))"]
["reset!" "5" "(let [a (atom 0)] (reset! a 5) @a)"]
["reset! returns new" "5" "(let [a (atom 0)] (reset! a 5))"]
["swap!" "1" "(let [a (atom 0)] (swap! a inc) @a)"]
["swap! with args" "10" "(let [a (atom 1)] (swap! a + 2 3 4) @a)"]
["swap! returns new" "1" "(let [a (atom 0)] (swap! a inc))"]
["swap-vals!" "[0 1]" "(let [a (atom 0)] (swap-vals! a inc))"]
["reset-vals!" "[0 9]" "(let [a (atom 0)] (reset-vals! a 9))"]
["compare-and-set! ok" "true" "(let [a (atom 0)] (compare-and-set! a 0 1))"]
["compare-and-set! no" "false" "(let [a (atom 0)] (compare-and-set! a 9 1))"]
["atom?" "true" "(do (require (quote [clojure.core])) (instance? clojure.lang.Atom (atom 0)))"]
["atom? predicate" "true" "(atom? (atom 0))"]
["atom? on non-atom" "false" "(atom? 5)"])
(defspec "state / watches & validators"
["add-watch fires" "1" "(let [a (atom 0) seen (atom 0)] (add-watch a :k (fn [k r o n] (reset! seen 1))) (reset! a 5) @seen)"]
["remove-watch" "0" "(let [a (atom 0) seen (atom 0)] (add-watch a :k (fn [k r o n] (swap! seen inc))) (remove-watch a :k) (reset! a 5) @seen)"]
["set-validator! ok" "5" "(let [a (atom 0)] (set-validator! a number?) (reset! a 5) @a)"]
["set-validator! rejects" :throws "(let [a (atom 0)] (set-validator! a pos?) (reset! a -1))"]
["get-validator" "true" "(let [a (atom 0)] (set-validator! a number?) (fn? (get-validator a)))"])
(defspec "state / volatiles & delays"
["volatile! deref" "0" "(let [v (volatile! 0)] @v)"]
["vreset!" "5" "(let [v (volatile! 0)] (vreset! v 5) @v)"]
["vswap!" "1" "(let [v (volatile! 0)] (vswap! v inc) @v)"]
["delay not forced" "0" "(let [c (atom 0) d (delay (swap! c inc))] @c)"]
["delay force once" "1" "(let [c (atom 0) d (delay (swap! c inc))] (force d) (force d) @c)"]
["delay value" "5" "(let [d (delay 5)] @d)"]
["realized? before" "false" "(let [d (delay 5)] (realized? d))"]
["realized? after" "true" "(let [d (delay 5)] (force d) (realized? d))"])
(defspec "state / promises"
["promise deliver" "5" "(let [p (promise)] (deliver p 5) @p)"]
["promise undelivered" "nil" "(let [p (promise)] @p)"])
# Minimal synchronous agent shim (jolt has no thread pool/STM) — enough for
# libraries that hold an agent without depending on async dispatch.
(defspec "state / agents (synchronous shim)"
["agent deref" "0" "(deref (agent 0))"]
["agent with opts" "0" "(deref (agent 0 :error-mode :continue))"]
["send-off applies" "5" "(let [a (agent 0)] (send-off a + 5) (deref a))"]
["send applies" "7" "(let [a (agent 1)] (send a + 6) (deref a))"]
["agent-error nil" "nil" "(agent-error (agent 0))"])