So, an update on this idea:
v1 of this was rejected (
https://github.com/elixir-lang/elixir/pull/15309). I think I understand the reasoning. Makes sense. To José's point, perhaps a different API would be better, and less brittle. What about something that looks more like this?
my_test_list
|> Enum.each(fn test_case ->
with_assertion_context test_case do
# do all the assertions & refutes you want
# and it'll be transformed at compile time to a fancier call that has the assertion context in it for a nicer diff based error message
assert test_case.foo == "bar"
refute test_case.bar == 1
assert test.baz == "quux", "this is assert/2 and is implemented as a function and thus would not get replaced at compile time by with_assertion_context"
end
end)
The nice things about this:
- the lexical scope of the context is obvious
- it's not terrible to implement
- probably not significant performance impact
- probably usually used at the same "level" as a loop/iteration, and it kinda fits
- if you need multiple contexts, it can easily be done by just having multiple assertion contexts consecutively
- it feels declarative, not imperative, so it feels like a good match for Elixir's style and BEAM's immutability characteristics.
Downside:
- Not obvious what should happen in the case of nested assertion contexts (open question...should it fail? Should one win? Should there be some form of concatenation?)
- a bit noisier than I'd like (though less noisy than my v1 idea of putting it on every assert, so fair enough)
- that's one extra indentation inside of a loop during testing - though I'm not in the habit of testing this way all the time (it's just handy for some cases) so the tradeoff to me is worth it
Thoughts? I'm not totally sold on the `with_assertion_context` name either - that feels like a compiler plumbing sort of name, not a user facing sort of name, but I'm at a loss of what obvious thing to call this that specifically, semantically makes it obvious that we're talking about modifying/adding to error messages in assertions.