Skip to content

Commit

Permalink
Merge branch 'adding-wildcard_count_calls' into new-features
Browse files Browse the repository at this point in the history
  • Loading branch information
daha committed Oct 1, 2011
2 parents db3c4ca + 99422e2 commit 763d336
Show file tree
Hide file tree
Showing 2 changed files with 194 additions and 8 deletions.
85 changes: 80 additions & 5 deletions src/meck.erl
Expand Up @@ -38,6 +38,8 @@
-export([unload/0]).
-export([unload/1]).
-export([called/3]).
-export([count_calls/3]).
-export([wildcard_count_calls/3]).

%% Callback exports
-export([init/1]).
Expand Down Expand Up @@ -306,6 +308,32 @@ unload(Mods) when is_list(Mods) -> lists:foreach(fun unload/1, Mods), ok.
called(Mod, Fun, Args) ->
has_call({Mod, Fun, Args}, meck:history(Mod)).

%% @spec count_calls(Mod:: atom(), Fun:: atom(), Args:: list(term()))
%% -> non_neg_integer()
%% @doc Returns the number of times `Mod:Func' has been called with `Args'.
%%
%% This will check the history for the module, `Mod', to determine
%% how many times the function, `Fun', was called with arguments, `Args' and
%% returns the result.
-spec count_calls(Mod::atom(), Fun::atom(), Args::list()) -> non_neg_integer().
count_calls(Mod, Fun, Args) ->
i_count_calls({Mod, Fun, Args}, meck:history(Mod), 0).

