%%% -*- erlang-indent-level: 2 -*- %%%------------------------------------------------------------------- %%% Author: Kostis Sagonas %%% %%% Contains tests for correct handling of guards and guard BIFs. %%%------------------------------------------------------------------- -module(basic_guards). -export([test/0]). %% Prevent the inlining of the following functions -export([bad_arith/0, bad_tuple/0, is_strange_guard/0]). test() -> ok = guard0(4.2), ok = guard1([foo]), ok = test_guard2(), ok = test_guard3(), ok = test_guard4(), ok = test_is_boolean(), ok = test_bad_guards(), ok. %%-------------------------------------------------------------------- guard0(X) when X /= 0, is_float(X) -> ok. guard1(X) when is_atom(X) orelse is_float(X) -> error1; guard1(X) when is_reference(hd(X)) -> error2; guard1(X) when is_integer(hd(X)) -> error3; guard1(X) when hd(X) == foo -> ok. %%-------------------------------------------------------------------- test_guard2() -> ok1 = guard2(true), not_boolean = guard2(42), ok2 = guard2(false), ok. guard2(X) when X -> % gets transformed to: is_boolean(X), X =:= true ok1; guard2(X) when X =:= false -> ok2; guard2(_) -> not_boolean. %%-------------------------------------------------------------------- -define(is_foo(X), (is_atom(X) or (is_tuple(X) and (element(1, X) =:= 'foo')))). test_guard3() -> no = f('foo'), yes = f({'foo', 42}), no = f(42), ok. f(X) when ?is_foo(X) -> yes; f(_) -> no. %%-------------------------------------------------------------------- -define(EXT_REF, <<131,114,0,3,100,0,19,114,101,102,95,116,101,115,116,95,98,117,103,64,103,111,114,98,97,103,2,0,0,0,125,0,0,0,0,0,0,0,0>>). test_guard4() -> yes = is_ref(make_ref()), no = is_ref(gazonk), yes = is_ref(an_external_ref(?EXT_REF)), ok. is_ref(Ref) when is_reference(Ref) -> yes; is_ref(_Ref) -> no. an_external_ref(Bin) -> binary_to_term(Bin). %%-------------------------------------------------------------------- test_is_boolean() -> ok = is_boolean_in_if(), ok = is_boolean_in_guard(). is_boolean_in_if() -> ok1 = tif(true), ok2 = tif(false), not_bool = tif(other), ok. is_boolean_in_guard() -> ok = tg(true), ok = tg(false), not_bool = tg(other), ok. tif(V) -> Yes = yes(), %% just to prevent the optimizer removing this if %% the following line generates an is_boolean instruction V, Yes == yes -> %% while the following one does not (?!) %% Yes == yes, V -> ok1; not(not(not(V))) -> ok2; V -> ok3; true -> not_bool end. tg(V) when is_boolean(V) -> ok; tg(_) -> not_bool. yes() -> yes. %%-------------------------------------------------------------------- %% original test by Bjorn G test_bad_guards() -> ok = bad_arith(), ok = bad_tuple(), ok = is_strange_guard(), ok. bad_arith() -> 13 = bad_arith1(1, 12), 42 = bad_arith1(1, infinity), 42 = bad_arith1(infinity, 1), 42 = bad_arith2(infinity, 1), 42 = bad_arith3(inf), 42 = bad_arith4(infinity, 1), ok. bad_arith1(T1, T2) when (T1 + T2) < 17 -> T1 + T2; bad_arith1(_, _) -> 42. bad_arith2(T1, T2) when (T1 * T2) < 17 -> T1 * T2; bad_arith2(_, _) -> 42. bad_arith3(T) when (bnot T) < 17 -> T; bad_arith3(_) -> 42. bad_arith4(T1, T2) when (T1 bsr T2) < 10 -> T1 bsr T2; bad_arith4(_, _) -> 42. bad_tuple() -> error = bad_tuple1(a), error = bad_tuple1({a, b}), x = bad_tuple1({x, b}), 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. is_strange_guard() when is_tuple({1, bar, length([1, 2, 3, 4]), self()}) -> ok; is_strange_guard() -> error.