Files
rose-ash/spec/tests/test-read-write.sx
giles 7d329f024d spec: read/write/display — S-expression reader/writer on ports
Adds read, write, display, newline, write-to-string, display-to-string
and current-*-port primitives to both JS and OCaml hosts.

JS: sxReadNormalize (#t/#f→true/false), sxReadConvert (()→nil),
    sxEq array comparison, sxWriteVal symbol/keyword name fix,
    readerMacroGet/readerMacroSet registry in parser platform.
OCaml: sx_write_val/sx_display_val helpers, read/write/display/newline
    primitives on port types; parser extended for #t/#f and N/D rationals.
42 new tests (test-read-write.sx), all passing on JS and OCaml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 18:32:30 +00:00

212 lines
6.3 KiB
Plaintext

;; ==========================================================================
;; test-read-write.sx — Tests for read / write / display / newline
;; ==========================================================================
;; --------------------------------------------------------------------------
;; read — parse one datum from an input port
;; --------------------------------------------------------------------------
(defsuite
"read:basics"
(deftest
"read integer"
(let ((p (open-input-string "42"))) (assert= (read p) 42)))
(deftest
"read float"
(let ((p (open-input-string "3.14"))) (assert= (read p) 3.14)))
(deftest
"read string"
(let ((p (open-input-string "\"hello\""))) (assert= (read p) "hello")))
(deftest
"read boolean true"
(let ((p (open-input-string "#t"))) (assert (read p))))
(deftest
"read boolean false"
(let ((p (open-input-string "#f"))) (assert (not (read p)))))
(deftest
"read nil"
(let ((p (open-input-string "()"))) (assert-nil (read p))))
(deftest
"read list"
(let
((p (open-input-string "(1 2 3)")))
(assert= (read p) (list 1 2 3))))
(deftest
"read nested list"
(let
((p (open-input-string "(+ 1 (* 2 3))")))
(assert=
(read p)
(list (quote +) 1 (list (quote *) 2 3))))))
;; --------------------------------------------------------------------------
;; read — eof and multi-read
;; --------------------------------------------------------------------------
(defsuite
"read:eof"
(deftest
"read eof returns eof-object"
(let ((p (open-input-string ""))) (assert (eof-object? (read p)))))
(deftest
"read whitespace-only returns eof"
(let ((p (open-input-string " "))) (assert (eof-object? (read p)))))
(deftest
"read two forms"
(let
((p (open-input-string "1 2")))
(let
((a (read p)) (b (read p)))
(assert (and (= a 1) (= b 2))))))
(deftest
"read returns eof after last form"
(let
((p (open-input-string "42")))
(read p)
(assert (eof-object? (read p))))))
;; --------------------------------------------------------------------------
;; write — serialize with quoting
;; --------------------------------------------------------------------------
(defsuite
"write:basics"
(deftest "write integer" (assert= (write-to-string 42) "42"))
(deftest
"write negative integer"
(assert= (write-to-string -5) "-5"))
(deftest "write float" (assert= (write-to-string 3.14) "3.14"))
(deftest "write true" (assert= (write-to-string true) "#t"))
(deftest "write false" (assert= (write-to-string false) "#f"))
(deftest "write nil" (assert= (write-to-string nil) "()"))
(deftest
"write string quotes"
(assert= (write-to-string "hello") "\"hello\""))
(deftest
"write string with escapes"
(assert= (write-to-string "a\"b") "\"a\\\"b\""))
(deftest
"write list"
(assert=
(write-to-string (list 1 2 3))
"(1 2 3)"))
(deftest
"write nested list"
(assert=
(write-to-string (list 1 (list 2 3)))
"(1 (2 3))"))
(deftest "write symbol" (assert= (write-to-string (quote foo)) "foo"))
(deftest "write rational" (assert= (write-to-string 1/3) "1/3")))
;; --------------------------------------------------------------------------
;; display — serialize without quoting
;; --------------------------------------------------------------------------
(defsuite
"display:basics"
(deftest "display integer" (assert= (display-to-string 42) "42"))
(deftest
"display string no quotes"
(assert= (display-to-string "hello") "hello"))
(deftest "display true" (assert= (display-to-string true) "#t"))
(deftest "display nil" (assert= (display-to-string nil) "()"))
(deftest
"display list"
(assert=
(display-to-string (list 1 2 3))
"(1 2 3)")))
;; --------------------------------------------------------------------------
;; write vs display distinction
;; --------------------------------------------------------------------------
(defsuite
"write-vs-display"
(deftest
"write quotes string, display does not"
(let
((s "hello"))
(assert
(and
(= (write-to-string s) "\"hello\"")
(= (display-to-string s) "hello")))))
(deftest
"write and display same for numbers"
(assert= (write-to-string 42) (display-to-string 42)))
(deftest
"write and display same for lists"
(assert=
(write-to-string (list 1 2))
(display-to-string (list 1 2)))))
;; --------------------------------------------------------------------------
;; write/display/newline to port
;; --------------------------------------------------------------------------
(defsuite
"write-to-port"
(deftest
"write to output port"
(let
((p (open-output-string)))
(write 42 p)
(assert= (get-output-string p) "42")))
(deftest
"display to output port"
(let
((p (open-output-string)))
(display "hi" p)
(assert= (get-output-string p) "hi")))
(deftest
"newline to output port"
(let
((p (open-output-string)))
(newline p)
(assert= (get-output-string p) "\n")))
(deftest
"write then newline"
(let
((p (open-output-string)))
(write "hello" p)
(newline p)
(assert= (get-output-string p) "\"hello\"\n")))
(deftest
"display multiple values"
(let
((p (open-output-string)))
(display 1 p)
(display " " p)
(display 2 p)
(assert= (get-output-string p) "1 2"))))
;; --------------------------------------------------------------------------
;; write round-trip
;; --------------------------------------------------------------------------
(defsuite
"write:round-trip"
(deftest
"integer round-trips"
(let
((p (open-input-string (write-to-string 42))))
(assert= (read p) 42)))
(deftest
"string round-trips"
(let
((p (open-input-string (write-to-string "hello world"))))
(assert= (read p) "hello world")))
(deftest
"list round-trips"
(let
((p (open-input-string (write-to-string (list 1 2 3)))))
(assert= (read p) (list 1 2 3))))
(deftest
"boolean true round-trips"
(let
((p (open-input-string (write-to-string true))))
(assert (read p))))
(deftest
"boolean false round-trips"
(let
((p (open-input-string (write-to-string false))))
(assert (not (read p))))))