manopapad/proper — pull request #58 by norton (2012-12-19 04:57:01+00:00)
Title: Permit caller to "prime" PropEr's typeserver and random generator prior to testing

The motivation of this change request is to permit testing of a
module's exported functions by using both PropEr *and* Meck. Before
Meck is enabled to mock a module, the cache of PropEr's typeserver
must be first populated. Otherwise, PropEr is unable to gather a
module's specs.

Sample code to illustrate this technique:

````
-spec check_specs(module()) -> term().
check_specs(Mod) ->
%% pass through to the original Function Under Test (FUT)
check_specs(Mod, fun(_Module, _Fun, Args) -> meck:passthrough(Args) end, [], []).

-spec check_specs(module(), fun((module(), atom(), list()) -> term())) -> term().
check_specs(Mod, FUT) ->
check_specs(Mod, FUT, [], []).

-spec check_specs(module(), fun((module(), atom(), list()) -> term()), proplist()) -> term().
check_specs(Mod, FUT, PropErOptions) ->
check_specs(Mod, FUT, PropErOptions, []).

-spec check_specs(module(), fun((module(), atom(), list()) -> term()), proplist(), proplist()) -> term().
check_specs(Mod, FUT, PropErOptions, MeckOptions) ->
proper:global_state_erase(),
proper:global_state_init_size(1),
case proper_typeserver:get_exp_specced(Mod) of
{ok, MFAs} ->
meck:new(Mod, MeckOptions),
try
%% @NOTE Expand MFA clauses for larger arity as needed
Fun = fun({M,F,0}) ->
meck:expect(M,F, fun() -> FUT(M, F, []) end);
({M,F,1}) ->
meck:expect(M,F, fun(A1) -> FUT(M, F, [A1]) end);
({M,F,2}) ->
meck:expect(M,F, fun(A1, A2) -> FUT(M, F, [A1, A2]) end)
end,
lists:foreach(Fun, MFAs),
proper:check_specs(Mod, PropErOptions)
after
meck:unload(Mod)
end;
{error,Reason} ->
error(Reason, [Mod, PropErOptions, MeckOptions])
end.
````