chimez
2019-4-23 10:01:50

@chimez has joined the channel


jimmysnielsen
2019-4-23 10:45:40

what is the proper way to test a function returning multiple values? The following seems very weird to me.. #lang racket/base

(require rackunit)

(define (f x) x) (define (g x) (values x (add1 x)))

(module+ test (check-equal? 3 (f 3)) (define-values (n1 n2) (g 3)) ; this works but is complicated (check-equal? n1 3) (check-equal? n2 4) (check-equal? (values 3 4) (g 3)) ; fails )


greg
2019-4-23 11:32:12

@jimmysnielsen The few times I’ve needed to test multiple values, I’ve done something like what you showed: Use define-values (or let-values) plus multiple check-equal?s. It’s awkward but I’ve never done it enough, to care enough to detour and figure out something better. Then I always forget about it.


greg
2019-4-23 11:32:25

If you do this frequently, you could define-check something like a “check-equal-values?”. The following seems to work for me. (define-check (check-equal-values? actual-thunk expected-list) (define actual-list (call-with-values actual-thunk list)) (with-check-info (['actual actual-list] ['expected expected-list]) (unless (equal? actual-list expected-list) (fail-check))))


greg
2019-4-23 11:34:28

Note, to use this you need to put the first, “actual” values-producing expression in a thunk (like how you’d use check-exn). And, put the expected values in a list. For example: (define (f x) (values x (add1 x))) (check-equal-values? (λ () (f 1)) (list 1 2)) ;succeeds (check-equal-values? (λ () (f 1)) (list 42 42)) ;fails with... -------------------- ; FAILURE ; /tmp/chk.rkt:16:0 name: check-equal-values? location: chk.rkt:16:0 actual: (1 2) expected: (42 42) --------------------


greg
2019-4-23 11:35:54

So that’s still a bit awkward. Maybe someone else has a better idea. (Maybe there’s no great non-awkward way? If so, maybe that’s why rackunit doesn’t already provide something like this?)


greg
2019-4-23 11:37:51

p.s. I put actual before expected, because that’s the convention rackunit uses for failure messages.


jimmysnielsen
2019-4-23 11:43:18

thanks @greg I will keep the thunk in mind. I dont often need to test this so I might just stick with the “define-values solution”. And thanks also for the little reminder on actual before expected to keep things nice and tidy wrt failure messages.


samdphillips
2019-4-23 17:33:58

IIRC I think chk has a form to handle multiple values



sorawee
2019-4-23 19:33:10

FWIW, there’s a pending PR doing exactly this https://github.com/racket/rackunit/pull/73


alexknauth
2019-4-24 01:33:27

Currently check-equal? is a function-like check form, which means it evaluates its arguments in the same way a function would. The check-equal?/values form needs to be a full macro, since it evaluates its arguments in a multi-valued context; a function-like form can’t do that. So, should check-equal?/values be a separate form from check-equal?, or can/should they be merged into one?


notjack
2019-4-24 02:39:39

@alexknauth I think making it a separate thing is weird and awkward. But I also think that as long as “checks are functions” is rackunit’s philosophy, adding more exceptions to that rule is confusing.


notjack
2019-4-24 02:40:03

So really I think we should just ditch that philosophy


philip.mcgrath
2019-4-24 02:47:22

IDK about the larger questions, but there could be a function-like check-equal?/values that takes two thunks and compares their return values, somewhat like check-exn.