testing.scm 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079
  1. ;; Copyright (c) 2005, 2006, 2007, 2012, 2013 Per Bothner
  2. ;; Added "full" support for Chicken, Gauche, Guile and SISC.
  3. ;; Alex Shinn, Copyright (c) 2005.
  4. ;; Modified for Scheme Spheres by Álvaro Castro-Castilla, Copyright (c) 2012.
  5. ;; Support for Guile 2 by Mark H Weaver <mhw@netris.org>, Copyright (c) 2014.
  6. ;;
  7. ;; Permission is hereby granted, free of charge, to any person
  8. ;; obtaining a copy of this software and associated documentation
  9. ;; files (the "Software"), to deal in the Software without
  10. ;; restriction, including without limitation the rights to use, copy,
  11. ;; modify, merge, publish, distribute, sublicense, and/or sell copies
  12. ;; of the Software, and to permit persons to whom the Software is
  13. ;; furnished to do so, subject to the following conditions:
  14. ;;
  15. ;; The above copyright notice and this permission notice shall be
  16. ;; included in all copies or substantial portions of the Software.
  17. ;;
  18. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  19. ;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20. ;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21. ;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  22. ;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  23. ;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  24. ;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  25. ;; SOFTWARE.
  26. (cond-expand
  27. (chicken
  28. (require-extension syntax-case))
  29. (guile-2
  30. (use-modules (srfi srfi-9)
  31. ;; In 2.0.9, srfi-34 and srfi-35 are not well integrated
  32. ;; with either Guile's native exceptions or R6RS exceptions.
  33. ;;(srfi srfi-34) (srfi srfi-35)
  34. (srfi srfi-39)))
  35. (guile
  36. (use-modules (ice-9 syncase) (srfi srfi-9)
  37. ;;(srfi srfi-34) (srfi srfi-35) - not in Guile 1.6.7
  38. (srfi srfi-39)))
  39. (sisc
  40. (require-extension (srfi 9 34 35 39)))
  41. (kawa
  42. (module-compile-options warn-undefined-variable: #t
  43. warn-invoke-unknown-method: #t)
  44. (import (scheme base)
  45. (only (kawa base) try-catch))
  46. (provide 'srfi-64)
  47. (provide 'testing)
  48. (require 'srfi-35))
  49. (gauche
  50. (define-module srfi-64)
  51. (select-module srfi-64))
  52. (else
  53. ))
  54. (cond-expand
  55. (kawa
  56. ;; Kawa's default top-level environment has test-begin built in,
  57. ;; as a magic macro that imports this library (without test-begin).
  58. ;; This puts test-begin but only test-begin in the default environment,
  59. ;; which makes normal test suites loadable without non-portable commands.
  60. ;; Therefore we need to export %test-begin, which performs the
  61. ;; functionality of test-begin without the magic import.
  62. (define-syntax %test-export
  63. (syntax-rules ()
  64. ((%test-export test-begin . other-names)
  65. (module-export %test-begin test-begin . other-names)))))
  66. (gauche
  67. (define-syntax %test-export export))
  68. (else
  69. (define-syntax %test-export
  70. (syntax-rules ()
  71. ((%test-export . names) (if #f #f))))))
  72. ;; List of exported names
  73. (%test-export
  74. test-begin ;; must be listed first, since in Kawa (at least) it is "magic".
  75. test-end test-assert test-eqv test-eq test-equal
  76. test-approximate test-assert test-error test-apply test-with-runner
  77. test-match-nth test-match-all test-match-any test-match-name
  78. test-skip test-expect-fail test-read-eval-string
  79. test-runner-group-path test-group test-group-with-cleanup
  80. test-result-ref test-result-set! test-result-clear test-result-remove
  81. test-result-kind test-passed?
  82. test-log-to-file
  83. ; Misc test-runner functions
  84. test-runner? test-runner-reset test-runner-null
  85. test-runner-simple test-runner-current test-runner-factory test-runner-get
  86. test-runner-create test-runner-test-name
  87. ;; test-runner field setter and getter functions - see %test-record-define:
  88. test-runner-pass-count test-runner-pass-count!
  89. test-runner-fail-count test-runner-fail-count!
  90. test-runner-xpass-count test-runner-xpass-count!
  91. test-runner-xfail-count test-runner-xfail-count!
  92. test-runner-skip-count test-runner-skip-count!
  93. test-runner-group-stack test-runner-group-stack!
  94. test-runner-on-test-begin test-runner-on-test-begin!
  95. test-runner-on-test-end test-runner-on-test-end!
  96. test-runner-on-group-begin test-runner-on-group-begin!
  97. test-runner-on-group-end test-runner-on-group-end!
  98. test-runner-on-final test-runner-on-final!
  99. test-runner-on-bad-count test-runner-on-bad-count!
  100. test-runner-on-bad-end-name test-runner-on-bad-end-name!
  101. test-result-alist test-result-alist!
  102. test-runner-aux-value test-runner-aux-value!
  103. ;; default/simple call-back functions, used in default test-runner,
  104. ;; but can be called to construct more complex ones.
  105. test-on-group-begin-simple test-on-group-end-simple
  106. test-on-bad-count-simple test-on-bad-end-name-simple
  107. test-on-final-simple test-on-test-end-simple
  108. test-on-final-simple)
  109. (cond-expand
  110. (srfi-9
  111. (define-syntax %test-record-define
  112. (syntax-rules ()
  113. ((%test-record-define tname alloc runner? (name index getter setter) ...)
  114. (define-record-type tname
  115. (alloc)
  116. runner?
  117. (name getter setter) ...)))))
  118. (else
  119. (define %test-runner-cookie (list "test-runner"))
  120. (define-syntax %test-record-define
  121. (syntax-rules ()
  122. ((%test-record-define tname alloc runner? (name index getter setter) ...)
  123. (begin
  124. (define (runner? obj)
  125. (and (vector? obj)
  126. (> (vector-length obj) 1)
  127. (eq (vector-ref obj 0) %test-runner-cookie)))
  128. (define (alloc)
  129. (let ((runner (make-vector 23)))
  130. (vector-set! runner 0 %test-runner-cookie)
  131. runner))
  132. (begin
  133. (define (getter runner)
  134. (vector-ref runner index)) ...)
  135. (begin
  136. (define (setter runner value)
  137. (vector-set! runner index value)) ...)))))))
  138. (%test-record-define test-runner
  139. %test-runner-alloc test-runner?
  140. ;; Cumulate count of all tests that have passed and were expected to.
  141. (pass-count 1 test-runner-pass-count test-runner-pass-count!)
  142. (fail-count 2 test-runner-fail-count test-runner-fail-count!)
  143. (xpass-count 3 test-runner-xpass-count test-runner-xpass-count!)
  144. (xfail-count 4 test-runner-xfail-count test-runner-xfail-count!)
  145. (skip-count 5 test-runner-skip-count test-runner-skip-count!)
  146. (skip-list 6 %test-runner-skip-list %test-runner-skip-list!)
  147. (fail-list 7 %test-runner-fail-list %test-runner-fail-list!)
  148. ;; Normally #t, except when in a test-apply.
  149. (run-list 8 %test-runner-run-list %test-runner-run-list!)
  150. (skip-save 9 %test-runner-skip-save %test-runner-skip-save!)
  151. (fail-save 10 %test-runner-fail-save %test-runner-fail-save!)
  152. (group-stack 11 test-runner-group-stack test-runner-group-stack!)
  153. (on-test-begin 12 test-runner-on-test-begin test-runner-on-test-begin!)
  154. (on-test-end 13 test-runner-on-test-end test-runner-on-test-end!)
  155. ;; Call-back when entering a group. Takes (runner suite-name count).
  156. (on-group-begin 14 test-runner-on-group-begin test-runner-on-group-begin!)
  157. ;; Call-back when leaving a group.
  158. (on-group-end 15 test-runner-on-group-end test-runner-on-group-end!)
  159. ;; Call-back when leaving the outermost group.
  160. (on-final 16 test-runner-on-final test-runner-on-final!)
  161. ;; Call-back when expected number of tests was wrong.
  162. (on-bad-count 17 test-runner-on-bad-count test-runner-on-bad-count!)
  163. ;; Call-back when name in test=end doesn't match test-begin.
  164. (on-bad-end-name 18 test-runner-on-bad-end-name test-runner-on-bad-end-name!)
  165. ;; Cumulate count of all tests that have been done.
  166. (total-count 19 %test-runner-total-count %test-runner-total-count!)
  167. ;; Stack (list) of (count-at-start . expected-count):
  168. (count-list 20 %test-runner-count-list %test-runner-count-list!)
  169. (result-alist 21 test-result-alist test-result-alist!)
  170. ;; Field can be used by test-runner for any purpose.
  171. ;; test-runner-simple uses it for a log file.
  172. (aux-value 22 test-runner-aux-value test-runner-aux-value!)
  173. )
  174. (define (test-runner-reset runner)
  175. (test-result-alist! runner '())
  176. (test-runner-pass-count! runner 0)
  177. (test-runner-fail-count! runner 0)
  178. (test-runner-xpass-count! runner 0)
  179. (test-runner-xfail-count! runner 0)
  180. (test-runner-skip-count! runner 0)
  181. (%test-runner-total-count! runner 0)
  182. (%test-runner-count-list! runner '())
  183. (%test-runner-run-list! runner #t)
  184. (%test-runner-skip-list! runner '())
  185. (%test-runner-fail-list! runner '())
  186. (%test-runner-skip-save! runner '())
  187. (%test-runner-fail-save! runner '())
  188. (test-runner-group-stack! runner '()))
  189. (define (test-runner-group-path runner)
  190. (reverse (test-runner-group-stack runner)))
  191. (define (%test-null-callback runner) #f)
  192. (define (test-runner-null)
  193. (let ((runner (%test-runner-alloc)))
  194. (test-runner-reset runner)
  195. (test-runner-on-group-begin! runner (lambda (runner name count) #f))
  196. (test-runner-on-group-end! runner %test-null-callback)
  197. (test-runner-on-final! runner %test-null-callback)
  198. (test-runner-on-test-begin! runner %test-null-callback)
  199. (test-runner-on-test-end! runner %test-null-callback)
  200. (test-runner-on-bad-count! runner (lambda (runner count expected) #f))
  201. (test-runner-on-bad-end-name! runner (lambda (runner begin end) #f))
  202. runner))
  203. ;; Not part of the specification. FIXME
  204. ;; Controls whether a log file is generated.
  205. (define test-log-to-file #t)
  206. (define (test-runner-simple)
  207. (let ((runner (%test-runner-alloc)))
  208. (test-runner-reset runner)
  209. (test-runner-on-group-begin! runner test-on-group-begin-simple)
  210. (test-runner-on-group-end! runner test-on-group-end-simple)
  211. (test-runner-on-final! runner test-on-final-simple)
  212. (test-runner-on-test-begin! runner test-on-test-begin-simple)
  213. (test-runner-on-test-end! runner test-on-test-end-simple)
  214. (test-runner-on-bad-count! runner test-on-bad-count-simple)
  215. (test-runner-on-bad-end-name! runner test-on-bad-end-name-simple)
  216. runner))
  217. (cond-expand
  218. (srfi-39
  219. (define test-runner-current (make-parameter #f))
  220. (define test-runner-factory (make-parameter test-runner-simple)))
  221. (else
  222. (define %test-runner-current #f)
  223. (define-syntax test-runner-current
  224. (syntax-rules ()
  225. ((test-runner-current)
  226. %test-runner-current)
  227. ((test-runner-current runner)
  228. (set! %test-runner-current runner))))
  229. (define %test-runner-factory test-runner-simple)
  230. (define-syntax test-runner-factory
  231. (syntax-rules ()
  232. ((test-runner-factory)
  233. %test-runner-factory)
  234. ((test-runner-factory runner)
  235. (set! %test-runner-factory runner))))))
  236. ;; A safer wrapper to test-runner-current.
  237. (cond-expand
  238. (kawa
  239. (define (test-runner-get) ::test-runner
  240. (let ((r (test-runner-current)))
  241. (if (not r)
  242. (error "test-runner not initialized - test-begin missing?"))
  243. r)))
  244. (else
  245. (define (test-runner-get)
  246. (let ((r (test-runner-current)))
  247. (if (not r)
  248. (cond-expand
  249. (srfi-23 (error "test-runner not initialized - test-begin missing?"))
  250. (else #t)))
  251. r))))
  252. (define (%test-specifier-matches spec runner)
  253. (spec runner))
  254. (define (test-runner-create)
  255. ((test-runner-factory)))
  256. (define (%test-any-specifier-matches list runner)
  257. (let ((result #f))
  258. (let loop ((l list))
  259. (cond ((null? l) result)
  260. (else
  261. (if (%test-specifier-matches (car l) runner)
  262. (set! result #t))
  263. (loop (cdr l)))))))
  264. ;; Returns #f, #t, or 'xfail.
  265. (define (%test-should-execute runner)
  266. (let ((run (%test-runner-run-list runner)))
  267. (cond ((or
  268. (not (or (eqv? run #t)
  269. (%test-any-specifier-matches run runner)))
  270. (%test-any-specifier-matches
  271. (%test-runner-skip-list runner)
  272. runner))
  273. (test-result-set! runner 'result-kind 'skip)
  274. #f)
  275. ((%test-any-specifier-matches
  276. (%test-runner-fail-list runner)
  277. runner)
  278. (test-result-set! runner 'result-kind 'xfail)
  279. 'xfail)
  280. (else #t))))
  281. (define (%test-begin suite-name count)
  282. (if (not (test-runner-current))
  283. (test-runner-current (test-runner-create)))
  284. (let ((runner (test-runner-current)))
  285. ((test-runner-on-group-begin runner) runner suite-name count)
  286. (%test-runner-skip-save! runner
  287. (cons (%test-runner-skip-list runner)
  288. (%test-runner-skip-save runner)))
  289. (%test-runner-fail-save! runner
  290. (cons (%test-runner-fail-list runner)
  291. (%test-runner-fail-save runner)))
  292. (%test-runner-count-list! runner
  293. (cons (cons (%test-runner-total-count runner)
  294. count)
  295. (%test-runner-count-list runner)))
  296. (test-runner-group-stack! runner (cons suite-name
  297. (test-runner-group-stack runner)))))
  298. (define-syntax test-begin
  299. (syntax-rules ()
  300. ((test-begin suite-name)
  301. (%test-begin suite-name #f))
  302. ((test-begin suite-name count)
  303. (%test-begin suite-name count))))
  304. (define (test-on-group-begin-simple runner suite-name count)
  305. (if (null? (test-runner-group-stack runner))
  306. (begin
  307. (display "%%%% Starting test ")
  308. (display suite-name)
  309. (if test-log-to-file
  310. (let* ((log-name (if (string? test-log-to-file) test-log-to-file
  311. (string-append suite-name ".log")))
  312. ;; Replace "bad" characters in log file name with #\_
  313. (fix-invalid-char
  314. (lambda (ch)
  315. (if (or (char-alphabetic? ch)
  316. (char-numeric? ch)
  317. (char=? ch #\Space)
  318. (char=? ch #\-)
  319. (char=? ch #\+)
  320. (char=? ch #\_)
  321. (char=? ch #\.)
  322. (char=? ch #\,))
  323. ch
  324. #\_)))
  325. (log-file-name
  326. (cond-expand (r7rs
  327. (string-map fix-invalid-char log-name))
  328. (else
  329. (let ((t (string-copy log-name))
  330. (tlen (string-length log-name)))
  331. (do ((i 0 (+ i 1))) ((>= i tlen) t)
  332. (string-set! t i (fix-invalid-char
  333. (string-ref t i))))))))
  334. (log-file
  335. (cond-expand (mzscheme
  336. (open-output-file log-file-name 'truncate/replace))
  337. (else (open-output-file log-file-name)))))
  338. (display "%%%% Starting test " log-file)
  339. (display suite-name log-file)
  340. (newline log-file)
  341. (test-runner-aux-value! runner log-file)
  342. (display " (Writing full log to \"")
  343. (display log-file-name)
  344. (display "\")")))
  345. (newline)))
  346. (let ((log (test-runner-aux-value runner)))
  347. (if (output-port? log)
  348. (begin
  349. (display "Group begin: " log)
  350. (display suite-name log)
  351. (newline log))))
  352. #f)
  353. (define (test-on-group-end-simple runner)
  354. (let ((log (test-runner-aux-value runner)))
  355. (if (output-port? log)
  356. (begin
  357. (display "Group end: " log)
  358. (display (car (test-runner-group-stack runner)) log)
  359. (newline log))))
  360. #f)
  361. (define (%test-on-bad-count-write runner count expected-count port)
  362. (display "*** Total number of tests was " port)
  363. (display count port)
  364. (display " but should be " port)
  365. (display expected-count port)
  366. (display ". ***" port)
  367. (newline port)
  368. (display "*** Discrepancy indicates testsuite error or exceptions. ***" port)
  369. (newline port))
  370. (define (test-on-bad-count-simple runner count expected-count)
  371. (%test-on-bad-count-write runner count expected-count (current-output-port))
  372. (let ((log (test-runner-aux-value runner)))
  373. (if (output-port? log)
  374. (%test-on-bad-count-write runner count expected-count log))))
  375. (define (test-on-bad-end-name-simple runner begin-name end-name)
  376. (let ((msg (string-append (%test-format-line runner) "test-end " begin-name
  377. " does not match test-begin " end-name)))
  378. (cond-expand
  379. (srfi-23 (error msg))
  380. (else (display msg) (newline)))))
  381. (define (%test-final-report1 value label port)
  382. (if (> value 0)
  383. (begin
  384. (display label port)
  385. (display value port)
  386. (newline port))))
  387. (define (%test-final-report-simple runner port)
  388. (%test-final-report1 (test-runner-pass-count runner)
  389. "# of expected passes " port)
  390. (%test-final-report1 (test-runner-xfail-count runner)
  391. "# of expected failures " port)
  392. (%test-final-report1 (test-runner-xpass-count runner)
  393. "# of unexpected successes " port)
  394. (%test-final-report1 (test-runner-fail-count runner)
  395. "# of unexpected failures " port)
  396. (%test-final-report1 (test-runner-skip-count runner)
  397. "# of skipped tests " port))
  398. (define (test-on-final-simple runner)
  399. (%test-final-report-simple runner (current-output-port))
  400. (let ((log (test-runner-aux-value runner)))
  401. (if (output-port? log)
  402. (%test-final-report-simple runner log))))
  403. (define (%test-format-line runner)
  404. (let* ((line-info (test-result-alist runner))
  405. (source-file (assq 'source-file line-info))
  406. (source-line (assq 'source-line line-info))
  407. (file (if source-file (cdr source-file) "")))
  408. (if source-line
  409. (string-append file ":"
  410. (number->string (cdr source-line)) ": ")
  411. "")))
  412. (define (%test-end suite-name line-info)
  413. (let* ((r (test-runner-get))
  414. (groups (test-runner-group-stack r))
  415. (line (%test-format-line r)))
  416. (test-result-alist! r line-info)
  417. (if (null? groups)
  418. (let ((msg (string-append line "test-end not in a group")))
  419. (cond-expand
  420. (srfi-23 (error msg))
  421. (else (display msg) (newline)))))
  422. (if (and suite-name (not (equal? suite-name (car groups))))
  423. ((test-runner-on-bad-end-name r) r suite-name (car groups)))
  424. (let* ((count-list (%test-runner-count-list r))
  425. (expected-count (cdar count-list))
  426. (saved-count (caar count-list))
  427. (group-count (- (%test-runner-total-count r) saved-count)))
  428. (if (and expected-count
  429. (not (= expected-count group-count)))
  430. ((test-runner-on-bad-count r) r group-count expected-count))
  431. ((test-runner-on-group-end r) r)
  432. (test-runner-group-stack! r (cdr (test-runner-group-stack r)))
  433. (%test-runner-skip-list! r (car (%test-runner-skip-save r)))
  434. (%test-runner-skip-save! r (cdr (%test-runner-skip-save r)))
  435. (%test-runner-fail-list! r (car (%test-runner-fail-save r)))
  436. (%test-runner-fail-save! r (cdr (%test-runner-fail-save r)))
  437. (%test-runner-count-list! r (cdr count-list))
  438. (cond ((null? (test-runner-group-stack r))
  439. ((test-runner-on-final r) r)
  440. (test-runner-current #f))))))
  441. (define-syntax test-group
  442. (syntax-rules ()
  443. ((test-group suite-name . body)
  444. (let ((r (test-runner-current)))
  445. ;; Ideally should also set line-number, if available.
  446. (test-result-alist! r (list (cons 'test-name suite-name)))
  447. (if (%test-should-execute r)
  448. (dynamic-wind
  449. (lambda () (test-begin suite-name))
  450. (lambda () . body)
  451. (lambda () (test-end suite-name))))))))
  452. (define-syntax test-group-with-cleanup
  453. (syntax-rules ()
  454. ((test-group-with-cleanup suite-name form cleanup-form)
  455. (test-group suite-name
  456. (dynamic-wind
  457. (lambda () #f)
  458. (lambda () form)
  459. (lambda () cleanup-form))))
  460. ((test-group-with-cleanup suite-name cleanup-form)
  461. (test-group-with-cleanup suite-name #f cleanup-form))
  462. ((test-group-with-cleanup suite-name form1 form2 form3 . rest)
  463. (test-group-with-cleanup suite-name (begin form1 form2) form3 . rest))))
  464. (define (test-on-test-begin-simple runner)
  465. (let ((log (test-runner-aux-value runner)))
  466. (if (output-port? log)
  467. (let* ((results (test-result-alist runner))
  468. (source-file (assq 'source-file results))
  469. (source-line (assq 'source-line results))
  470. (source-form (assq 'source-form results))
  471. (test-name (assq 'test-name results)))
  472. (display "Test begin:" log)
  473. (newline log)
  474. (if test-name (%test-write-result1 test-name log))
  475. (if source-file (%test-write-result1 source-file log))
  476. (if source-line (%test-write-result1 source-line log))
  477. (if source-form (%test-write-result1 source-form log))))))
  478. (define-syntax test-result-ref
  479. (syntax-rules ()
  480. ((test-result-ref runner pname)
  481. (test-result-ref runner pname #f))
  482. ((test-result-ref runner pname default)
  483. (let ((p (assq pname (test-result-alist runner))))
  484. (if p (cdr p) default)))))
  485. (define (test-on-test-end-simple runner)
  486. (let ((log (test-runner-aux-value runner))
  487. (kind (test-result-ref runner 'result-kind)))
  488. (if (memq kind '(fail xpass))
  489. (let* ((results (test-result-alist runner))
  490. (source-file (assq 'source-file results))
  491. (source-line (assq 'source-line results))
  492. (test-name (assq 'test-name results)))
  493. (if (or source-file source-line)
  494. (begin
  495. (if source-file (display (cdr source-file)))
  496. (display ":")
  497. (if source-line (display (cdr source-line)))
  498. (display ": ")))
  499. (display (if (eq? kind 'xpass) "XPASS" "FAIL"))
  500. (if test-name
  501. (begin
  502. (display " ")
  503. (display (cdr test-name))))
  504. (newline)))
  505. (if (output-port? log)
  506. (begin
  507. (display "Test end:" log)
  508. (newline log)
  509. (let loop ((list (test-result-alist runner)))
  510. (if (pair? list)
  511. (let ((pair (car list)))
  512. ;; Write out properties not written out by on-test-begin.
  513. (if (not (memq (car pair)
  514. '(test-name source-file source-line source-form)))
  515. (%test-write-result1 pair log))
  516. (loop (cdr list)))))))))
  517. (define (%test-write-result1 pair port)
  518. (display " " port)
  519. (display (car pair) port)
  520. (display ": " port)
  521. (write (cdr pair) port)
  522. (newline port))
  523. (define (test-result-set! runner pname value)
  524. (let* ((alist (test-result-alist runner))
  525. (p (assq pname alist)))
  526. (if p
  527. (set-cdr! p value)
  528. (test-result-alist! runner (cons (cons pname value) alist)))))
  529. (define (test-result-actual-value! runner value)
  530. (test-result-set! runner 'actual-value value))
  531. (define (test-result-expected-value! runner value)
  532. (test-result-set! runner 'expected-value value))
  533. (define (test-result-clear runner)
  534. (test-result-alist! runner '()))
  535. (define (test-result-remove runner pname)
  536. (let* ((alist (test-result-alist runner))
  537. (p (assq pname alist)))
  538. (if p
  539. (test-result-alist! runner
  540. (let loop ((r alist))
  541. (if (eq? r p) (cdr r)
  542. (cons (car r) (loop (cdr r)))))))))
  543. (define (test-result-kind . rest)
  544. (let ((runner (if (pair? rest) (car rest) (test-runner-current))))
  545. (test-result-ref runner 'result-kind)))
  546. (define (test-passed? . rest)
  547. (let ((runner (if (pair? rest) (car rest) (test-runner-get))))
  548. (memq (test-result-ref runner 'result-kind) '(pass xpass))))
  549. (define (%test-report-result)
  550. (let* ((r (test-runner-get))
  551. (result-kind (test-result-kind r)))
  552. (case result-kind
  553. ((pass)
  554. (test-runner-pass-count! r (+ 1 (test-runner-pass-count r))))
  555. ((fail)
  556. (test-runner-fail-count! r (+ 1 (test-runner-fail-count r))))
  557. ((xpass)
  558. (test-runner-xpass-count! r (+ 1 (test-runner-xpass-count r))))
  559. ((xfail)
  560. (test-runner-xfail-count! r (+ 1 (test-runner-xfail-count r))))
  561. (else
  562. (test-runner-skip-count! r (+ 1 (test-runner-skip-count r)))))
  563. (%test-runner-total-count! r (+ 1 (%test-runner-total-count r)))
  564. ((test-runner-on-test-end r) r)))
  565. (cond-expand
  566. (guile
  567. (define-syntax %test-evaluate-with-catch
  568. (syntax-rules ()
  569. ((%test-evaluate-with-catch test-expression)
  570. (catch #t
  571. (lambda () test-expression)
  572. (lambda (key . args)
  573. (test-result-set! (test-runner-current) 'actual-error
  574. (cons key args))
  575. #f))))))
  576. (kawa
  577. (define-syntax %test-evaluate-with-catch
  578. (syntax-rules ()
  579. ((%test-evaluate-with-catch test-expression)
  580. (try-catch test-expression
  581. (ex <java.lang.Throwable>
  582. (test-result-set! (test-runner-current) 'actual-error ex)
  583. #f))))))
  584. (srfi-34
  585. (define-syntax %test-evaluate-with-catch
  586. (syntax-rules ()
  587. ((%test-evaluate-with-catch test-expression)
  588. (guard (err (else #f)) test-expression)))))
  589. (chicken
  590. (define-syntax %test-evaluate-with-catch
  591. (syntax-rules ()
  592. ((%test-evaluate-with-catch test-expression)
  593. (condition-case test-expression (ex () #f))))))
  594. (else
  595. (define-syntax %test-evaluate-with-catch
  596. (syntax-rules ()
  597. ((%test-evaluate-with-catch test-expression)
  598. test-expression)))))
  599. (cond-expand
  600. ((or kawa mzscheme)
  601. (cond-expand
  602. (mzscheme
  603. (define-for-syntax (%test-syntax-file form)
  604. (let ((source (syntax-source form)))
  605. (cond ((string? source) file)
  606. ((path? source) (path->string source))
  607. (else #f)))))
  608. (kawa
  609. (define (%test-syntax-file form)
  610. (syntax-source form))))
  611. (define (%test-source-line2 form)
  612. (let* ((line (syntax-line form))
  613. (file (%test-syntax-file form))
  614. (line-pair (if line (list (cons 'source-line line)) '())))
  615. (cons (cons 'source-form (syntax-object->datum form))
  616. (if file (cons (cons 'source-file file) line-pair) line-pair)))))
  617. (guile-2
  618. (define (%test-source-line2 form)
  619. (let* ((src-props (syntax-source form))
  620. (file (and src-props (assq-ref src-props 'filename)))
  621. (line (and src-props (assq-ref src-props 'line)))
  622. (file-alist (if file
  623. `((source-file . ,file))
  624. '()))
  625. (line-alist (if line
  626. `((source-line . ,(+ line 1)))
  627. '())))
  628. (datum->syntax (syntax here)
  629. `((source-form . ,(syntax->datum form))
  630. ,@file-alist
  631. ,@line-alist)))))
  632. (else
  633. (define (%test-source-line2 form)
  634. '())))
  635. (define (%test-on-test-begin r)
  636. (%test-should-execute r)
  637. ((test-runner-on-test-begin r) r)
  638. (not (eq? 'skip (test-result-ref r 'result-kind))))
  639. (define (%test-on-test-end r result)
  640. (test-result-set! r 'result-kind
  641. (if (eq? (test-result-ref r 'result-kind) 'xfail)
  642. (if result 'xpass 'xfail)
  643. (if result 'pass 'fail))))
  644. (define (test-runner-test-name runner)
  645. (test-result-ref runner 'test-name ""))
  646. (define-syntax %test-comp2body
  647. (syntax-rules ()
  648. ((%test-comp2body r comp expected expr)
  649. (let ()
  650. (if (%test-on-test-begin r)
  651. (let ((exp expected))
  652. (test-result-expected-value! r exp)
  653. (let ((res (%test-evaluate-with-catch expr)))
  654. (test-result-actual-value! r res)
  655. (%test-on-test-end r (comp exp res)))))
  656. (%test-report-result)))))
  657. (define (%test-approximate= error)
  658. (lambda (value expected)
  659. (let ((rval (real-part value))
  660. (ival (imag-part value))
  661. (rexp (real-part expected))
  662. (iexp (imag-part expected)))
  663. (and (>= rval (- rexp error))
  664. (>= ival (- iexp error))
  665. (<= rval (+ rexp error))
  666. (<= ival (+ iexp error))))))
  667. (define-syntax %test-comp1body
  668. (syntax-rules ()
  669. ((%test-comp1body r expr)
  670. (let ()
  671. (if (%test-on-test-begin r)
  672. (let ()
  673. (let ((res (%test-evaluate-with-catch expr)))
  674. (test-result-actual-value! r res)
  675. (%test-on-test-end r res))))
  676. (%test-report-result)))))
  677. (cond-expand
  678. ((or kawa mzscheme guile-2)
  679. ;; Should be made to work for any Scheme with syntax-case
  680. ;; However, I haven't gotten the quoting working. FIXME.
  681. (define-syntax test-end
  682. (lambda (x)
  683. (syntax-case (list x (list (syntax quote) (%test-source-line2 x))) ()
  684. (((mac suite-name) line)
  685. (syntax
  686. (%test-end suite-name line)))
  687. (((mac) line)
  688. (syntax
  689. (%test-end #f line))))))
  690. (define-syntax test-assert
  691. (lambda (x)
  692. (syntax-case (list x (list (syntax quote) (%test-source-line2 x))) ()
  693. (((mac tname expr) line)
  694. (syntax
  695. (let* ((r (test-runner-get))
  696. (name tname))
  697. (test-result-alist! r (cons (cons 'test-name tname) line))
  698. (%test-comp1body r expr))))
  699. (((mac expr) line)
  700. (syntax
  701. (let* ((r (test-runner-get)))
  702. (test-result-alist! r line)
  703. (%test-comp1body r expr)))))))
  704. (define (%test-comp2 comp x)
  705. (syntax-case (list x (list (syntax quote) (%test-source-line2 x)) comp) ()
  706. (((mac tname expected expr) line comp)
  707. (syntax
  708. (let* ((r (test-runner-get))
  709. (name tname))
  710. (test-result-alist! r (cons (cons 'test-name tname) line))
  711. (%test-comp2body r comp expected expr))))
  712. (((mac expected expr) line comp)
  713. (syntax
  714. (let* ((r (test-runner-get)))
  715. (test-result-alist! r line)
  716. (%test-comp2body r comp expected expr))))))
  717. (define-syntax test-eqv
  718. (lambda (x) (%test-comp2 (syntax eqv?) x)))
  719. (define-syntax test-eq
  720. (lambda (x) (%test-comp2 (syntax eq?) x)))
  721. (define-syntax test-equal
  722. (lambda (x) (%test-comp2 (syntax equal?) x)))
  723. (define-syntax test-approximate ;; FIXME - needed for non-Kawa
  724. (lambda (x)
  725. (syntax-case (list x (list (syntax quote) (%test-source-line2 x))) ()
  726. (((mac tname expected expr error) line)
  727. (syntax
  728. (let* ((r (test-runner-get))
  729. (name tname))
  730. (test-result-alist! r (cons (cons 'test-name tname) line))
  731. (%test-comp2body r (%test-approximate= error) expected expr))))
  732. (((mac expected expr error) line)
  733. (syntax
  734. (let* ((r (test-runner-get)))
  735. (test-result-alist! r line)
  736. (%test-comp2body r (%test-approximate= error) expected expr))))))))
  737. (else
  738. (define-syntax test-end
  739. (syntax-rules ()
  740. ((test-end)
  741. (%test-end #f '()))
  742. ((test-end suite-name)
  743. (%test-end suite-name '()))))
  744. (define-syntax test-assert
  745. (syntax-rules ()
  746. ((test-assert tname test-expression)
  747. (let* ((r (test-runner-get))
  748. (name tname))
  749. (test-result-alist! r '((test-name . tname)))
  750. (%test-comp1body r test-expression)))
  751. ((test-assert test-expression)
  752. (let* ((r (test-runner-get)))
  753. (test-result-alist! r '())
  754. (%test-comp1body r test-expression)))))
  755. (define-syntax %test-comp2
  756. (syntax-rules ()
  757. ((%test-comp2 comp tname expected expr)
  758. (let* ((r (test-runner-get))
  759. (name tname))
  760. (test-result-alist! r (list (cons 'test-name tname)))
  761. (%test-comp2body r comp expected expr)))
  762. ((%test-comp2 comp expected expr)
  763. (let* ((r (test-runner-get)))
  764. (test-result-alist! r '())
  765. (%test-comp2body r comp expected expr)))))
  766. (define-syntax test-equal
  767. (syntax-rules ()
  768. ((test-equal . rest)
  769. (%test-comp2 equal? . rest))))
  770. (define-syntax test-eqv
  771. (syntax-rules ()
  772. ((test-eqv . rest)
  773. (%test-comp2 eqv? . rest))))
  774. (define-syntax test-eq
  775. (syntax-rules ()
  776. ((test-eq . rest)
  777. (%test-comp2 eq? . rest))))
  778. (define-syntax test-approximate
  779. (syntax-rules ()
  780. ((test-approximate tname expected expr error)
  781. (%test-comp2 (%test-approximate= error) tname expected expr))
  782. ((test-approximate expected expr error)
  783. (%test-comp2 (%test-approximate= error) expected expr))))))
  784. (cond-expand
  785. (guile
  786. (define-syntax %test-error
  787. (syntax-rules ()
  788. ((%test-error r etype expr)
  789. (cond ((%test-on-test-begin r)
  790. (let ((et etype))
  791. (test-result-set! r 'expected-error et)
  792. (%test-on-test-end r
  793. (catch #t
  794. (lambda ()
  795. (test-result-actual-value! r expr)
  796. #f)
  797. (lambda (key . args)
  798. ;; TODO: decide how to specify expected
  799. ;; error types for Guile.
  800. (test-result-set! r 'actual-error
  801. (cons key args))
  802. #t)))
  803. (%test-report-result))))))))
  804. (mzscheme
  805. (define-syntax %test-error
  806. (syntax-rules ()
  807. ((%test-error r etype expr)
  808. (%test-comp1body r (with-handlers (((lambda (h) #t) (lambda (h) #t)))
  809. (let ()
  810. (test-result-set! r 'actual-value expr)
  811. #f)))))))
  812. (chicken
  813. (define-syntax %test-error
  814. (syntax-rules ()
  815. ((%test-error r etype expr)
  816. (%test-comp1body r (condition-case expr (ex () #t)))))))
  817. (kawa
  818. (define-syntax %test-error
  819. (syntax-rules ()
  820. ((%test-error r #t expr)
  821. (cond ((%test-on-test-begin r)
  822. (test-result-set! r 'expected-error #t)
  823. (%test-on-test-end r
  824. (try-catch
  825. (let ()
  826. (test-result-actual-value! r expr)
  827. #f)
  828. (ex <java.lang.Throwable>
  829. (test-result-set! r 'actual-error ex)
  830. #t)))
  831. (%test-report-result))))
  832. ((%test-error r etype expr)
  833. (if (%test-on-test-begin r)
  834. (let ((et etype))
  835. (test-result-set! r 'expected-error et)
  836. (%test-on-test-end r
  837. (try-catch
  838. (let ()
  839. (test-result-actual-value! r expr)
  840. #f)
  841. (ex <java.lang.Throwable>
  842. (test-result-set! r 'actual-error ex)
  843. (cond ((instance? et java.lang.Class)
  844. (instance? ex et))
  845. (else #t)))))
  846. (%test-report-result)))))))
  847. ((and srfi-34 srfi-35)
  848. (define-syntax %test-error
  849. (syntax-rules ()
  850. ((%test-error r etype expr)
  851. (%test-comp1body r (guard (ex ((condition-type? etype)
  852. (and (condition? ex) (condition-has-type? ex etype)))
  853. ((procedure? etype)
  854. (etype ex))
  855. ((equal? etype #t)
  856. #t)
  857. (else #t))
  858. expr #f))))))
  859. (srfi-34
  860. (define-syntax %test-error
  861. (syntax-rules ()
  862. ((%test-error r etype expr)
  863. (%test-comp1body r (guard (ex (else #t)) expr #f))))))
  864. (else
  865. (define-syntax %test-error
  866. (syntax-rules ()
  867. ((%test-error r etype expr)
  868. (begin
  869. ((test-runner-on-test-begin r) r)
  870. (test-result-set! r 'result-kind 'skip)
  871. (%test-report-result)))))))
  872. (cond-expand
  873. ((or kawa mzscheme guile-2)
  874. (define-syntax test-error
  875. (lambda (x)
  876. (syntax-case (list x (list (syntax quote) (%test-source-line2 x))) ()
  877. (((mac tname etype expr) line)
  878. (syntax
  879. (let* ((r (test-runner-get))
  880. (name tname))
  881. (test-result-alist! r (cons (cons 'test-name tname) line))
  882. (%test-error r etype expr))))
  883. (((mac etype expr) line)
  884. (syntax
  885. (let* ((r (test-runner-get)))
  886. (test-result-alist! r line)
  887. (%test-error r etype expr))))
  888. (((mac expr) line)
  889. (syntax
  890. (let* ((r (test-runner-get)))
  891. (test-result-alist! r line)
  892. (%test-error r #t expr))))))))
  893. (else
  894. (define-syntax test-error
  895. (syntax-rules ()
  896. ((test-error name etype expr)
  897. (let ((r (test-runner-get)))
  898. (test-result-alist! r `((test-name . ,name)))
  899. (%test-error r etype expr)))
  900. ((test-error etype expr)
  901. (let ((r (test-runner-get)))
  902. (test-result-alist! r '())
  903. (%test-error r etype expr)))
  904. ((test-error expr)
  905. (let ((r (test-runner-get)))
  906. (test-result-alist! r '())
  907. (%test-error r #t expr)))))))
  908. (define-syntax test-with-runner
  909. (syntax-rules ()
  910. ((test-with-runner runner form ...)
  911. (let ((saved-runner (test-runner-current)))
  912. (dynamic-wind
  913. (lambda () (test-runner-current runner))
  914. (lambda () form ...)
  915. (lambda () (test-runner-current saved-runner)))))))
  916. (define (test-apply first . rest)
  917. (if (test-runner? first)
  918. (test-with-runner first (apply test-apply rest))
  919. (let ((r (test-runner-current)))
  920. (if r
  921. (let ((run-list (%test-runner-run-list r)))
  922. (cond ((null? rest)
  923. (%test-runner-run-list! r (reverse run-list))
  924. (first)) ;; actually apply procedure thunk
  925. (else
  926. (%test-runner-run-list!
  927. r
  928. (if (eq? run-list #t) (list first) (cons first run-list)))
  929. (apply test-apply rest)
  930. (%test-runner-run-list! r run-list))))
  931. (let ((r (test-runner-create)))
  932. (test-with-runner r (apply test-apply first rest))
  933. ((test-runner-on-final r) r))))))
  934. ;;; Predicates
  935. (define (%test-match-nth n count)
  936. (let ((i 0))
  937. (lambda (runner)
  938. (set! i (+ i 1))
  939. (and (>= i n) (< i (+ n count))))))
  940. (define-syntax test-match-nth
  941. (syntax-rules ()
  942. ((test-match-nth n)
  943. (test-match-nth n 1))
  944. ((test-match-nth n count)
  945. (%test-match-nth n count))))
  946. (define (%test-match-all . pred-list)
  947. (lambda (runner)
  948. (let ((result #t))
  949. (let loop ((l pred-list))
  950. (if (null? l)
  951. result
  952. (begin
  953. (if (not ((car l) runner))
  954. (set! result #f))
  955. (loop (cdr l))))))))
  956. (define-syntax test-match-all
  957. (syntax-rules ()
  958. ((test-match-all pred ...)
  959. (%test-match-all (%test-as-specifier pred) ...))))
  960. (define (%test-match-any . pred-list)
  961. (lambda (runner)
  962. (let ((result #f))
  963. (let loop ((l pred-list))
  964. (if (null? l)
  965. result
  966. (begin
  967. (if ((car l) runner)
  968. (set! result #t))
  969. (loop (cdr l))))))))
  970. (define-syntax test-match-any
  971. (syntax-rules ()
  972. ((test-match-any pred ...)
  973. (%test-match-any (%test-as-specifier pred) ...))))
  974. ;; Coerce to a predicate function:
  975. (define (%test-as-specifier specifier)
  976. (cond ((procedure? specifier) specifier)
  977. ((integer? specifier) (test-match-nth 1 specifier))
  978. ((string? specifier) (test-match-name specifier))
  979. (else
  980. (error "not a valid test specifier"))))
  981. (define-syntax test-skip
  982. (syntax-rules ()
  983. ((test-skip pred ...)
  984. (let ((runner (test-runner-get)))
  985. (%test-runner-skip-list! runner
  986. (cons (test-match-all (%test-as-specifier pred) ...)
  987. (%test-runner-skip-list runner)))))))
  988. (define-syntax test-expect-fail
  989. (syntax-rules ()
  990. ((test-expect-fail pred ...)
  991. (let ((runner (test-runner-get)))
  992. (%test-runner-fail-list! runner
  993. (cons (test-match-all (%test-as-specifier pred) ...)
  994. (%test-runner-fail-list runner)))))))
  995. (define (test-match-name name)
  996. (lambda (runner)
  997. (equal? name (test-runner-test-name runner))))
  998. (define (test-read-eval-string string)
  999. (let* ((port (open-input-string string))
  1000. (form (read port)))
  1001. (if (eof-object? (read-char port))
  1002. (cond-expand
  1003. (guile (eval form (current-module)))
  1004. (gauche (eval form ((with-module gauche.internal vm-current-module))))
  1005. (else (eval form)))
  1006. (cond-expand
  1007. (srfi-23 (error "(not at eof)"))
  1008. (else "error")))))