123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
- ; Support for writing and running test suites
- (define-record-type test-suite :test-suite
- (really-make-test-suite name test-cases)
- test-suite?
- (name test-suite-name)
- (test-cases test-suite-cases set-test-suite-cases!))
- (define-record-discloser :test-suite
- (lambda (t)
- (list 'test-suite
- (test-suite-name t))))
- (define-record-type compound-test-suite :compound-test-suite
- (make-compound-test-suite name components)
- compound-test-suite?
- (name compound-test-suite-name)
- (components compound-test-suite-components))
- (define-record-discloser :compound-test-suite
- (lambda (t)
- (list 'compound-test-suite
- (compound-test-suite-name t)
- (compound-test-suite-components t))))
- (define (make-test-suite name)
- (really-make-test-suite name '()))
- (define-syntax define-test-suite
- (syntax-rules ()
- ((define-test-suite ?name)
- (define ?name (make-test-suite '?name)))
- ((define-test-suite ?name (?comp0 ...))
- (define ?name (make-compound-test-suite '?name (list ?comp0 ...))))))
- (define (add-test-case! suite case)
- (let ((same-name?
- (lambda (a-case)
- (eq? (test-case-name case) (test-case-name a-case)))))
- (cond
- ((any same-name?
- (test-suite-cases suite))
- => (lambda (duplicate)
- (warn "duplicate test case, removing old one" duplicate)
- (set-test-suite-cases! suite
- (delete same-name? (test-suite-cases suite)))))))
- (set-test-suite-cases! suite
- (cons case (test-suite-cases suite))))
- (define (zap-test-suite! suite)
- (set-test-suite-cases! suite '()))
- (define-record-type test-case :test-case
- (make-test-case name suite thunk)
- test-case?
- (name test-case-name)
- (suite test-case-suite)
- (thunk test-case-thunk))
- (define-record-discloser :test-case
- (lambda (c)
- (list 'test-case (test-case-name c))))
- (define-syntax define-test-case
- (syntax-rules ()
- ((define-test-case ?name ?suite ?body0 ?body1 ...)
- (let ((suite ?suite))
- (add-test-case! suite
- (make-test-case '?name
- suite
- (lambda ()
- ?body0 ?body1 ...)))))))
- (define-syntax define-test-cases
- (syntax-rules ()
- ((define-test-cases ?suite
- (?name ?body0 ?body1 ...) ...)
- (begin
- (define-test-case ?name ?suite ?body0 ?body1 ...) ...))))
- (define-syntax check
- (syntax-rules (=> not)
- ((check ?actual)
- (check (and ?actual #t) => #t))
- ((check ?actual => ?expected)
- (check ?actual (=> equal?) ?expected))
- ((check ?actual (=> ?equal?) ?expected)
- (let ((expected ?expected)
- (equal? ?equal?))
- (guard
- (c
- (else
- (register-failure!
- (make-check-failure (fluid $test-case)
- '?actual #f c '?expected expected equal?))))
- (let ((actual ?actual))
- (if (not (equal? actual expected))
- (register-failure!
- (make-check-failure (fluid $test-case)
- '?actual actual #f '?expected expected equal?)))))))))
- (define (always-true _)
- #t)
- (define-syntax check-exception
- (syntax-rules (=>)
- ((check-exception ?actual)
- (check-exception ?actual => always-true))
- ((check-exception ?actual => ?predicate)
- (let ((predicate ?predicate))
- (guard
- (c
- ((not (predicate c))
- (register-failure!
- (make-check-exception-failure (fluid $test-case)
- '?actual #f c predicate)))
- (else (values)))
-
- (let ((actual ?actual))
- (register-failure!
- (make-check-exception-failure (fluid $test-case)
- '?actual actual #f predicate))))))))
- ; special case: inexact
- (define (=within tolerance)
- (lambda (z1 z2)
- (< (magnitude (- z2 z1)) tolerance)))
- (define $test-case (make-fluid #f))
- (define $failures (make-fluid #f))
- (define (register-failure! failure)
- (let ((cell (fluid $failures)))
- (cell-set! cell
- (cons failure (cell-ref cell)))))
- (define-record-type check-failure :check-failure
- (make-check-failure test-case
- actual-expr actual-val actual-condition expected-expr expected-val
- equal?-proc)
- check-failure?
- (test-case check-failure-test-case)
- (actual-expr check-failure-actual-expr)
- (actual-val check-failure-actual-val)
- ;; may be #f
- (actual-condition check-failure-actual-condition)
- (expected-expr check-failure-expected-expr)
- (expected-val check-failure-expected-val)
- (equal?-proc check-failure-equal?-proc))
- (define-record-discloser :check-failure
- (lambda (f)
- (list 'check-failure
- (check-failure-test-case f)
- (list 'actual
- (check-failure-actual-expr f)
- (or (check-failure-actual-condition f)
- (check-failure-actual-val f)))
- (list 'expected
- (check-failure-expected-expr f)
- (check-failure-expected-val f))
- (check-failure-equal?-proc f))))
- (define-record-type check-exception-failure :check-exception-failure
- (make-check-exception-failure test-case
- actual-expr actual-val actual-condition predicate)
- check-exception-failure?
- (test-case check-exception-failure-test-case)
- (actual-expr check-exception-failure-actual-expr)
- (actual-val check-exception-failure-actual-val)
- ;; may be #f
- (actual-condition check-exception-failure-actual-condition)
- (predicate check-exception-failure-predicate))
- (define-record-discloser :check-exception-failure
- (lambda (f)
- (list 'check-exception-failure
- (check-exception-failure-test-case f)
- (list 'actual
- (check-exception-failure-actual-expr f)
- (or (check-exception-failure-actual-condition f)
- (check-exception-failure-actual-val f)))
- (check-exception-failure-predicate f))))
- (define (run-test-suite suite)
- (let ((p (current-error-port))
- (cell (make-cell '())))
- (let-fluid
- $failures cell
- (lambda ()
- (let recur ((suite suite))
- (display "[" p)
- (cond
- ((test-suite? suite)
- (display (test-suite-name suite) p)
- (newline p)
- (for-each (lambda (case)
- (display " (" p)
- (display (test-case-name case) p)
- (let-fluid $test-case case
- (test-case-thunk case))
- (display ")" p)
- (newline p))
- (reverse (test-suite-cases suite))))
- ((compound-test-suite? suite)
- (display (compound-test-suite-name suite) p)
- (newline p)
- (for-each recur (compound-test-suite-components suite))))
- (display "]" p)
- (newline p) (newline p))))
- (let ((failures (reverse (cell-ref cell))))
- (if (null? failures)
- (begin
- (display "ALL TESTS SUCCEDED" p)
- (newline p))
- (begin
- (display "FAILURES:" p)
- (newline p)
- (for-each report-failure failures)))
- failures)))
- (define (failure-test-case f)
- (cond
- ((check-failure? f)
- (check-failure-test-case f))
- ((check-exception-failure? f)
- (check-exception-failure-test-case f))))
- (define (report-failure f)
- (let ((p (current-error-port)))
- (let* ((cas (failure-test-case f))
- (suite (test-case-suite cas)))
-
- (display "Test case " p)
- (display (test-case-name cas) p)
- (display " [" p)
- (display (test-suite-name suite) p)
- (display "] FAILED:" p)
- (newline p)
- (cond
- ((check-failure? f)
- (display "From expression " p)
- (write (check-failure-actual-expr f) p)
- (display " EXPECTED value " p)
- (display (check-failure-expected-val f) p)
- (display " of " p)
- (write (check-failure-expected-expr f) p)
- (newline p)
- (display "INSTEAD got " p)
- (cond
- ((check-failure-actual-condition f)
- => (lambda (con)
- (display "exception with condition:" p)
- (display-condition con p)))
- (else
- (write (check-failure-actual-val f) p)
- (newline p))))
- ((check-exception-failure? f)
- (display "From expression " p)
- (write (check-exception-failure-actual-expr f) p)
- (display " EXPECTED exception" p)
- (let ((pred (check-exception-failure-predicate f)))
- (if (not (eq? always-true pred))
- (begin
- (display " with condition matching " p)
- (write pred p))))
- (newline p)
- (display "INSTEAD got " p)
- (cond
- ((check-exception-failure-actual-condition f)
- => (lambda (con)
- (display "exception with condition:" p)
- (display-condition con p)))
- (else
- (write (check-exception-failure-actual-val f) p)
- (newline p)))))
-
- (newline p))))
|