summaryrefslogtreecommitdiff
path: root/src/cth_fail_fast.erl
blob: 13b35570dde73c6f7f98a4665cc026833ab5f348 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
-module(cth_fail_fast).

%% Callbacks
-export([id/1]).
-export([init/2]).

-export([pre_init_per_suite/3]).
-export([post_init_per_suite/4]).
-export([pre_end_per_suite/3]).
-export([post_end_per_suite/4]).

-export([pre_init_per_group/3]).
-export([post_init_per_group/4]).
-export([pre_end_per_group/3]).
-export([post_end_per_group/4]).

-export([pre_init_per_testcase/3]).
-export([post_end_per_testcase/4]).

-export([on_tc_fail/3]).
-export([on_tc_skip/3, on_tc_skip/4]).

-export([terminate/1]).

%% We work by setting an 'abort' variable on each test case that fails
%% and then triggering the failure before starting the next test. This
%% ensures that all other hooks have run for the same event, and
%% simplifies error reporting.
-record(state, {abort=false}).

%% @doc Return a unique id for this CTH.
id(_Opts) ->
    {?MODULE, make_ref()}.

%% @doc Always called before any other callback function. Use this to initiate
%% any common state.
init(_Id, _Opts) ->
    {ok, #state{}}.

%% @doc Called before init_per_suite is called.
pre_init_per_suite(_Suite,_Config,#state{abort=true}) ->
    abort();
pre_init_per_suite(_Suite,Config,State) ->
    {Config, State}.

%% @doc Called after init_per_suite.
post_init_per_suite(_Suite,_Config,Return,State) ->
    {Return, State}.

%% @doc Called before end_per_suite.
pre_end_per_suite(_Suite,_Config,#state{abort=true}) ->
    abort();
pre_end_per_suite(_Suite,Config,State) ->
    {Config, State}.

%% @doc Called after end_per_suite.
post_end_per_suite(_Suite,_Config,Return,State) ->
    {Return, State}.

%% @doc Called before each init_per_group.
pre_init_per_group(_Group,_Config,#state{abort=true}) ->
    abort();
pre_init_per_group(_Group,Config,State) ->
    {Config, State}.

%% @doc Called after each init_per_group.
post_init_per_group(_Group,_Config,Return, State) ->
    {Return, State}.

%% @doc Called after each end_per_group.
pre_end_per_group(_Group,_Config,#state{abort=true}) ->
    abort();
pre_end_per_group(_Group,Config,State) ->
    {Config, State}.

%% @doc Called after each end_per_group.
post_end_per_group(_Group,_Config,Return, State) ->
    {Return, State}.

%% @doc Called before each test case.
pre_init_per_testcase(_TC,_Config,#state{abort=true}) ->
    abort();
pre_init_per_testcase(_TC,Config,State) ->
    {Config, State}.

%% @doc Called after each test case.
post_end_per_testcase(_TC,_Config,ok,State) ->
    {ok, State};
post_end_per_testcase(_TC,_Config,Error,State) ->
    {Error, State#state{abort=true}}.

%% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
%% post_end_per_group and post_end_per_testcase if the suite, group or test case failed.
on_tc_fail(_TC, _Reason, State) ->
    State.

%% @doc Called when a test case is skipped by either user action
%% or due to an init function failing. (>= 19.3)
on_tc_skip(_Suite, _TC, {tc_auto_skip, _}, State) ->
    State#state{abort=true};
on_tc_skip(_Suite, _TC, _Reason, State) ->
    State.

%% @doc Called when a test case is skipped by either user action
%% or due to an init function failing. (Pre-19.3)
on_tc_skip(_TC, {tc_auto_skip, _}, State) ->
    State#state{abort=true};
on_tc_skip(_TC, _Reason, State) ->
    State.

%% @doc Called when the scope of the CTH is done
terminate(#state{}) ->
    ok.

%%% Helpers
abort() ->
    io:format(user, "Detected test failure. Aborting~n", []),
    halt(1).