Add in-source documentation of `scm_to_stringn ()'.
[bpt/guile.git] / test-suite / lib.scm
CommitLineData
000ee07f 1;;;; test-suite/lib.scm --- generic support for testing
0ba0b384 2;;;; Copyright (C) 1999, 2000, 2001, 2004, 2006, 2007, 2009 Free Software Foundation, Inc.
bba2d190 3;;;;
53befeb7
NJ
4;;;; This program is free software; you can redistribute it and/or
5;;;; modify it under the terms of the GNU Lesser General Public
6;;;; License as published by the Free Software Foundation; either
7;;;; version 3, or (at your option) any later version.
bba2d190 8;;;;
000ee07f
JB
9;;;; This program is distributed in the hope that it will be useful,
10;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53befeb7 12;;;; GNU Lesser General Public License for more details.
bba2d190 13;;;;
53befeb7
NJ
14;;;; You should have received a copy of the GNU Lesser General Public
15;;;; License along with this software; see the file COPYING.LESSER.
16;;;; If not, write to the Free Software Foundation, Inc., 51 Franklin
17;;;; Street, Fifth Floor, Boston, MA 02110-1301 USA
000ee07f 18
6b4113af 19(define-module (test-suite lib)
8bc4547c 20 :use-module (ice-9 stack-catch)
1a179b03
MD
21 :use-module (ice-9 regex)
22 :export (
000ee07f 23
6b4113af 24 ;; Exceptions which are commonly being tested for.
d6754c23 25 exception:bad-variable
d6e04e7c 26 exception:missing-expression
08c608e1 27 exception:out-of-range exception:unbound-var
0ac46745 28 exception:used-before-defined
08c608e1 29 exception:wrong-num-args exception:wrong-type-arg
0825ae0b 30 exception:numerical-overflow
d15ad007 31 exception:struct-set!-denied
a1ef7406 32 exception:system-error
d15ad007 33 exception:miscellaneous-error
970aac16 34 exception:string-contains-nul
0ba0b384 35 exception:read-error
6b4113af 36
000ee07f 37 ;; Reporting passes and failures.
6b4113af
DH
38 run-test
39 pass-if expect-fail
40 pass-if-exception expect-fail-exception
000ee07f
JB
41
42 ;; Naming groups of tests in a regular fashion.
43 with-test-prefix with-test-prefix* current-test-prefix
d6e04e7c 44 format-test-name
000ee07f 45
2d04022c
NJ
46 ;; Using the debugging evaluator.
47 with-debugging-evaluator with-debugging-evaluator*
48
ce3ed012
MG
49;; Using a given locale
50with-locale with-locale*
51
000ee07f
JB
52 ;; Reporting results in various ways.
53 register-reporter unregister-reporter reporter-registered?
54 make-count-reporter print-counts
bba2d190 55 make-log-reporter
087dab1c 56 full-reporter
d6e04e7c 57 user-reporter))
000ee07f
JB
58
59
60;;;; If you're using Emacs's Scheme mode:
000ee07f
JB
61;;;; (put 'with-test-prefix 'scheme-indent-function 1)
62
63\f
57e7f270
DH
64;;;; CORE FUNCTIONS
65;;;;
66;;;; The function (run-test name expected-result thunk) is the heart of the
67;;;; testing environment. The first parameter NAME is a unique name for the
68;;;; test to be executed (for an explanation of this parameter see below under
69;;;; TEST NAMES). The second parameter EXPECTED-RESULT is a boolean value
70;;;; that indicates whether the corresponding test is expected to pass. If
71;;;; EXPECTED-RESULT is #t the test is expected to pass, if EXPECTED-RESULT is
72;;;; #f the test is expected to fail. Finally, THUNK is the function that
73;;;; actually performs the test. For example:
74;;;;
75;;;; (run-test "integer addition" #t (lambda () (= 2 (+ 1 1))))
76;;;;
77;;;; To report success, THUNK should either return #t or throw 'pass. To
78;;;; report failure, THUNK should either return #f or throw 'fail. If THUNK
79;;;; returns a non boolean value or throws 'unresolved, this indicates that
80;;;; the test did not perform as expected. For example the property that was
81;;;; to be tested could not be tested because something else went wrong.
82;;;; THUNK may also throw 'untested to indicate that the test was deliberately
83;;;; not performed, for example because the test case is not complete yet.
84;;;; Finally, if THUNK throws 'unsupported, this indicates that this test
85;;;; requires some feature that is not available in the configured testing
86;;;; environment. All other exceptions thrown by THUNK are considered as
87;;;; errors.
88;;;;
6b4113af
DH
89;;;;
90;;;; Convenience macros for tests expected to pass or fail
91;;;;
bba2d190 92;;;; * (pass-if name body) is a short form for
57e7f270 93;;;; (run-test name #t (lambda () body))
bba2d190 94;;;; * (expect-fail name body) is a short form for
57e7f270
DH
95;;;; (run-test name #f (lambda () body))
96;;;;
bba2d190 97;;;; For example:
57e7f270
DH
98;;;;
99;;;; (pass-if "integer addition" (= 2 (+ 1 1)))
6b4113af
DH
100;;;;
101;;;;
102;;;; Convenience macros to test for exceptions
103;;;;
104;;;; The following macros take exception parameters which are pairs
105;;;; (type . message), where type is a symbol that denotes an exception type
106;;;; like 'wrong-type-arg or 'out-of-range, and message is a string holding a
107;;;; regular expression that describes the error message for the exception
108;;;; like "Argument .* out of range".
109;;;;
110;;;; * (pass-if-exception name exception body) will pass if the execution of
111;;;; body causes the given exception to be thrown. If no exception is
112;;;; thrown, the test fails. If some other exception is thrown, is is an
113;;;; error.
114;;;; * (expect-fail-exception name exception body) will pass unexpectedly if
115;;;; the execution of body causes the given exception to be thrown. If no
116;;;; exception is thrown, the test fails expectedly. If some other
117;;;; exception is thrown, it is an error.
57e7f270
DH
118
119\f
000ee07f
JB
120;;;; TEST NAMES
121;;;;
122;;;; Every test in the test suite has a unique name, to help
123;;;; developers find tests that are failing (or unexpectedly passing),
124;;;; and to help gather statistics.
125;;;;
126;;;; A test name is a list of printable objects. For example:
127;;;; ("ports.scm" "file" "read and write back list of strings")
128;;;; ("ports.scm" "pipe" "read")
129;;;;
130;;;; Test names may contain arbitrary objects, but they always have
131;;;; the following properties:
132;;;; - Test names can be compared with EQUAL?.
133;;;; - Test names can be reliably stored and retrieved with the standard WRITE
134;;;; and READ procedures; doing so preserves their identity.
bba2d190 135;;;;
000ee07f 136;;;; For example:
bba2d190 137;;;;
57e7f270 138;;;; (pass-if "simple addition" (= 4 (+ 2 2)))
bba2d190 139;;;;
000ee07f
JB
140;;;; In that case, the test name is the list ("simple addition").
141;;;;
e46083d5
DH
142;;;; In the case of simple tests the expression that is tested would often
143;;;; suffice as a test name by itself. Therefore, the convenience macros
144;;;; pass-if and expect-fail provide a shorthand notation that allows to omit
145;;;; a test name in such cases.
146;;;;
147;;;; * (pass-if expression) is a short form for
148;;;; (run-test 'expression #t (lambda () expression))
149;;;; * (expect-fail expression) is a short form for
150;;;; (run-test 'expression #f (lambda () expression))
151;;;;
152;;;; For example:
153;;;;
154;;;; (pass-if (= 2 (+ 1 1)))
155;;;;
000ee07f
JB
156;;;; The WITH-TEST-PREFIX syntax and WITH-TEST-PREFIX* procedure establish
157;;;; a prefix for the names of all tests whose results are reported
158;;;; within their dynamic scope. For example:
bba2d190 159;;;;
000ee07f
JB
160;;;; (begin
161;;;; (with-test-prefix "basic arithmetic"
162;;;; (pass-if "addition" (= (+ 2 2) 4))
05c4ba00 163;;;; (pass-if "subtraction" (= (- 4 2) 2)))
000ee07f 164;;;; (pass-if "multiplication" (= (* 2 2) 4)))
bba2d190 165;;;;
000ee07f
JB
166;;;; In that example, the three test names are:
167;;;; ("basic arithmetic" "addition"),
05c4ba00 168;;;; ("basic arithmetic" "subtraction"), and
000ee07f
JB
169;;;; ("multiplication").
170;;;;
171;;;; WITH-TEST-PREFIX can be nested. Each WITH-TEST-PREFIX postpends
172;;;; a new element to the current prefix:
bba2d190 173;;;;
000ee07f
JB
174;;;; (with-test-prefix "arithmetic"
175;;;; (with-test-prefix "addition"
176;;;; (pass-if "integer" (= (+ 2 2) 4))
177;;;; (pass-if "complex" (= (+ 2+3i 4+5i) 6+8i)))
178;;;; (with-test-prefix "subtraction"
179;;;; (pass-if "integer" (= (- 2 2) 0))
180;;;; (pass-if "complex" (= (- 2+3i 1+2i) 1+1i))))
bba2d190 181;;;;
000ee07f
JB
182;;;; The four test names here are:
183;;;; ("arithmetic" "addition" "integer")
184;;;; ("arithmetic" "addition" "complex")
185;;;; ("arithmetic" "subtraction" "integer")
186;;;; ("arithmetic" "subtraction" "complex")
187;;;;
188;;;; To print a name for a human reader, we DISPLAY its elements,
189;;;; separated by ": ". So, the last set of test names would be
190;;;; reported as:
bba2d190 191;;;;
000ee07f
JB
192;;;; arithmetic: addition: integer
193;;;; arithmetic: addition: complex
194;;;; arithmetic: subtraction: integer
195;;;; arithmetic: subtraction: complex
196;;;;
197;;;; The Guile benchmarks use with-test-prefix to include the name of
198;;;; the source file containing the test in the test name, to help
199;;;; developers to find failing tests, and to provide each file with its
200;;;; own namespace.
201
202\f
203;;;; REPORTERS
bba2d190 204;;;;
000ee07f
JB
205;;;; A reporter is a function which we apply to each test outcome.
206;;;; Reporters can log results, print interesting results to the
207;;;; standard output, collect statistics, etc.
bba2d190 208;;;;
57e7f270
DH
209;;;; A reporter function takes two mandatory arguments, RESULT and TEST, and
210;;;; possibly additional arguments depending on RESULT; its return value
000ee07f
JB
211;;;; is ignored. RESULT has one of the following forms:
212;;;;
bba2d190 213;;;; pass - The test named TEST passed.
57e7f270
DH
214;;;; Additional arguments are ignored.
215;;;; upass - The test named TEST passed unexpectedly.
216;;;; Additional arguments are ignored.
217;;;; fail - The test named TEST failed.
218;;;; Additional arguments are ignored.
219;;;; xfail - The test named TEST failed, as expected.
220;;;; Additional arguments are ignored.
221;;;; unresolved - The test named TEST did not perform as expected, for
222;;;; example the property that was to be tested could not be
223;;;; tested because something else went wrong.
224;;;; Additional arguments are ignored.
225;;;; untested - The test named TEST was not actually performed, for
bba2d190 226;;;; example because the test case is not complete yet.
57e7f270
DH
227;;;; Additional arguments are ignored.
228;;;; unsupported - The test named TEST requires some feature that is not
229;;;; available in the configured testing environment.
230;;;; Additional arguments are ignored.
231;;;; error - An error occurred while the test named TEST was
232;;;; performed. Since this result means that the system caught
233;;;; an exception it could not handle, the exception arguments
234;;;; are passed as additional arguments.
000ee07f
JB
235;;;;
236;;;; This library provides some standard reporters for logging results
237;;;; to a file, reporting interesting results to the user, and
238;;;; collecting totals.
087dab1c
JB
239;;;;
240;;;; You can use the REGISTER-REPORTER function and friends to add
241;;;; whatever reporting functions you like. If you don't register any
242;;;; reporters, the library uses FULL-REPORTER, which simply writes
243;;;; all results to the standard output.
000ee07f
JB
244
245\f
57e7f270
DH
246;;;; MISCELLANEOUS
247;;;;
248
6b4113af 249;;; Define some exceptions which are commonly being tested for.
d6754c23
DH
250(define exception:bad-variable
251 (cons 'syntax-error "Bad variable"))
d6e04e7c
DH
252(define exception:missing-expression
253 (cons 'misc-error "^missing or extra expression"))
6b4113af 254(define exception:out-of-range
a47d845f 255 (cons 'out-of-range "^.*out of range"))
08c608e1
DH
256(define exception:unbound-var
257 (cons 'unbound-variable "^Unbound variable"))
0ac46745
MV
258(define exception:used-before-defined
259 (cons 'unbound-variable "^Variable used before given a value"))
08c608e1
DH
260(define exception:wrong-num-args
261 (cons 'wrong-number-of-args "^Wrong number of arguments"))
6b4113af 262(define exception:wrong-type-arg
a47d845f 263 (cons 'wrong-type-arg "^Wrong type"))
0825ae0b
KR
264(define exception:numerical-overflow
265 (cons 'numerical-overflow "^Numerical overflow"))
d15ad007
LC
266(define exception:struct-set!-denied
267 (cons 'misc-error "^set! denied for field"))
a1ef7406
LC
268(define exception:system-error
269 (cons 'system-error ".*"))
d15ad007
LC
270(define exception:miscellaneous-error
271 (cons 'misc-error "^.*"))
0ba0b384
LC
272(define exception:read-error
273 (cons 'read-error "^.*$"))
6b4113af 274
970aac16
KR
275;; as per throw in scm_to_locale_stringn()
276(define exception:string-contains-nul
277 (cons 'misc-error "^string contains #\\\\nul character"))
278
279
57e7f270
DH
280;;; Display all parameters to the default output port, followed by a newline.
281(define (display-line . objs)
282 (for-each display objs)
283 (newline))
284
285;;; Display all parameters to the given output port, followed by a newline.
286(define (display-line-port port . objs)
287 (for-each (lambda (obj) (display obj port)) objs)
288 (newline port))
289
290\f
291;;;; CORE FUNCTIONS
292;;;;
293
294;;; The central testing routine.
295;;; The idea is taken from Greg, the GNUstep regression test environment.
296(define run-test #f)
297(let ((test-running #f))
298 (define (local-run-test name expect-pass thunk)
299 (if test-running
300 (error "Nested calls to run-test are not permitted.")
301 (let ((test-name (full-name name)))
302 (set! test-running #t)
303 (catch #t
304 (lambda ()
305 (let ((result (thunk)))
306 (if (eq? result #t) (throw 'pass))
307 (if (eq? result #f) (throw 'fail))
308 (throw 'unresolved)))
309 (lambda (key . args)
310 (case key
bba2d190 311 ((pass)
57e7f270 312 (report (if expect-pass 'pass 'upass) test-name))
bba2d190 313 ((fail)
57e7f270 314 (report (if expect-pass 'fail 'xfail) test-name))
bba2d190 315 ((unresolved untested unsupported)
57e7f270 316 (report key test-name))
bba2d190 317 ((quit)
57e7f270
DH
318 (report 'unresolved test-name)
319 (quit))
bba2d190 320 (else
57e7f270
DH
321 (report 'error test-name (cons key args))))))
322 (set! test-running #f))))
323 (set! run-test local-run-test))
324
325;;; A short form for tests that are expected to pass, taken from Greg.
ce09ee19
AW
326(define-syntax pass-if
327 (syntax-rules ()
328 ((_ name)
329 ;; presume this is a simple test, i.e. (pass-if (even? 2))
330 ;; where the body should also be the name.
331 (run-test 'name #t (lambda () name)))
332 ((_ name rest ...)
333 (run-test name #t (lambda () rest ...)))))
57e7f270
DH
334
335;;; A short form for tests that are expected to fail, taken from Greg.
ce09ee19
AW
336(define-syntax expect-fail
337 (syntax-rules ()
338 ((_ name)
339 ;; presume this is a simple test, i.e. (expect-fail (even? 2))
340 ;; where the body should also be the name.
341 (run-test 'name #f (lambda () name)))
342 ((_ name rest ...)
343 (run-test name #f (lambda () rest ...)))))
57e7f270 344
6b4113af
DH
345;;; A helper function to implement the macros that test for exceptions.
346(define (run-test-exception name exception expect-pass thunk)
347 (run-test name expect-pass
348 (lambda ()
8bc4547c 349 (stack-catch (car exception)
6b4113af 350 (lambda () (thunk) #f)
bba2d190
TTN
351 (lambda (key proc message . rest)
352 (cond
353 ;; handle explicit key
354 ((string-match (cdr exception) message)
355 #t)
356 ;; handle `(error ...)' which uses `misc-error' for key and doesn't
357 ;; yet format the message and args (we have to do it here).
358 ((and (eq? 'misc-error (car exception))
359 (list? rest)
360 (string-match (cdr exception)
361 (apply simple-format #f message (car rest))))
362 #t)
e6729603
DH
363 ;; handle syntax errors which use `syntax-error' for key and don't
364 ;; yet format the message and args (we have to do it here).
365 ((and (eq? 'syntax-error (car exception))
366 (list? rest)
367 (string-match (cdr exception)
368 (apply simple-format #f message (car rest))))
369 #t)
bba2d190
TTN
370 ;; unhandled; throw again
371 (else
372 (apply throw key proc message rest))))))))
6b4113af
DH
373
374;;; A short form for tests that expect a certain exception to be thrown.
ce09ee19
AW
375(define-syntax pass-if-exception
376 (syntax-rules ()
377 ((_ name exception body rest ...)
378 (run-test-exception name exception #t (lambda () body rest ...)))))
6b4113af
DH
379
380;;; A short form for tests expected to fail to throw a certain exception.
ce09ee19
AW
381(define-syntax expect-fail-exception
382 (syntax-rules ()
383 ((_ name exception body rest ...)
384 (run-test-exception name exception #f (lambda () body rest ...)))))
6b4113af 385
57e7f270
DH
386\f
387;;;; TEST NAMES
388;;;;
389
390;;;; Turn a test name into a nice human-readable string.
391(define (format-test-name name)
392 (call-with-output-string
393 (lambda (port)
394 (let loop ((name name)
395 (separator ""))
396 (if (pair? name)
397 (begin
398 (display separator port)
399 (display (car name) port)
400 (loop (cdr name) ": ")))))))
401
402;;;; For a given test-name, deliver the full name including all prefixes.
403(define (full-name name)
404 (append (current-test-prefix) (list name)))
000ee07f
JB
405
406;;; A fluid containing the current test prefix, as a list.
407(define prefix-fluid (make-fluid))
408(fluid-set! prefix-fluid '())
57e7f270
DH
409(define (current-test-prefix)
410 (fluid-ref prefix-fluid))
000ee07f
JB
411
412;;; Postpend PREFIX to the current name prefix while evaluting THUNK.
413;;; The name prefix is only changed within the dynamic scope of the
414;;; call to with-test-prefix*. Return the value returned by THUNK.
415(define (with-test-prefix* prefix thunk)
416 (with-fluids ((prefix-fluid
417 (append (fluid-ref prefix-fluid) (list prefix))))
418 (thunk)))
419
420;;; (with-test-prefix PREFIX BODY ...)
421;;; Postpend PREFIX to the current name prefix while evaluating BODY ...
422;;; The name prefix is only changed within the dynamic scope of the
423;;; with-test-prefix expression. Return the value returned by the last
424;;; BODY expression.
425(defmacro with-test-prefix (prefix . body)
426 `(with-test-prefix* ,prefix (lambda () ,@body)))
427
2d04022c
NJ
428;;; Call THUNK using the debugging evaluator.
429(define (with-debugging-evaluator* thunk)
430 (let ((dopts #f))
431 (dynamic-wind
432 (lambda ()
433 (set! dopts (debug-options))
434 (debug-enable 'debug))
435 thunk
436 (lambda ()
437 (debug-options dopts)))))
438
439;;; Evaluate BODY... using the debugging evaluator.
440(define-macro (with-debugging-evaluator . body)
441 `(with-debugging-evaluator* (lambda () ,@body)))
442
ce3ed012
MG
443;;; Call THUNK with a given locale
444(define (with-locale* nloc thunk)
445 (let ((loc #f))
446 (dynamic-wind
447 (lambda ()
448 (if (defined? 'setlocale)
449 (begin
450 (set! loc
451 (false-if-exception (setlocale LC_ALL nloc)))
452 (if (not loc)
453 (throw 'unresolved)))
454 (throw 'unresolved)))
455 thunk
456 (lambda ()
457 (if (defined? 'setlocale)
458 (setlocale LC_ALL loc))))))
459
460;;; Evaluate BODY... using the given locale.
461(define-macro (with-locale loc . body)
462 `(with-locale* ,loc (lambda () ,@body)))
2d04022c 463
000ee07f 464\f
57e7f270 465;;;; REPORTERS
bba2d190 466;;;;
000ee07f
JB
467
468;;; The global list of reporters.
469(define reporters '())
470
087dab1c
JB
471;;; The default reporter, to be used only if no others exist.
472(define default-reporter #f)
473
000ee07f
JB
474;;; Add the procedure REPORTER to the current set of reporter functions.
475;;; Signal an error if that reporter procedure object is already registered.
476(define (register-reporter reporter)
477 (if (memq reporter reporters)
478 (error "register-reporter: reporter already registered: " reporter))
479 (set! reporters (cons reporter reporters)))
480
481;;; Remove the procedure REPORTER from the current set of reporter
482;;; functions. Signal an error if REPORTER is not currently registered.
483(define (unregister-reporter reporter)
484 (if (memq reporter reporters)
485 (set! reporters (delq! reporter reporters))
486 (error "unregister-reporter: reporter not registered: " reporter)))
487
488;;; Return true iff REPORTER is in the current set of reporter functions.
489(define (reporter-registered? reporter)
490 (if (memq reporter reporters) #t #f))
491
000ee07f 492;;; Send RESULT to all currently registered reporter functions.
57e7f270 493(define (report . args)
087dab1c 494 (if (pair? reporters)
57e7f270 495 (for-each (lambda (reporter) (apply reporter args))
087dab1c 496 reporters)
57e7f270 497 (apply default-reporter args)))
000ee07f
JB
498
499\f
57e7f270
DH
500;;;; Some useful standard reporters:
501;;;; Count reporters count the occurrence of each test result type.
502;;;; Log reporters write all test results to a given log file.
503;;;; Full reporters write all test results to the standard output.
504;;;; User reporters write interesting test results to the standard output.
505
506;;; The complete list of possible test results.
bba2d190 507(define result-tags
57e7f270
DH
508 '((pass "PASS" "passes: ")
509 (fail "FAIL" "failures: ")
510 (upass "UPASS" "unexpected passes: ")
511 (xfail "XFAIL" "expected failures: ")
512 (unresolved "UNRESOLVED" "unresolved test cases: ")
513 (untested "UNTESTED" "untested test cases: ")
514 (unsupported "UNSUPPORTED" "unsupported test cases: ")
515 (error "ERROR" "errors: ")))
516
517;;; The list of important test results.
bba2d190 518(define important-result-tags
57e7f270
DH
519 '(fail upass unresolved error))
520
521;;; Display a single test result in formatted form to the given port
522(define (print-result port result name . args)
523 (let* ((tag (assq result result-tags))
524 (label (if tag (cadr tag) #f)))
525 (if label
526 (begin
527 (display label port)
528 (display ": " port)
529 (display (format-test-name name) port)
530 (if (pair? args)
531 (begin
532 (display " - arguments: " port)
533 (write args port)))
534 (newline port))
535 (error "(test-suite lib) FULL-REPORTER: unrecognized result: "
536 result))))
000ee07f
JB
537
538;;; Return a list of the form (COUNTER RESULTS), where:
539;;; - COUNTER is a reporter procedure, and
540;;; - RESULTS is a procedure taking no arguments which returns the
541;;; results seen so far by COUNTER. The return value is an alist
542;;; mapping outcome symbols (`pass', `fail', etc.) onto counts.
543(define (make-count-reporter)
57e7f270 544 (let ((counts (map (lambda (tag) (cons (car tag) 0)) result-tags)))
000ee07f 545 (list
57e7f270
DH
546 (lambda (result name . args)
547 (let ((pair (assq result counts)))
bba2d190 548 (if pair
57e7f270 549 (set-cdr! pair (+ 1 (cdr pair)))
bba2d190 550 (error "count-reporter: unexpected test result: "
57e7f270 551 (cons result (cons name args))))))
000ee07f
JB
552 (lambda ()
553 (append counts '())))))
554
555;;; Print a count reporter's results nicely. Pass this function the value
556;;; returned by a count reporter's RESULTS procedure.
57e7f270 557(define (print-counts results . port?)
bba2d190 558 (let ((port (if (pair? port?)
57e7f270
DH
559 (car port?)
560 (current-output-port))))
561 (newline port)
562 (display-line-port port "Totals for this test run:")
563 (for-each
564 (lambda (tag)
565 (let ((result (assq (car tag) results)))
566 (if result
567 (display-line-port port (caddr tag) (cdr result))
568 (display-line-port port
569 "Test suite bug: "
570 "no total available for `" (car tag) "'"))))
571 result-tags)
572 (newline port)))
000ee07f
JB
573
574;;; Return a reporter procedure which prints all results to the file
575;;; FILE, in human-readable form. FILE may be a filename, or a port.
576(define (make-log-reporter file)
577 (let ((port (if (output-port? file) file
578 (open-output-file file))))
57e7f270
DH
579 (lambda args
580 (apply print-result port args)
000ee07f
JB
581 (force-output port))))
582
087dab1c 583;;; A reporter that reports all results to the user.
57e7f270
DH
584(define (full-reporter . args)
585 (apply print-result (current-output-port) args))
087dab1c
JB
586
587;;; A reporter procedure which shows interesting results (failures,
57e7f270
DH
588;;; unexpected passes etc.) to the user.
589(define (user-reporter result name . args)
590 (if (memq result important-result-tags)
591 (apply full-reporter result name args)))
087dab1c
JB
592
593(set! default-reporter full-reporter)