testing.scm 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. ;; Copyright 1996, 1997, 1998 Per Bothner.
  2. ;;
  3. ;; Usage:
  4. ;; (load "testing.scm")
  5. ;; (test-init "Miscellaneous" 2)
  6. ;; (test '(3 4 5 6) (lambda x x) 3 4 5 6)
  7. ;; (test '(a b c . d) 'dot '(a . (b . (c . d))))
  8. ;; (test-report)
  9. ;;
  10. ;; test-init: The first argument is the name of the test.
  11. ;; A log is written to (string-append NAME ".log").
  12. ;; The second (optional) argument is the total number of tests;
  13. ;; at the end an error is written if the actual count does not match.
  14. ;;
  15. ;; test: The first argument is the expected result.
  16. ;; The second argument is either a procecure applied to the remaining
  17. ;; arguments; or it is a symbol (used when reporting), in which case
  18. ;; the third argument is matched against the first.
  19. ;; The resulting values are matched using equal?.
  20. ;;
  21. ;; section: You can divide your tests into "sections" with the section
  22. ;; procedure. The arguments of the previous section are displayed if any
  23. ;; errors are reported.
  24. ;;
  25. ;; test-report: Called at end to print a summary.
  26. ;;
  27. ;; fail-expected: If non-false, if means the following test is
  28. ;; expected to fail. The actual value should be string explaining
  29. ;; the failure. For example:
  30. ;; (set! fail-expected "sqrt of negative number not supported")
  31. ;; (test "+2.0i" number->string (sqrt -4))
  32. ;;
  33. ;; verbose: If true, all tests are written to standard output,
  34. ;; not just to the log file.
  35. (define verbose #f)
  36. (define pass-count 0)
  37. (define fail-count 0)
  38. (define xfail-count 0)
  39. (define xpass-count 0)
  40. (define *log-file* #f)
  41. (define test-name "<unknown>")
  42. ;;; Set this (to an explanatory string) if the next test is known to fail.
  43. (define-variable fail-expected #f)
  44. ;;; The current section.
  45. (define cur-section #f)
  46. ;;; The section when we last emitted a message.
  47. (define last-section #f)
  48. (define total-expected-count #f)
  49. (define (test-init name #!optional total-count)
  50. (set! test-name name)
  51. (set! total-expected-count total-count)
  52. (set! *log-file* (open-output-file (string-append name ".log")))
  53. (display (string-append "%%%% Starting test " name) *log-file*)
  54. (newline *log-file*)
  55. (display (string-append "%%%% Starting test " name
  56. " (Writing full log to \"" name ".log\")"))
  57. (newline)
  58. (set! pass-count 0)
  59. (set! xpass-count 0)
  60. (set! fail-count 0)
  61. (set! xfail-count 0))
  62. (define (display-section port)
  63. (display "SECTION" port)
  64. (do ((l cur-section (cdr l)))
  65. ((null? l) #f)
  66. (write-char #\Space port)
  67. (display (car l) port))
  68. (newline port))
  69. (define (maybe-report-section)
  70. (and cur-section *log-file* (not (eq? cur-section last-section))
  71. (begin (display-section (current-output-port))
  72. (set! last-section cur-section))))
  73. (define (section . args)
  74. (set! cur-section args)
  75. (display-section (or *log-file* (current-output-port)))
  76. (set! last-section #f))
  77. (define record-error (lambda (e) (set! errs (cons (list cur-section e) errs))))
  78. (define (report-pass port fun args res)
  79. (display (if fail-expected "XPASS:" "PASS: ") port)
  80. (write (cons fun args) port)
  81. (display " ==> " port)
  82. (write res port)
  83. (newline port))
  84. (define (report-fail port fun args res expect)
  85. (display (cond ((string? fail-expected)
  86. (string-append "XFAIL (" fail-expected "): "))
  87. (fail-expected "XFAIL: ")
  88. (else "FAIL: "))
  89. port)
  90. (write (cons fun args) port)
  91. (display " ==> " port)
  92. (write res port)
  93. (display " BUT EXPECTED " port)
  94. (write expect port)
  95. (newline port))
  96. #|
  97. (define-syntax test
  98. (syntax-rules ()
  99. ((test expect fun . args)
  100. (cons #t (test1 (source-filename) (source-line) expect fun . args)))))
  101. |#
  102. ;; test.scm redefines + in one of its tests. This causes problems when we
  103. ;; want to use '+ in the test function below. The clean (future) solution
  104. ;; would be to put this file inside a module. FIXME.
  105. (define (test expect fun #!rest args)
  106. ((lambda (res)
  107. (cond ((equal? expect res)
  108. (if fail-expected
  109. (set! xpass-count (+ xpass-count 1))
  110. (set! pass-count (+ pass-count 1)))
  111. (if *log-file*
  112. (report-pass *log-file* fun args res))
  113. (cond ((or verbose fail-expected)
  114. (maybe-report-section)
  115. (report-pass (current-output-port) fun args res))))
  116. (#t
  117. (if fail-expected
  118. (set! xfail-count (+ xfail-count 1))
  119. (set! fail-count (+ fail-count 1)))
  120. (if *log-file*
  121. (report-fail *log-file* fun args res expect))
  122. (cond ((or verbose (not fail-expected))
  123. (maybe-report-section)
  124. (report-fail (current-output-port) fun args res expect)))))
  125. (set! fail-expected #f))
  126. (if (procedure? fun)
  127. (cond-expand (kawa
  128. (try-catch
  129. (apply fun args)
  130. (ex <java.lang.Throwable>
  131. ;; (invoke ex 'printStackTrace) ;; for DEBUGGING
  132. ex)))
  133. (else
  134. (apply fun args)))
  135. (car args))))
  136. (define (report-display value)
  137. (display value)
  138. (and *log-file* (display value *log-file*)))
  139. (define (report-newline)
  140. (newline)
  141. (and *log-file* (newline *log-file*)))
  142. (define (report1 value string)
  143. (cond ((> value 0)
  144. (report-display string)
  145. (report-display value)
  146. (report-newline))))
  147. (define (test-report)
  148. (report1 pass-count "# of expected passes ")
  149. (report1 xfail-count "# of expected failures ")
  150. (report1 xpass-count "# of unexpected successes ")
  151. (report1 fail-count "# of unexpected failures ")
  152. (if (and total-expected-count
  153. (not (= total-expected-count
  154. (+ pass-count xfail-count xpass-count fail-count))))
  155. (begin
  156. (report-display "*** Total number of tests should be: ")
  157. (report-display total-expected-count)
  158. (report-display ". ***")
  159. (report-newline)
  160. (report-display "*** Discrepancy indicates testsuite error or exceptions. ***")
  161. (report-newline)))
  162. (cond (*log-file*
  163. (close-output-port *log-file*)
  164. (set! *log-file* #f))))