Skip to content

Commit f590b48

Browse files
committed
Implement simple unit test framework.
1 parent 79bc854 commit f590b48

File tree

2 files changed

+228
-0
lines changed

2 files changed

+228
-0
lines changed

LispKit.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
CC96D10520386A40006AA27B /* 151.sld in Copy pre-installed SRFI libraries */ = {isa = PBXBuildFile; fileRef = CC96D10420386860006AA27B /* 151.sld */; };
140140
CC96D1072038AC59006AA27B /* 145.sld in Copy pre-installed SRFI libraries */ = {isa = PBXBuildFile; fileRef = CC96D1062038AAB4006AA27B /* 145.sld */; };
141141
CC96D1092038B17A006AA27B /* 137.sld in Copy pre-installed SRFI libraries */ = {isa = PBXBuildFile; fileRef = CC96D1082038AEC1006AA27B /* 137.sld */; };
142+
CC96D10B203997F0006AA27B /* test.sld in Copy pre-installed LispKit libraries */ = {isa = PBXBuildFile; fileRef = CC96D10A20399770006AA27B /* test.sld */; };
142143
CC97FA161CFA515E0008596E /* Definitions.scm in Resources */ = {isa = PBXBuildFile; fileRef = CC97FA151CFA51520008596E /* Definitions.scm */; };
143144
CC98B4571EBD43C900BCD049 /* NumberKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CC5C713E1EBD3D3A00280CF4 /* NumberKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
144145
CC98B4581EBD43E500BCD049 /* NumberKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CC5C713E1EBD3D3A00280CF4 /* NumberKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -265,6 +266,7 @@
265266
dstPath = LispKit/Resources/Libraries/lispkit;
266267
dstSubfolderSpec = 7;
267268
files = (
269+
CC96D10B203997F0006AA27B /* test.sld in Copy pre-installed LispKit libraries */,
268270
CC436C401FFBD52F0095559E /* logic.sld in Copy pre-installed LispKit libraries */,
269271
CC90B2361FE5D7BC0044F724 /* queue.sld in Copy pre-installed LispKit libraries */,
270272
CC90B2341FE55E8B0044F724 /* stack.sld in Copy pre-installed LispKit libraries */,
@@ -513,6 +515,7 @@
513515
CC96D10420386860006AA27B /* 151.sld */ = {isa = PBXFileReference; lastKnownFileType = text; path = 151.sld; sourceTree = "<group>"; };
514516
CC96D1062038AAB4006AA27B /* 145.sld */ = {isa = PBXFileReference; lastKnownFileType = text; path = 145.sld; sourceTree = "<group>"; };
515517
CC96D1082038AEC1006AA27B /* 137.sld */ = {isa = PBXFileReference; lastKnownFileType = text; path = 137.sld; sourceTree = "<group>"; };
518+
CC96D10A20399770006AA27B /* test.sld */ = {isa = PBXFileReference; lastKnownFileType = text; path = test.sld; sourceTree = "<group>"; };
516519
CC97FA151CFA51520008596E /* Definitions.scm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Definitions.scm; sourceTree = "<group>"; };
517520
CC98B4591EBD444400BCD049 /* NumberKit.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = NumberKit.framework.dSYM; path = Carthage/Build/Mac/NumberKit.framework.dSYM; sourceTree = "<group>"; };
518521
CC9EB1141F5C9D4000697511 /* Topological.scm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Topological.scm; sourceTree = "<group>"; };
@@ -678,6 +681,7 @@
678681
CC5847FE1E506D7400BE6497 /* lispkit */ = {
679682
isa = PBXGroup;
680683
children = (
684+
CC96D10A20399770006AA27B /* test.sld */,
681685
CC2345401F655B8B00C38817 /* datatype.sld */,
682686
CC68B3A81FCC73C300EB4AF9 /* object.sld */,
683687
CCD6C3E81F35F95D0002F7D4 /* enum.sld */,
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
;;; LISPKIT TEST
2+
;;;
3+
;;; Simple framework for implementing and running simple test suites. This is derived from
4+
;;; similar, but much more sophisticated facilities from Chicken and Chibi scheme.
5+
;;;
6+
;;; Some of this code was originally implemented by Alex Shinn for his matching library.
7+
;;; Copyright © 2010-2014 Alex Shinn. All rights reserved.
8+
;;; BSD-style license: http://synthcode.com/license.txt
9+
;;;
10+
;;; Author: Matthias Zenger
11+
;;; Copyright © 2018 Matthias Zenger. All rights reserved.
12+
;;;
13+
;;; Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
14+
;;; except in compliance with the License. You may obtain a copy of the License at
15+
;;;
16+
;;; http://www.apache.org/licenses/LICENSE-2.0
17+
;;;
18+
;;; Unless required by applicable law or agreed to in writing, software distributed under the
19+
;;; License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
20+
;;; either express or implied. See the License for the specific language governing permissions
21+
;;; and limitations under the License.
22+
23+
(define-library (lispkit test)
24+
25+
(export test-begin
26+
test-end
27+
test
28+
test-equal
29+
test-assert
30+
test-error
31+
test-group
32+
approx-equal?)
33+
34+
(import (lispkit base))
35+
36+
(begin
37+
38+
(define tests-passed 0)
39+
(define tests-failed 0)
40+
(define tests-start-time 0)
41+
(define internal-fail-token (gensym))
42+
43+
(define (test-begin)
44+
(set! tests-passed 0)
45+
(set! tests-failed 0)
46+
(set! tests-start-time (current-second)))
47+
48+
(define (test-end)
49+
(let ((end (current-second))
50+
(total (+ tests-passed tests-failed)))
51+
(newline)
52+
(display "")
53+
(display total)
54+
(display " tests completed in ")
55+
(display (format-float (inexact (/ (- end tests-start-time) 1000)) 3))
56+
(display " seconds")
57+
(newline)
58+
(display "")
59+
(display tests-passed)
60+
(display " (")
61+
(display (format-percent tests-passed total))
62+
(display "%) tests passed")
63+
(newline)
64+
(display "")
65+
(display tests-failed)
66+
(display " (")
67+
(display (format-percent tests-failed total))
68+
(display "%) tests failed")
69+
(newline)))
70+
71+
(define (test-failures) tests-failed)
72+
73+
(define (format-result spec name expect result)
74+
(do ((ls spec (cdr ls)))
75+
((null? ls) (newline))
76+
(cond ((eq? (car ls) 'expect)
77+
(write expect))
78+
((eq? (car ls) 'result)
79+
(write result))
80+
((eq? (car ls) 'name)
81+
(if name (begin (display #\space) (display name))))
82+
(else
83+
(display (car ls))))))
84+
85+
(define (format-float n prec)
86+
(let* ((str (number->string n))
87+
(len (string-length str)))
88+
(let lp ((i (- len 1)))
89+
(cond ((negative? i)
90+
(string-append str "." (make-string prec #\0)))
91+
((eqv? #\. (string-ref str i))
92+
(let ((diff (+ 1 (- prec (- len i)))))
93+
(cond ((positive? diff)
94+
(string-append str (make-string diff #\0)))
95+
((negative? diff)
96+
(substring str 0 (+ i prec 1)))
97+
(else
98+
str))))
99+
(else
100+
(lp (- i 1)))))))
101+
102+
(define (format-percent num denom)
103+
(let ((x (if (zero? denom) num (inexact (/ num denom)))))
104+
(format-float (* 100 x) 2)))
105+
106+
(define (run-test name thunk expect eq pass-msg fail-msg)
107+
(let ((result (thunk)))
108+
(cond ((eq expect result)
109+
(set! tests-passed (+ tests-passed 1))
110+
(format-result pass-msg name expect result))
111+
(else
112+
(set! tests-failed (+ tests-failed 1))
113+
(format-result fail-msg name expect result)))))
114+
115+
(define (run-equal name thunk expect eq)
116+
(run-test name
117+
thunk
118+
expect
119+
eq
120+
'("[PASS]" name)
121+
(if (eq? expect #t)
122+
'("[FAIL]" name ": received " result)
123+
'("[FAIL]" name ": expected " expect " but received " result))))
124+
125+
(define-syntax test
126+
(syntax-rules (quote)
127+
((_ expect expr)
128+
(test (write-to-string 'expr) expect expr))
129+
((_ name expect (expr ...))
130+
(test-equal name expect (expr ...) equal?))
131+
((_ name (quote expect) expr)
132+
(test-equal name (quote expect) expr equal?))
133+
((_ name (expect ...) expr)
134+
(syntax-error "the test expression should come last: (test <expected> (<expr> ...))"
135+
'(test name (expect ...) expr)))
136+
((_ name expect expr)
137+
(test-equal name expect expr equal?))
138+
((_ a ...)
139+
(syntax-error "a test requires 2 or 3 arguments" '(test a ...)))))
140+
141+
(define-syntax test-equal
142+
(syntax-rules ()
143+
((_ name value expr eq)
144+
(run-equal name (lambda () expr) value eq))
145+
((_ name value expr)
146+
(run-equal name (lambda () expr) value equal?))
147+
((_ value expr)
148+
(test-equal (write-to-string 'expr) value expr))))
149+
150+
(define-syntax test-assert
151+
(syntax-rules ()
152+
((_ name expr)
153+
(run-equal name (lambda () (if expr #t #f)) #t eq?))
154+
((_ expr)
155+
(test-assert (write-to-string 'expr) expr))))
156+
157+
(define-syntax test-error
158+
(syntax-rules ()
159+
((_ name expr)
160+
(run-equal name
161+
(lambda () (with-exception-handler (lambda (e) internal-fail-token)
162+
(lambda () expr)))
163+
internal-fail-token
164+
eq?))
165+
((_ expr)
166+
(test-error (write-to-string 'expr) expr))))
167+
168+
(define-syntax test-group
169+
(syntax-rules ()
170+
((_ name body ...)
171+
(begin
172+
(newline)
173+
(display name)
174+
(display ":")
175+
(newline)
176+
body ...))))
177+
178+
(define (approx-equal? a b epsilon)
179+
(cond ((> (abs a) (abs b))
180+
(approx-equal? b a epsilon))
181+
((zero? a)
182+
(< (abs b) epsilon))
183+
(else
184+
(< (abs (/ (- a b) b)) epsilon))))
185+
186+
(define (call-with-output-string proc)
187+
(let ((out (open-output-string)))
188+
(proc out)
189+
(get-output-string out)))
190+
191+
(define (write-to-string x)
192+
(call-with-output-string
193+
(lambda (out)
194+
(let wr ((x x))
195+
(if (pair? x)
196+
(cond ((and (symbol? (car x))
197+
(pair? (cdr x))
198+
(null? (cddr x))
199+
(assq (car x) '((quote . "'")
200+
(quasiquote . "`")
201+
(unquote . ",")
202+
(unquote-splicing . ",@"))))
203+
=> (lambda (s) (display (cdr s) out) (wr (cadr x))))
204+
(else
205+
(display "(" out)
206+
(wr (car x))
207+
(let lp ((ls (cdr x)))
208+
(cond ((pair? ls)
209+
(display " " out)
210+
(wr (car ls))
211+
(lp (cdr ls)))
212+
((not (null? ls))
213+
(display " . " out)
214+
(write ls out))))
215+
(display ")" out)))
216+
(write x out))))))
217+
218+
(define (display-to-string x)
219+
(if (string? x)
220+
x
221+
(call-with-output-string (lambda (out) (display x out)))))
222+
)
223+
)
224+

0 commit comments

Comments
 (0)