/lang/check-expect/check-expect.rkt

http://github.com/dyoo/mzscheme-vm · Racket · 238 lines · 190 code · 38 blank · 10 comment · 24 complexity · a7ea74d3138ba928bf29ddcd4f82b6b6 MD5 · raw file

  1. #lang s-exp "../base.rkt"
  2. (require (for-syntax racket/base)
  3. "../location.rkt"
  4. "display-location.rkt")
  5. (provide check-expect
  6. check-within
  7. check-error
  8. run-tests)
  9. (define *tests* '())
  10. (define-for-syntax (syntax-location-values stx)
  11. (list (syntax-source stx) ;; can be path or symbol
  12. (syntax-position stx)
  13. (syntax-line stx)
  14. (syntax-column stx)
  15. (syntax-span stx)))
  16. (define-for-syntax (check-at-toplevel! who stx)
  17. (unless (eq? (syntax-local-context) 'module)
  18. (raise-syntax-error #f
  19. (format "~a: found a test that is not at the top level."
  20. who)
  21. stx)))
  22. (define-syntax (check-expect stx)
  23. (syntax-case stx ()
  24. [(_ test expected)
  25. (begin
  26. (check-at-toplevel! 'check-expect stx)
  27. (with-syntax ([stx stx]
  28. [(id offset line column span)
  29. (syntax-location-values stx)])
  30. #'(accumulate-test!
  31. (lambda ()
  32. (check-expect* 'stx
  33. (make-location 'id offset line column span)
  34. (lambda () test)
  35. (lambda () expected))))))]))
  36. (define-syntax (check-within stx)
  37. (syntax-case stx ()
  38. [(_ test expected delta)
  39. (begin
  40. (check-at-toplevel! 'check-within stx)
  41. (with-syntax ([stx stx]
  42. [(id offset line column span)
  43. (syntax-location-values stx)])
  44. #'(accumulate-test!
  45. (lambda ()
  46. (check-within* 'stx
  47. (make-location 'id offset line column span)
  48. (lambda () test)
  49. (lambda () expected)
  50. (lambda () delta))))))]))
  51. (define-syntax (check-error stx)
  52. (syntax-case stx ()
  53. [(_ test expected-msg)
  54. (begin
  55. (check-at-toplevel! 'check-error stx)
  56. (with-syntax ([stx stx]
  57. [(id offset line column span)
  58. (syntax-location-values stx)])
  59. #'(accumulate-test!
  60. (lambda ()
  61. (check-error* 'stx
  62. (make-location 'id offset line column span)
  63. (lambda () test)
  64. (lambda () expected-msg))))))]))
  65. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  66. (define (check-expect* test-datum a-loc test-thunk expected-thunk)
  67. (with-handlers ([void
  68. (lambda (exn)
  69. (printf "check-expect: ~s"
  70. (exn-message exn))
  71. (newline)
  72. (display-location test-datum a-loc)
  73. #f)])
  74. (let ([expected-value (expected-thunk)]
  75. [test-value (test-thunk)])
  76. (cond
  77. [(equal? test-value expected-value)
  78. #t]
  79. [else
  80. (printf "check-expect: actual value ~s differs from ~s, the expected value" test-value expected-value)
  81. (newline)
  82. (display-location test-datum a-loc)
  83. #f]))))
  84. (define (check-within* test-datum a-loc test-thunk expected-thunk delta-thunk)
  85. (with-handlers ([void
  86. (lambda (exn)
  87. (printf "check-within: ~s"
  88. (exn-message exn))
  89. (newline)
  90. (display-location test-datum a-loc)
  91. #f)])
  92. (with-handlers ([void
  93. (lambda (exn)
  94. (printf "check-within: ~s"
  95. (exn-message exn))
  96. (newline)
  97. (display-location test-datum a-loc)
  98. #f)])
  99. (let ([expected-value (expected-thunk)]
  100. [test-value (test-thunk)]
  101. [delta-value (delta-thunk)])
  102. (cond
  103. [(not (real? delta-value))
  104. (printf "check-within requires an inexact number for the range. ~s is not inexact.\n" delta-value)
  105. (display-location test-datum a-loc)
  106. #f]
  107. [(equal~? test-value expected-value delta-value)
  108. #t]
  109. [else
  110. (printf "check-within: actual value ~s differs from ~s, the expected value.\n" test-value expected-value)
  111. (display-location test-datum a-loc)
  112. #f])))))
  113. (define (check-error* test-datum a-loc test-thunk expected-message-thunk)
  114. (with-handlers ([void
  115. (lambda (exn)
  116. (printf "check-error: ~s"
  117. (exn-message exn))
  118. (newline)
  119. (display-location test-datum a-loc)
  120. #f)])
  121. (let ([expected-message (expected-message-thunk)])
  122. (with-handlers
  123. ([unexpected-no-error?
  124. (lambda (une)
  125. (printf "check-error expected the error ~s, but got ~s instead.\n"
  126. expected-message
  127. (unexpected-no-error-result une))
  128. (display-location test-datum a-loc)
  129. #f)]
  130. [exn:fail?
  131. (lambda (exn)
  132. (cond [(string=? (exn-message exn) expected-message)
  133. #t]
  134. [else
  135. (printf "check-error: expected the error ~s, but got ~s instead.\n"
  136. expected-message
  137. (exn-message exn))
  138. (display-location test-datum a-loc)
  139. #f]))])
  140. (let ([result (test-thunk)])
  141. (raise (make-unexpected-no-error result)))))))
  142. ;; a test is a thunk of type: (-> boolean)
  143. ;; where it returns true if the test was successful,
  144. ;; false otherwise.
  145. ;; accumulate-test!
  146. (define (accumulate-test! a-test)
  147. (set! *tests* (cons a-test *tests*)))
  148. ;; test-suffixed: number -> string
  149. (define (test-suffixed n)
  150. (case n
  151. [(0) "zero tests"]
  152. [(1) "one test"]
  153. [else (format "~a tests" n)]))
  154. ;; capitalize: string -> string
  155. (define (capitalize s)
  156. (cond [(> (string-length s) 0)
  157. (string-append (string (char-upcase (string-ref s 0)))
  158. (substring s 1))]
  159. [else
  160. s]))
  161. ;; run-tests: -> void
  162. (define (run-tests)
  163. (when (> (length *tests*) 0)
  164. ;; Run through the tests
  165. (printf "Running tests...\n")
  166. (let loop ([tests-passed 0]
  167. [tests-failed 0]
  168. [tests (reverse *tests*)])
  169. (cond
  170. [(empty? tests)
  171. ;; Report test results
  172. (cond [(= tests-passed (length *tests*))
  173. (display (case (length *tests*)
  174. [(1) "The test passed!"]
  175. [(2) "Both tests passed!"]
  176. [else
  177. (format "All ~a tests passed!"
  178. (length *tests*))]))
  179. (newline)]
  180. [else
  181. (printf "Ran ~a.\n"
  182. (test-suffixed (length *tests*)))
  183. (printf "~a passed.\n"
  184. (capitalize (test-suffixed tests-passed)))
  185. (printf "~a failed.\n"
  186. (capitalize (test-suffixed tests-failed)))])
  187. (set! *tests* '())]
  188. [else
  189. (let* ([test-thunk (first tests)]
  190. [test-result (test-thunk)])
  191. (cond
  192. [test-result
  193. (loop (add1 tests-passed)
  194. tests-failed
  195. (rest tests))]
  196. [else
  197. (loop tests-passed
  198. (add1 tests-failed)
  199. (rest tests))]))]))))
  200. (define-struct unexpected-no-error (result))