(defsuite "stdlib-equality" (deftest "eq? delegates to =" (assert-true (eq? 1 1)) (assert-false (eq? 1 2)) (assert-true (eq? "a" "a"))) (deftest "eqv? delegates to =" (assert-true (eqv? 42 42)) (assert-false (eqv? 42 43))) (deftest "equal? delegates to =" (assert-true (equal? "hello" "hello")) (assert-false (equal? "hello" "world"))) (deftest "equality on nil" (assert-true (eq? nil nil)) (assert-true (eqv? nil nil)) (assert-true (equal? nil nil))) (deftest "equality across types" (assert-false (eq? 1 "1")) (assert-false (eq? true 1)))) (defsuite "stdlib-type-predicates" (deftest "boolean?" (assert-true (boolean? true)) (assert-true (boolean? false)) (assert-false (boolean? 1)) (assert-false (boolean? "true"))) (deftest "number?" (assert-true (number? 42)) (assert-true (number? 3.14)) (assert-true (number? 0)) (assert-false (number? "42"))) (deftest "string?" (assert-true (string? "hello")) (assert-true (string? "")) (assert-false (string? 42))) (deftest "list?" (assert-true (list? (list 1 2 3))) (assert-true (list? (list))) (assert-false (list? "not a list"))) (deftest "dict?" (assert-true (dict? {:a 1})) (assert-false (dict? (list 1 2)))) (deftest "continuation? on non-continuation" (assert-false (continuation? 42)) (assert-false (continuation? "hello")))) (defsuite "stdlib-numeric-predicates" (deftest "zero?" (assert-true (zero? 0)) (assert-false (zero? 1)) (assert-false (zero? -1))) (deftest "odd?" (assert-true (odd? 1)) (assert-true (odd? 3)) (assert-true (odd? -1)) (assert-false (odd? 0)) (assert-false (odd? 2))) (deftest "even?" (assert-true (even? 0)) (assert-true (even? 2)) (assert-true (even? -2)) (assert-false (even? 1)) (assert-false (even? 3))) (deftest "empty? on list" (assert-true (empty? (list))) (assert-false (empty? (list 1)))) (deftest "empty? on string" (assert-true (empty? "")) (assert-false (empty? "a"))) (deftest "empty? on nil" (assert-true (empty? nil))) (deftest "empty? on dict" (assert-true (empty? {})) (assert-false (empty? {:a 1})))) (defsuite "stdlib-numeric-ops" (deftest "abs positive" (assert-equal 5 (abs 5))) (deftest "abs negative" (assert-equal 5 (abs -5))) (deftest "abs zero" (assert-equal 0 (abs 0))) (deftest "ceil integer" (assert-equal 3 (ceil 3))) (deftest "ceil fractional" (assert-equal 4 (ceil 3.1)) (assert-equal 4 (ceil 3.9))) (deftest "ceil negative" (assert-equal -3 (ceil -3.9))) (deftest "round integer" (assert-equal 3 (round 3))) (deftest "round fractional" (assert-equal 4 (round 3.5)) (assert-equal 3 (round 3.4))) (deftest "round with ndigits" (assert-equal 3.1 (round 3.14 1)) (assert-equal 3.14 (round 3.145 2))) (deftest "min" (assert-equal 1 (min 1 2)) (assert-equal -1 (min -1 0))) (deftest "max" (assert-equal 2 (max 1 2)) (assert-equal 0 (max -1 0))) (deftest "clamp within range" (assert-equal 5 (clamp 5 0 10))) (deftest "clamp below" (assert-equal 0 (clamp -5 0 10))) (deftest "clamp above" (assert-equal 10 (clamp 15 0 10)))) (defsuite "stdlib-list-ops" (deftest "first" (assert-equal 1 (first (list 1 2 3)))) (deftest "first empty" (assert-nil (first (list)))) (deftest "first nil" (assert-nil (first nil))) (deftest "last" (assert-equal 3 (last (list 1 2 3)))) (deftest "last single" (assert-equal 1 (last (list 1)))) (deftest "last empty" (assert-nil (last (list)))) (deftest "rest" (assert-equal (list 2 3) (rest (list 1 2 3)))) (deftest "rest single" (assert-equal (list) (rest (list 1)))) (deftest "rest nil" (assert-equal (list) (rest nil))) (deftest "nth valid" (assert-equal 2 (nth (list 1 2 3) 1))) (deftest "nth first" (assert-equal 1 (nth (list 1 2 3) 0))) (deftest "nth out of bounds" (assert-nil (nth (list 1 2 3) 5))) (deftest "nth negative" (assert-nil (nth (list 1 2 3) -1))) (deftest "nth nil" (assert-nil (nth nil 0))) (deftest "cons" (assert-equal (list 0 1 2) (cons 0 (list 1 2)))) (deftest "cons to nil" (assert-equal (list 0) (cons 0 nil))) (deftest "append element" (assert-equal (list 1 2 3) (append (list 1 2) 3))) (deftest "append list" (assert-equal (list 1 2 3 4) (append (list 1 2) (list 3 4)))) (deftest "reverse" (assert-equal (list 3 2 1) (reverse (list 1 2 3)))) (deftest "reverse empty" (assert-equal (list) (reverse (list)))) (deftest "flatten" (assert-equal (list 1 2 3 4) (flatten (list (list 1 2) (list 3 4))))) (deftest "flatten mixed" (assert-equal (list 1 2 3) (flatten (list 1 (list 2 3))))) (deftest "range basic" (assert-equal (list 0 1 2) (range 0 3 1))) (deftest "range with step" (assert-equal (list 0 2 4) (range 0 6 2))) (deftest "chunk-every" (assert-equal (list (list 1 2) (list 3 4) (list 5)) (chunk-every (list 1 2 3 4 5) 2))) (deftest "chunk-every even" (assert-equal (list (list 1 2 3) (list 4 5 6)) (chunk-every (list 1 2 3 4 5 6) 3))) (deftest "zip-pairs" (assert-equal (list (list 1 2) (list 2 3) (list 3 4)) (zip-pairs (list 1 2 3 4)))) (deftest "zip-pairs short" (assert-equal (list (list 1 2)) (zip-pairs (list 1 2))))) (defsuite "stdlib-dict-ops" (deftest "vals" (let ((v (vals {:b 2 :a 1}))) (assert-equal 2 (len v)) (assert-true (some (fn (x) (= x 1)) v)) (assert-true (some (fn (x) (= x 2)) v)))) (deftest "has-key? present" (assert-true (has-key? {:b 2 :a 1} "a"))) (deftest "has-key? absent" (assert-false (has-key? {:a 1} "z"))) (deftest "assoc" (let ((d (assoc {:a 1} "b" 2))) (assert-equal 1 (get d "a")) (assert-equal 2 (get d "b")))) (deftest "assoc overwrites" (let ((d (assoc {:a 1} "a" 99))) (assert-equal 99 (get d "a")))) (deftest "dissoc" (let ((d (dissoc {:b 2 :a 1} "a"))) (assert-false (has-key? d "a")) (assert-true (has-key? d "b")))) (deftest "into list from list" (assert-equal (list 1 2 3 4) (into (list 1 2) (list 3 4)))) (deftest "into dict from pairs" (let ((d (into {} (list (list "a" 1) (list "b" 2))))) (assert-equal 1 (get d "a")) (assert-equal 2 (get d "b"))))) (defsuite "stdlib-string-ops" (deftest "upcase" (assert-equal "HELLO" (upcase "hello"))) (deftest "downcase" (assert-equal "hello" (downcase "HELLO"))) (deftest "string-length" (assert-equal 5 (string-length "hello")) (assert-equal 0 (string-length ""))) (deftest "substring" (assert-equal "ell" (substring "hello" 1 4))) (deftest "substring from start" (assert-equal "he" (substring "hello" 0 2))) (deftest "string-contains? found" (assert-true (string-contains? "hello world" "world"))) (deftest "string-contains? not found" (assert-false (string-contains? "hello" "xyz"))) (deftest "starts-with?" (assert-true (starts-with? "hello" "hel")) (assert-false (starts-with? "hello" "xyz"))) (deftest "ends-with?" (assert-true (ends-with? "hello" "llo")) (assert-false (ends-with? "hello" "xyz"))) (deftest "ends-with? suffix longer than string" (assert-false (ends-with? "hi" "hello")))) (defsuite "stdlib-utility" (deftest "contains? string" (assert-true (contains? "hello world" "world")) (assert-false (contains? "hello" "xyz"))) (deftest "contains? list" (assert-true (contains? (list 1 2 3) 2)) (assert-false (contains? (list 1 2 3) 4))) (deftest "contains? dict" (assert-true (contains? {:a 1} "a")) (assert-false (contains? {:a 1} "b"))) (deftest "contains? other returns false" (assert-false (contains? 42 1))) (deftest "pluralize singular" (assert-equal "item" (pluralize 1 "item" "items"))) (deftest "pluralize plural" (assert-equal "items" (pluralize 2 "item" "items"))) (deftest "pluralize zero" (assert-equal "items" (pluralize 0 "item" "items"))) (deftest "escape html entities" (assert-equal "&<>"'" (escape "&<>\"'"))) (deftest "escape plain string unchanged" (assert-equal "hello" (escape "hello"))) (deftest "assert passes" (assert-equal true (assert true "should pass"))) (deftest "parse-datetime passthrough" (assert-equal "2024-01-01" (parse-datetime "2024-01-01"))) (deftest "parse-datetime nil" (assert-nil (parse-datetime nil))))