safsaf/tests/test-exceptions.scm

147 lines
5.4 KiB
Scheme
Raw Normal View History

;; Safsaf, a Guile web framework
;; Copyright (C) 2026 Christopher Baines <mail@cbaines.net>
;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU Lesser General Public License
;; as published by the Free Software Foundation, either version 3 of
;; the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; Lesser General Public License for more details.
;;
;; You should have received a copy of the GNU Lesser General Public
;; License along with this program. If not, see
;; <https://www.gnu.org/licenses/>.
;;; test-exceptions.scm — Tests for (safsaf handler-wrappers exceptions)
(use-modules (tests support)
(safsaf handler-wrappers exceptions)
(srfi srfi-71)
(web request)
(web response)
(web uri))
(define (make-request method path headers)
(build-request (build-uri 'http #:host "localhost" #:path path)
#:method method
#:headers headers))
(define (failing-handler request body-port)
(error "test explosion"))
(define (ok-handler request body-port)
(values (build-response #:code 200) "ok"))
(define html-request
(make-request 'GET "/" '((accept . ((text/html))))))
(define json-request
(make-request 'GET "/" '((accept . ((application/json))))))
(define-suite exceptions-tests
(suite "passthrough"
(test "successful handler passes through unchanged"
(define wrapped (exceptions-handler-wrapper ok-handler))
(let ((resp body (wrapped html-request #f)))
(is (= 200 (response-code resp)))
(is (equal? "ok" body)))))
(suite "production mode"
(test "returns 500 for HTML client"
(define wrapped (exceptions-handler-wrapper failing-handler))
(let ((resp body (wrapped html-request #f)))
(is (= 500 (response-code resp)))
;; Body is a streaming procedure from html-response.
(is (procedure? body))))
(test "returns 500 JSON for JSON client"
(define wrapped (exceptions-handler-wrapper failing-handler))
(let ((resp body (wrapped json-request #f)))
(is (= 500 (response-code resp)))
(is (string? body))
;; Should contain error key but not backtrace.
(is (string-contains body "Internal Server Error"))
(is (not (string-contains body "test explosion"))))))
(suite "dev mode"
(test "returns 500 with backtrace for HTML client"
(define wrapped (exceptions-handler-wrapper failing-handler
#:dev? #t))
(let ((resp body (wrapped html-request #f)))
(is (= 500 (response-code resp)))
;; Body is a streaming procedure containing backtrace.
(is (procedure? body))))
(test "returns 500 JSON with backtrace for JSON client"
(define wrapped (exceptions-handler-wrapper failing-handler
#:dev? #t))
(let ((resp body (wrapped json-request #f)))
(is (= 500 (response-code resp)))
(is (string? body))
(is (string-contains body "backtrace"))
(is (string-contains body "test explosion")))))
(suite "custom renderers"
(test "render-error overrides everything"
(define wrapped
(exceptions-handler-wrapper
failing-handler
#:render-error
(lambda (request code message bt dev?)
(values (build-response #:code code) "custom error"))))
(let ((resp body (wrapped html-request #f)))
(is (= 500 (response-code resp)))
(is (equal? "custom error" body))))
(test "render-html overrides only HTML"
(define wrapped
(exceptions-handler-wrapper
failing-handler
#:render-html
(lambda (request code message bt dev?)
(values (build-response #:code code
#:headers '((content-type text/html)))
"custom html"))))
;; HTML request gets custom renderer.
(let ((resp body (wrapped html-request #f)))
(is (equal? "custom html" body)))
;; JSON request gets default JSON renderer.
(let ((resp body (wrapped json-request #f)))
(is (string? body))
(is (string-contains body "Internal Server Error"))))
(test "render-json overrides only JSON"
(define wrapped
(exceptions-handler-wrapper
failing-handler
#:render-json
(lambda (request code message bt dev?)
(values (build-response #:code code
#:headers '((content-type application/json)))
"{\"err\":\"custom\"}"))))
;; JSON request gets custom renderer.
(let ((resp body (wrapped json-request #f)))
(is (equal? "{\"err\":\"custom\"}" body)))
;; HTML request gets default HTML renderer.
(let ((resp body (wrapped html-request #f)))
(is (procedure? body)))))
(suite "make-exceptions-handler-wrapper"
(test "factory returns a working wrapper"
(define wrapper (make-exceptions-handler-wrapper #:dev? #t))
(define wrapped (wrapper failing-handler))
(let ((resp body (wrapped json-request #f)))
(is (= 500 (response-code resp)))
(is (string-contains body "test explosion"))))))
(run-tests exceptions-tests)