File: test.scm

package info (click to toggle)
chicken 5.3.0-2
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 32,892 kB
  • sloc: ansic: 580,083; lisp: 71,987; tcl: 1,445; sh: 588; makefile: 60
file content (148 lines) | stat: -rw-r--r-- 4,777 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
;;;; test.scm - minimal testing framework
;
; by Alex Shinn, lifted from match-test by felix

(import (only chicken.string ->string))
(import (only chicken.time current-process-milliseconds))

(define *current-group-name* "")
(define *pass* 0)
(define *fail* 0)
(define *start* 0)
(define *total-pass* 0)
(define *total-fail* 0)
(define *total-start* 0)
(define *fail-token* (gensym))

(define (run-test name thunk expect eq pass-msg fail-msg)
  (let ((result (thunk)))
    (cond
      ((eq expect result)
       (set! *pass* (+ *pass* 1))
       (format-result pass-msg name expect result))
      (else
       (set! *fail* (+ *fail* 1))
       (format-result fail-msg name expect result)))))

(define (format-result ls name expect result)
  (let lp ((ls ls))
    (cond
      ((null? ls) (newline))
      ((eq? (car ls) 'expect) (write expect) (lp (cdr ls)))
      ((eq? (car ls) 'result) (write result) (lp (cdr ls)))
      ((eq? (car ls) 'name) (if name (begin (display #\space) (display name))) (lp (cdr ls)))
      (else (display (car ls)) (lp (cdr ls))))))

(define (test-begin . o)
  (set! *current-group-name* (if (null? o) "<unnamed>" (car o)))
  (print "== " *current-group-name* " ==")
  (set! *total-pass* (+ *total-pass* *pass*))
  (set! *total-fail* (+ *total-fail* *fail*))
  (set! *pass* 0)
  (set! *fail* 0)
  (set! *start* (current-process-milliseconds))
  (when (= 0 *total-start*)
    (set! *total-start* (current-process-milliseconds))))

(define (format-float n prec)
  (let* ((str (number->string n))
         (len (string-length str)))
    (let lp ((i (- len 1)))
      (cond
        ((negative? i)
         (string-append str "." (make-string prec #\0)))
        ((eqv? #\. (string-ref str i))
         (let ((diff (+ 1 (- prec (- len i)))))
           (cond
             ((positive? diff)
              (string-append str (make-string diff #\0)))
             ((negative? diff)
              (substring str 0 (+ i prec 1)))
             (else
              str))))
        (else
         (lp (- i 1)))))))

(define (format-percent num denom)
  (let ((x (if (zero? denom) num (exact->inexact (/ num denom)))))
    (format-float (* 100 x) 2)))

(define (test-end . o)
  (let ((end (current-process-milliseconds))
        (total (+ *pass* *fail*)))
    (print "  " total " tests completed in "
	   (format-float (exact->inexact (/ (- end *start*) 1000)) 3)
	   " seconds")
    (print "  " *pass* " ("
	   (format-percent *pass* total)
	   "%) tests passed")
    (print "  " *fail* " ("
	   (format-percent *fail* total)
	   "%) tests failed"))
    (print "-- " *current-group-name* " --\n\n"))

(define (test-exit . o)
  (print " TOTALS: ")
  (set! *total-pass* (+ *total-pass* *pass*)) ; should be 0
  (set! *total-fail* (+ *total-fail* *fail*)) ; should be 0
  (let ((end (current-process-milliseconds))
        (total (+ *total-pass* *total-fail*)))
    (print "  " total " tests completed in "
	   (format-float (exact->inexact (/ (- end *total-start*) 1000)) 3)
	   " seconds")
    (print "  " *total-pass* " ("
	   (format-percent *total-pass* total)
	   "%) tests passed")
    (print "  " *total-fail* " ("
	   (format-percent *total-fail* total)
	   "%) tests failed")
    (exit (if (zero? *total-fail*) 0 1))))

(define (run-equal name thunk expect eq)
  (run-test name thunk expect eq
            '("(PASS)" name)
            '("(FAIL)" name ": expected " expect " but got " result)))

(define current-test-epsilon (make-parameter 1e-5))

(define (approx-equal? a b epsilon)
  (cond
   ((> (abs a) (abs b)) (approx-equal? b a epsilon))
   ((zero? a) (< (abs b) epsilon))
   (else (< (abs (/ (- a b) b)) epsilon))))

(define (test-equal? expect res)
  (or (equal? expect res)
      (and (number? expect)
           (inexact? expect)
           (inexact? res)
           (approx-equal? expect res (current-test-epsilon)))))

(define current-test-comparator (make-parameter test-equal?))

(define-syntax test-equal
  (syntax-rules ()
    ((_ name expr value eq) (run-equal name (lambda () expr) value eq))
    ((_ name expr value) (run-equal name (lambda () expr) value (current-test-comparator)))
    ((_ expr value) (run-equal (->string 'expr) (lambda () expr) value (current-test-comparator)))))

(define-syntax test-error
  (syntax-rules ()
    ((_ name expr)
     (run-equal
      name
      (lambda () (handle-exceptions ex *fail-token* expr))
      *fail-token* eq?) )
    ((_ expr) (test-error 'expr expr))))

(define-syntax test-assert
  (syntax-rules ()
    ((_ name expr) (run-equal name (lambda () (if expr #t #f)) #t eq?))
    ((_ expr) (run-equal (->string expr) (lambda () (if expr #t #f)) #t eq?))))

(define-syntax test-group
  (syntax-rules ()
    ((_ name body ...)
     (begin
       (print "\n" name ":\n")
       body ...))))