Packages

Yet another mocking library for Erlang

Current section

Files

Jump to
hoax src hoax.erl
Raw

src/hoax.erl

-module(hoax).
-export([start/0, stop/0]).
-export([expect/1]).
-export([mock/2, stub/3, mock_behaviour/3, arguments/1]).
-export([fixture/1, fixture/2, fixture/3, fixture/4, test/1]).
-export([parameterized_fixture/3, parameterized_fixture/4]).
-ignore_xref([mock/2, stub/3, mock_behaviour/3]).
-ifdef(HOAX_SUPPRESS_DEPRECATION_WARNING).
-define(DEPRECATION_WARNING(_), warning_ignored).
-else.
-include_lib("eunit/include/eunit.hrl").
-define(DEPRECATION_WARNING(Msg), ?debugMsg(Msg)).
-endif.
-include("hoax_int.hrl").
%% ===================================================================
%% hoax API
%% ===================================================================
start() ->
hoax_tab:exists() andalso stop(),
hoax_tab:create().
stop() ->
lists:foreach(
fun hoax_code:purge_and_delete/1,
hoax_tab:delete()).
expect(RecordList) when is_list(RecordList) ->
ByModule = lists:foldr(
fun (Rec = #expectation{key={Mod,_,_}}, Dict) ->
dict:append(Mod, Rec, Dict)
end,
dict:new(),
RecordList),
dict:fold(
fun (ModuleName, Records, _) ->
Exports = hoax_code:get_export_list(ModuleName, Records),
hoax_expect:assert_exported(Records, Exports),
Forms = hoax_module:generate(ModuleName, Exports),
hoax_code:compile(ModuleName, Forms)
end,
ok,
ByModule).
mock(ModuleName, Expectation) when is_tuple(Expectation) ->
mock(ModuleName, [Expectation]);
mock(ModuleName, Expectations) ->
Records = hoax_expect:parse(ModuleName, Expectations),
Exports = hoax_code:get_export_list(ModuleName, Records),
hoax_expect:assert_exported(Records, Exports),
Forms = hoax_module:generate(ModuleName, Exports),
hoax_code:compile(ModuleName, Forms).
mock_behaviour(Behaviour, ModuleName, Expectation) when is_tuple(Expectation) ->
mock_behaviour(Behaviour, ModuleName, [Expectation]);
mock_behaviour(Behaviour, ModuleName, Expectations) ->
Records = hoax_expect:parse(ModuleName, Expectations),
Callbacks = hoax_code:get_callback_list(Behaviour, ModuleName),
hoax_expect:assert_exported(Records, Callbacks),
Forms = hoax_module:generate(ModuleName, Callbacks),
hoax_code:compile(ModuleName, Forms).
stub(B, M, E) ->
?DEPRECATION_WARNING("WARNING: hoax:stub/3 is deprecated. Use hoax:mock_behaviour/3 instead."),
mock_behaviour(B, M, E).
arguments(F) when is_function(F) ->
Info = erlang:fun_info(F),
Module = proplists:get_value(module, Info),
Name = proplists:get_value(name, Info),
Arity = proplists:get_value(arity, Info),
arguments({Module, Name, Arity});
arguments({_Module, _Name, _Arity} = Key) ->
lists:append([Args || #expectation{actual_args=Args} <- hoax_tab:lookup_expectations(Key)]).
fixture(Module) ->
fixture_tuple(Module, 0, fun default_test_selector/1).
fixture(Module, Prefix) ->
fixture_tuple(Module, 0, prefix_test_selector(Prefix)).
fixture(Module, Setup, Teardown) when is_atom(Setup), is_atom(Teardown) ->
fixture_tuple(Module, 0, Setup, Teardown, setup_teardown_test_selector(Setup, Teardown)).
fixture(Module, Prefix, Setup, Teardown) when is_atom(Setup), is_atom(Teardown) ->
fixture_tuple(Module, 0, Setup, Teardown, prefix_setup_teardown_test_selector(Prefix, Setup, Teardown)).
parameterized_fixture(Module, Setup, Teardown) when is_atom(Setup), is_atom(Teardown) ->
fixture_tuple(Module, 1, Setup, Teardown, setup_teardown_test_selector(Setup, Teardown)).
parameterized_fixture(Module, Prefix, Setup, Teardown) when is_atom(Setup), is_atom(Teardown) ->
fixture_tuple(Module, 1, Setup, Teardown, prefix_setup_teardown_test_selector(Prefix, Setup, Teardown)).
test(Func) when is_function(Func, 0) ->
try
start(),
Func()
after
stop()
end.
default_test_selector(Func) ->
Name = atom_to_list(Func),
Func =/= module_info andalso
Func =/= test andalso
(not lists:suffix("_test", Name)) andalso
(not lists:suffix("_test_", Name)).
prefix_to_list(Prefix) when is_list(Prefix) -> Prefix;
prefix_to_list(Prefix) when is_atom(Prefix) -> atom_to_list(Prefix).
prefix_test_selector(Prefix) ->
fun(F) ->
default_test_selector(F) andalso lists:prefix(prefix_to_list(Prefix), atom_to_list(F))
end.
setup_teardown_test_selector(Setup, Teardown) ->
fun(F) ->
default_test_selector(F) andalso F =/= Setup andalso F =/= Teardown
end.
prefix_setup_teardown_test_selector(Prefix, Setup, Teardown) ->
fun(F) ->
default_test_selector(F) andalso F =/= Setup andalso F =/= Teardown andalso
lists:prefix(prefix_to_list(Prefix), atom_to_list(F))
end.
fixture_tuple(Module, Arity, Selector) ->
fixture_tuple(Module, Arity, fun() -> ok end, fun(_) -> ok end, Selector).
fixture_tuple(Module, Arity, UserSetup, UserTeardown, Selector) when is_atom(UserSetup), is_atom(UserTeardown) ->
fixture_tuple(Module, Arity, fun Module:UserSetup/0, fun Module:UserTeardown/1, Selector);
fixture_tuple(Module, Arity, UserSetup, UserTeardown, Selector) when is_function(UserSetup), is_function(UserTeardown) ->
Tests = [fun Module:F/Arity || {F, A} <- Module:module_info(exports), A == Arity, Selector(F) == true],
TestList = case Arity of
0 -> Tests;
1 -> [{with, [T]} || T <- Tests]
end,
{foreach,
fun() -> fixture_setup(UserSetup) end,
fun(X) -> UserTeardown(X), stop() end,
TestList
}.
fixture_setup(UserSetup) ->
try
start(),
UserSetup()
catch
X:Y ->
stop(),
erlang:X(Y)
end.