1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2011-2020. 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-module(beam_except_SUITE).
21
22-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
23	 init_per_group/2,end_per_group/2,
24	 multiple_allocs/1,bs_get_tail/1,coverage/1,
25         binary_construction_allocation/1]).
26
27suite() -> [{ct_hooks,[ts_install_cth]}].
28
29all() ->
30    [{group,p}].
31
32groups() ->
33    [{p,[parallel],
34      [multiple_allocs,
35       bs_get_tail,
36       coverage,
37       binary_construction_allocation]}].
38
39init_per_suite(Config) ->
40    test_lib:recompile(?MODULE),
41    Config.
42
43end_per_suite(_Config) ->
44    ok.
45
46init_per_group(_GroupName, Config) ->
47    Config.
48
49end_per_group(_GroupName, Config) ->
50    Config.
51
52multiple_allocs(_Config) ->
53    {'EXIT',{{badmatch,#{true:=[p]}},_}} =
54	 (catch could(pda, 0.0, {false,true}, {p})),
55    {'EXIT',{{bad_generator,0},_}} = (catch place(lee)),
56    {'EXIT',{{badmatch,wanted},_}} = (catch conditions()),
57
58    ok.
59
60could(Coupons = pda, Favorite = _pleasure = 0.0, {_, true}, {Presents}) ->
61  (0 = true) = #{true => [Presents]}.
62
63place(lee) ->
64    (pregnancy = presentations) = [hours | [purchase || _ <- 0]] + wine.
65
66conditions() ->
67    (talking = going) = storage + [large = wanted].
68
69bs_get_tail(Config) ->
70    {<<"abc">>,0,0,Config} = bs_get_tail_1(id(<<0:32, "abc">>), 0, 0, Config),
71    {'EXIT',
72     {function_clause,
73      [{?MODULE,bs_get_tail_1,[<<>>,0,0,Config],_}|_]}} =
74        (catch bs_get_tail_1(id(<<>>), 0, 0, Config)),
75
76    ok = bs_get_tail_2(<<"W">>, <<"X">>, <<"Z">>),
77    ok = bs_get_tail_2(<<"M">>, <<"X">>, <<"Z">>),
78    {'EXIT',
79     {function_clause,
80      [{?MODULE,do_get_bs_tail_2,[<<"A">>,<<"B">>,[],<<"C">>],_}|_]}} =
81        (catch bs_get_tail_2(<<"A">>, <<"B">>, <<"C">>)),
82
83    ok.
84
85bs_get_tail_1(<<_:32, Rest/binary>>, Z1, Z2, F1) ->
86    {Rest,Z1,Z2,F1}.
87
88bs_get_tail_2(A, B, C) ->
89    do_get_bs_tail_2(A, B, [], C).
90
91do_get_bs_tail_2(<<"W">>, <<"X">>, _, <<"Z">>) -> ok;
92do_get_bs_tail_2(<<"M">>, <<"X">>, _, <<"Z">>) -> ok.
93
94coverage(_) ->
95    File = {file,"fake.erl"},
96    ok = fc(a),
97    {'EXIT',{function_clause,
98	     [{?MODULE,fc,[[x]],[File,{line,2}]}|_]}} =
99	(catch fc([x])),
100    {'EXIT',{function_clause,
101	     [{?MODULE,fc,[y],[File,{line,2}]}|_]}} =
102	(catch fc(y)),
103    case ?MODULE of
104        beam_except_no_opt_SUITE ->
105            %% There will be a different stack fram in
106            %% unoptimized code.
107            ok;
108        _ ->
109            {'EXIT',{function_clause,
110                     [{?MODULE,fc,[[a,b,c]],[File,{line,6}]}|_]}} =
111                (catch fc([a,b,c]))
112    end,
113
114    {'EXIT',{undef,[{erlang,error,[a,b,c,d],_}|_]}} =
115	(catch erlang:error(a, b, c, d)),
116
117    {'EXIT',{badarith,[{?MODULE,bar,1,[File,{line,9}]}|_]}} =
118	(catch bar(x)),
119    {'EXIT',{{case_clause,{1}},[{?MODULE,bar,1,[File,{line,9}]}|_]}} =
120	(catch bar(0)),
121
122    Self = self(),
123    {'EXIT',{{strange,Self},[{?MODULE,foo,[any],[File,{line,14}]}|_]}} =
124        (catch foo(any)),
125
126    {ok,succeed,1,2} = foobar(succeed, 1, 2),
127    {'EXIT',{function_clause,[{?MODULE,foobar,[[fail],1,2],
128                               [{file,"fake.erl"},{line,16}]}|_]}} =
129        (catch foobar([fail], 1, 2)),
130    {'EXIT',{function_clause,[{?MODULE,fake_function_clause1,[{a,b},42.0],_}|_]}} =
131        (catch fake_function_clause1({a,b})),
132
133    {'EXIT',{function_clause,[{?MODULE,fake_function_clause2,[42|bad_tl],_}|_]}} =
134        (catch fake_function_clause2(42, bad_tl)),
135    {'EXIT',{function_clause,[{?MODULE,fake_function_clause3,[x,y],_}|_]}} =
136        (catch fake_function_clause3(42, id([x,y]))),
137
138    {'EXIT',{{badmatch,0.0},_}} = (catch coverage_1(id(42))),
139    {'EXIT',{badarith,_}} = (catch coverage_1(id(a))),
140
141    ok.
142
143coverage_1(X) ->
144    %% ERL-1167: Would crash beam_except.
145    true = 0 / X.
146
147fake_function_clause1(A) -> error(function_clause, [A,42.0]).
148fake_function_clause2(A, Tl) -> error(function_clause, [A|Tl]).
149fake_function_clause3(_, Stk) -> error(function_clause, Stk).
150
151binary_construction_allocation(_Config) ->
152    ok = do_binary_construction_allocation("PUT"),
153    ok.
154
155do_binary_construction_allocation(Req) ->
156    %% Allocation for building the error term was done by the
157    %% bs_init2 instruction. beam_except crashed because it expected
158    %% an explicit allocation instruction.
159    ok = case Req of
160             "POST" -> {error, <<"BAD METHOD ", Req/binary>>, Req};
161             _ -> ok
162         end.
163
164id(I) -> I.
165
166-file("fake.erl", 1).
167fc(a) ->	                                %Line 2
168    ok;						%Line 3
169fc(L) when length(L) > 2 ->			%Line 4
170    %% Not the same as a "real" function_clause error.
171    error(function_clause, [L]).		%Line 6
172%% Would crash the compiler.
173bar(X) ->					%Line 8
174    case {X+1} of				%Line 9
175	1 -> ok					%Line 10
176    end.					%Line 11
177%% Cover collection code for function_clause exceptions.
178foo(A) ->                                       %Line 13
179    error({strange,self()}, [A]).               %Line 14
180%% Cover beam_except:tag_literal/1.
181foobar(A, B, C) when is_atom(A) ->              %Line 16
182    {ok,A,B,C}.                                 %Line 17
183