Skip to content

Commit

Permalink
Do not allow guards in assert/1 (#13817)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jean Klingler authored Sep 9, 2024
1 parent 5cb8633 commit 5137c33
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 0 deletions.
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, """
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

0 comments on commit 5137c33

Please # to comment.