%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %% -module(erl2html2_SUITE). -compile(export_all). -include_lib("common_test/include/ct.hrl"). -define(HEADER, ["\n", "\n", "\n", "Module ", Src, "\n", "\n", "\n", "\n"]). %%-------------------------------------------------------------------- %% @spec suite() -> Info %% Info = [tuple()] %% @end %%-------------------------------------------------------------------- suite() -> [{timetrap,{seconds,30}}, {ct_hooks,[ts_install_cth,test_server_test_lib]}]. %%-------------------------------------------------------------------- %% @spec init_per_suite(Config0) -> %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} %% Config0 = Config1 = [tuple()] %% Reason = term() %% @end %%-------------------------------------------------------------------- init_per_suite(Config) -> Config. %%-------------------------------------------------------------------- %% @spec end_per_suite(Config0) -> void() | {save_config,Config1} %% Config0 = Config1 = [tuple()] %% @end %%-------------------------------------------------------------------- end_per_suite(_Config) -> ok. %%-------------------------------------------------------------------- %% @spec init_per_group(GroupName, Config0) -> %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} %% GroupName = atom() %% Config0 = Config1 = [tuple()] %% Reason = term() %% @end %%-------------------------------------------------------------------- init_per_group(_GroupName, Config) -> Config. %%-------------------------------------------------------------------- %% @spec end_per_group(GroupName, Config0) -> %% void() | {save_config,Config1} %% GroupName = atom() %% Config0 = Config1 = [tuple()] %% @end %%-------------------------------------------------------------------- end_per_group(_GroupName, _Config) -> ok. %%-------------------------------------------------------------------- %% @spec init_per_testcase(TestCase, Config0) -> %% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} %% TestCase = atom() %% Config0 = Config1 = [tuple()] %% Reason = term() %% @end %%-------------------------------------------------------------------- init_per_testcase(_TestCase, Config) -> Config. %%-------------------------------------------------------------------- %% @spec end_per_testcase(TestCase, Config0) -> %% void() | {save_config,Config1} | {fail,Reason} %% TestCase = atom() %% Config0 = Config1 = [tuple()] %% Reason = term() %% @end %%-------------------------------------------------------------------- end_per_testcase(_TestCase, _Config) -> ok. %%-------------------------------------------------------------------- %% @spec groups() -> [Group] %% Group = {GroupName,Properties,GroupsAndTestCases} %% GroupName = atom() %% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] %% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] %% TestCase = atom() %% Shuffle = shuffle | {shuffle,{integer(),integer(),integer()}} %% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | %% repeat_until_any_ok | repeat_until_any_fail %% N = integer() | forever %% @end %%-------------------------------------------------------------------- groups() -> []. %%-------------------------------------------------------------------- %% @spec all() -> GroupsAndTestCases | {skip,Reason} %% GroupsAndTestCases = [{group,GroupName} | TestCase] %% GroupName = atom() %% TestCase = atom() %% Reason = term() %% @end %%-------------------------------------------------------------------- all() -> [macros_defined, macros_undefined]. %%-------------------------------------------------------------------- %% @spec TestCase(Config0) -> %% ok | exit() | {skip,Reason} | {comment,Comment} | %% {save_config,Config1} | {skip_and_save,Reason,Config1} %% Config0 = Config1 = [tuple()] %% Reason = term() %% Comment = term() %% @end %%-------------------------------------------------------------------- macros_defined(Config) -> %% let erl2html2 use epp as parser DataDir = ?config(data_dir,Config), InclDir = filename:join(DataDir, "include"), {Src,Dst} = convert_module("m1",[InclDir],Config), {true,L} = check_line_numbers(Src,Dst), ok = check_link_targets(Src,Dst,L,[{baz,0}],[]), ok. macros_undefined(Config) -> %% let erl2html2 use epp_dodger as parser {Src,Dst} = convert_module("m1",[],Config), {true,L} = check_line_numbers(Src,Dst), ok = check_link_targets(Src,Dst,L,[{baz,0}],[{quux,0}]), ok. convert_module(Mod,InclDirs,Config) -> DataDir = ?config(data_dir,Config), PrivDir = ?config(priv_dir,Config), Src = filename:join(DataDir,Mod++".erl"), Dst = filename:join(PrivDir,Mod++".erl.html"), io:format("~s\n",[Src,filename:basename(Src)]), ok = erl2html2:convert(Src, Dst, InclDirs, ""), io:format("~s\n",[Dst,filename:basename(Dst)]), {Src,Dst}. %% Check that there are the same number of lines in each file, and %% that all line numbers are displayed in the dst file. check_line_numbers(Src,Dst) -> {ok,SFd} = file:open(Src,[read]), {ok,DFd} = file:open(Dst,[read]), {ok,SN} = count_src_lines(SFd,0), ok = file:close(SFd), {ok,DN} = read_dst_line_numbers(DFd), ok = file:close(DFd), {SN == DN,SN}. count_src_lines(Fd,N) -> case io:get_line(Fd,"") of eof -> {ok,N}; {error,Reason} -> {error,Reason,N}; _Line -> count_src_lines(Fd,N+1) end. read_dst_line_numbers(Fd) -> "
\n" = io:get_line(Fd,""),
    read_dst_line_numbers(Fd,0).
