1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 1998-2011. All Rights Reserved.
    5: %% 
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %% 
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %% 
   17: %% %CopyrightEnd%
   18: %%
   19: %%
   20: %%----------------------------------------------------------------------
   21: %% Purpose : Test suite for the IDL preprocessor
   22: %%----------------------------------------------------------------------
   23: 
   24: -module(ic_pp_SUITE).
   25: -include_lib("test_server/include/test_server.hrl").
   26: 
   27: 
   28: 
   29: %% Standard options to the ic compiler, NOTE unholy use of OutDir
   30: 
   31: -define(OUT(X), filename:join([?config(priv_dir, Config), gen, to_list(X)])).
   32: -define(GCC, "g++").
   33: -define(GCC_VER, "2.95.3").
   34: 
   35: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
   36: -export([arg_norm/1]).
   37: -export([cascade_norm/1]).
   38: -export([comment_norm/1]).
   39: -export([concat_norm/1]).
   40: -export([define_norm/1]).
   41: -export([if_norm/1]).
   42: -export([if_zero/1]).
   43: -export([misc_norm/1]).
   44: -export([improp_nest_constr_norm/1]).
   45: -export([inc_norm/1]).
   46: -export([line_norm/1]).
   47: -export([nopara_norm/1]).
   48: -export([predef_norm/1]).
   49: -export([predef_time_norm/1]).
   50: -export([self_ref_norm/1]).
   51: -export([separate_norm/1]).
   52: -export([swallow_sc_norm/1]).
   53: -export([unintended_grp_norm/1]).
   54: -export([cases/0, init_per_suite/1, end_per_suite/1]).
   55: 
   56: 
   57: suite() -> [{ct_hooks,[ts_install_cth]}].
   58: 
   59: all() -> 
   60:     cases().
   61: 
   62: groups() -> 
   63:     [{arg, [], [arg_norm]}, {cascade, [], [cascade_norm]},
   64:      {comment, [], [comment_norm]},
   65:      {concat, [], [concat_norm]},
   66:      {define, [], [define_norm]}, {inc, [], [inc_norm]},
   67:      {improp_nest_constr, [], [improp_nest_constr_norm]},
   68:      {misc, [], [misc_norm]}, {line, [], [line_norm]},
   69:      {nopara, [], [nopara_norm]},
   70:      {predef, [], [predef_norm]},
   71:      {predef_time, [], [predef_time_norm]},
   72:      {self_ref, [], [self_ref_norm]},
   73:      {separate, [], [separate_norm]},
   74:      {swallow_sc, [], [swallow_sc_norm]},
   75:      {unintended_grp, [], [unintended_grp_norm]},
   76:      {'if', [],[if_norm, if_zero]}].
   77: 
   78: init_per_group(_GroupName, Config) ->
   79: 	Config.
   80: 
   81: end_per_group(_GroupName, Config) ->
   82: 	Config.
   83: 
   84: 
   85: init_per_suite(Config) ->
   86:     if
   87: 	is_list(Config) ->
   88: 	    case os:type() of
   89: 		{win32, _} ->
   90: 		    {skipped, "Very unplesent to run on windows"};
   91: 		_ ->
   92: 		    check_gcc(Config)
   93: 	    end;
   94: 	true ->
   95: 	    exit("Config not a list")
   96:     end.
   97: 
   98: check_gcc(Config) ->
   99:     case os:find_executable(?GCC) of
  100: 	false ->
  101: 	    {skipped, 
  102: 	     lists:flatten(io_lib:format("Can not run without ~s in path", 
  103: 					 [?GCC]))};
  104: 	_ ->
  105: 	    case trim(os:cmd(?GCC++" --version")) of
  106: 		?GCC_VER++[] -> 
  107: 		    Config;
  108: 		?GCC_VER++[D|_] when is_integer(D), D>=$0, D=<$9 -> 
  109: 		    fail_gcc(?GCC_VER++[D]);
  110: 		?GCC_VER++_ ->
  111: 		    Config;
  112: 		Ver ->
  113: 		    fail_gcc(Ver)
  114: 	    end
  115:     end.
  116: 
  117: fail_gcc(Ver) ->
  118:     {skipped, lists:flatten(io_lib:format("Need ~s v~s, not ~s", 
  119: 					  [?GCC, ?GCC_VER, Ver]))}.
  120: 
  121: trim(S) -> lists:reverse(skip_white(lists:reverse(skip_white(S)))).
  122: 
  123: skip_white([$\s|T]) -> skip_white(T);
  124: skip_white([$\n|T]) -> skip_white(T);
  125: skip_white([$\r|T]) -> skip_white(T);
  126: skip_white([$\t|T]) -> skip_white(T);
  127: skip_white(L) -> L.
  128:     
  129: 
  130: end_per_suite(Config) ->
  131:     Config.
  132: 
  133: 
  134: cases() -> 
  135:     [{group, arg}, {group, cascade}, {group, comment},
  136:      {group, concat}, {group, define}, {group, misc}, {group, 'if'},
  137:      {group, improp_nest_constr}, {group, inc},
  138:      {group, line}, {group, nopara}, {group, predef},
  139:      {group, predef_time}, {group, self_ref},
  140:      {group, separate}, {group, swallow_sc},
  141:      {group, unintended_grp}].
  142:     
  143: 
  144: 
  145: %%--------------------------------------------------------------------
  146: %% arg
  147: %%--------------------------------------------------------------------
  148: 
  149: 
  150: arg_norm(doc) -> ["Checks arguments for #define."];
  151: arg_norm(suite) -> [];
  152: arg_norm(Config) when is_list(Config) ->
  153:     DataDir = ?config(data_dir, Config),
  154:     _OutDir = ?OUT(arg_norm),
  155:     File = filename:join(DataDir, arg),
  156:     
  157:     ?line ok = test_file(File, DataDir),
  158:     ok.
  159: 
  160: 
  161: %%--------------------------------------------------------------------
  162: %% cascade
  163: %%--------------------------------------------------------------------
  164: 
  165: 
  166: cascade_norm(doc) -> ["Check cascade #define."];
  167: cascade_norm(suite) -> [];
  168: cascade_norm(Config) when is_list(Config) ->
  169:     DataDir = ?config(data_dir, Config),
  170:     _OutDir = ?OUT(cascade_norm),
  171:     File = filename:join(DataDir, cascade),
  172:     
  173:     ?line ok = test_file(File, DataDir),
  174:     ok.
  175: 
  176: 
  177: %%--------------------------------------------------------------------
  178: %% comment
  179: %%--------------------------------------------------------------------
  180: 
  181: 
  182: comment_norm(doc) -> ["Check comments."];
  183: comment_norm(suite) -> [];
  184: comment_norm(Config) when is_list(Config) ->
  185:     DataDir = ?config(data_dir, Config),
  186:     _OutDir = ?OUT(comment_norm),
  187:     File = filename:join(DataDir, comment),
  188:     
  189:     ?line ok = test_file(File, DataDir),
  190:     ok.
  191: 
  192: 
  193: %%--------------------------------------------------------------------
  194: %% concat
  195: %%--------------------------------------------------------------------
  196: 
  197: 
  198: concat_norm(doc) -> ["Check concatinations, i.e ## ."];
  199: concat_norm(suite) -> [];
  200: concat_norm(Config) when is_list(Config) ->
  201:     DataDir = ?config(data_dir, Config),
  202:     _OutDir = ?OUT(concat_norm),
  203:     File = filename:join(DataDir, concat),
  204:     
  205:     ?line ok = test_file(File, DataDir),
  206:     ok.
  207: 
  208: 
  209: %%--------------------------------------------------------------------
  210: %% define
  211: %%--------------------------------------------------------------------
  212: 
  213: 
  214: define_norm(doc) -> ["Check misceleaneous #define."];
  215: define_norm(suite) -> [];
  216: define_norm(Config) when is_list(Config) ->
  217:     DataDir = ?config(data_dir, Config),
  218:     _OutDir = ?OUT(define_norm),
  219:     File = filename:join(DataDir, define),
  220:     
  221:     ?line ok = test_file(File, DataDir),
  222:     ok.
  223: 
  224: 
  225: %%--------------------------------------------------------------------
  226: %% if
  227: %%--------------------------------------------------------------------
  228: 
  229: if_norm(doc) -> ["Check #if, #elif, and #endif. ."];
  230: if_norm(suite) -> [];
  231: if_norm(Config) when is_list(Config) ->
  232:     DataDir = ?config(data_dir, Config),
  233:     _OutDir = ?OUT(if_norm),
  234:     File = filename:join(DataDir, 'if'),
  235:     
  236:     ?line ok = test_file(File, DataDir),
  237:     ok.
  238: 
  239: if_zero(doc) -> ["Check #if 0"];
  240: if_zero(suite) -> [];
  241: if_zero(Config) when is_list(Config) ->
  242:     DataDir = ?config(data_dir, Config),
  243:     _OutDir = ?OUT(if_zero),
  244:     File = filename:join(DataDir, if_zero),
  245:     
  246:     ?line ok = test_file(File, DataDir),
  247:     ok.
  248: 
  249: 
  250: %%--------------------------------------------------------------------
  251: %% inc
  252: %%--------------------------------------------------------------------
  253: 
  254: 
  255: inc_norm(doc) -> ["Check #include."];
  256: inc_norm(suite) -> [];
  257: inc_norm(Config) when is_list(Config) ->
  258:     DataDir = ?config(data_dir, Config),
  259:     _OutDir = ?OUT(inc_norm),
  260:     File = filename:join(DataDir, inc),
  261:     
  262:     ?line ok = test_file(File, DataDir),
  263:     ok.
  264: 
  265: 
  266: 
  267: %%--------------------------------------------------------------------
  268: %% improp_nest_constr
  269: %%--------------------------------------------------------------------
  270: 
  271: 
  272: improp_nest_constr_norm(doc) -> ["Check improperly nested constructs."];
  273: improp_nest_constr_norm(suite) -> [];
  274: improp_nest_constr_norm(Config) when is_list(Config) ->
  275:     DataDir = ?config(data_dir, Config),
  276:     _OutDir = ?OUT(improp_nest_constr_norm),
  277:     File = filename:join(DataDir, improp_nest_constr),
  278:     
  279:     ?line ok = test_file(File, DataDir),
  280:     ok.
  281: 
  282: 
  283: %%--------------------------------------------------------------------
  284: %% misc
  285: %%--------------------------------------------------------------------
  286: 
  287: 
  288: misc_norm(doc) -> ["Misceleaneous checks."];
  289: misc_norm(suite) -> [];
  290: misc_norm(Config) when is_list(Config) ->
  291:     DataDir = ?config(data_dir, Config),
  292:     _OutDir = ?OUT(misc_norm),
  293:     File = filename:join(DataDir, misc),
  294:     
  295:     ?line ok = test_file(File, DataDir),
  296:     ok.
  297: 
  298: 
  299: %%--------------------------------------------------------------------
  300: %% line
  301: %%--------------------------------------------------------------------
  302: 
  303: 
  304: line_norm(doc) -> ["Checks #line."];
  305: line_norm(suite) -> [];
  306: line_norm(Config) when is_list(Config) ->
  307:     DataDir = ?config(data_dir, Config),
  308:     _OutDir = ?OUT(line_norm),
  309:     File = filename:join(DataDir, line),
  310:     
  311:     ?line ok = test_file(File, DataDir),
  312:     ok.
  313: 
  314: 
  315: %%--------------------------------------------------------------------
  316: %% nopara
  317: %%--------------------------------------------------------------------
  318: 
  319: 
  320: nopara_norm(doc) -> ["Checks #define with no parameters."];
  321: nopara_norm(suite) -> [];
  322: nopara_norm(Config) when is_list(Config) ->
  323:     DataDir = ?config(data_dir, Config),
  324:     _OutDir = ?OUT(nopara_norm),
  325:     File = filename:join(DataDir, nopara),
  326:     
  327:     ?line ok = test_file(File, DataDir),
  328:     ok.
  329: 
  330: 
  331: %%--------------------------------------------------------------------
  332: %% predef
  333: %%--------------------------------------------------------------------
  334: 
  335: 
  336: predef_norm(doc) -> ["Checks predefined macros. Note: not __TIME__ and __DATE__."];
  337: predef_norm(suite) -> [];
  338: predef_norm(Config) when is_list(Config) ->
  339:     DataDir = ?config(data_dir, Config),
  340:     _OutDir = ?OUT(predef_norm),
  341:     File = filename:join(DataDir, predef),
  342:     
  343:     ?line ok = test_file(File, DataDir),
  344:     ok.
  345: 
  346: 
  347: %%--------------------------------------------------------------------
  348: %% predef_time
  349: %%--------------------------------------------------------------------
  350: 
  351: 
  352: predef_time_norm(doc) -> ["Checks the predefined macros __TIME__ and __DATE__."];
  353: predef_time_norm(suite) -> [];
  354: predef_time_norm(Config) when is_list(Config) ->
  355:     DataDir = ?config(data_dir, Config),
  356:     _OutDir = ?OUT(predef_time_norm),
  357:     File = filename:join(DataDir, predef_time),
  358:     
  359:     ?line ok = test_file(File, DataDir),
  360:     ok.
  361: 
  362: 
  363: %%--------------------------------------------------------------------
  364: %% self_ref
  365: %%--------------------------------------------------------------------
  366: 
  367: 
  368: self_ref_norm(doc) -> ["Checks self referring macros."];
  369: self_ref_norm(suite) -> [];
  370: self_ref_norm(Config) when is_list(Config) ->
  371:     DataDir = ?config(data_dir, Config),
  372:     _OutDir = ?OUT(self_ref_norm),
  373:     File = filename:join(DataDir, self_ref),
  374:     
  375:     ?line ok = test_file(File, DataDir),
  376:     ok.
  377: 
  378: 
  379: %%--------------------------------------------------------------------
  380: %% separate
  381: %%--------------------------------------------------------------------
  382: 
  383: 
  384: separate_norm(doc) -> ["Checks separete expansion of macro arguments."];
  385: separate_norm(suite) -> [];
  386: separate_norm(Config) when is_list(Config) ->
  387:     DataDir = ?config(data_dir, Config),
  388:     _OutDir = ?OUT(separate_norm),
  389:     File = filename:join(DataDir, separate),
  390:     
  391:     ?line ok = test_file(File, DataDir),
  392:     ok.
  393: 
  394: 
  395: %%--------------------------------------------------------------------
  396: %% swallow_sc
  397: %%--------------------------------------------------------------------
  398: 
  399: 
  400: swallow_sc_norm(doc) -> ["Checks swallowing an undesirable semicolon."];
  401: swallow_sc_norm(suite) -> [];
  402: swallow_sc_norm(Config) when is_list(Config) ->
  403:     DataDir = ?config(data_dir, Config),
  404:     _OutDir = ?OUT(swallow_sc_norm),
  405:     File = filename:join(DataDir, swallow_sc),
  406:     
  407:     ?line ok = test_file(File, DataDir),
  408:     ok.
  409: 
  410: 
  411: %%--------------------------------------------------------------------
  412: %% unintended_grp
  413: %%--------------------------------------------------------------------
  414: 
  415: 
  416: unintended_grp_norm(doc) -> ["Checks unintended grouping of arithmetic."];
  417: unintended_grp_norm(suite) -> [];
  418: unintended_grp_norm(Config) when is_list(Config) ->
  419:     DataDir = ?config(data_dir, Config),
  420:     _OutDir = ?OUT(unintended_grp_norm),
  421:     File = filename:join(DataDir, unintended_grp),
  422:     
  423:     ?line ok = test_file(File, DataDir),
  424:     ok.
  425: 
  426: 
  427: 
  428: 
  429: 
  430: test_file(FileT, DataDir) ->
  431:     case test_file_1(FileT, DataDir) of
  432: 	ok -> ok;
  433: 	Chars ->
  434: 	    io:put_chars(Chars),
  435: 	    {error,{FileT,DataDir}}
  436:     end.
  437: 
  438: test_file_1(FileT, DataDir) ->
  439:     Tok = string:tokens(FileT, "/"),
  440:     FileName = lists:last(Tok),
  441:     File = FileT++".idl",
  442: 
  443:     ?line test_server:format("File  ~p~n",[File]),
  444:     ?line test_server:format("FileName  ~p~n",[FileName]),
  445: 
  446:     Flags = "-I"++DataDir,
  447: 
  448:     ?line test_server:format("Flags  ~p~n",[Flags]),
  449: 
  450:     ?line Erl = pp_erl(File, Flags),
  451:     ?line Gcc = pp_gcc(File, Flags),
  452: 
  453:     ?line case Erl of
  454: 	{error,_ErlError} ->
  455: 	    ?line test_server:format("Internal_pp Result ~n==================~n~p~n~n",[Erl]);
  456: 	{warning, _ErlWar} ->
  457: 	    ?line test_server:format("Internal_pp Result ~n==================~n~p~n~n",[Erl]);
  458: 	_ ->
  459: 	    ?line test_server:format("Internal_pp Result ~n==================~n~s~n~n",[Erl])
  460:     end,
  461:     
  462:     ?line case Gcc of
  463: 	{error,GccError} ->
  464: 	    Error = string:tokens(GccError, "\n"),
  465: 	    ?line test_server:format(?GCC" Result ~n==========~n~p~n~n",
  466: 				     [Error]);
  467: 	_ ->
  468: 	    ?line test_server:format(?GCC" Result ~n==========~n~s~n~n",[Gcc])
  469:     end,
  470: 
  471: 
  472: 
  473:     ?line case {Erl,Gcc} of
  474: 	{{warning,W}, {error,X}} ->
  475: 	    ?line case is_ok(W,X) of
  476: 		yes ->
  477: 		    ok;
  478: 		no ->
  479: 		    io_lib:format("Internal_pp found Warning = ~p ~n"
  480: 				  ?GCC" found Error = ~p~n",[W,X])
  481: 	    end;
  482: 	   
  483: 
  484: 	{{warning,W}, _} ->
  485: 	    io_lib:format(?GCC" did not find warnings while ~n"
  486: 			  "Internal_pp found the following Warning = ~p~n",[W]);
  487: 
  488: 	{{error,E}, {error,X}} ->
  489: 	    ?line case is_ok(E,X) of
  490: 		yes ->
  491: 		    ok;
  492: 		no ->
  493: 		    io_lib:format("Internal_pp found Error = ~p ~n"
  494: 				  ?GCC" found Error = ~p~n",[E,X])
  495: 	    end;
  496: 
  497: 	{{error,E}, _} ->
  498: 	    ?line case FileName of
  499: 		"if" ->
  500: 		    ?line case if_res(E) of
  501: 			ok ->
  502: 			    ok;
  503: 			_ ->
  504: 			    io_lib:format(?GCC" did not find errors while ~n"
  505: 					  "Internal_pp found the following Error = ~p~n",[E])
  506: 		    end;
  507: 		_ ->
  508: 		    io_lib:format(?GCC" did not find errors while ~n"
  509: 				  "Internal_pp found the following Error = ~p~n",[lists:flatten(E)])
  510: 	    end;
  511: 
  512: 	{_, {error,X}} ->
  513: 	    io_lib:format("Internal_pp did not find errors while ~n"
  514: 			  ?GCC" found the following Error = ~p~n",[X]);
  515: 
  516: 	_ ->
  517: 
  518: 	    ?line file:write_file("/tmp/Erl.pp",list_to_binary(Erl)),
  519: 	    ?line file:write_file("/tmp/Gcc.pp",list_to_binary(Gcc)),
  520: 	    
  521: 	    ?line Res = os:cmd("diff -b -w /tmp/Erl.pp /tmp/Gcc.pp"),
  522: 	    ?line test_server:format("///////////{error,E} E ~p  FileName~p~n",[Res,FileName]),
  523: 	    ?line case {Res, FileName} of
  524: 		{[], _} ->
  525: 		    ?line test_server:format("Diff = []   OK!!!!!!~n"),
  526: 		    ok;
  527: 		{_, "predef_time"} ->
  528: 		    Tokens = string:tokens(Res,"\n"),
  529: 		    ?line test_server:format("///////////{error,E} Tokens~p~n",[Tokens]),
  530: 		    case Tokens of
  531: 			["3c3",_,"---",_,"5c5",_,"---",_,"9c9",_,"---",_] ->
  532: 			    ok;
  533: 			_ ->
  534: 			    io_lib:format("Diff Result = ~p~n",[Res])
  535: 		    end;
  536: 		_ ->
  537: 		    io_lib:format("Diff Result = ~p~n",[Res])
  538: 	    end
  539:     end.
  540: 
  541: 
  542: 
  543: 
  544: 
  545: pp_erl(File, Flags) ->
  546:     case ic_pp:run(File,Flags) of
  547: 	{ok, [$#, $ , $1 | Rest], []} ->
  548: 	    [$#, $ , $1 | Rest];
  549: 	{ok, [$#, $ , $1 | _Rest], Warning} ->
  550: 	    {warning,Warning};
  551: 	{error,Error} ->
  552: 	    {error,Error}
  553:     end.
  554: 
  555: pp_gcc(File, Flags) ->
  556:     Cmd = ?GCC" -x c++ -E",
  557:     Line	= Cmd++" "++Flags++" "++File,
  558: 
  559:     case os:cmd(Line) of
  560: 	[$#, $ , $1 | Rest] ->			
  561: 	    [$#, $ , $1 | Rest];
  562: 	Res ->
  563: 
  564: 	    case string:str(Res,"# 1 \"") of
  565: 		0 ->
  566: 		    {error,Res};
  567: 		X ->
  568: 		    {error, string:sub_string(Res, 1, X-1)}
  569: 	    end
  570:     end.
  571: 
  572: 
  573: is_ok([],_Gcc) ->
  574:     yes;
  575: is_ok([{FileName,Line,Text}|T],Gcc) ->
  576:     Str = FileName++":"++integer_to_list(Line)++": "++Text,
  577:     case string:str(Gcc,Str) of
  578: 	0 ->
  579: 	    io:format("~n is_ok Internal_pp missed Error = ~s~n",[Str]),
  580: 	    no;
  581: 	_X ->
  582: 	    is_ok(T,Gcc)
  583:     end;
  584: is_ok([Str|T],Gcc) ->
  585:     case string:str(Gcc,Str) of
  586: 	0 ->
  587: 	    io:format("~n is_ok Internal_pp missed Error = ~s~n",[Str]),
  588: 	    no;
  589: 	_X ->
  590: 	    is_ok(T,Gcc)
  591:     end.
  592: 
  593: 
  594: to_list(X) when is_atom(X) -> atom_to_list(X);
  595: to_list(X) -> X.
  596: 
  597: 
  598: 
  599: if_res(E) ->
  600:     if_res(E,1).
  601: 
  602: if_res([H|T],Nr) ->
  603:     %% Dir = "/clearcase/otp/libraries/ic/test/ic_pp_SUITE_data/if.idl",
  604:     case {Nr, H} of
  605: 	{1, {_Dir, 2, "only '#if 0' is implemented at present"}} ->
  606: 	    if_res(T,Nr+1);
  607: 	{2, {_Dir, 3, "only '#if 0' is implemented at present"}} ->
  608: 	    if_res(T,Nr+1);
  609: 	{3, {_Dir, 5, "`else' command is not implemented at present"}} ->
  610: 	    if_res(T,Nr+1);
  611: 	{4, {_Dir, 9, "`elif' command is not implemented at present"}} ->
  612: 	    if_res(T,Nr+1);
  613: 	{5, {_Dir, 11, "`else' command is not implemented at present"}} ->
  614: 	    ok;
  615: 	_ ->
  616: 	    error
  617:     end;
  618: if_res(_, _) ->
  619:     error.
  620: 
  621: 
  622: