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}]).