read_dst_line_numbers(Fd,Last) when is_integer(Last) ->
    case io:get_line(Fd,"") of
	eof ->
	    {ok,Last};
	{error,Reason} ->
	    {error,Reason,Last};
	"
"++_ -> {ok,Last}; ""++_ -> {ok,Last}; Line -> %% erlang:display(Line), Num = check_line_number(Last,Line,Line), read_dst_line_numbers(Fd,Num) end. check_line_number(Last,Line,OrigLine) -> case Line of " ct:fail({no_line_number_after,Last,OrigLine}) end, if Num == Last+1 -> Num; true -> ct:fail({unexpected_integer,Num,Last}) end end. %% Check that there is one link target for each line and one for each %% function. %% The test module has -compile(export_all), so all functions are %% found by listing the exported ones. check_link_targets(Src,Dst,L,RmFncs,ShouldRemain) -> Mod = list_to_atom(filename:basename(filename:rootname(Src))), Exports = Mod:module_info(exports)--[{module_info,0},{module_info,1}|RmFncs], LastExprFuncs = [Func || {Func,_A} <- Exports], {ok,{FAs,Fs,L},_} = xmerl_sax_parser:file(Dst, [{event_fun,fun sax_event/3}, {event_state,{Exports,LastExprFuncs,0}}]), true = (length(FAs) == length(ShouldRemain)), [] = [FA || FA <- FAs, not lists:member(FA,ShouldRemain)], [] = [F || F <- Fs, not lists:keymember(F,1,ShouldRemain)], ok. sax_event(Event,_Loc,State) -> sax_event(Event,State). sax_event({startElement,_Uri,"a",_QN,Attrs},{Exports,LastExprFuncs,PrevLine}) -> {_,_,"name",Name} = lists:keyfind("name",3,Attrs), case catch list_to_integer(Name) of Line when is_integer(Line) -> case PrevLine + 1 of Line -> {Exports,LastExprFuncs,Line}; Other -> ct:fail({unexpected_line_number_target,Other}) end; {'EXIT',_} -> {match,[FStr,EndStr]} = re:run(Name,"^(.*)-(last_expr|[0-9]+)$", [{capture,all_but_first,list}]), F = list_to_atom(http_uri:decode(FStr)), case EndStr of "last_expr" -> true = lists:member(F,LastExprFuncs), {Exports,lists:delete(F,LastExprFuncs),PrevLine}; _ -> A = list_to_integer(EndStr), A = proplists:get_value(F,Exports), {lists:delete({F,A},Exports),LastExprFuncs,PrevLine} end end; sax_event(_,State) -> State.