1 %%%---------------------------------------------------------------------------
3 %%% Functions to use when running test cases.
5 %%%---------------------------------------------------------------------------
15 -export_type([test/0, test_plan/0]).
17 %%%---------------------------------------------------------------------------
20 -type test() :: {Func :: {module(), atom()}, Description :: string(),
21 Status :: run | {todo | skip, Why :: string()}}.
23 -type test_plan() :: {plan, pos_integer()} | no_plan.
26 %%%---------------------------------------------------------------------------
28 %%%---------------------------------------------------------------------------
30 %%----------------------------------------------------------
32 %% @doc Run tests according to plan.
34 -spec run(test_plan(), [test()]) ->
38 TestRun = case Plan of
39 no_plan -> estap_server:no_plan();
40 {plan, C} -> estap_server:plan(C)
42 run_tests(TestRun, Tests),
43 estap_server:done(TestRun).
45 %% @doc Run tests, one by one, reporting their results to tracking process.
47 %% @TODO Return something meaningful.
49 -spec run_tests(estap_server:test_run_id(), [test()]) ->
52 run_tests(_TestRun, [] = _Tests) ->
54 run_tests(TestRun, [{TestFunSpec, Description, Status} | Rest] = _Tests) ->
55 estap_server:running(TestRun, Description),
58 case test(TestFunSpec) of
60 estap_server:test_passed(TestRun);
62 estap_server:test_failed(TestRun, Result);
64 estap_server:dubious_result(TestRun, Result);
66 estap_server:test_died(TestRun, Reason)
69 %estap_server:test_todo(TestRun, Why)
70 case test(TestFunSpec) of
72 estap_server:test_todo(TestRun, success, Why);
74 estap_server:test_todo(TestRun, {failure, Result}, Why);
76 estap_server:test_todo(TestRun, {dubious, Result}, Why);
78 estap_server:test_todo(TestRun, {died, Reason}, Why)
81 estap_server:test_skipped(TestRun, Why)
83 run_tests(TestRun, Rest).
85 %% @doc Run a single test function, according to its specification.
87 -spec test({Module :: module(), Function :: atom()}) ->
93 test({Mod, Func} = _TestFunSpec) ->
95 ResultRef = make_ref(),
96 ResultTo = {self(), ResultRef},
97 {Pid, MonRef} = spawn_monitor(?MODULE, call, [ResultTo, Mod, Func, Args]),
99 {result, ResultRef, TestResult} ->
100 erlang:demonitor(MonRef, [flush]),
102 {'DOWN', MonRef, process, Pid, Reason} ->
107 %% @doc Run the specified function, collect its result (possibly thrown) and
108 %% report it back to `ResultTo'.
110 -spec call({pid(), term()}, module(), atom(), [term()]) ->
113 call({Pid, Ref} = _ResultTo, Mod, Fun, Args) ->
114 TestResult = try apply(Mod, Fun, Args) of
116 {ok, Value} -> {success, {ok, Value}};
117 true -> {success, true};
118 error -> {failure, error};
119 {error, Reason} -> {failure, {error, Reason}};
120 false -> {failure, false};
121 Result -> {dubious, Result}
123 throw:ok -> {success, ok};
124 throw:{ok, Value} -> {success, {ok, Value}};
125 throw:true -> {success, true};
126 throw:error -> {failure, error};
127 throw:{error, Reason} -> {failure, {error, Reason}};
128 throw:false -> {failure, false}
130 Pid ! {result, Ref, TestResult},
133 %%----------------------------------------------------------
135 %%%---------------------------------------------------------------------------
136 %%% vim:ft=erlang:foldmethod=marker