New API to retrieve arguments passed to a mocked function #45

Closed
wants to merge 2 commits into
from
View
@@ -38,6 +38,8 @@
-export([unload/1]).
-export([called/3]).
-export([called/4]).
+-export([arguments/3]).
+-export([arguments/4]).
-export([num_calls/3]).
-export([num_calls/4]).
@@ -264,7 +266,7 @@ history(Mod) when is_atom(Mod) -> call(Mod, history).
%% @see num_calls/4
-spec history(Mod::atom(), Pid:: pid() | '_') -> history().
history(Mod, Pid) when is_atom(Mod), is_pid(Pid) orelse Pid == '_' ->
- match_history(match_mfa('_', Pid), call(Mod, history)).
+ match_history(match_mf_args('_', Pid), call(Mod, history)).
%% @spec unload() -> list(atom())
%% @doc Unloads all mocked modules from memory.
@@ -331,6 +333,26 @@ num_calls(Mod, Fun, Args) ->
num_calls(Mod, Fun, Args, Pid) ->
num_calls({Mod, Fun, Args}, meck:history(Mod, Pid)).
+%% @spec arguments(Mod:: atom(), Fun:: atom(), Arity:: non_neg_integer()) -> list(list(term()))
+%% @doc Returns all arguments with which `Mod:Func' has been called
+%%
+%% @equiv arguments(Mod, Fun, Arity, '_')
+arguments(Mod, Fun, Arity) ->
+ arguments_for_all_calls({Mod, Fun, Arity}, meck:history(Mod)).
+
+%% @spec arguments(Mod:: atom(), Fun:: atom(), Arity:: non_neg_integer(),
+%% Pid::pid()) -> list(list(term()))
+%% @doc Returns all arguments with which `Mod:Func' has been called by `Pid'
+%%
+%% This will check the history for the module, `Mod', to find all arguments
+%% passed by the process `Pid' to the function, `Fun', with arity, `Arity'.
+%%
+%% @see arguments/3
+-spec arguments(Mod::atom(), Fun::atom(), Arity::non_neg_integer(), Pid::pid()) -> list().
+arguments(Mod, Fun, Arity, Pid) ->
+ arguments_for_all_calls({Mod, Fun, Arity}, meck:history(Mod, Pid)).
+
+
%%==============================================================================
%% Callback functions
%%==============================================================================
@@ -732,17 +754,27 @@ add_history(Mod, Item) ->
cast(Mod, {add_history, Item}).
has_call(MFA, History) ->
- [] =/= match_history(match_mfa(MFA), History).
+ [] =/= match_history(match_mf_args(MFA), History).
num_calls(MFA, History) ->
- length(match_history(match_mfa(MFA), History)).
+ length(match_history(match_mf_args(MFA), History)).
match_history(MatchSpec, History) ->
MS = ets:match_spec_compile(MatchSpec),
ets:match_spec_run(History, MS).
-match_mfa(MFA) -> match_mfa(MFA, '_').
+match_mf_args(MFA) -> match_mf_args(MFA, '_').
-match_mfa(MFA, Pid) ->
+match_mf_args(MFA, Pid) ->
[{{Pid, MFA, '_'}, [], ['$_']},
{{Pid, MFA, '_', '_', '_'}, [], ['$_']}].
+
+match_mf_arity(MFA) -> match_mf_arity(MFA, '_').
+
+match_mf_arity({M, F, Arity}, Pid) ->
+ Guard = {'=:=', Arity, {length, '$1'}},
+ [{{Pid, {M, F, '$1'}, '_'}, [Guard], ['$1']},
+ {{Pid, {M, F, '$1'}, '_', '_', '_'}, [Guard], ['$1']}].
+
+arguments_for_all_calls(MFA, History) ->
+ match_history(match_mf_arity(MFA), History).
View
@@ -72,6 +72,10 @@ meck_test_() ->
fun ?MODULE:num_calls_/1,
fun ?MODULE:num_calls_error_/1,
fun ?MODULE:num_calls_with_pid_no_args_/1,
+ fun ?MODULE:arguments_when_never_called_/1,
+ fun ?MODULE:arguments_when_called_with_different_arity_/1,
+ fun ?MODULE:arguments_when_called_once_with_same_arity_/1,
+ fun ?MODULE:arguments_when_called_multiple_times_with_same_arity_/1,
fun ?MODULE:called_wildcard_/1,
fun ?MODULE:sequence_/1,
fun ?MODULE:sequence_multi_/1,
@@ -440,6 +444,31 @@ num_calls_with_pid_no_args_(Mod) ->
?assertEqual(meck:num_calls(Mod, test, Args, '_'),
meck:num_calls(Mod, test, Args)).
+arguments_when_never_called_(Mod) ->
+ ok = meck:expect(Mod, test, 3, ok),
+ ?assertEqual([], meck:arguments(Mod, test, 3)).
+
+arguments_when_called_with_different_arity_(Mod) ->
+ ok = meck:expect(Mod, test, 3, ok),
+ ok = meck:expect(Mod, test, 1, ok),
+ ok = Mod:test(foo),
+ ?assertEqual([], meck:arguments(Mod, test, 3)).
+
+arguments_when_called_once_with_same_arity_(Mod) ->
+ ok = meck:expect(Mod, test, 3, ok),
+ ok = meck:expect(Mod, test, 1, ok),
+ ok = Mod:test(foo),
+ ok = Mod:test(foo, bar, baz),
+ ?assertEqual([[foo, bar, baz]], meck:arguments(Mod, test, 3)).
+
+arguments_when_called_multiple_times_with_same_arity_(Mod) ->
+ ok = meck:expect(Mod, test, 3, ok),
+ ok = meck:expect(Mod, test, 1, ok),
+ ok = Mod:test(foo),
+ ok = Mod:test(foo, bar, baz),
+ ok = Mod:test(7, 8, 9),
+ ?assertEqual([[foo, bar, baz], [7, 8, 9]], meck:arguments(Mod, test, 3)).
+
expect_apply(Mod, Func, Args) ->
ok = meck:expect(Mod, Func, length(Args), ok),
ok = apply(Mod, Func, Args).