Packages

A collection of goodies for the property-based testing framework PropEr

Current section

Files

Jump to
proper_contrib src proper_contrib_statem.erl
Raw

src/proper_contrib_statem.erl

%%==============================================================================
%% Helper Functions for the proper_statem module
%%==============================================================================
-module(proper_contrib_statem).
%%==============================================================================
%% API
%%==============================================================================
-export([ run/1
, run/2
]).
%%==============================================================================
%% Includes
%%==============================================================================
-include_lib("proper/include/proper.hrl").
%%==============================================================================
%% Type Definitions
%%==============================================================================
-type symbolic_call() :: {'call', atom(), atom(), [any()]}.
-type symbolic_var() :: {'var', pos_integer()}.
-type command() :: {'set', symbolic_var(), symbolic_call()}
| {'init', any()}.
-type command_list() :: [command()].
-type history() :: [{any(), any()}].
-type options() :: #{ setup_fun => fun(() -> any())
, teardown_fun => fun((any()) -> ok)
, cleanup_fun => fun(() -> ok)
, whenfail_fun => fun(( command_list()
, history()
, any()
, any()
) -> ok)
}.
%%==============================================================================
%% API
%%==============================================================================
-spec run(atom()) ->
{'setup', fun((...) -> fun(() -> any())), boolean()}.
run(Module) ->
run(Module, #{}).
-spec run(atom(), options()) ->
{'setup', fun((...) -> fun(() -> any())), boolean()}.
run(Module, Options) ->
SetupFun = maps:get(setup_fun , Options, fun() -> ok end),
TearDownFun = maps:get(teardown_fun , Options, fun(_) -> ok end),
CleanupFun = maps:get(cleanup_fun , Options, fun() -> ok end),
WhenFail = maps:get(whenfail_fun , Options, fun whenfail_fun/4),
?SETUP( fun() ->
Data = SetupFun(),
fun() -> TearDownFun(Data) end
end
, ?FORALL( Cmds
, proper_statem:commands(Module)
, begin
CleanupFun(),
{ History
, State
, Result
} = proper_statem:run_commands(Module, Cmds),
?WHENFAIL(
WhenFail(Cmds, History, State, Result),
proper:aggregate( proper_statem:command_names(Cmds)
, Result =:= ok
)
)
end
)).
%%==============================================================================
%% Internal Functions
%%==============================================================================
-spec whenfail_fun( command_list()
, history()
, any()
, any()
) -> ok.
whenfail_fun(Cmds, History, State, Result) ->
Names = proper_statem:command_names(Cmds),
AnnotatedHistory = lists:zip(lists:sublist(Names, 1, length(History)), History),
io:format("Annotated History: ~p\nState: ~p\nResult: ~p\nCmd Names: ~p\n",
[ AnnotatedHistory
, State
, Result
, Names
]).