;; Tests for perform/IO suspension chaining through for-each ;; Bug: after resume from first perform inside for-each, ;; subsequent iterations' performs don't suspend — they complete ;; synchronously, breaking multi-step async sequences like test runners. (defsuite "perform-for-each-chain" (deftest "for-each with perform suspends on each iteration" (let ((state1 (cek-step-loop (make-cek-state (quote (let ((results (list))) (for-each (fn (item) (let ((val (perform {:op "fetch" :key item}))) (append! results val))) (list "a" "b" "c")) results)) (make-env) (list))))) (assert-true (cek-suspended? state1)) (assert= "a" (get (cek-io-request state1) :key)) (let ((state2 (cek-resume state1 "result-a"))) (assert-true (cek-suspended? state2)) (assert= "b" (get (cek-io-request state2) :key)) (let ((state3 (cek-resume state2 "result-b"))) (assert-true (cek-suspended? state3)) (assert= "c" (get (cek-io-request state3) :key)) (let ((final (cek-resume state3 "result-c"))) (assert-true (cek-terminal? final)) (assert= 3 (len (cek-value final)))))))) (deftest "for-each with guard and perform chains correctly" (let ((state1 (cek-step-loop (make-cek-state (quote (let ((results (list))) (for-each (fn (item) (guard (e (true (append! results (str "fail:" item)))) (let ((val (perform {:op "fetch" :key item}))) (append! results (str "ok:" val))))) (list "x" "y")) results)) (make-env) (list))))) (assert-true (cek-suspended? state1)) (let ((state2 (cek-resume state1 "X"))) (assert-true (cek-suspended? state2)) (let ((final (cek-resume state2 "Y"))) (assert-true (cek-terminal? final)) (let ((results (cek-value final))) (assert= 2 (len results)) (assert= "ok:X" (nth results 0)) (assert= "ok:Y" (nth results 1))))))) (deftest "nested performs in for-each — reload + wait pattern" (let ((state1 (cek-step-loop (make-cek-state (quote (let ((log (list))) (for-each (fn (name) (perform {:op "wait" :ms 1000}) (append! log (str "reloaded:" name)) (perform {:op "wait" :ms 500}) (append! log (str "done:" name))) (list "t1" "t2")) log)) (make-env) (list))))) (assert-true (cek-suspended? state1)) (assert= 1000 (get (cek-io-request state1) :ms)) (let ((s2 (cek-resume state1 nil))) (assert-true (cek-suspended? s2)) (assert= 500 (get (cek-io-request s2) :ms)) (let ((s3 (cek-resume s2 nil))) (assert-true (cek-suspended? s3)) (assert= 1000 (get (cek-io-request s3) :ms)) (let ((s4 (cek-resume s3 nil))) (assert-true (cek-suspended? s4)) (assert= 500 (get (cek-io-request s4) :ms)) (let ((final (cek-resume s4 nil))) (assert-true (cek-terminal? final)) (assert= 4 (len (cek-value final))))))))))