1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2004-2011. 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: 20: %% 21: %%% Purpose : Test records. 22: 23: -module(record_SUITE). 24: 25: -include_lib("test_server/include/test_server.hrl"). 26: 27: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2, 28: init_per_testcase/2,end_per_testcase/2, 29: init_per_suite/1,end_per_suite/1, 30: errors/1,record_test/1,eval_once/1]). 31: 32: suite() -> [{ct_hooks,[ts_install_cth]}]. 33: 34: all() -> 35: cases(). 36: 37: groups() -> 38: []. 39: 40: init_per_group(_GroupName, Config) -> 41: Config. 42: 43: end_per_group(_GroupName, Config) -> 44: Config. 45: 46: 47: cases() -> 48: [errors, record_test, eval_once]. 49: 50: init_per_testcase(_Case, Config) -> 51: test_lib:interpret(?MODULE), 52: Dog = test_server:timetrap(?t:minutes(1)), 53: [{watchdog,Dog}|Config]. 54: 55: end_per_testcase(_Case, Config) -> 56: Dog = ?config(watchdog, Config), 57: ?t:timetrap_cancel(Dog), 58: ok. 59: 60: init_per_suite(Config) when is_list(Config) -> 61: ?line test_lib:interpret(?MODULE), 62: ?line true = lists:member(?MODULE, int:interpreted()), 63: Config. 64: 65: end_per_suite(Config) when is_list(Config) -> 66: ok. 67: 68: -record(foo, {a,b,c,d}). 69: -record(bar, {a,b,c,d}). 70: -record(barf, {a,b,c,d,e}). 71: 72: errors(Config) when is_list(Config) -> 73: Foo = #foo{a=1,b=2,c=3,d=4}, 74: ?line #foo{a=19,b=42,c=3,d=4} = update_foo(Foo, 19, 42), 75: 76: ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19)), 77: ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35)), 78: ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35, 17)), 79: ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35, 17, 42)), 80: 81: ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19)), 82: ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35)), 83: ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35, 17)), 84: ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35, 17, 42)), 85: ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 86: 35, 17, 42, -2)), 87: 88: ok. 89: 90: update_foo(#foo{}=R, A, B) -> 91: R#foo{a=A,b=B}. 92: 93: update_foo_bar(#foo{}=R, A) -> 94: R#bar{a=A}. 95: 96: update_foo_bar(#foo{}=R, A, _B) -> 97: R#bar{a=A,b=A}. 98: 99: update_foo_bar(#foo{}=R, A, _B, C) -> 100: R#bar{a=A,b=A,c=C}. 101: 102: update_foo_bar(#foo{}=R, A, _B, C, D) -> 103: R#bar{a=A,b=A,c=C,d=D}. 104: 105: update_foo_barf(#foo{}=R, A) -> 106: R#barf{a=A}. 107: 108: update_foo_barf(#foo{}=R, A, _B) -> 109: R#barf{a=A,b=A}. 110: 111: update_foo_barf(#foo{}=R, A, _B, C) -> 112: R#barf{a=A,b=A,c=C}. 113: 114: update_foo_barf(#foo{}=R, A, _B, C, D) -> 115: R#barf{a=A,b=A,c=C,d=D}. 116: 117: update_foo_barf(#foo{}=R, A, _B, C, D, E) -> 118: R#barf{a=A,b=A,c=C,d=D,e=E}. 119: 120: 121: -define(TrueGuard(Expr), if Expr -> ok; true -> ?t:fail() end). 122: -define(FalseGuard(Expr), if Expr -> ?t:fail(); true -> ok end). 123: 124: record_test(Config) when is_list(Config) -> 125: ?line true = is_record(#foo{}, foo), 126: ?line false = is_record(#foo{}, barf), 127: ?line false = is_record({foo}, foo), 128: 129: ?line true = erlang:is_record(#foo{}, foo), 130: ?line false = erlang:is_record(#foo{}, barf), 131: ?line false = erlang:is_record({foo}, foo), 132: 133: ?line false = is_record([], foo), 134: ?line false = is_record(Config, foo), 135: 136: ?line ?TrueGuard(is_record(#foo{}, foo)), 137: ?line ?FalseGuard(is_record(#foo{}, barf)), 138: ?line ?FalseGuard(is_record({foo}, foo)), 139: 140: ?line ?TrueGuard(erlang:is_record(#foo{}, foo)), 141: ?line ?FalseGuard(erlang:is_record(#foo{}, barf)), 142: ?line ?FalseGuard(erlang:is_record({foo}, foo)), 143: 144: ?line ?FalseGuard(is_record([], foo)), 145: ?line ?FalseGuard(is_record(Config, foo)), 146: 147: %% 'not is_record/2' to test guard optimization. 148: 149: ?line ?FalseGuard(not is_record(#foo{}, foo)), 150: ?line ?TrueGuard(not is_record(#foo{}, barf)), 151: ?line ?TrueGuard(not is_record({foo}, foo)), 152: 153: ?line ?FalseGuard(not erlang:is_record(#foo{}, foo)), 154: ?line ?TrueGuard(not erlang:is_record(#foo{}, barf)), 155: ?line ?TrueGuard(not erlang:is_record({foo}, foo)), 156: 157: Foo = id(#foo{}), 158: ?line ?FalseGuard(not erlang:is_record(Foo, foo)), 159: ?line ?TrueGuard(not erlang:is_record(Foo, barf)), 160: 161: ?line ?TrueGuard(not is_record(Config, foo)), 162: 163: ?line ?TrueGuard(not is_record(a, foo)), 164: ?line ?TrueGuard(not is_record([], foo)), 165: 166: %% Pass non-literal first argument. 167: 168: ?line true = is_record(id(#foo{}), foo), 169: ?line false = is_record(id(#foo{}), barf), 170: ?line false = is_record(id({foo}), foo), 171: 172: ?line true = erlang:is_record(id(#foo{}), foo), 173: ?line false = erlang:is_record(id(#foo{}), barf), 174: ?line false = erlang:is_record(id({foo}), foo), 175: 176: NoRec1 = id(blurf), 177: NoRec2 = id([]), 178: 179: ?line ?TrueGuard(not is_record(NoRec1, foo)), 180: ?line ?TrueGuard(not is_record(NoRec2, foo)), 181: 182: %% Force the use of guard bifs by using the 'xor' operation. 183: 184: False = id(false), 185: ?line ?TrueGuard(is_record(#foo{}, foo) xor False), 186: ?line ?FalseGuard(is_record(#foo{}, barf) xor False), 187: ?line ?FalseGuard(is_record({foo}, foo) xor False ), 188: 189: ?line ?TrueGuard(is_record(Foo, foo) xor False), 190: ?line ?FalseGuard(is_record(Foo, barf) xor False), 191: 192: 193: %% Implicit guards by using a list comprehension. 194: 195: List = id([1,#foo{a=2},3,#bar{d=4},5,#foo{a=6},7]), 196: 197: ?line [#foo{a=2},#foo{a=6}] = [X || X <- List, is_record(X, foo)], 198: ?line [#bar{d=4}] = [X || X <- List, is_record(X, bar)], 199: ?line [1,#foo{a=2},3,5,#foo{a=6},7] = 200: [X || X <- List, not is_record(X, bar)], 201: ?line [1,3,5,7] = 202: [X || X <- List, ((not is_record(X, bar)) and (not is_record(X, foo)))], 203: ?line [#foo{a=2},#bar{d=4},#foo{a=6}] = 204: [X || X <- List, ((is_record(X, bar)) or (is_record(X, foo)))], 205: ?line [1,3,#bar{d=4}] = 206: [X || X <- List, ((is_record(X, bar)) or (X < 5))], 207: 208: ?line MyList = [#foo{a=3},x,[],{a,b}], 209: ?line [#foo{a=3}] = [X || X <- MyList, is_record(X, foo)], 210: ?line [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo)], 211: ?line [#foo{a=3}] = [X || X <- MyList, begin is_record(X, foo) end], 212: ?line [x,[],{a,b}] = [X || X <- MyList, begin not is_record(X, foo) end], 213: ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, is_record(X, foo) or 214: not is_binary(X)], 215: ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo) or 216: not is_binary(X)], 217: ?line [#foo{a=3}] = [X || X <- MyList, is_record(X, foo) or is_reference(X)], 218: ?line [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo) or 219: is_reference(X)], 220: ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, 221: begin is_record(X, foo) or 222: not is_binary(X) end], 223: ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, 224: begin not is_record(X, foo) or 225: not is_binary(X) end], 226: ?line [#foo{a=3}] = [X || X <- MyList, 227: begin is_record(X, foo) or is_reference(X) end], 228: ?line [x,[],{a,b}] = [X || X <- MyList, 229: begin not is_record(X, foo) or 230: is_reference(X) end], 231: ok. 232: 233: eval_once(Config) when is_list(Config) -> 234: ?line once(fun(GetRec) -> 235: true = erlang:is_record(GetRec(), foo) 236: end, #foo{}), 237: ?line once(fun(GetRec) -> 238: (GetRec())#foo{a=1} 239: end, #foo{}), 240: ?line once(fun(GetRec) -> 241: (GetRec())#foo{a=1,b=2} 242: end, #foo{}), 243: ?line once(fun(GetRec) -> 244: (GetRec())#foo{a=1,b=2,c=3} 245: end, #foo{}), 246: ?line once(fun(GetRec) -> 247: (GetRec())#foo{a=1,b=2,c=3,d=4} 248: end, #foo{}), 249: ok. 250: 251: once(Test, Record) -> 252: put(?MODULE, 0), 253: GetRec = fun() -> 254: put(?MODULE, 1+get(?MODULE)), 255: Record 256: end, 257: Result = Test(GetRec), 258: case get(?MODULE) of 259: 1 -> ok; 260: N -> 261: io:format("Evaluated ~w times\n", [N]), 262: ?t:fail() 263: end, 264: Result. 265: 266: id(I) -> I.