1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2001-2018. 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(andor_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 t_case/1,t_and_or/1,t_andalso/1,t_orelse/1,inside/1,overlap/1, 25 combined/1,in_case/1,slow_compilation/1]). 26 27-include_lib("common_test/include/ct.hrl"). 28 29suite() -> [{ct_hooks,[ts_install_cth]}]. 30 31all() -> 32 [{group,p}]. 33 34groups() -> 35 [{p,[parallel], 36 [t_case,t_and_or,t_andalso,t_orelse,inside,overlap, 37 combined,in_case,slow_compilation]}]. 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 52 53t_case(Config) when is_list(Config) -> 54 %% We test boolean cases almost but not quite like cases 55 %% generated by andalso/orelse. 56 less = t_case_a(1, 2), 57 not_less = t_case_a(2, 2), 58 {'EXIT',{{case_clause,false},_}} = (catch t_case_b({x,y,z}, 2)), 59 {'EXIT',{{case_clause,true},_}} = (catch t_case_b(a, a)), 60 eq = t_case_c(a, a), 61 ne = t_case_c(42, []), 62 t = t_case_d(x, x, true), 63 f = t_case_d(x, x, false), 64 f = t_case_d(x, y, true), 65 {'EXIT',{badarg,_}} = (catch t_case_d(x, y, blurf)), 66 true = (catch t_case_e({a,b}, {a,b})), 67 false = (catch t_case_e({a,b}, 42)), 68 69 true = t_case_xy(42, 100, 700), 70 true = t_case_xy(42, 100, whatever), 71 false = t_case_xy(42, wrong, 700), 72 false = t_case_xy(42, wrong, whatever), 73 74 true = t_case_xy(0, whatever, 700), 75 true = t_case_xy(0, 100, 700), 76 false = t_case_xy(0, whatever, wrong), 77 false = t_case_xy(0, 100, wrong), 78 79 ok. 80 81t_case_a(A, B) -> 82 case A < B of 83 [_|_] -> ok; 84 true -> less; 85 false -> not_less; 86 {a,b,c} -> ok; 87 _Var -> ok 88 end. 89 90t_case_b(A, B) -> 91 case A =:= B of 92 blurf -> ok 93 end. 94 95t_case_c(A, B) -> 96 case not(A =:= B) of 97 true -> ne; 98 false -> eq 99 end. 100 101t_case_d(A, B, X) -> 102 case (A =:= B) and X of 103 true -> t; 104 false -> f 105 end. 106 107t_case_e(A, B) -> 108 case A =:= B of 109 Bool when is_tuple(A) -> id(Bool) 110 end. 111 112t_case_xy(X, Y, Z) -> 113 Res = t_case_x(X, Y, Z), 114 Res = t_case_y(X, Y, Z). 115 116t_case_x(X, Y, Z) -> 117 case abs(X) =:= 42 of 118 true -> 119 Y =:= 100; 120 false -> 121 Z =:= 700 122 end. 123 124t_case_y(X, Y, Z) -> 125 case abs(X) =:= 42 of 126 false -> 127 Z =:= 700; 128 true -> 129 Y =:= 100 130 end. 131 132-define(GUARD(E), if E -> true; 133 true -> false 134 end). 135 136t_and_or(Config) when is_list(Config) -> 137 true = true and true, 138 false = true and false, 139 false = false and true, 140 false = false and false, 141 142 true = id(true) and true, 143 false = id(true) and false, 144 false = id(false) and true, 145 false = id(false) and false, 146 147 true = true and id(true), 148 false = true and id(false), 149 false = false and id(true), 150 false = false and id(false), 151 152 true = true or true, 153 true = true or false, 154 true = false or true, 155 false = false or false, 156 157 true = id(true) or true, 158 true = id(true) or false, 159 true = id(false) or true, 160 false = id(false) or false, 161 162 true = true or id(true), 163 true = true or id(false), 164 true = false or id(true), 165 false = false or id(false), 166 167 True = id(true), 168 169 false = ?GUARD(erlang:'and'(bar, True)), 170 false = ?GUARD(erlang:'or'(bar, True)), 171 false = ?GUARD(erlang:'not'(erlang:'and'(bar, True))), 172 false = ?GUARD(erlang:'not'(erlang:'not'(erlang:'and'(bar, True)))), 173 174 true = (fun (X = true) when X or true or X -> true end)(True), 175 176 Tuple = id({a,b}), 177 case Tuple of 178 {_,_} -> 179 {'EXIT',{badarg,_}} = (catch true and Tuple) 180 end, 181 182 ok. 183 184t_andalso(Config) when is_list(Config) -> 185 Bs = [true,false], 186 Ps = [{X,Y} || X <- Bs, Y <- Bs], 187 lists:foreach(fun (P) -> t_andalso_1(P) end, Ps), 188 189 true = true andalso true, 190 false = true andalso false, 191 false = false andalso true, 192 false = false andalso false, 193 194 true = ?GUARD(true andalso true), 195 false = ?GUARD(true andalso false), 196 false = ?GUARD(false andalso true), 197 false = ?GUARD(false andalso false), 198 199 false = false andalso glurf, 200 false = false andalso exit(exit_now), 201 202 true = not id(false) andalso not id(false), 203 false = not id(false) andalso not id(true), 204 false = not id(true) andalso not id(false), 205 false = not id(true) andalso not id(true), 206 207 {'EXIT',{badarg,_}} = (catch not id(glurf) andalso id(true)), 208 {'EXIT',{badarg,_}} = (catch not id(false) andalso not id(glurf)), 209 false = id(false) andalso not id(glurf), 210 false = false andalso not id(glurf), 211 212 true = begin (X1 = true) andalso X1, X1 end, 213 false = false = begin (X2 = false) andalso X2, X2 end, 214 215 ok. 216 217t_orelse(Config) when is_list(Config) -> 218 Bs = [true,false], 219 Ps = [{X,Y} || X <- Bs, Y <- Bs], 220 lists:foreach(fun (P) -> t_orelse_1(P) end, Ps), 221 222 true = true orelse true, 223 true = true orelse false, 224 true = false orelse true, 225 false = false orelse false, 226 227 true = ?GUARD(true orelse true), 228 true = ?GUARD(true orelse false), 229 true = ?GUARD(false orelse true), 230 false = ?GUARD(false orelse false), 231 232 true = true orelse glurf, 233 true = true orelse exit(exit_now), 234 235 true = not id(false) orelse not id(false), 236 true = not id(false) orelse not id(true), 237 true = not id(true) orelse not id(false), 238 false = not id(true) orelse not id(true), 239 240 {'EXIT',{badarg,_}} = (catch not id(glurf) orelse id(true)), 241 {'EXIT',{badarg,_}} = (catch not id(true) orelse not id(glurf)), 242 true = id(true) orelse not id(glurf), 243 true = true orelse not id(glurf), 244 245 true = begin (X1 = true) orelse X1, X1 end, 246 false = begin (X2 = false) orelse X2, X2 end, 247 248 ok. 249 250t_andalso_1({X,Y}) -> 251 io:fwrite("~w andalso ~w: ",[X,Y]), 252 V1 = echo(X) andalso echo(Y), 253 V1 = if 254 X andalso Y -> true; 255 true -> false 256 end, 257 V1 = id(X and Y). 258 259t_orelse_1({X,Y}) -> 260 io:fwrite("~w orelse ~w: ",[X,Y]), 261 V1 = echo(X) orelse echo(Y), 262 V1 = if 263 X orelse Y -> true; 264 true -> false 265 end, 266 V1 = id(X or Y). 267 268inside(Config) when is_list(Config) -> 269 true = inside(-8, 1), 270 false = inside(-53.5, -879798), 271 false = inside(1.0, -879), 272 false = inside(59, -879), 273 false = inside(-11, 1.0), 274 false = inside(100, 0.2), 275 false = inside(100, 1.2), 276 false = inside(-53.5, 4), 277 false = inside(1.0, 5.3), 278 false = inside(59, 879), 279 ok. 280 281inside(Xm, Ym) -> 282 X = -10.0, 283 Y = -2.0, 284 W = 20.0, 285 H = 4.0, 286 Res = inside(Xm, Ym, X, Y, W, H), 287 Res = if 288 X =< Xm andalso Xm < X+W andalso Y =< Ym andalso Ym < Y+H -> true; 289 true -> false 290 end, 291 case not id(Res) of 292 Outside -> 293 Outside = if 294 not(X =< Xm andalso Xm < X+W andalso Y =< Ym andalso Ym < Y+H) -> true; 295 true -> false 296 end 297 end, 298 {Res,Xm,Ym,X,Y,W,H} = inside_guard(Xm, Ym, X, Y, W, H), 299 io:format("~p =< ~p andalso ~p < ~p andalso ~p =< ~p andalso ~p < ~p ==> ~p", 300 [X,Xm,Xm,X+W,Y,Ym,Ym,Y+H,Res]), 301 Res. 302 303inside(Xm, Ym, X, Y, W, H) -> 304 X =< Xm andalso Xm < X+W andalso Y =< Ym andalso Ym < Y+H. 305 306inside_guard(Xm, Ym, X, Y, W, H) when X =< Xm andalso Xm < X+W 307 andalso Y =< Ym andalso Ym < Y+H -> 308 {true,Xm,Ym,X,Y,W,H}; 309inside_guard(Xm, Ym, X, Y, W, H) -> 310 {false,Xm,Ym,X,Y,W,H}. 311 312overlap(Config) when is_list(Config) -> 313 true = overlap(7.0, 2.0, 8.0, 0.5), 314 true = overlap(7.0, 2.0, 8.0, 2.5), 315 true = overlap(7.0, 2.0, 5.3, 2), 316 true = overlap(7.0, 2.0, 0.0, 100.0), 317 318 false = overlap(-1, 2, -35, 0.5), 319 false = overlap(-1, 2, 777, 0.5), 320 false = overlap(-1, 2, 2, 10), 321 false = overlap(2, 10, 12, 55.3), 322 ok. 323 324overlap(Pos1, Len1, Pos2, Len2) -> 325 Res = case Pos1 of 326 Pos1 when (Pos2 =< Pos1 andalso Pos1 < Pos2+Len2) 327 orelse (Pos1 =< Pos2 andalso Pos2 < Pos1+Len1) -> 328 true; 329 Pos1 -> false 330 end, 331 Res = (Pos2 =< Pos1 andalso Pos1 < Pos2+Len2) 332 orelse (Pos1 =< Pos2 andalso Pos2 < Pos1+Len1), 333 Res = case Pos1 of 334 Pos1 when (Pos2 =< Pos1 andalso Pos1 < Pos2+Len2) 335 orelse (Pos1 =< Pos2 andalso Pos2 < Pos1+Len1) -> 336 true; 337 Pos1 -> false 338 end, 339 id(Res). 340 341 342-define(COMB(A,B,C), (A andalso B orelse C)). 343 344combined(Config) when is_list(Config) -> 345 false = comb(false, false, false), 346 true = comb(false, false, true), 347 false = comb(false, true, false), 348 true = comb(false, true, true), 349 350 false = comb(true, false, false), 351 true = comb(true, true, false), 352 true = comb(true, false, true), 353 true = comb(true, true, true), 354 355 false = comb(false, blurf, false), 356 true = comb(false, blurf, true), 357 true = comb(true, true, blurf), 358 359 false = ?COMB(false, false, false), 360 true = ?COMB(false, false, true), 361 false = ?COMB(false, true, false), 362 true = ?COMB(false, true, true), 363 364 false = ?COMB(true, false, false), 365 true = ?COMB(true, true, false), 366 true = ?COMB(true, false, true), 367 true = ?COMB(true, true, true), 368 369 false = ?COMB(false, blurf, false), 370 true = ?COMB(false, blurf, true), 371 true = ?COMB(true, true, blurf), 372 373 false = simple_comb(false, false), 374 false = simple_comb(false, true), 375 false = simple_comb(true, false), 376 true = simple_comb(true, true), 377 378 ok. 379-undef(COMB). 380 381comb(A, B, C) -> 382 Res = A andalso B orelse C, 383 Res = if 384 A andalso B orelse C -> true; 385 true -> false 386 end, 387 NotRes = if 388 not(A andalso B orelse C) -> true; 389 true -> false 390 end, 391 NotRes = id(not Res), 392 Res = A andalso B orelse C, 393 Res = if 394 A andalso B orelse C -> true; 395 true -> false 396 end, 397 NotRes = id(not Res), 398 Res = if 399 A andalso B orelse C -> true; 400 true -> false 401 end, 402 id(Res). 403 404simple_comb(A, B) -> 405 %% Use Res twice, to ensure that a careless optimization of 'not' 406 %% doesn't leave Res as a free variable. 407 Res = A andalso B, 408 _ = id(not Res), 409 Res. 410 411%% Test that a boolean expression in a case expression is properly 412%% optimized (in particular, that the error behaviour is correct). 413in_case(Config) when is_list(Config) -> 414 edge_rings = in_case_1(1, 1, 1, 1, 1), 415 not_loop = in_case_1(0.5, 1, 1, 1, 1), 416 loop = in_case_1(0.5, 0.9, 1.1, 1, 4), 417 {'EXIT',{badarith,_}} = (catch in_case_1(1, 1, 1, 1, 0)), 418 {'EXIT',{badarith,_}} = (catch in_case_1(1, 1, 1, 1, nan)), 419 {'EXIT',{badarg,_}} = (catch in_case_1(1, 1, 1, blurf, 1)), 420 {'EXIT',{badarith,_}} = (catch in_case_1([nan], 1, 1, 1, 1)), 421 ok. 422 423in_case_1(LenUp, LenDw, LenN, Rotation, Count) -> 424 Res = in_case_1_body(LenUp, LenDw, LenN, Rotation, Count), 425 Res = in_case_1_guard(LenUp, LenDw, LenN, Rotation, Count), 426 Res. 427 428in_case_1_body(LenUp, LenDw, LenN, Rotation, Count) -> 429 case (LenUp/Count > 0.707) and (LenN/Count > 0.707) and 430 (abs(Rotation) > 0.707) of 431 true -> 432 edge_rings; 433 false -> 434 case (LenUp >= 1) or (LenDw >= 1) or 435 (LenN =< 1) or (Count < 4) of 436 true -> 437 not_loop; 438 false -> 439 loop 440 end 441 end. 442 443in_case_1_guard(LenUp, LenDw, LenN, Rotation, Count) -> 444 case (LenUp/Count > 0.707) andalso (LenN/Count > 0.707) andalso 445 (abs(Rotation) > 0.707) of 446 true -> edge_rings; 447 false when LenUp >= 1 orelse LenDw >= 1 orelse 448 LenN =< 1 orelse Count < 4 -> not_loop; 449 false -> loop 450 end. 451 452-record(state, {stack = []}). 453 454slow_compilation(_) -> 455 %% The function slow_compilation_1 used to compile very slowly. 456 ok = slow_compilation_1({a}, #state{}). 457 458slow_compilation_1(T1, #state{stack = [T2|_]}) 459 when element(1, T2) == a, element(1, T1) == b, element(1, T1) == c -> 460 ok; 461slow_compilation_1(T, _) 462 when element(1, T) == a1; element(1, T) == b1; element(1, T) == c1 -> 463 ok; 464slow_compilation_1(T, _) 465 when element(1, T) == a2; element(1, T) == b2; element(1, T) == c2 -> 466 ok; 467slow_compilation_1(T, _) when element(1, T) == a -> 468 ok; 469slow_compilation_1(T, _) 470 when 471 element(1, T) == a, 472 (element(1, T) == b) and (element(1, T) == c) -> 473 ok; 474slow_compilation_1(_, T) when element(1, T) == a -> 475 ok; 476slow_compilation_1(_, T) when element(1, T) == b -> 477 ok; 478slow_compilation_1(T, _) when element(1, T) == a -> 479 ok. 480 481%% Utilities. 482 483echo(X) -> 484 io:fwrite("eval(~w); ",[X]), 485 X. 486 487id(I) -> I. 488