1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%%
21-module(exception_SUITE).
22
23-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
24	 init_per_testcase/2,end_per_testcase/2,
25	 init_per_suite/1,end_per_suite/1,
26	 badmatch/1,pending_errors/1,nil_arith/1,
27         stacktrace/1,nested_stacktrace/1,raise/1,gunilla/1,per/1]).
28
29-export([bad_guy/2]).
30
31-include_lib("common_test/include/ct.hrl").
32
33suite() ->
34    [{ct_hooks,[ts_install_cth]},
35     {timetrap,{minutes,1}}].
36
37%% Filler.
38%%
39%%
40%% This is line 40.
41even(N) when is_integer(N), N > 1, (N rem 2) == 0 ->
42    odd(N-1)++[N].
43
44odd(N) when is_integer(N), N > 1, (N rem 2) == 1 ->
45    even(N-1)++[N].
46
47
48all() ->
49    cases().
50
51groups() ->
52    [].
53
54init_per_group(_GroupName, Config) ->
55    Config.
56
57end_per_group(_GroupName, Config) ->
58    Config.
59
60
61cases() ->
62    [badmatch, pending_errors, nil_arith, stacktrace,
63     nested_stacktrace, raise, gunilla, per].
64
65-define(try_match(E),
66	catch ?MODULE:bar(),
67	{'EXIT', {{badmatch, nomatch}, _}} = (catch E = nomatch)).
68
69init_per_testcase(_Case, Config) ->
70    test_lib:interpret(?MODULE),
71    Config.
72
73end_per_testcase(_Case, _Config) ->
74    ok.
75
76init_per_suite(Config) when is_list(Config) ->
77    test_lib:interpret(?MODULE),
78    true = lists:member(?MODULE, int:interpreted()),
79    Config.
80
81end_per_suite(Config) when is_list(Config) ->
82    ok.
83
84%% Test that deliberately bad matches are reported correctly.
85
86badmatch(Config) when is_list(Config) ->
87    ?try_match(a),
88    ?try_match(42),
89    ?try_match({a, b, c}),
90    ?try_match([]),
91    ?try_match(1.0),
92    ok.
93
94%% Test various exceptions, in the presence of a previous error suppressed
95%% in a guard.
96pending_errors(Config) when is_list(Config) ->
97    pending(e_badmatch, {badmatch, b}),
98    pending(x, function_clause),
99    pending(e_case, {case_clause, xxx}),
100    pending(e_if, if_clause),
101    pending(e_badarith, badarith),
102    pending(e_undef, undef),
103    pending(e_timeoutval, timeout_value),
104    pending(e_badarg, badarg),
105    pending(e_badarg_spawn, badarg),
106    ok.
107
108bad_guy(pe_badarith, Other) when Other+1 == 0 -> % badarith (suppressed)
109    ok;
110bad_guy(pe_badarg, Other) when length(Other) > 0 -> % badarg (suppressed)
111    ok;
112bad_guy(_, e_case) ->
113    case id(xxx) of
114	ok -> ok
115    end;					% case_clause
116bad_guy(_, e_if) ->
117    if
118	a == b -> ok
119    end;					% if_clause
120bad_guy(_, e_badarith) ->
121    1+b;					% badarith
122bad_guy(_, e_undef) ->
123    non_existing_module:foo();			% undef
124bad_guy(_, e_timeoutval) ->
125    receive
126    after arne ->				% timeout_value
127	    ok
128    end;
129bad_guy(_, e_badarg) ->
130    node(xxx);					% badarg
131bad_guy(_, e_badarg_spawn) ->
132    spawn({}, {}, {});				% badarg
133bad_guy(_, e_badmatch) ->
134    a = id(b).					% badmatch
135
136pending(Arg, Expected) ->
137    pending(pe_badarith, Arg, Expected),
138    pending(pe_badarg, Arg, Expected).
139
140pending(First, Second, Expected) ->
141    pending_catched(First, Second, Expected),
142    pending_exit_message([First, Second], Expected).
143
144pending_catched(First, Second, Expected) ->
145    ok = io:format("Catching bad_guy(~p, ~p)", [First, Second]),
146    case catch bad_guy(First, Second) of
147	{'EXIT', Reason} ->
148	    pending(Reason, bad_guy, [First, Second], Expected);
149	Other ->
150	    ct:fail({not_exit, Other})
151    end.
152
153pending_exit_message(Args, Expected) ->
154    ok = io:format("Trapping EXITs from spawn_link(~p, ~p, ~p)",
155		   [?MODULE, bad_guy, Args]),
156    process_flag(trap_exit, true),
157    Pid = spawn_link(?MODULE, bad_guy, Args),
158    receive
159	{'EXIT', Pid, Reason} ->
160	    pending(Reason, bad_guy, Args, Expected);
161	Other ->
162	    ct:fail({unexpected_message, Other})
163    after 10000 ->
164	    ct:fail(timeout)
165    end,
166    process_flag(trap_exit, false).
167
168pending({badarg, [{erlang,Bif,BifArgs,_},{?MODULE,Func,Arity,_}|_]},
169	Func, Args, _Code)
170  when is_atom(Bif), is_list(BifArgs), length(Args) == Arity ->
171    ok;
172pending({undef,[{non_existing_module,foo,[],_}|_]}, _, _, _) ->
173    ok;
174pending({function_clause,[{?MODULE,Func,Args,_}|_]}, Func, Args, _Code) ->
175    ok;
176pending({Code,[{?MODULE,Func,Arity,_}|_]}, Func, Args, Code)
177  when length(Args) == Arity ->
178    ok;
179pending(Reason, _Function, _Args, _Code) ->
180    ct:fail({bad_exit_reason,Reason}).
181
182%% Test that doing arithmetics on [] gives a badarith EXIT and not a crash.
183
184nil_arith(Config) when is_list(Config) ->
185    ba_plus_minus_times([], []),
186
187    ba_plus_minus_times([], 0),
188    ba_plus_minus_times([], 42),
189    ba_plus_minus_times([], 38724978123478923784),
190    ba_plus_minus_times([], 38.72),
191
192    ba_plus_minus_times(0, []),
193    ba_plus_minus_times(334, []),
194    ba_plus_minus_times(387249797813478923784, []),
195    ba_plus_minus_times(344.22, []),
196
197    ba_div_rem([], []),
198
199    ba_div_rem([], 0),
200    ba_div_rem([], 1),
201    ba_div_rem([], 42),
202    ba_div_rem([], 38724978123478923784),
203    ba_div_rem(344.22, []),
204
205    ba_div_rem(0, []),
206    ba_div_rem(1, []),
207    ba_div_rem(334, []),
208    ba_div_rem(387249797813478923784, []),
209    ba_div_rem(344.22, []),
210
211    ba_div_rem(344.22, 0.0),
212    ba_div_rem(1, 0.0),
213    ba_div_rem(392873498733971, 0.0),
214
215    ba_bop([], []),
216    ba_bop(0, []),
217    ba_bop(42, []),
218    ba_bop(-42342742987343, []),
219    ba_bop(238.342, []),
220    ba_bop([], 0),
221    ba_bop([], -243),
222    ba_bop([], 243),
223    ba_bop([], 2438724982478933),
224    ba_bop([], 3987.37),
225
226    ba_bnot([]),
227    ba_bnot(23.33),
228
229    ba_shift([], []),
230    ba_shift([], 0),
231    ba_shift([], 4),
232    ba_shift([], -4),
233    ba_shift([], 2343333333333),
234    ba_shift([], -333333333),
235    ba_shift([], 234.00),
236    ba_shift(23, []),
237    ba_shift(0, []),
238    ba_shift(-3433443433433323, []),
239    ba_shift(433443433433323, []),
240    ba_shift(343.93, []),
241    ok.
242
243ba_plus_minus_times(A, B) ->
244    io:format("~p + ~p", [A, B]),
245    {'EXIT', {badarith, _}} = (catch A + B),
246    io:format("~p - ~p", [A, B]),
247    {'EXIT', {badarith, _}} = (catch A - B),
248    io:format("~p * ~p", [A, B]),
249    {'EXIT', {badarith, _}} = (catch A * B).
250
251ba_div_rem(A, B) ->
252    io:format("~p / ~p", [A, B]),
253    {'EXIT', {badarith, _}} = (catch A / B),
254    io:format("~p div ~p", [A, B]),
255    {'EXIT', {badarith, _}} = (catch A div B),
256    io:format("~p rem ~p", [A, B]),
257    {'EXIT', {badarith, _}} = (catch A rem B).
258
259ba_bop(A, B) ->
260    io:format("~p band ~p", [A, B]),
261    {'EXIT', {badarith, _}} = (catch A band B),
262    io:format("~p bor ~p", [A, B]),
263    {'EXIT', {badarith, _}} = (catch A bor B),
264    io:format("~p bxor ~p", [A, B]),
265    {'EXIT', {badarith, _}} = (catch A bxor B).
266
267ba_shift(A, B) ->
268    io:format("~p bsl ~p", [A, B]),
269    {'EXIT', {badarith, _}} = (catch A bsl B),
270    io:format("~p bsr ~p", [A, B]),
271    {'EXIT', {badarith, _}} = (catch A bsr B).
272
273ba_bnot(A) ->
274    io:format("bnot ~p", [A]),
275    {'EXIT', {badarith, _}} = (catch bnot A).
276
277stacktrace(Conf) when is_list(Conf) ->
278    V = [make_ref()|self()],
279    {value2,{caught1,badarg,[{erlang,abs,[V],_}|_]=St1}} =
280	stacktrace_1({'abs',V}, error, {value,V}),
281    {caught2,{error,badarith},[{?MODULE,my_add,2,_}|_]=St2} =
282	stacktrace_1({'div',{1,0}}, error, {'add',{0,a}}),
283    {caught2,{error,{try_clause,V}},[{?MODULE,stacktrace_1,3,_}|_]=St3} =
284	stacktrace_1({value,V}, error, {value,V}),
285    {caught2,{throw,V},[{?MODULE,foo,1,_}|_]=St4} =
286	stacktrace_1({value,V}, error, {throw,V}),
287    ok.
288
289stacktrace_1(X, C1, Y) ->
290    try try foo(X) of
291            C1 -> value1
292        catch
293            C1:D1:S1 -> {caught1,D1,S1}
294        after
295	    foo(Y)
296        end of
297        V2 -> {value2,V2}
298    catch
299        C2:D2:S2 -> {caught2,{C2,D2},S2}
300    end.
301
302
303
304nested_stacktrace(Conf) when is_list(Conf) ->
305    V = [{make_ref()}|[self()]],
306    value1 = nested_stacktrace_1({{value,{V,x1}},void,{V,x1}},
307                                 {void,void,void}),
308    {caught1,
309     [{?MODULE,my_add,2,_}|_],
310     value2} = nested_stacktrace_1({{'add',{V,x1}},error,badarith},
311                                   {{value,{V,x2}},void,{V,x2}}),
312    {caught1,
313     [{?MODULE,my_add,2,_}|_],
314     {caught2,[{erlang,abs,[V],_}|_]}} =
315	nested_stacktrace_1({{'add',{V,x1}},error,badarith},
316			    {{'abs',V},error,badarg}),
317    ok.
318
319nested_stacktrace_1({X1,C1,V1}, {X2,C2,V2}) ->
320    try foo(X1) of
321        V1 -> value1
322    catch
323        C1:V1:S1 ->
324            T2 = try foo(X2) of
325                     V2 -> value2
326                 catch
327                     C2:V2:S2 -> {caught2,S2}
328                end,
329            {caught1,S1,T2}
330    end.
331
332
333
334raise(Conf) when is_list(Conf) ->
335    erase(raise),
336    A =
337	try
338	    try foo({'div',{1,0}})
339	    catch
340		error:badarith:A0 ->
341		    put(raise, A0),
342		    erlang:raise(error, badarith, A0)
343	    end
344	catch
345	    error:badarith:A1 ->
346		A1 = get(raise)
347	end,
348    [{?MODULE,my_div,2,_}|_] = A,
349    %%
350    N = 8, % Must be even
351    N = erlang:system_flag(backtrace_depth, N),
352    try even(N)
353    catch error:function_clause -> ok
354    end,
355    %%
356    C = odd_even(N+1, []),
357    try
358        odd(N+1)
359    catch
360        error:function_clause -> ok
361    end,
362    try
363        erlang:raise(error, function_clause, C)
364    catch
365        error:function_clause -> ok
366    end,
367    ok.
368
369odd_even(N, R) when is_integer(N), N > 1 ->
370    odd_even(N-1,
371	     [if (N rem 2) == 0 ->
372		      {?MODULE,even,1,[{file,?MODULE_STRING++".erl"},
373				       {line,42}]};
374		 true ->
375		      {?MODULE,odd,1,[{file,?MODULE_STRING++".erl"},
376				      {line,45}]}
377	      end|R]);
378odd_even(1, R) ->
379    [{?MODULE,odd,[1],[{file,?MODULE_STRING++".erl"},
380		       {line,44}]}|R].
381
382foo({value,Value}) -> Value;
383foo({'div',{A,B}}) ->
384    my_div(A, B);
385foo({'add',{A,B}}) ->
386    my_add(A, B);
387foo({'abs',X}) ->
388    my_abs(X);
389foo({error,Error}) ->
390    erlang:error(Error);
391foo({throw,Throw}) ->
392    erlang:throw(Throw);
393foo({exit,Exit}) ->
394    erlang:exit(Exit);
395foo({raise,{Class,Reason,Stacktrace}}) ->
396    erlang:raise(Class, Reason, Stacktrace).
397%%foo(function_clause) -> % must not be defined!
398
399my_div(A, B) ->
400    A div B.
401
402my_add(A, B) ->
403    A + B.
404
405my_abs(X) -> abs(X).
406
407gunilla(Config) when is_list(Config) ->
408    {throw,kalle} = gunilla_1(),
409    ok.
410
411gunilla_1() ->
412    try try arne()
413	after
414	    pelle
415	end
416    catch
417	C:R ->
418	    {C,R}
419    end.
420
421arne() ->
422    %% Empty stack trace used to cause change the error class to 'error'.
423    erlang:raise(throw, kalle, []).
424
425per(Config) when is_list(Config) ->
426    try
427	t1(0,pad,0),
428	t2(0,pad,0)
429    catch
430	error:badarith ->
431	    ok
432    end.
433
434t1(_,X,_) ->
435    (1 bsl X) + 1.
436
437t2(_,X,_) ->
438    (X bsl 1) + 1.
439
440id(I) -> I.
441