Skip to content

Commit 2b67d0a

Browse files
authored
Optimize stub_with (#157)
1 parent 5994819 commit 2b67d0a

File tree

1 file changed

+54
-26
lines changed

1 file changed

+54
-26
lines changed

lib/mox.ex

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -647,11 +647,17 @@ defmodule Mox do
647647
end
648648

649649
defp do_stub_with(mock, module, behaviours, _behaviours_common) do
650-
for behaviour <- behaviours,
651-
{fun, arity} <- behaviour.behaviour_info(:callbacks),
652-
function_exported?(mock, fun, arity) do
653-
stub(mock, fun, :erlang.make_fun(module, fun, arity))
654-
end
650+
key_expectation_list =
651+
for behaviour <- behaviours,
652+
{fun, arity} <- behaviour.behaviour_info(:callbacks),
653+
function_exported?(mock, fun, arity) do
654+
{
655+
{mock, fun, arity},
656+
{0, [], :erlang.make_fun(module, fun, arity)}
657+
}
658+
end
659+
660+
add_expectations!(mock, key_expectation_list)
655661

656662
mock
657663
end
@@ -675,30 +681,47 @@ defmodule Mox do
675681
raise ArgumentError, "unknown function #{name}/#{arity} for mock #{inspect(mock)}"
676682
end
677683

678-
case add_expectation(self(), key, value) do
684+
case add_expectations(self(), mock, [{key, value}]) do
679685
:ok ->
680686
:ok
681687

682-
{:error, {:currently_allowed, owner_pid}} ->
683-
inspected = inspect(self())
688+
{:error, error} ->
689+
raise ArgumentError, expectation_error_to_message(error, mock)
690+
end
691+
end
684692

685-
raise ArgumentError, """
686-
cannot add expectations/stubs to #{inspect(mock)} in the current process (#{inspected}) \
687-
because the process has been allowed by #{inspect(owner_pid)}. \
688-
You cannot define expectations/stubs in a process that has been allowed
689-
"""
693+
defp add_expectations!(mock, key_expectation_list) do
694+
validate_mock!(mock)
690695

691-
{:error, {:not_shared_owner, global_pid}} ->
692-
inspected = inspect(self())
696+
case add_expectations(self(), mock, key_expectation_list) do
697+
:ok ->
698+
:ok
693699

694-
raise ArgumentError, """
695-
cannot add expectations/stubs to #{inspect(mock)} in the current process (#{inspected}) \
696-
because Mox is in global mode and the global process is #{inspect(global_pid)}. \
697-
Only the process that set Mox to global can set expectations/stubs in global mode
698-
"""
700+
{:error, error} ->
701+
raise ArgumentError, expectation_error_to_message(error, mock)
699702
end
700703
end
701704

705+
defp expectation_error_to_message({:currently_allowed, owner_pid}, mock) do
706+
inspected = inspect(self())
707+
708+
"""
709+
cannot add expectations/stubs to #{inspect(mock)} in the current process (#{inspected}) \
710+
because the process has been allowed by #{inspect(owner_pid)}. \
711+
You cannot define expectations/stubs in a process that has been allowed
712+
"""
713+
end
714+
715+
defp expectation_error_to_message({:not_shared_owner, global_pid}, mock) do
716+
inspected = inspect(self())
717+
718+
"""
719+
cannot add expectations/stubs to #{inspect(mock)} in the current process (#{inspected}) \
720+
because Mox is in global mode and the global process is #{inspect(global_pid)}. \
721+
Only the process that set Mox to global can set expectations/stubs in global mode
722+
"""
723+
end
724+
702725
@doc """
703726
Allows other processes to share expectations and stubs
704727
defined by owner process.
@@ -924,10 +947,10 @@ defmodule Mox do
924947
end
925948
end
926949

927-
defp add_expectation(owner_pid, {mock, _, _} = key, expectation) do
950+
defp add_expectations(owner_pid, mock, key_expectation_list) do
928951
case ensure_pid_can_add_expectation(owner_pid, mock) do
929952
:ok ->
930-
update_fun = &{:ok, init_or_merge_expectations(&1, key, expectation)}
953+
update_fun = &{:ok, init_or_merge_expectations(&1, key_expectation_list)}
931954
:ok = get_and_update!(owner_pid, mock, update_fun)
932955

933956
{:error, reason} ->
@@ -984,13 +1007,18 @@ defmodule Mox do
9841007
end
9851008
end
9861009

987-
defp init_or_merge_expectations(current_exps, key, {n, calls, stub} = new_exp)
1010+
defp init_or_merge_expectations(current_exps, [{key, {n, calls, stub} = new_exp} | tail])
9881011
when is_map(current_exps) or is_nil(current_exps) do
989-
Map.update(current_exps || %{}, key, new_exp, fn {current_n, current_calls, _current_stub} ->
990-
{current_n + n, current_calls ++ calls, stub}
991-
end)
1012+
init_or_merge_expectations(
1013+
Map.update(current_exps || %{}, key, new_exp, fn {current_n, current_calls, _current_stub} ->
1014+
{current_n + n, current_calls ++ calls, stub}
1015+
end),
1016+
tail
1017+
)
9921018
end
9931019

1020+
defp init_or_merge_expectations(current_exps, []), do: current_exps
1021+
9941022
defp ok_or_remote(source) when node(source) == node(), do: :ok
9951023
defp ok_or_remote(_source), do: :remote
9961024
end

0 commit comments

Comments
 (0)