Step 15: bytecode + CEK state serialization — 16 tests
bytecode-serialize/deserialize: sxbc v2 format wrapping compiled code dicts. cek-serialize/deserialize: cek-state v1 format wrapping suspended CEK state (phase, request, env, kont). Both use SX s-expression round-trip via inspect/parse. lib/serialize.sx has pure SX versions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
145
spec/tests/test-bytecode-serial.sx
Normal file
145
spec/tests/test-bytecode-serial.sx
Normal file
@@ -0,0 +1,145 @@
|
||||
;; Step 15: Bytecode + continuation serialization
|
||||
;; Round-trip compiled code and suspended CEK state through strings.
|
||||
|
||||
;; ── Bytecode serialization ────────────────────────────────────────
|
||||
|
||||
(defsuite
|
||||
"bytecode-serialize-basic"
|
||||
(deftest
|
||||
"compile and serialize round-trips"
|
||||
(let
|
||||
((code (compile "(+ 1 2)")))
|
||||
(assert (not (nil? code)))
|
||||
(let
|
||||
((serialized (bytecode-serialize code)))
|
||||
(assert (string? serialized))
|
||||
(assert (> (string-length serialized) 0)))))
|
||||
(deftest
|
||||
"serialized format has sxbc header"
|
||||
(let
|
||||
((code (compile "(+ 1 2)")))
|
||||
(let
|
||||
((serialized (bytecode-serialize code)))
|
||||
(assert (starts-with? serialized "(sxbc 2")))))
|
||||
(deftest
|
||||
"deserialized code has same structure"
|
||||
(let
|
||||
((code (compile "(+ 1 2)")))
|
||||
(let
|
||||
((serialized (bytecode-serialize code))
|
||||
(restored (bytecode-deserialize serialized)))
|
||||
(assert (not (nil? restored)))
|
||||
(assert (dict? restored)))))
|
||||
(deftest
|
||||
"deserialized bytecode array matches"
|
||||
(let
|
||||
((code (compile "(+ 1 2)")))
|
||||
(let
|
||||
((serialized (bytecode-serialize code))
|
||||
(restored (bytecode-deserialize serialized)))
|
||||
(assert= (get restored "bytecode") (get code "bytecode")))))
|
||||
(deftest
|
||||
"deserialized constants match"
|
||||
(let
|
||||
((code (compile "(str \"hello\" \" \" \"world\")")))
|
||||
(let
|
||||
((serialized (bytecode-serialize code))
|
||||
(restored (bytecode-deserialize serialized)))
|
||||
(assert= (get restored "constants") (get code "constants"))))))
|
||||
|
||||
(defsuite
|
||||
"bytecode-serialize-types"
|
||||
(deftest
|
||||
"number bytecodes round-trip"
|
||||
(let
|
||||
((code (compile "(+ 42 3)")))
|
||||
(let
|
||||
((restored (bytecode-deserialize (bytecode-serialize code))))
|
||||
(assert= (get restored "bytecode") (get code "bytecode")))))
|
||||
(deftest
|
||||
"multiple expressions round-trip"
|
||||
(let
|
||||
((code (compile "(define x 1)")))
|
||||
(let
|
||||
((restored (bytecode-deserialize (bytecode-serialize code))))
|
||||
(assert= (get restored "bytecode") (get code "bytecode"))
|
||||
(assert= (get restored "constants") (get code "constants")))))
|
||||
(deftest
|
||||
"dict expression round-trips"
|
||||
(let
|
||||
((code (compile "(dict :a 1 :b 2)")))
|
||||
(let
|
||||
((restored (bytecode-deserialize (bytecode-serialize code))))
|
||||
(assert= (get restored "constants") (get code "constants")))))
|
||||
(deftest
|
||||
"lambda expression round-trips"
|
||||
(let
|
||||
((code (compile "(fn (x) (+ x 1))")))
|
||||
(let
|
||||
((restored (bytecode-deserialize (bytecode-serialize code))))
|
||||
(assert= (get restored "bytecode") (get code "bytecode")))))
|
||||
(deftest
|
||||
"invalid format raises error"
|
||||
(let
|
||||
((raised false))
|
||||
(guard
|
||||
(e (true (set! raised true)))
|
||||
(bytecode-deserialize "not valid"))
|
||||
(assert raised "should raise for invalid format"))))
|
||||
|
||||
;; ── CEK state serialization ───────────────────────────────────────
|
||||
|
||||
(defsuite
|
||||
"cek-serialize-basic"
|
||||
(deftest
|
||||
"suspended state serializes"
|
||||
(let
|
||||
((state (make-cek-suspended {:op "test"} (dict) (list))))
|
||||
(let
|
||||
((serialized (cek-serialize state)))
|
||||
(assert (string? serialized))
|
||||
(assert (starts-with? serialized "(cek-state 1")))))
|
||||
(deftest
|
||||
"deserialized state preserves phase"
|
||||
(let
|
||||
((state (make-cek-suspended {:op "test"} (dict) (list))))
|
||||
(let
|
||||
((restored (cek-deserialize (cek-serialize state))))
|
||||
(assert (cek-suspended? restored)))))
|
||||
(deftest
|
||||
"deserialized state preserves request"
|
||||
(let
|
||||
((state (make-cek-suspended {:url "/api" :op "fetch"} (dict) (list))))
|
||||
(let
|
||||
((restored (cek-deserialize (cek-serialize state))))
|
||||
(let
|
||||
((req (cek-io-request restored)))
|
||||
(assert= (get req :op) "fetch")
|
||||
(assert= (get req :url) "/api"))))))
|
||||
|
||||
(defsuite
|
||||
"cek-serialize-values"
|
||||
(deftest
|
||||
"request with nested data round-trips"
|
||||
(let
|
||||
((req {:params {:ids (list 1 2 3) :name "test"} :op "query"}) (state (make-cek-suspended req (dict) (list))))
|
||||
(let
|
||||
((restored (cek-deserialize (cek-serialize state))))
|
||||
(let
|
||||
((rreq (cek-io-request restored)))
|
||||
(assert= (get rreq :op) "query")
|
||||
(assert= (get (get rreq :params) :name) "test")
|
||||
(assert= (get (get rreq :params) :ids) (list 1 2 3))))))
|
||||
(deftest
|
||||
"string with special chars round-trips"
|
||||
(let
|
||||
((req {:op "test" :data "line1\nline2\ttab"}) (state (make-cek-suspended req (dict) (list))))
|
||||
(let
|
||||
((restored (cek-deserialize (cek-serialize state))))
|
||||
(assert= (get (cek-io-request restored) :data) "line1\nline2\ttab"))))
|
||||
(deftest
|
||||
"invalid cek format raises error"
|
||||
(let
|
||||
((raised false))
|
||||
(guard (e (true (set! raised true))) (cek-deserialize "garbage"))
|
||||
(assert raised "should raise for invalid format"))))
|
||||
Reference in New Issue
Block a user