Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions lib/ex_unit/lib/ex_unit/assertions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ defmodule ExUnit.Assertions do

Even though the match works, `assert` still expects a truth
value. In such cases, simply use `==/2` or `match?/2`.

If you need more complex pattern matching using guards, you
need to use `match?/2`:

assert match?([%{id: id} | _] when is_integer(id), records)

"""
defmacro assert({:=, meta, [left, right]} = assertion) do
code = escape_quoted(:assert, meta, assertion)
Expand Down Expand Up @@ -357,6 +363,23 @@ defmodule ExUnit.Assertions do
end

@doc false
def __match__({:when, _, _} = left, right, _, _, _) do
suggestion =
quote do
assert match?(unquote(left), unquote(right))
end

raise ArgumentError, """
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what the best way to raise here would be.
Ideally this would be a CompileError.

BTW, I noticed that right now without assert we're getting:

error: undefined function when/2 (there is no such import)

But I think we can have a better error message in this case, given that when is a reserved word and can't be used as a function name?

invalid pattern in assert/1:

#{Macro.to_string(left) |> Inspect.Error.pad(2)}

To assert with guards, use match?/2:

#{Macro.to_string(suggestion) |> Inspect.Error.pad(2)}
"""
end

def __match__(left, right, code, check, caller) do
left = __expand_pattern__(left, caller)
vars = collect_vars_from_pattern(left)
Expand Down
27 changes: 27 additions & 0 deletions lib/ex_unit/test/ex_unit/assertions_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,33 @@ defmodule ExUnit.AssertionsTest do
end
end

test "assert match with `when` in the pattern fails" do
message = """
invalid pattern in assert\/1:

x when is_map(x)

To assert with guards, use match?/2:

assert match?(x when is_map(x), %{})
"""

assert_raise ArgumentError, message, fn ->
Code.eval_string("""
defmodule AssertGuard do
import ExUnit.Assertions

def run do
assert (x when is_map(x)) = %{}
end
end
""")
end
after
:code.purge(AssertGuard)
:code.delete(AssertGuard)
end

test "assert match with __ENV__ in the pattern" do
message =
ExUnit.CaptureIO.capture_io(:stderr, fn ->
Expand Down
Loading