;; IO suspension tests — verifies perform/cek-step-loop/cek-resume (defsuite "io-suspend-basic" (deftest "perform creates suspended state" (let ((state (cek-step-loop (make-cek-state (quote (perform {:op "test"})) (make-env) (list))))) (assert (cek-suspended? state)) (assert (not (cek-terminal? state))))) (deftest "suspended state carries IO request" (let ((state (cek-step-loop (make-cek-state (quote (perform {:service "blog" :op "query"})) (make-env) (list))))) (let ((req (cek-io-request state))) (assert= (get req "op") "query") (assert= (get req "service") "blog")))) (deftest "cek-resume delivers result" (let ((state (cek-step-loop (make-cek-state (quote (perform {:op "test"})) (make-env) (list))))) (let ((final (cek-resume state 42))) (assert (cek-terminal? final)) (assert= (cek-value final) 42)))) (deftest "cek-resume with string result" (let ((state (cek-step-loop (make-cek-state (quote (perform {:op "test"})) (make-env) (list))))) (let ((final (cek-resume state "hello"))) (assert (cek-terminal? final)) (assert= (cek-value final) "hello")))) (deftest "cek-run errors on suspension" (let ((result (cek-try (fn () (cek-run (make-cek-state (quote (perform {:op "test"})) (make-env) (list))))))) (assert= (symbol-name (first result)) "error")))) (defsuite "io-suspend-control-flow" (deftest "perform inside let — result used in binding" (let ((state (cek-step-loop (make-cek-state (quote (let ((x (perform {:op "get-value"}))) (+ x 10))) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state 32))) (assert (cek-terminal? final)) (assert= (cek-value final) 42)))) (deftest "perform inside if condition" (let ((state (cek-step-loop (make-cek-state (quote (if (perform {:op "check"}) "yes" "no")) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state true))) (assert (cek-terminal? final)) (assert= (cek-value final) "yes")))) (deftest "perform inside if — false branch" (let ((state (cek-step-loop (make-cek-state (quote (if (perform {:op "check"}) "yes" "no")) (make-env) (list))))) (let ((final (cek-resume state false))) (assert (cek-terminal? final)) (assert= (cek-value final) "no")))) (deftest "sequential performs — two suspensions" (let ((state1 (cek-step-loop (make-cek-state (quote (let ((a (perform {:op "first"}))) (let ((b (perform {:op "second"}))) (+ a b)))) (make-env) (list))))) (assert (cek-suspended? state1)) (assert= (get (cek-io-request state1) "op") "first") (let ((state2 (cek-resume state1 10))) (assert (cek-suspended? state2)) (assert= (get (cek-io-request state2) "op") "second") (let ((final (cek-resume state2 32))) (assert (cek-terminal? final)) (assert= (cek-value final) 42))))) (deftest "perform inside begin — not last expr" (let ((state (cek-step-loop (make-cek-state (quote (begin (perform {:op "side-effect"}) "done")) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state nil))) (assert (cek-terminal? final)) (assert= (cek-value final) "done"))))) (defsuite "io-suspend-functions" (deftest "perform inside lambda" (let ((state (cek-step-loop (make-cek-state (quote ((fn (x) (+ x (perform {:op "get"}))) 10)) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state 32))) (assert (cek-terminal? final)) (assert= (cek-value final) 42)))) (deftest "perform result passed to function" (let ((state (cek-step-loop (make-cek-state (quote (let ((double (fn (x) (* x 2)))) (double (perform {:op "get-val"})))) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state 21))) (assert (cek-terminal? final)) (assert= (cek-value final) 42))))) (defsuite "io-suspend-values" (deftest "resume with nil" (let ((state (cek-step-loop (make-cek-state (quote (perform {:op "test"})) (make-env) (list))))) (let ((final (cek-resume state nil))) (assert (cek-terminal? final)) (assert (nil? (cek-value final)))))) (deftest "resume with list" (let ((state (cek-step-loop (make-cek-state (quote (perform {:op "fetch"})) (make-env) (list))))) (let ((final (cek-resume state (list 1 2 3)))) (assert (cek-terminal? final)) (assert= (len (cek-value final)) 3)))) (deftest "resume with dict" (let ((state (cek-step-loop (make-cek-state (quote (let ((result (perform {:op "query"}))) (get result "name"))) (make-env) (list))))) (let ((final (cek-resume state {:name "alice"}))) (assert (cek-terminal? final)) (assert= (cek-value final) "alice"))))) (defsuite "io-suspend-jit" (deftest "named function with perform suspends" (let ((state (cek-step-loop (make-cek-state (quote (begin (define fetch-data (fn (key) (perform {:op "fetch" :key key}))) (fetch-data "users"))) (make-env) (list))))) (assert (cek-suspended? state)) (assert= (get (cek-io-request state) "op") "fetch") (let ((final (cek-resume state (list "alice" "bob")))) (assert (cek-terminal? final)) (assert= (len (cek-value final)) 2)))) (deftest "named function with perform and computation" (let ((state (cek-step-loop (make-cek-state (quote (begin (define fetch-and-count (fn (key) (let ((data (perform {:op "fetch" :key key}))) (len data)))) (fetch-and-count "items"))) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state (list 1 2 3 4 5)))) (assert (cek-terminal? final)) (assert= (cek-value final) 5)))) (deftest "two named functions with sequential performs" (let ((state1 (cek-step-loop (make-cek-state (quote (begin (define get-name (fn () (perform {:op "get-name"}))) (define get-age (fn () (perform {:op "get-age"}))) (str (get-name) " is " (get-age) " years old"))) (make-env) (list))))) (assert (cek-suspended? state1)) (assert= (get (cek-io-request state1) "op") "get-name") (let ((state2 (cek-resume state1 "Alice"))) (assert (cek-suspended? state2)) (assert= (get (cek-io-request state2) "op") "get-age") (let ((final (cek-resume state2 30))) (assert (cek-terminal? final)) (assert= (cek-value final) "Alice is 30 years old")))))) (defsuite "io-suspend-cross-boundary" (deftest "function calling component that performs IO" (let ((state (cek-step-loop (make-cek-state (quote (begin (defcomp ~data-loader (&key source) (perform {:op "load" :source source})) (define render (fn (src) (let ((data (~data-loader :source src))) (str "loaded: " (len data) " items")))) (render "products"))) (make-env) (list))))) (assert (cek-suspended? state)) (assert= (get (cek-io-request state) "op") "load") (assert= (get (cek-io-request state) "source") "products") (let ((final (cek-resume state (list "a" "b" "c")))) (assert (cek-terminal? final)) (assert= (cek-value final) "loaded: 3 items"))))) (defsuite "io-suspend-error-handling" (deftest "guard wraps perform — normal completion" (let ((state (cek-step-loop (make-cek-state (quote (guard (e (true (str "caught: " e))) (perform {:op "get"}))) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state "ok-result"))) (assert (cek-terminal? final)) (assert= (cek-value final) "ok-result")))) (deftest "perform result flows through let in guard body" (let ((state (cek-step-loop (make-cek-state (quote (guard (e (true "error")) (let ((x (perform {:op "get"}))) (+ x 1)))) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state 41))) (assert (cek-terminal? final)) (assert= (cek-value final) 42))))) (defsuite "vm-import-suspension" (deftest "vm-execute-module runs trivial bytecode" (let ((globals (dict)) (code (compile-module (quote (42))))) (assert= (vm-execute-module code globals) 42))) (deftest "vm-execute-module converts code-from-value internally" (let ((globals (dict)) (code (compile-module (quote ((define x 99) x))))) (assert= (vm-execute-module code globals) 99))) (deftest "compile-module handles import form" (let ((code (compile-module (quote ((import (test lib))))))) (assert (dict? code)) (assert (not (nil? (get code :bytecode)))))) (deftest "vm-execute-module returns suspension dict on import" (let ((globals (dict)) (code (compile-module (quote ((import (test lib))))))) (let ((result (vm-execute-module code globals))) (assert (dict? result) "result should be a dict") (assert= (get result :suspended) true) (assert= (get result :op) "import")))) (deftest "vm-resume-module continues after suspension" (let ((globals (dict)) (code (compile-module (quote ((import (test lib)) (define x 42) x))))) (let ((r1 (vm-execute-module code globals))) (assert= (get r1 :suspended) true) (let ((r2 (vm-resume-module r1))) (assert= r2 42))))) (deftest "vm multiple sequential imports suspend and resume" (let ((globals (dict)) (code (compile-module (quote ((import (test a)) (import (test b)) (define x 99) x))))) (let ((r1 (vm-execute-module code globals))) (assert= (get r1 :suspended) true) (let ((r2 (vm-resume-module r1))) (assert= (get r2 :suspended) true) (let ((r3 (vm-resume-module r2))) (assert= r3 99)))))))