123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- (define-module (test-suite lib)
- :use-module (ice-9 stack-catch)
- :use-module (ice-9 regex)
- :export (
-
- exception:bad-variable
- exception:missing-expression
- exception:out-of-range exception:unbound-var
- exception:used-before-defined
- exception:wrong-num-args exception:wrong-type-arg
- exception:numerical-overflow
- exception:struct-set!-denied
- exception:system-error
- exception:miscellaneous-error
- exception:string-contains-nul
-
- run-test
- pass-if expect-fail
- pass-if-exception expect-fail-exception
-
- with-test-prefix with-test-prefix* current-test-prefix
- format-test-name
-
- with-debugging-evaluator with-debugging-evaluator*
-
- register-reporter unregister-reporter reporter-registered?
- make-count-reporter print-counts
- make-log-reporter
- full-reporter
- user-reporter))
- (define exception:bad-variable
- (cons 'syntax-error "Bad variable"))
- (define exception:missing-expression
- (cons 'misc-error "^missing or extra expression"))
- (define exception:out-of-range
- (cons 'out-of-range "^.*out of range"))
- (define exception:unbound-var
- (cons 'unbound-variable "^Unbound variable"))
- (define exception:used-before-defined
- (cons 'unbound-variable "^Variable used before given a value"))
- (define exception:wrong-num-args
- (cons 'wrong-number-of-args "^Wrong number of arguments"))
- (define exception:wrong-type-arg
- (cons 'wrong-type-arg "^Wrong type"))
- (define exception:numerical-overflow
- (cons 'numerical-overflow "^Numerical overflow"))
- (define exception:struct-set!-denied
- (cons 'misc-error "^set! denied for field"))
- (define exception:system-error
- (cons 'system-error ".*"))
- (define exception:miscellaneous-error
- (cons 'misc-error "^.*"))
- (define exception:string-contains-nul
- (cons 'misc-error "^string contains #\\\\nul character"))
- (define (display-line . objs)
- (for-each display objs)
- (newline))
- (define (display-line-port port . objs)
- (for-each (lambda (obj) (display obj port)) objs)
- (newline port))
- (define run-test #f)
- (let ((test-running #f))
- (define (local-run-test name expect-pass thunk)
- (if test-running
- (error "Nested calls to run-test are not permitted.")
- (let ((test-name (full-name name)))
- (set! test-running #t)
- (catch #t
- (lambda ()
- (let ((result (thunk)))
- (if (eq? result #t) (throw 'pass))
- (if (eq? result #f) (throw 'fail))
- (throw 'unresolved)))
- (lambda (key . args)
- (case key
- ((pass)
- (report (if expect-pass 'pass 'upass) test-name))
- ((fail)
- (report (if expect-pass 'fail 'xfail) test-name))
- ((unresolved untested unsupported)
- (report key test-name))
- ((quit)
- (report 'unresolved test-name)
- (quit))
- (else
- (report 'error test-name (cons key args))))))
- (set! test-running #f))))
- (set! run-test local-run-test))
- (defmacro pass-if (name . rest)
- (if (and (null? rest) (pair? name))
-
-
- `(run-test ',name #t (lambda () ,name))
- `(run-test ,name #t (lambda () ,@rest))))
- (defmacro expect-fail (name . rest)
- (if (and (null? rest) (pair? name))
-
-
- `(run-test ',name #f (lambda () ,name))
- `(run-test ,name #f (lambda () ,@rest))))
- (define (run-test-exception name exception expect-pass thunk)
- (run-test name expect-pass
- (lambda ()
- (stack-catch (car exception)
- (lambda () (thunk) #f)
- (lambda (key proc message . rest)
- (cond
-
- ((string-match (cdr exception) message)
- #t)
-
-
- ((and (eq? 'misc-error (car exception))
- (list? rest)
- (string-match (cdr exception)
- (apply simple-format #f message (car rest))))
- #t)
-
-
- ((and (eq? 'syntax-error (car exception))
- (list? rest)
- (string-match (cdr exception)
- (apply simple-format #f message (car rest))))
- #t)
-
- (else
- (apply throw key proc message rest))))))))
- (defmacro pass-if-exception (name exception body . rest)
- `(,run-test-exception ,name ,exception #t (lambda () ,body ,@rest)))
- (defmacro expect-fail-exception (name exception body . rest)
- `(,run-test-exception ,name ,exception #f (lambda () ,body ,@rest)))
- (define (format-test-name name)
- (call-with-output-string
- (lambda (port)
- (let loop ((name name)
- (separator ""))
- (if (pair? name)
- (begin
- (display separator port)
- (display (car name) port)
- (loop (cdr name) ": ")))))))
- (define (full-name name)
- (append (current-test-prefix) (list name)))
- (define prefix-fluid (make-fluid))
- (fluid-set! prefix-fluid '())
- (define (current-test-prefix)
- (fluid-ref prefix-fluid))
- (define (with-test-prefix* prefix thunk)
- (with-fluids ((prefix-fluid
- (append (fluid-ref prefix-fluid) (list prefix))))
- (thunk)))
- (defmacro with-test-prefix (prefix . body)
- `(with-test-prefix* ,prefix (lambda () ,@body)))
- (define (with-debugging-evaluator* thunk)
- (let ((dopts #f))
- (dynamic-wind
- (lambda ()
- (set! dopts (debug-options))
- (debug-enable 'debug))
- thunk
- (lambda ()
- (debug-options dopts)))))
- (define-macro (with-debugging-evaluator . body)
- `(with-debugging-evaluator* (lambda () ,@body)))
- (define reporters '())
- (define default-reporter #f)
- (define (register-reporter reporter)
- (if (memq reporter reporters)
- (error "register-reporter: reporter already registered: " reporter))
- (set! reporters (cons reporter reporters)))
- (define (unregister-reporter reporter)
- (if (memq reporter reporters)
- (set! reporters (delq! reporter reporters))
- (error "unregister-reporter: reporter not registered: " reporter)))
- (define (reporter-registered? reporter)
- (if (memq reporter reporters) #t #f))
- (define (report . args)
- (if (pair? reporters)
- (for-each (lambda (reporter) (apply reporter args))
- reporters)
- (apply default-reporter args)))
- (define result-tags
- '((pass "PASS" "passes: ")
- (fail "FAIL" "failures: ")
- (upass "UPASS" "unexpected passes: ")
- (xfail "XFAIL" "expected failures: ")
- (unresolved "UNRESOLVED" "unresolved test cases: ")
- (untested "UNTESTED" "untested test cases: ")
- (unsupported "UNSUPPORTED" "unsupported test cases: ")
- (error "ERROR" "errors: ")))
- (define important-result-tags
- '(fail upass unresolved error))
- (define (print-result port result name . args)
- (let* ((tag (assq result result-tags))
- (label (if tag (cadr tag) #f)))
- (if label
- (begin
- (display label port)
- (display ": " port)
- (display (format-test-name name) port)
- (if (pair? args)
- (begin
- (display " - arguments: " port)
- (write args port)))
- (newline port))
- (error "(test-suite lib) FULL-REPORTER: unrecognized result: "
- result))))
- (define (make-count-reporter)
- (let ((counts (map (lambda (tag) (cons (car tag) 0)) result-tags)))
- (list
- (lambda (result name . args)
- (let ((pair (assq result counts)))
- (if pair
- (set-cdr! pair (+ 1 (cdr pair)))
- (error "count-reporter: unexpected test result: "
- (cons result (cons name args))))))
- (lambda ()
- (append counts '())))))
- (define (print-counts results . port?)
- (let ((port (if (pair? port?)
- (car port?)
- (current-output-port))))
- (newline port)
- (display-line-port port "Totals for this test run:")
- (for-each
- (lambda (tag)
- (let ((result (assq (car tag) results)))
- (if result
- (display-line-port port (caddr tag) (cdr result))
- (display-line-port port
- "Test suite bug: "
- "no total available for `" (car tag) "'"))))
- result-tags)
- (newline port)))
- (define (make-log-reporter file)
- (let ((port (if (output-port? file) file
- (open-output-file file))))
- (lambda args
- (apply print-result port args)
- (force-output port))))
- (define (full-reporter . args)
- (apply print-result (current-output-port) args))
- (define (user-reporter result name . args)
- (if (memq result important-result-tags)
- (apply full-reporter result name args)))
- (set! default-reporter full-reporter)
|