214 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Scheme
		
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Scheme
		
	
	
	
| ;;; 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*)))))
 |