`test_throws` with macros after PR 23533

Due to a recent change (this one, I think?), errors resulting from a macro seem to be wrapped inside a LoadError

macro m()
  error("err")
end

0.6:

julia> @m
ERROR: err

0.7-dev:

julia> @m
ERROR: LoadError: err
Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] @m(::LineNumberNode, ::Module) at ./REPL[1]:2
while loading REPL[2], in expression starting on line 1```

The stack traces are really useful for debugging, but now I can’t use @test_throws to test for a specific error in macros.

using Base.Test

macro m(x::Expr)
  x.head == :tuple || throw(ArgumentError("@m requires a tuple!"))
  x
end
julia> @test_throws ArgumentError @eval @m [1,2,3]
Test Failed
  Expression: #= REPL[11]:1 =# @eval #= REPL[11]:1 =# @m([1, 2, 3])
    Expected: ArgumentError
      Thrown: LoadError
ERROR: There was an error during testing

Workarounds exist, of course:

@test_throws ArgumentError try @eval @m [1,2,3] catch err; throw(err.error) end

But that to me seems to be reintroducing the very thing that @test_throws was supposed to abstract away, maybe.

I have nothing else to say, just thought this was something worth bringing up. (apologies if I am mistaken)


I spent an hour thinking about it but still have no clue what this post classifies as or where I should put it, (it’s not a proposal or a question and the relevance it has to Julia is TBD) feel free to move this to where it’s appropriate or/and throw it in the garbage.

5 Likes

I just ran into the same problem developing a macro package, in julia 1.1. Are there any more recent insights than the workaround mentioned above (for which thanks, BTW).

The workaround suggested by @fcard does not always work. It depends where the error is thrown. If the exception if thrown by the macro itself, then that exception is wrapped inside a LoadError , but if the code that is generated by the macro throws the exception, the wrapping does not occur and the workaround fails.

At present @davidavdav and I are using another workaround. Instead of throwing the exception in the to-be-tested macro, we return :(throw(some_exception)). Then unmodified @test_throws works as intended, without having to dig some_exception out of the enclosing LoadError.

4 Likes