Revision e02be919
| b/gnuradio-core/src/guile/gnuradio/test-suite/guile-test | ||
|---|---|---|
| 1 |
#!../libguile/guile \ |
|
| 2 |
-e main -s |
|
| 3 |
!# |
|
| 4 |
|
|
| 5 |
;;;; guile-test --- run the Guile test suite |
|
| 6 |
;;;; Jim Blandy <ji[email protected]> --- May 1999 |
|
| 7 |
;;;; |
|
| 8 |
;;;; Copyright (C) 1999, 2001, 2006 Free Software Foundation, Inc. |
|
| 9 |
;;;; |
|
| 10 |
;;;; This program is free software; you can redistribute it and/or modify |
|
| 11 |
;;;; it under the terms of the GNU General Public License as published by |
|
| 12 |
;;;; the Free Software Foundation; either version 2, or (at your option) |
|
| 13 |
;;;; any later version. |
|
| 14 |
;;;; |
|
| 15 |
;;;; This program is distributed in the hope that it will be useful, |
|
| 16 |
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 17 |
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 18 |
;;;; GNU General Public License for more details. |
|
| 19 |
;;;; |
|
| 20 |
;;;; You should have received a copy of the GNU General Public License |
|
| 21 |
;;;; along with this software; see the file COPYING. If not, write to |
|
| 22 |
;;;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
| 23 |
;;;; Boston, MA 02110-1301 USA |
|
| 24 |
|
|
| 25 |
|
|
| 26 |
;;;; Usage: [guile -e main -s] guile-test [OPTIONS] [TEST ...] |
|
| 27 |
;;;; |
|
| 28 |
;;;; Run tests from the Guile test suite. Report failures and |
|
| 29 |
;;;; unexpected passes to the standard output, along with a summary of |
|
| 30 |
;;;; all the results. Record each reported test outcome in the log |
|
| 31 |
;;;; file, `guile.log'. The exit status is #f if any of the tests |
|
| 32 |
;;;; fail or pass unexpectedly. |
|
| 33 |
;;;; |
|
| 34 |
;;;; Normally, guile-test scans the test directory, and executes all |
|
| 35 |
;;;; files whose names end in `.test'. (It assumes they contain |
|
| 36 |
;;;; Scheme code.) However, you can have it execute specific tests by |
|
| 37 |
;;;; listing their filenames on the command line. |
|
| 38 |
;;;; |
|
| 39 |
;;;; The option `--test-suite' can be given to specify the test |
|
| 40 |
;;;; directory. If no such option is given, the test directory is |
|
| 41 |
;;;; taken from the environment variable TEST_SUITE_DIR (if defined), |
|
| 42 |
;;;; otherwise a default directory that is hardcoded in this file is |
|
| 43 |
;;;; used (see "Installation" below). |
|
| 44 |
;;;; |
|
| 45 |
;;;; If present, the `--log-file LOG' option tells `guile-test' to put |
|
| 46 |
;;;; the log output in a file named LOG. |
|
| 47 |
;;;; |
|
| 48 |
;;;; If present, the `--debug' option will enable a debugging mode. |
|
| 49 |
;;;; |
|
| 50 |
;;;; If present, the `--flag-unresolved' option will cause guile-test |
|
| 51 |
;;;; to exit with failure status if any tests are UNRESOLVED. |
|
| 52 |
;;;; |
|
| 53 |
;;;; |
|
| 54 |
;;;; Installation: |
|
| 55 |
;;;; |
|
| 56 |
;;;; If you change the #! line at the top of this script to point at |
|
| 57 |
;;;; the Guile interpreter you want to test, you can call this script |
|
| 58 |
;;;; as an executable instead of having to pass it as a parameter to |
|
| 59 |
;;;; guile via "guile -e main -s guile-test". Further, you can edit |
|
| 60 |
;;;; the definition of default-test-suite to point to the parent |
|
| 61 |
;;;; directory of the `tests' tree, which makes it unnecessary to set |
|
| 62 |
;;;; the environment variable `TEST_SUITE_DIR'. |
|
| 63 |
;;;; |
|
| 64 |
;;;; |
|
| 65 |
;;;; Shortcomings: |
|
| 66 |
;;;; |
|
| 67 |
;;;; At the moment, due to a simple-minded implementation, test files |
|
| 68 |
;;;; must live in the test directory, and you must specify their names |
|
| 69 |
;;;; relative to the top of the test directory. If you want to send |
|
| 70 |
;;;; me a patch that fixes this, but still leaves sane test names in |
|
| 71 |
;;;; the log file, that would be great. At the moment, all the tests |
|
| 72 |
;;;; I care about are in the test directory, though. |
|
| 73 |
;;;; |
|
| 74 |
;;;; It would be nice if you could specify the Guile interpreter you |
|
| 75 |
;;;; want to test on the command line. As it stands, if you want to |
|
| 76 |
;;;; change which Guile interpreter you're testing, you need to edit |
|
| 77 |
;;;; the #! line at the top of this file, which is stupid. |
|
| 78 |
|
|
| 79 |
(define (main . args) |
|
| 80 |
(let ((module (resolve-module '(test-suite guile-test)))) |
|
| 81 |
(apply (module-ref module 'main) args))) |
|
| 82 |
|
|
| 83 |
(define-module (test-suite guile-test) |
|
| 84 |
:use-module (test-suite lib) |
|
| 85 |
:use-module (ice-9 getopt-long) |
|
| 86 |
:use-module (ice-9 and-let-star) |
|
| 87 |
:use-module (ice-9 rdelim) |
|
| 88 |
:export (main data-file-name test-file-name)) |
|
| 89 |
|
|
| 90 |
|
|
| 91 |
;;; User configurable settings: |
|
| 92 |
(define default-test-suite |
|
| 93 |
(string-append (getenv "HOME") "/bogus-path/test-suite")) |
|
| 94 |
|
|
| 95 |
|
|
| 96 |
;;; Variables that will receive their actual values later. |
|
| 97 |
(define test-suite default-test-suite) |
|
| 98 |
|
|
| 99 |
(define tmp-dir #f) |
|
| 100 |
|
|
| 101 |
|
|
| 102 |
;;; General utilities, that probably should be in a library somewhere. |
|
| 103 |
|
|
| 104 |
;;; Enable debugging |
|
| 105 |
(define (enable-debug-mode) |
|
| 106 |
(write-line %load-path) |
|
| 107 |
(set! %load-verbosely #t) |
|
| 108 |
(debug-enable 'backtrace 'debug)) |
|
| 109 |
|
|
| 110 |
;;; Traverse the directory tree at ROOT, applying F to the name of |
|
| 111 |
;;; each file in the tree, including ROOT itself. For a subdirectory |
|
| 112 |
;;; SUB, if (F SUB) is true, we recurse into SUB. Do not follow |
|
| 113 |
;;; symlinks. |
|
| 114 |
(define (for-each-file f root) |
|
| 115 |
|
|
| 116 |
;; A "hard directory" is a path that denotes a directory and is not a |
|
| 117 |
;; symlink. |
|
| 118 |
(define (file-is-hard-directory? filename) |
|
| 119 |
(eq? (stat:type (lstat filename)) 'directory)) |
|
| 120 |
|
|
| 121 |
(let visit ((root root)) |
|
| 122 |
(let ((should-recur (f root))) |
|
| 123 |
(if (and should-recur (file-is-hard-directory? root)) |
|
| 124 |
(let ((dir (opendir root))) |
|
| 125 |
(let loop () |
|
| 126 |
(let ((entry (readdir dir))) |
|
| 127 |
(cond |
|
| 128 |
((eof-object? entry) #f) |
|
| 129 |
((or (string=? entry ".") |
|
| 130 |
(string=? entry "..") |
|
| 131 |
(string=? entry "CVS") |
|
| 132 |
(string=? entry "RCS")) |
|
| 133 |
(loop)) |
|
| 134 |
(else |
|
| 135 |
(visit (string-append root "/" entry)) |
|
| 136 |
(loop)))))))))) |
|
| 137 |
|
|
| 138 |
|
|
| 139 |
;;; The test driver. |
|
| 140 |
|
|
| 141 |
|
|
| 142 |
;;; Localizing test files and temporary data files. |
|
| 143 |
|
|
| 144 |
(define (data-file-name filename) |
|
| 145 |
(in-vicinity tmp-dir filename)) |
|
| 146 |
|
|
| 147 |
(define (test-file-name test) |
|
| 148 |
(in-vicinity test-suite test)) |
|
| 149 |
|
|
| 150 |
;;; Return a list of all the test files in the test tree. |
|
| 151 |
(define (enumerate-tests test-dir) |
|
| 152 |
(let ((root-len (+ 1 (string-length test-dir))) |
|
| 153 |
(tests '())) |
|
| 154 |
(for-each-file (lambda (file) |
|
| 155 |
(if (has-suffix? file ".test") |
|
| 156 |
(let ((short-name |
|
| 157 |
(substring file root-len))) |
|
| 158 |
(set! tests (cons short-name tests)))) |
|
| 159 |
#t) |
|
| 160 |
test-dir) |
|
| 161 |
|
|
| 162 |
;; for-each-file presents the files in whatever order it finds |
|
| 163 |
;; them in the directory. We sort them here, so they'll always |
|
| 164 |
;; appear in the same order. This makes it easier to compare test |
|
| 165 |
;; log files mechanically. |
|
| 166 |
(sort tests string<?))) |
|
| 167 |
|
|
| 168 |
(define (main args) |
|
| 169 |
(let ((options (getopt-long args |
|
| 170 |
`((test-suite |
|
| 171 |
(single-char #\t) |
|
| 172 |
(value #t)) |
|
| 173 |
(flag-unresolved |
|
| 174 |
(single-char #\u)) |
|
| 175 |
(log-file |
|
| 176 |
(single-char #\l) |
|
| 177 |
(value #t)) |
|
| 178 |
(debug |
|
| 179 |
(single-char #\d)))))) |
|
| 180 |
(define (opt tag default) |
|
| 181 |
(let ((pair (assq tag options))) |
|
| 182 |
(if pair (cdr pair) default))) |
|
| 183 |
|
|
| 184 |
(if (opt 'debug #f) |
|
| 185 |
(enable-debug-mode)) |
|
| 186 |
|
|
| 187 |
(set! test-suite |
|
| 188 |
(or (opt 'test-suite #f) |
|
| 189 |
(getenv "TEST_SUITE_DIR") |
|
| 190 |
default-test-suite)) |
|
| 191 |
|
|
| 192 |
;; directory where temporary files are created. |
|
| 193 |
;; when run from "make check", this must be under the build-dir, |
|
| 194 |
;; not the src-dir. |
|
| 195 |
(set! tmp-dir (getcwd)) |
|
| 196 |
|
|
| 197 |
(let* ((tests |
|
| 198 |
(let ((foo (opt '() '()))) |
|
| 199 |
(if (null? foo) |
|
| 200 |
(enumerate-tests test-suite) |
|
| 201 |
foo))) |
|
| 202 |
(log-file |
|
| 203 |
(opt 'log-file "guile.log"))) |
|
| 204 |
|
|
| 205 |
;; Open the log file. |
|
| 206 |
(let ((log-port (open-output-file log-file))) |
|
| 207 |
|
|
| 208 |
;; Register some reporters. |
|
| 209 |
(let ((global-pass #t) |
|
| 210 |
(counter (make-count-reporter))) |
|
| 211 |
(register-reporter (car counter)) |
|
| 212 |
(register-reporter (make-log-reporter log-port)) |
|
| 213 |
(register-reporter user-reporter) |
|
| 214 |
(register-reporter (lambda results |
|
| 215 |
(case (car results) |
|
| 216 |
((unresolved) |
|
| 217 |
(and (opt 'flag-unresolved #f) |
|
| 218 |
(set! global-pass #f))) |
|
| 219 |
((fail upass error) |
|
| 220 |
(set! global-pass #f))))) |
|
| 221 |
|
|
| 222 |
;; Run the tests. |
|
| 223 |
(for-each (lambda (test) |
|
| 224 |
(display (string-append "Running " test "\n")) |
|
| 225 |
(with-test-prefix test |
|
| 226 |
(load (test-file-name test)))) |
|
| 227 |
tests) |
|
| 228 |
|
|
| 229 |
;; Display the final counts, both to the user and in the log |
|
| 230 |
;; file. |
|
| 231 |
(let ((counts ((cadr counter)))) |
|
| 232 |
(print-counts counts) |
|
| 233 |
(print-counts counts log-port)) |
|
| 234 |
|
|
| 235 |
(close-port log-port) |
|
| 236 |
(quit global-pass)))))) |
|
| 237 |
|
|
| 238 |
|
|
| 239 |
;;; Local Variables: |
|
| 240 |
;;; mode: scheme |
|
| 241 |
;;; End: |
|
| b/gnuradio-core/src/guile/gnuradio/test-suite/lib.scm | ||
|---|---|---|
| 1 |
;;;; test-suite/lib.scm --- generic support for testing |
|
| 2 |
;;;; Copyright (C) 1999, 2000, 2001, 2004, 2006, 2007 Free Software Foundation, Inc. |
|
| 3 |
;;;; |
|
| 4 |
;;;; This program is free software; you can redistribute it and/or modify |
|
| 5 |
;;;; it under the terms of the GNU General Public License as published by |
|
| 6 |
;;;; the Free Software Foundation; either version 2, or (at your option) |
|
| 7 |
;;;; any later version. |
|
| 8 |
;;;; |
|
| 9 |
;;;; This program is distributed in the hope that it will be useful, |
|
| 10 |
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 11 |
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 12 |
;;;; GNU General Public License for more details. |
|
| 13 |
;;;; |
|
| 14 |
;;;; You should have received a copy of the GNU General Public License |
|
| 15 |
;;;; along with this software; see the file COPYING. If not, write to |
|
| 16 |
;;;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
| 17 |
;;;; Boston, MA 02110-1301 USA |
|
| 18 |
|
|
| 19 |
(define-module (test-suite lib) |
|
| 20 |
:use-module (ice-9 stack-catch) |
|
| 21 |
:use-module (ice-9 regex) |
|
| 22 |
:export ( |
|
| 23 |
|
|
| 24 |
;; Exceptions which are commonly being tested for. |
|
| 25 |
exception:bad-variable |
|
| 26 |
exception:missing-expression |
|
| 27 |
exception:out-of-range exception:unbound-var |
|
| 28 |
exception:used-before-defined |
|
| 29 |
exception:wrong-num-args exception:wrong-type-arg |
|
| 30 |
exception:numerical-overflow |
|
| 31 |
exception:struct-set!-denied |
|
| 32 |
exception:system-error |
|
| 33 |
exception:miscellaneous-error |
|
| 34 |
exception:string-contains-nul |
|
| 35 |
|
|
| 36 |
;; Reporting passes and failures. |
|
| 37 |
run-test |
|
| 38 |
pass-if expect-fail |
|
| 39 |
pass-if-exception expect-fail-exception |
|
| 40 |
|
|
| 41 |
;; Naming groups of tests in a regular fashion. |
|
| 42 |
with-test-prefix with-test-prefix* current-test-prefix |
|
| 43 |
format-test-name |
|
| 44 |
|
|
| 45 |
;; Using the debugging evaluator. |
|
| 46 |
with-debugging-evaluator with-debugging-evaluator* |
|
| 47 |
|
|
| 48 |
;; Reporting results in various ways. |
|
| 49 |
register-reporter unregister-reporter reporter-registered? |
|
| 50 |
make-count-reporter print-counts |
|
| 51 |
make-log-reporter |
|
| 52 |
full-reporter |
|
| 53 |
user-reporter)) |
|
| 54 |
|
|
| 55 |
|
|
| 56 |
;;;; If you're using Emacs's Scheme mode: |
|
| 57 |
;;;; (put 'with-test-prefix 'scheme-indent-function 1) |
|
| 58 |
|
|
| 59 |
|
|
| 60 |
;;;; CORE FUNCTIONS |
|
| 61 |
;;;; |
|
| 62 |
;;;; The function (run-test name expected-result thunk) is the heart of the |
|
| 63 |
;;;; testing environment. The first parameter NAME is a unique name for the |
|
| 64 |
;;;; test to be executed (for an explanation of this parameter see below under |
|
| 65 |
;;;; TEST NAMES). The second parameter EXPECTED-RESULT is a boolean value |
|
| 66 |
;;;; that indicates whether the corresponding test is expected to pass. If |
|
| 67 |
;;;; EXPECTED-RESULT is #t the test is expected to pass, if EXPECTED-RESULT is |
|
| 68 |
;;;; #f the test is expected to fail. Finally, THUNK is the function that |
|
| 69 |
;;;; actually performs the test. For example: |
|
| 70 |
;;;; |
|
| 71 |
;;;; (run-test "integer addition" #t (lambda () (= 2 (+ 1 1)))) |
|
| 72 |
;;;; |
|
| 73 |
;;;; To report success, THUNK should either return #t or throw 'pass. To |
|
| 74 |
;;;; report failure, THUNK should either return #f or throw 'fail. If THUNK |
|
| 75 |
;;;; returns a non boolean value or throws 'unresolved, this indicates that |
|
| 76 |
;;;; the test did not perform as expected. For example the property that was |
|
| 77 |
;;;; to be tested could not be tested because something else went wrong. |
|
| 78 |
;;;; THUNK may also throw 'untested to indicate that the test was deliberately |
|
| 79 |
;;;; not performed, for example because the test case is not complete yet. |
|
| 80 |
;;;; Finally, if THUNK throws 'unsupported, this indicates that this test |
|
| 81 |
;;;; requires some feature that is not available in the configured testing |
|
| 82 |
;;;; environment. All other exceptions thrown by THUNK are considered as |
|
| 83 |
;;;; errors. |
|
| 84 |
;;;; |
|
| 85 |
;;;; |
|
| 86 |
;;;; Convenience macros for tests expected to pass or fail |
|
| 87 |
;;;; |
|
| 88 |
;;;; * (pass-if name body) is a short form for |
|
| 89 |
;;;; (run-test name #t (lambda () body)) |
|
| 90 |
;;;; * (expect-fail name body) is a short form for |
|
| 91 |
;;;; (run-test name #f (lambda () body)) |
|
| 92 |
;;;; |
|
| 93 |
;;;; For example: |
|
| 94 |
;;;; |
|
| 95 |
;;;; (pass-if "integer addition" (= 2 (+ 1 1))) |
|
| 96 |
;;;; |
|
| 97 |
;;;; |
|
| 98 |
;;;; Convenience macros to test for exceptions |
|
| 99 |
;;;; |
|
| 100 |
;;;; The following macros take exception parameters which are pairs |
|
| 101 |
;;;; (type . message), where type is a symbol that denotes an exception type |
|
| 102 |
;;;; like 'wrong-type-arg or 'out-of-range, and message is a string holding a |
|
| 103 |
;;;; regular expression that describes the error message for the exception |
|
| 104 |
;;;; like "Argument .* out of range". |
|
| 105 |
;;;; |
|
| 106 |
;;;; * (pass-if-exception name exception body) will pass if the execution of |
|
| 107 |
;;;; body causes the given exception to be thrown. If no exception is |
|
| 108 |
;;;; thrown, the test fails. If some other exception is thrown, is is an |
|
| 109 |
;;;; error. |
|
| 110 |
;;;; * (expect-fail-exception name exception body) will pass unexpectedly if |
|
| 111 |
;;;; the execution of body causes the given exception to be thrown. If no |
|
| 112 |
;;;; exception is thrown, the test fails expectedly. If some other |
|
| 113 |
;;;; exception is thrown, it is an error. |
|
| 114 |
|
|
| 115 |
|
|
| 116 |
;;;; TEST NAMES |
|
| 117 |
;;;; |
|
| 118 |
;;;; Every test in the test suite has a unique name, to help |
|
| 119 |
;;;; developers find tests that are failing (or unexpectedly passing), |
|
| 120 |
;;;; and to help gather statistics. |
|
| 121 |
;;;; |
|
| 122 |
;;;; A test name is a list of printable objects. For example: |
|
| 123 |
;;;; ("ports.scm" "file" "read and write back list of strings")
|
|
| 124 |
;;;; ("ports.scm" "pipe" "read")
|
|
| 125 |
;;;; |
|
| 126 |
;;;; Test names may contain arbitrary objects, but they always have |
|
| 127 |
;;;; the following properties: |
|
| 128 |
;;;; - Test names can be compared with EQUAL?. |
|
| 129 |
;;;; - Test names can be reliably stored and retrieved with the standard WRITE |
|
| 130 |
;;;; and READ procedures; doing so preserves their identity. |
|
| 131 |
;;;; |
|
| 132 |
;;;; For example: |
|
| 133 |
;;;; |
|
| 134 |
;;;; (pass-if "simple addition" (= 4 (+ 2 2))) |
|
| 135 |
;;;; |
|
| 136 |
;;;; In that case, the test name is the list ("simple addition").
|
|
| 137 |
;;;; |
|
| 138 |
;;;; In the case of simple tests the expression that is tested would often |
|
| 139 |
;;;; suffice as a test name by itself. Therefore, the convenience macros |
|
| 140 |
;;;; pass-if and expect-fail provide a shorthand notation that allows to omit |
|
| 141 |
;;;; a test name in such cases. |
|
| 142 |
;;;; |
|
| 143 |
;;;; * (pass-if expression) is a short form for |
|
| 144 |
;;;; (run-test 'expression #t (lambda () expression)) |
|
| 145 |
;;;; * (expect-fail expression) is a short form for |
|
| 146 |
;;;; (run-test 'expression #f (lambda () expression)) |
|
| 147 |
;;;; |
|
| 148 |
;;;; For example: |
|
| 149 |
;;;; |
|
| 150 |
;;;; (pass-if (= 2 (+ 1 1))) |
|
| 151 |
;;;; |
|
| 152 |
;;;; The WITH-TEST-PREFIX syntax and WITH-TEST-PREFIX* procedure establish |
|
| 153 |
;;;; a prefix for the names of all tests whose results are reported |
|
| 154 |
;;;; within their dynamic scope. For example: |
|
| 155 |
;;;; |
|
| 156 |
;;;; (begin |
|
| 157 |
;;;; (with-test-prefix "basic arithmetic" |
|
| 158 |
;;;; (pass-if "addition" (= (+ 2 2) 4)) |
|
| 159 |
;;;; (pass-if "subtraction" (= (- 4 2) 2))) |
|
| 160 |
;;;; (pass-if "multiplication" (= (* 2 2) 4))) |
|
| 161 |
;;;; |
|
| 162 |
;;;; In that example, the three test names are: |
|
| 163 |
;;;; ("basic arithmetic" "addition"),
|
|
| 164 |
;;;; ("basic arithmetic" "subtraction"), and
|
|
| 165 |
;;;; ("multiplication").
|
|
| 166 |
;;;; |
|
| 167 |
;;;; WITH-TEST-PREFIX can be nested. Each WITH-TEST-PREFIX postpends |
|
| 168 |
;;;; a new element to the current prefix: |
|
| 169 |
;;;; |
|
| 170 |
;;;; (with-test-prefix "arithmetic" |
|
| 171 |
;;;; (with-test-prefix "addition" |
|
| 172 |
;;;; (pass-if "integer" (= (+ 2 2) 4)) |
|
| 173 |
;;;; (pass-if "complex" (= (+ 2+3i 4+5i) 6+8i))) |
|
| 174 |
;;;; (with-test-prefix "subtraction" |
|
| 175 |
;;;; (pass-if "integer" (= (- 2 2) 0)) |
|
| 176 |
;;;; (pass-if "complex" (= (- 2+3i 1+2i) 1+1i)))) |
|
| 177 |
;;;; |
|
| 178 |
;;;; The four test names here are: |
|
| 179 |
;;;; ("arithmetic" "addition" "integer")
|
|
| 180 |
;;;; ("arithmetic" "addition" "complex")
|
|
| 181 |
;;;; ("arithmetic" "subtraction" "integer")
|
|
| 182 |
;;;; ("arithmetic" "subtraction" "complex")
|
|
| 183 |
;;;; |
|
| 184 |
;;;; To print a name for a human reader, we DISPLAY its elements, |
|
| 185 |
;;;; separated by ": ". So, the last set of test names would be |
|
| 186 |
;;;; reported as: |
|
| 187 |
;;;; |
|
| 188 |
;;;; arithmetic: addition: integer |
|
| 189 |
;;;; arithmetic: addition: complex |
|
| 190 |
;;;; arithmetic: subtraction: integer |
|
| 191 |
;;;; arithmetic: subtraction: complex |
|
| 192 |
;;;; |
|
| 193 |
;;;; The Guile benchmarks use with-test-prefix to include the name of |
|
| 194 |
;;;; the source file containing the test in the test name, to help |
|
| 195 |
;;;; developers to find failing tests, and to provide each file with its |
|
| 196 |
;;;; own namespace. |
|
| 197 |
|
|
| 198 |
|
|
| 199 |
;;;; REPORTERS |
|
| 200 |
;;;; |
|
| 201 |
;;;; A reporter is a function which we apply to each test outcome. |
|
| 202 |
;;;; Reporters can log results, print interesting results to the |
|
| 203 |
;;;; standard output, collect statistics, etc. |
|
| 204 |
;;;; |
|
| 205 |
;;;; A reporter function takes two mandatory arguments, RESULT and TEST, and |
|
| 206 |
;;;; possibly additional arguments depending on RESULT; its return value |
|
| 207 |
;;;; is ignored. RESULT has one of the following forms: |
|
| 208 |
;;;; |
|
| 209 |
;;;; pass - The test named TEST passed. |
|
| 210 |
;;;; Additional arguments are ignored. |
|
| 211 |
;;;; upass - The test named TEST passed unexpectedly. |
|
| 212 |
;;;; Additional arguments are ignored. |
|
| 213 |
;;;; fail - The test named TEST failed. |
|
| 214 |
;;;; Additional arguments are ignored. |
|
| 215 |
;;;; xfail - The test named TEST failed, as expected. |
|
| 216 |
;;;; Additional arguments are ignored. |
|
| 217 |
;;;; unresolved - The test named TEST did not perform as expected, for |
|
| 218 |
;;;; example the property that was to be tested could not be |
|
| 219 |
;;;; tested because something else went wrong. |
|
| 220 |
;;;; Additional arguments are ignored. |
|
| 221 |
;;;; untested - The test named TEST was not actually performed, for |
|
| 222 |
;;;; example because the test case is not complete yet. |
|
| 223 |
;;;; Additional arguments are ignored. |
|
| 224 |
;;;; unsupported - The test named TEST requires some feature that is not |
|
| 225 |
;;;; available in the configured testing environment. |
|
| 226 |
;;;; Additional arguments are ignored. |
|
| 227 |
;;;; error - An error occurred while the test named TEST was |
|
| 228 |
;;;; performed. Since this result means that the system caught |
|
| 229 |
;;;; an exception it could not handle, the exception arguments |
|
| 230 |
;;;; are passed as additional arguments. |
|
| 231 |
;;;; |
|
| 232 |
;;;; This library provides some standard reporters for logging results |
|
| 233 |
;;;; to a file, reporting interesting results to the user, and |
|
| 234 |
;;;; collecting totals. |
|
| 235 |
;;;; |
|
| 236 |
;;;; You can use the REGISTER-REPORTER function and friends to add |
|
| 237 |
;;;; whatever reporting functions you like. If you don't register any |
|
| 238 |
;;;; reporters, the library uses FULL-REPORTER, which simply writes |
|
| 239 |
;;;; all results to the standard output. |
|
| 240 |
|
|
| 241 |
|
|
| 242 |
;;;; MISCELLANEOUS |
|
| 243 |
;;;; |
|
| 244 |
|
|
| 245 |
;;; Define some exceptions which are commonly being tested for. |
|
| 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:miscellaneous-error |
|
| 267 |
(cons 'misc-error "^.*")) |
|
| 268 |
|
|
| 269 |
;; as per throw in scm_to_locale_stringn() |
|
| 270 |
(define exception:string-contains-nul |
|
| 271 |
(cons 'misc-error "^string contains #\\\\nul character")) |
|
| 272 |
|
|
| 273 |
|
|
| 274 |
;;; Display all parameters to the default output port, followed by a newline. |
|
| 275 |
(define (display-line . objs) |
|
| 276 |
(for-each display objs) |
|
| 277 |
(newline)) |
|
| 278 |
|
|
| 279 |
;;; Display all parameters to the given output port, followed by a newline. |
|
| 280 |
(define (display-line-port port . objs) |
|
| 281 |
(for-each (lambda (obj) (display obj port)) objs) |
|
| 282 |
(newline port)) |
|
| 283 |
|
|
| 284 |
|
|
| 285 |
;;;; CORE FUNCTIONS |
|
| 286 |
;;;; |
|
| 287 |
|
|
| 288 |
;;; The central testing routine. |
|
| 289 |
;;; The idea is taken from Greg, the GNUstep regression test environment. |
|
| 290 |
(define run-test #f) |
|
| 291 |
(let ((test-running #f)) |
|
| 292 |
(define (local-run-test name expect-pass thunk) |
|
| 293 |
(if test-running |
|
| 294 |
(error "Nested calls to run-test are not permitted.") |
|
| 295 |
(let ((test-name (full-name name))) |
|
| 296 |
(set! test-running #t) |
|
| 297 |
(catch #t |
|
| 298 |
(lambda () |
|
| 299 |
(let ((result (thunk))) |
|
| 300 |
(if (eq? result #t) (throw 'pass)) |
|
| 301 |
(if (eq? result #f) (throw 'fail)) |
|
| 302 |
(throw 'unresolved))) |
|
| 303 |
(lambda (key . args) |
|
| 304 |
(case key |
|
| 305 |
((pass) |
|
| 306 |
(report (if expect-pass 'pass 'upass) test-name)) |
|
| 307 |
((fail) |
|
| 308 |
(report (if expect-pass 'fail 'xfail) test-name)) |
|
| 309 |
((unresolved untested unsupported) |
|
| 310 |
(report key test-name)) |
|
| 311 |
((quit) |
|
| 312 |
(report 'unresolved test-name) |
|
| 313 |
(quit)) |
|
| 314 |
(else |
|
| 315 |
(report 'error test-name (cons key args)))))) |
|
| 316 |
(set! test-running #f)))) |
|
| 317 |
(set! run-test local-run-test)) |
|
| 318 |
|
|
| 319 |
;;; A short form for tests that are expected to pass, taken from Greg. |
|
| 320 |
(defmacro pass-if (name . rest) |
|
| 321 |
(if (and (null? rest) (pair? name)) |
|
| 322 |
;; presume this is a simple test, i.e. (pass-if (even? 2)) |
|
| 323 |
;; where the body should also be the name. |
|
| 324 |
`(run-test ',name #t (lambda () ,name)) |
|
| 325 |
`(run-test ,name #t (lambda () ,@rest)))) |
|
| 326 |
|
|
| 327 |
;;; A short form for tests that are expected to fail, taken from Greg. |
|
| 328 |
(defmacro expect-fail (name . rest) |
|
| 329 |
(if (and (null? rest) (pair? name)) |
|
| 330 |
;; presume this is a simple test, i.e. (expect-fail (even? 2)) |
|
| 331 |
;; where the body should also be the name. |
|
| 332 |
`(run-test ',name #f (lambda () ,name)) |
|
| 333 |
`(run-test ,name #f (lambda () ,@rest)))) |
|
| 334 |
|
|
| 335 |
;;; A helper function to implement the macros that test for exceptions. |
|
| 336 |
(define (run-test-exception name exception expect-pass thunk) |
|
| 337 |
(run-test name expect-pass |
|
| 338 |
(lambda () |
|
| 339 |
(stack-catch (car exception) |
|
| 340 |
(lambda () (thunk) #f) |
|
| 341 |
(lambda (key proc message . rest) |
|
| 342 |
(cond |
|
| 343 |
;; handle explicit key |
|
| 344 |
((string-match (cdr exception) message) |
|
| 345 |
#t) |
|
| 346 |
;; handle `(error ...)' which uses `misc-error' for key and doesn't |
|
| 347 |
;; yet format the message and args (we have to do it here). |
|
| 348 |
((and (eq? 'misc-error (car exception)) |
|
| 349 |
(list? rest) |
|
| 350 |
(string-match (cdr exception) |
|
| 351 |
(apply simple-format #f message (car rest)))) |
|
| 352 |
#t) |
|
| 353 |
;; handle syntax errors which use `syntax-error' for key and don't |
|
| 354 |
;; yet format the message and args (we have to do it here). |
|
| 355 |
((and (eq? 'syntax-error (car exception)) |
|
| 356 |
(list? rest) |
|
| 357 |
(string-match (cdr exception) |
|
| 358 |
(apply simple-format #f message (car rest)))) |
|
| 359 |
#t) |
|
| 360 |
;; unhandled; throw again |
|
| 361 |
(else |
|
| 362 |
(apply throw key proc message rest)))))))) |
|
| 363 |
|
|
| 364 |
;;; A short form for tests that expect a certain exception to be thrown. |
|
| 365 |
(defmacro pass-if-exception (name exception body . rest) |
|
| 366 |
`(,run-test-exception ,name ,exception #t (lambda () ,body ,@rest))) |
|
| 367 |
|
|
| 368 |
;;; A short form for tests expected to fail to throw a certain exception. |
|
| 369 |
(defmacro expect-fail-exception (name exception body . rest) |
|
| 370 |
`(,run-test-exception ,name ,exception #f (lambda () ,body ,@rest))) |
|
| 371 |
|
|
| 372 |
|
|
| 373 |
;;;; TEST NAMES |
|
| 374 |
;;;; |
|
| 375 |
|
|
| 376 |
;;;; Turn a test name into a nice human-readable string. |
|
| 377 |
(define (format-test-name name) |
|
| 378 |
(call-with-output-string |
|
| 379 |
(lambda (port) |
|
| 380 |
(let loop ((name name) |
|
| 381 |
(separator "")) |
|
| 382 |
(if (pair? name) |
|
| 383 |
(begin |
|
| 384 |
(display separator port) |
|
| 385 |
(display (car name) port) |
|
| 386 |
(loop (cdr name) ": "))))))) |
|
| 387 |
|
|
| 388 |
;;;; For a given test-name, deliver the full name including all prefixes. |
|
| 389 |
(define (full-name name) |
|
| 390 |
(append (current-test-prefix) (list name))) |
|
| 391 |
|
|
| 392 |
;;; A fluid containing the current test prefix, as a list. |
|
| 393 |
(define prefix-fluid (make-fluid)) |
|
| 394 |
(fluid-set! prefix-fluid '()) |
|
| 395 |
(define (current-test-prefix) |
|
| 396 |
(fluid-ref prefix-fluid)) |
|
| 397 |
|
|
| 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 |
|
|
| 406 |
;;; (with-test-prefix PREFIX BODY ...) |
|
| 407 |
;;; Postpend PREFIX to the current name prefix while evaluating BODY ... |
|
| 408 |
;;; The name prefix is only changed within the dynamic scope of the |
|
| 409 |
;;; with-test-prefix expression. Return the value returned by the last |
|
| 410 |
;;; BODY expression. |
|
| 411 |
(defmacro with-test-prefix (prefix . body) |
|
| 412 |
`(with-test-prefix* ,prefix (lambda () ,@body))) |
|
| 413 |
|
|
| 414 |
;;; Call THUNK using the debugging evaluator. |
|
| 415 |
(define (with-debugging-evaluator* thunk) |
|
| 416 |
(let ((dopts #f)) |
|
| 417 |
(dynamic-wind |
|
| 418 |
(lambda () |
|
| 419 |
(set! dopts (debug-options)) |
|
| 420 |
(debug-enable 'debug)) |
|
| 421 |
thunk |
|
| 422 |
(lambda () |
|
| 423 |
(debug-options dopts))))) |
|
| 424 |
|
|
| 425 |
;;; Evaluate BODY... using the debugging evaluator. |
|
| 426 |
(define-macro (with-debugging-evaluator . body) |
|
| 427 |
`(with-debugging-evaluator* (lambda () ,@body))) |
|
| 428 |
|
|
| 429 |
|
|
| 430 |
|
|
| 431 |
;;;; REPORTERS |
|
| 432 |
;;;; |
|
| 433 |
|
|
| 434 |
;;; The global list of reporters. |
|
| 435 |
(define reporters '()) |
|
| 436 |
|
|
| 437 |
;;; The default reporter, to be used only if no others exist. |
|
| 438 |
(define default-reporter #f) |
|
| 439 |
|
|
| 440 |
;;; Add the procedure REPORTER to the current set of reporter functions. |
|
| 441 |
;;; Signal an error if that reporter procedure object is already registered. |
|
| 442 |
(define (register-reporter reporter) |
|
| 443 |
(if (memq reporter reporters) |
|
| 444 |
(error "register-reporter: reporter already registered: " reporter)) |
|
| 445 |
(set! reporters (cons reporter reporters))) |
|
| 446 |
|
|
| 447 |
;;; Remove the procedure REPORTER from the current set of reporter |
|
| 448 |
;;; functions. Signal an error if REPORTER is not currently registered. |
|
| 449 |
(define (unregister-reporter reporter) |
|
| 450 |
(if (memq reporter reporters) |
|
| 451 |
(set! reporters (delq! reporter reporters)) |
|
| 452 |
(error "unregister-reporter: reporter not registered: " reporter))) |
|
| 453 |
|
|
| 454 |
;;; Return true iff REPORTER is in the current set of reporter functions. |
|
| 455 |
(define (reporter-registered? reporter) |
|
| 456 |
(if (memq reporter reporters) #t #f)) |
|
| 457 |
|
|
| 458 |
;;; Send RESULT to all currently registered reporter functions. |
|
| 459 |
(define (report . args) |
|
| 460 |
(if (pair? reporters) |
|
| 461 |
(for-each (lambda (reporter) (apply reporter args)) |
|
| 462 |
reporters) |
|
| 463 |
(apply default-reporter args))) |
|
| 464 |
|
|
| 465 |
|
|
| 466 |
;;;; Some useful standard reporters: |
|
| 467 |
;;;; Count reporters count the occurrence of each test result type. |
|
| 468 |
;;;; Log reporters write all test results to a given log file. |
|
| 469 |
;;;; Full reporters write all test results to the standard output. |
|
| 470 |
;;;; User reporters write interesting test results to the standard output. |
|
| 471 |
|
|
| 472 |
;;; The complete list of possible test results. |
|
| 473 |
(define result-tags |
|
| 474 |
'((pass "PASS" "passes: ") |
|
| 475 |
(fail "FAIL" "failures: ") |
|
| 476 |
(upass "UPASS" "unexpected passes: ") |
|
| 477 |
(xfail "XFAIL" "expected failures: ") |
|
| 478 |
(unresolved "UNRESOLVED" "unresolved test cases: ") |
|
| 479 |
(untested "UNTESTED" "untested test cases: ") |
|
| 480 |
(unsupported "UNSUPPORTED" "unsupported test cases: ") |
|
| 481 |
(error "ERROR" "errors: "))) |
|
| 482 |
|
|
| 483 |
;;; The list of important test results. |
|
| 484 |
(define important-result-tags |
|
| 485 |
'(fail upass unresolved error)) |
|
| 486 |
|
|
| 487 |
;;; Display a single test result in formatted form to the given port |
|
| 488 |
(define (print-result port result name . args) |
|
| 489 |
(let* ((tag (assq result result-tags)) |
|
| 490 |
(label (if tag (cadr tag) #f))) |
|
| 491 |
(if label |
|
| 492 |
(begin |
|
| 493 |
(display label port) |
|
| 494 |
(display ": " port) |
|
| 495 |
(display (format-test-name name) port) |
|
| 496 |
(if (pair? args) |
|
| 497 |
(begin |
|
| 498 |
(display " - arguments: " port) |
|
| 499 |
(write args port))) |
|
| 500 |
(newline port)) |
|
| 501 |
(error "(test-suite lib) FULL-REPORTER: unrecognized result: " |
|
| 502 |
result)))) |
|
| 503 |
|
|
| 504 |
;;; Return a list of the form (COUNTER RESULTS), where: |
|
| 505 |
;;; - COUNTER is a reporter procedure, and |
|
| 506 |
;;; - RESULTS is a procedure taking no arguments which returns the |
|
| 507 |
;;; results seen so far by COUNTER. The return value is an alist |
|
| 508 |
;;; mapping outcome symbols (`pass', `fail', etc.) onto counts. |
|
| 509 |
(define (make-count-reporter) |
|
| 510 |
(let ((counts (map (lambda (tag) (cons (car tag) 0)) result-tags))) |
|
| 511 |
(list |
|
| 512 |
(lambda (result name . args) |
|
| 513 |
(let ((pair (assq result counts))) |
|
| 514 |
(if pair |
|
| 515 |
(set-cdr! pair (+ 1 (cdr pair))) |
|
| 516 |
(error "count-reporter: unexpected test result: " |
|
| 517 |
(cons result (cons name args)))))) |
|
| 518 |
(lambda () |
|
| 519 |
(append counts '()))))) |
|
| 520 |
|
|
| 521 |
;;; Print a count reporter's results nicely. Pass this function the value |
|
| 522 |
;;; returned by a count reporter's RESULTS procedure. |
|
| 523 |
(define (print-counts results . port?) |
|
| 524 |
(let ((port (if (pair? port?) |
|
| 525 |
(car port?) |
|
| 526 |
(current-output-port)))) |
|
| 527 |
(newline port) |
|
| 528 |
(display-line-port port "Totals for this test run:") |
|
| 529 |
(for-each |
|
| 530 |
(lambda (tag) |
|
| 531 |
(let ((result (assq (car tag) results))) |
|
| 532 |
(if result |
|
| 533 |
(display-line-port port (caddr tag) (cdr result)) |
|
| 534 |
(display-line-port port |
|
| 535 |
"Test suite bug: " |
|
| 536 |
"no total available for `" (car tag) "'")))) |
|
| 537 |
result-tags) |
|
| 538 |
(newline port))) |
|
| 539 |
|
|
| 540 |
;;; Return a reporter procedure which prints all results to the file |
|
| 541 |
;;; FILE, in human-readable form. FILE may be a filename, or a port. |
|
| 542 |
(define (make-log-reporter file) |
|
| 543 |
(let ((port (if (output-port? file) file |
|
| 544 |
(open-output-file file)))) |
|
| 545 |
(lambda args |
|
| 546 |
(apply print-result port args) |
|
| 547 |
(force-output port)))) |
|
| 548 |
|
|
| 549 |
;;; A reporter that reports all results to the user. |
|
| 550 |
(define (full-reporter . args) |
|
| 551 |
(apply print-result (current-output-port) args)) |
|
| 552 |
|
|
| 553 |
;;; A reporter procedure which shows interesting results (failures, |
|
| 554 |
;;; unexpected passes etc.) to the user. |
|
| 555 |
(define (user-reporter result name . args) |
|
| 556 |
(if (memq result important-result-tags) |
|
| 557 |
(apply full-reporter result name args))) |
|
| 558 |
|
|
| 559 |
(set! default-reporter full-reporter) |
|
| /dev/null | ||
|---|---|---|
| 1 |
#!../libguile/guile \ |
|
| 2 |
-e main -s |
|
| 3 |
!# |
|
| 4 |
|
|
| 5 |
;;;; guile-test --- run the Guile test suite |
|
| 6 |
;;;; Jim Blandy <[email protected]> --- May 1999 |
|
| 7 |
;;;; |
|
| 8 |
;;;; Copyright (C) 1999, 2001, 2006 Free Software Foundation, Inc. |
|
| 9 |
;;;; |
|
| 10 |
;;;; This program is free software; you can redistribute it and/or modify |
|
| 11 |
;;;; it under the terms of the GNU General Public License as published by |
|
| 12 |
;;;; the Free Software Foundation; either version 2, or (at your option) |
|
| 13 |
;;;; any later version. |
|
| 14 |
;;;; |
|
| 15 |
;;;; This program is distributed in the hope that it will be useful, |
|
| 16 |
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 17 |
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 18 |
;;;; GNU General Public License for more details. |
|
| 19 |
;;;; |
|
| 20 |
;;;; You should have received a copy of the GNU General Public License |
|
| 21 |
;;;; along with this software; see the file COPYING. If not, write to |
|
| 22 |
;;;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
| 23 |
;;;; Boston, MA 02110-1301 USA |
|
| 24 |
|
|
| 25 |
|
|
| 26 |
;;;; Usage: [guile -e main -s] guile-test [OPTIONS] [TEST ...] |
|
| 27 |
;;;; |
|
| 28 |
;;;; Run tests from the Guile test suite. Report failures and |
|
| 29 |
;;;; unexpected passes to the standard output, along with a summary of |
|
| 30 |
;;;; all the results. Record each reported test outcome in the log |
|
| 31 |
;;;; file, `guile.log'. The exit status is #f if any of the tests |
|
| 32 |
;;;; fail or pass unexpectedly. |
|
| 33 |
;;;; |
|
| 34 |
;;;; Normally, guile-test scans the test directory, and executes all |
|
| 35 |
;;;; files whose names end in `.test'. (It assumes they contain |
|
| 36 |
;;;; Scheme code.) However, you can have it execute specific tests by |
|
| 37 |
;;;; listing their filenames on the command line. |
|
| 38 |
;;;; |
|
| 39 |
;;;; The option `--test-suite' can be given to specify the test |
|
| 40 |
;;;; directory. If no such option is given, the test directory is |
|
| 41 |
;;;; taken from the environment variable TEST_SUITE_DIR (if defined), |
|
| 42 |
;;;; otherwise a default directory that is hardcoded in this file is |
|
| 43 |
;;;; used (see "Installation" below). |
|
| 44 |
;;;; |
|
| 45 |
;;;; If present, the `--log-file LOG' option tells `guile-test' to put |
|
| 46 |
;;;; the log output in a file named LOG. |
|
| 47 |
;;;; |
|
| 48 |
;;;; If present, the `--debug' option will enable a debugging mode. |
|
| 49 |
;;;; |
|
| 50 |
;;;; If present, the `--flag-unresolved' option will cause guile-test |
|
| 51 |
;;;; to exit with failure status if any tests are UNRESOLVED. |
|
| 52 |
;;;; |
|
| 53 |
;;;; |
|
| 54 |
;;;; Installation: |
|
| 55 |
;;;; |
|
| 56 |
;;;; If you change the #! line at the top of this script to point at |
|
| 57 |
;;;; the Guile interpreter you want to test, you can call this script |
|
| 58 |
;;;; as an executable instead of having to pass it as a parameter to |
|
| 59 |
;;;; guile via "guile -e main -s guile-test". Further, you can edit |
|
| 60 |
;;;; the definition of default-test-suite to point to the parent |
|
| 61 |
;;;; directory of the `tests' tree, which makes it unnecessary to set |
|
| 62 |
;;;; the environment variable `TEST_SUITE_DIR'. |
|
| 63 |
;;;; |
|
| 64 |
;;;; |
|
| 65 |
;;;; Shortcomings: |
|
| 66 |
;;;; |
|
| 67 |
;;;; At the moment, due to a simple-minded implementation, test files |
|
| 68 |
;;;; must live in the test directory, and you must specify their names |
|
| 69 |
;;;; relative to the top of the test directory. If you want to send |
|
| 70 |
;;;; me a patch that fixes this, but still leaves sane test names in |
|
| 71 |
;;;; the log file, that would be great. At the moment, all the tests |
|
| 72 |
;;;; I care about are in the test directory, though. |
|
| 73 |
;;;; |
|
| 74 |
;;;; It would be nice if you could specify the Guile interpreter you |
|
| 75 |
;;;; want to test on the command line. As it stands, if you want to |
|
| 76 |
;;;; change which Guile interpreter you're testing, you need to edit |
|
| 77 |
;;;; the #! line at the top of this file, which is stupid. |
|
| 78 |
|
|
| 79 |
(define (main . args) |
|
| 80 |
(let ((module (resolve-module '(test-suite guile-test)))) |
|
| 81 |
(apply (module-ref module 'main) args))) |
|
| 82 |
|
|
| 83 |
(define-module (test-suite guile-test) |
|
| 84 |
:use-module (test-suite lib) |
|
| 85 |
:use-module (ice-9 getopt-long) |
|
| 86 |
:use-module (ice-9 and-let-star) |
|
| 87 |
:use-module (ice-9 rdelim) |
|
| 88 |
:export (main data-file-name test-file-name)) |
|
| 89 |
|
|
| 90 |
|
|
| 91 |
;;; User configurable settings: |
|
| 92 |
(define default-test-suite |
|
| 93 |
(string-append (getenv "HOME") "/bogus-path/test-suite")) |
|
| 94 |
|
|
| 95 |
|
|
| 96 |
;;; Variables that will receive their actual values later. |
|
| 97 |
(define test-suite default-test-suite) |
|
| 98 |
|
|
| 99 |
(define tmp-dir #f) |
|
| 100 |
|
|
| 101 |
|
|
| 102 |
;;; General utilities, that probably should be in a library somewhere. |
|
| 103 |
|
|
| 104 |
;;; Enable debugging |
|
| 105 |
(define (enable-debug-mode) |
|
| 106 |
(write-line %load-path) |
|
| 107 |
(set! %load-verbosely #t) |
|
| 108 |
(debug-enable 'backtrace 'debug)) |
|
| 109 |
|
|
| 110 |
;;; Traverse the directory tree at ROOT, applying F to the name of |
|
| 111 |
;;; each file in the tree, including ROOT itself. For a subdirectory |
|
| 112 |
;;; SUB, if (F SUB) is true, we recurse into SUB. Do not follow |
|
| 113 |
;;; symlinks. |
|
| 114 |
(define (for-each-file f root) |
|
| 115 |
|
|
| 116 |
;; A "hard directory" is a path that denotes a directory and is not a |
|
| 117 |
;; symlink. |
|
| 118 |
(define (file-is-hard-directory? filename) |
|
| 119 |
(eq? (stat:type (lstat filename)) 'directory)) |
|
| 120 |
|
|
| 121 |
(let visit ((root root)) |
|
| 122 |
(let ((should-recur (f root))) |
|
| 123 |
(if (and should-recur (file-is-hard-directory? root)) |
|
| 124 |
(let ((dir (opendir root))) |
|
| 125 |
(let loop () |
|
| 126 |
(let ((entry (readdir dir))) |
|
| 127 |
(cond |
|
| 128 |
((eof-object? entry) #f) |
|
| 129 |
((or (string=? entry ".") |
|
| 130 |
(string=? entry "..") |
|
| 131 |
(string=? entry "CVS") |
|
| 132 |
(string=? entry "RCS")) |
|
| 133 |
(loop)) |
|
| 134 |
(else |
|
| 135 |
(visit (string-append root "/" entry)) |
|
| 136 |
(loop)))))))))) |
|
| 137 |
|
|
| 138 |
|
|
| 139 |
;;; The test driver. |
|
| 140 |
|
|
| 141 |
|
|
| 142 |
;;; Localizing test files and temporary data files. |
|
| 143 |
|
|
| 144 |
(define (data-file-name filename) |
|
| 145 |
(in-vicinity tmp-dir filename)) |
|
| 146 |
|
|
| 147 |
(define (test-file-name test) |
|
| 148 |
(in-vicinity test-suite test)) |
|
| 149 |
|
|
| 150 |
;;; Return a list of all the test files in the test tree. |
|
| 151 |
(define (enumerate-tests test-dir) |
|
| 152 |
(let ((root-len (+ 1 (string-length test-dir))) |
|
| 153 |
(tests '())) |
|
| 154 |
(for-each-file (lambda (file) |
|
| 155 |
(if (has-suffix? file ".test") |
|
| 156 |
(let ((short-name |
|
| 157 |
(substring file root-len))) |
|
| 158 |
(set! tests (cons short-name tests)))) |
|
| 159 |
#t) |
|
| 160 |
test-dir) |
|
| 161 |
|
|
| 162 |
;; for-each-file presents the files in whatever order it finds |
|
| 163 |
;; them in the directory. We sort them here, so they'll always |
|
| 164 |
;; appear in the same order. This makes it easier to compare test |
|
| 165 |
;; log files mechanically. |
|
| 166 |
(sort tests string<?))) |
|
| 167 |
|
|
| 168 |
(define (main args) |
|
| 169 |
(let ((options (getopt-long args |
|
| 170 |
`((test-suite |
|
| 171 |
(single-char #\t) |
|
| 172 |
(value #t)) |
|
| 173 |
(flag-unresolved |
|
| 174 |
(single-char #\u)) |
|
| 175 |
(log-file |
|
| 176 |
(single-char #\l) |
|
| 177 |
(value #t)) |
|
| 178 |
(debug |
|
| 179 |
(single-char #\d)))))) |
|
| 180 |
(define (opt tag default) |
|
| 181 |
(let ((pair (assq tag options))) |
|
| 182 |
(if pair (cdr pair) default))) |
|
| 183 |
|
|
| 184 |
(if (opt 'debug #f) |
|
| 185 |
(enable-debug-mode)) |
|
| 186 |
|
|
| 187 |
(set! test-suite |
|
| 188 |
(or (opt 'test-suite #f) |
|
| 189 |
(getenv "TEST_SUITE_DIR") |
|
| 190 |
default-test-suite)) |
|
| 191 |
|
|
| 192 |
;; directory where temporary files are created. |
|
| 193 |
;; when run from "make check", this must be under the build-dir, |
|
| 194 |
;; not the src-dir. |
|
| 195 |
(set! tmp-dir (getcwd)) |
|
| 196 |
|
|
| 197 |
(let* ((tests |
|
| 198 |
(let ((foo (opt '() '()))) |
|
| 199 |
(if (null? foo) |
|
| 200 |
(enumerate-tests test-suite) |
|
| 201 |
foo))) |
|
| 202 |
(log-file |
|
| 203 |
(opt 'log-file "guile.log"))) |
|
| 204 |
|
|
| 205 |
;; Open the log file. |
|
| 206 |
(let ((log-port (open-output-file log-file))) |
|
| 207 |
|
|
| 208 |
;; Register some reporters. |
|
| 209 |
(let ((global-pass #t) |
|
| 210 |
(counter (make-count-reporter))) |
|
| 211 |
(register-reporter (car counter)) |
|
| 212 |
(register-reporter (make-log-reporter log-port)) |
|
| 213 |
(register-reporter user-reporter) |
|
| 214 |
(register-reporter (lambda results |
|
| 215 |
(case (car results) |
|
| 216 |
((unresolved) |
|
| 217 |
(and (opt 'flag-unresolved #f) |
|
| 218 |
(set! global-pass #f))) |
|
| 219 |
((fail upass error) |
|
| 220 |
(set! global-pass #f))))) |
|
| 221 |
|
|
| 222 |
;; Run the tests. |
|
| 223 |
(for-each (lambda (test) |
|
| 224 |
(display (string-append "Running " test "\n")) |
|
| 225 |
(with-test-prefix test |
|
| 226 |
(load (test-file-name test)))) |
|
| 227 |
tests) |
|
| 228 |
|
|
| 229 |
;; Display the final counts, both to the user and in the log |
|
| 230 |
;; file. |
|
| 231 |
(let ((counts ((cadr counter)))) |
|
| 232 |
(print-counts counts) |
|
| 233 |
(print-counts counts log-port)) |
|
| 234 |
|
|
| 235 |
(close-port log-port) |
|
| 236 |
(quit global-pass)))))) |
|
| 237 |
|
|
| 238 |
|
|
| 239 |
;;; Local Variables: |
|
| 240 |
;;; mode: scheme |
|
| 241 |
;;; End: |
|
| /dev/null | ||
|---|---|---|
| 1 |
;;;; test-suite/lib.scm --- generic support for testing |
|
| 2 |
;;;; Copyright (C) 1999, 2000, 2001, 2004, 2006, 2007 Free Software Foundation, Inc. |
|
| 3 |
;;;; |
|
| 4 |
;;;; This program is free software; you can redistribute it and/or modify |
|
| 5 |
;;;; it under the terms of the GNU General Public License as published by |
|
| 6 |
;;;; the Free Software Foundation; either version 2, or (at your option) |
|
| 7 |
;;;; any later version. |
|
| 8 |
;;;; |
|
| 9 |
;;;; This program is distributed in the hope that it will be useful, |
|
| 10 |
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 11 |
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 12 |
;;;; GNU General Public License for more details. |
|
| 13 |
;;;; |
|
| 14 |
;;;; You should have received a copy of the GNU General Public License |
|
| 15 |
;;;; along with this software; see the file COPYING. If not, write to |
|
| 16 |
;;;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
| 17 |
;;;; Boston, MA 02110-1301 USA |
|
| 18 |
|
|
| 19 |
(define-module (test-suite lib) |
|
| 20 |
:use-module (ice-9 stack-catch) |
|
| 21 |
:use-module (ice-9 regex) |
|
| 22 |
:export ( |
|
| 23 |
|
|
| 24 |
;; Exceptions which are commonly being tested for. |
|
| 25 |
exception:bad-variable |
|
| 26 |
exception:missing-expression |
|
| 27 |
exception:out-of-range exception:unbound-var |
|
| 28 |
exception:used-before-defined |
|
| 29 |
exception:wrong-num-args exception:wrong-type-arg |
|
| 30 |
exception:numerical-overflow |
|
| 31 |
exception:struct-set!-denied |
|
| 32 |
exception:system-error |
|
| 33 |
exception:miscellaneous-error |
|
| 34 |
exception:string-contains-nul |
|
| 35 |
|
|
| 36 |
;; Reporting passes and failures. |
|
| 37 |
run-test |
|
| 38 |
pass-if expect-fail |
|
| 39 |
pass-if-exception expect-fail-exception |
|
| 40 |
|
|
| 41 |
;; Naming groups of tests in a regular fashion. |
|
| 42 |
with-test-prefix with-test-prefix* current-test-prefix |
|
| 43 |
format-test-name |
|
| 44 |
|
|
| 45 |
;; Using the debugging evaluator. |
|
| 46 |
with-debugging-evaluator with-debugging-evaluator* |
|
| 47 |
|
|
| 48 |
;; Reporting results in various ways. |
|
| 49 |
register-reporter unregister-reporter reporter-registered? |
|
| 50 |
make-count-reporter print-counts |
|
| 51 |
make-log-reporter |
|
| 52 |
full-reporter |
|
| 53 |
user-reporter)) |
|
| 54 |
|
|
| 55 |
|
|
| 56 |
;;;; If you're using Emacs's Scheme mode: |
|
| 57 |
;;;; (put 'with-test-prefix 'scheme-indent-function 1) |
|
| 58 |
|
|
| 59 |
|
|
| 60 |
;;;; CORE FUNCTIONS |
|
| 61 |
;;;; |
|
| 62 |
;;;; The function (run-test name expected-result thunk) is the heart of the |
|
| 63 |
;;;; testing environment. The first parameter NAME is a unique name for the |
|
| 64 |
;;;; test to be executed (for an explanation of this parameter see below under |
|
| 65 |
;;;; TEST NAMES). The second parameter EXPECTED-RESULT is a boolean value |
|
| 66 |
;;;; that indicates whether the corresponding test is expected to pass. If |
|
| 67 |
;;;; EXPECTED-RESULT is #t the test is expected to pass, if EXPECTED-RESULT is |
|
| 68 |
;;;; #f the test is expected to fail. Finally, THUNK is the function that |
|
| 69 |
;;;; actually performs the test. For example: |
|
| 70 |
;;;; |
|
| 71 |
;;;; (run-test "integer addition" #t (lambda () (= 2 (+ 1 1)))) |
|
| 72 |
;;;; |
|
| 73 |
;;;; To report success, THUNK should either return #t or throw 'pass. To |
|
| 74 |
;;;; report failure, THUNK should either return #f or throw 'fail. If THUNK |
|
| 75 |
;;;; returns a non boolean value or throws 'unresolved, this indicates that |
|
| 76 |
;;;; the test did not perform as expected. For example the property that was |
|
| 77 |
;;;; to be tested could not be tested because something else went wrong. |
|
| 78 |
;;;; THUNK may also throw 'untested to indicate that the test was deliberately |
|
| 79 |
;;;; not performed, for example because the test case is not complete yet. |
|
| 80 |
;;;; Finally, if THUNK throws 'unsupported, this indicates that this test |
|
| 81 |
;;;; requires some feature that is not available in the configured testing |
|
| 82 |
;;;; environment. All other exceptions thrown by THUNK are considered as |
|
| 83 |
;;;; errors. |
|
| 84 |
;;;; |
|
| 85 |
;;;; |
|
| 86 |
;;;; Convenience macros for tests expected to pass or fail |
|
| 87 |
;;;; |
|
| 88 |
;;;; * (pass-if name body) is a short form for |
|
| 89 |
;;;; (run-test name #t (lambda () body)) |
|
| 90 |
;;;; * (expect-fail name body) is a short form for |
|
| 91 |
;;;; (run-test name #f (lambda () body)) |
|
| 92 |
;;;; |
|
| 93 |
;;;; For example: |
|
| 94 |
;;;; |
|
| 95 |
;;;; (pass-if "integer addition" (= 2 (+ 1 1))) |
|
| 96 |
;;;; |
|
| 97 |
;;;; |
|
| 98 |
;;;; Convenience macros to test for exceptions |
|
| 99 |
;;;; |
|
| 100 |
;;;; The following macros take exception parameters which are pairs |
|
| 101 |
;;;; (type . message), where type is a symbol that denotes an exception type |
|
| 102 |
;;;; like 'wrong-type-arg or 'out-of-range, and message is a string holding a |
|
| 103 |
;;;; regular expression that describes the error message for the exception |
|
| 104 |
;;;; like "Argument .* out of range". |
|
| 105 |
;;;; |
|
| 106 |
;;;; * (pass-if-exception name exception body) will pass if the execution of |
|
| 107 |
;;;; body causes the given exception to be thrown. If no exception is |
|
| 108 |
;;;; thrown, the test fails. If some other exception is thrown, is is an |
|
| 109 |
;;;; error. |
|
| 110 |
;;;; * (expect-fail-exception name exception body) will pass unexpectedly if |
|
| 111 |
;;;; the execution of body causes the given exception to be thrown. If no |
|
| 112 |
;;;; exception is thrown, the test fails expectedly. If some other |
|
| 113 |
;;;; exception is thrown, it is an error. |
|
| 114 |
|
|
| 115 |
|
|
| 116 |
;;;; TEST NAMES |
|
| 117 |
;;;; |
|
| 118 |
;;;; Every test in the test suite has a unique name, to help |
|
| 119 |
;;;; developers find tests that are failing (or unexpectedly passing), |
|
| 120 |
;;;; and to help gather statistics. |
|
| 121 |
;;;; |
|
| 122 |
;;;; A test name is a list of printable objects. For example: |
|
| 123 |
;;;; ("ports.scm" "file" "read and write back list of strings")
|
|
| 124 |
;;;; ("ports.scm" "pipe" "read")
|
|
| 125 |
;;;; |
|
| 126 |
;;;; Test names may contain arbitrary objects, but they always have |
|
| 127 |
;;;; the following properties: |
|
| 128 |
;;;; - Test names can be compared with EQUAL?. |
|
| 129 |
;;;; - Test names can be reliably stored and retrieved with the standard WRITE |
|
| 130 |
;;;; and READ procedures; doing so preserves their identity. |
|
| 131 |
;;;; |
|
| 132 |
;;;; For example: |
|
| 133 |
;;;; |
|
| 134 |
;;;; (pass-if "simple addition" (= 4 (+ 2 2))) |
|
| 135 |
;;;; |
|
| 136 |
;;;; In that case, the test name is the list ("simple addition").
|
|
| 137 |
;;;; |
|
| 138 |
;;;; In the case of simple tests the expression that is tested would often |
|
| 139 |
;;;; suffice as a test name by itself. Therefore, the convenience macros |
|
| 140 |
;;;; pass-if and expect-fail provide a shorthand notation that allows to omit |
|
| 141 |
;;;; a test name in such cases. |
|
| 142 |
;;;; |
|
| 143 |
;;;; * (pass-if expression) is a short form for |
|
| 144 |
;;;; (run-test 'expression #t (lambda () expression)) |
|
| 145 |
;;;; * (expect-fail expression) is a short form for |
|
| 146 |
;;;; (run-test 'expression #f (lambda () expression)) |
|
| 147 |
;;;; |
|
| 148 |
;;;; For example: |
|
| 149 |
;;;; |
|
| 150 |
;;;; (pass-if (= 2 (+ 1 1))) |
|
| 151 |
;;;; |
|
| 152 |
;;;; The WITH-TEST-PREFIX syntax and WITH-TEST-PREFIX* procedure establish |
|
| 153 |
;;;; a prefix for the names of all tests whose results are reported |
|
| 154 |
;;;; within their dynamic scope. For example: |
|
| 155 |
;;;; |
|
| 156 |
;;;; (begin |
|
| 157 |
;;;; (with-test-prefix "basic arithmetic" |
|
| 158 |
;;;; (pass-if "addition" (= (+ 2 2) 4)) |
|
| 159 |
;;;; (pass-if "subtraction" (= (- 4 2) 2))) |
|
| 160 |
;;;; (pass-if "multiplication" (= (* 2 2) 4))) |
|
| 161 |
;;;; |
|
| 162 |
;;;; In that example, the three test names are: |
|
| 163 |
;;;; ("basic arithmetic" "addition"),
|
|
| 164 |
;;;; ("basic arithmetic" "subtraction"), and
|
|
| 165 |
;;;; ("multiplication").
|
|
| 166 |
;;;; |
|
| 167 |
;;;; WITH-TEST-PREFIX can be nested. Each WITH-TEST-PREFIX postpends |
|
| 168 |
;;;; a new element to the current prefix: |
|
| 169 |
;;;; |
|
| 170 |
;;;; (with-test-prefix "arithmetic" |
|
| 171 |
;;;; (with-test-prefix "addition" |
|
| 172 |
;;;; (pass-if "integer" (= (+ 2 2) 4)) |
|
| 173 |
;;;; (pass-if "complex" (= (+ 2+3i 4+5i) 6+8i))) |
|
| 174 |
;;;; (with-test-prefix "subtraction" |
|
| 175 |
;;;; (pass-if "integer" (= (- 2 2) 0)) |
|
| 176 |
;;;; (pass-if "complex" (= (- 2+3i 1+2i) 1+1i)))) |
|
| 177 |
;;;; |
|
| 178 |
;;;; The four test names here are: |
|
| 179 |
;;;; ("arithmetic" "addition" "integer")
|
|
| 180 |
;;;; ("arithmetic" "addition" "complex")
|
|
| 181 |
;;;; ("arithmetic" "subtraction" "integer")
|
|
| 182 |
;;;; ("arithmetic" "subtraction" "complex")
|
|
| 183 |
;;;; |
|
| 184 |
;;;; To print a name for a human reader, we DISPLAY its elements, |
|
| 185 |
;;;; separated by ": ". So, the last set of test names would be |
|
| 186 |
;;;; reported as: |
|
| 187 |
;;;; |
|
| 188 |
;;;; arithmetic: addition: integer |
|
| 189 |
;;;; arithmetic: addition: complex |
|
| 190 |
;;;; arithmetic: subtraction: integer |
|
| 191 |
;;;; arithmetic: subtraction: complex |
|
| 192 |
;;;; |
|
| 193 |
;;;; The Guile benchmarks use with-test-prefix to include the name of |
|
| 194 |
;;;; the source file containing the test in the test name, to help |
|
| 195 |
;;;; developers to find failing tests, and to provide each file with its |
|
| 196 |
;;;; own namespace. |
|
| 197 |
|
|
| 198 |
|
|
| 199 |
;;;; REPORTERS |
|
| 200 |
;;;; |
|
| 201 |
;;;; A reporter is a function which we apply to each test outcome. |
|
| 202 |
;;;; Reporters can log results, print interesting results to the |
|
| 203 |
;;;; standard output, collect statistics, etc. |
|
| 204 |
;;;; |
|
| 205 |
;;;; A reporter function takes two mandatory arguments, RESULT and TEST, and |
|
| 206 |
;;;; possibly additional arguments depending on RESULT; its return value |
|
| 207 |
;;;; is ignored. RESULT has one of the following forms: |
|
| 208 |
;;;; |
|
| 209 |
;;;; pass - The test named TEST passed. |
|
| 210 |
;;;; Additional arguments are ignored. |
|
| 211 |
;;;; upass - The test named TEST passed unexpectedly. |
|
| 212 |
;;;; Additional arguments are ignored. |
|
| 213 |
;;;; fail - The test named TEST failed. |
|
| 214 |
;;;; Additional arguments are ignored. |
|
| 215 |
;;;; xfail - The test named TEST failed, as expected. |
|
| 216 |
;;;; Additional arguments are ignored. |
|
| 217 |
;;;; unresolved - The test named TEST did not perform as expected, for |
|
| 218 |
;;;; example the property that was to be tested could not be |
|
| 219 |
;;;; tested because something else went wrong. |
|
| 220 |
;;;; Additional arguments are ignored. |
|
| 221 |
;;;; untested - The test named TEST was not actually performed, for |
|
| 222 |
;;;; example because the test case is not complete yet. |
|
| 223 |
;;;; Additional arguments are ignored. |
|
| 224 |
;;;; unsupported - The test named TEST requires some feature that is not |
|
| 225 |
;;;; available in the configured testing environment. |
|
| 226 |
;;;; Additional arguments are ignored. |
|
| 227 |
;;;; error - An error occurred while the test named TEST was |
|
| 228 |
;;;; performed. Since this result means that the system caught |
|
| 229 |
;;;; an exception it could not handle, the exception arguments |
|
| 230 |
;;;; are passed as additional arguments. |
|
| 231 |
;;;; |
|
| 232 |
;;;; This library provides some standard reporters for logging results |
|
| 233 |
;;;; to a file, reporting interesting results to the user, and |
|
| 234 |
;;;; collecting totals. |
|
| 235 |
;;;; |
|
| 236 |
;;;; You can use the REGISTER-REPORTER function and friends to add |
|
| 237 |
;;;; whatever reporting functions you like. If you don't register any |
|
| 238 |
;;;; reporters, the library uses FULL-REPORTER, which simply writes |
|
| 239 |
;;;; all results to the standard output. |
|
| 240 |
|
|
| 241 |
|
|
| 242 |
;;;; MISCELLANEOUS |
|
| 243 |
;;;; |
|
| 244 |
|
|
| 245 |
;;; Define some exceptions which are commonly being tested for. |
|
| 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:miscellaneous-error |
|
| 267 |
(cons 'misc-error "^.*")) |
|
| 268 |
|
|
| 269 |
;; as per throw in scm_to_locale_stringn() |
|
| 270 |
(define exception:string-contains-nul |
|
| 271 |
(cons 'misc-error "^string contains #\\\\nul character")) |
|
| 272 |
|
|
| 273 |
|
|
| 274 |
;;; Display all parameters to the default output port, followed by a newline. |
|
| 275 |
(define (display-line . objs) |
|
| 276 |
(for-each display objs) |
|
| 277 |
(newline)) |
|
| 278 |
|
|
| 279 |
;;; Display all parameters to the given output port, followed by a newline. |
|
| 280 |
(define (display-line-port port . objs) |
|
| 281 |
(for-each (lambda (obj) (display obj port)) objs) |
|
| 282 |
(newline port)) |
|
| 283 |
|
|
| 284 |
|
|
| 285 |
;;;; CORE FUNCTIONS |
|
| 286 |
;;;; |
|
| 287 |
|
|
| 288 |
;;; The central testing routine. |
|
| 289 |
;;; The idea is taken from Greg, the GNUstep regression test environment. |
|
| 290 |
(define run-test #f) |
|
| 291 |
(let ((test-running #f)) |
|
| 292 |
(define (local-run-test name expect-pass thunk) |
|
| 293 |
(if test-running |
|
| 294 |
(error "Nested calls to run-test are not permitted.") |
|
| 295 |
(let ((test-name (full-name name))) |
|
| 296 |
(set! test-running #t) |
|
| 297 |
(catch #t |
|
| 298 |
(lambda () |
|
| 299 |
(let ((result (thunk))) |
|
| 300 |
(if (eq? result #t) (throw 'pass)) |
|
| 301 |
(if (eq? result #f) (throw 'fail)) |
|
| 302 |
(throw 'unresolved))) |
|
| 303 |
(lambda (key . args) |
|
| 304 |
(case key |
|
| 305 |
((pass) |
|
| 306 |
(report (if expect-pass 'pass 'upass) test-name)) |
|
| 307 |
((fail) |
|
| 308 |
(report (if expect-pass 'fail 'xfail) test-name)) |
|
| 309 |
((unresolved untested unsupported) |
|
| 310 |
(report key test-name)) |
|
| 311 |
((quit) |
|
| 312 |
(report 'unresolved test-name) |
|
| 313 |
(quit)) |
|
| 314 |
(else |
|
| 315 |
(report 'error test-name (cons key args)))))) |
|
| 316 |
(set! test-running #f)))) |
|
| 317 |
(set! run-test local-run-test)) |
|
| 318 |
|
|
| 319 |
;;; A short form for tests that are expected to pass, taken from Greg. |
|
| 320 |
(defmacro pass-if (name . rest) |
|
| 321 |
(if (and (null? rest) (pair? name)) |
|
| 322 |
;; presume this is a simple test, i.e. (pass-if (even? 2)) |
|
| 323 |
;; where the body should also be the name. |
|
| 324 |
`(run-test ',name #t (lambda () ,name)) |
|
| 325 |
`(run-test ,name #t (lambda () ,@rest)))) |
|
| 326 |
|
|
| 327 |
;;; A short form for tests that are expected to fail, taken from Greg. |
|
| 328 |
(defmacro expect-fail (name . rest) |
|
| 329 |
(if (and (null? rest) (pair? name)) |
|
| 330 |
;; presume this is a simple test, i.e. (expect-fail (even? 2)) |
|
| 331 |
;; where the body should also be the name. |
|
| 332 |
`(run-test ',name #f (lambda () ,name)) |
|
| 333 |
`(run-test ,name #f (lambda () ,@rest)))) |
|
| 334 |
|
|
| 335 |
;;; A helper function to implement the macros that test for exceptions. |
|
| 336 |
(define (run-test-exception name exception expect-pass thunk) |
|
| 337 |
(run-test name expect-pass |
|
| 338 |
(lambda () |
|
| 339 |
(stack-catch (car exception) |
|
| 340 |
(lambda () (thunk) #f) |
|
| 341 |
(lambda (key proc message . rest) |
|
| 342 |
(cond |
|
| 343 |
;; handle explicit key |
|
| 344 |
((string-match (cdr exception) message) |
|
| 345 |
#t) |
|
| 346 |
;; handle `(error ...)' which uses `misc-error' for key and doesn't |
|
| 347 |
;; yet format the message and args (we have to do it here). |
|
| 348 |
((and (eq? 'misc-error (car exception)) |
|
| 349 |
(list? rest) |
|
| 350 |
(string-match (cdr exception) |
|
| 351 |
(apply simple-format #f message (car rest)))) |
|
| 352 |
#t) |
|
| 353 |
;; handle syntax errors which use `syntax-error' for key and don't |
|
| 354 |
;; yet format the message and args (we have to do it here). |
|
| 355 |
((and (eq? 'syntax-error (car exception)) |
|
| 356 |
(list? rest) |
|
| 357 |
(string-match (cdr exception) |
|
| 358 |
(apply simple-format #f message (car rest)))) |
|
| 359 |
#t) |
|
| 360 |
;; unhandled; throw again |
|
| 361 |
(else |
|
| 362 |
(apply throw key proc message rest)))))))) |
|
| 363 |
|
|
| 364 |
;;; A short form for tests that expect a certain exception to be thrown. |
|
| 365 |
(defmacro pass-if-exception (name exception body . rest) |
|
| 366 |
`(,run-test-exception ,name ,exception #t (lambda () ,body ,@rest))) |
|
| 367 |
|
|
| 368 |
;;; A short form for tests expected to fail to throw a certain exception. |
|
| 369 |
(defmacro expect-fail-exception (name exception body . rest) |
|
| 370 |
`(,run-test-exception ,name ,exception #f (lambda () ,body ,@rest))) |
|
| 371 |
|
|
| 372 |
|
|
| 373 |
;;;; TEST NAMES |
|
| 374 |
;;;; |
|
| 375 |
|
|
| 376 |
;;;; Turn a test name into a nice human-readable string. |
|
| 377 |
(define (format-test-name name) |
|
| 378 |
(call-with-output-string |
|
| 379 |
(lambda (port) |
|
| 380 |
(let loop ((name name) |
|
| 381 |
(separator "")) |
|
| 382 |
(if (pair? name) |
|
| 383 |
(begin |
|
| 384 |
(display separator port) |
|
| 385 |
(display (car name) port) |
|
| 386 |
(loop (cdr name) ": "))))))) |
|
| 387 |
|
|
| 388 |
;;;; For a given test-name, deliver the full name including all prefixes. |
|
| 389 |
(define (full-name name) |
|
| 390 |
(append (current-test-prefix) (list name))) |
|
| 391 |
|
|
| 392 |
;;; A fluid containing the current test prefix, as a list. |
|
| 393 |
(define prefix-fluid (make-fluid)) |
|
| 394 |
(fluid-set! prefix-fluid '()) |
|
| 395 |
(define (current-test-prefix) |
|
| 396 |
(fluid-ref prefix-fluid)) |
|
| 397 |
|
|
| 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 |
|
|
| 406 |
;;; (with-test-prefix PREFIX BODY ...) |
|
| 407 |
;;; Postpend PREFIX to the current name prefix while evaluating BODY ... |
|
| 408 |
;;; The name prefix is only changed within the dynamic scope of the |
|
| 409 |
;;; with-test-prefix expression. Return the value returned by the last |
|
| 410 |
;;; BODY expression. |
|
| 411 |
(defmacro with-test-prefix (prefix . body) |
|
| 412 |
`(with-test-prefix* ,prefix (lambda () ,@body))) |
|
| 413 |
|
|
| 414 |
;;; Call THUNK using the debugging evaluator. |
|
| 415 |
(define (with-debugging-evaluator* thunk) |
|
| 416 |
(let ((dopts #f)) |
|
| 417 |
(dynamic-wind |
|
| 418 |
(lambda () |
|
| 419 |
(set! dopts (debug-options)) |
|
| 420 |
(debug-enable 'debug)) |
|
| 421 |
thunk |
|
| 422 |
(lambda () |
|
| 423 |
(debug-options dopts))))) |
|
| 424 |
|
|
| 425 |
;;; Evaluate BODY... using the debugging evaluator. |
|
| 426 |
(define-macro (with-debugging-evaluator . body) |
|
| 427 |
`(with-debugging-evaluator* (lambda () ,@body))) |
|
| 428 |
|
|
| 429 |
|
|
| 430 |
|
|
Also available in: Unified diff