Skip to content

Commit 3b5a202

Browse files
committed
Migrated collatz-conjecture to new test system.
1 parent 659ea8b commit 3b5a202

File tree

2 files changed

+169
-125
lines changed

2 files changed

+169
-125
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
(import (except (rnrs) current-output-port))
2+
3+
(define test-fields '(input expected actual))
4+
5+
(define (test-run-solution solution input)
6+
(if (procedure? solution) (apply solution input) solution))
7+
8+
(define (scheme->string o)
9+
(with-output-to-string
10+
(lambda ()
11+
(write o))))
12+
13+
(define (process-condition e)
14+
(if (not (condition? e)) e
15+
`(error
16+
,(if (who-condition? e) (condition-who e)
17+
'unknown)
18+
,(condition-message e)
19+
,@(if (not (irritants-condition? e)) '()
20+
(condition-irritants e)))))
21+
22+
(define (test-success description success-predicate
23+
procedure input expected code)
24+
(call/cc
25+
(lambda (k)
26+
(let ([out (open-output-string)])
27+
(dynamic-wind
28+
(lambda () (set! out (open-output-string)))
29+
(lambda ()
30+
(with-exception-handler
31+
(lambda (e)
32+
(k `(fail
33+
(description . ,description)
34+
(code . ,code)
35+
(input . ,input)
36+
(expected . ,expected)
37+
(actual . ,(process-condition e))
38+
(stdout . ,(get-output-string out)))))
39+
(lambda ()
40+
(let ([result (parameterize ([current-output-port out])
41+
(test-run-solution procedure input))])
42+
(unless (success-predicate result expected)
43+
(raise result))
44+
`(pass
45+
(description . ,description)
46+
(code . ,code)
47+
(stdout . ,(get-output-string out)))))))
48+
(lambda () (close-output-port out)))))))
49+
50+
(define (test-error description procedure input code)
51+
(call/cc
52+
(lambda (k)
53+
(let ([out '()])
54+
(dynamic-wind
55+
(lambda () (set! out (open-output-string)))
56+
(lambda ()
57+
(with-exception-handler
58+
(lambda (e)
59+
(k `(pass
60+
(description . ,description)
61+
(code . ,code)
62+
(stdout . ,(get-output-string out)))))
63+
(lambda ()
64+
(let ((result (parameterize ([current-output-port out])
65+
(test-run-solution procedure input))))
66+
`(fail
67+
(description . ,description)
68+
(code . ,code)
69+
(input . ,input)
70+
(expected . error)
71+
(actual . ,result)
72+
(stdout . ,(get-output-string out)))))))
73+
(lambda () (close-output-port out)))))))
74+
75+
(define (run-test test)
76+
(eval (append test `((quote ,test))) (interaction-environment)))
77+
78+
(define (run-test-suite tests . query)
79+
(for-each
80+
(lambda (field)
81+
(unless (and (symbol? field) (memq field test-fields))
82+
(error 'run-test-suite
83+
(format #t "~a not in ~a" field test-fields))))
84+
query)
85+
(let-values ([(passes failures)
86+
(partition
87+
(lambda (result) (eq? 'pass (car result)))
88+
(map run-test tests))])
89+
(cond
90+
[(null? failures) (format #t "~%Well done!~%~%")]
91+
[else
92+
(format
93+
#t
94+
"~%Passed ~a/~a tests.~%~%The following test cases failed:~%~%"
95+
(length passes)
96+
(length tests))
97+
(for-each
98+
(lambda (failure)
99+
(format
100+
#t
101+
"* ~a~%"
102+
(cond
103+
[(assoc 'description (cdr failure)) => cdr]
104+
[else (cdr failure)]))
105+
(for-each
106+
(lambda (field)
107+
(let ([info (assoc field (cdr failure))])
108+
(display " - ")
109+
(write (car info))
110+
(display ": ")
111+
(write (cdr info))
112+
(newline)))
113+
query))
114+
failures)
115+
(error 'test "incorrect solution")])))
116+
117+
118+
(define (run-docker suite)
119+
(write (map run-test suite)))
120+
121+
(define (test suite . query)
122+
(apply run-test-suite suite query))
123+
124+
(define (tests suites . query)
125+
(for-each (lambda (suite) (apply test suite query)) suites))
126+
127+
(define (run-with-cli solution suites)
128+
(let ((args (command-line)))
129+
(cond
130+
;; Normal execution. This is the default behavior used by students
131+
;; running their tests locally.
132+
[(null? (cdr args))
133+
(load solution)
134+
(tests suites 'input 'expected 'actual)]
135+
;; Scheme programs ingesting this output can expect an alist with
136+
;; the keys 'test-lib-version and 'status. No test-lib version
137+
;; means an older version of these test utilities is in use, so there
138+
;; will only be pass/fail lists in the output. When status is 'error,
139+
;; A message is provided for explanation. It is usually a stringified
140+
;; condition. When status is 'completed everything is normal, and the
141+
;; rest of the list comsists of pass/fail lists.
142+
[(string=? (cadr args) "--docker")
143+
(write
144+
`((test-lib-version . 1)
145+
,@(call/cc
146+
(lambda (k)
147+
(with-exception-handler
148+
;; Catch failures while loading/compiling the solution.
149+
(lambda (e)
150+
(k `((status . error)
151+
(message
152+
. ,(string-append
153+
"Failed with value: "
154+
(scheme->string (process-condition e)))))))
155+
(lambda ()
156+
(load solution)
157+
`((status . ok)
158+
,@(fold-left (lambda (results suite)
159+
(append results (map run-test suite)))
160+
'() suites))))))))]
161+
;; You can pass the name of a file to load instead of the "expected" solution filename.
162+
[else (load (cadr args)) (tests suites 'input 'expected)])))
Lines changed: 7 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,10 @@
1-
(import (except (rnrs) current-output-port))
2-
3-
(define test-fields '(input output))
4-
5-
(define (test-run-solution solution input)
6-
(if (procedure? solution) (apply solution input) solution))
7-
8-
(define (test-success description success-predicate
9-
procedure input output)
10-
(call/cc
11-
(lambda (k)
12-
(let ([out (open-output-string)])
13-
(with-exception-handler
14-
(lambda (e)
15-
(let ([result `(fail
16-
(description . ,description)
17-
(input . ,input)
18-
(output . ,output)
19-
(stdout . ,(get-output-string out)))])
20-
(close-output-port out)
21-
(k result)))
22-
(lambda ()
23-
(let ([result (parameterize ([current-output-port out])
24-
(test-run-solution procedure input))])
25-
(unless (success-predicate result output)
26-
(error 'exercism-test
27-
"test fails"
28-
description
29-
input
30-
result
31-
output)))
32-
(let ([result `(pass
33-
(description . ,description)
34-
(stdout . ,(get-output-string out)))])
35-
(close-output-port out)
36-
result)))))))
37-
38-
(define (test-error description procedure input)
39-
(call/cc
40-
(lambda (k)
41-
(let ([out (open-output-string)])
42-
(with-exception-handler
43-
(lambda (e)
44-
(let ([result `(pass
45-
(description . ,description)
46-
(stdout . ,(get-output-string out)))])
47-
(close-output-port out)
48-
(k result)))
49-
(lambda ()
50-
(parameterize ([current-output-port out])
51-
(test-run-solution procedure input))
52-
(let ([result `(fail
53-
(description . ,description)
54-
(input . ,input)
55-
(output . error)
56-
(stdout . ,(get-output-string out)))])
57-
(close-output-port out)
58-
result)))))))
59-
60-
(define (run-test-suite tests . query)
61-
(for-each
62-
(lambda (field)
63-
(unless (and (symbol? field) (memq field test-fields))
64-
(error 'run-test-suite
65-
(format #t "~a not in ~a" field test-fields))))
66-
query)
67-
(let-values ([(passes failures)
68-
(partition
69-
(lambda (result) (eq? 'pass (car result)))
70-
(map (lambda (test) (test)) tests))])
71-
(cond
72-
[(null? failures) (format #t "~%Well done!~%~%")]
73-
[else
74-
(format
75-
#t
76-
"~%Passed ~a/~a tests.~%~%The following test cases failed:~%~%"
77-
(length passes)
78-
(length tests))
79-
(for-each
80-
(lambda (failure)
81-
(format
82-
#t
83-
"* ~a~%"
84-
(cond
85-
[(assoc 'description (cdr failure)) => cdr]
86-
[else (cdr failure)]))
87-
(for-each
88-
(lambda (field)
89-
(let ([info (assoc field (cdr failure))])
90-
(display " - ")
91-
(write (car info))
92-
(display ": ")
93-
(write (cdr info))
94-
(newline)))
95-
query))
96-
failures)
97-
(error 'test "incorrect solution")])))
98-
99-
(define (run-docker test-cases)
100-
(write (map (lambda (test) (test)) test-cases)))
101-
102-
(define collatz)
1+
(load "test-util.ss")
1032

1043
(define test-cases
105-
(list
106-
(lambda ()
107-
(test-success "zero steps for one" = collatz '(1) 0))
108-
(lambda ()
109-
(test-success "divide if even" = collatz '(16) 4))
110-
(lambda ()
111-
(test-success "even and odd steps" = collatz '(12) 9))
112-
(lambda ()
113-
(test-success "large number of even and odd steps" = collatz
114-
'(1000000) 152))))
115-
116-
(define (test . query)
117-
(apply run-test-suite test-cases query))
118-
119-
(let ([args (command-line)])
120-
(cond
121-
[(null? (cdr args))
122-
(load "collatz-conjecture.scm")
123-
(test 'input 'output)]
124-
[(string=? (cadr args) "--docker")
125-
(load "collatz-conjecture.scm")
126-
(run-docker test-cases)]
127-
[else (load (cadr args)) (test 'input 'output)]))
4+
`((test-success "zero steps for one" = collatz '(1) 0)
5+
(test-success "divide if even" = collatz '(16) 4)
6+
(test-success "even and odd steps" = collatz '(12) 9)
7+
(test-success "large number of even and odd steps" = collatz
8+
'(1000000) 152)))
1289

10+
(run-with-cli "collatz-conjecture.scm" `(,test-cases))

0 commit comments

Comments
 (0)