[racket] How to write a unit test for syntax-parse expectation failure error message?

From: Ryan Culpepper (ryan at cs.utah.edu)
Date: Sun Dec 2 13:34:02 EST 2012

On 12/02/2012 12:14 PM, Greg Hendershott wrote:
> I'd like to write a unit test that a syntax-parse expectation failure
> elicits a certain error message. For instance, I'd do a regexp-match?
> that "something" is present in a message like "expected something".
>
> However it seems that syntax-parse expectation failures don't raise an
> exception. In other words, this will never return 'caught:
>
> (with-handlers ([exn? (lambda (exn) 'caught)])
>    something-that-elicits-a-syntax-parse-expectation-failure)
>
> (At first I'd tried exn:syntax?, and when that didn't work, I checked
> to see if it was any kind of exception. Seems not.)
>
> Is there another way to go about this?

No, that's how you do it. For example:

(require syntax/parse)

(with-handlers ([exn:fail:syntax? (lambda (e) 'caught)])
   (syntax-parse #'1 [x:id 'id]))
;; => 'caught

I suspect that what you actually want to do is test a macro that uses 
syntax-parse; in that case, the issue you're running into is that the 
macro raises a syntax error at compile time, but the with-handlers 
doesn't (or rather, wouldn't) get set up to catch the exception until 
run time.

There are two ways to fix the problem. One is to use eval or expand in 
your test:

(define testing-ns (make-base-namespace))
;; setup testing-ns
(with-handlers ([exn:fail:syntax? ___])
   (parameterize ((current-namespace testing-ns))
     (expand '(macro-using-syntax-parse ___))))

The other way is to wrap the macro call in something that catches the 
compile-time exception and produces code that raises a similar run-time 
exception:

(with-handler ([exn:fail:syntax? ___])
   (convert-syntax-error
     (macro-using-syntax-parse ___)))

The syntax-parse tests use the second technique. Here's the definition 
of convert-syntax-error from tests/stxparse/setup:

(define-syntax (convert-syntax-error stx)
   (syntax-case stx ()
     [(_ expr)
      (with-handlers ([exn:fail:syntax?
                       (lambda (e)
                         #`(error '#,(exn-message e)))])
        (parameterize ((error-print-source-location #f))
          (local-expand #'expr 'expression null)))]))

Ryan


Posted on the users mailing list.