1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 1998-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(epp_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: 
   23: -export([rec_1/1, include_local/1, predef_mac/1,
   24: 	 upcase_mac_1/1, upcase_mac_2/1,
   25: 	 variable_1/1, otp_4870/1, otp_4871/1, otp_5362/1,
   26:          pmod/1, not_circular/1, skip_header/1, otp_6277/1, otp_7702/1,
   27:          otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1, otp_8503/1,
   28:          otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1, otp_10820/1]).
   29: 
   30: -export([epp_parse_erl_form/2]).
   31: 
   32: %%
   33: %% Define to run outside of test server
   34: %%
   35: %-define(STANDALONE,1).
   36: 
   37: -ifdef(STANDALONE).
   38: -compile(export_all).
   39: -define(line, put(line, ?LINE), ).
   40: -define(config(A,B),config(A,B)).
   41: %% -define(t, test_server).
   42: -define(t, io).
   43: config(priv_dir, _) ->
   44:     filename:absname("./epp_SUITE_priv");
   45: config(data_dir, _) ->
   46:     filename:absname("./epp_SUITE_data").
   47: -else.
   48: -include_lib("test_server/include/test_server.hrl").
   49: -export([init_per_testcase/2, end_per_testcase/2]).
   50: 
   51: % Default timetrap timeout (set in init_per_testcase).
   52: -define(default_timeout, ?t:minutes(1)).
   53: 
   54: init_per_testcase(_, Config) ->
   55:     ?line Dog = ?t:timetrap(?default_timeout),
   56:     [{watchdog, Dog} | Config].
   57: end_per_testcase(_, Config) ->
   58:     Dog = ?config(watchdog, Config),
   59:     test_server:timetrap_cancel(Dog),
   60:     ok.
   61: -endif.
   62: 
   63: suite() -> [{ct_hooks,[ts_install_cth]}].
   64: 
   65: all() -> 
   66:     [rec_1, {group, upcase_mac}, include_local, predef_mac,
   67:      {group, variable}, otp_4870, otp_4871, otp_5362, pmod,
   68:      not_circular, skip_header, otp_6277, otp_7702, otp_8130,
   69:      overload_mac, otp_8388, otp_8470, otp_8503, otp_8562,
   70:      otp_8665, otp_8911, otp_10302, otp_10820].
   71: 
   72: groups() -> 
   73:     [{upcase_mac, [], [upcase_mac_1, upcase_mac_2]},
   74:      {variable, [], [variable_1]}].
   75: 
   76: init_per_suite(Config) ->
   77:     Config.
   78: 
   79: end_per_suite(_Config) ->
   80:     ok.
   81: 
   82: init_per_group(_GroupName, Config) ->
   83:     Config.
   84: 
   85: end_per_group(_GroupName, Config) ->
   86:     Config.
   87: 
   88: rec_1(doc) ->
   89:     ["Recursive macros hang or crash epp (OTP-1398)."];
   90: rec_1(suite) ->
   91:     [];
   92: rec_1(Config) when is_list(Config) ->
   93:     ?line File = filename:join(?config(data_dir, Config), "mac.erl"),
   94:     ?line {ok, List} = epp_parse_file(File, [], []),
   95:     %% we should encounter errors
   96:     ?line {value, _} = lists:keysearch(error, 1, List),
   97:     ?line check_errors(List),
   98:     ok.
   99: 
  100: include_local(doc) ->
  101:     [];
  102: include_local(suite) ->
  103:     [];
  104: include_local(Config) when is_list(Config) ->
  105:     ?line DataDir = ?config(data_dir, Config),
  106:     ?line File = filename:join(DataDir, "include_local.erl"),
  107:     FooHrl = filename:join([DataDir,"include","foo.hrl"]),
  108:     BarHrl = filename:join([DataDir,"include","bar.hrl"]),
  109:     %% include_local.erl includes include/foo.hrl which
  110:     %% includes bar.hrl (also in include/) without requiring
  111:     %% any additional include path, and overriding any file
  112:     %% of the same name that the path points to
  113:     ?line {ok, List} = epp:parse_file(File, [DataDir], []),
  114:     ?line {value, {attribute,_,a,{true,true}}} =
  115: 	lists:keysearch(a,3,List),
  116:     [{File,1},{FooHrl,1},{BarHrl,1},{FooHrl,5},{File,5}] =
  117:         [ FileLine || {attribute,_,file,FileLine} <- List ],
  118:     ok.
  119: 
  120: %%% Here is a little reimplementation of epp:parse_file, which times out
  121: %%% after 4 seconds if the epp server doesn't respond. If we use the
  122: %%% regular epp:parse_file, the test case will time out, and then epp
  123: %%% server will go on growing until we dump core.
  124: epp_parse_file(File, Inc, Predef) ->
  125:     {ok, Epp} = epp:open(File, Inc, Predef),
  126:     List = collect_epp_forms(Epp),
  127:     epp:close(Epp),
  128:     {ok, List}.
  129: 
  130: collect_epp_forms(Epp) ->
  131:     Result = epp_parse_erl_form(Epp),
  132:     case Result of
  133: 	{error, _Error} ->
  134: 	    [Result | collect_epp_forms(Epp)];
  135: 	{ok, Form} ->
  136: 	    [Form | collect_epp_forms(Epp)];
  137: 	{eof, _} ->
  138: 	    [Result]
  139:     end.
  140: 
  141: epp_parse_erl_form(Epp) ->
  142:     P = spawn(?MODULE, epp_parse_erl_form, [Epp, self()]),
  143:     receive
  144: 	{P, Result} ->
  145: 	    Result
  146:     after 4000 ->
  147: 	    exit(Epp, kill),
  148: 	    exit(P, kill),
  149: 	    timeout
  150:     end.
  151: 
  152: epp_parse_erl_form(Epp, Parent) ->
  153:     Parent ! {self(), epp:parse_erl_form(Epp)}.
  154: 
  155: check_errors([]) ->
  156:     ok;
  157: check_errors([{error, Info} | Rest]) ->
  158:     ?line {Line, Mod, Desc} = Info,
  159:     ?line case Line of
  160:               I when is_integer(I) -> ok;
  161:               {L,C} when is_integer(L), is_integer(C), C >= 1 -> ok
  162:           end,
  163:     ?line Str = lists:flatten(Mod:format_error(Desc)),
  164:     ?line [Str] = io_lib:format("~s", [Str]),
  165:     check_errors(Rest);
  166: check_errors([_ | Rest]) ->
  167:     check_errors(Rest).
  168: 
  169: 
  170: upcase_mac_1(doc) ->
  171:     [];
  172: upcase_mac_1(suite) ->
  173:     [];
  174: upcase_mac_1(Config) when is_list(Config) ->
  175:     ?line File = filename:join(?config(data_dir, Config), "mac2.erl"),
  176:     ?line {ok, List} = epp:parse_file(File, [], []),
  177:     ?line [_, {attribute, _, plupp, Tuple} | _] = List,
  178:     ?line Tuple = {1, 1, 3, 3},
  179:     ok.
  180: 
  181: upcase_mac_2(doc) ->
  182:     [];
  183: upcase_mac_2(suite) ->
  184:     [];
  185: upcase_mac_2(Config) when is_list(Config) ->
  186:     ?line File = filename:join(?config(data_dir, Config), "mac2.erl"),
  187:     ?line {ok, List} = epp:parse_file(File, [], [{p, 5}, {'P', 6}]),
  188:     ?line [_, {attribute, _, plupp, Tuple} | _] = List,
  189:     ?line Tuple = {5, 5, 6, 6},
  190:     ok.
  191: 
  192: predef_mac(doc) ->
  193:     [];
  194: predef_mac(suite) ->
  195:     [];
  196: predef_mac(Config) when is_list(Config) ->
  197:     ?line File = filename:join(?config(data_dir, Config), "mac3.erl"),
  198:     ?line {ok, List} = epp:parse_file(File, [], []),
  199:     ?line [_,
  200: 	   {attribute, LineCol1, l, Line1},
  201: 	   {attribute, _, f, File},
  202: 	   {attribute, _, machine1, _},
  203: 	   {attribute, _, module, mac3},
  204: 	   {attribute, _, m, mac3},
  205: 	   {attribute, _, ms, "mac3"},
  206: 	   {attribute, _, machine2, _}
  207: 	   | _] = List,
  208:     ?line case LineCol1 of
  209:               Line1 -> ok;
  210:               {Line1,_} -> ok
  211:           end,
  212:     ok.
  213: 
  214: 
  215: variable_1(doc) ->
  216:     [];
  217: variable_1(suite) ->
  218:     [];
  219: variable_1(Config) when is_list(Config) ->
  220:     ?line DataDir = ?config(data_dir, Config),
  221:     ?line File = filename:join(DataDir, "variable_1.erl"),
  222:     ?line true = os:putenv("VAR", DataDir),
  223:     %% variable_1.erl includes variable_1_include.hrl and
  224:     %% variable_1_include_dir.hrl.
  225:     ?line {ok, List} = epp:parse_file(File, [], []),
  226:     ?line {value, {attribute,_,a,{value1,value2}}} =
  227: 	lists:keysearch(a,3,List),
  228:     ok.
  229: 
  230: otp_4870(doc) ->
  231:     ["undef without module declaration"];
  232: otp_4870(suite) ->
  233:     [];
  234: otp_4870(Config) when is_list(Config) ->
  235:     Ts = [{otp_4870,
  236:            <<"-undef(foo).
  237:            ">>,
  238:            []}],
  239:     ?line [] = check(Config, Ts),
  240:     ok.
  241: 
  242: otp_4871(doc) ->
  243:     ["crashing erl_scan"];
  244: otp_4871(suite) ->
  245:     [];
  246: otp_4871(Config) when is_list(Config) ->
  247:     ?line Dir = ?config(priv_dir, Config),
  248:     ?line File = filename:join(Dir, "otp_4871.erl"),
  249:     ?line ok = file:write_file(File, "-module(otp_4871)."),
  250:     %% Testing crash in erl_scan. Unfortunately there currently is
  251:     %% no known way to crash erl_scan so it is emulated by killing the
  252:     %% file io server. This assumes lots of things about how
  253:     %% the processes are started and how monitors are set up,
  254:     %% so there are some sanity checks before killing.
  255:     ?line {ok,Epp} = epp:open(File, []),
  256:     timer:sleep(1),
  257:     ?line true = current_module(Epp, epp),
  258:     ?line {monitored_by,[Io]} = process_info(Epp, monitored_by),
  259:     ?line true = current_module(Io, file_io_server),
  260:     ?line exit(Io, emulate_crash),
  261:     timer:sleep(1),
  262:     ?line {error,{_Line,epp,cannot_parse}} = otp_4871_parse_file(Epp),
  263:     ?line epp:close(Epp),
  264:     ok.
  265: 
  266: current_module(Pid, Mod) ->
  267:     case process_info(Pid, current_function) of
  268:         {current_function, undefined} ->
  269:             true = test_server:is_native(Mod);
  270:         {current_function, {Mod, _, _}} ->
  271:             true
  272:     end.
  273: 
  274: otp_4871_parse_file(Epp) ->
  275:     case epp:parse_erl_form(Epp) of
  276: 	{ok,_} -> otp_4871_parse_file(Epp);
  277: 	Other -> Other
  278:     end.
  279: 
  280: otp_5362(doc) ->
  281:     ["OTP-5362. The -file attribute is recognized."];
  282: otp_5362(suite) ->
  283:     [];
  284: otp_5362(Config) when is_list(Config) ->
  285:     Dir = ?config(priv_dir, Config),
  286: 
  287:     Copts = [return, strong_validation,{i,Dir}],
  288: 
  289:     File_Incl = filename:join(Dir, "incl_5362.erl"),
  290:     File_Incl2 = filename:join(Dir, "incl2_5362.erl"),
  291:     File_Incl3 = filename:join(Dir, "incl3_5362.erl"),
  292:     Incl = <<"-module(incl_5362).
  293: 
  294:               -include(\"incl2_5362.erl\").
  295: 
  296:               -include_lib(\"incl3_5362.erl\").
  297: 
  298:               hi(There) -> % line 7
  299:                    a.
  300:            ">>,
  301:     Incl2 = <<"-file(\"some.file\", 100).
  302: 
  303:                foo(Bar) -> % line 102
  304:                    foo.
  305:             ">>,
  306:     Incl3 = <<"glurk(Foo) -> % line 1
  307:                   bar.
  308:             ">>,
  309:     ?line ok = file:write_file(File_Incl, Incl),
  310:     ?line ok = file:write_file(File_Incl2, Incl2),
  311:     ?line ok = file:write_file(File_Incl3, Incl3),
  312: 
  313:     ?line {ok, incl_5362, InclWarnings} = compile:file(File_Incl, Copts),
  314:     ?line true = message_compare(
  315:                    [{File_Incl3,[{{1,1},erl_lint,{unused_function,{glurk,1}}},
  316:                                  {{1,7},erl_lint,{unused_var,'Foo'}}]},
  317:                     {File_Incl,[{{7,15},erl_lint,{unused_function,{hi,1}}},
  318:                                 {{7,18},erl_lint,{unused_var,'There'}}]},
  319:                     {"some.file",[{{102,16},erl_lint,{unused_function,{foo,1}}},
  320:                                   {{102,20},erl_lint,{unused_var,'Bar'}}]}],
  321:                    lists:usort(InclWarnings)),
  322: 
  323:     file:delete(File_Incl),
  324:     file:delete(File_Incl2),
  325:     file:delete(File_Incl3),
  326: 
  327:     %% A -file attribute referring back to the including file.
  328:     File_Back = filename:join(Dir, "back_5362.erl"),
  329:     File_Back_hrl = filename:join(Dir, "back_5362.hrl"),
  330:     Back = <<"-module(back_5362).
  331: 
  332:               -compile(export_all).
  333: 
  334:               -file(?FILE, 1).
  335:               -include(\"back_5362.hrl\").
  336: 
  337:               foo(V) -> % line 4
  338:                   bar.
  339:               ">>,
  340:     Back_hrl = [<<"
  341:                   -file(\"">>,File_Back,<<"\", 2).
  342:                  ">>],
  343: 
  344:     ?line ok = file:write_file(File_Back, Back),
  345:     ?line ok = file:write_file(File_Back_hrl, list_to_binary(Back_hrl)),
  346: 
  347:     ?line {ok, back_5362, BackWarnings} = compile:file(File_Back, Copts),
  348:     ?line true = message_compare(
  349:                    [{File_Back,[{{4,19},erl_lint,{unused_var,'V'}}]}],
  350:                    BackWarnings),
  351:     file:delete(File_Back),
  352:     file:delete(File_Back_hrl),
  353: 
  354:     %% Set filename but keep line.
  355:     File_Change = filename:join(Dir, "change_5362.erl"),
  356:     Change = [<<"-module(change_5362).
  357: 
  358:                 -file(?FILE, 100).
  359: 
  360:                 -compile(export_all).
  361: 
  362:                 -file(\"other.file\", ?LINE). % like an included file...
  363:                 foo(A) -> % line 105
  364:                     bar.
  365: 
  366:                 -file(\"">>,File_Change,<<"\", 1000).
  367: 
  368:                 bar(B) -> % line 1002
  369:                     foo.
  370:               ">>],
  371: 
  372:     ?line ok = file:write_file(File_Change, list_to_binary(Change)),
  373: 
  374:     ?line {ok, change_5362, ChangeWarnings} =
  375:         compile:file(File_Change, Copts),
  376:     ?line true = message_compare(
  377:                    [{File_Change,[{{1002,21},erl_lint,{unused_var,'B'}}]},
  378:                     {"other.file",[{{105,21},erl_lint,{unused_var,'A'}}]}],
  379:                    lists:usort(ChangeWarnings)),
  380: 
  381:     file:delete(File_Change),
  382: 
  383:     %% -file attribute ending with a blank (not a newline).
  384:     File_Blank = filename:join(Dir, "blank_5362.erl"),
  385: 
  386:     Blank = <<"-module(blank_5362).
  387: 
  388:                -compile(export_all).
  389: 
  390:                -
  391:                file(?FILE, 18). q(Q) -> foo. % line 18
  392: 
  393:                a(A) -> % line 20
  394:                    1.
  395: 
  396:                -file(?FILE, 42).
  397: 
  398:                b(B) -> % line 44
  399:                    2.
  400: 
  401:                -file(?FILE, ?LINE). c(C) -> % line 47
  402:                    3.
  403:             ">>,
  404:     ?line ok = file:write_file(File_Blank, Blank),
  405:     ?line {ok, blank_5362, BlankWarnings} = compile:file(File_Blank, Copts),
  406:     ?line true = message_compare(
  407:              [{File_Blank,[{{18,3},erl_lint,{unused_var,'Q'}},
  408:                            {{20,18},erl_lint,{unused_var,'A'}},
  409:                            {{44,18},erl_lint,{unused_var,'B'}},
  410:                            {{47,3},erl_lint,{unused_var,'C'}}]}],
  411:               lists:usort(BlankWarnings)),
  412:     file:delete(File_Blank),
  413: 
  414:     %% __FILE__ is set by inclusion and by -file attribute
  415:     FILE_incl = filename:join(Dir, "file_5362.erl"),
  416:     FILE_incl1 = filename:join(Dir, "file_incl_5362.erl"),
  417:     FILE = <<"-module(file_5362).
  418: 
  419:               -export([ff/0, ii/0]).
  420: 
  421:               -include(\"file_incl_5362.erl\").
  422: 
  423:               -file(\"other_file\", 100).
  424: 
  425:               ff() ->
  426:                   ?FILE.">>,
  427:     FILE1 = <<"ii() -> ?FILE.
  428:               ">>,
  429:     FILE_Mod = file_5362,
  430:     ?line ok = file:write_file(FILE_incl, FILE),
  431:     ?line ok = file:write_file(FILE_incl1, FILE1),
  432:     FILE_Copts = [return, {i,Dir},{outdir,Dir}],
  433:     ?line {ok, file_5362, []} = compile:file(FILE_incl, FILE_Copts),
  434:     AbsFile = filename:rootname(FILE_incl, ".erl"),
  435:     ?line {module, FILE_Mod} = code:load_abs(AbsFile, FILE_Mod),
  436:     ?line II = FILE_Mod:ii(),
  437:     ?line "file_incl_5362.erl" = filename:basename(II),
  438:     ?line FF = FILE_Mod:ff(),
  439:     ?line "other_file" = filename:basename(FF),
  440:     code:purge(file_5362),
  441: 
  442:     file:delete(FILE_incl),
  443:     file:delete(FILE_incl1),
  444: 
  445:     ok.
  446: 
  447: pmod(Config) when is_list(Config) ->
  448:     ?line DataDir = ?config(data_dir, Config),
  449:     ?line Pmod = filename:join(DataDir, "pmod.erl"),
  450:     ?line case epp:parse_file([Pmod], [], []) of
  451: 	      {ok,Forms} ->
  452: 		  %% ?line io:format("~p\n", [Forms]),
  453: 		  ?line [] = [F || {error,_}=F <- Forms],
  454: 		  ok
  455: 	  end,
  456:     ok.
  457: 
  458: not_circular(Config) when is_list(Config) ->
  459:     %% Used to generate a compilation error, wrongly saying that it
  460:     %% was a circular definition.
  461: 
  462:     Ts = [{circular_1,
  463:            <<"-define(S(S), ??S).\n"
  464:              "t() -> \"string\" = ?S(string), ok.\n">>,
  465:            ok}],
  466:     ?line [] = run(Config, Ts),
  467:     ok.
  468: 
  469: skip_header(doc) ->
  470:     ["Skip some bytes in the beginning of the file."];
  471: skip_header(suite) ->
  472:     [];
  473: skip_header(Config) when is_list(Config) ->
  474:     ?line PrivDir = ?config(priv_dir, Config),
  475:     ?line File = filename:join([PrivDir, "epp_test_skip_header.erl"]),
  476:     ?line ok = file:write_file(File,
  477: 			       <<"some bytes
  478:                                   in the beginning of the file
  479:                                   that should be skipped
  480:                                   -module(epp_test_skip_header).
  481:                                   -export([main/1]).
  482: 
  483:                                   main(_) -> ?MODULE.
  484: 
  485:                                   ">>),
  486:     ?line {ok, Fd} = file:open(File, [read]),
  487:     ?line io:get_line(Fd, ''),
  488:     ?line io:get_line(Fd, ''),
  489:     ?line io:get_line(Fd, ''),
  490:     ?line {ok, Epp} = epp:open(list_to_atom(File), Fd, 4, [], []),
  491: 
  492:     ?line Forms = epp:parse_file(Epp),
  493:     ?line [] = [Reason || {error, Reason} <- Forms],
  494:     ?line ok = epp:close(Epp),
  495:     ?line ok = file:close(Fd),
  496: 
  497:     ok.
  498: 
  499: otp_6277(doc) ->
  500:     ["?MODULE before module declaration."];
  501: otp_6277(suite) ->
  502:     [];
  503: otp_6277(Config) when is_list(Config) ->
  504:     Ts = [{otp_6277,
  505:            <<"-undef(ASSERT).
  506:               -define(ASSERT, ?MODULE).
  507: 
  508:               ?ASSERT().">>,
  509:            [{error,{{4,16},epp,{undefined,'MODULE', none}}}]}],
  510:     ?line [] = check(Config, Ts),
  511:     ok.
  512: 
  513: otp_7702(doc) ->
  514:     ["OTP-7702. Wrong line number in stringifying macro expansion."];
  515: otp_7702(suite) ->
  516:     [];
  517: otp_7702(Config) when is_list(Config) ->
  518:     Dir = ?config(priv_dir, Config),
  519:     File = filename:join(Dir, "file_7702.erl"),
  520:     Contents = <<"-module(file_7702).
  521: 
  522:                   -export([t/0]).
  523: 
  524:                   -define(RECEIVE(Msg,Body),
  525:                        receive
  526:                            Msg -> Body;
  527:                            M ->
  528:                 exit({unexpected_message,M,on_line,?LINE,was_expecting,??Msg})
  529:                        after 10000 ->
  530:                             exit({timeout,on_line,?LINE,was_expecting,??Msg})
  531:                        end).
  532:                    t() ->
  533:                        ?RECEIVE(foo, bar).">>,
  534:     ?line ok = file:write_file(File, Contents),
  535:     ?line {ok, file_7702, []} =
  536:         compile:file(File, [debug_info,return,{outdir,Dir}]),
  537: 
  538:     BeamFile = filename:join(Dir, "file_7702.beam"),
  539:     {ok, AC} = beam_lib:chunks(BeamFile, [abstract_code]),
  540: 
  541:     {file_7702,[{abstract_code,{_,Forms}}]} = AC,
  542:     Fun = fun(Attrs) ->
  543:                   {line, L} = erl_parse:get_attribute(Attrs, line),
  544:                   L
  545:           end,
  546:     Forms2 = [erl_lint:modify_line(Form, Fun) || Form <- Forms],
  547:     ?line
  548:         [{attribute,1,file,_},
  549:          _,
  550:          _,
  551:          {function,_,t,0,
  552:           [{clause,_,[],[],
  553:             [{'receive',14,
  554:               [_,
  555:                {clause,14,
  556:                 [{var,14,'M'}],
  557:                 [],
  558:                 [{_,_,_,
  559:                   [{tuple,14,
  560:                     [{atom,14,unexpected_message},
  561:                      {var,14,'M'},
  562:                      {atom,14,on_line},
  563:                      {integer,14,14},
  564:                      {atom,14,was_expecting},
  565:                      {string,14,"foo"}]}]}]}],
  566:               {integer,14,10000},
  567:               [{call,14,
  568:                 {atom,14,exit},
  569:                 [{tuple,14,
  570:                   [{atom,14,timeout},
  571:                    {atom,14,on_line},
  572:                    {integer,14,14},
  573:                    {atom,14,was_expecting},
  574:                    {string,14,"foo"}]}]}]}]}]},
  575:          {eof,14}] = Forms2,
  576: 
  577:     file:delete(File),
  578:     file:delete(BeamFile),
  579: 
  580:     ok.
  581: 
  582: otp_8130(doc) ->
  583:     ["OTP-8130. Misc tests."];
  584: otp_8130(suite) ->
  585:     [];
  586: otp_8130(Config) when is_list(Config) ->
  587:     true = os:putenv("epp_inc1", "stdlib"),
  588:     Ts = [{otp_8130_1,
  589:            <<"-define(M(A), ??A). "
  590:              "t() ->  "
  591:              "   L = \"{ 34 , \\\"1\\\\x{AAA}\\\" , \\\"34\\\" , X . a , $\\\\x{AAA} }\", "
  592:              "   R = ?M({34,\"1\\x{aaa}\",\"34\",X.a,$\\x{aaa}}),"
  593:              "   Lt = erl_scan:string(L, 1, [unicode]),"
  594:              "   Rt = erl_scan:string(R, 1, [unicode]),"
  595:              "   Lt = Rt, ok. ">>,
  596:           ok},
  597: 
  598:           {otp_8130_2,
  599:            <<"-define(M(A), ??B). "
  600:              "t() -> B = 18, 18 = ?M(34), ok. ">>,
  601:            ok},
  602: 
  603:           {otp_8130_2a,
  604:            <<"-define(m(A), ??B). "
  605:              "t() -> B = 18, 18 = ?m(34), ok. ">>,
  606:            ok},
  607: 
  608:           {otp_8130_3,
  609:            <<"-define(M1(A, B), {A,B}).\n"
  610:              "t0() -> 1.\n"
  611:              "t() ->\n"
  612:              "   {2,7} =\n"
  613:              "      ?M1(begin 1 = fun() -> 1 end(),\n" % Bug -R13B01
  614:              "                2 end,\n"
  615:              "          7),\n"
  616:              "   {2,7} =\n"
  617:              "      ?M1(begin 1 = fun t0/0(),\n"
  618:              "                2 end,\n"
  619:              "          7),\n"
  620:              "   {2,7} =\n"
  621:              "      ?M1(begin 2 = byte_size(<<\"34\">>),\n"
  622:              "                2 end,\n"
  623:              "          7),\n"
  624:              "   R2 = math:sqrt(2.0),\n"
  625:              "   {2,7} =\n"
  626:              "      ?M1(begin yes = if R2 > 1 -> yes end,\n"
  627:              "                2 end,\n"
  628:              "          7),\n"
  629:              "   {2,7} =\n"
  630:              "      ?M1(begin yes = case R2 > 1  of true -> yes end,\n"
  631:              "                2 end,\n"
  632:              "          7),\n"
  633:              "   {2,7} =\n"
  634:              "      ?M1(begin yes = receive 1 -> 2 after 0 -> yes end,\n"
  635:              "                2 end,\n"
  636:              "          7),\n"
  637:              "   {2,7} =\n"
  638:              "      ?M1(begin yes = try 1 of 1 -> yes after foo end,\n"
  639:              "                2 end,\n"
  640:              "          7),\n"
  641:              "ok.\n">>,
  642:            ok},
  643: 
  644:           {otp_8130_4,
  645:            <<"-define(M3(), A).\n"
  646:              "t() -> A = 1, ?M3(), ok.\n">>,
  647:            ok},
  648: 
  649:           {otp_8130_5,
  650:            <<"-include_lib(\"$epp_inc1/include/qlc.hrl\").\n"
  651:              "t() -> [1] = qlc:e(qlc:q([X || X <- [1]])), ok.\n">>,
  652:            ok},
  653: 
  654:           {otp_8130_6,
  655:            <<"-include_lib(\"kernel/include/file.hrl\").\n"
  656:              "t() -> 14 = (#file_info{size = 14})#file_info.size, ok.\n">>,
  657:            ok},
  658: 
  659:           {otp_8130_7_new,
  660:            <<"-record(b, {b}).\n"
  661:              "-define(A, {{a,#b.b).\n"
  662:              "t() -> {{a,2}} = ?A}}, ok.">>,
  663:            ok},
  664: 
  665:           {otp_8130_8,
  666:            <<"\n-define(A(B), B).\n"
  667:              "-undef(A).\n"
  668:              "-define(A, ok).\n"
  669:              "t() -> ?A.\n">>,
  670:            ok},
  671:           {otp_8130_9,
  672:            <<"-define(a, 1).\n"
  673:              "-define(b, {?a,?a}).\n"
  674:              "t() -> ?b.\n">>,
  675:            {1,1}}
  676: 
  677:          ],
  678:     ?line [] = run(Config, Ts),
  679: 
  680:     Cs = [{otp_8130_c1,
  681:            <<"-define(M1(A), if\n"
  682:              "A =:= 1 -> B;\n"
  683:              "true -> 2\n"
  684:              "end).\n"
  685:             "t() -> {?M1(1), ?M1(2)}. \n">>,
  686:            {errors,[{{5,13},erl_lint,{unbound_var,'B'}},
  687:                     {{5,21},erl_lint,{unbound_var,'B'}}],
  688:             []}},
  689: 
  690:           {otp_8130_c2,
  691:            <<"-define(M(A), A).\n"
  692:              "t() -> ?M(1\n">>,
  693:            {errors,[{{2,9},epp,{arg_error,'M'}}],[]}},
  694: 
  695:           {otp_8130_c3,
  696:            <<"-define(M(A), A).\n"
  697:              "t() -> ?M.\n">>,
  698:            {errors,[{{2,9},epp,{mismatch,'M'}}],[]}},
  699: 
  700:           {otp_8130_c4,
  701:            <<"-define(M(A), A).\n"
  702:              "t() -> ?M(1, 2).\n">>,
  703:            {errors,[{{2,9},epp,{mismatch,'M'}}],[]}},
  704: 
  705:           {otp_8130_c5,
  706:            <<"-define(M(A), A).\n"
  707:              "t() -> ?M().\n">>,
  708:            {errors,[{{2,9},epp,{mismatch,'M'}}],[]}},
  709: 
  710:           {otp_8130_c6,
  711:            <<"-define(M3(), A).\n"
  712:              "t() -> A = 1, ?3.14159}.\n">>,
  713:            {errors,[{{2,16},epp,{call,"?3.14159"}}],[]}},
  714: 
  715:           {otp_8130_c7,
  716:            <<"\nt() -> ?A.\n">>,
  717:            {errors,[{{2,9},epp,{undefined,'A', none}}],[]}},
  718: 
  719:           {otp_8130_c8,
  720:            <<"\n-include_lib(\"$apa/foo.hrl\").\n">>,
  721:            {errors,[{{2,2},epp,{include,lib,"$apa/foo.hrl"}}],[]}},
  722: 
  723: 
  724:           {otp_8130_c9,
  725:            <<"-define(S, ?S).\n"
  726:              "t() -> ?S.\n">>,
  727:            {errors,[{{2,9},epp,{circular,'S', none}}],[]}},
  728: 
  729:           {otp_8130_c10,
  730:            <<"\n-file.">>,
  731:            {errors,[{{2,2},epp,{bad,file}}],[]}},
  732: 
  733:           {otp_8130_c11,
  734:            <<"\n-include_lib 92.">>,
  735:            {errors,[{{2,2},epp,{bad,include_lib}}],[]}},
  736: 
  737:           {otp_8130_c12,
  738:            <<"\n-include_lib(\"kernel/include/fopp.hrl\").\n">>,
  739:            {errors,[{{2,2},epp,{include,lib,"kernel/include/fopp.hrl"}}],[]}},
  740: 
  741:           {otp_8130_c13,
  742:            <<"\n-include(foo).\n">>,
  743:            {errors,[{{2,2},epp,{bad,include}}],[]}},
  744: 
  745:           {otp_8130_c14,
  746:            <<"\n-undef({foo}).\n">>,
  747:            {errors,[{{2,2},epp,{bad,undef}}],[]}},
  748: 
  749:           {otp_8130_c15,
  750:            <<"\n-define(a, 1).\n"
  751:             "-define(a, 1).\n">>,
  752:            {errors,[{{3,9},epp,{redefine,a}}],[]}},
  753: 
  754:           {otp_8130_c16,
  755:            <<"\n-define(A, 1).\n"
  756:             "-define(A, 1).\n">>,
  757:            {errors,[{{3,9},epp,{redefine,'A'}}],[]}},
  758: 
  759:           {otp_8130_c17,
  760:            <<"\n-define(A(B), B).\n"
  761:             "-define(A, 1).\n">>,
  762:            []},
  763: 
  764:           {otp_8130_c18,
  765:            <<"\n-define(A, 1).\n"
  766:             "-define(A(B), B).\n">>,
  767:            []},
  768: 
  769:           {otp_8130_c19,
  770:            <<"\n-define(a(B), B).\n"
  771:             "-define(a, 1).\n">>,
  772:            []},
  773: 
  774:           {otp_8130_c20,
  775:            <<"\n-define(a, 1).\n"
  776:             "-define(a(B), B).\n">>,
  777:            []},
  778: 
  779:           {otp_8130_c21,
  780:            <<"\n-define(A(B, B), B).\n">>,
  781:            {errors,[{{2,2},epp,{bad,define}}],[]}},
  782: 
  783:           {otp_8130_c22,
  784:            <<"\n-define(a(B, B), B).\n">>,
  785:            {errors,[{{2,2},epp,{bad,define}}],[]}},
  786: 
  787:           {otp_8130_c23,
  788:            <<"\n-file(?b, 3).\n">>,
  789:            {errors,[{{2,8},epp,{undefined,b, none}}],[]}},
  790: 
  791:           {otp_8130_c24,
  792:            <<"\n-include(\"no such file.erl\").\n">>,
  793:            {errors,[{{2,2},epp,{include,file,"no such file.erl"}}],[]}},
  794: 
  795:           {otp_8130_7,
  796:            <<"-record(b, {b}).\n"
  797:              "-define(A, {{a,#b.b.\n"
  798:              "t() -> {{a,2}} = ?A}}, ok.">>,
  799:            {errors,[{{2,20},epp,missing_parenthesis},
  800:                     {{3,19},epp,{undefined,'A',none}}],[]}}
  801: 
  802:           ],
  803:     ?line [] = compile(Config, Cs),
  804: 
  805:     Cks = [{otp_check_1,
  806:             <<"\n-include_lib(\"epp_test.erl\").\n">>,
  807:             [{error,{{2,2},epp,{depth,"include_lib"}}}]},
  808: 
  809:            {otp_check_2,
  810:             <<"\n-include(\"epp_test.erl\").\n">>,
  811:             [{error,{{2,2},epp,{depth,"include"}}}]}
  812:            ],
  813:     ?line [] = check(Config, Cks),
  814: 
  815:     ?line Dir = ?config(priv_dir, Config),
  816:     ?line File = filename:join(Dir, "otp_8130.erl"),
  817:     ?line ok = file:write_file(File,
  818:                                "-module(otp_8130).\n"
  819:                                "-define(a, 3.14).\n"
  820:                                "t() -> ?a.\n"),
  821:     ?line {ok,Epp} = epp:open(File, []),
  822:     ?line ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE','LINE',
  823:            'MACHINE','MODULE','MODULE_STRING'] = macs(Epp),
  824:     ?line {ok,[{'-',_},{atom,_,file}|_]} = epp:scan_erl_form(Epp),
  825:     ?line {ok,[{'-',_},{atom,_,module}|_]} = epp:scan_erl_form(Epp),
  826:     ?line {ok,[{atom,_,t}|_]} = epp:scan_erl_form(Epp),
  827:     ?line {eof,_} = epp:scan_erl_form(Epp),
  828:     ?line ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE','LINE',
  829:            'MACHINE','MODULE','MODULE_STRING',a] = macs(Epp),
  830:     ?line epp:close(Epp),
  831: 
  832:     %% escript
  833:     ModuleStr = "any_name",
  834:     Module = list_to_atom(ModuleStr),
  835:     fun() ->
  836:             PreDefMacros = [{'MODULE', Module, redefine},
  837:                             {'MODULE_STRING', ModuleStr, redefine},
  838:                             a, {b,2}],
  839:             ?line {ok,Epp2} = epp:open(File, [], PreDefMacros),
  840:             ?line [{atom,_,true}] = macro(Epp2, a),
  841:             ?line [{integer,_,2}] = macro(Epp2, b),
  842:             ?line false = macro(Epp2, c),
  843:             ?line epp:close(Epp2)
  844:     end(),
  845:     fun() ->
  846:             PreDefMacros = [{a,b,c}],
  847:             ?line {error,{bad,{a,b,c}}} = epp:open(File, [], PreDefMacros)
  848:     end(),
  849:     fun() ->
  850:             PreDefMacros = [a, {a,1}],
  851:             ?line {error,{redefine,a}} = epp:open(File, [], PreDefMacros)
  852:     end(),
  853:     fun() ->
  854:             PreDefMacros = [{a,1},a],
  855:             ?line {error,{redefine,a}} = epp:open(File, [], PreDefMacros)
  856:     end(),
  857: 
  858:     ?line {error,enoent} = epp:open("no such file", []),
  859:     ?line {error,enoent} = epp:parse_file("no such file", [], []),
  860: 
  861:     _ = ifdef(Config),
  862: 
  863:     ok.
  864: 
  865: macs(Epp) ->
  866:     Macros = epp:macro_defs(Epp), % not documented
  867:     lists:sort([MName || {{atom,MName},_} <- Macros]).
  868: 
  869: macro(Epp, N) ->
  870:     case lists:keyfind({atom,N}, 1, epp:macro_defs(Epp)) of
  871:         false -> false;
  872:         {{atom,N},{_,V}} -> V;
  873:         {{atom,N},Defs} -> lists:append([V || {_,{_,V}} <- Defs])
  874:     end.
  875: 
  876: ifdef(Config) ->
  877:     Cs = [{ifdef_c1,
  878:            <<"-ifdef(a).\n"
  879:              "a bug.\n"
  880:              "-else.\n"
  881:              "-ifdef(A).\n"
  882:              "a bug.\n"
  883:              "-endif.\n"
  884:              "-else.\n"
  885:              "t() -> ok.\n"
  886:              "-endif.">>,
  887:            {errors,[{{7,2},epp,{illegal,"repeated",'else'}}],[]}},
  888: 
  889:           {ifdef_c2,
  890:            <<"-define(a, true).\n"
  891:              "-ifdef(a).\n"
  892:              "a bug.\n"
  893:              "-endif.">>,
  894:            {errors,[{{3,3},erl_parse,["syntax error before: ","bug"]}],[]}},
  895: 
  896:           {ifdef_c3,
  897:            <<"-define(a, true).\n"
  898:              "-ifdef(a).\n"
  899:              "-endif">>,
  900: 
  901:            {errors,[{{3,2},epp,{bad,endif}},
  902:                     {{3,7},epp,{illegal,"unterminated",ifdef}}],
  903:           []}},
  904: 
  905:           {ifdef_c4,
  906:            <<"\n-ifdef a.\n"
  907:              "-endif.\n">>,
  908:            {errors,[{{2,2},epp,{bad,ifdef}}],[]}},
  909: 
  910:           {ifdef_c5,
  911:            <<"-ifdef(a).\n"
  912:              "-else.\n"
  913:              "-endif.\n"
  914:              "-endif.\n">>,
  915:            {errors,[{{4,2},epp,{illegal,"unbalanced",endif}}],[]}},
  916: 
  917:           {ifdef_c6,
  918:            <<"-ifdef(a).\n"
  919:              "-else.\n"
  920:              "-endif.\n"
  921:              "-else.\n">>,
  922:            {errors,[{{4,2},epp,{illegal,"unbalanced",'else'}}],[]}},
  923: 
  924:           {ifdef_c7,
  925:            <<"-ifndef(a).\n"
  926:              "-else\n"
  927:              "foo bar\n"
  928:              "-else.\n"
  929:              "t() -> a.\n"
  930:              "-endif.\n">>,
  931:            {errors,[{{2,2},epp,{bad,else}}],[]}},
  932: 
  933:           {ifdef_c8,
  934:            <<"-ifdef(a).\n"
  935:               "-foo bar.">>,
  936:            {errors,[{{2,10},epp,{illegal,"unterminated",ifdef}}],[]}},
  937: 
  938:           {ifdef_c9,
  939:            <<"-ifdef(a).\n"
  940:               "3.3e12000.\n"
  941:               "-endif.\n">>,
  942:            []},
  943: 
  944:           {ifdef_c10,
  945:            <<"\nt() -> 3.3e12000.\n">>,
  946:            {errors,[{{2,8},erl_scan,{illegal,float}},
  947:                     {{2,17},erl_parse,["syntax error before: ","'.'"]}], % ...
  948:             []}},
  949: 
  950:           {ifndef_c1,
  951:            <<"-ifndef(a).\n"
  952:              "-ifndef(A).\n"
  953:              "t() -> ok.\n"
  954:              "-endif.\n"
  955:              "-else.\n"
  956:              "a bug.\n"
  957:              "-else.\n"
  958:              "a bug.\n"
  959:              "-endif.">>,
  960:            {errors,[{{7,2},epp,{illegal,"repeated",'else'}}],[]}},
  961: 
  962:           {ifndef_c3,
  963:            <<"-ifndef(a).\n"
  964:              "-endif">>,
  965: 
  966:            {errors,[{{2,2},epp,{bad,endif}},
  967:                     {{2,7},epp,{illegal,"unterminated",ifndef}}],
  968:           []}},
  969: 
  970:           {ifndef_c4,
  971:            <<"\n-ifndef a.\n"
  972:              "-endif.\n">>,
  973:            {errors,[{{2,2},epp,{bad,ifndef}}],[]}},
  974: 
  975:           {define_c5,
  976:            <<"-\ndefine a.\n">>,
  977:            {errors,[{{2,1},epp,{bad,define}}],[]}},
  978: 
  979:           {define_c6,
  980:            <<"\n-if.\n"
  981:              "-endif.\n">>,
  982:            {errors,[{{2,2},epp,{'NYI','if'}}],[]}},
  983: 
  984:           {define_c7,
  985:            <<"-ifndef(a).\n"
  986:              "-elif.\n"
  987:              "-endif.\n">>,
  988:            {errors,[{{2,2},epp,{'NYI',elif}}],[]}},
  989: 
  990:           {define_c7,
  991:            <<"-ifndef(a).\n"
  992:              "-if.\n"
  993:              "-elif.\n"
  994:              "-endif.\n"
  995:              "-endif.\n"
  996:              "t() -> a.\n">>,
  997:            {errors,[{{2,2},epp,{'NYI','if'}}],[]}}
  998:           ],
  999:     ?line [] = compile(Config, Cs),
 1000: 
 1001:     Ts =  [{ifdef_1,
 1002:             <<"-ifdef(a).\n"
 1003:               "a bug.\n"
 1004:               "-else.\n"
 1005:               "-ifdef(A).\n"
 1006:               "a bug.\n"
 1007:               "-endif.\n"
 1008:               "t() -> ok.\n"
 1009:               "-endif.">>,
 1010:            ok},
 1011: 
 1012:            {ifdef_2,
 1013:             <<"-define(a, true).\n"
 1014:               "-ifdef(a).\n"
 1015:               "-define(A, true).\n"
 1016:               "-ifdef(A).\n"
 1017:               "t() -> ok.\n"
 1018:               "-else.\n"
 1019:               "a bug.\n"
 1020:               "-endif.\n"
 1021:               "-else.\n"
 1022:               "a bug.\n"
 1023:               "-endif.">>,
 1024:            ok},
 1025: 
 1026:            {ifdef_3,
 1027:             <<"\n-define(a, true).\n"
 1028:               "-ifndef(a).\n"
 1029:               "a bug.\n"
 1030:               "-else.\n"
 1031:               "-define(A, true).\n"
 1032:               "-ifndef(A).\n"
 1033:               "a bug.\n"
 1034:               "-else.\n"
 1035:               "t() -> ok.\n"
 1036:               "-endif.\n"
 1037:               "-endif.">>,
 1038:            ok},
 1039: 
 1040:            {ifdef_4,
 1041:                        <<"-ifdef(a).\n"
 1042:               "a bug.\n"
 1043:               "-ifdef(a).\n"
 1044:                "a bug.\n"
 1045:               "-else.\n"
 1046:               "-endif.\n"
 1047:              "-ifdef(A).\n"
 1048:               "a bug.\n"
 1049:              "-endif.\n"
 1050:              "-else.\n"
 1051:              "t() -> ok.\n"
 1052:              "-endif.">>,
 1053:             ok},
 1054: 
 1055:            {ifdef_5,
 1056:            <<"-ifdef(a).\n"
 1057:               "-ifndef(A).\n"
 1058:               "a bug.\n"
 1059:               "-else.\n"
 1060:               "-endif.\n"
 1061:              "a bug.\n"
 1062:              "-else.\n"
 1063:               "t() -> ok.\n"
 1064:              "-endif.">>,
 1065:             ok},
 1066: 
 1067:            {ifdef_6,
 1068:            <<"-ifdef(a).\n"
 1069:               "-if(A).\n"
 1070:               "a bug.\n"
 1071:               "-else.\n"
 1072:               "-endif.\n"
 1073:              "a bug.\n"
 1074:              "-else.\n"
 1075:               "t() -> ok.\n"
 1076:              "-endif.">>,
 1077:             ok}
 1078: 
 1079:            ],
 1080:     ?line [] = run(Config, Ts).
 1081: 
 1082: 
 1083: 
 1084: overload_mac(doc) ->
 1085:     ["Advanced test on overloading macros."];
 1086: overload_mac(suite) ->
 1087:     [];
 1088: overload_mac(Config) when is_list(Config) ->
 1089:     Cs = [
 1090:           %% '-undef' removes all definitions of a macro
 1091:           {overload_mac_c1,
 1092:            <<"-define(A, a).\n"
 1093:             "-define(A(X), X).\n"
 1094:             "-undef(A).\n"
 1095:             "t1() -> ?A.\n",
 1096:             "t2() -> ?A(1).">>,
 1097:            {errors,[{{4,10},epp,{undefined,'A', none}},
 1098:                     {{5,10},epp,{undefined,'A', 1}}],[]}},
 1099: 
 1100:           %% cannot overload predefined macros
 1101:           {overload_mac_c2,
 1102:            <<"-define(MODULE(X), X).">>,
 1103:            {errors,[{{1,50},epp,{redefine_predef,'MODULE'}}],[]}},
 1104: 
 1105:           %% cannot overload macros with same arity
 1106:           {overload_mac_c3,
 1107:            <<"-define(A(X), X).\n"
 1108:             "-define(A(Y), Y).">>,
 1109:            {errors,[{{2,9},epp,{redefine,'A'}}],[]}},
 1110: 
 1111:           {overload_mac_c4,
 1112:            <<"-define(A, a).\n"
 1113:             "-define(A(X,Y), {X,Y}).\n"
 1114:             "a(X) -> X.\n"
 1115:             "t() -> ?A(1).">>,
 1116:            {errors,[{{4,9},epp,{mismatch,'A'}}],[]}}
 1117:          ],
 1118:     ?line [] = compile(Config, Cs),
 1119: 
 1120:     Ts = [
 1121:           {overload_mac_r1,
 1122:            <<"-define(A, 1).\n"
 1123:             "-define(A(X), X).\n"
 1124:             "-define(A(X, Y), {X, Y}).\n"
 1125:             "t() -> {?A, ?A(2), ?A(3, 4)}.">>,
 1126:            {1, 2, {3, 4}}},
 1127: 
 1128:           {overload_mac_r2,
 1129:            <<"-define(A, 1).\n"
 1130:             "-define(A(X), X).\n"
 1131:             "t() -> ?A(?A).">>,
 1132:            1},
 1133: 
 1134:           {overload_mac_r3,
 1135:            <<"-define(A, ?B).\n"
 1136:             "-define(B, a).\n"
 1137:             "-define(B(X), {b,X}).\n"
 1138:             "a(X) -> X.\n"
 1139:             "t() -> ?A(1).">>,
 1140:            1}
 1141:           ],
 1142:     ?line [] = run(Config, Ts).
 1143: 
 1144: 
 1145: otp_8388(doc) ->
 1146:     ["OTP-8388. More tests on overloaded macros."];
 1147: otp_8388(suite) ->
 1148:     [];
 1149: otp_8388(Config) when is_list(Config) ->
 1150:     Dir = ?config(priv_dir, Config),
 1151:     ?line File = filename:join(Dir, "otp_8388.erl"),
 1152:     ?line ok = file:write_file(File, <<"-module(otp_8388)."
 1153:                                        "-define(LINE, a).">>),
 1154:     fun() ->
 1155:             PreDefMacros = [{'LINE', a}],
 1156:             ?line {error,{redefine_predef,'LINE'}} =
 1157:                 epp:open(File, [], PreDefMacros)
 1158:     end(),
 1159: 
 1160:     fun() ->
 1161:             PreDefMacros = ['LINE'],
 1162:             ?line {error,{redefine_predef,'LINE'}} =
 1163:                 epp:open(File, [], PreDefMacros)
 1164:     end(),
 1165: 
 1166:     Ts = [
 1167:           {macro_1,
 1168:            <<"-define(m(A), A).\n"
 1169:              "t() -> ?m(,).\n">>,
 1170:            {errors,[{{2,9},epp,{arg_error,m}}],[]}},
 1171:           {macro_2,
 1172:            <<"-define(m(A), A).\n"
 1173:              "t() -> ?m(a,).\n">>,
 1174:            {errors,[{{2,9},epp,{arg_error,m}}],[]}},
 1175:           {macro_3,
 1176:            <<"-define(LINE, a).\n">>,
 1177:            {errors,[{{1,50},epp,{redefine_predef,'LINE'}}],[]}},
 1178:           {macro_4,
 1179:            <<"-define(A(B, C, D), {B,C,D}).\n"
 1180:              "t() -> ?A(a,,3).\n">>,
 1181:            {errors,[{{2,9},epp,{mismatch,'A'}}],[]}},
 1182:           {macro_5,
 1183:            <<"-define(Q, {?F0(), ?F1(,,4)}).\n">>,
 1184:            {errors,[{{1,62},epp,{arg_error,'F1'}}],[]}},
 1185:           {macro_6,
 1186:            <<"-define(FOO(X), ?BAR(X)).\n"
 1187:              "-define(BAR(X), ?FOO(X)).\n"
 1188:              "-undef(FOO).\n"
 1189:              "test() -> ?BAR(1).\n">>,
 1190:            {errors,[{{4,12},epp,{undefined,'FOO',1}}],[]}}
 1191:          ],
 1192:     ?line [] = compile(Config, Ts),
 1193:     ok.
 1194: 
 1195: otp_8470(doc) ->
 1196:     ["OTP-8470. Bugfix (one request - two replies)."];
 1197: otp_8470(suite) ->
 1198:     [];
 1199: otp_8470(Config) when is_list(Config) ->
 1200:     Dir = ?config(priv_dir, Config),
 1201:     C = <<"-file(\"erl_parse.yrl\", 486).\n"
 1202:           "-file(\"erl_parse.yrl\", 488).\n">>,
 1203:     ?line File = filename:join(Dir, "otp_8470.erl"),
 1204:     ?line ok = file:write_file(File, C),
 1205:     ?line {ok, _List} = epp:parse_file(File, [], []),
 1206:     file:delete(File),
 1207:     ?line receive _ -> fail() after 0 -> ok end,
 1208:     ok.
 1209: 
 1210: otp_8503(doc) ->
 1211:     ["OTP-8503. Record with no fields is considered typed."];
 1212: otp_8503(suite) ->
 1213:     [];
 1214: otp_8503(Config) when is_list(Config) ->
 1215:     Dir = ?config(priv_dir, Config),
 1216:     C = <<"-record(r, {}).">>,
 1217:     ?line File = filename:join(Dir, "otp_8503.erl"),
 1218:     ?line ok = file:write_file(File, C),
 1219:     ?line {ok, List} = epp:parse_file(File, [], []),
 1220:     ?line [_] = [F || {attribute,_,type,{{record,r},[],[]}}=F <- List],
 1221:     file:delete(File),
 1222:     ?line receive _ -> fail() after 0 -> ok end,
 1223:     ok.
 1224: 
 1225: otp_8562(doc) ->
 1226:     ["OTP-8503. Record with no fields is considered typed."];
 1227: otp_8562(suite) ->
 1228:     [];
 1229: otp_8562(Config) when is_list(Config) ->
 1230:     Cs = [{otp_8562,
 1231:            <<"-define(P(), {a,b}.\n"
 1232:              "-define(P3, .\n">>,
 1233:            {errors,[{{1,60},epp,missing_parenthesis},
 1234:                     {{2,13},epp,missing_parenthesis}], []}}
 1235:          ],
 1236:     ?line [] = compile(Config, Cs),
 1237:     ok.
 1238: 
 1239: otp_8911(doc) ->
 1240:     ["OTP-8911. -file and file inclusion bug"];
 1241: otp_8911(suite) ->
 1242:     [];
 1243: otp_8911(Config) when is_list(Config) ->
 1244:     case test_server:is_cover() of
 1245: 	true ->
 1246: 	    {skip, "Testing cover, so can not run when cover is already running"};
 1247: 	false ->
 1248: 	    do_otp_8911(Config)
 1249:     end.
 1250: do_otp_8911(Config) ->
 1251:     ?line {ok, CWD} = file:get_cwd(),
 1252:     ?line ok = file:set_cwd(?config(priv_dir, Config)),
 1253: 
 1254:     File = "i.erl",
 1255:     Cont = <<"-module(i).
 1256:               -compile(export_all).
 1257:               -file(\"fil1\", 100).
 1258:               -include(\"i1.erl\").
 1259:               t() ->
 1260:                   a.
 1261:            ">>,
 1262:     ?line ok = file:write_file(File, Cont),
 1263:     Incl = <<"-file(\"fil2\", 35).
 1264:               t1() ->
 1265:                   b.
 1266:            ">>,
 1267:     File1 = "i1.erl",
 1268:     ?line ok = file:write_file(File1, Incl),
 1269: 
 1270:     ?line {ok, i} = cover:compile(File),
 1271:     ?line a = i:t(),
 1272:     ?line {ok,[{{i,6},1}]} = cover:analyse(i, calls, line),
 1273:     ?line cover:stop(),
 1274: 
 1275:     file:delete(File),
 1276:     file:delete(File1),
 1277:     ?line file:set_cwd(CWD),
 1278:     ok.
 1279: 
 1280: otp_8665(doc) ->
 1281:     ["OTP-8665. Bugfix premature end."];
 1282: otp_8665(suite) ->
 1283:     [];
 1284: otp_8665(Config) when is_list(Config) ->
 1285:     Cs = [{otp_8562,
 1286:            <<"-define(A, a)\n">>,
 1287:            {errors,[{{1,54},epp,premature_end}],[]}}
 1288:          ],
 1289:     ?line [] = compile(Config, Cs),
 1290:     ok.
 1291: 
 1292: otp_10302(doc) ->
 1293:     "OTP-10302. Unicode characters scanner/parser.";
 1294: otp_10302(suite) ->
 1295:     [];
 1296: otp_10302(Config) when is_list(Config) ->
 1297:     %% Two messages (one too many). Keeps otp_4871 happy.
 1298:     Cs = [{otp_8562,
 1299:            <<"%% coding: utf-8\n \n \x{E4}">>,
 1300:            {errors,[{3,epp,cannot_parse},
 1301:                     {3,file_io_server,invalid_unicode}],[]}}
 1302:          ],
 1303:     [] = compile(Config, Cs),
 1304:     Dir = ?config(priv_dir, Config),
 1305:     File = filename:join(Dir, "otp_10302.erl"),
 1306:     utf8 = encoding("coding: utf-8", File),
 1307:     utf8 = encoding("coding: UTF-8", File),
 1308:     latin1 = encoding("coding: Latin-1", File),
 1309:     latin1 = encoding("coding: latin-1", File),
 1310:     none = encoding_com("coding: utf-8", File),
 1311:     none = encoding_com("\n\n%% coding: utf-8", File),
 1312:     none = encoding_nocom("\n\n coding: utf-8", File),
 1313:     utf8 = encoding_com("\n%% coding: utf-8", File),
 1314:     utf8 = encoding_nocom("\n coding: utf-8", File),
 1315:     none = encoding("coding: \nutf-8", File),
 1316:     latin1 = encoding("Encoding :  latin-1", File),
 1317:     utf8 = encoding("ccoding: UTF-8", File),
 1318:     utf8 = encoding("coding= utf-8", File),
 1319:     utf8 = encoding_com(" %% coding= utf-8", File),
 1320:     utf8 = encoding("coding  =  utf-8", File),
 1321:     none = encoding("coding: utf-16 coding: utf-8", File), %first is bad
 1322:     none = encoding("Coding: utf-8", File),    %capital c
 1323:     utf8 = encoding("-*- coding: utf-8 -*-", File),
 1324:     utf8 = encoding("-*-coding= utf-8-*-", File),
 1325:     utf8 = encoding("codingcoding= utf-8", File),
 1326:     ok = prefix("coding: utf-8", File, utf8),
 1327: 
 1328:     "coding: latin-1" = epp:encoding_to_string(latin1),
 1329:     "coding: utf-8" = epp:encoding_to_string(utf8),
 1330:     true = lists:member(epp:default_encoding(), [latin1, utf8]),
 1331: 
 1332:     ok.
 1333: 
 1334: prefix(S, File, Enc) ->
 1335:     prefix(0, S, File, Enc).
 1336: 
 1337: prefix(100, _S, _File, _) ->
 1338:     ok;
 1339: prefix(N, S, File, Enc) ->
 1340:     Enc = encoding(lists:duplicate(N, $\s) ++ S, File),
 1341:     prefix(N+1, S, File, Enc).
 1342: 
 1343: encoding(Enc, File) ->
 1344:     E = encoding_com("%% " ++ Enc, File),
 1345:     none = encoding_com(Enc, File),
 1346:     E = encoding_nocom(Enc, File).
 1347: 
 1348: encoding_com(Enc, File) ->
 1349:     B = list_to_binary(Enc),
 1350:     E = epp:read_encoding_from_binary(B),
 1351:     ok = file:write_file(File, Enc),
 1352:     {ok, Fd} = file:open(File, [read]),
 1353:     E = epp:set_encoding(Fd),
 1354:     ok = file:close(Fd),
 1355:     E = epp:read_encoding(File).
 1356: 
 1357: encoding_nocom(Enc, File) ->
 1358:     Options = [{in_comment_only, false}],
 1359:     B = list_to_binary(Enc),
 1360:     E = epp:read_encoding_from_binary(B, Options),
 1361:     ok = file:write_file(File, Enc),
 1362:     {ok, Fd} = file:open(File, [read]),
 1363:     ok = file:close(Fd),
 1364:     E = epp:read_encoding(File, Options).
 1365: 
 1366: otp_10820(doc) ->
 1367:     "OTP-10820. Unicode filenames.";
 1368: otp_10820(suite) ->
 1369:     [];
 1370: otp_10820(Config) when is_list(Config) ->
 1371:     L = [915,953,959,973,957,953,954,959,957,964],
 1372:     Dir = ?config(priv_dir, Config),
 1373:     File = filename:join(Dir, L++".erl"),
 1374:     C1 = <<"%% coding: utf-8\n -module(any).">>,
 1375:     ok = do_otp_10820(File, C1, "+pc latin1"),
 1376:     ok = do_otp_10820(File, C1, "+pc unicode"),
 1377:     C2 = <<"\n-module(any).">>,
 1378:     ok = do_otp_10820(File, C2, "+pc latin1"),
 1379:     ok = do_otp_10820(File, C2, "+pc unicode").
 1380: 
 1381: do_otp_10820(File, C, PC) ->
 1382:     {ok,Node} = start_node(erl_pp_helper, "+fnu " ++ PC),
 1383:     ok = rpc:call(Node, file, write_file, [File, C]),
 1384:     {ok,[{attribute,1,file,{File,1}},
 1385:          {attribute,2,module,any},
 1386:          {eof,2}]} = rpc:call(Node, epp, parse_file, [File, [],[]]),
 1387:     true = test_server:stop_node(Node),
 1388:     ok.
 1389: 
 1390: check(Config, Tests) ->
 1391:     eval_tests(Config, fun check_test/2, Tests).
 1392: 
 1393: compile(Config, Tests) ->
 1394:     eval_tests(Config, fun compile_test/2, Tests).
 1395: 
 1396: run(Config, Tests) ->
 1397:     eval_tests(Config, fun run_test/2, Tests).
 1398: 
 1399: eval_tests(Config, Fun, Tests) ->
 1400:     F = fun({N,P,E}, BadL) ->
 1401:                 %% io:format("Testing ~p~n", [P]),
 1402:                 Return = Fun(Config, P),
 1403:                 case message_compare(E, Return) of
 1404:                     true ->
 1405:                         BadL;
 1406:                     false ->
 1407:                         ?t:format("~nTest ~p failed. Expected~n  ~p~n"
 1408:                                   "but got~n  ~p~n", [N, E, Return]),
 1409: 			fail()
 1410:                 end
 1411:         end,
 1412:     lists:foldl(F, [], Tests).
 1413: 
 1414: 
 1415: check_test(Config, Test) ->
 1416:     Filename = "epp_test.erl",
 1417:     ?line PrivDir = ?config(priv_dir, Config),
 1418:     ?line File = filename:join(PrivDir, Filename),
 1419:     ?line ok = file:write_file(File, Test),
 1420:     ?line case epp:parse_file(File, [PrivDir], []) of
 1421:               {ok,Forms} ->
 1422:                   [E || E={error,_} <- Forms];
 1423:               {error,Error} ->
 1424:                   Error
 1425:           end.
 1426: 
 1427: compile_test(Config, Test0) ->
 1428:     Test = [<<"-module(epp_test). -compile(export_all). ">>, Test0],
 1429:     Filename = "epp_test.erl",
 1430:     ?line PrivDir = ?config(priv_dir, Config),
 1431:     ?line File = filename:join(PrivDir, Filename),
 1432:     ?line ok = file:write_file(File, Test),
 1433:     Opts = [export_all,return,nowarn_unused_record,{outdir,PrivDir}],
 1434:     case compile_file(File, Opts) of
 1435:         {ok, Ws} -> warnings(File, Ws);
 1436:         Else -> Else
 1437:     end.
 1438: 
 1439: warnings(File, Ws) ->
 1440:     case lists:append([W || {F, W} <- Ws, F =:= File]) of
 1441:         [] -> [];
 1442:         L -> {warnings, L}
 1443:     end.
 1444: 
 1445: compile_file(File, Opts) ->
 1446:     case compile:file(File, Opts) of
 1447:         {ok, _M, Ws} -> {ok, Ws};
 1448:         {error, FEs, []} -> {errors, errs(FEs, File), []};
 1449:         {error, FEs, [{File,Ws}]} -> {error, errs(FEs, File), Ws}
 1450:     end.
 1451: 
 1452: errs([{File,Es}|L], File) ->
 1453:     Es ++ errs(L, File);
 1454: errs([_|L], File) ->
 1455:     errs(L, File);
 1456: errs([], _File) ->
 1457:     [].
 1458: 
 1459: run_test(Config, Test0) ->
 1460:     Test = [<<"-module(epp_test). -compile(export_all). ">>, Test0],
 1461:     Filename = "epp_test.erl",
 1462:     ?line PrivDir = ?config(priv_dir, Config),
 1463:     ?line File = filename:join(PrivDir, Filename),
 1464:     ?line ok = file:write_file(File, Test),
 1465:     Opts = [return, {i,PrivDir},{outdir,PrivDir}],
 1466:     ?line {ok, epp_test, []} = compile:file(File, Opts),
 1467:     AbsFile = filename:rootname(File, ".erl"),
 1468:     ?line {module, epp_test} = code:load_abs(AbsFile, epp_test),
 1469:     ?line Reply = epp_test:t(),
 1470:     code:purge(epp_test),
 1471:     Reply.
 1472: 
 1473: fail() ->
 1474:     io:format("failed~n"),
 1475:     test_server:fail().
 1476: 
 1477: message_compare(T, T) ->
 1478:     true;
 1479: message_compare(T1, T2) ->
 1480:     ln(T1) =:= T2.
 1481: 
 1482: %% Replaces locations like {Line,Column} with Line.
 1483: ln({warnings,L}) ->
 1484:     {warnings,ln0(L)};
 1485: ln({errors,EL,WL}) ->
 1486:     {errors,ln0(EL),ln0(WL)};
 1487: ln(L) ->
 1488:     ln0(L).
 1489: 
 1490: ln0(L) ->
 1491:     lists:keysort(1, ln1(L)).
 1492: 
 1493: ln1([]) ->
 1494:     [];
 1495: ln1([{File,Ms}|MsL]) when is_list(File) ->
 1496:     [{File,ln0(Ms)}|ln1(MsL)];
 1497: ln1([M|Ms]) ->
 1498:     [ln2(M)|ln1(Ms)].
 1499: 
 1500: ln2({{L,_C},Mod,Mess}) ->
 1501:     {L,Mod,Mess};
 1502: ln2({error,M}) ->
 1503:     {error,ln2(M)};
 1504: ln2(M) ->
 1505:     M.
 1506: 
 1507: %% +fnu means a peer node has to be started; slave will not do
 1508: start_node(Name, Xargs) ->
 1509:     ?line PA = filename:dirname(code:which(?MODULE)),
 1510:     test_server:start_node(Name, peer, [{args, "-pa " ++ PA ++ " " ++ Xargs}]).