%% @spec wildcard_count_calls(Mod:: atom(), Fun:: atom(),
%% Args::list(term()) | '_') -> non_neg_integer()
%% @doc Returns the number of times `Mod:Func' has been called with
%% wildcards matching of `Args'.
%%
%% This will check the history for the module, `Mod', to determine
%% whether the function, `Fun', was called with arguments, `Args'. It
%% uses the wildcard '_' to match one element in a list or tuple. By
%% setting `Args' to '_' any arguments is matched. It returns the
%% number of matching calls.
-spec wildcard_count_calls(Mod::atom(), Fun::atom(), Args::list() | '_' ) ->
non_neg_integer().
wildcard_count_calls(Mod, Fun, Args) ->
i_wildcard_count_calls({Mod, Fun, Args}, meck:history(Mod), 0).

%%==============================================================================
%% Callback functions
%%==============================================================================
Expand Down Expand Up @@ -728,10 +756,57 @@ get_history_without_pid(History) ->
remove_first_element(Tuple) when is_tuple(Tuple) ->
list_to_tuple(tl(tuple_to_list(Tuple))).

has_call({_M, _F, _A}, []) -> false;
has_call({M, F, A}, [{{M, F, A}, _Result} | _Rest]) ->
has_call(_MFA, []) -> false;
has_call(MFA, [{MFA, _Result} | _Rest]) ->
true;
has_call({M, F, A}, [{{M, F, A}, _ExType, _Exception, _Stack} | _Rest]) ->
has_call(MFA, [{MFA, _ExType, _Exception, _Stack} | _Rest]) ->
true;
has_call({M, F, A}, [_Call | Rest]) ->
has_call({M, F, A}, Rest).
has_call(MFA, [_Call | Rest]) ->
has_call(MFA, Rest).

i_count_calls(_MFA, [], Count) ->
Count;
i_count_calls(MFA, [{MFA, _Result} | Rest], Count) ->
i_count_calls(MFA, Rest, Count + 1);
i_count_calls(MFA, [{MFA, _ExType, _Exception, _Stack} | Rest], Count) ->
i_count_calls(MFA, Rest, Count + 1);
i_count_calls(MFA, [_Call | Rest], Count) ->
i_count_calls(MFA, Rest, Count).

i_wildcard_count_calls(_MFA, [], Count) ->
Count;
i_wildcard_count_calls(MFA = {M, F, A1} , [{{M, F, A2}, _Result} | Rest], Count) ->
match_args_update_count(A1, A2, MFA, Rest, Count);
i_wildcard_count_calls(MFA = {M, F, A1},
[{{M, F, A2}, _ExType, _Exception, _Stack} | Rest], Count) ->
match_args_update_count(A1, A2, MFA, Rest, Count);
i_wildcard_count_calls(MFA, [_Call | Rest], Count) ->
i_wildcard_count_calls(MFA, Rest, Count).

match_args_update_count(Args1, Args2, MFA, Rest, Count) ->
case i_wildcard_match_args(Args1, Args2) of
true ->
i_wildcard_count_calls(MFA, Rest, Count + 1);
false ->
i_wildcard_count_calls(MFA, Rest, Count)
end.

i_wildcard_match_args(Args, Args) ->
true;
i_wildcard_match_args([], _) ->
false;
i_wildcard_match_args(_, []) ->
false;
i_wildcard_match_args('_', _) ->
true;
i_wildcard_match_args([H|T1], [H|T2]) ->
i_wildcard_match_args(T1, T2);
i_wildcard_match_args(['_'|T1], [_|T2]) ->
i_wildcard_match_args(T1, T2);
i_wildcard_match_args([H1|T1], [H2|T2]) when is_list(H1) and is_list(H2) ->
i_wildcard_match_args(H1, H2) and i_wildcard_match_args(T1,T2);
i_wildcard_match_args([H1|T1], [H2|T2]) when is_tuple(H1) and is_tuple(H2) ->
i_wildcard_match_args(tuple_to_list(H1), tuple_to_list(H2))
and i_wildcard_match_args(T1,T2);
i_wildcard_match_args([_H1|_T1], [_H2|_T2]) ->
false.
117 changes: 114 additions & 3 deletions test/meck_tests.erl
Expand Up @@ -72,6 +72,17 @@ meck_test_() ->
fun called_true_few_args_/1,
fun called_false_error_/1,
fun called_true_error_/1,
fun count_calls_/1,
fun count_calls_error_/1,
fun wildcard_count_calls_with_wildcard_on_args_/1,
fun wildcard_count_calls_with_wildcard_on_args_error_/1,
fun wildcard_count_calls_simple_/1,
fun wildcard_count_calls_in_list_/1,
fun wildcard_count_calls_in_longer_list_/1,
fun wildcard_count_calls_in_deep_lists_/1,
fun wildcard_count_calls_in_tuples_/1,
fun wildcard_count_calls_simple_error_/1,
fun wildcard_count_calls_error_/1,
fun sequence_/1,
fun sequence_multi_/1,
fun loop_/1,
Expand Down Expand Up @@ -410,11 +421,111 @@ called_false_error_(Mod) ->

called_true_error_(Mod) ->
Args = [one, "two", {3, 3}],
TestFun = fun (_, _, _) -> meck:exception(error, my_error) end,
ok = meck:expect(Mod, test, TestFun),
catch apply(Mod, test, Args),
expect_catch_apply(Mod, test, Args),
assert_called(Mod, test, Args, true).

count_calls_(Mod) ->
Args = [],
IncorrectArgs = [foo],
ok = meck:expect(Mod, test1, length(Args), ok),
?assertEqual(0, meck:count_calls(Mod, test1, Args)),
ok = apply(Mod, test1, Args),
?assertEqual(1, meck:count_calls(Mod, test1, Args)),
?assertEqual(0, meck:count_calls(Mod, test1, IncorrectArgs)).

count_calls_error_(Mod) ->
Args = [one, "two", {3, 3}],
expect_catch_apply(Mod, test, Args),
?assertEqual(1, meck:count_calls(Mod, test, Args)).

wildcard_count_calls_with_wildcard_on_args_(Mod) ->
Args = [a],
expect_apply(Mod, test1, Args),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, '_')).

wildcard_count_calls_with_wildcard_on_args_error_(Mod) ->
Args = [one, "two", {3, 3}],
expect_catch_apply(Mod, test, Args),
?assertEqual(1, meck:wildcard_count_calls(Mod, test, '_')).

wildcard_count_calls_simple_(Mod) ->
Args = [a, [b]],
IncorrectArgs1 = [a],
IncorrectArgs2 = [a, [b], c],
ok = meck:expect(Mod, test1, length(Args), ok),
?assertEqual(0, meck:wildcard_count_calls(Mod, test1, Args)),
ok = apply(Mod, test1, Args),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, Args)),
?assertEqual(0, meck:wildcard_count_calls(Mod, test1, IncorrectArgs1)),
?assertEqual(0, meck:wildcard_count_calls(Mod, test1, IncorrectArgs2)).

wildcard_count_calls_in_list_(Mod) ->
Args = [a],
MatchingArgs = ['_'],
ok = meck:expect(Mod, test1, length(Args), ok),
?assertEqual(0, meck:wildcard_count_calls(Mod, test1, Args)),
?assertEqual(0, meck:wildcard_count_calls(Mod, test1, MatchingArgs)),
ok = apply(Mod, test1, Args),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, MatchingArgs)).

wildcard_count_calls_in_longer_list_(Mod) ->
Args = [a, b],
MatchingArgs1 = ['_', b],
MatchingArgs2 = [a | '_'],
expect_apply(Mod, test1, Args),
expect_apply(Mod, test2, Args),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, Args)),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, MatchingArgs1)),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, MatchingArgs2)).

wildcard_count_calls_in_deep_lists_(Mod) ->
Args = [a, [b, [c]]],
MatchingArgs1 = [a, ['_',[c]]],
MatchingArgs2 = [a, [b,'_']],
MatchingArgs3 = [a, [b, ['_']]],
expect_apply(Mod, test1, Args),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, MatchingArgs1)),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, MatchingArgs2)),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, MatchingArgs3)).

wildcard_count_calls_in_tuples_(Mod) ->
Args = [{a,b,{c}}],
MatchingArgs1 = [{'_',b,{c}}],
MatchingArgs2 = [{a,b,'_'}],
MatchingArgs3 = [{a,b,{'_'}}],
expect_apply(Mod, test1, Args),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, MatchingArgs1)),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, MatchingArgs2)),
?assertEqual(1, meck:wildcard_count_calls(Mod, test1, MatchingArgs3)).

wildcard_count_calls_simple_error_(Mod) ->
Args = [one, "two", {3, 3}],
IncorrectArgs1 = [one, "two", 4],
expect_catch_apply(Mod, test, Args),
?assertEqual(1, meck:wildcard_count_calls(Mod, test, Args)),
?assertEqual(0, meck:wildcard_count_calls(Mod, test, IncorrectArgs1)).


wildcard_count_calls_error_(Mod) ->
Args = [one, "two", {3, 3}],
MatchingArgs1 = ['_', "two", {3, 3}],
MatchingArgs2 = [one |'_'],
MatchingArgs3 = [one, "two", {3, '_'}],
expect_catch_apply(Mod, test, Args),
?assertEqual(1, meck:wildcard_count_calls(Mod, test, MatchingArgs1)),
?assertEqual(1, meck:wildcard_count_calls(Mod, test, MatchingArgs2)),
?assertEqual(1, meck:wildcard_count_calls(Mod, test, MatchingArgs3)).

expect_apply(Mod, Func, Args) ->
ok = meck:expect(Mod, Func, length(Args), ok),
ok = apply(Mod, Func, Args).

expect_catch_apply(Mod, Func, Args) ->
TestFun = fun (_, _, _) -> meck:exception(error, my_error) end,
ok = meck:expect(Mod, Func, TestFun),
catch apply(Mod, Func, Args).


sequence_(Mod) ->
Sequence = [a, b, c, d, e],
?assertEqual(ok, meck:sequence(Mod, s, 2, Sequence)),
Expand Down

0 comments on commit 763d336

Please sign in to comment.