Packages
espec
1.6.4
1.10.0
1.9.2
1.9.1
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.0
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.1
1.0.0
0.8.28
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.2
0.4.1
0.4.0
0.3.7
0.3.5
0.3.0
0.2.0
0.1.0
BDD testing framework for Elixir inspired by RSpec.
Current section
Files
Jump to
Current section
Files
lib/espec/assert_receive.ex
defmodule ESpec.AssertReceive do
@moduledoc """
Defines `assert_receive` and `assert_received` helper macros
"""
@default_timeout 100
defmodule AssertReceiveError do
defexception message: nil
end
alias ESpec.ExpectTo
alias ESpec.Assertions.AssertReceive
@doc "Asserts that a message matching `pattern` was or is going to be received."
defmacro assert_receive(pattern, timeout \\ @default_timeout) do
do_assert_receive(pattern, timeout, __CALLER__)
end
@doc "Asserts that a message matching `pattern` was received and is in the current process' mailbox."
defmacro assert_received(pattern) do
do_assert_receive(pattern, 0, __CALLER__)
end
defp do_assert_receive(pattern, timeout, caller) do
binary = Macro.to_string(pattern)
pattern = Macro.expand(pattern, caller)
vars = collect_vars_from_pattern(pattern)
pins = collect_pins_from_pattern(pattern)
pattern =
case pattern do
{:when, meta, [left, right]} ->
{:when, meta, [quote(do: unquote(left) = received), right]}
left ->
quote(do: unquote(left) = received)
end
ESpec.AssertReceive.__assert_receive__(pattern, binary, vars, pins, timeout)
end
@doc false
def __assert_receive__(pattern, binary, vars, pins, timeout \\ 100) do
quote do
result =
{received, unquote(vars)} =
receive do
unquote(pattern) -> {received, unquote(vars)}
after
unquote(timeout) ->
args = [unquote(binary), unquote(pins), ESpec.AssertReceive.__mailbox_messages__()]
ExpectTo.to(
{AssertReceive, args},
{ExpectTo, {:error, :timeout}, ESpec.Expect.pruned_stacktrace()}
)
end
args = [unquote(binary), unquote(pins), ESpec.AssertReceive.__mailbox_messages__()]
ExpectTo.to({AssertReceive, args}, {ExpectTo, result, ESpec.Expect.pruned_stacktrace()})
end
end
@max_mailbox_length 10
@doc false
def __mailbox_messages__ do
{:messages, messages} = Process.info(self(), :messages)
Enum.take(messages, @max_mailbox_length)
end
defp collect_pins_from_pattern(expr) do
{_, pins} =
Macro.prewalk(expr, [], fn
{:^, _, [{name, _, _} = var]}, acc ->
{:ok, [{name, var} | acc]}
form, acc ->
{form, acc}
end)
Enum.uniq_by(pins, &elem(&1, 0))
end
defp collect_vars_from_pattern({:when, _, [left, right]}) do
pattern = collect_vars_from_pattern(left)
for {name, _, context} = var <- collect_vars_from_pattern(right),
Enum.any?(pattern, &match?({^name, _, ^context}, &1)),
into: pattern,
do: var
end
defp collect_vars_from_pattern(expr) do
Macro.prewalk(expr, [], fn
{:::, _, [left, _]}, acc ->
{[left], acc}
{skip, _, [_]}, acc when skip in [:^, :@] ->
{:ok, acc}
{:_, _, context}, acc when is_atom(context) ->
{:ok, acc}
{name, meta, context}, acc when is_atom(name) and is_atom(context) ->
{:ok, [{name, [generated: true] ++ meta, context} | acc]}
any_node, acc ->
{any_node, acc}
end)
|> elem(1)
end
end