1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 2005-2012. 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: -module(erl_expand_records_SUITE).
   21: 
   22: %-define(debug, true).
   23: 
   24: -ifdef(debug).
   25: -define(line, put(line, ?LINE), ).
   26: -define(config(X,Y), foo).
   27: -define(privdir, "erl_expand_records_SUITE_priv").
   28: -define(t, test_server).
   29: -else.
   30: -include_lib("test_server/include/test_server.hrl").
   31: -define(privdir, ?config(priv_dir, Config)).
   32: -endif.
   33: 
   34: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   35: 	 init_per_group/2,end_per_group/2, 
   36: 	 init_per_testcase/2, end_per_testcase/2]).
   37: 
   38: -export([attributes/1, expr/1, guard/1,
   39:          init/1, pattern/1, strict/1, update/1,
   40: 	 otp_5915/1, otp_7931/1, otp_5990/1,
   41: 	 otp_7078/1, otp_7101/1]).
   42: 
   43: % Default timetrap timeout (set in init_per_testcase).
   44: -define(default_timeout, ?t:minutes(1)).
   45: 
   46: init_per_testcase(_Case, Config) ->
   47:     ?line Dog = ?t:timetrap(?default_timeout),
   48:     [{watchdog, Dog} | Config].
   49: 
   50: end_per_testcase(_Case, _Config) ->
   51:     Dog = ?config(watchdog, _Config),
   52:     test_server:timetrap_cancel(Dog),
   53:     ok.
   54: 
   55: suite() -> [{ct_hooks,[ts_install_cth]}].
   56: 
   57: all() -> 
   58:     [attributes, expr, guard, init,
   59:      pattern, strict, update, {group, tickets}].
   60: 
   61: groups() -> 
   62:     [{tickets, [],
   63:       [otp_5915, otp_7931, otp_5990, otp_7078, otp_7101]}].
   64: 
   65: init_per_suite(Config) ->
   66:     Config.
   67: 
   68: end_per_suite(_Config) ->
   69:     ok.
   70: 
   71: init_per_group(_GroupName, Config) ->
   72:     Config.
   73: 
   74: end_per_group(_GroupName, Config) ->
   75:     Config.
   76: 
   77: 
   78: attributes(doc) ->
   79:     "Import module and functions.";
   80: attributes(suite) -> [];
   81: attributes(Config) when is_list(Config) ->
   82:     Ts = [
   83:       <<"-import(lists, [append/2, reverse/1]).
   84: 
   85:          -record(r, {a,b}).
   86: 
   87:          t() ->
   88:              [2,1] = reverse(append([1],[2])),
   89:              3 = length([1,2,3]),
   90:              3 = record_info(size, r),
   91:              [a, b] = record_info(fields, r),
   92:              [] = erl_expand_records_SUITE:attributes(suite),
   93:              ok.
   94:       ">>
   95:       ],
   96:     ?line run(Config, Ts),
   97:     ok.
   98:     
   99: expr(doc) ->
  100:     "Some expressions.";
  101: expr(suite) -> [];
  102: expr(Config) when is_list(Config) ->
  103:     Ts = [
  104:       <<"
  105:          -record(r, {a,b,c}).
  106: 
  107:          t() ->
  108:              [1,2] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
  109:                                R#r.a < 3],
  110:              [1,2] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
  111:                                begin R#r.a < 3 end],
  112:              [1,2,3] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
  113:                                  begin is_record(R, r) end],
  114:              [1,2,3] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
  115:                                  begin erlang:is_record(R, r) end],
  116:              ok.
  117:       ">>,
  118:       <<"
  119:          -record(r, {a,b,c}).
  120: 
  121:          f(X) -> X.
  122: 
  123:          t() ->
  124:              A = {$c, 1, 3.14, a, \"hi\", [], [a,b]},
  125:              R = #r{a = element(6, A), b = #r.b},
  126:              3 = R#r.b,
  127:              <<1:8>> = <<(begin erlang:element(2, A) end):8>>,
  128:              self() ! {a, message, []},
  129:              One = 1 = fun f/1(1),
  130:              2 = fun(X) -> X end(One + One),
  131:              3 = fun exprec_test:f/1(3),
  132:              4 = exprec_test:f(4),
  133:              5 = f(5),
  134:              L = receive 
  135:                      {a,message,L0} ->
  136:                          L0
  137:                  end,
  138:              case catch a:foo(bar) of
  139:                  {'EXIT', _} -> ok
  140:              end,
  141:              _ = receive 			%Suppress warning.
  142:                     noop ->
  143:                        1/(length(L) - 0)
  144:                  after 0 ->
  145:                     ok
  146:                  end,
  147:              if 
  148:                  R#r.c =:= undefined ->
  149:                      ok;
  150:                  true ->
  151:                      not_ok
  152:              end.
  153: 
  154:          is_record(_, _, _) ->
  155:              error(wrong_is_record).
  156:       ">>
  157:       ],
  158: 
  159:     %% The code above should run equally well with and without
  160:     %% strict record tests.
  161:     ?line run(Config, Ts, [no_strict_record_tests]),
  162:     ?line run(Config, Ts, [strict_record_tests]),
  163:     
  164:     ok.
  165:     
  166: guard(doc) ->
  167:     "is_record in guards.";
  168: guard(suite) -> [];
  169: guard(Config) when is_list(Config) ->
  170:     File = filename("guard.erl", Config),
  171:     Beam = filename("guard.beam", Config),
  172:     Test = <<"-module(guard).
  173: 
  174:               -export([t/1]).
  175: 
  176:               -record(r, {a,b}).
  177: 
  178:               t(_) when is_record(3, r) ->
  179:                   1;
  180:               t(_) when is_record(a, r) ->
  181:                   2;
  182:               t(_) when is_record(3.14, r) ->
  183:                   3;
  184:               t(_) when is_record([], r) ->
  185:                   4;
  186:               t(_) when is_record([a], r) ->
  187:                   5;
  188:               t(_) when is_record($a, r) ->
  189:                   6;
  190:               t(_) when is_record(\"foo\", r) ->
  191:                   7;
  192:               t(_) when is_record(#r.a, r) ->
  193:                   8;
  194:               t(_) when is_record(<<\"foo\">>, r) -> % line 23
  195:                   9;
  196:               t(_) when is_record(1 + 2, r) ->
  197:                   10;
  198:               t(_) when is_record(+ 3, r) ->
  199:                   11;
  200:               t(_) ->
  201:                   12.
  202:              ">>,
  203: 
  204:     ?line ok = file:write_file(File, Test),
  205:     ?line {ok, guard, Ws} = compile:file(File, [return,{outdir,?privdir}]),
  206:     ?line Warnings = [L || {_File,WL} <- Ws, {L,_M,nomatch_guard} <- WL],
  207:     ?line [7,9,11,13,15,17,19,21,23,25,27] = Warnings,
  208: 
  209:     ?line ok = file:delete(File),
  210:     ?line ok = file:delete(Beam),
  211:     ok.
  212: 
  213: init(doc) ->
  214:     "Wildcard initialisation.";
  215: init(suite) -> [];
  216: init(Config) when is_list(Config) ->
  217:     Ts = [
  218:       <<"
  219:          -record(r, {a,b,c,d = foo}).
  220: 
  221:          t() ->
  222:              R = #r{_ = init, b = b},
  223:              #r{c = init, b = b, a = init} = R,
  224:              case R of
  225:                  #r{b = b, _ = init} -> ok;
  226:                  _ -> not_ok
  227:              end.
  228:       ">>
  229:       ],
  230:     ?line run(Config, Ts),
  231:     ok.
  232:     
  233: pattern(doc) ->
  234:     "Some patterns.";
  235: pattern(suite) -> [];
  236: pattern(Config) when is_list(Config) ->
  237:     Ts = [
  238:       <<"-import(lists, [append/2, reverse/1]).
  239: 
  240:          -record(r, {a,b}).
  241: 
  242:          t() ->
  243:              1 = t(#r{}),
  244:              2 = t($a),
  245:              3 = t(1000),
  246:              4 = t({1000}),
  247:              5 = t(3),
  248:              6 = t(-3.14),
  249:              7 = t({4.0}),
  250:              8 = t(3.14),
  251:              9 = t(\"str\"),
  252:              10 = t([]),
  253:              11 = t([a|b]),
  254:              12 = t(\"string\"),
  255:              13 = t({[]}),
  256:              14 = t({a,b}),
  257:              15 = t({{}}),
  258:              16 = t({tuple,tupel}),
  259:              17 = t(4),
  260:              18 = t(10),
  261:              19 = t({a}),
  262:              20 = t(<<100:8,220:8>>),
  263:              21 = t(#r{a = #r{}}),
  264:              22 = t(2),
  265:              23 = t(#r{a = #r{}, b = b}),
  266:              24 = t(abc),
  267:              ok.
  268: 
  269:          t(abc) ->
  270:              24;
  271:          t($a) ->
  272:              2;
  273:          t(3) ->
  274:              5;
  275:          t(3.14) ->
  276:              8;
  277:          t(\"str\") ->
  278:              9;
  279:          t([]) ->
  280:              10;
  281:          t([a|b]) ->
  282:              11;
  283:          t(L) when is_list(L) ->
  284:              12;
  285:          t({L}) when list(L) ->
  286:              13;
  287:          t({a,b}) ->
  288:              14;
  289:          t({T}) when is_tuple(T) ->
  290:              15;
  291:          t(+ 4) ->
  292:              17;
  293:          t(3+7) ->
  294:              18;
  295:          t(<<A:8, (100+120):8>>) when A =:= 100 ->
  296:              20;
  297:          t(#r{a = #r{}, b = undefined}) ->
  298:              21;
  299:          t(#r.a) ->
  300:              22;
  301:          t(A) when is_record(A, r), record(element(2, A), r) ->
  302:              23;
  303:          t(A) when is_record(A, r) ->
  304:              1;
  305:          t(I) when is_integer(I) ->
  306:              3;
  307:          t({I}) when integer(I) ->
  308:              4;
  309:          t({F}) when float(F) ->
  310:              7;
  311:          t({A} = B) when A < B ->
  312:              19;
  313:          t(F) when is_float(F) ->
  314:              6;
  315:          t(T) when tuple(T) ->
  316:              16.
  317:       ">>
  318:       ],
  319:     ?line run(Config, Ts),
  320:     ok.
  321:     
  322: strict(doc) ->
  323:     "";
  324: strict(suite) -> [];
  325: strict(Config) when is_list(Config) ->
  326:     Ts1 = [
  327:       <<"-record(r1, {a,b}).
  328:          -record(r2, {a,b}).
  329: 
  330:          t() ->
  331:              A = #r1{a = 1, b = 2},
  332:              ok = try 
  333:                       {1, 2} = {A#r2.a, A#r2.b},
  334:                       not_ok
  335:                   catch error:{badrecord,r2} -> ok
  336:                   end,
  337:              try
  338:                  case foo of
  339:                      _ when A#r2.a =:= 1 -> not_ok
  340:                  end
  341:              catch error:_ -> ok
  342:              end.
  343:          element(_, _) ->
  344:              error(wrong_element).
  345:       ">>
  346:       ],
  347:     ?line run(Config, Ts1, [strict_record_tests]),
  348: 
  349:     Ts2 = [
  350:       <<"-record(r1, {a,b}).
  351:          -record(r2, {a,b}).
  352: 
  353:          t() ->
  354:              A = #r1{a = 1, b = 2},
  355:              {1, 2} = {A#r2.a, A#r2.b},
  356:              case foo of
  357:                  _ when A#r2.a =:= 1 -> ok
  358:              end.
  359:          element(_, _) ->
  360:              error(wrong_element).
  361:       ">>
  362:       ],
  363:     ?line run(Config, Ts2, [no_strict_record_tests]),
  364:     ok.
  365:     
  366: update(doc) ->
  367:     "Record updates.";
  368: update(suite) -> [];
  369: update(Config) when is_list(Config) ->
  370:     Ts = [
  371:       <<"-record(r, {a,b,c,d,e,f}).
  372: 
  373:          t() ->
  374:              R0 = #r{},
  375:              R1 = R0#r{a = #r.a, e = {x,y}},
  376:              2 = R1#r.a,
  377:              R2 = R1#r{},
  378:              true = R1 =:= R2,
  379:              R3 = R2#r{c = fun(X) -> X end, 
  380:                        d = <<\"foo\">>, 
  381:                        e = [x,y,z], 
  382:                        f = {R0,R1}},
  383:              R4 = R3#r{a = R3#r{b = #r{}}},
  384:              true = erlang:is_record((R4#r.a)#r.b, r),
  385:              #r{a = R0, b = 3, c = 3.14, d = [], e = [[]], f = [{}]} = 
  386:                  R4#r{a = R0, b = 3, c = 3.14, d = [], e = [[]], f = [{}]},
  387:              ok.
  388: 
  389:          %% Just playing around a bit...
  390:          t1() ->
  391:              ((#r{a = (#r{b = #r{}})#r{a = #r{}}})#r{b = #r{}})#r{c = #r{}}.
  392: 
  393:          t2() ->
  394:              R0 = #r{},
  395:              #r{_ = R0#r{a = ok}}.
  396: 
  397:          %% Implicit calls to setelement/3 must go to the BIF,
  398:          %% not to this function.
  399:          setelement(_, _, _) ->
  400:              erlang:error(wrong_setelement_called).
  401:       ">>
  402:       ],
  403:     ?line run(Config, Ts),
  404:     ok.
  405:     
  406: 
  407: otp_5915(doc) ->
  408:     "Strict record tests in guards.";
  409: otp_5915(suite) -> [];
  410: otp_5915(Config) when is_list(Config) ->
  411:     %% These tests are also run by the compiler's record_SUITE.
  412:     Ts = [
  413:       <<"-record(r, {a = 4,b}).
  414:          -record(r1, {a,b}).
  415:          -record(r2, {a = #r1{},b,c=length([1,2,3])}).
  416:          -record(r3, {a = fun(_) -> #r1{} end(1), b}).
  417: 
  418:          t() ->
  419:              foo = fun(A) when A#r1.a > A#r1.b -> foo end(#r1{b = 2}),
  420:              0 = fun(A) when A#r2.a -> 0 end(#r2{a = true}),
  421:              1 = fun(A) when (#r1{a = A})#r1.a > 2 -> 1 end(3),
  422:              2 = fun(N) when ((#r2{a = #r{a = 4}, b = length([a,b,c])})#r2.a)#r.a > N ->
  423:                          2 end(2),
  424:              3 = fun(A) when (A#r2.a)#r1.a =:= 3 -> 3 end(#r2{a = #r1{a = 3}}),
  425:              ok = fun() ->
  426:                           F = fun(A) when record(A#r.a, r1) -> 4;
  427:                                  (A) when record(A#r1.a, r1) -> 5
  428:                               end,
  429:                           5 = F(#r1{a = #r1{}}),
  430:                           4 = F(#r{a = #r1{}}),
  431:                           ok
  432:                   end(),
  433:              3 = fun(A) when record(A#r1.a, r),
  434:                                    (A#r1.a)#r.a > 3 -> 3
  435:                  end(#r1{a = #r{a = 4}}),
  436:              7 = fun(A) when record(A#r3.a, r1) -> 7 end(#r3{}),
  437:              [#r1{a = 2,b = 1}] = 
  438:                  fun() ->
  439:                          [A || A <- [#r1{a = 1, b = 3}, 
  440:                                      #r2{a = 2,b = 1}, 
  441:                                      #r1{a = 2, b = 1}],
  442:                                A#r1.a > 
  443:                                    A#r1.b]
  444:                  end(),
  445:              {[_],b} = 
  446:                  fun(L) ->
  447:                          %% A is checked only once:
  448:                          R1 = [{A,B} || A <- L, A#r1.a, B <- L, A#r1.b],
  449:                          A = #r2{a = true},
  450:                          %% A is checked again:
  451:                          B = if A#r1.a -> a; true -> b end,
  452:                          {R1,B}
  453:                  end([#r1{a = true, b = true}]),
  454: 
  455:              p = fun(A) when (A#r1.a =:= 2) or (A#r2.a =:= 1) -> o;
  456:                     (_) -> p
  457:                  end(#r1{a = 2}),
  458: 
  459:              o = fun(A) when (A#r1.a =:= 2) orelse (A#r2.a =:= 1) -> o;
  460:                     (_) -> p
  461:                  end(#r1{a = 2}),
  462: 
  463:              3 = fun(A) when A#r1.a > 3, 
  464:                              record(A, r1) -> 3
  465:                  end(#r1{a = 5}),
  466: 
  467:              ok = fun() ->
  468:                           F = fun(A) when (A#r2.a =:= 1) orelse (A#r2.a) -> 2;
  469:                                  (A) when (A#r1.a =:= 1) orelse (A#r1.a) -> 1;
  470:                                  (A) when (A#r2.a =:= 2) andalso (A#r2.b) -> 3
  471:                               end,
  472:                           1 = F(#r1{a = 1}),
  473:                           2 = F(#r2{a = true}),
  474:                           3 = F(#r2{a = 2, b = true}),
  475:                           ok
  476:                   end(),
  477: 
  478:              b = fun(A) when false or not (A#r.a =:= 1) -> a;
  479:                     (_) -> b
  480:                  end(#r1{a = 1}),
  481:              b = fun(A) when not (A#r.a =:= 1) or false -> a;
  482:                     (_) -> b
  483:                  end(#r1{a = 1}),
  484: 
  485:              ok = fun() ->
  486:                           F = fun(A) when not (A#r.a =:= 1) -> yes;
  487:                                  (_) -> no
  488:                               end,
  489:                           no = F(#r1{a = 2}),
  490:                           yes = F(#r{a = 2}),
  491:                           no = F(#r{a = 1}),
  492:                           ok
  493:                   end(),
  494: 
  495:              a = fun(A) when record(A, r),
  496:                              A#r.a =:= 1,
  497:                              A#r.b =:= 2 ->a
  498:                  end(#r{a = 1, b = 2}),
  499:              a = fun(A) when erlang:is_record(A, r),
  500:                              A#r.a =:= 1,
  501:                              A#r.b =:= 2 -> a
  502:                  end(#r{a = 1, b = 2}),
  503:              a = fun(A) when is_record(A, r),
  504:                              A#r.a =:= 1,
  505:                              A#r.b =:= 2 -> a
  506:                  end(#r{a = 1, b = 2}),
  507: 
  508:              nop = fun(A) when (is_record(A, r1) and (A#r1.a > 3)) or (A#r2.a < 1) ->
  509:                            japp;
  510:                       (_) ->
  511:                            nop
  512:                    end(#r2{a = 0}),
  513:              nop = fun(A) when (A#r1.a > 3) or (A#r2.a < 1) -> japp;
  514:                       (_) ->
  515:                            nop
  516:                    end(#r2{a = 0}),
  517: 
  518:              ok = fun() ->
  519:                           F = fun(A) when (A#r1.a =:= 2) or (A#r2.a =:= 1) -> o;
  520:                                  (_) -> p
  521:                               end,
  522:                           p = F(#r2{a = 1}),
  523:                           p = F(#r1{a = 2}),
  524:                           ok
  525:                   end(),
  526: 
  527:              ok = fun() ->
  528:                           F = fun(A) when fail, A#r1.a; A#r1.a -> ab;
  529:                                  (_) -> bu
  530:                               end,
  531:                           ab = F(#r1{a = true}),
  532:                           bu = F(#r2{a = true}),
  533:                           ok
  534:                   end(),
  535: 
  536:              both = fun(A) when A#r.a, A#r.b -> both 
  537:                     end(#r{a = true, b = true}),
  538: 
  539:              ok = fun() ->
  540:                           F = fun(A, B) when ((A#r1.a) orelse (B#r2.a)) 
  541:                                              or (B#r2.b) or (A#r1.b) -> true;
  542:                                  (_, _) -> false
  543:                               end,
  544:                           true = F(#r1{a = false, b = false}, #r2{a = false, b = true}),
  545:                           false = F(#r1{a = true, b = true}, #r1{a = false, b = true}),
  546:                           ok
  547:                   end(),
  548: 
  549:              ok.
  550:       ">>
  551:       ],
  552:     ?line run(Config, Ts, [strict_record_tests]),
  553:     ok.
  554: 
  555: otp_7931(doc) ->
  556:     "Test optimization of record accesses and is_record/3 tests in guards";
  557: otp_7931(suite) -> [];
  558: otp_7931(Config) when is_list(Config) ->
  559:     Ts = [
  560:       <<"-record(r, {a = 4,b}).
  561:          -record(r1, {a,b}).
  562:          -record(r2, {a = #r1{},b,c=length([1,2,3])}).
  563:          -record(r3, {a = fun(_) -> #r1{} end(1), b}).
  564: 
  565:          t() ->
  566:              ok = fun() ->
  567:                     F = fun(F, [H,H|T]) when is_record(H, r) ->
  568:                                 [H|F(F, T)];
  569:                              (F, [H|T]) when is_record(H, r) ->
  570:                                 [H|F(F, T)];
  571:                              (_, []) -> []
  572:                           end,
  573:                     [#r{a=4,b=7},#r{a=1,b=42}] =
  574:                        F(F, [#r{a=4,b=7},#r{a=4,b=7},#r{a=1,b=42}]),
  575:                     {'EXIT',_} = (catch F(F, [#r1{}])),
  576:                     ok
  577:                   end(),
  578: 
  579:              true = fun() ->
  580:                       R = #r{},
  581:                       if is_record(R, r) -> true; true -> false end
  582:                      end(),
  583: 
  584:              ok = fun() ->
  585:                       F = fun(true, B) when B#r1.a -> ok;
  586:                              (false, _) -> error
  587:                       end,
  588:                       ok = F(true, #r1{a=true}),
  589:                       error = F(false, anything_goes),
  590:                       {'EXIT',_} = (catch F(true, #r1{})),
  591:                       {'EXIT',_} = (catch F(true, #r{})),
  592:                       ok
  593:                   end(),
  594: 
  595: 	     ok = fun() ->
  596: 		      F = fun([{a,R}=T]) when R#r.a =:= 42 ->
  597:                                    {ok,tuple_size(T)};
  598: 			     ([{a,R}=T]) when R#r1.a =:= 7 ->
  599:                                    {ok,tuple_size(T)};
  600: 			     (_) -> error
  601: 		          end,
  602: 		      {ok,2} = F([{a,#r{a=42}}]),
  603: 		      {ok,2} = F([{a,#r1{a=7}}]),
  604: 		      error = F([{a,#r1{}}]),
  605: 		      error = F({a,b,c}),
  606: 		      error = F([]),
  607: 		      ok
  608: 	     end(),
  609: 
  610: 	     ok = fun() ->
  611: 		      F = fun(X, Y, Z) when is_record(X, r1) andalso
  612:                                             (is_record(Y, r2) orelse
  613:                                              is_record(Z, r3)) -> true;
  614: 			     (_, _, _) -> false
  615: 		          end,
  616: 		      true = F(#r1{}, #r2{}, #r3{}),
  617:  		      true = F(#r1{}, #r2{}, blurf),
  618:  		      true = F(#r1{}, blurf, #r3{}),
  619:  		      false = F(#r1{}, blurf, blurf),
  620: 		      false = F(blurf, #r2{}, #r3{}),
  621:  		      false = F(blurf, #r2{}, blurf),
  622:  		      false = F(blurf, blurf, #r3{}),
  623:  		      false = F(blurf, blurf, blurf),
  624: 		      ok
  625: 	     end(),
  626: 
  627: 	     ok = fun() ->
  628: 		      F = fun(R=#r{a=42}) when R#r.b =:= 7 ->
  629:                                    {ok,R};
  630: 			     (_) -> error
  631: 		          end,
  632: 		      {ok,#r{a=42,b=7}} = F(#r{a=42,b=7}),
  633: 		      error = F(#r{}),
  634: 		      error = F([a,b,c]),
  635: 		      ok
  636: 	     end(),
  637: 
  638:              ok.
  639:       ">>
  640:       ],
  641:     ?line run(Config, Ts, [strict_record_tests]),
  642:     ok.
  643: 
  644: otp_5990(doc) ->
  645:     "OTP-5990. {erlang,is_record}.";
  646: otp_5990(suite) -> [];
  647: otp_5990(Config) when is_list(Config) ->
  648:     Ts = [
  649:       <<"
  650:          -record(r, {a,b,c}).
  651: 
  652:          t() ->
  653:              [1,2,3] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
  654:                                  begin {erlang,is_record}(R, r) end],
  655:              [1,2,3] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
  656:                                  begin {erlang,is_record}(R, r) end],
  657:              ok.
  658:       ">>,
  659: 
  660:       <<"
  661:          -record('OrdSet', {orddata = {},
  662:                             ordtype = {}}).
  663: 
  664:          to_sets(S) when tuple(S#'OrdSet'.ordtype) ->
  665:              ok.
  666: 
  667:          lc(S) ->
  668:              [X || X <- [S], tuple(X#'OrdSet'.ordtype)].
  669: 
  670:          t() ->
  671:              S = #'OrdSet'{},
  672:              ok = to_sets(S),
  673:              [S] = lc(S),
  674:              ok.
  675:       ">>
  676:       ],
  677:     ?line run(Config, Ts, [strict_record_tests]),
  678:     ok.
  679:         
  680: 
  681: otp_7078(doc) ->
  682:     "OTP-7078. Record update: missing test.";
  683: otp_7078(suite) -> [];
  684: otp_7078(Config) when is_list(Config) ->
  685:     Ts = [
  686:       <<"
  687:          -record(r, {f}).
  688:          -record(r2, {}).
  689: 
  690:          t() ->
  691:              {'EXIT',_} = (catch (#r2{})#r{}),
  692:              {'EXIT',_} = (catch (#r2{})#r{f = 2}),
  693:              ok.
  694:       ">>,
  695: 
  696:       <<"
  697:          -record(r, {f}).
  698: 
  699:          maker(F) -> 
  700:              put(a, get(a)+1),
  701:              #r{f = F}.
  702: 
  703:          t() ->
  704:              put(a, 0),
  705:              (maker(2))#r{},
  706:              1 = get(a),
  707:              ok.
  708:       ">>
  709: 
  710:       ],
  711:     ?line run(Config, Ts, [strict_record_tests]),
  712:     ok.
  713: 
  714: -record(otp_7101, {a,b,c=[],d=[],e=[]}).
  715: 
  716: otp_7101(doc) ->
  717:     "OTP-7101. Record update: more than one call to setelement/3.";
  718: otp_7101(suite) -> [];
  719: otp_7101(Config) when is_list(Config) ->
  720:     Rec = #otp_7101{},
  721: 
  722:     %% Spawn a tracer process to count the number of setelement/3 calls.
  723:     %% The tracer will forward all trace messages to us.
  724:     Self = self(),
  725:     Tracer = spawn_link(fun() -> otp_7101_tracer(Self, 0) end),
  726:     ?line 1 = erlang:trace_pattern({erlang,setelement,3}, true),
  727:     ?line erlang:trace(self(), true, [{tracer,Tracer},call]),
  728:     
  729:     %% Update the record.
  730:     ?line #otp_7101{a=2,b=1,c=[],d=[],e=[]} = otp_7101_update1(Rec),
  731:     ?line #otp_7101{a=1,b=2,c=[],d=[],e=[]} = otp_7101_update2(Rec),
  732:     ?line #otp_7101{a=2,b=1,c=[],d=[],e=[]} = otp_7101_update3(Rec),
  733:     ?line #otp_7101{a=1,b=2,c=[],d=[],e=[]} = otp_7101_update4(Rec),
  734: 
  735:     %% Verify that setelement/3 was called the same number of times as
  736:     %% the number of record updates.
  737:     ?line Ref = erlang:trace_delivered(Self),
  738:     receive
  739: 	{trace_delivered, Self, Ref} ->
  740: 	    Tracer ! done
  741:     end,
  742:     ?line 1 = erlang:trace_pattern({erlang,setelement,3}, false),
  743:     receive
  744: 	4 ->
  745: 	    ok;
  746: 	Other ->
  747: 	    ?line ?t:fail({unexpected,Other})
  748:     end.
  749: 
  750: otp_7101_tracer(Parent, N) ->
  751:     receive
  752: 	{trace,Parent,call,{erlang,setelement,[_,_,_]}} ->
  753: 	    otp_7101_tracer(Parent, N+1);
  754: 	done ->
  755: 	    Parent ! N
  756:     end.
  757: 
  758: otp_7101_update1(R) ->
  759:     R#otp_7101{b=1,
  760: 	       a=2}.
  761: 
  762: otp_7101_update2(R) ->
  763:     R#otp_7101{a=1,
  764: 	       b=2}.
  765: 
  766: otp_7101_update3(R) ->
  767:     R#otp_7101{b=1,a=2}.
  768: 
  769: otp_7101_update4(R) ->
  770:     R#otp_7101{a=1,b=2}.
  771: 
  772: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  773: 
  774: run(Config, Tests) ->
  775:     run(Config, Tests, []).
  776: 
  777: run(Config, Tests, Opts) ->
  778:     F = fun(P) ->
  779:                 {SourceFile, Mod} = compile_file_mod(Config),
  780:                 _ = compile_file(Config, P, Opts),
  781:                 AbsFile = filename:rootname(SourceFile, ".erl"),
  782:                 code:purge(Mod),
  783:                 code:load_abs(AbsFile, Mod),
  784: %io:format("run~n"),
  785:                 case catch Mod:t() of
  786:                     {'EXIT', _Reason} = Error ->
  787:                         ?t:format("failed, got ~p~n", [Error]),
  788:                         fail();
  789:                     ok ->
  790:                         ok
  791:                 end
  792:         end,
  793:     lists:foreach(F, Tests).
  794: 
  795: %% Compiles a test module and returns the list of errors and warnings.
  796: 
  797: compile_file(Config, Test0, Opts0) ->
  798:     {File, _Mod} = compile_file_mod(Config),
  799:     Filename = 'exprec_test.erl',
  800:     Test = list_to_binary(["-module(exprec_test). "
  801:                            "-compile(export_all). ",
  802:                            Test0]),
  803:     File = filename(Filename, Config),
  804:     Opts = [export_all,return,{outdir,?privdir}|Opts0],
  805:     ok = file:write_file(File, Test),
  806:     {ok, _M, Ws} = compile:file(File, Opts),
  807:     warnings(File, Ws).
  808: 
  809: compile_file_mod(Config) ->
  810:     {filename('exprec_test.erl', Config), exprec_test}.
  811: 
  812: filename(Name, Config) when is_atom(Name) ->
  813:     filename(atom_to_list(Name), Config);
  814: filename(Name, Config) ->
  815:     filename:join(?privdir, Name).
  816: 
  817: warnings(File, Ws) ->
  818:     case lists:append([W || {F, W} <- Ws, F =:= File]) of
  819:         [] -> [];
  820:         L -> {warnings, L}
  821:     end.
  822: 
  823: fail() ->
  824:     io:format("failed~n"),
  825:     ?t:fail().