1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1997-2013. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: -module(tuple_SUITE). 20: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 21: init_per_group/2,end_per_group/2, 22: t_size/1, t_tuple_size/1, t_element/1, t_setelement/1, 23: t_insert_element/1, t_delete_element/1, 24: t_list_to_tuple/1, t_tuple_to_list/1, 25: t_make_tuple_2/1, t_make_tuple_3/1, t_append_element/1, 26: build_and_match/1, tuple_with_case/1, tuple_in_guard/1]). 27: -include_lib("test_server/include/test_server.hrl"). 28: 29: %% Tests tuples and the BIFs: 30: %% 31: %% size(Tuple) 32: %% element/2 33: %% setelement/3 34: %% tuple_to_list/1 35: %% list_to_tuple/1 36: %% make_tuple/2 37: %% 38: 39: suite() -> [{ct_hooks,[ts_install_cth]}]. 40: 41: all() -> 42: [build_and_match, t_size, t_tuple_size, t_list_to_tuple, 43: t_tuple_to_list, t_element, t_setelement, 44: t_make_tuple_2, t_make_tuple_3, t_append_element, 45: t_insert_element, t_delete_element, 46: tuple_with_case, tuple_in_guard]. 47: 48: groups() -> 49: []. 50: 51: init_per_suite(Config) -> 52: Config. 53: 54: end_per_suite(_Config) -> 55: ok. 56: 57: init_per_group(_GroupName, Config) -> 58: Config. 59: 60: end_per_group(_GroupName, Config) -> 61: Config. 62: 63: 64: build_and_match(Config) when is_list(Config) -> 65: {} = id({}), 66: {1} = id({1}), 67: {1, 2} = id({1, 2}), 68: {1, 2, 3} = id({1, 2, 3}), 69: {1, 2, 3, 4} = id({1, 2, 3, 4}), 70: {1, 2, 3, 4, 5} = id({1, 2, 3, 4, 5}), 71: {1, 2, 3, 4, 5, 6} = id({1, 2, 3, 4, 5, 6}), 72: {1, 2, 3, 4, 5, 6} = id({1, 2, 3, 4, 5, 6}), 73: {1, 2, 3, 4, 5, 6, 7} = id({1, 2, 3, 4, 5, 6, 7}), 74: {1, 2, 3, 4, 5, 6, 7, 8} = id({1, 2, 3, 4, 5, 6, 7, 8}), 75: ok. 76: 77: %% Tests size(Tuple). 78: 79: t_size(Config) when is_list(Config) -> 80: 0 = size({}), 81: 1 = size({a}), 82: 1 = size({{a}}), 83: 2 = size({{a}, {b}}), 84: 3 = size({1, 2, 3}), 85: ok. 86: 87: t_tuple_size(Config) when is_list(Config) -> 88: 0 = tuple_size(id({})), 89: 1 = tuple_size(id({a})), 90: 1 = tuple_size(id({{a}})), 91: 2 = tuple_size(id({{a},{b}})), 92: 3 = tuple_size(id({1,2,3})), 93: 94: %% Error cases. 95: {'EXIT',{badarg,_}} = (catch tuple_size([])), 96: {'EXIT',{badarg,_}} = (catch tuple_size(<<1,2,3>>)), 97: error = ludicrous_tuple_size({a,b,c}), 98: error = ludicrous_tuple_size([a,b,c]), 99: ok. 100: 101: 102: ludicrous_tuple_size(T) 103: when tuple_size(T) =:= 16#7777777777777777777777777777777777 -> ok; 104: ludicrous_tuple_size(_) -> error. 105: 106: %% Tests element/2. 107: 108: t_element(Config) when is_list(Config) -> 109: a = element(1, {a}), 110: a = element(1, {a, b}), 111: 112: List = lists:seq(1, 4096), 113: Tuple = list_to_tuple(lists:seq(1, 4096)), 114: get_elements(List, Tuple, 1), 115: 116: {'EXIT', {badarg, _}} = (catch element(0, id({a,b}))), 117: {'EXIT', {badarg, _}} = (catch element(3, id({a,b}))), 118: {'EXIT', {badarg, _}} = (catch element(1, id({}))), 119: {'EXIT', {badarg, _}} = (catch element(1, id([a,b]))), 120: {'EXIT', {badarg, _}} = (catch element(1, id(42))), 121: {'EXIT', {badarg, _}} = (catch element(id(1.5), id({a,b}))), 122: 123: ok. 124: 125: get_elements([Element|Rest], Tuple, Pos) -> 126: Element = element(Pos, Tuple), 127: get_elements(Rest, Tuple, Pos+1); 128: get_elements([], _Tuple, _Pos) -> 129: ok. 130: 131: %% Tests set_element/3. 132: 133: t_setelement(Config) when is_list(Config) -> 134: {x} = setelement(1, id({1}), x), 135: {x,2} = setelement(1, id({1,2}), x), 136: {1,x} = setelement(2, id({1,2}), x), 137: 138: Tuple = list_to_tuple(lists:duplicate(2048, x)), 139: NewTuple = set_all_elements(Tuple, 1), 140: NewTuple = list_to_tuple(lists:seq(1+7, 2048+7)), 141: 142: {'EXIT', {badarg, _}} = (catch setelement(0, {a, b}, x)), 143: {'EXIT', {badarg, _}} = (catch setelement(3, {a, b}, x)), 144: {'EXIT', {badarg, _}} = (catch setelement(1, {}, x)), 145: {'EXIT', {badarg, _}} = (catch setelement(1, [a, b], x)), 146: {'EXIT', {badarg, _}} = (catch setelement(1.5, {a, b}, x)), 147: 148: %% Nested setelement with literals. 149: AnotherTuple = id({0,0,a,b,c}), 150: {93748793749387837476555412,3.0,gurka,b,c} = 151: setelement(1, setelement(2, setelement(3, AnotherTuple, gurka), 152: 3.0), 93748793749387837476555412), 153: 154: ok. 155: 156: set_all_elements(Tuple, Pos) when Pos =< size(Tuple) -> 157: set_all_elements(setelement(Pos, Tuple, Pos+7), Pos+1); 158: set_all_elements(Tuple, Pos) when Pos > size(Tuple) -> 159: Tuple. 160: 161: %% Tests list_to_tuple/1. 162: 163: t_list_to_tuple(Config) when is_list(Config) -> 164: {} = list_to_tuple([]), 165: {a} = list_to_tuple([a]), 166: {a, b} = list_to_tuple([a, b]), 167: {a, b, c} = list_to_tuple([a, b, c]), 168: {a, b, c, d} = list_to_tuple([a, b, c, d]), 169: {a, b, c, d, e} = list_to_tuple([a, b, c, d, e]), 170: 171: Size = 4096, 172: Tuple = list_to_tuple(lists:seq(1, Size)), 173: Size = size(Tuple), 174: 175: {'EXIT', {badarg, _}} = (catch list_to_tuple(id({a,b}))), 176: {'EXIT', {badarg, _}} = (catch list_to_tuple(id([a|b]))), 177: {'EXIT', {badarg, _}} = (catch list_to_tuple(id([a|b]))), 178: 179: % test upper boundry, 16777215 elements 180: MaxSize = 1 bsl 24 - 1, 181: MaxTuple = list_to_tuple(lists:seq(1, MaxSize)), 182: MaxSize = size(MaxTuple), 183: 184: {'EXIT', {badarg,_}} = (catch list_to_tuple(lists:seq(1, 1 bsl 24))), 185: ok. 186: 187: %% Tests tuple_to_list/1. 188: 189: t_tuple_to_list(Config) when is_list(Config) -> 190: [] = tuple_to_list({}), 191: [a] = tuple_to_list({a}), 192: [a, b] = tuple_to_list({a, b}), 193: [a, b, c] = tuple_to_list({a, b, c}), 194: [a, b, c, d] = tuple_to_list({a, b, c, d}), 195: [a, b, c, d] = tuple_to_list({a, b, c, d}), 196: 197: Size = 4096, 198: List = lists:seq(1, Size), 199: Tuple = list_to_tuple(List), 200: Size = size(Tuple), 201: List = tuple_to_list(Tuple), 202: 203: {'EXIT', {badarg,_}} = (catch tuple_to_list(id(a))), 204: {'EXIT', {badarg,_}} = (catch tuple_to_list(id(42))), 205: 206: ok. 207: 208: %% Tests the make_tuple/2 BIF. 209: t_make_tuple_2(Config) when is_list(Config) -> 210: t_make_tuple1([]), 211: t_make_tuple1(42), 212: t_make_tuple1(a), 213: t_make_tuple1({}), 214: t_make_tuple1({a}), 215: t_make_tuple1(erlang:make_tuple(400, [])), 216: 217: % test upper boundry, 16777215 elements 218: t_make_tuple(1 bsl 24 - 1, a), 219: {'EXIT', {badarg,_}} = (catch erlang:make_tuple(1 bsl 24, a)), 220: 221: {'EXIT', {badarg,_}} = (catch erlang:make_tuple(-1, a)), 222: % 26 bits is the total header arity room (for now) 223: {'EXIT', {badarg,_}} = (catch erlang:make_tuple(1 bsl 26 + 3, a)), 224: % bignum 225: {'EXIT', {badarg,_}} = (catch erlang:make_tuple(1 bsl 65 + 3, a)), 226: ok. 227: 228: t_make_tuple1(Element) -> 229: lists:foreach(fun(Size) -> t_make_tuple(Size, Element) end, 230: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 255, 256, 511, 512, 999, 231: 1000, 1023, 1024, 4095, 4096]). 232: 233: t_make_tuple(Size, Element) -> 234: Tuple = erlang:make_tuple(Size, Element), 235: lists:foreach(fun(El) when El =:= Element -> 236: ok; 237: (Other) -> 238: test_server:fail({got, Other, expected, Element}) 239: end, tuple_to_list(Tuple)). 240: 241: %% Tests the erlang:make_tuple/3 BIF. 242: t_make_tuple_3(Config) when is_list(Config) -> 243: {} = erlang:make_tuple(0, def, []), 244: {def} = erlang:make_tuple(1, def, []), 245: {a} = erlang:make_tuple(1, def, [{1,a}]), 246: 247: {a,def,c,def,e} = erlang:make_tuple(5, def, [{5,e},{1,a},{3,c}]), 248: {a,def,c,def,e} = erlang:make_tuple(5, def, [{1,blurf},{5,e},{3,blurf},{1,a},{3,c}]), 249: MaxSize = 1 bsl 16 - 1, 250: MaxTuple = erlang:make_tuple(MaxSize, def, [{1,blurf},{5,e},{3,blurf},{1,a},{3,c}]), 251: MaxSize = size(MaxTuple), 252: 253: %% Error cases. 254: {'EXIT',{badarg,_}} = (catch erlang:make_tuple(0, def, [{1,a}])), 255: {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{-1,a}])), 256: {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{0,a}])), 257: {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{6,z}])), 258: {'EXIT',{badarg,_}} = (catch erlang:make_tuple(a, def, [{6,z}])), 259: {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [{1,a}|b])), 260: {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [42])), 261: {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, [[a,b,c]])), 262: {'EXIT',{badarg,_}} = (catch erlang:make_tuple(5, def, non_list)), 263: {'EXIT',{badarg,_}} = (catch erlang:make_tuple(1 bsl 24, def, [{5,e},{1,a},{3,c}])), 264: 265: ok. 266: 267: %% Tests the erlang:insert_element/3 BIF. 268: t_insert_element(Config) when is_list(Config) -> 269: {a} = erlang:insert_element(1, {}, a), 270: {{b,b},a} = erlang:insert_element(1, {a}, {b,b}), 271: {a,b} = erlang:insert_element(2, {a}, b), 272: [b,def|_] = tuple_to_list(erlang:insert_element(1, erlang:make_tuple(1 bsl 20, def), b)), 273: [def,b|_] = tuple_to_list(erlang:insert_element(2, erlang:make_tuple(1 bsl 20, def), b)), 274: [def,b|_] = lists:reverse(tuple_to_list(erlang:insert_element(1 bsl 20, erlang:make_tuple(1 bsl 20, def), b))), 275: [b,def|_] = lists:reverse(tuple_to_list(erlang:insert_element((1 bsl 20) + 1, erlang:make_tuple(1 bsl 20, def), b))), 276: 277: %% Error cases. 278: {'EXIT',{badarg,_}} = (catch erlang:insert_element(1, [], a)), 279: {'EXIT',{badarg,_}} = (catch erlang:insert_element(1, a, a)), 280: {'EXIT',{badarg,_}} = (catch erlang:insert_element(0, {}, a)), 281: {'EXIT',{badarg,_}} = (catch erlang:insert_element(0, {b,b,b,b,b}, a)), 282: {'EXIT',{badarg,_}} = (catch erlang:insert_element(-1, {}, a)), 283: {'EXIT',{badarg,_}} = (catch erlang:insert_element(2, {}, a)), 284: {'EXIT',{badarg,_}} = (catch erlang:insert_element(6, {b,b,b,b}, a)), 285: {'EXIT',{badarg,_}} = (catch erlang:insert_element(1 bsl 20, {b,b,b,b}, a)), 286: ok. 287: 288: %% Tests the erlang:delete_element/3 BIF. 289: t_delete_element(Config) when is_list(Config) -> 290: {} = erlang:delete_element(1, {a}), 291: {{b,b},c} = erlang:delete_element(1, {a,{b,b},c}), 292: {a,b} = erlang:delete_element(2, {a,c,b}), 293: [2,3|_] = tuple_to_list(erlang:delete_element(1, list_to_tuple(lists:seq(1, 1 bsl 20)))), 294: [1,3|_] = tuple_to_list(erlang:delete_element(2, list_to_tuple(lists:seq(1, 1 bsl 20)))), 295: [(1 bsl 20) - 1, (1 bsl 20) - 2 |_] = lists:reverse(tuple_to_list(erlang:delete_element(1 bsl 20, list_to_tuple(lists:seq(1, 1 bsl 20))))), 296: [(1 bsl 20), (1 bsl 20) - 2 |_] = lists:reverse(tuple_to_list(erlang:delete_element((1 bsl 20) - 1, list_to_tuple(lists:seq(1, 1 bsl 20))))), 297: 298: %% Error cases. 299: {'EXIT',{badarg,_}} = (catch erlang:delete_element(1, [])), 300: {'EXIT',{badarg,_}} = (catch erlang:delete_element(1, a)), 301: {'EXIT',{badarg,_}} = (catch erlang:delete_element(0, {})), 302: {'EXIT',{badarg,_}} = (catch erlang:delete_element(-1, {})), 303: {'EXIT',{badarg,_}} = (catch erlang:delete_element(1, {})), 304: {'EXIT',{badarg,_}} = (catch erlang:delete_element(0, {b,b,b,b,b})), 305: {'EXIT',{badarg,_}} = (catch erlang:delete_element(5, {b,b,b,b})), 306: {'EXIT',{badarg,_}} = (catch erlang:delete_element(1 bsl 20, {b,c,b,b,b})), 307: ok. 308: 309: 310: %% Tests the append_element/2 BIF. 311: t_append_element(Config) when is_list(Config) -> 312: ok = t_append_element({}, 2048, 2048), 313: 314: % test upper boundry, 16777215 elements 315: MaxSize = 1 bsl 24 - 1, 316: MaxTuple = list_to_tuple(lists:seq(1, MaxSize)), 317: {'EXIT',{badarg,_}} = (catch erlang:append_element(MaxTuple, a)), 318: ok. 319: 320: t_append_element(_Tuple, 0, _High) -> ok; 321: t_append_element(Tuple, N, High) -> 322: NewTuple = erlang:append_element(Tuple, N), 323: verify_seq(tuple_to_list(Tuple), High, N), 324: t_append_element(NewTuple, N-1, High). 325: 326: verify_seq([], High, High) -> ok; 327: verify_seq([High], High, High) -> ok; 328: verify_seq([High|T], High, Lower) -> 329: verify_seq(T, High-1, Lower). 330: 331: %% Tests that a case nested inside a tuple is ok. 332: %% (This is known to crash earlier versions of BEAM.) 333: 334: tuple_with_case(Config) when is_list(Config) -> 335: {reply, true} = tuple_with_case(), 336: ok. 337: 338: tuple_with_case() -> 339: %% The following comments apply to the BEAM compiler. 340: foo(), % Reset var count. 341: {reply, % Compiler will choose {x,1} for tuple. 342: case foo() of % Call will reset var count. 343: {'EXIT', Reason} -> % Case will return in {x,1} (first free). 344: {error, Reason}; % but the tuple will be build in {x,1}, 345: _ -> % so case value is lost and a circular 346: true % data element is built. 347: end}. 348: 349: foo() -> ignored. 350: 351: %% Test to build a tuple in a guard. 352: 353: tuple_in_guard(Config) when is_list(Config) -> 354: Tuple1 = id({a,b}), 355: Tuple2 = id({a,b,c}), 356: if 357: Tuple1 == {element(1, Tuple2),element(2, Tuple2)} -> 358: ok; 359: true -> 360: test_server:fail() 361: end, 362: if 363: Tuple2 == {element(1, Tuple2),element(2, Tuple2), 364: element(3, Tuple2)} -> 365: ok; 366: true -> 367: test_server:fail() 368: end, 369: ok. 370: 371: %% Use this function to avoid compile-time evaluation of an expression. 372: id(I) -> I. 373: