lib.scm 25 KB

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