Skip to content

Commit

Permalink
Add sequence/4 expect function
Browse files Browse the repository at this point in the history
The sequence/4 expect function will return a sequence of results until
the list is exhausted where the last element will be returned
indefinately.
  • Loading branch information
eproxus committed May 25, 2011
1 parent 6680628 commit 35de01e
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 5 deletions.
43 changes: 39 additions & 4 deletions src/meck.erl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
-export([new/2]).
-export([expect/3]).
-export([expect/4]).
-export([sequence/4]).
-export([delete/3]).
-export([exception/2]).
-export([passthrough/1]).
Expand Down Expand Up @@ -138,6 +139,25 @@ expect(Mod, Func, Arity, Result) when is_list(Mod) ->
lists:foreach(fun(M) -> expect(M, Func, Arity, Result) end, Mod),
ok.

%% @spec sequence(Mod:: atom() | list(atom()), Func::atom(),
%% Arity::pos_integer(), Sequence::[term()]) -> ok
%% @doc Adds an expectation with the supplied arity which returns a
%% value from `Sequence' one at a time.
%%
%% This creates an expectation which takes `Arity' number of arguments
%% and returns one element from `Sequence' at a time. Thus, calls to
%% this expect will exhaust the list of return values in order until
%% the last value is reached. That value is then returned for all
%% subsequent calls.
-spec sequence(Mod:: atom() | [atom()], Func::atom(),
Arity::pos_integer(), Result::[term()]) -> ok.
sequence(Mod, Func, Arity, Sequence)
when is_atom(Mod), is_atom(Func), is_integer(Arity), Arity >= 0 ->
call(Mod, {sequence, Func, Arity, Sequence});
sequence(Mod, Func, Arity, Sequence) when is_list(Mod) ->
lists:foreach(fun(M) -> sequence(M, Func, Arity, Sequence) end, Mod),
ok.

%% @spec delete(Mod:: atom() | list(atom()), Func::atom(),
%% Arity::pos_integer()) -> ok
%% @doc Deletes an expectation.
Expand Down Expand Up @@ -243,15 +263,19 @@ init([Mod, Options]) ->

%% @hidden
handle_call({get_expect, Func, Arity}, _From, S) ->
Expect = get_expect(S#state.expects, Func, Arity),
{reply, Expect, S};
{Expect, NewExpects} = get_expect(S#state.expects, Func, Arity),
{reply, Expect, S#state{expects = NewExpects}};
handle_call({expect, Func, Expect}, _From, S) ->
NewExpects = store_expect(S#state.mod, Func, Expect, S#state.expects),
{reply, ok, S#state{expects = NewExpects}};
handle_call({expect, Func, Arity, Result}, _From, S) ->
NewExpects = store_expect(S#state.mod, Func, {anon, Arity, Result},
S#state.expects),
{reply, ok, S#state{expects = NewExpects}};
handle_call({sequence, Func, Arity, Sequence}, _From, S) ->
NewExpects = store_expect(S#state.mod, Func, {sequence, Arity, Sequence},
S#state.expects),
{reply, ok, S#state{expects = NewExpects}};
handle_call({delete, Func, Arity}, _From, S) ->
NewExpects = delete_expect(S#state.mod, Func, Arity, S#state.expects),
{reply, ok, S#state{expects = NewExpects}};
Expand Down Expand Up @@ -349,7 +373,15 @@ init_expects(Mod, Options) ->


get_expect(Expects, Func, Arity) ->
e_fetch(Expects, Func, Arity).
case e_fetch(Expects, Func, Arity) of
{sequence, Arity, [Last]} ->
{{sequence, Arity, Last}, Expects};
{sequence, Arity, [Result|Rest]} ->
{{sequence, Arity, Result},
e_store(Expects, Func, {sequence, Arity, Rest})};
Other ->
{Other, Expects}
end.

store_expect(Mod, Func, Expect, Expects) ->
change_expects(fun e_store/3, Mod, Func, Expect, Expects).
Expand Down Expand Up @@ -407,7 +439,7 @@ var(Name) -> {var, ?LINE, Name}.

var_name(A) -> list_to_atom("A"++integer_to_list(A)).

arity({anon, Arity, _Result}) ->
arity({Type, Arity, _Result}) when Type == anon; Type == sequence ->
Arity;
arity(Fun) when is_function(Fun) ->
{arity, Arity} = erlang:fun_info(Fun, arity),
Expand Down Expand Up @@ -455,6 +487,9 @@ passthrough_fun(Args) -> fun() -> {passthrough, Args} end.
call_expect(_Mod, _Func, {anon, Arity, Return}, VarList)
when Arity == length(VarList) ->
Return;
call_expect(_Mod, _Func, {sequence, Arity, Return}, VarList)
when Arity == length(VarList) ->
Return;
call_expect(Mod, Func, passthrough, VarList) ->
apply(original_name(Mod), Func, VarList);
call_expect(_Mod, _Func, Fun, VarList) when is_function(Fun) ->
Expand Down
28 changes: 27 additions & 1 deletion test/meck_tests.erl
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ meck_test_() ->
fun called_false_few_args_/1,
fun called_true_few_args_/1,
fun called_false_error_/1,
fun called_true_error_/1
fun called_true_error_/1,
fun sequence_/1,
fun sequence_multi_/1
]]}.

setup() ->
Expand Down Expand Up @@ -372,6 +374,30 @@ called_true_error_(Mod) ->
?assertEqual(true, meck:called(Mod, test, Args)),
?assert(meck:validate(Mod)).

sequence_(Mod) ->
Sequence = [a, b, c, d, e],
?assertEqual(ok, meck:sequence(Mod, s, 2, Sequence)),
?assertEqual(Sequence,
[Mod:s(a, b) || _ <- lists:seq(1, length(Sequence))]),
?assertEqual([e, e, e, e, e],
[Mod:s(a, b) || _ <- lists:seq(1, 5)]),
?assert(meck:validate(Mod)).

sequence_multi_(Mod) ->
meck:new(mymod2),
Mods = [Mod, mymod2],
Sequence = [a, b, c, d, e],
?assertEqual(ok, meck:sequence(Mods, s, 2, Sequence)),
?assertEqual(Sequence,
[Mod:s(a, b) || _ <- lists:seq(1, length(Sequence))]),
?assertEqual([e, e, e, e, e],
[Mod:s(a, b) || _ <- lists:seq(1, 5)]),
?assertEqual(Sequence,
[mymod2:s(a, b) || _ <- lists:seq(1, length(Sequence))]),
?assertEqual([e, e, e, e, e],
[mymod2:s(a, b) || _ <- lists:seq(1, 5)]),
?assert(meck:validate(Mods)).

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

call_original_test() ->
Expand Down

0 comments on commit 35de01e

Please sign in to comment.