safsaf/tests/CLAUDE.md
Christopher Baines 5b0e6397dc
All checks were successful
/ test (push) Successful in 9s
Initial commit
Safsaf is a Guile web framework, written using Claude Code running
Claude Opus 4.6, based off of the Guix Data Service, Nar Herder and
Guix Build Coordinator codebases.
2026-04-13 14:24:19 +03:00

73 lines
2.1 KiB
Markdown

# Testing
## Framework
Tests use a minimal SRFI-269 implementation in `(tests support)`. Three
primitives — `is`, `test`, `suite` — build first-class test entities and
deliver them to a pluggable runner. Definition is separated from execution.
## Running tests
All tests (via Automake):
make check
Single file:
./pre-inst-env guile tests/test-router.scm
## Writing tests
```scheme
(use-modules (tests support)
(safsaf router)) ; module under test
(define-suite router-tests
(suite "route construction"
(test "creates route with method and pattern"
(let ((r (route 'GET '("users") identity)))
(is (route? r))
(is (eq? 'GET (route-method r))))))
(suite "matching"
(test "exact path match"
...)))
(run-tests router-tests)
```
Key points:
- `(is expr)` — assert expr is truthy. Returns the value on success.
- `(is (pred arg ...))` — predicate form; on failure shows evaluated args.
- `(test "desc" body ...)` — a single test case with one or more assertions.
- `(suite "desc" body ...)` — group tests and nested suites.
- `(define-suite name body ...)` — bind a suite-thunk to a variable.
- `(run-tests thunk)` — run with the simple runner, print summary, exit.
- Tests should be self-contained: don't depend on ordering or side effects
from other tests.
- Use `define` inside `test` bodies for local setup.
## Synthetic requests
Many tests need Guile `<request>` objects without a real HTTP server.
Build them with `build-request` from `(web request)`:
```scheme
(use-modules (web request) (web uri))
(define* (make-request method path #:optional (headers '()))
(build-request (build-uri 'http #:host "localhost" #:path path)
#:method method
#:headers headers))
```
Handler signature is `(request body-port) → (values response body)`. When
calling handlers or wrapped handlers in tests, pass `#f` as the body-port:
```scheme
(let ((resp body (wrapped (make-request 'GET "/" '()) #f)))
(is (= 200 (response-code resp))))
```
For handlers that read `current-route-params`, `parameterize` it directly.