;; ========================================================================== ;; test-continuations.sx — Tests for delimited continuations (shift/reset) ;; ;; Requires: test-framework.sx loaded, continuations extension enabled. ;; ========================================================================== ;; -------------------------------------------------------------------------- ;; 1. Basic shift/reset ;; -------------------------------------------------------------------------- (defsuite "basic-shift-reset" (deftest "reset passthrough" (assert-equal 42 (reset 42))) (deftest "reset evaluates expression" (assert-equal 3 (reset (+ 1 2)))) (deftest "shift aborts to reset" (assert-equal 42 (reset (+ 1 (shift k 42))))) (deftest "shift with single invoke" (assert-equal 11 (reset (+ 1 (shift k (k 10)))))) (deftest "shift with multiple invokes" (assert-equal (list 11 21) (reset (+ 1 (shift k (list (k 10) (k 20))))))) (deftest "shift returns string" (assert-equal "aborted" (reset (+ 1 (shift k "aborted"))))) (deftest "shift returns nil" (assert-nil (reset (+ 1 (shift k nil))))) (deftest "nested expression with shift" (assert-equal 16 (+ 1 (reset (+ 10 (shift k (k 5)))))))) ;; -------------------------------------------------------------------------- ;; 2. Continuation predicates ;; -------------------------------------------------------------------------- (defsuite "continuation-predicates" (deftest "k is a continuation inside shift" (assert-true (reset (shift k (continuation? k))))) (deftest "number is not a continuation" (assert-false (continuation? 42))) (deftest "function is not a continuation" (assert-false (continuation? (fn (x) x)))) (deftest "nil is not a continuation" (assert-false (continuation? nil))) (deftest "string is not a continuation" (assert-false (continuation? "hello")))) ;; -------------------------------------------------------------------------- ;; 3. Continuation as value ;; -------------------------------------------------------------------------- (defsuite "continuation-as-value" (deftest "k returned from reset" ;; shift body returns k itself — reset returns the continuation (let ((k (reset (+ 1 (shift k k))))) (assert-true (continuation? k)) (assert-equal 11 (k 10)))) (deftest "invoke returned k multiple times" (let ((k (reset (+ 1 (shift k k))))) (assert-equal 11 (k 10)) (assert-equal 21 (k 20)) (assert-equal 2 (k 1)))) (deftest "pass k to another function" (let ((apply-k (fn (k v) (k v)))) (assert-equal 15 (reset (+ 5 (shift k (apply-k k 10))))))) (deftest "k in data structure" (let ((result (reset (+ 1 (shift k (list k 42)))))) (assert-equal 42 (nth result 1)) (assert-equal 100 ((first result) 99))))) ;; -------------------------------------------------------------------------- ;; 4. Nested reset ;; -------------------------------------------------------------------------- (defsuite "nested-reset" (deftest "inner reset captures independently" (assert-equal 12 (reset (+ 1 (reset (+ 10 (shift k (k 1)))))))) (deftest "inner abort outer continues" (assert-equal 43 (reset (+ 1 (reset (+ 10 (shift k 42))))))) (deftest "outer shift captures outer reset" (assert-equal 100 (reset (+ 1 (shift k (k 99))))))) ;; -------------------------------------------------------------------------- ;; 5. Interaction with scoped effects ;; -------------------------------------------------------------------------- (defsuite "continuations-with-scopes" (deftest "provide survives resume" (assert-equal "dark" (reset (provide "theme" "dark" (+ 0 (shift k (k 0))) (context "theme"))))) (deftest "scope and emit across shift" (assert-equal (list "a") (reset (scope "acc" (emit! "acc" "a") (+ 0 (shift k (k 0))) (emitted "acc")))))) ;; -------------------------------------------------------------------------- ;; 6. TCO interaction ;; -------------------------------------------------------------------------- (defsuite "tco-interaction" (deftest "shift in tail position" (assert-equal 42 (reset (if true (shift k (k 42)) 0)))) (deftest "shift in let body" (assert-equal 10 (reset (let ((x 5)) (+ x (shift k (k 5))))))))