Skip to content

Commit 6eec4fc

Browse files
committed
add check-equal?/values and check-match/values
1 parent 5fc1ec7 commit 6eec4fc

4 files changed

Lines changed: 147 additions & 8 deletions

File tree

rackunit-doc/rackunit/scribblings/check.scrbl

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
#lang scribble/doc
22
@(require "base.rkt")
33

4-
@(require (for-label racket/match racket/flonum))
4+
@(require (for-label racket/match racket/flonum racket/list))
55

66
@(define rackunit-eval (make-base-eval))
7-
@(interaction-eval #:eval rackunit-eval (require rackunit racket/flonum))
7+
@(interaction-eval #:eval rackunit-eval (require rackunit racket/flonum racket/list))
88
@(interaction-eval #:eval rackunit-eval (error-print-context-length 0))
99

1010
@title{Checks}
@@ -17,7 +17,8 @@ check will report the failure using the current @tech{check-info stack}
1717

1818
Although checks are implemented as macros, which is
1919
necessary to grab source locations (see @secref{rackunit:custom-checks}), they are conceptually
20-
functions (with the exception of @racket[check-match] below).
20+
functions (with the exception of @racket[check-match], @racket[check-equal?/values], and
21+
@racket[check-match/values] below).
2122
This means, for instance, checks always evaluate
2223
their arguments. You can use a check as a first class
2324
function, though this will affect the source location that the check grabs.
@@ -250,6 +251,41 @@ This check fails because of a failure to match:
250251

251252
}
252253

254+
@defform[(check-equal?/values actual-expr expected-expr)]{
255+
256+
Like @racket[check-equal?], except handling multiple values.
257+
For the check to pass, the @racket[actual-expr] and
258+
@racket[expected-expr] must produce the same number of values
259+
and the two lists of values must be equal.
260+
261+
@interaction[#:eval rackunit-eval
262+
(check-equal?/values (quotient/remainder 67 12)
263+
(values 5 7))
264+
(check-equal?/values (split-at (list 'a 'b 'c 'd 'e) 2)
265+
(values (list 'a 'b)
266+
(list 'c 'd 'e)))
267+
]
268+
}
269+
270+
@defform*[#:literals (values)
271+
((check-match/values expr (values pattern ...))
272+
(check-match/values expr (values pattern ...) #:when pred)
273+
(check-match/values expr (values pattern ...) #:unless pred))]{
274+
275+
Like @racket[check-match], except handling multiple values.
276+
For the check to pass, the @racket[expr] must produce the same
277+
number of values as the number of @racket[pattern]s, each
278+
value must match the corresponding pattern, and the
279+
`#:when`/`#:unless` conditions must pass if they exist.
280+
281+
@interaction[#:eval rackunit-eval
282+
(check-match/values (split-at (list 1 3 4 6 8) 2)
283+
(values (list (? odd?) ...)
284+
(list (? even?) ...)))
285+
]
286+
}
287+
288+
253289

254290
@defproc[(check (op (-> any any any))
255291
(v1 any)

rackunit-lib/rackunit/private/check.rkt

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
check-not-eqv?
4343
check-not-equal?
4444
check-match
45+
check-equal?/values
46+
check-match/values
4547
fail)
4648

4749
(define current-check-handler (make-parameter display-test-failure/error))
@@ -231,8 +233,65 @@
231233
(make-check-actual actual-val)
232234
(make-check-expected 'expected))
233235
(lambda ()
234-
(check-true (match actual-val
235-
[expected pred]
236-
[_ #f]))))))]
236+
(check-not-false (match actual-val
237+
[expected pred]
238+
[_ #f]))))))]
237239
[(_ actual expected)
238240
(syntax/loc stx (check-match actual expected #t))]))
241+
242+
;; NOTE: Like check-match, the check-equal?/values and check-match/values forms
243+
;; do not evaluate their arguments like functions would, so they're defined
244+
;; with define-syntax instead
245+
(define-syntax check-equal?/values
246+
(lambda (stx)
247+
(syntax-case stx ()
248+
[(_ actual expected)
249+
(quasisyntax
250+
(let ([actual-lst (call-with-values (λ () actual) list)]
251+
[expected-lst (call-with-values (λ () expected) list)])
252+
(with-check-info*
253+
(list (make-check-name 'check-equal?/values)
254+
(make-check-location
255+
(syntax->location (quote-syntax #,(datum->syntax #f 'loc stx))))
256+
(make-check-expression '#,(syntax->datum stx))
257+
(make-check-actual (cons 'values (map printed actual-lst)))
258+
(make-check-expected (cons 'values (map printed expected-lst))))
259+
(lambda ()
260+
(check-equal? actual-lst expected-lst)))))])))
261+
262+
(define-syntax check-match/values
263+
(lambda (stx)
264+
(syntax-case stx (values)
265+
[(_ actual (values expected ...))
266+
(syntax/loc stx
267+
(check-match/values actual
268+
(values expected ...)
269+
#:when #t))]
270+
[(_ actual (values expected ...) #:unless unless-condition)
271+
(syntax/loc stx
272+
(check-match/values actual
273+
(values expected ...)
274+
#:when (not unless-condition)))]
275+
[(_ actual (values expected ...) #:when pred)
276+
(quasisyntax
277+
(let ([actual-lst (call-with-values (λ () actual) list)])
278+
(with-check-info*
279+
(list (make-check-name 'check-match/values)
280+
(make-check-location
281+
(syntax->location (quote-syntax #,(datum->syntax #f 'loc stx))))
282+
(make-check-expression '#,(syntax->datum stx))
283+
(make-check-actual (cons 'values (map printed actual-lst)))
284+
(make-check-expected '(values expected ...)))
285+
(lambda ()
286+
(check-not-false (match actual-lst
287+
[(list expected ...) pred]
288+
[_ #f]))))))])))
289+
290+
;; A helper struct for check-equal?/values and check-match/values
291+
(struct printed (val) #:transparent
292+
#:property prop:custom-write
293+
(lambda (this out mode)
294+
(if (integer? mode)
295+
(print (printed-val this) out mode)
296+
(print (printed-val this) out))))
297+

rackunit-lib/rackunit/private/test.rkt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@
112112
check-not-equal?
113113
check-regexp-match
114114
check-match
115+
check-equal?/values
116+
check-match/values
115117
fail)
116118

117119

rackunit-test/tests/rackunit/check-test.rkt

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,30 @@
138138
(check-match (data 1 2 (data 1 2 3))
139139
(data _ _ (data x y z))
140140
(equal? (+ x y z) 6))))
141-
141+
142+
(test-case "Trivial check-match/values test"
143+
(check-match/values "whatever" (values _)))
144+
145+
(test-case "Simple check-match/values test"
146+
(check-match/values (values 1 2 3) (values _ _ 3)))
147+
148+
(test-case "Using check-match/values with ellipses"
149+
(check-match/values (values 1 2 4 5)
150+
(values 1 (? even? es) ... 5)
151+
#:when (equal? (apply + es) 6)))
152+
153+
(test-case "check-match/values with nested struct"
154+
(let ()
155+
(struct data (f1 f2 f3))
156+
(define (f)
157+
(values (data 1 2 (data 1 2 3))
158+
(data 4 5 (data 6 7 8))))
159+
(check-match/values (f)
160+
(values (data _ 2 (data x y z))
161+
(data _ 5 (data a b c)))
162+
#:when (equal? (+ x y z a b c) 27))))
163+
164+
142165
;; Failures
143166
(make-failure-test "check-equal? failure"
144167
check-equal? 1 2)
@@ -180,12 +203,31 @@
180203
(hash 'a 3.0 'b 98.6)
181204
0.0)
182205

206+
207+
;; check-match
183208
(make-failure-test/stx "check-match failure pred"
184209
check-match 5 x (even? x))
185210

186211
(make-failure-test/stx "check-match failure match"
187212
check-match (list 4 5) (list _))
188-
213+
214+
;; check-match/values
215+
(make-failure-test/stx "check-match/values: wrong number of values"
216+
check-match/values (values 3 4) (values _))
217+
218+
(make-failure-test/stx "check-match/values: right number, one value wrong"
219+
check-match/values (values 1 2 3) (values 1 2 4))
220+
221+
(make-failure-test/stx "check-match/values: when-condition failure"
222+
check-match/values (values 1 2 3) (values x y z)
223+
#:when (odd? (+ x y z)))
224+
225+
(make-failure-test/stx "check-match/values: failure with ellipses"
226+
check-match/values
227+
(values 1 2 4 5)
228+
(values 1 (? even? es) ...))
229+
230+
189231
(test-case "check-= allows differences within epsilon"
190232
(check-= 1.0 1.09 1.1))
191233
(test-case "check-within allows differences within epsilon"

0 commit comments

Comments
 (0)