[racket] A `check-expansion` for rackunit to test macros?

From: Greg Hendershott (greghendershott at gmail.com)
Date: Mon Aug 26 10:45:19 EDT 2013

I recently got a pull request where someone defined a
`check-expansion` form to use with rackunit. Simplified excerpt:

#lang racket/base

(require syntax/parse/define)

(define-simple-macro (if-let [binding:id value:expr] then:expr else:expr)
  (let ([binding value])
    (if binding then else)))

(module+ test
  (require rackunit)
  (define (check-expansion input expected-output)
    (check-equal? (syntax->datum (expand-once input)) expected-output))
  (check-expansion '(if-let [x #t] 0 1)   '(let [(x #t)] (if x 0 1))))

Although DrRacket doesn't warn that the the test fails, it fails with
`raco test`:

raco test conditionals.rkt
raco test: (submod "conditionals.rkt" test)
if-let: unbound identifier;
 also, no #%app syntax transformer is bound
  at: if-let
  in: (if-let (x #t) 0 1)
[running body]
[running body]
   /Applications/Racket_v5.3.5/collects/raco/raco.rkt: [running body]
   /Applications/Racket_v5.3.5/collects/raco/main.rkt: [running body]

Without giving it much time or deep thought, I came up with this
version which succeeds in both DrRacket and raco test:

(module+ test
  (require rackunit)
  (define (check-expansion input expected-output)
    (check-equal? (syntax->datum (expand-once input))
                  (syntax->datum expected-output)))
  (check-expansion #'(if-let [x #t] 0 1)   #'(let [(x #t)] (if x 0 1))))

In light of that:

[1] Why don't DrRacket and `raco test` both succeed for the first version?

[2] Is my new version correct?

[3] Could/should rackunit provide something like `check-expansion`?

Posted on the users mailing list.