;; lib/dream/tests/json.sx — JSON encode/parse round-trips.

(define dream-js-pass 0)
(define dream-js-fail 0)
(define dream-js-fails (list))

(define
  dream-js-test
  (fn
    (name actual expected)
    (if
      (= actual expected)
      (set! dream-js-pass (+ dream-js-pass 1))
      (begin
        (set! dream-js-fail (+ dream-js-fail 1))
        (append! dream-js-fails {:name name :actual actual :expected expected})))))

;; ── encoding scalars ───────────────────────────────────────────────
(dream-js-test "encode int" (dream-json-encode 42) "42")
(dream-js-test "encode float" (dream-json-encode 1.5) "1.5")
(dream-js-test "encode true" (dream-json-encode true) "true")
(dream-js-test "encode false" (dream-json-encode false) "false")
(dream-js-test "encode nil" (dream-json-encode nil) "null")
(dream-js-test "encode string" (dream-json-encode "hi") "\"hi\"")
(dream-js-test
  "encode string escapes quote"
  (dream-json-encode "a\"b")
  "\"a\\\"b\"")
(dream-js-test
  "encode list"
  (dream-json-encode (list 1 2 3))
  "[1,2,3]")
(dream-js-test
  "encode list of strings"
  (dream-json-encode (list "a" "b"))
  "[\"a\",\"b\"]")
(dream-js-test
  "encode single-key dict"
  (dream-json-encode {:a 1})
  "{\"a\":1}")
(dream-js-test "encode empty list" (dream-json-encode (list)) "[]")
(dream-js-test "encode empty dict" (dream-json-encode {}) "{}")

;; ── parsing scalars ────────────────────────────────────────────────
(dream-js-test "parse int" (dream-json-parse "5") 5)
(dream-js-test "parse negative" (dream-json-parse "-7") -7)
(dream-js-test "parse float" (dream-json-parse "1.5") 1.5)
(dream-js-test "parse true" (dream-json-parse "true") true)
(dream-js-test "parse false" (dream-json-parse "false") false)
(dream-js-test "parse null" (dream-json-parse "null") nil)
(dream-js-test "parse string" (dream-json-parse "\"hello\"") "hello")
(dream-js-test "parse string escape" (dream-json-parse "\"a\\nb\"") "a\nb")
(dream-js-test
  "parse array"
  (dream-json-parse "[1,2,3]")
  (list 1 2 3))
(dream-js-test "parse empty array" (dream-json-parse "[]") (list))
(dream-js-test
  "parse with whitespace"
  (dream-json-parse "  [ 1 , 2 ]  ")
  (list 1 2))

;; ── parsing objects ────────────────────────────────────────────────
(define dream-js-obj (dream-json-parse "{\"x\":5,\"y\":\"hi\"}"))
(dream-js-test "parse obj number" (get dream-js-obj "x") 5)
(dream-js-test "parse obj string" (get dream-js-obj "y") "hi")
(dream-js-test "parse empty obj" (dream-json-parse "{}") {})

;; ── nested ─────────────────────────────────────────────────────────
(define dream-js-nested (dream-json-parse "{\"a\":[1,{\"b\":2}],\"c\":true}"))
(dream-js-test
  "nested array first"
  (first (get dream-js-nested "a"))
  1)
(dream-js-test
  "nested object in array"
  (get (nth (get dream-js-nested "a") 1) "b")
  2)
(dream-js-test "nested bool" (get dream-js-nested "c") true)

;; ── round-trips ────────────────────────────────────────────────────
(define dream-js-v {:name "Ada" :age 36 :tags (list "math" "engine")})
(define dream-js-rt (dream-json-parse (dream-json-encode dream-js-v)))
(dream-js-test "roundtrip name" (get dream-js-rt "name") "Ada")
(dream-js-test "roundtrip age" (get dream-js-rt "age") 36)
(dream-js-test
  "roundtrip tags"
  (get dream-js-rt "tags")
  (list "math" "engine"))

;; ── response + request helpers ─────────────────────────────────────
(dream-js-test
  "json-value content-type"
  (dream-resp-header (dream-json-value {:ok true}) "content-type")
  "application/json")
(dream-js-test
  "json-value body"
  (dream-resp-body (dream-json-value {:ok true}))
  "{\"ok\":true}")
(dream-js-test
  "json-body parses request"
  (get (dream-json-body (dream-request "POST" "/" {} "{\"n\":9}")) "n")
  9)

(define dream-js-tests-run! (fn () {:total (+ dream-js-pass dream-js-fail) :passed dream-js-pass :failed dream-js-fail :fails dream-js-fails}))
