1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2006-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%%
22-module(andor_SUITE).
23
24-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
25	 init_per_testcase/2,end_per_testcase/2,
26	 init_per_suite/1,end_per_suite/1,
27	 t_andalso/1,t_orelse/1,inside/1,overlap/1,
28	 combined/1,in_case/1]).
29
30-include_lib("common_test/include/ct.hrl").
31
32-warning("Ignore me -- testing that the debugger can handle warnings").
33
34suite() ->
35    [{ct_hooks,[ts_install_cth]},
36     {timetrap,{minutes,1}}].
37
38all() ->
39    cases().
40
41groups() ->
42    [].
43
44init_per_group(_GroupName, Config) ->
45    Config.
46
47end_per_group(_GroupName, Config) ->
48    Config.
49
50
51init_per_testcase(_Case, Config) ->
52    test_lib:interpret(?MODULE),
53    Config.
54
55end_per_testcase(_Case, _Config) ->
56    ok.
57
58init_per_suite(Config) when is_list(Config) ->
59    test_lib:interpret(?MODULE),
60    true = lists:member(?MODULE, int:interpreted()),
61    Config.
62
63end_per_suite(Config) when is_list(Config) ->
64    ok.
65
66cases() ->
67    [t_andalso, t_orelse, inside, overlap, combined,
68     in_case].
69
70t_andalso(Config) when is_list(Config) ->
71    Bs = [true,false],
72    Ps = [{X,Y} || X <- Bs, Y <- Bs],
73    lists:foreach(fun (P) -> t_andalso_1(P) end, Ps),
74
75    true = true andalso true,
76    false = true andalso false,
77    false = false andalso true,
78    false = false andalso false,
79
80    false = false andalso glurf,
81    false = false andalso exit(exit_now),
82
83    true = not id(false) andalso not id(false),
84    false = not id(false) andalso not id(true),
85    false = not id(true) andalso not id(false),
86    false = not id(true) andalso not id(true),
87
88    {'EXIT',{badarg,_}} = (catch not id(glurf) andalso id(true)),
89    {'EXIT',{badarg,_}} = (catch not id(false) andalso not id(glurf)),
90    false = id(false) andalso not id(glurf),
91    false = false andalso not id(glurf),
92
93    ok.
94
95t_orelse(Config) when is_list(Config) ->
96    Bs = [true,false],
97    Ps = [{X,Y} || X <- Bs, Y <- Bs],
98    lists:foreach(fun (P) -> t_orelse_1(P) end, Ps),
99
100    true = true orelse true,
101    true = true orelse false,
102    true = false orelse true,
103    false = false orelse false,
104
105    true = true orelse glurf,
106    true = true orelse exit(exit_now),
107
108    true = not id(false) orelse not id(false),
109    true = not id(false) orelse not id(true),
110    true = not id(true) orelse not id(false),
111    false = not id(true) orelse not id(true),
112
113    {'EXIT',{badarg,_}} = (catch not id(glurf) orelse id(true)),
114    {'EXIT',{badarg,_}} = (catch not id(true) orelse not id(glurf)),
115    true = id(true) orelse not id(glurf),
116    true = true orelse not id(glurf),
117
118    ok.
119
120t_andalso_1({X,Y}) ->
121    io:fwrite("~w andalso ~w: ",[X,Y]),
122    V1 = echo(X) andalso echo(Y),
123    V1 = if
124	     X andalso Y -> true;
125	     true -> false
126	 end,
127    check(V1, X and Y).
128
129t_orelse_1({X,Y}) ->
130    io:fwrite("~w orelse ~w: ",[X,Y]),
131    V1 = echo(X) orelse echo(Y),
132    V1 = if
133	     X orelse Y -> true;
134	     true -> false
135	 end,
136    check(V1, X or Y).
137
138inside(Config) when is_list(Config) ->
139    true = inside(-8, 1),
140    false = inside(-53.5, -879798),
141    false = inside(1.0, -879),
142    false = inside(59, -879),
143    false = inside(-11, 1.0),
144    false = inside(100, 0.2),
145    false = inside(100, 1.2),
146    false = inside(-53.5, 4),
147    false = inside(1.0, 5.3),
148    false = inside(59, 879),
149    ok.
150
151inside(Xm, Ym) ->
152    X = -10.0,
153    Y = -2.0,
154    W = 20.0,
155    H = 4.0,
156    Res = inside(Xm, Ym, X, Y, W, H),
157    Res = if
158	      X =< Xm andalso Xm < X+W andalso Y =< Ym andalso Ym < Y+H -> true;
159	      true -> false
160	  end,
161    case not id(Res) of
162	Outside ->
163	    Outside = if
164			  not(X =< Xm andalso Xm < X+W andalso Y =< Ym andalso Ym < Y+H) -> true;
165			  true -> false
166		      end
167    end,
168    {Res,Xm,Ym,X,Y,W,H} = inside_guard(Xm, Ym, X, Y, W, H),
169    io:format("~p =< ~p andalso ~p < ~p andalso ~p =< ~p andalso ~p < ~p ==> ~p",
170	      [X,Xm,Xm,X+W,Y,Ym,Ym,Y+H,Res]),
171    Res.
172
173inside(Xm, Ym, X, Y, W, H) ->
174    X =< Xm andalso Xm < X+W andalso Y =< Ym andalso Ym < Y+H.
175
176inside_guard(Xm, Ym, X, Y, W, H) when X =< Xm andalso Xm < X+W
177				      andalso Y =< Ym andalso Ym < Y+H ->
178    {true,Xm,Ym,X,Y,W,H};
179inside_guard(Xm, Ym, X, Y, W, H) ->
180    {false,Xm,Ym,X,Y,W,H}.
181
182overlap(Config) when is_list(Config) ->
183    true = overlap(7.0, 2.0, 8.0, 0.5),
184    true = overlap(7.0, 2.0, 8.0, 2.5),
185    true = overlap(7.0, 2.0, 5.3, 2),
186    true = overlap(7.0, 2.0, 0.0, 100.0),
187
188    false = overlap(-1, 2, -35, 0.5),
189    false = overlap(-1, 2, 777, 0.5),
190    false = overlap(-1, 2, 2, 10),
191    false = overlap(2, 10, 12, 55.3),
192    ok.
193
194overlap(Pos1, Len1, Pos2, Len2) ->
195    Res = case Pos1 of
196	      Pos1 when (Pos2 =< Pos1 andalso Pos1 < Pos2+Len2)
197			orelse (Pos1 =< Pos2 andalso Pos2 < Pos1+Len1) ->
198		  true;
199	      Pos1 -> false
200	  end,
201    Res = (Pos2 =< Pos1 andalso Pos1 < Pos2+Len2)
202	orelse (Pos1 =< Pos2 andalso Pos2 < Pos1+Len1),
203    Res = case Pos1 of
204	      Pos1 when (Pos2 =< Pos1 andalso Pos1 < Pos2+Len2)
205			orelse (Pos1 =< Pos2 andalso Pos2 < Pos1+Len1) ->
206		  true;
207	      Pos1 -> false
208	  end,
209    id(Res).
210
211
212-define(COMB(A,B,C), (A andalso B orelse C)).
213
214combined(Config) when is_list(Config) ->
215    false = comb(false, false, false),
216    true = comb(false, false, true),
217    false = comb(false, true, false),
218    true = comb(false, true, true),
219
220    false = comb(true, false, false),
221    true = comb(true, true, false),
222    true = comb(true, false, true),
223    true = comb(true, true, true),
224
225    false = comb(false, blurf, false),
226    true = comb(false, blurf, true),
227    true = comb(true, true, blurf),
228
229    false = ?COMB(false, false, false),
230    true = ?COMB(false, false, true),
231    false = ?COMB(false, true, false),
232    true = ?COMB(false, true, true),
233
234    false = ?COMB(true, false, false),
235    true = ?COMB(true, true, false),
236    true = ?COMB(true, false, true),
237    true = ?COMB(true, true, true),
238
239    false = ?COMB(false, blurf, false),
240    true = ?COMB(false, blurf, true),
241    true = ?COMB(true, true, blurf),
242
243    ok.
244-undef(COMB).
245
246comb(A, B, C) ->
247    Res = A andalso B orelse C,
248    Res = if
249	      A andalso B orelse C -> true;
250	      true -> false
251	  end,
252    NotRes = if
253		 not(A andalso B orelse C) -> true;
254		 true -> false
255	     end,
256    NotRes = id(not Res),
257    Res = A andalso B orelse C,
258    Res = if
259	      A andalso B orelse C -> true;
260	      true -> false
261	  end,
262    NotRes = id(not Res),
263    Res = if
264	      A andalso B orelse C -> true;
265	      true -> false
266	  end,
267    id(Res).
268
269%% Test that a boolean expression in a case expression is properly
270%% optimized (in particular, that the error behaviour is correct).
271in_case(Config) when is_list(Config) ->
272    edge_rings = in_case_1(1, 1, 1, 1, 1),
273    not_loop = in_case_1(0.5, 1, 1, 1, 1),
274    loop = in_case_1(0.5, 0.9, 1.1, 1, 4),
275    {'EXIT',{badarith,_}} = (catch in_case_1(1, 1, 1, 1, 0)),
276    {'EXIT',{badarith,_}} = (catch in_case_1(1, 1, 1, 1, nan)),
277    {'EXIT',{badarg,_}} = (catch in_case_1(1, 1, 1, blurf, 1)),
278    {'EXIT',{badarith,_}} = (catch in_case_1([nan], 1, 1, 1, 1)),
279    ok.
280
281in_case_1(LenUp, LenDw, LenN, Rotation, Count) ->
282    Res = in_case_1_body(LenUp, LenDw, LenN, Rotation, Count),
283    Res = in_case_1_guard(LenUp, LenDw, LenN, Rotation, Count),
284    Res.
285
286in_case_1_body(LenUp, LenDw, LenN, Rotation, Count) ->
287    case (LenUp/Count > 0.707) and (LenN/Count > 0.707) and
288	(abs(Rotation) > 0.707) of
289	true ->
290	    edge_rings;
291	false ->
292	    case (LenUp >= 1) or (LenDw >= 1) or
293		(LenN =< 1) or (Count < 4) of
294		true ->
295		    not_loop;
296		false ->
297		    loop
298	    end
299    end.
300
301in_case_1_guard(LenUp, LenDw, LenN, Rotation, Count) ->
302    case (LenUp/Count > 0.707) andalso (LenN/Count > 0.707) andalso
303	(abs(Rotation) > 0.707) of
304	true -> edge_rings;
305	false when LenUp >= 1 orelse LenDw >= 1 orelse
306		   LenN =< 1 orelse Count < 4 -> not_loop;
307	false -> loop
308    end.
309
310check(V1, V0) ->
311    if V1 /= V0 ->
312	    io:fwrite("error: ~w.\n", [V1]),
313	    ct:fail(failed);
314       true ->
315	    io:fwrite("ok: ~w.\n", [V1])
316    end.
317
318echo(X) ->
319    io:fwrite("eval(~w); ",[X]),
320    X.
321
322id(I) -> I.
323