%%% -*- erlang-indent-level: 2 -*- %%%------------------------------------------------------------------- %%% Author: Kostis Sagonas %%% %%% Contains tests that manipulate and pattern match against tuples. %%%------------------------------------------------------------------- -module(basic_tuples). -export([test/0]). test() -> Num = 4711, ok = test_match({}, {1}, {1,2}, {1,2,3}, {1,2,3,4}, {1,2,3,4,5}, {1,2,3,4,5,6}, {1,2,3,4,5,6,7}, {1,2,3,4,5,6,7,8}), ok = test_size({}, {a}, {{a},{b}}, {a,{b},c}), ok = test_element({}, {a}, {a,b}, Num), ok = test_setelement({}, {1}, {1,2}, 3, [1,2]), ok = test_tuple_to_list({}, {a}, {a,b}, {a,b,c}, {a,b,c,d}, Num), ok = test_list_to_tuple([], [a], [a,b], [a,b,c], [a,b,c,d], Num), ok = test_tuple_with_case(), ok = test_tuple_in_guard({a, b}, {a, b, c}), ok. %%-------------------------------------------------------------------- %% Tests matching of tuples test_match(T0, T1, T2, T3, T4, T5, T6, T7, T8) -> {} = T0, {1} = T1, {1, 2} = T2, {1, 2, 3} = T3, {1, 2, 3, 4} = T4, {1, 2, 3, 4, 5} = T5, {1, 2, 3, 4, 5, 6} = T6, T6 = {1, 2, 3, 4, 5, 6}, T7 = {1, 2, 3, 4, 5, 6, 7}, {1, 2, 3, 4, 5, 6, 7, 8} = T8, ok. %%-------------------------------------------------------------------- %% Tests the size/1 and tuple_size/1 BIFs. test_size(T0, T1, T2, T3) -> [0, 1, 2, 3] = [size(T) || T <- [T0, T1, T2, T3]], [0, 1, 2, 3] = [tuple_size(T) || T <- [T0, T1, T2, T3]], ok. %%-------------------------------------------------------------------- %% Tests element/2. test_element(T0, T1, T2, N) -> a = element(1, T1), a = element(1, T2), %% indirect calls to element/2 List = lists:seq(1, N), Tuple = list_to_tuple(List), ok = get_elements(List, Tuple, 1), %% some cases that throw exceptions {'EXIT', _} = (catch my_element(0, T2)), {'EXIT', _} = (catch my_element(3, T2)), {'EXIT', _} = (catch my_element(1, T0)), {'EXIT', _} = (catch my_element(1, List)), {'EXIT', _} = (catch my_element(1, N)), {'EXIT', _} = (catch my_element(1.5, T2)), ok. my_element(Pos, Term) -> element(Pos, Term). get_elements([Element|Rest], Tuple, Pos) -> Element = element(Pos, Tuple), get_elements(Rest, Tuple, Pos + 1); get_elements([], _Tuple, _Pos) -> ok. %%-------------------------------------------------------------------- %% Tests set_element/3. test_setelement(T0, T1, Pair, Three, L) -> {x} = setelement(1, T1, x), {x, 2} = setelement(1, Pair, x), {1, x} = setelement(2, Pair, x), %% indirect calls to setelement/3 Tuple = list_to_tuple(lists:duplicate(2048, x)), NewTuple = set_all_elements(Tuple, 1), NewTuple = list_to_tuple(lists:seq(1+7, 2048+7)), %% the following cases were rewritten to use the Three %% variable in this weird way so as to silence the compiler {'EXIT', _} = (catch setelement(Three - Three, Pair, x)), {'EXIT', _} = (catch setelement(Three, Pair, x)), {'EXIT', _} = (catch setelement(Three div Three, T0, x)), {'EXIT', _} = (catch setelement(Three div Three, L, x)), {'EXIT', _} = (catch setelement(Three / 2, Pair, x)), ok. set_all_elements(Tuple, Pos) when Pos =< tuple_size(Tuple) -> set_all_elements(setelement(Pos, Tuple, Pos+7), Pos+1); set_all_elements(Tuple, Pos) when Pos > tuple_size(Tuple) -> Tuple. %%-------------------------------------------------------------------- %% Tests tuple_to_list/1. test_tuple_to_list(T0, T1, T2, T3, T4, Size) -> [] = tuple_to_list(T0), [a] = tuple_to_list(T1), [a, b] = tuple_to_list(T2), [a, b, c] = tuple_to_list(T3), [a, b, c, d] = tuple_to_list(T4), [a, b, c, d] = tuple_to_list(T4), %% test a big tuple List = lists:seq(1, Size), Tuple = list_to_tuple(List), Size = tuple_size(Tuple), List = tuple_to_list(Tuple), %% some cases that should result in errors {'EXIT', _} = (catch my_tuple_to_list(element(2, T3))), {'EXIT', _} = (catch my_tuple_to_list(Size)), ok. my_tuple_to_list(X) -> tuple_to_list(X). %%-------------------------------------------------------------------- %% Tests list_to_tuple/1. test_list_to_tuple(L0, L1, L2, L3, L4, Size) -> {} = list_to_tuple(L0), {a} = list_to_tuple(L1), {a, b} = list_to_tuple(L2), {a, b, c} = list_to_tuple(L3), {a, b, c, d} = list_to_tuple(L4), {a, b, c, d, e} = list_to_tuple(L4++[e]), %% test list_to_tuple with a big list Tuple = list_to_tuple(lists:seq(1, Size)), Size = tuple_size(Tuple), %% some cases that should result in errors {'EXIT', _} = (catch my_list_to_tuple({a,b})), {'EXIT', _} = (catch my_list_to_tuple([hd(L1)|hd(L2)])), ok. my_list_to_tuple(X) -> list_to_tuple(X). %%-------------------------------------------------------------------- %% Tests that a case nested inside a tuple is ok. %% (This was known to crash earlier versions of BEAM.) test_tuple_with_case() -> {reply, true} = tuple_with_case(), ok. tuple_with_case() -> %% The following comments apply to the BEAM compiler. void(), % Reset var count. {reply, % Compiler will choose {x,1} for tuple. case void() of % Call will reset var count. {'EXIT', Reason} -> % Case will return in {x,1} (first free), {error, Reason}; % but the tuple will be build in {x,1}, _ -> % so case value is lost and a circular true % data element is built. end}. void() -> ok. %%-------------------------------------------------------------------- %% Test to build a tuple in a guard. test_tuple_in_guard(T2, T3) -> %% T2 = {a, b}; T3 = {a, b, c} ok = if T2 == {element(1, T3), element(2, T3)} -> ok; true -> other end, ok = if T3 == {element(1, T3), element(2, T3), element(3, T3)} -> ok; true -> other end, ok.