Skip to content

Commit

Permalink
Merge pull request #153 from edgurgel/add-merge-expects-option
Browse files Browse the repository at this point in the history
Add merge_expects option
  • Loading branch information
eproxus committed Nov 9, 2015
2 parents 403e2dd + 762cd2f commit b80f342
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 5 deletions.
7 changes: 7 additions & 0 deletions src/meck.erl
Expand Up @@ -182,6 +182,13 @@ new(Mod) when is_list(Mod) -> lists:foreach(fun new/1, Mod), ok.
%% passed in. It is possible to specify this option as just `stub_all'
%% then stubs will return atom `ok'. If used along with `passthrough'
%% then `stub_all' is ignored. </dd>
%%
%% <dt>`merge_expects'</dt>
%% <dd>The expectations for the function/arity signature are merged with
%% existing ones instead of replacing all of them each time an
%% expectation is added. Expectations are added to the end of the
%% function clause list, meaning that pattern matching will be performed
%% in the order the expectations were added.</dd>
%% </dl>
-spec new(Mods, Options) -> ok when
Mods :: Mod | [Mod],
Expand Down
22 changes: 17 additions & 5 deletions src/meck_proc.erl
Expand Up @@ -60,6 +60,7 @@
history = [] :: meck_history:history() | undefined,
original :: term(),
was_sticky = false :: boolean(),
merge_expects = false :: boolean(),
reload :: {Compiler::pid(), {From::pid(), Tag::any()}} |
undefined,
trackers = [] :: [tracker()]}).
Expand Down Expand Up @@ -198,6 +199,7 @@ init([Mod, Options]) ->
_ -> false
end,
NoPassCover = proplists:get_bool(no_passthrough_cover, Options),
MergeExpects = proplists:get_bool(merge_expects, Options),
EnableOnLoad = proplists:get_bool(enable_on_load, Options),
Original = backup_original(Mod, NoPassCover, EnableOnLoad),
NoHistory = proplists:get_bool(no_history, Options),
Expand All @@ -213,6 +215,7 @@ init([Mod, Options]) ->
expects = Expects,
original = Original,
was_sticky = WasSticky,
merge_expects = MergeExpects,
history = History}}
catch
exit:{error_loading_module, Mod, sticky_directory} ->
Expand All @@ -224,13 +227,13 @@ handle_call({get_result_spec, Func, Args}, _From, S) ->
{ResultSpec, NewExpects} = do_get_result_spec(S#state.expects, Func, Args),
{reply, ResultSpec, S#state{expects = NewExpects}};
handle_call({set_expect, Expect}, From,
S = #state{mod = Mod, expects = Expects}) ->
S = #state{mod = Mod, expects = Expects, merge_expects = MergeExpects}) ->
check_if_being_reloaded(S),
FuncAri = {Func, Ari} = meck_expect:func_ari(Expect),
case validate_expect(Mod, Func, Ari, S#state.can_expect) of
ok ->
{NewExpects, CompilerPid} = store_expect(Mod, FuncAri, Expect,
Expects),
Expects, MergeExpects),
{noreply, S#state{expects = NewExpects,
reload = {CompilerPid, From}}};
{error, Reason} ->
Expand Down Expand Up @@ -485,10 +488,19 @@ validate_expect(Mod, Func, Ari, CanExpect) ->
end.

-spec store_expect(Mod::atom(), meck_expect:func_ari(),
meck_expect:expect(), Expects::meck_dict()) ->
meck_expect:expect(), Expects::meck_dict(), boolean()) ->
{NewExpects::meck_dict(), CompilerPid::pid()}.
store_expect(Mod, FuncAri, Expect, Expects) ->
NewExpects = dict:store(FuncAri, Expect, Expects),
store_expect(Mod, FuncAri, Expect, Expects, true) ->
NewExpects = case dict:is_key(FuncAri, Expects) of
true ->
{FuncAri, ExistingClauses} = dict:fetch(FuncAri, Expects),
{FuncAri, NewClauses} = Expect,
dict:store(FuncAri, {FuncAri, ExistingClauses ++ NewClauses}, Expects);
false -> dict:store(FuncAri, Expect, Expects)
end,
compile_expects(Mod, NewExpects);
store_expect(Mod, FuncAri, Expect, Expects, false) ->
NewExpects = dict:store(FuncAri, Expect, Expects),
compile_expects(Mod, NewExpects).

-spec do_delete_expect(Mod::atom(), meck_expect:func_ari(), Expects::meck_dict()) ->
Expand Down
36 changes: 36 additions & 0 deletions test/meck_tests.erl
Expand Up @@ -803,6 +803,42 @@ expect_ret_specs_(Mod) ->

%% --- Tests with own setup ----------------------------------------------------

merge_expects_module_test() ->
Mod = merge_mod,
meck:new(Mod, [non_strict, merge_expects]),
%% Given
meck:expect(Mod, f, [2001], meck:raise(error, a)),
meck:expect(Mod, f, [2002], meck:raise(throw, b)),
meck:expect(Mod, f, [2003], meck:raise(exit, c)),
meck:expect(Mod, f, [2004], meck:val(d)),
%% When/Then
?assertException(error, a, Mod:f(2001)),
?assertException(throw, b, Mod:f(2002)),
?assertException(exit, c, Mod:f(2003)),
?assertMatch(d, Mod:f(2004)),
meck:unload(Mod).

merge_expects_ret_specs_test() ->
Mod = merge_mod,
meck:new(Mod, [non_strict, merge_expects]),
%% When
meck:expect(Mod, f, [1, 1], meck:seq([a, b, c])),
meck:expect(Mod, f, [1, '_'], meck:loop([d, e])),
meck:expect(Mod, f, ['_', '_'], meck:val(f)),
%% Then
?assertEqual(d, Mod:f(1, 2)),
?assertEqual(f, Mod:f(2, 2)),
?assertEqual(e, Mod:f(1, 2)),
?assertEqual(a, Mod:f(1, 1)),
?assertEqual(d, Mod:f(1, 2)),
?assertEqual(b, Mod:f(1, 1)),
?assertEqual(c, Mod:f(1, 1)),
?assertEqual(f, Mod:f(2, 2)),
?assertEqual(c, Mod:f(1, 1)),
?assertEqual(e, Mod:f(1, 2)),
?assertEqual(c, Mod:f(1, 1)),
meck:unload(Mod).

undefined_module_test() ->
%% When/Then
?assertError({{undefined_module, blah}, _}, meck:new(blah, [no_link])).
Expand Down

0 comments on commit b80f342

Please sign in to comment.