Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m9s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
233 lines
7.1 KiB
Plaintext
233 lines
7.1 KiB
Plaintext
;; lib/dream/tests/router.sx — routing dispatch, path params, scopes.
|
|
|
|
(define dream-rt-pass 0)
|
|
(define dream-rt-fail 0)
|
|
(define dream-rt-fails (list))
|
|
|
|
(define
|
|
dream-rt-test
|
|
(fn
|
|
(name actual expected)
|
|
(if
|
|
(= actual expected)
|
|
(set! dream-rt-pass (+ dream-rt-pass 1))
|
|
(begin
|
|
(set! dream-rt-fail (+ dream-rt-fail 1))
|
|
(append! dream-rt-fails {:name name :actual actual :expected expected})))))
|
|
|
|
(define
|
|
dream-rt-req
|
|
(fn (method target) (dream-request method target {} "")))
|
|
|
|
;; ── basic dispatch ─────────────────────────────────────────────────
|
|
(define
|
|
dream-rt-app
|
|
(dream-router
|
|
(list
|
|
(dream-get "/" (fn (req) (dream-text "home")))
|
|
(dream-get "/about" (fn (req) (dream-text "about")))
|
|
(dream-post "/submit" (fn (req) (dream-text "posted"))))))
|
|
|
|
(dream-rt-test
|
|
"GET / -> home"
|
|
(dream-resp-body (dream-rt-app (dream-rt-req "GET" "/")))
|
|
"home")
|
|
(dream-rt-test
|
|
"GET /about"
|
|
(dream-resp-body (dream-rt-app (dream-rt-req "GET" "/about")))
|
|
"about")
|
|
(dream-rt-test
|
|
"POST /submit"
|
|
(dream-resp-body (dream-rt-app (dream-rt-req "POST" "/submit")))
|
|
"posted")
|
|
(dream-rt-test
|
|
"unknown path 404"
|
|
(dream-status (dream-rt-app (dream-rt-req "GET" "/nope")))
|
|
404)
|
|
(dream-rt-test
|
|
"wrong method 404"
|
|
(dream-status (dream-rt-app (dream-rt-req "GET" "/submit")))
|
|
404)
|
|
(dream-rt-test
|
|
"trailing slash equiv"
|
|
(dream-resp-body (dream-rt-app (dream-rt-req "GET" "/about/")))
|
|
"about")
|
|
(dream-rt-test
|
|
"query ignored for routing"
|
|
(dream-resp-body (dream-rt-app (dream-rt-req "GET" "/about?x=1")))
|
|
"about")
|
|
|
|
;; ── path params ────────────────────────────────────────────────────
|
|
(define
|
|
dream-rt-papp
|
|
(dream-router
|
|
(list
|
|
(dream-get
|
|
"/users/:id"
|
|
(fn (req) (dream-text (dream-param req "id"))))
|
|
(dream-get
|
|
"/users/:id/posts/:pid"
|
|
(fn
|
|
(req)
|
|
(dream-text
|
|
(str (dream-param req "id") "-" (dream-param req "pid")))))
|
|
(dream-get
|
|
"/files/**"
|
|
(fn (req) (dream-text (dream-param req "**")))))))
|
|
|
|
(dream-rt-test
|
|
"single param"
|
|
(dream-resp-body (dream-rt-papp (dream-rt-req "GET" "/users/42")))
|
|
"42")
|
|
(dream-rt-test
|
|
"two params"
|
|
(dream-resp-body (dream-rt-papp (dream-rt-req "GET" "/users/7/posts/9")))
|
|
"7-9")
|
|
(dream-rt-test
|
|
"param no over-match"
|
|
(dream-status (dream-rt-papp (dream-rt-req "GET" "/users/7/extra")))
|
|
404)
|
|
(dream-rt-test
|
|
"catch-all captures rest"
|
|
(dream-resp-body (dream-rt-papp (dream-rt-req "GET" "/files/a/b/c.txt")))
|
|
"a/b/c.txt")
|
|
(dream-rt-test
|
|
"catch-all empty rest"
|
|
(dream-resp-body (dream-rt-papp (dream-rt-req "GET" "/files/")))
|
|
"")
|
|
|
|
;; ── route order: first match wins ──────────────────────────────────
|
|
(define
|
|
dream-rt-order
|
|
(dream-router
|
|
(list
|
|
(dream-get "/x/specific" (fn (req) (dream-text "specific")))
|
|
(dream-get "/x/:slug" (fn (req) (dream-text "generic"))))))
|
|
(dream-rt-test
|
|
"first match wins"
|
|
(dream-resp-body (dream-rt-order (dream-rt-req "GET" "/x/specific")))
|
|
"specific")
|
|
(dream-rt-test
|
|
"fallthrough to param"
|
|
(dream-resp-body (dream-rt-order (dream-rt-req "GET" "/x/other")))
|
|
"generic")
|
|
|
|
;; ── ANY method ─────────────────────────────────────────────────────
|
|
(define
|
|
dream-rt-any
|
|
(dream-router
|
|
(list (dream-any "/ping" (fn (req) (dream-text (dream-method req)))))))
|
|
(dream-rt-test
|
|
"ANY matches GET"
|
|
(dream-resp-body (dream-rt-any (dream-rt-req "GET" "/ping")))
|
|
"GET")
|
|
(dream-rt-test
|
|
"ANY matches DELETE"
|
|
(dream-resp-body (dream-rt-any (dream-rt-req "DELETE" "/ping")))
|
|
"DELETE")
|
|
|
|
;; ── handler returns bare string (coerced) ──────────────────────────
|
|
(define
|
|
dream-rt-coerce
|
|
(dream-router (list (dream-get "/s" (fn (req) "bare")))))
|
|
(dream-rt-test
|
|
"string coerced to 200"
|
|
(dream-status (dream-rt-coerce (dream-rt-req "GET" "/s")))
|
|
200)
|
|
(dream-rt-test
|
|
"string coerced body"
|
|
(dream-resp-body (dream-rt-coerce (dream-rt-req "GET" "/s")))
|
|
"bare")
|
|
|
|
;; ── scope: prefix mount ────────────────────────────────────────────
|
|
(define
|
|
dream-rt-scoped
|
|
(dream-router
|
|
(list
|
|
(dream-get "/" (fn (req) (dream-text "root")))
|
|
(dream-scope
|
|
"/api"
|
|
(list)
|
|
(list
|
|
(dream-get "/users" (fn (req) (dream-text "api-users")))
|
|
(dream-get
|
|
"/users/:id"
|
|
(fn
|
|
(req)
|
|
(dream-text (str "api-user-" (dream-param req "id"))))))))))
|
|
(dream-rt-test
|
|
"scope root still works"
|
|
(dream-resp-body (dream-rt-scoped (dream-rt-req "GET" "/")))
|
|
"root")
|
|
(dream-rt-test
|
|
"scope prefix path"
|
|
(dream-resp-body (dream-rt-scoped (dream-rt-req "GET" "/api/users")))
|
|
"api-users")
|
|
(dream-rt-test
|
|
"scope prefix param"
|
|
(dream-resp-body (dream-rt-scoped (dream-rt-req "GET" "/api/users/5")))
|
|
"api-user-5")
|
|
(dream-rt-test
|
|
"scope unprefixed 404"
|
|
(dream-status (dream-rt-scoped (dream-rt-req "GET" "/users")))
|
|
404)
|
|
|
|
;; ── scope: middleware applied to all routes ────────────────────────
|
|
(define
|
|
dream-rt-mw
|
|
(fn (next) (fn (req) (dream-add-header (next req) "X-Scope" "on"))))
|
|
(define
|
|
dream-rt-mwapp
|
|
(dream-router
|
|
(list
|
|
(dream-scope
|
|
"/v1"
|
|
(list dream-rt-mw)
|
|
(list (dream-get "/a" (fn (req) (dream-text "a"))))))))
|
|
(dream-rt-test
|
|
"scope mw header"
|
|
(dream-resp-header (dream-rt-mwapp (dream-rt-req "GET" "/v1/a")) "x-scope")
|
|
"on")
|
|
(dream-rt-test
|
|
"scope mw body intact"
|
|
(dream-resp-body (dream-rt-mwapp (dream-rt-req "GET" "/v1/a")))
|
|
"a")
|
|
|
|
;; ── nested scopes ──────────────────────────────────────────────────
|
|
(define
|
|
dream-rt-outer
|
|
(fn (next) (fn (req) (dream-add-header (next req) "X-Outer" "1"))))
|
|
(define
|
|
dream-rt-inner
|
|
(fn (next) (fn (req) (dream-add-header (next req) "X-Inner" "1"))))
|
|
(define
|
|
dream-rt-nested
|
|
(dream-router
|
|
(list
|
|
(dream-scope
|
|
"/api"
|
|
(list dream-rt-outer)
|
|
(list
|
|
(dream-scope
|
|
"/v2"
|
|
(list dream-rt-inner)
|
|
(list (dream-get "/thing" (fn (req) (dream-text "thing"))))))))))
|
|
(dream-rt-test
|
|
"nested path"
|
|
(dream-resp-body (dream-rt-nested (dream-rt-req "GET" "/api/v2/thing")))
|
|
"thing")
|
|
(dream-rt-test
|
|
"nested outer mw"
|
|
(dream-resp-header
|
|
(dream-rt-nested (dream-rt-req "GET" "/api/v2/thing"))
|
|
"x-outer")
|
|
"1")
|
|
(dream-rt-test
|
|
"nested inner mw"
|
|
(dream-resp-header
|
|
(dream-rt-nested (dream-rt-req "GET" "/api/v2/thing"))
|
|
"x-inner")
|
|
"1")
|
|
|
|
(define dream-rt-tests-run! (fn () {:total (+ dream-rt-pass dream-rt-fail) :passed dream-rt-pass :failed dream-rt-fail :fails dream-rt-fails}))
|