;; ==========================================================================
;; 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))))))))
