test-suite.scm 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Support for writing and running test suites
  3. (define-record-type test-suite :test-suite
  4. (really-make-test-suite name test-cases)
  5. test-suite?
  6. (name test-suite-name)
  7. (test-cases test-suite-cases set-test-suite-cases!))
  8. (define-record-discloser :test-suite
  9. (lambda (t)
  10. (list 'test-suite
  11. (test-suite-name t))))
  12. (define-record-type compound-test-suite :compound-test-suite
  13. (make-compound-test-suite name components)
  14. compound-test-suite?
  15. (name compound-test-suite-name)
  16. (components compound-test-suite-components))
  17. (define-record-discloser :compound-test-suite
  18. (lambda (t)
  19. (list 'compound-test-suite
  20. (compound-test-suite-name t)
  21. (compound-test-suite-components t))))
  22. (define (make-test-suite name)
  23. (really-make-test-suite name '()))
  24. (define-syntax define-test-suite
  25. (syntax-rules ()
  26. ((define-test-suite ?name)
  27. (define ?name (make-test-suite '?name)))
  28. ((define-test-suite ?name (?comp0 ...))
  29. (define ?name (make-compound-test-suite '?name (list ?comp0 ...))))))
  30. (define (add-test-case! suite case)
  31. (let ((same-name?
  32. (lambda (a-case)
  33. (eq? (test-case-name case) (test-case-name a-case)))))
  34. (cond
  35. ((any same-name?
  36. (test-suite-cases suite))
  37. => (lambda (duplicate)
  38. (warn "duplicate test case, removing old one" duplicate)
  39. (set-test-suite-cases! suite
  40. (delete same-name? (test-suite-cases suite)))))))
  41. (set-test-suite-cases! suite
  42. (cons case (test-suite-cases suite))))
  43. (define (zap-test-suite! suite)
  44. (set-test-suite-cases! suite '()))
  45. (define-record-type test-case :test-case
  46. (make-test-case name suite thunk)
  47. test-case?
  48. (name test-case-name)
  49. (suite test-case-suite)
  50. (thunk test-case-thunk))
  51. (define-record-discloser :test-case
  52. (lambda (c)
  53. (list 'test-case (test-case-name c))))
  54. (define-syntax define-test-case
  55. (syntax-rules ()
  56. ((define-test-case ?name ?suite ?body0 ?body1 ...)
  57. (let ((suite ?suite))
  58. (add-test-case! suite
  59. (make-test-case '?name
  60. suite
  61. (lambda ()
  62. ?body0 ?body1 ...)))))))
  63. (define-syntax define-test-cases
  64. (syntax-rules ()
  65. ((define-test-cases ?suite
  66. (?name ?body0 ?body1 ...) ...)
  67. (begin
  68. (define-test-case ?name ?suite ?body0 ?body1 ...) ...))))
  69. (define-syntax check
  70. (syntax-rules (=> not)
  71. ((check ?actual)
  72. (check (and ?actual #t) => #t))
  73. ((check ?actual => ?expected)
  74. (check ?actual (=> equal?) ?expected))
  75. ((check ?actual (=> ?equal?) ?expected)
  76. (let ((expected ?expected)
  77. (equal? ?equal?))
  78. (guard
  79. (c
  80. (else
  81. (register-failure!
  82. (make-check-failure (fluid $test-case)
  83. '?actual #f c '?expected expected equal?))))
  84. (let ((actual ?actual))
  85. (if (not (equal? actual expected))
  86. (register-failure!
  87. (make-check-failure (fluid $test-case)
  88. '?actual actual #f '?expected expected equal?)))))))))
  89. (define (always-true _)
  90. #t)
  91. (define-syntax check-exception
  92. (syntax-rules (=>)
  93. ((check-exception ?actual)
  94. (check-exception ?actual => always-true))
  95. ((check-exception ?actual => ?predicate)
  96. (let ((predicate ?predicate))
  97. (guard
  98. (c
  99. ((not (predicate c))
  100. (register-failure!
  101. (make-check-exception-failure (fluid $test-case)
  102. '?actual #f c predicate)))
  103. (else (values)))
  104. (let ((actual ?actual))
  105. (register-failure!
  106. (make-check-exception-failure (fluid $test-case)
  107. '?actual actual #f predicate))))))))
  108. ; special case: inexact
  109. (define (=within tolerance)
  110. (lambda (z1 z2)
  111. (< (magnitude (- z2 z1)) tolerance)))
  112. (define $test-case (make-fluid #f))
  113. (define $failures (make-fluid #f))
  114. (define (register-failure! failure)
  115. (let ((cell (fluid $failures)))
  116. (cell-set! cell
  117. (cons failure (cell-ref cell)))))
  118. (define-record-type check-failure :check-failure
  119. (make-check-failure test-case
  120. actual-expr actual-val actual-condition expected-expr expected-val
  121. equal?-proc)
  122. check-failure?
  123. (test-case check-failure-test-case)
  124. (actual-expr check-failure-actual-expr)
  125. (actual-val check-failure-actual-val)
  126. ;; may be #f
  127. (actual-condition check-failure-actual-condition)
  128. (expected-expr check-failure-expected-expr)
  129. (expected-val check-failure-expected-val)
  130. (equal?-proc check-failure-equal?-proc))
  131. (define-record-discloser :check-failure
  132. (lambda (f)
  133. (list 'check-failure
  134. (check-failure-test-case f)
  135. (list 'actual
  136. (check-failure-actual-expr f)
  137. (or (check-failure-actual-condition f)
  138. (check-failure-actual-val f)))
  139. (list 'expected
  140. (check-failure-expected-expr f)
  141. (check-failure-expected-val f))
  142. (check-failure-equal?-proc f))))
  143. (define-record-type check-exception-failure :check-exception-failure
  144. (make-check-exception-failure test-case
  145. actual-expr actual-val actual-condition predicate)
  146. check-exception-failure?
  147. (test-case check-exception-failure-test-case)
  148. (actual-expr check-exception-failure-actual-expr)
  149. (actual-val check-exception-failure-actual-val)
  150. ;; may be #f
  151. (actual-condition check-exception-failure-actual-condition)
  152. (predicate check-exception-failure-predicate))
  153. (define-record-discloser :check-exception-failure
  154. (lambda (f)
  155. (list 'check-exception-failure
  156. (check-exception-failure-test-case f)
  157. (list 'actual
  158. (check-exception-failure-actual-expr f)
  159. (or (check-exception-failure-actual-condition f)
  160. (check-exception-failure-actual-val f)))
  161. (check-exception-failure-predicate f))))
  162. (define (run-test-suite suite)
  163. (let ((p (current-error-port))
  164. (cell (make-cell '())))
  165. (let-fluid
  166. $failures cell
  167. (lambda ()
  168. (let recur ((suite suite))
  169. (display "[" p)
  170. (cond
  171. ((test-suite? suite)
  172. (display (test-suite-name suite) p)
  173. (newline p)
  174. (for-each (lambda (case)
  175. (display " (" p)
  176. (display (test-case-name case) p)
  177. (let-fluid $test-case case
  178. (test-case-thunk case))
  179. (display ")" p)
  180. (newline p))
  181. (reverse (test-suite-cases suite))))
  182. ((compound-test-suite? suite)
  183. (display (compound-test-suite-name suite) p)
  184. (newline p)
  185. (for-each recur (compound-test-suite-components suite))))
  186. (display "]" p)
  187. (newline p) (newline p))))
  188. (let ((failures (reverse (cell-ref cell))))
  189. (if (null? failures)
  190. (begin
  191. (display "ALL TESTS SUCCEDED" p)
  192. (newline p))
  193. (begin
  194. (display "FAILURES:" p)
  195. (newline p)
  196. (for-each report-failure failures)))
  197. failures)))
  198. (define (failure-test-case f)
  199. (cond
  200. ((check-failure? f)
  201. (check-failure-test-case f))
  202. ((check-exception-failure? f)
  203. (check-exception-failure-test-case f))))
  204. (define (report-failure f)
  205. (let ((p (current-error-port)))
  206. (let* ((cas (failure-test-case f))
  207. (suite (test-case-suite cas)))
  208. (display "Test case " p)
  209. (display (test-case-name cas) p)
  210. (display " [" p)
  211. (display (test-suite-name suite) p)
  212. (display "] FAILED:" p)
  213. (newline p)
  214. (cond
  215. ((check-failure? f)
  216. (display "From expression " p)
  217. (write (check-failure-actual-expr f) p)
  218. (display " EXPECTED value " p)
  219. (display (check-failure-expected-val f) p)
  220. (display " of " p)
  221. (write (check-failure-expected-expr f) p)
  222. (newline p)
  223. (display "INSTEAD got " p)
  224. (cond
  225. ((check-failure-actual-condition f)
  226. => (lambda (con)
  227. (display "exception with condition:" p)
  228. (display-condition con p)))
  229. (else
  230. (write (check-failure-actual-val f) p)
  231. (newline p))))
  232. ((check-exception-failure? f)
  233. (display "From expression " p)
  234. (write (check-exception-failure-actual-expr f) p)
  235. (display " EXPECTED exception" p)
  236. (let ((pred (check-exception-failure-predicate f)))
  237. (if (not (eq? always-true pred))
  238. (begin
  239. (display " with condition matching " p)
  240. (write pred p))))
  241. (newline p)
  242. (display "INSTEAD got " p)
  243. (cond
  244. ((check-exception-failure-actual-condition f)
  245. => (lambda (con)
  246. (display "exception with condition:" p)
  247. (display-condition con p)))
  248. (else
  249. (write (check-exception-failure-actual-val f) p)
  250. (newline p)))))
  251. (newline p))))