scsh-0.6/scsh/test/test-base.scm

214 lines
6.3 KiB
Scheme
Raw Normal View History

;;; Basic functions for the scsh-test-suite
;;; Author: 2001 David Frese
;; --- The list to store the tests ---
(define *test-list* '())
;; --- add-test! ------------------------------------------------
;; This is the main function to add a test to the test-suite
;; name - a symbol naming the test uniquely
;; group - a symbol for the group of this test
;; proc - the function that does the test
;; args - the arguments for proc
;; add-test deletes all previously added tests that have the same
;; name (group is ignored)!
;; proc should return #f or signal an error, if the test failed.
;; Every other value means, that the test succeeded.
(define (add-test! name group proc . args)
(let ((test (make-testdt name group proc args)))
(let ((other (filter (lambda (test)
(equal? (testdt-name test)
name))
*test-list*)))
(for-each (lambda (test)
(set! *test-list* (delete! test *test-list*)))
other))
(set! *test-list* (cons test *test-list*))))
(define (find-test name)
(find (lambda (test)
(eq? (testdt-name test) name))
*test-list*))
;; --- add-test-multiple! ----------------------------------------
;; This function calls add-test! multiple times, with the same proc,
;; but different arguments.
;; name, group, proc see add-test! above
;; input-lists - each additional parameter has to be a list, specifying
;; alternative operands for proc.
;; Now add-test! is called for each permutation of input-lists.
;; If there's more than 1 permutation, the name is appended with
;; "-1"..."-n" respectively.
;; Example:
;; (add-test-multiple! 'test 'general proc '(a b) '(1 2))
;; results in 4 tests, that could have been generated with
;; (add-test 'test-1 'general proc 'a 1)
;; (add-test 'test-2 'general proc 'b 1)
;; (add-test 'test-3 'general proc 'a 2)
;; (add-test 'test-4 'general proc 'b 2)
;; Note: In future versions, these tests will run simultanously
;; with multi-threading.
(define (add-test-multiple! name group proc . input-lists)
(let* ((permutations (permute-lists input-lists))
(single? (and (not (null? permutations))
(null? (cdr permutations)))))
(let loop ((i 0)
(permutations permutations))
(if (not (null? permutations))
(let ((input-params (car permutations))
(new-name (if single?
name
(string->symbol (string-append
(symbol->string name)
"-"
(number->string i))))))
(apply add-test!
new-name
group
proc
input-params)
(loop (+ i 1) (cdr permutations)))))))
(define (permute-lists lists)
(cond
((null? lists) lists)
((null? (cdr lists)) (map list (car lists)))
(else
(let ((first-list (car lists))
(rest-perm (permute-lists (cdr lists))))
(fold-right (lambda (elem result)
(append
(map (lambda (new-param)
(cons new-param elem))
first-list)
result))
'()
rest-perm)))))
;; --- Functions for the test-datatype ---
(define-record-type testdt :testdt
(make-testdt name group proc args)
testdt?
(name testdt-name)
(group testdt-group)
(proc testdt-proc)
(args testdt-args))
;; --- Basic function to make a test ---
(define (run-test test . rest)
(let ((silent (if (null? rest) #f (car rest)))
(name (testdt-name test))
(group (testdt-group test))
(proc (testdt-proc test))
(args (testdt-args test)))
(let ((display-start (lambda ()
(display "Testing ")
(display group)
(display ":")
(display name)
(display " ... "))))
(if (not silent)
(display-start))
(call-with-current-continuation
(lambda (k)
(if (with-handler
(lambda (cond more)
(display "Error: ")
(display cond)
(newline)
(k #f))
(lambda ()
(apply proc args)))
(begin
(if silent
(display ".")
(display "OK\n"))
#t)
(begin
(if silent
(begin (newline)
(display-start)))
(display "Error! Input was ")
(display args)
(newline)
#f)))))))
;; --- Exported functions to make a test -------------------------------
;; The following 3 functions start the testing. They all have an
;; optional parameter >silent< with default #f. if silent is #t,
;; only those tests that signaled an error are printed on the screen.
;; test-single - runs the test with that name, returns the result of proc.
;; test-group - runs all tests that are part of that group. the result
;; is unspecified.
;; test-all - runs all tests in the test-suite.
(define (test-single name . rest)
(let ((test (find-test name)))
(if test
(apply run-test test rest)
(begin
(display "Test ") (display name)
(display " not found")
(newline)))))
(define (test-single/args name . args)
(let* ((test (find-test name))
(group (testdt-group test))
(proc (testdt-proc test)))
(run-test (apply make-testdt name group proc args))))
(define (test-group group . rest)
(let ((tests (filter (lambda (test)
(eq? (testdt-group test)
group))
*test-list*)))
(if (null? tests)
(begin
(display "Group ") (display group)
(display " doesn't contain any tests")
(newline))
(for-each (lambda (test)
(apply run-test
test rest))
tests))))
(define (test-all . rest)
(for-each (lambda (test)
(apply run-test
test rest))
*test-list*))
;; --- Summary functions -------------------------------------------
;; test-summary displays all registered tests in the test-suite, if
;; called with no arguments. Calling it with the additional parameter
;; group, displays only those tests that belong to that group.
(define (test-summary . rest)
(let ((group (if (null? rest) #f (car rest))))
(if group
(begin
(display "Listing group: ") (display group) (newline)
(for-each (lambda (test)
(if (eq? (testdt-group test) group)
(begin
(display (testdt-name test))
(newline))))
*test-list*))
(begin
(display "Listing all tests in format: group:name") (newline)
(for-each (lambda (test)
(display (testdt-group test))
(display ":")
(display (testdt-name test))
(newline))
*test-list*)))))