From c3b086d38bd152af39381bfae96c1e9ce7e7be9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 12 Aug 2010 16:20:20 +0200 Subject: Add test suite for debugger --- lib/debugger/test/guard_SUITE.erl | 1479 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1479 insertions(+) create mode 100644 lib/debugger/test/guard_SUITE.erl (limited to 'lib/debugger/test/guard_SUITE.erl') diff --git a/lib/debugger/test/guard_SUITE.erl b/lib/debugger/test/guard_SUITE.erl new file mode 100644 index 0000000000..b5269989c8 --- /dev/null +++ b/lib/debugger/test/guard_SUITE.erl @@ -0,0 +1,1479 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(guard_SUITE). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + bad_arith/1,bad_tuple/1,test_heap_guards/1,guard_bifs/1, + type_tests/1,const_guard/1, + const_cond/1,basic_not/1,complex_not/1, + semicolon/1,complex_semicolon/1,comma/1, + or_guard/1,more_or_guards/1, + complex_or_guards/1,and_guard/1, + xor_guard/1,more_xor_guards/1, + old_guard_tests/1, + build_in_guard/1,gbif/1, + t_is_boolean/1,is_function_2/1, + tricky/1,rel_ops/1, + basic_andalso_orelse/1,traverse_dcd/1, + check_qlc_hrl/1]). + +-include("test_server.hrl"). + +-export([init/4]). +-import(lists, [member/2]). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [bad_arith,bad_tuple,test_heap_guards,guard_bifs,type_tests,const_guard, + const_cond,basic_not,complex_not, + semicolon,complex_semicolon, + comma,or_guard,more_or_guards, + complex_or_guards,and_guard, + xor_guard,more_xor_guards, + build_in_guard,old_guard_tests,gbif, + t_is_boolean,is_function_2,tricky,rel_ops, + basic_andalso_orelse,traverse_dcd,check_qlc_hrl]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + ?line Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +bad_arith(doc) -> "Test that a bad arithmetic operation in a guard works correctly."; +bad_arith(suite) -> []; +bad_arith(Config) when list(Config) -> + ?line 5 = bad_arith1(2, 3), + ?line 10 = bad_arith1(1, infinity), + ?line 10 = bad_arith1(infinity, 1), + ?line 42 = bad_div(24, 0), + ok. + +bad_arith1(T1, T2) when T1+T2 < 10 -> + T1+T2; +bad_arith1(_, _) -> + 10. + +bad_div(A, B) when A/B > 0 -> + A/B; +bad_div(A, B) when A div B > 0 -> + A div B; +bad_div(_A, _B) -> + 42. + +bad_tuple(doc) -> "Test that bad arguments to element/2 are handled correctly."; +bad_tuple(suite) -> []; +bad_tuple(Config) when list(Config) -> + ?line error = bad_tuple1(a), + ?line error = bad_tuple1({a, b}), + ?line x = bad_tuple1({x, b}), + ?line y = bad_tuple1({a, b, y}), + ok. + +bad_tuple1(T) when element(1, T) == x -> x; +bad_tuple1(T) when element(3, T) == y -> y; +bad_tuple1(_) -> error. + +test_heap_guards(doc) -> ""; +test_heap_guards(suite) -> []; +test_heap_guards(Config) when list(Config) -> + ?line process_flag(trap_exit, true), + ?line Tuple = {a, tuple, is, built, here, xxx}, + ?line List = [a, list, is, built, here], + + ?line try_fun(fun a_case/1, [Tuple], [Tuple]), + ?line try_fun(fun a_case/1, [List], [List, List]), + ?line try_fun(fun a_case/1, [a], [a]), + + ?line try_fun(fun an_if/1, [Tuple], [Tuple]), + ?line try_fun(fun an_if/1, [List], [List, List]), + ?line try_fun(fun an_if/1, [a], [a]), + + ?line try_fun(fun receive_test/1, [Tuple], [Tuple]), + ?line try_fun(fun receive_test/1, [List], [List, List]), + ?line try_fun(fun receive_test/1, [a], [a]), + ok. + +a_case(V) -> + case V of + T when T == {a, tuple, is, built, here, xxx} -> + [T]; + L when L == [a, list, is, built, here] -> + [L, L]; + a -> + [a] + end. + +an_if(V) -> + if + V == {a, tuple, is, built, here, xxx} -> + [V]; + V == [a, list, is, built, here] -> + [V, V]; + V == a -> + [a] + end. + +receive_test(V) -> + self() ! V, + a_receive(). + +a_receive() -> + receive + T when T == {a, tuple, is, built, here, xxx} -> + [T]; + L when L == [a, list, is, built, here] -> + [L, L]; + a -> + [a] + end. + +try_fun(Fun, Args, Result) -> + try_fun(16, Fun, Args, Result, []). + +try_fun(0, _, _, _, _) -> + ok; +try_fun(Iter, Fun, Args, Result, Filler) -> + Pid = spawn_link(?MODULE, init, [self(),Fun,Args,list_to_tuple(Filler)]), + receive + {'EXIT',Pid,{result,Result}} -> + ?line try_fun(Iter-1, Fun, Args, Result, [0|Filler]); + {'EXIT',Pid,{result,Other}} -> + ?line io:format("Expected ~p; got ~p~n", [Result,Other]), + ?line test_server:fail(); + Other -> + ?line test_server:fail({unexpected_message,Other}) + end. + +init(_ReplyTo, Fun, Args, Filler) -> + Result = {result, apply(Fun, Args)}, + dummy(Filler), + io:format("~p: result = ~p\n", [?LINE,Result]), + exit(Result). + +dummy(_) -> + ok. + +guard_bifs(doc) -> "Test all guard bifs with nasty (but legal arguments)."; +guard_bifs(suite) -> []; +guard_bifs(Config) when list(Config) -> + ?line Big = -237849247829874297658726487367328971246284736473821617265433, + ?line Float = 387924.874, + + %% Succeding use of guard bifs. + + ?line try_gbif('abs/1', Big, -Big), + ?line try_gbif('float/1', Big, float(Big)), + ?line try_gbif('trunc/1', Float, 387924.0), + ?line try_gbif('round/1', Float, 387925.0), + ?line try_gbif('length/1', [], 0), + + ?line try_gbif('length/1', [a], 1), + ?line try_gbif('length/1', [a, b], 2), + ?line try_gbif('length/1', lists:seq(0, 31), 32), + + ?line try_gbif('hd/1', [a], a), + ?line try_gbif('hd/1', [a, b], a), + + ?line try_gbif('tl/1', [a], []), + ?line try_gbif('tl/1', [a, b], [b]), + ?line try_gbif('tl/1', [a, b, c], [b, c]), + + ?line try_gbif('size/1', {}, 0), + ?line try_gbif('size/1', {a}, 1), + ?line try_gbif('size/1', {a, b}, 2), + ?line try_gbif('size/1', {a, b, c}, 3), + ?line try_gbif('size/1', list_to_binary([]), 0), + ?line try_gbif('size/1', list_to_binary([1]), 1), + ?line try_gbif('size/1', list_to_binary([1, 2]), 2), + ?line try_gbif('size/1', list_to_binary([1, 2, 3]), 3), + + ?line try_gbif('element/2', {x}, {1, x}), + ?line try_gbif('element/2', {x, y}, {1, x}), + ?line try_gbif('element/2', {x, y}, {2, y}), + + ?line try_gbif('self/0', 0, self()), + ?line try_gbif('node/0', 0, node()), + ?line try_gbif('node/1', self(), node()), + + %% Failing use of guard bifs. + + ?line try_fail_gbif('abs/1', Big, 1), + ?line try_fail_gbif('abs/1', [], 1), + + ?line try_fail_gbif('float/1', Big, 42), + ?line try_fail_gbif('float/1', [], 42), + + ?line try_fail_gbif('trunc/1', Float, 0.0), + ?line try_fail_gbif('trunc/1', [], 0.0), + + ?line try_fail_gbif('round/1', Float, 1.0), + ?line try_fail_gbif('round/1', [], a), + + ?line try_fail_gbif('length/1', [], 1), + ?line try_fail_gbif('length/1', [a], 0), + ?line try_fail_gbif('length/1', a, 0), + ?line try_fail_gbif('length/1', {a}, 0), + + ?line try_fail_gbif('hd/1', [], 0), + ?line try_fail_gbif('hd/1', [a], x), + ?line try_fail_gbif('hd/1', x, x), + + ?line try_fail_gbif('tl/1', [], 0), + ?line try_fail_gbif('tl/1', [a], x), + ?line try_fail_gbif('tl/1', x, x), + + ?line try_fail_gbif('size/1', {}, 1), + ?line try_fail_gbif('size/1', [], 0), + ?line try_fail_gbif('size/1', [a], 1), + + ?line try_fail_gbif('element/2', {}, {1, x}), + ?line try_fail_gbif('element/2', {x}, {1, y}), + ?line try_fail_gbif('element/2', [], {1, z}), + + ?line try_fail_gbif('self/0', 0, list_to_pid("<0.0.0>")), + ?line try_fail_gbif('node/0', 0, xxxx), + ?line try_fail_gbif('node/1', self(), xxx), + ?line try_fail_gbif('node/1', yyy, xxx), + ok. + +try_gbif(Id, X, Y) -> + case guard_bif(Id, X, Y) of + {Id, X, Y} -> + io:format("guard_bif(~p, ~p, ~p) -- ok", [Id, X, Y]); + Other -> + ?line ok = io:format("guard_bif(~p, ~p, ~p) -- bad result: ~p\n", + [Id, X, Y, Other]), + ?line test_server:fail() + end. + +try_fail_gbif(Id, X, Y) -> + case catch guard_bif(Id, X, Y) of + {'EXIT', {function_clause,{?MODULE,guard_bif,[Id,X,Y]}}} -> %Jam + io:format("guard_bif(~p, ~p, ~p) -- ok", [Id,X,Y]); + {'EXIT', {function_clause,[{?MODULE,guard_bif,[Id,X,Y]}|_]}} -> %Beam + io:format("guard_bif(~p, ~p, ~p) -- ok", [Id,X,Y]); + Other -> + ?line ok = io:format("guard_bif(~p, ~p, ~p) -- bad result: ~p\n", + [Id, X, Y, Other]), + ?line test_server:fail() + end. + +guard_bif('abs/1', X, Y) when abs(X) == Y -> + {'abs/1', X, Y}; +guard_bif('float/1', X, Y) when float(X) == Y -> + {'float/1', X, Y}; +guard_bif('trunc/1', X, Y) when trunc(X) == Y -> + {'trunc/1', X, Y}; +guard_bif('round/1', X, Y) when round(X) == Y -> + {'round/1', X, Y}; +guard_bif('length/1', X, Y) when length(X) == Y -> + {'length/1', X, Y}; +guard_bif('hd/1', X, Y) when hd(X) == Y -> + {'hd/1', X, Y}; +guard_bif('tl/1', X, Y) when tl(X) == Y -> + {'tl/1', X, Y}; +guard_bif('size/1', X, Y) when size(X) == Y -> + {'size/1', X, Y}; +guard_bif('element/2', X, {Pos, Expected}) when element(Pos, X) == Expected -> + {'element/2', X, {Pos, Expected}}; +guard_bif('self/0', X, Y) when self() == Y -> + {'self/0', X, Y}; +guard_bif('node/0', X, Y) when node() == Y -> + {'node/0', X, Y}; +guard_bif('node/1', X, Y) when node(X) == Y -> + {'node/1', X, Y}. + +type_tests(doc) -> "Test the type tests."; +type_tests(suite) -> []; +type_tests(Config) when list(Config) -> + ?line Types = all_types(), + ?line Tests = type_test_desc(), + ?line put(errors, 0), + ?line put(violations, 0), + ?line type_tests(Tests, Types), + ?line case {get(errors), get(violations)} of + {0, 0} -> + ok; + {0, N} -> + {comment, integer_to_list(N) ++ " standard violation(s)"}; + {Errors, Violations} -> + io:format("~p sub test(s) failed, ~p violation(s)", + [Errors, Violations]), + ?line test_server:fail() + end. + +type_tests([{Test, AllowedTypes}| T], AllTypes) -> + type_tests(Test, AllTypes, AllowedTypes), + type_tests(T, AllTypes); +type_tests([], _) -> + ok. + +type_tests(Test, [Type|T], Allowed) -> + {TypeTag, Value} = Type, + case member(TypeTag, Allowed) of + true -> + case catch type_test(Test, Value) of + Test -> + ok; + _Other -> + io:format("Test ~p(~p) failed", [Test, Value]), + put(errors, get(errors) + 1) + end; + false -> + case catch type_test(Test, Value) of + {'EXIT', {function_clause, {?MODULE, type_test, [Test, Value]}}} -> + ok; + {'EXIT', {function_clause,[{?MODULE,type_test,[Test,Value]}|_]}} -> + ok; + {'EXIT',Other} -> + ?line test_server:fail({unexpected_error_reason,Other}); + tuple when function(Value) -> + io:format("Standard violation: Test ~p(~p) should fail", + [Test, Value]), + put(violations, get(violations) + 1); + _Other -> + io:format("Test ~p(~p) succeeded (should fail)", [Test, Value]), + put(errors, get(errors) + 1) + end + end, + type_tests(Test, T, Allowed); +type_tests(_, [], _) -> + ok. + +all_types() -> + [{small, 42}, + {big, 392742928742947293873938792874019287447829874290742}, + {float, 3.14156}, + {nil, []}, + {cons, [a]}, + {tuple, {a, b}}, + {atom, xxxx}, + {ref, make_ref()}, + {pid, self()}, + {port, open_port({spawn, efile}, [])}, + {function, fun(X) -> X+1, "" end}, + {binary, list_to_binary([])}]. + +type_test_desc() -> + [{integer, [small, big]}, + {float, [float]}, + {number, [small, big, float]}, + {atom, [atom]}, + {list, [cons, nil]}, + {nonempty_list, [cons]}, + {nil, [nil]}, + {tuple, [tuple]}, + {pid, [pid]}, + {port, [port]}, + {reference, [ref]}, + {function, [function]}]. + +type_test(integer, X) when integer(X) -> + integer; +type_test(float, X) when float(X) -> + float; +type_test(number, X) when number(X) -> + number; +type_test(atom, X) when atom(X) -> + atom; +type_test(list, X) when list(X) -> + list; +type_test(nonempty_list, [_]) -> + nonempty_list; +type_test(nil, []) -> + nil; +type_test(tuple, X) when tuple(X) -> + tuple; +type_test(pid, X) when pid(X) -> + pid; +type_test(reference, X) when reference(X) -> + reference; +type_test(port, X) when port(X) -> + port; +type_test(binary, X) when binary(X) -> + binary; +type_test(function, X) when function(X) -> + function. + +const_guard(Config) when is_list(Config) -> + ?line if + (0 == 0) and ((0 == 0) or (0 == 0)) -> + ok + end. + + +const_cond(Config) when is_list(Config) -> + ?line ok = const_cond({}, 0), + ?line ok = const_cond({a}, 1), + ?line error = const_cond({a,b}, 3), + ?line error = const_cond({a}, 0), + ?line error = const_cond({a,b}, 1), + ok. + +const_cond(T, Sz) -> + case T of + _X when false -> never; + _X when tuple(T), eq == eq, size(T) == Sz -> ok; + _X when tuple(T), eq == leq, size(T) =< Sz -> ok; + _X -> error + end. + +basic_not(Config) when is_list(Config) -> + True = id(true), + False = id(false), + Glurf = id(glurf), + A = id(5), + B = id(37.5), + C = id(-1), + D = id(5), + ATuple = {False,True,Glurf}, + + ?line check(fun() -> if not false -> ok; true -> error end end, ok), + ?line check(fun() -> if not true -> ok; true -> error end end, error), + ?line check(fun() -> if not False -> ok; true -> error end end, ok), + ?line check(fun() -> if not True -> ok; true -> error end end, error), + + ?line check(fun() -> if A > B -> gt; A < B -> lt; A == B -> eq end end, lt), + ?line check(fun() -> if A > C -> gt; A < C -> lt; A == C -> eq end end, gt), + ?line check(fun() -> if A > D -> gt; A < D -> lt; A == D -> eq end end, eq), + + ?line check(fun() -> if not (7 > 453) -> le; not (7 < 453) -> ge; + not (7 == 453) -> ne; true -> eq end end, le), + ?line check(fun() -> if not (7 > -8) -> le; not (7 < -8) -> ge; + not (7 == -8) -> ne; true -> eq end end, ge), + ?line check(fun() -> if not (7 > 7) -> le; not (7 < 7) -> ge; + not (7 == 7) -> ne; true -> eq end end, le), + + ?line check(fun() -> if not (A > B) -> le; not (A < B) -> ge; + not (A == B) -> ne; true -> eq end end, le), + ?line check(fun() -> if not (A > C) -> le; not (A < C) -> ge; + not (A == C) -> ne; true -> eq end end, ge), + ?line check(fun() -> if not (A > D) -> le; not (A < D) -> ge; + not (A == D) -> ne; true -> eq end end, le), + + ?line check(fun() -> if not element(1, ATuple) -> ok; true -> error end end, ok), + ?line check(fun() -> if not element(2, ATuple) -> ok; true -> error end end, error), + ?line check(fun() -> if not element(3, ATuple) -> ok; true -> error end end, error), + + ?line check(fun() -> if not glurf -> ok; true -> error end end, error), + ?line check(fun() -> if not Glurf -> ok; true -> error end end, error), + + ok. + +complex_not(Config) when is_list(Config) -> + ATuple = id({false,true,gurka}), + ?line check(fun() -> if not(element(1, ATuple)) -> ok; true -> error end end, ok), + ?line check(fun() -> if not(element(2, ATuple)) -> ok; true -> error end end, error), + + ?line check(fun() -> if not(element(3, ATuple) == gurka) -> ok; + true -> error end end, error), + ?line check(fun() -> if not(element(3, ATuple) =/= gurka) -> ok; + true -> error end end, ok), + + ?line check(fun() -> if {a,not(element(2, ATuple))} == {a,false} -> ok; + true -> error end end, ok), + ?line check(fun() -> if {a,not(element(1, ATuple))} == {a,false} -> ok; + true -> error end end, error), + + ?line check(fun() -> if not(element(1, ATuple) or element(3, ATuple)) -> ok; + true -> error end end, error), + + %% orelse + ?line check(fun() -> if not(element(1, ATuple) orelse element(3, ATuple)) -> ok; + true -> error end end, error), + + ok. + +semicolon(Config) when is_list(Config) -> + + %% True/false combined using ';' (literal atoms). + + ?line check(fun() -> if true; false -> ok end end, ok), + ?line check(fun() -> if false; true -> ok end end, ok), + ?line check(fun() -> if true; true -> ok end end, ok), + ?line check(fun() -> if false; false -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if false; false -> ok end), + exit + end, exit), + + %% True/false combined used ';'. + + True = id(true), + False = id(false), + + ?line check(fun() -> if True; False -> ok end end, ok), + ?line check(fun() -> if False; True -> ok end end, ok), + ?line check(fun() -> if True; True -> ok end end, ok), + ?line check(fun() -> if False; False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if False; False -> ok end), + exit + end, exit), + + %% Combine true/false with a non-boolean value. + Glurf = id(glurf), + + + ?line check(fun() -> if True; Glurf -> ok end end, ok), + ?line check(fun() -> if Glurf; True -> ok end end, ok), + ?line check(fun() -> if Glurf; Glurf -> ok; true -> error end end, error), + ?line check(fun() -> if False; Glurf -> ok; true -> error end end, error), + ?line check(fun() -> if Glurf; False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if Glurf; Glurf -> ok end), + exit + end, exit), + + %% Combine true/false with errors. + + ATuple = id({false,true,gurka}), + + ?line check(fun() -> if True; element(42, ATuple) -> ok end end, ok), + ?line check(fun() -> if element(42, ATuple); True -> ok end end, ok), + ?line check(fun() -> if element(42, ATuple); element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> if False; element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> if element(42, ATuple); + False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if element(42, ATuple); + element(42, ATuple) -> ok end), + exit + end, exit), + + ok. + +complex_semicolon(Config) when is_list(Config) -> + ?line ok = csemi1(int, {blurf}), + ?line ok = csemi1(string, {blurf}), + ?line ok = csemi1(float, [a]), + ?line error = csemi1(35, 42), + + %% 2 + ?line ok = csemi2({}, {a,b,c}), + ?line ok = csemi2({1,3.5}, {a,b,c}), + ?line ok = csemi2(dum, {a,b,c}), + + ?line ok = csemi2({45,-19.3}, {}), + ?line ok = csemi2({45,-19.3}, {dum}), + ?line ok = csemi2({45,-19.3}, {dum,dum}), + + ?line error = csemi2({45}, {dum}), + ?line error = csemi2([], {dum}), + ?line error = csemi2({dum}, []), + ?line error = csemi2([], []), + + %% 3 + ?line csemi3(fun csemi3a/4), + ?line csemi3(fun csemi3b/4), + ?line csemi3(fun csemi3c/4), + + %% 4 + ?line csemi4(fun csemi4a/4), + ?line csemi4(fun csemi4b/4), + ?line csemi4(fun csemi4c/4), + ?line csemi4(fun csemi4d/4), + + %% 4, 'orelse' instead of 'or' + ?line csemi4_orelse(fun csemi4_orelse_a/4), + ?line csemi4_orelse(fun csemi4_orelse_b/4), + ?line csemi4_orelse(fun csemi4_orelse_c/4), + ?line csemi4_orelse(fun csemi4_orelse_d/4), + + ok. + +csemi1(Type, Val) when is_list(Val), Type == float; + Type == int; Type == string -> ok; +csemi1(_, _) -> error. + +csemi2(A, B) when size(A) > 1; size(B) > 2 -> ok; +csemi2(_, _) -> error. + +csemi3(Csemi3) -> + ok = Csemi3({}, {a,b,c}, [0], [0]), + ok = Csemi3({1,3.5}, {a,b,c}, -1, -1), + ok = Csemi3(dum, {a,b,c}, 0.0, 0.0), + ok = Csemi3(dum, {c}, b, a), + ok = Csemi3(dum, <<1,2,3>>, 0.0, 0.0), + ok = Csemi3(<<3.5/float>>, {a,b,c}, -1, -1), + + ok = Csemi3({45,-19.3}, {}, [], []), + ok = Csemi3({45,-19.3}, {dum}, 42, 42), + ok = Csemi3({45,-19.3}, {dum,dum}, 33, 33), + + ok = Csemi3({45}, {dum}, 1.0, 0), + ok = Csemi3([a], {dum}, 1.0, 0), + ok = Csemi3({dum}, [], 1.0, 0), + ok = Csemi3([], [], 1.0, 0), + ok = Csemi3(blurf, {dum}, 1.0, 0), + ok = Csemi3({a}, blurf, 1.0, 0), + ok = Csemi3([a], [dum], 1.0, 0), + ok = Csemi3({dum}, [], 1.0, 0), + ok = Csemi3([], [], 1.0, 0), + + error = Csemi3({45}, {dum}, 0, 0), + error = Csemi3([a], {dum}, 0, 0), + error = Csemi3({dum}, [], 0, 0), + error = Csemi3([], [], 0, 0), + ok. + +csemi3a(A, B, X, Y) when X > Y; size(A) > 1; size(B) > 2 -> ok; +csemi3a(_, _, _, _) -> error. + +csemi3b(A, B, X, Y) when size(A) > 1; X > Y; size(B) > 2 -> ok; +csemi3b(_, _, _, _) -> error. + +csemi3c(A, B, X, Y) when size(A) > 1; size(B) > 2; X > Y -> ok; +csemi3c(_, _, _, _) -> error. + + +csemi4(Test) -> + ok = Test({a,b}, 2, {c,d}, 2), + ok = Test({1,2,3}, 0, [], 0), + ok = Test({}, 2, blurf, 0), + ok = Test({}, 2, {1}, 2), + + error = Test([], 4, {}, 0), + error = Test({}, 0, [a,b], 4), + error = Test({}, 0, [a,b], 0), + error = Test([], 0, {}, 0), + error = Test({}, 0, {}, 0), + + ok. + +csemi4a(A, X, B, Y) when (size(A) > 1) or (X > 1); + (size(B) > 1) or (Y > 1) -> ok; +csemi4a(_, _, _, _) -> error. + +csemi4b(A, X, B, Y) when (X > 1) or (size(A) > 1); + (size(B) > 1) or (Y > 1) -> ok; +csemi4b(_, _, _, _) -> error. + +csemi4c(A, X, B, Y) when (size(A) > 1) or (X > 1); + (Y > 1) or (size(B) > 1) -> ok; +csemi4c(_, _, _, _) -> error. + +csemi4d(A, X, B, Y) when (X > 1) or (size(A) > 1); + (Y > 1) or (size(B) > 1) -> ok; +csemi4d(_, _, _, _) -> error. + + +csemi4_orelse(Test) -> + ok = Test({a,b}, 2, {c,d}, 2), + ok = Test({1,2,3}, 0, [], 0), + ok = Test({}, 2, blurf, 0), + ok = Test({}, 2, {1}, 2), + + ?line error = Test([], 1, {}, 0), + + ok. + +csemi4_orelse_a(A, X, B, Y) when (size(A) > 1) orelse (X > 1); + (size(B) > 1) orelse (Y > 1) -> ok; +csemi4_orelse_a(_, _, _, _) -> error. + +csemi4_orelse_b(A, X, B, Y) when (X > 1) orelse (size(A) > 1); + (size(B) > 1) orelse (Y > 1) -> ok; +csemi4_orelse_b(_, _, _, _) -> error. + +csemi4_orelse_c(A, X, B, Y) when (size(A) > 1) orelse (X > 1); + (Y > 1) orelse (size(B) > 1) -> ok; +csemi4_orelse_c(_, _, _, _) -> error. + +csemi4_orelse_d(A, X, B, Y) when (X > 1) or (size(A) > 1); + (Y > 1) or (size(B) > 1) -> ok; +csemi4_orelse_d(_, _, _, _) -> error. + + +comma(Config) when is_list(Config) -> + + %% ',' combinations of literal true/false. + + ?line check(fun() -> if true, false -> ok; true -> error end end, error), + ?line check(fun() -> if false, true -> ok; true -> error end end, error), + ?line check(fun() -> if true, true -> ok end end, ok), + ?line check(fun() -> if false, false -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if true, false -> ok; + false, true -> ok; + false, false -> ok + end), + exit + end, exit), + + %% ',' combinations of true/false in variables. + + True = id(true), + False = id(false), + + ?line check(fun() -> if True, False -> ok; true -> error end end, error), + ?line check(fun() -> if False, True -> ok; true -> error end end, error), + ?line check(fun() -> if True, True -> ok end end, ok), + ?line check(fun() -> if False, False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True, False -> ok; + False, True -> ok; + False, False -> ok + end), + exit + end, exit), + + %% ',' combinations of true/false, and non-boolean in variables. + + Glurf = id(glurf), + + ?line check(fun() -> if True, Glurf -> ok; true -> error end end, error), + ?line check(fun() -> if Glurf, True -> ok; true -> error end end, error), + ?line check(fun() -> if True, True -> ok end end, ok), + ?line check(fun() -> if Glurf, Glurf -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True, Glurf -> ok; + Glurf, True -> ok; + Glurf, Glurf -> ok + end), + exit + end, exit), + + %% ',' combinations of true/false with errors. + ATuple = id({a,b,c}), + + ?line check(fun() -> if True, element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> if element(42, ATuple), True -> ok; + true -> error end end, error), + ?line check(fun() -> if True, True -> ok end end, ok), + ?line check(fun() -> if element(42, ATuple), element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True, element(42, ATuple) -> ok; + element(42, ATuple), True -> ok; + element(42, ATuple), element(42, ATuple) -> ok + end), + exit + end, exit), + + ok. + +or_guard(Config) when is_list(Config) -> + True = id(true), + False = id(false), + Glurf = id(glurf), + + %% 'or' combinations of literal true/false. + ?line check(fun() -> if true or false -> ok end end, ok), + ?line check(fun() -> if false or true -> ok end end, ok), + ?line check(fun() -> if true or true -> ok end end, ok), + ?line check(fun() -> if false or false -> ok; true -> error end end, error), + + ?line check(fun() -> if glurf or true -> ok; true -> error end end, error), + ?line check(fun() -> if true or glurf -> ok; true -> error end end, error), + ?line check(fun() -> if glurf or glurf -> ok; true -> error end end, error), + + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if false or false -> ok end), + exit + end, exit), + + + %% 'or' combinations using variables containing true/false. + ?line check(fun() -> if True or False -> ok end end, ok), + ?line check(fun() -> if False or True -> ok end end, ok), + ?line check(fun() -> if True or True -> ok end end, ok), + ?line check(fun() -> if False or False -> ok; true -> error end end, error), + + ?line check(fun() -> if True or Glurf -> ok; true -> error end end, error), + ?line check(fun() -> if Glurf or True -> ok; true -> error end end, error), + ?line check(fun() -> if Glurf or Glurf -> ok; true -> error end end, error), + + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if False or False -> ok end), + exit + end, exit), + + ok. + +more_or_guards(Config) when is_list(Config) -> + True = id(true), + False = id(false), + ATuple = id({false,true,gurka}), + + ?line check(fun() -> + if element(42, ATuple) or False -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if False or element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(18, ATuple) or element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if True or element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(42, ATuple) or True -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(1, ATuple) or element(42, ATuple) or True -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(1, ATuple) or True or element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if + (<> == <<0>>) or element(2, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if + element(2, ATuple) or (<> == <<1>>) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(2, ATuple) or element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if + element(1, ATuple) or + element(2, ATuple) or + element(19, ATuple) -> ok; + true -> error end + end, error), + ok. + +complex_or_guards(Config) when is_list(Config) -> + %% complex_or_1/2 + ?line ok = complex_or_1({a,b,c,d}, {1,2,3}), + ?line ok = complex_or_1({a,b,c,d}, {1}), + ?line ok = complex_or_1({a}, {1,2,3}), + ?line error = complex_or_1({a}, {1}), + + ?line error = complex_or_1(1, 2), + ?line error = complex_or_1([], {a,b,c,d}), + ?line error = complex_or_1({a,b,c,d}, []), + + + %% complex_or_2/1 + ?line ok = complex_or_2({true,{}}), + ?line ok = complex_or_2({false,{a}}), + ?line ok = complex_or_2({false,{a,b,c}}), + ?line ok = complex_or_2({true,{a,b,c,d}}), + + ?line error = complex_or_2({blurf,{a,b,c}}), + + ?line error = complex_or_2({true}), + ?line error = complex_or_2({true,no_tuple}), + ?line error = complex_or_2({true,[]}), + + %% complex_or_3/2 + ?line ok = complex_or_3({true}, {}), + ?line ok = complex_or_3({false}, {a}), + ?line ok = complex_or_3({false}, {a,b,c}), + ?line ok = complex_or_3({true}, {a,b,c,d}), + ?line ok = complex_or_3({false}, <<1,2,3>>), + ?line ok = complex_or_3({true}, <<1,2,3,4>>), + + ?line error = complex_or_3(blurf, {a,b,c}), + + ?line error = complex_or_3({false}, <<1,2,3,4>>), + ?line error = complex_or_3([], <<1,2>>), + ?line error = complex_or_3({true}, 45), + ?line error = complex_or_3(<<>>, <<>>), + + %% complex_or_4/2 + ?line ok = complex_or_4(<<1,2,3>>, {true}), + ?line ok = complex_or_4(<<1,2,3>>, {false}), + ?line ok = complex_or_4(<<1,2,3>>, {true}), + ?line ok = complex_or_4({1,2,3}, {true}), + ?line error = complex_or_4({1,2,3,4}, {false}), + + ?line error = complex_or_4(<<1,2,3,4>>, []), + ?line error = complex_or_4([], {true}), + + %% complex_or_5/2 + ?line ok = complex_or_5(<<1>>, {false}), + ?line ok = complex_or_5(<<1,2,3>>, {true}), + ?line ok = complex_or_5(<<1,2,3,4>>, {false}), + ?line ok = complex_or_5({1,2,3}, {false}), + ?line ok = complex_or_5({1,2,3,4}, {false}), + + ?line error = complex_or_5(blurf, {false}), + ?line error = complex_or_5(<<1>>, klarf), + ?line error = complex_or_5(blurf, klarf), + + %% complex_or_6/2 + ?line ok = complex_or_6({true,true}, {1,2,3,4}), + ?line ok = complex_or_6({true,true}, <<1,2,3,4>>), + ?line ok = complex_or_6({false,false}, <<1,2,3,4>>), + ?line ok = complex_or_6({false,true}, <<1>>), + ?line ok = complex_or_6({true,false}, {1}), + ?line ok = complex_or_6({true,true}, {1}), + + ?line error = complex_or_6({false,false}, {1}), + + ?line error = complex_or_6({true}, {1,2,3,4}), + ?line error = complex_or_6({}, {1,2,3,4}), + ?line error = complex_or_6([], {1,2,3,4}), + ?line error = complex_or_6([], {1,2,3,4}), + ?line error = complex_or_6({true,false}, klurf), + + ok. + +complex_or_1(A, B) -> + if + ((3 < size(A)) and (size(A) < 9)) or + ((2 < size(B)) and (size(B) < 7)) -> ok; + true -> error + end. + +complex_or_2(Tuple) -> + if + element(1, Tuple) or not (size(element(2, Tuple)) > 3) -> ok; + true -> error + end. + +complex_or_3(A, B) -> + if + not (size(B) > 3) or element(1, A) -> ok; + true -> error + end. + +complex_or_4(A, B) -> + if + not (is_tuple(A) and (size(A) > 3)) or element(1, B) -> ok; + true -> error + end. + +complex_or_5(A, B) -> + if + not (is_tuple(A) or (size(A) > 3)) or not element(1, B) -> ok; + true -> error + end. + +complex_or_6(A, B) -> + if + not (not element(1, A) and not element(2, A)) or + not (not (size(B) > 3)) -> ok; + true -> error + end. + +and_guard(Config) when is_list(Config) -> + + %% 'and' combinations of literal true/false. + + ?line check(fun() -> if true and false -> ok; true -> error end end, error), + ?line check(fun() -> if false and true -> ok; true -> error end end, error), + ?line check(fun() -> if true and true -> ok end end, ok), + ?line check(fun() -> if false and false -> ok; true -> error end end, error), + + ?line check(fun() -> if glurf and true -> ok; true -> error end end, error), + ?line check(fun() -> if true and glurf -> ok; true -> error end end, error), + ?line check(fun() -> if glurf and glurf -> ok; true -> error end end, error), + + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if true and false -> ok; + false and true -> ok; + false and false -> ok + end), + exit + end, exit), + + %% 'and' combinations of true/false in variables. + + True = id(true), + False = id(false), + + ?line check(fun() -> if True and False -> ok; true -> error end end, error), + ?line check(fun() -> if False and True -> ok; true -> error end end, error), + ?line check(fun() -> if True and True -> ok end end, ok), + ?line check(fun() -> if False and False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True and False -> ok; + False and True -> ok; + False and False -> ok + end), + exit + end, exit), + + %% 'and' combinations of true/false and a non-boolean in variables. + + Glurf = id(glurf), + + ?line check(fun() -> if True and Glurf -> ok; true -> error end end, error), + ?line check(fun() -> if Glurf and True -> ok; true -> error end end, error), + ?line check(fun() -> if True and True -> ok end end, ok), + ?line check(fun() -> if Glurf and Glurf -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True and Glurf -> ok; + Glurf and True -> ok; + Glurf and Glurf -> ok + end), + exit + end, exit), + + %% 'and' combinations of true/false with errors. + ATuple = id({a,b,c}), + + ?line check(fun() -> if True and element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> if element(42, ATuple) and True -> ok; + true -> error end end, error), + ?line check(fun() -> if True and True -> ok end end, ok), + ?line check(fun() -> if element(42, ATuple) and element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True and element(42, ATuple) -> ok; + element(42, ATuple) and True -> ok; + element(42, ATuple) and element(42, ATuple) -> ok + end), + exit + end, exit), + + ?line ok = relprod({'Set',a,b}, {'Set',a,b}), + + ok. + +relprod(R1, R2) when (erlang:size(R1) =:= 3) and (erlang:element(1,R1) =:= 'Set'), (erlang:size(R2) =:= 3) and (erlang:element(1,R2) =:= 'Set') -> + ok. + + +xor_guard(Config) when is_list(Config) -> + + %% 'xor' combinations of literal true/false. + ?line check(fun() -> if true xor false -> ok end end, ok), + ?line check(fun() -> if false xor true -> ok end end, ok), + ?line check(fun() -> if true xor true -> ok; true -> error end end, error), + ?line check(fun() -> if false xor false -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if false xor false -> ok end), + exit + end, exit), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if true xor true -> ok end), + exit + end, exit), + + + %% 'xor' combinations using variables containing true/false. + + True = id(true), + False = id(false), + + ?line check(fun() -> if True xor False -> ok end end, ok), + ?line check(fun() -> if False xor True -> ok end end, ok), + ?line check(fun() -> if True xor True -> ok; true -> error end end, error), + ?line check(fun() -> if False xor False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if False xor False -> ok end), + exit + end, exit), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if True xor True -> ok end), + exit + end, exit), + + ok. + +more_xor_guards(Config) when is_list(Config) -> + True = id(true), + False = id(false), + ATuple = id({false,true,gurka}), + + ?line check(fun() -> + if element(42, ATuple) xor False -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if False xor element(42, ATuple) xor False -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(18, ATuple) xor element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if True xor element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(42, ATuple) xor True -> ok; + true -> error end + end, error), + ok. + +build_in_guard(Config) when is_list(Config) -> + SubBin = <<5.0/float>>, + ?line B = <<1,SubBin/binary,3.5/float>>, + ?line if + B =:= <<1,SubBin/binary,3.5/float>> -> ok + end. + +old_guard_tests(Config) when list(Config) -> + %% Check that all the old guard tests are still recognized. + ?line list = og(Config), + ?line atom = og(an_atom), + ?line binary = og(<<1,2>>), + ?line float = og(3.14), + ?line integer = og(43), + ?line a_function = og(fun() -> ok end), + ?line pid = og(self()), + ?line reference = og(make_ref()), + ?line tuple = og({}), + + ?line number = on(45.333), + ?line number = on(-19), + ok. + +og(V) when atom(V) -> atom; +og(V) when binary(V) -> binary; +og(V) when float(V) -> float; +og(V) when integer(V) -> integer; +og(V) when function(V) -> a_function; +og(V) when list(V) -> list; +og(V) when pid(V) -> pid; +og(V) when port(V) -> port; +og(V) when reference(V) -> reference; +og(V) when tuple(V) -> tuple; +og(_) -> what. + +on(V) when number(V) -> number; +on(_) -> not_number. + +gbif(Config) when is_list(Config) -> + ?line error = gbif_1(1, {false,true}), + ?line ok = gbif_1(2, {false,true}), + ok. + +gbif_1(P, T) when element(P, T) -> ok; +gbif_1(_, _) -> error. + + +t_is_boolean(Config) when is_list(Config) -> + ?line true = is_boolean(true), + ?line true = is_boolean(false), + ?line true = is_boolean(id(true)), + ?line true = is_boolean(id(false)), + + ?line false = is_boolean(glurf), + ?line false = is_boolean(id(glurf)), + + ?line false = is_boolean([]), + ?line false = is_boolean(id([])), + ?line false = is_boolean(42), + ?line false = is_boolean(id(-42)), + + ?line false = is_boolean(math:pi()), + ?line false = is_boolean(384793478934378924978439789873478934897), + + ?line false = is_boolean(id(self())), + ?line false = is_boolean(id({x,y,z})), + ?line false = is_boolean(id([a,b,c])), + ?line false = is_boolean(id(make_ref())), + ?line false = is_boolean(id(<<1,2,3>>)), + + ?line ok = bool(true), + ?line ok = bool(false), + ?line ok = bool(id(true)), + ?line ok = bool(id(false)), + + ?line error = bool(glurf), + ?line error = bool(id(glurf)), + + ?line error = bool([]), + ?line error = bool(id([])), + ?line error = bool(42), + ?line error = bool(id(-42)), + + ?line error = bool(math:pi()), + ?line error = bool(384793478934378924978439789873478934897), + + ?line error = bool(id(self())), + ?line error = bool(id({x,y,z})), + ?line error = bool(id([a,b,c])), + ?line error = bool(id(make_ref())), + ?line error = bool(id(<<1,2,3>>)), + + ok. + +bool(X) when is_boolean(X) -> ok; +bool(_) -> error. + + +is_function_2(Config) when is_list(Config) -> + true = is_function(id(fun ?MODULE:all/1), 1), + true = is_function(id(fun() -> ok end), 0), + false = is_function(id(fun ?MODULE:all/1), 0), + false = is_function(id(fun() -> ok end), 1), + + F = fun(_) -> ok end, + if + is_function(F, 1) -> ok + end. + +tricky(Config) when is_list(Config) -> + ?line not_ok = tricky_1(1, 2), + ?line not_ok = tricky_1(1, blurf), + ?line not_ok = tricky_1(foo, 2), + ?line not_ok = tricky_1(a, b), + + ?line false = rb(100000, [1], 42), + ?line true = rb(100000, [], 42), + ?line true = rb(555, [a,b,c], 19), + ok. + +tricky_1(X, Y) when abs((X == 1) or (Y == 2)) -> ok; +tricky_1(_, _) -> not_ok. + +%% From dets_v9:read_buckets/11, simplified. + +rb(Size, ToRead, SoFar) when SoFar + Size < 81920; ToRead == [] -> true; +rb(_, _, _) -> false. + + +-define(T(Op,A,B), + ok = if A Op B -> ok; true -> error end, + ok = if not (A Op B) -> error; true -> ok end, + (fun(X, Y, True, False) -> + ok = if X Op Y -> ok; true -> error end, + ok = if False; X Op Y; False -> ok; true -> error end, + ok = if X Op Y, True -> ok; true -> error end, + ok = if not (X Op Y) -> error; true -> ok end, + ok = if False; not (X Op Y); False -> error; true -> ok end + end)(id(A), id(B), id(true), id(false))). + +-define(F(Op,A,B), + ok = if A Op B -> error; true -> ok end, + ok = if not (A Op B) -> ok; true -> error end, + (fun(X, Y, True, False) -> + ok = if X Op Y -> error; true -> ok end, + ok = if False; X Op Y; False -> error; true -> ok end, + ok = if not (X Op Y); False -> ok; true -> error end, + ok = if not (X Op Y), True -> ok; true -> error end + end)(id(A), id(B), id(true), id(false))). + + +rel_ops(Config) when is_list(Config) -> + ?line ?T(=/=, 1, 1.0), + ?line ?F(=/=, 2, 2), + ?line ?F(=/=, {a}, {a}), + + ?line ?F(/=, a, a), + ?line ?F(/=, 0, 0.0), + ?line ?T(/=, 0, 1), + ?line ?F(/=, {a}, {a}), + + ?line ?T(==, 1, 1.0), + ?line ?F(==, a, {}), + + ?line ?F(=:=, 1, 1.0), + ?line ?T(=:=, 42.0, 42.0), + + ?line ?F(>, a, b), + ?line ?T(>, 42, 1.0), + ?line ?F(>, 42, 42.0), + + ?line ?T(<, a, b), + ?line ?F(<, 42, 1.0), + ?line ?F(<, 42, 42.0), + + ?line ?T(=<, 1.5, 5), + ?line ?F(=<, -9, -100.344), + ?line ?T(=<, 42, 42.0), + + ?line ?T(>=, 42, 42.0), + ?line ?F(>=, a, b), + ?line ?T(>=, 1.0, 0), + + ok. + +-undef(TestOp). + +basic_andalso_orelse(Config) when is_list(Config) -> + ?line T = id({type,integers,23,42}), + ?line 65 = if + ((element(1, T) =:= type) andalso (size(T) =:= 4) andalso + element(2, T) == integers) -> + element(3, T) + element(4, T); + true -> error + end, + ?line 65 = case [] of + [] when ((element(1, T) =:= type) andalso (size(T) =:= 4) andalso + element(2, T) == integers) -> + element(3, T) + element(4, T) + end, + + ?line 42 = basic_rt({type,integers,40,2}), + ?line 5.0 = basic_rt({vector,{3.0,4.0}}), + ?line 20 = basic_rt(['+',3,7]), + ?line {'Set',a,b} = basic_rt({{'Set',a,b},{'Set',a,b}}), + ?line 12 = basic_rt({klurf,4}), + + ?line error = basic_rt({type,integers,40,2,3}), + ?line error = basic_rt({kalle,integers,40,2}), + ?line error = basic_rt({kalle,integers,40,2}), + ?line error = basic_rt({1,2}), + ?line error = basic_rt([]), + + RelProdBody = + fun(R1, R2) -> + if + (erlang:size(R1) =:= 3) andalso (erlang:element(1,R1) =:= 'Set'), + (erlang:size(R2) =:= 3) andalso (erlang:element(1,R2) =:= 'Set') -> + ok + end + end, + + ?line ok = RelProdBody({'Set',a,b}, {'Set',a,b}), + ok. + +basic_rt(T) when is_tuple(T) andalso size(T) =:= 4 andalso element(1, T) =:= type andalso + element(2, T) == integers -> + element(3, T) + element(4, T); +basic_rt(T) when is_tuple(T) andalso size(T) =:= 2 andalso element(1, T) =:= vector -> + {X,Y} = element(2, T), + if + is_float(X), is_float(Y) -> + math:sqrt(X*X+Y*Y) + end; +basic_rt(['+',A,B]) -> + 2*id(A+B); +basic_rt({R1,R2}) when erlang:size(R1) =:= 3 andalso erlang:element(1,R1) =:= 'Set', + erlang:size(R2) =:= 3 andalso erlang:element(1,R2) =:= 'Set' -> + R1 = id(R1), + R2 = id(R2), + R1; +basic_rt(T) when is_tuple(T) andalso size(T) =:= 2 andalso element(1, T) =:= klurf -> + 3*id(element(2, T)); +basic_rt(_) -> + error. + +traverse_dcd(Config) when is_list(Config) -> + L0 = [{log_header,dcd_log,"1.0",a,b,c},{log_header,dcd_log,"2.0",a,b,c}, + {log_header,dcd_log,"0.0",a,b,c},blurf], + {cont,[{log_header,dcd_log,"0.0",a,b,c},blurf],log,funny} = + traverse_dcd({cont,L0}, log, funny), + L1 = [{log_header,dcd_log,"1.0"}], + {cont,L1,log,funny} = traverse_dcd({cont,L1}, log, funny), + L2 = [{a,tuple}], + {cont,L2,log,funny} = traverse_dcd({cont,L2}, log, funny), + ok. + +%% The function starts out with 3 arguments in {x,0}, {x,1}, {x,2}. +%% The outer match of a two tuple will places the first element in {x,3} and +%% second in {x,4}. The guard for the first clause must make ensure that all of those +%% registers are restored befor entering the second clause. +%% +%% (From mnesia_checkpoint.erl, modified.) + +traverse_dcd({Cont,[LogH|Rest]},Log,Fun) + when is_tuple(LogH) andalso size(LogH) =:= 6 andalso element(1, LogH) =:= log_header +andalso erlang:element(2,LogH) == dcd_log, +is_tuple(LogH) andalso size(LogH) =:= 6 andalso element(1, LogH) =:= log_header +andalso erlang:element(3,LogH) >= "1.0" -> + traverse_dcd({Cont,Rest},Log,Fun); +traverse_dcd({Cont,Recs},Log,Fun) -> + {Cont,Recs,Log,Fun}. + + +check_qlc_hrl(Config) when is_list(Config) -> + St = {r1,false,dum}, + ?line foo = cqlc(qlc, q, [{lc,1,2,3}], St), + ?line foo = cqlc(qlc, q, [{lc,1,2,3},b], St), + ?line St = cqlc(qlc, q, [], St), + ?line St = cqlc(qlc, blurf, [{lc,1,2,3},b], St), + ?line St = cqlc(q, q, [{lc,1,2,3},b], St), + ?line St = cqlc(qlc, q, [{lc,1,2,3},b,c], St), + ?line St = cqlc(qlc, q, [a,b], St), + ?line {r1,true,kalle} = cqlc(qlc, q, [{lc,1,2,3},b], {r1,true,kalle}), + ok. + +%% From erl_lint.erl; original name was check_qlc_hrl/4. +cqlc(M, F, As, St) -> + Arity = length(As), + case As of + [{lc,_L,_E,_Qs}|_] when M =:= qlc, F =:= q, + Arity < 3, + not (((element(1, St) =:= r1) orelse fail) and (size(St) =:= 3) and element(2, St)) -> + foo; + _ -> + St + end. + + + +%% Call this function to turn off constant propagation. +id(I) -> I. + +check(F, Result) -> + case F() of + Result -> ok; + Other -> + io:format("Expected: ~p\n", [Result]), + io:format(" Got: ~p\n", [Other]), + test_server:fail() + end. -- cgit v1.2.3