From e3d2aa8d14f8b5dfd5b5e321e91c791d6a8a5835 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Fri, 5 Jun 2026 00:26:44 -0400 Subject: [PATCH] test(spec): lazy sequences, transducers, metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add spec suites covering lazy-seq/lazy-cat laziness, infinite + self-referential seqs (ones/nats/fib), realized?; transducers (map/filter/take/cat/keep/mapcat as xforms, comp, into/transduce/sequence/eduction/completing); and metadata (with-meta/meta/vary-meta/^ reader). All passed against jolt as written — no implementation changes needed. jpm test green. --- test/spec/lazy-seqs-spec.janet | 30 ++++++++++++++++++++++++++++++ test/spec/metadata-spec.janet | 11 +++++++++++ test/spec/transducers-spec.janet | 29 +++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 test/spec/lazy-seqs-spec.janet create mode 100644 test/spec/metadata-spec.janet create mode 100644 test/spec/transducers-spec.janet diff --git a/test/spec/lazy-seqs-spec.janet b/test/spec/lazy-seqs-spec.janet new file mode 100644 index 0000000..ee67051 --- /dev/null +++ b/test/spec/lazy-seqs-spec.janet @@ -0,0 +1,30 @@ +# Specification: lazy sequences. +(use ../support/harness) + +(defspec "lazy / construction & laziness" + ["lazy-seq value" "[1 2 3]" "(take 3 (lazy-seq (cons 1 (lazy-seq (cons 2 (lazy-seq (cons 3 nil)))))))"] + ["not eagerly evaluated" "0" "(let [c (atom 0)] (lazy-seq (swap! c inc) nil) @c)"] + ["realized on demand" "1" "(let [c (atom 0) s (lazy-seq (swap! c inc) [1])] (first s) @c)"] + ["lazy-cat" "[0 1 2 3]" "(lazy-cat [0 1] [2 3])"] + ["doall forces" "[2 3 4]" "(doall (map inc [1 2 3]))"] + ["dorun returns nil" "nil" "(dorun (map inc [1 2 3]))"]) + +(defspec "lazy / infinite" + ["take from repeat" "[7 7 7]" "(take 3 (repeat 7))"] + ["take from iterate" "[1 2 4 8]" "(take 4 (iterate (fn [x] (* 2 x)) 1))"] + ["take from cycle" "[1 2 1 2]" "(take 4 (cycle [1 2]))"] + ["take from range" "[0 1 2]" "(take 3 (range))"] + ["drop then take" "[5 6 7]" "(take 3 (drop 5 (range)))"] + ["filter infinite" "[0 2 4]" "(take 3 (filter even? (range)))"] + ["map infinite" "[0 1 4]" "(take 3 (map (fn [x] (* x x)) (range)))"] + ["nth of infinite" "100" "(nth (range) 100)"]) + +(defspec "lazy / self-referential" + ["self-ref ones" "[1 1 1 1 1]" "(do (def ones (lazy-seq (cons 1 ones))) (take 5 ones))"] + ["self-ref nats" "[0 1 2 3 4]" "(do (def nats (lazy-cat [0] (map inc nats))) (take 5 nats))"] + ["self-ref fib" "[0 1 1 2 3 5 8 13 21 34]" + "(do (def fib (lazy-cat [0 1] (map + (rest fib) fib))) (take 10 fib))"]) + +(defspec "lazy / realized?" + ["unrealized" "false" "(realized? (lazy-seq (cons 1 nil)))"] + ["realized after" "true" "(let [s (lazy-seq (cons 1 nil))] (first s) (realized? s))"]) diff --git a/test/spec/metadata-spec.janet b/test/spec/metadata-spec.janet new file mode 100644 index 0000000..bdaf1cf --- /dev/null +++ b/test/spec/metadata-spec.janet @@ -0,0 +1,11 @@ +# Specification: metadata. +(use ../support/harness) + +(defspec "metadata / with-meta & meta" + ["meta of bare value" "nil" "(meta [1 2 3])"] + ["with-meta then meta" "{:a 1}" "(meta (with-meta [1 2 3] {:a 1}))"] + ["with-meta preserves value" "true" "(= [1 2 3] (with-meta [1 2 3] {:a 1}))"] + ["with-meta on map" "{:doc \"x\"}" "(meta (with-meta {:k 1} {:doc \"x\"}))"] + ["vary-meta" "{:a 2}" "(meta (vary-meta (with-meta [1] {:a 1}) update :a inc))"] + ["meta reader ^" "{:tag :int}" "(meta ^{:tag :int} [1 2])"] + ["with-meta on fn ok" "true" "(fn? (with-meta inc {:a 1}))"]) diff --git a/test/spec/transducers-spec.janet b/test/spec/transducers-spec.janet new file mode 100644 index 0000000..b470a63 --- /dev/null +++ b/test/spec/transducers-spec.janet @@ -0,0 +1,29 @@ +# Specification: transducers. +(use ../support/harness) + +(defspec "transducers / into" + ["map xform" "[2 3 4]" "(into [] (map inc) [1 2 3])"] + ["filter xform" "[2 4]" "(into [] (filter even?) [1 2 3 4])"] + ["remove xform" "[1 3]" "(into [] (remove even?) [1 2 3 4])"] + ["take xform" "[1 2]" "(into [] (take 2) [1 2 3 4])"] + ["drop xform" "[3 4]" "(into [] (drop 2) [1 2 3 4])"] + ["take-while xform" "[1 2]" "(into [] (take-while (fn [x] (< x 3))) [1 2 3 1])"] + ["keep xform" "[1 3]" "(into [] (keep (fn [x] (if (odd? x) x nil))) [1 2 3 4])"] + ["map-indexed xform" "[[0 :a] [1 :b]]" "(into [] (map-indexed vector) [:a :b])"] + ["mapcat xform" "[1 1 2 2]" "(into [] (mapcat (fn [x] [x x])) [1 2])"] + ["cat xform" "[1 2 3 4]" "(into [] cat [[1 2] [3 4]])"] + ["into a set" "#{2 3 4}" "(into #{} (map inc) [1 2 3])"]) + +# transducer comp applies left-to-right: (comp (map a) (filter b)) maps then filters +(defspec "transducers / compose" + ["comp map+filter" "[2 4 6 8]" "(into [] (comp (map (fn [x] (* x 2))) (filter even?)) [1 2 3 4])"] + ["comp filter+map" "[2 4]" "(into [] (comp (filter odd?) (map inc)) [1 2 3 4])"] + ["comp three" "[2]" "(into [] (comp (map inc) (filter even?) (take 1)) [1 2 3 4])"]) + +(defspec "transducers / transduce & sequence" + ["transduce sum" "9" "(transduce (map inc) + [1 2 3])"] + ["transduce init" "19" "(transduce (map inc) + 10 [1 2 3])"] + ["transduce filter" "6" "(transduce (filter even?) + [1 2 3 4])"] + ["sequence xform" "[2 3 4]" "(sequence (map inc) [1 2 3])"] + ["eduction" "[2 3 4]" "(into [] (eduction (map inc) [1 2 3]))"] + ["completing" "9" "(transduce (map inc) (completing +) 0 [1 2 3])"])