racket/collects/tests/r6rs/test.sls
2008-12-03 19:47:29 +00:00

234 lines
6.8 KiB
Scheme

#!r6rs
(library (tests r6rs test)
(export test
test/approx
test/alts
test/exn
test/values
test/output
test/unspec
test/unspec-or-exn
test/unspec-flonum-or-exn
test/output/unspec
run-test
report-test-results)
(import (rnrs))
(define-record-type err
(fields err-c))
(define-record-type expected-exception
(fields))
(define-record-type multiple-results
(fields values))
(define-record-type approx
(fields value))
(define-record-type alts
(fields values))
(define-syntax test
(syntax-rules ()
[(_ expr expected)
(begin
;; (write 'expr) (newline)
(run-test 'expr
(catch-exns (lambda () expr))
expected))]))
(define (catch-exns thunk)
(guard (c [#t (make-err c)])
(call-with-values thunk
(lambda x
(if (= 1 (length x))
(car x)
(make-multiple-results x))))))
(define-syntax test/approx
(syntax-rules ()
[(_ expr expected)
(run-test 'expr
(make-approx expr)
(make-approx expected))]))
(define-syntax test/alts
(syntax-rules ()
[(_ expr expected0 expected ...)
(run-test 'expr
expr
(make-alts (list expected0 expected ...)))]))
(define (good-enough? x y)
;; relative error should be with 0.1%, but greater
;; relative error is allowed when the expected value
;; is near zero.
(cond ((not (number? x)) #f)
((not (number? y)) #f)
((or (not (real? x))
(not (real? y)))
(and (good-enough? (real-part x) (real-part y))
(good-enough? (imag-part x) (imag-part y))))
((infinite? x)
(= x (* 2.0 y)))
((infinite? y)
(= (* 2.0 x) y))
((nan? y)
(nan? x))
((> (magnitude y) 1e-6)
(< (/ (magnitude (- x y))
(magnitude y))
1e-3))
(else
(< (magnitude (- x y)) 1e-6))))
(define-syntax test/exn
(syntax-rules ()
[(_ expr condition)
(test (guard (c [((condition-predicate (record-type-descriptor condition)) c)
(make-expected-exception)])
expr)
(make-expected-exception))]))
(define-syntax test/values
(syntax-rules ()
[(_ expr val ...)
(run-test 'expr
(catch-exns (lambda () expr))
(make-multiple-results (list val ...)))]))
(define-syntax test/output
(syntax-rules ()
[(_ expr expected str)
(run-test 'expr
(capture-output
(lambda ()
(run-test 'expr
(guard (c [#t (make-err c)])
expr)
expected)))
str)]))
(define-syntax test/unspec
(syntax-rules ()
[(_ expr)
(test (begin expr 'unspec) 'unspec)]))
(define-syntax test/unspec-or-exn
(syntax-rules ()
[(_ expr condition)
(test (guard (c [((condition-predicate (record-type-descriptor condition)) c)
'unspec])
(begin expr 'unspec))
'unspec)]))
(define-syntax test/unspec-flonum-or-exn
(syntax-rules ()
[(_ expr condition)
(test (guard (c [((condition-predicate (record-type-descriptor condition)) c)
'unspec-or-flonum])
(let ([v expr])
(if (flonum? v)
'unspec-or-flonum
(if (eq? v 'unspec-or-flonum)
(list v)
v))))
'unspec-or-flonum)]))
(define-syntax test/output/unspec
(syntax-rules ()
[(_ expr str)
(test/output (begin expr 'unspec) 'unspec str)]))
(define checked 0)
(define failures '())
(define (capture-output thunk)
(if (file-exists? "tmp-catch-out")
(delete-file "tmp-catch-out"))
(dynamic-wind
(lambda () 'nothing)
(lambda ()
(with-output-to-file "tmp-catch-out"
thunk)
(call-with-input-file "tmp-catch-out"
(lambda (p)
(get-string-n p 1024))))
(lambda ()
(if (file-exists? "tmp-catch-out")
(delete-file "tmp-catch-out")))))
(define (same-result? got expected)
(cond
[(and (real? expected) (nan? expected))
(and (real? got) (nan? got))]
[(expected-exception? expected)
(expected-exception? got)]
[(approx? expected)
(and (approx? got)
(good-enough? (approx-value expected)
(approx-value got)))]
[(multiple-results? expected)
(and (multiple-results? got)
(= (length (multiple-results-values expected))
(length (multiple-results-values got)))
(for-all same-result?
(multiple-results-values expected)
(multiple-results-values got)))]
[(alts? expected)
(exists (lambda (e) (same-result? got e))
(alts-values expected))]
[else (equal? got expected)]))
(define (run-test expr got expected)
(set! checked (+ 1 checked))
(unless (same-result? got expected)
(set! failures
(cons (list expr got expected)
failures))))
(define (write-result prefix v)
(cond
[(multiple-results? v)
(for-each (lambda (v)
(write-result prefix v))
(multiple-results-values v))]
[(approx? v)
(display prefix)
(display "approximately ")
(write (approx-value v))]
[(alts? v)
(write-result (string-append prefix " ")
(car (alts-values v)))
(for-each (lambda (v)
(write-result (string-append prefix "OR ")
v))
(cdr (alts-values v)))]
[else
(display prefix)
(write v)]))
(define (report-test-results)
(if (null? failures)
(begin
(display checked)
(display " tests passed\n"))
(begin
(display (length failures))
(display " tests failed:\n\n")
(for-each (lambda (t)
(display "Expression:\n ")
(write (car t))
(display "\nResult:")
(write-result "\n " (cadr t))
(display "\nExpected:")
(write-result "\n " (caddr t))
(display "\n\n"))
(reverse failures))
(display (length failures))
(display " of ")
(display checked)
(display " tests failed.\n")))))