%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2001-2009. 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(cover_web). -author('marting@erix.ericsson.se'). -behaviour(gen_server). %%Export of configuration function -export([configData/0]). %% External exports -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -export([start_link/0,start/0,stop/0]). -export([menu_frame/2,nodes_frame/2,import_frame/2, compile_frame/2,result_frame/2]). -export([list_dir/2,compile/2,add_node/2,remove_node/2,result/2, calls/2,coverage/2,import/2]). -record(state,{dir}). -include_lib("kernel/include/file.hrl"). %% Timeouts -define(DEFAULT_TIME,10000). -define(MAX_COMPILE_TIME,60000). -define(MAX_ANALYSE_TIME,30000). %% Colors -define(INFO_BG_COLOR,"#C0C0EA"). %%%---------------------------------------------------------------------- %%% API - called from erlang shell %%%---------------------------------------------------------------------- %% Start webtool and webcover from erlang shell start() -> webtool:start(), webtool:start_tools([],"app=webcover"), ok. %% Stop webtool and webcover from erlang shell stop() -> webtool:stop_tools([],"app=webcover"), webtool:stop(). %%%---------------------------------------------------------------------- %%% API - called from webtool %%%---------------------------------------------------------------------- start_link() -> gen_server:start_link({local, webcover_server},cover_web, [], []). nodes_frame(Env,Input)-> call({nodes_frame,Env,Input}). add_node(Env,Input)-> call({add_node,Env,Input}). remove_node(Env,Input)-> call({remove_node,Env,Input}). compile_frame(Env,Input)-> call({compile_frame,Env,Input}). list_dir(Env,Input) -> call({list_dir,Env,Input}). compile(Env,Input)-> call({compile,Env,Input},?MAX_COMPILE_TIME). result_frame(Env,Input)-> call({result_frame,Env,Input}). result(Env,Input) -> call({result,Env,Input},?MAX_ANALYSE_TIME). calls(Env,Input) -> call({calls,Env,Input}). coverage(Env,Input) -> call({coverage,Env,Input}). import_frame(Env,Input)-> call({import_frame,Env,Input}). import(Env,Input)-> call({import,Env,Input}). menu_frame(Env,Input)-> call({menu_frame,Env,Input}). call(Msg) -> call(Msg,?DEFAULT_TIME). call(Msg,Time) -> gen_server:call(webcover_server,Msg,Time). configData()-> {webcover,[{web_data,{"WebCover","/webcover"}}, {alias,{"/webcover",code:priv_dir(tools)}}, {alias,{erl_alias,"/webcover/erl",[cover_web]}}, {start,{child,{{local,webcover_server}, {cover_web,start_link,[]}, permanent,100,worker,[cover_web]}}} ]}. %%%---------------------------------------------------------------------- %%% Callback functions from gen_server %%%---------------------------------------------------------------------- %%---------------------------------------------------------------------- %% Func: init/1 %% Returns: {ok, State} | %% {ok, State, Timeout} | %% ignore | %% {stop, Reason} %%---------------------------------------------------------------------- init([]) -> cover:start(), CS = whereis(cover_server), link(CS), GL = spawn_link(fun group_leader_proc/0), group_leader(GL,CS), %% Must trap exists in order to have terminate/2 executed when %% crashing because of a linked process crash. process_flag(trap_exit,true), {ok,Cwd} = file:get_cwd(), {ok, #state{dir=Cwd}}. group_leader_proc() -> register(cover_group_leader_proc,self()), group_leader_loop([]). group_leader_loop(Warnings) -> receive {io_request,From,ReplyAs,{put_chars,io_lib,Func,[Format,Args]}} -> Msg = (catch io_lib:Func(Format,Args)), From ! {io_reply,ReplyAs,ok}, case lists:member(Msg,Warnings) of true -> group_leader_loop(Warnings); false -> group_leader_loop([Msg|Warnings]) end; {io_request,From,ReplyAs,{put_chars,_Encoding,io_lib,Func,[Format,Args]}} -> Msg = (catch io_lib:Func(Format,Args)), From ! {io_reply,ReplyAs,ok}, case lists:member(Msg,Warnings) of true -> group_leader_loop(Warnings); false -> group_leader_loop([Msg|Warnings]) end; IoReq when element(1,IoReq)=:= io_request -> group_leader() ! IoReq, group_leader_loop(Warnings); {From,get_warnings} -> Warnings1 = receive {io_request,From,ReplyAs, {put_chars,io_lib,Func,[Format,Args]}} -> Msg = (catch io_lib:Func(Format,Args)), From ! {io_reply,ReplyAs,ok}, case lists:member(Msg,Warnings) of true -> Warnings; false -> [Msg|Warnings] end after 0 -> Warnings end, From ! {warnings,Warnings1}, group_leader_loop([]) end. %%---------------------------------------------------------------------- %% Func: handle_call/3 %% Returns: {reply, Reply, State} | %% {reply, Reply, State, Timeout} | %% {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, Reply, State} | (terminate/2 is called) %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- handle_call({nodes_frame,_Env,_Input},_From,State)-> {reply,nodes_frame1(),State}; handle_call({add_node,_Env,Input},_From,State)-> {reply,do_add_node(Input),State}; handle_call({remove_node,_Env,Input},_From,State)-> {reply,do_remove_node(Input),State}; handle_call({compile_frame,_Env,_Input},_From,State)-> {reply,compile_frame1(State#state.dir),State}; handle_call({list_dir,_Env,Input},_From,State)-> Dir = get_input_data(Input,"path"), case filelib:is_dir(Dir) of true -> {reply,compile_frame1(Dir),State#state{dir=Dir}}; false -> Err = Dir ++ " is not a directory", {reply,compile_frame1(State#state.dir,Err),State} end; handle_call({compile,_Env,Input},_From,State)-> {reply,do_compile(Input,State#state.dir),State}; handle_call({result_frame,_Env,_Input},_From,State)-> {reply,result_frame1(),State}; handle_call({result,_Env,Input},_From,State)-> {reply,handle_result(Input),State}; handle_call({calls,_Env,Input},_From,State)-> {reply,call_page(Input),State}; handle_call({coverage,_Env,Input},_From,State)-> {reply,coverage_page(Input),State}; handle_call({import_frame,_Env,_Input},_From,State)-> {ok,Cwd} = file:get_cwd(), {reply,import_frame1(Cwd),State}; handle_call({import,_Env,Input},_From,State)-> {reply,do_import(Input),State}; handle_call({menu_frame,_Env,_Input},_From,State)-> {reply,menu_frame1(),State}; handle_call(_Request, _From, State) -> Reply = bad_request, {reply, Reply, State}. %%---------------------------------------------------------------------- %% Func: handle_cast/2 %% Returns: {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- handle_cast(_Msg, State) -> {noreply, State}. %%---------------------------------------------------------------------- %% Func: handle_info/2 %% Returns: {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, State} (terminate/2 is called) %%---------------------------------------------------------------------- handle_info({'EXIT',_Pid,Reason}, State) -> {stop, Reason, State}. %%---------------------------------------------------------------------- %% Func: terminate/2 %% Purpose: Shutdown the server %% Returns: any (ignored by gen_server) %%---------------------------------------------------------------------- terminate(_Reason, _State) -> cover:stop(), ok. %%-------------------------------------------------------------------- %% Func: code_change/3 %% Purpose: Convert process state when code is changed %% Returns: {ok, NewState} %%-------------------------------------------------------------------- code_change(_OldVsn, State, _Extra) -> {ok, State}. %%%---------------------------------------------------------------------- %%% Internal functions %%%---------------------------------------------------------------------- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% %% The functions that creates the whole pages by collecting all the %% %% neccessary data for each page. These functions are the public %% %% interface. %% %% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%---------------------------------------------------------------------- %% Returns the page to the left frame %%---------------------------------------------------------------------- menu_frame1()-> [header(),html_header(""),menu_body(),html_end()]. %%---------------------------------------------------------------------- %% Creates the page where the user can add and remove nodes %%---------------------------------------------------------------------- nodes_frame1()-> nodes_frame1([]). nodes_frame1(Err)-> [header(),html_header("Add/remove nodes"),nodes_body(Err),html_end()]. %%---------------------------------------------------------------------- %% Creates the page where the user can cover compile modules %%---------------------------------------------------------------------- compile_frame1(Dir)-> compile_frame1(Dir,[]). compile_frame1(Dir,Err) -> [header(),html_header("Cover compile"),compile_body(Dir,Err),html_end()]. %%---------------------------------------------------------------------- %% Creates the page where the user can handle results %%---------------------------------------------------------------------- result_frame1()-> result_frame1([]). result_frame1(Err) -> [header(),html_header("Show cover results"),result_body(Err),html_end()]. %%---------------------------------------------------------------------- %%The beginning of the page that clear the cover information on a cover %%compiled module %%---------------------------------------------------------------------- call_page(Input)-> [header(),html_header("Code coverage"),call_result(Input),html_end()]. coverage_page(Input)-> [header(),html_header("Code coverage"),coverage_result(Input),html_end()]. %%---------------------------------------------------------------------- %% Creates the page where the user an import files %%---------------------------------------------------------------------- import_frame1(Dir) -> import_frame1(Dir,""). import_frame1(Dir,Err) -> [header(),html_header("Import coverdata"),import_body(Dir,Err),html_end()]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% %% The functions that build the body of the menu frame %% %% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% menu_body() -> Nodes = cover:which_nodes(), Modules = cover:modules(), Imported = cover:imported(), ["Nodes
\n", "Compile
\n", "Import
\n", "Result\n", "

Nodes:\n", "

\n", "

Compiled modules:\n", "

\n", "

Imported files:\n", "

\n"]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% %% The functions that build the body of the nodes frame %% %% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% nodes_body(Err) -> CN = cover:which_nodes(), Fun = fun(N) -> NStr = atom_to_list(N), ["\n"] end, AllNodes = lists:append(lists:map(Fun,nodes()--CN)), CoverNodes = lists:append(lists:map(Fun,CN)), [reload_menu_script(Err), "

Nodes

\n", "\n", "\n", "\n", "\n", "\n", "\n" "\n", "\n", "\n", "\n", "\n", "", "
\n", "

You can run cover over several nodes simultaneously. Coverage data\n", "from all involved nodes will be merged during analysis.\n", "

Select or enter node names to add or remove here.\n", "



Add node:", "" "
\n", "


Remove node:\n", "" "
"]. do_add_node(Input) -> NodeStr = get_input_data(Input, "node"), Node = list_to_atom(NodeStr), case net_adm:ping(Node) of pong -> cover:start(Node), nodes_frame1(); pang -> nodes_frame1("Node \\\'" ++ NodeStr ++ "\\\' is not alive") end. do_remove_node(Input) -> Node = list_to_atom(get_input_data(Input, "node")), cover:stop(Node), nodes_frame1(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % The functions that is used when the user wants to compile something % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% compile_body(Dir,Err) -> Erls = filelib:wildcard(filename:join(Dir,"*.erl")), Beams = filelib:wildcard(filename:join(Dir,"*.beam")), [reload_menu_script(Err), "

Compile

\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n" "\n", "\n", "\n", "\n", "\n", "\n", "
\n", "Each module which shall be part of the cover analysis must be prepared\n", "or 'cover compiled'. On this page you can select .erl files and/or\n", ".beam files to include in the analysis. If you select a .erl file it\n", "will first be compiled with the Erlang compiler and then prepared for\n", "coverage analysis. If you select a .beam file it will be prepared for\n", "coverage analysis directly.\n", "
\n", "To list a different directory, enter the directory name here.\n", "
List directory:
\n", "", "", "

\n", "

Select one or more .erl or .beam files to prepare for coverage\n" "analysis, and click the \"Compile\" button.\n", "

To reload the original file after coverage analysis is complete,\n" "select one or more files and click the \"Uncompile\" button, or\n", "simply click the \"Uncompile all\" button to reload all originals.\n" "

.erl files.beam files
\n", "\n", "
\n", "Compile options are only needed for .erl files. The options must be\n" "given e.g. like this: \n" "[{i,\"/my/path/include\"},{i,\"/other/path/\"}]\n" "
Compile options:
\n", "\n", "
\n", "", "", "", "
\n"]. list_modules([File|Files]) -> Mod = filename:basename(File), ["\n" | list_modules(Files)]; list_modules([]) -> []. do_compile(Input,Dir) -> {Erls,Beams,Opts,Action} = get_compile_input(parse(Input),[],[]), Errs = case Action of "compile" -> do_compile(Erls,Beams,Opts,[]); "uncompile" -> do_uncompile(Erls++Beams); "uncompile_all" -> do_uncompile(cover:modules()) end, compile_frame1(Dir,Errs). get_compile_input([{"erl",File}|Input],Erl,Beam) -> get_compile_input(Input,[File|Erl],Beam); get_compile_input([{"beam",File}|Input],Erl,Beam) -> get_compile_input(Input,Erl,[File|Beam]); get_compile_input([{"options",Opts0},{"action",Action}],Erl,Beam) -> Opts = parse_options(Opts0), {Erl,Beam,Opts,Action}. do_compile([Erl|Erls],Beams,Opts,Errs) -> case cover:compile_module(Erl,Opts) of {ok,_} -> do_compile(Erls,Beams,Opts,Errs); {error,File} -> do_compile(Erls,Beams,Opts,["\\n"++File|Errs]) end; do_compile([],[Beam|Beams],Opts,Errs) -> case cover:compile_beam(Beam) of {ok,_} -> do_compile([],Beams,Opts,Errs); {error,{no_abstract_code,File}} -> do_compile([],Beams,Opts,["\\n"++File++" (no_abstract_code)"|Errs]) end; do_compile([],[],_,[]) -> []; do_compile([],[],_,Errs) -> "Compilation failed for the following files:" ++ Errs. parse_options(Options)-> case erl_scan:string(Options ++".") of {ok,Tokens,_Line} -> case erl_parse:parse_exprs(Tokens) of {ok,X}-> case lists:map(fun erl_parse:normalise/1, X) of [List] when is_list(List) -> List; List -> List end; _ -> [] end; _ -> [] end. do_uncompile(Files) -> lists:foreach( fun(File) -> Module = if is_atom(File) -> File; true -> ModStr = filename:basename(filename:rootname(File)), list_to_atom(ModStr) end, case code:which(Module) of cover_compiled -> code:purge(Module), case code:load_file(Module) of {module, Module} -> ok; {error, _Reason2} -> code:delete(Module) end; _ -> ok end end, Files), []. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % The functions that builds the body of the page for coverage analysis% % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% result_body(Err) -> [reload_menu_script(Err), "

Result

\n", "\n", "\n", "
\n", "

After executing all your tests you can view the result of the\n", "coverage analysis here. For each module you can\n", "

\n", "
Analyse to file
\n", "
The source code of the module is shown with the number of calls\n", "to each line stated in the left margin. Lines which are never called\n", "are colored red.
\n", "
Analyse coverage
\n", "
Show the number of covered and uncovered lines in the module.
\n", "
Analyse calls
\n", "
Show the number of calls in the module.
\n", "
Reset module
\n", "
Delete all coverage data for the module.
\n", "
Export module
\n", "
Write all coverage data for the module to a file. The data can\n", "later be imported from the \"Import\" page.
\n", "
\n", "

You can also reset or export data for all modules with the\n", "Reset all and Export all actions respectively. For these\n", "two actions there is no need to select a module.\n", "

Select module and action from the drop down menus below, and click\n", "the \"Execute\" button.\n", "



\n", result_selections(), "
"]. result_selections() -> ModList = filter_modlist(cover:modules()++cover:imported_modules(),[]), ["
\n", "\n", "\n", "\n", "\n" "
\n", "Module:\n", "
\n", "
\n", "Action:\n", "
\n", "
\n" "
\n", "
\n"]. filter_modlist([M|Ms],Already) -> case lists:member(M,Already) of true -> filter_modlist(Ms,Already); false -> MStr = atom_to_list(M), ["\n" | filter_modlist(Ms,[M|Already])] end; filter_modlist([],_Already) -> []. handle_result(Input) -> case parse(Input) of [{"module",M},{"action",A}] -> case A of "analyse_to_file" -> case cover:analyse_to_file(list_to_atom(M),[html]) of {ok,File} -> case file:read_file(File) of {ok,HTML}-> file:delete(File), [header(), reload_menu_script(""), binary_to_list(HTML)]; _ -> result_frame1("Can not read file" ++ File) end; {error,no_source_code_found} -> result_frame1("No source code found for \\\'" ++ M ++ "\\\'") end; "calls" -> call_page(Input); "coverage" -> coverage_page(Input); "reset" -> cover:reset(list_to_atom(M)), result_frame1("Coverage data for \\\'" ++ M ++ "\\\' is now reset"); "reset_all" -> cover:reset(), result_frame1("All coverage data is now reset"); "export" -> ExportFile = generate_filename(M), cover:export(ExportFile,list_to_atom(M)), result_frame1("Coverage data for \\\'" ++ M ++ "\\\' is now exported to file \\\"" ++ ExportFile ++ "\\\""); "export_all" -> ExportFile = generate_filename("COVER"), cover:export(ExportFile), result_frame1( "All coverage data is now exported to file \\\"" ++ ExportFile ++ "\\\"") end; [{"action",_A}] -> result_frame1("No module is selected") end. generate_filename(Prefix) -> {ok,Cwd} = file:get_cwd(), filename:join(Cwd,Prefix ++ "_" ++ ts() ++ ".coverdata"). ts() -> {{Y,M,D},{H,Min,S}} = calendar:now_to_local_time(erlang:timestamp()), io_lib:format("~4.4.0w~2.2.0w~2.2.0w-~2.2.0w~2.2.0w~2.2.0w", [Y,M,D,H,Min,S]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % The functions that builds the body of the page that shows the calls % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% call_result(Input)-> Mod = list_to_atom(get_input_data(Input, "module")), case cover:analyse(Mod,calls) of {error,_}-> error_body(); {ok,_} -> call_result2(Mod,Input) end. call_result2(Mod,Input)-> Result = case get_input_data(Input,"what") of "mod" -> call_result(mod,Mod); "func" -> call_result(func,Mod); "clause" -> call_result(clause,Mod); _-> call_result(all,Mod) end, result_choice("calls",Mod) ++ Result. result_choice(Level,Mod)-> ModStr=atom_to_list(Mod), [reload_menu_script(""), "\n", "\n", "\n", "\n", "\n", "
All DataModuleFunctionClause

\n"]. call_result(Mode,Module)-> Content = case Mode of mod-> format_cover_call(cover:analyse(Module,calls,module),mod); func-> format_cover_call(cover:analyse(Module,calls,function),func); clause-> format_cover_call(cover:analyse(Module,calls,clause),clause); _-> format_cover_call(cover:analyse(Module,calls,module),mod) ++ format_cover_call(cover:analyse(Module,calls,function),func)++ format_cover_call(cover:analyse(Module,calls,clause),clause) end, getModDate(Module,date())++"
"++ "" ++ Content ++"
". format_cover_call({error,_},_)-> ["\n", "



\n", "The selected module is not Cover Compiled\n", "
\n", "\n"]; format_cover_call({ok,{Mod,Calls}},mod)-> ["Module calls\n", "Module", "Number of calls\n", "" ++ atom_to_list(Mod) ++"" "" ++ integer_to_list(Calls)++"\n"]; format_cover_call({ok,Calls},func)-> ["Function calls\n", "ModuleFunction", "Arity", "Number of calls \n", lists:append( lists:map( fun({{Mod,Func,Arity},Nr_of_calls})-> [""++ atom_to_list(Mod)++"\n", "" ++ atom_to_list(Func) ++" \n", "", integer_to_list(Arity), "\n", "", integer_to_list(Nr_of_calls), "\n"] end, Calls))]; format_cover_call({ok,Calls},clause)-> ["Clause calls\n", "ModuleFunction", "Arity", "Ordinal", "Number of calls\n", lists:append( lists:map( fun({{Mod,Func,Arity,Ord},Nr_of_calls})-> ["", atom_to_list(Mod), "\n", "", atom_to_list(Func), "\n", "", integer_to_list(Arity), "\n", "", integer_to_list(Ord), "\n", "", integer_to_list(Nr_of_calls), "\n"] end, Calls))]. error_body()-> ["\n", "\n", "\n", "\n", "
\n", "





\n", "The selected module is not Cover Compiled\n", "
\n", "
\n"]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % The functions that builds the body of the page that shows coverage % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% coverage_result(Input)-> Mod = list_to_atom(get_input_data(Input, "module")), case cover:analyse(Mod,coverage) of {error,_}-> error_body(); {ok,_} -> coverage_result2(Mod,Input) end. coverage_result2(Mod,Input)-> Result = case get_input_data(Input,"what") of "mod" -> coverage_result(mod,Mod); "func" -> coverage_result(func,Mod); "clause" -> coverage_result(clause,Mod); _-> coverage_result(all,Mod) end, result_choice("coverage",Mod) ++ Result. coverage_result(Mode,Module)-> Content = case Mode of mod-> format_cover_coverage(cover:analyse(Module,coverage,module), mod); func-> format_cover_coverage(cover:analyse(Module,coverage,function), func); clause-> format_cover_coverage(cover:analyse(Module,coverage,clause), clause); _-> format_cover_coverage(cover:analyse(Module,coverage,module), mod) ++ format_cover_coverage(cover:analyse(Module,coverage,function), func)++ format_cover_coverage(cover:analyse(Module,coverage,clause), clause) end, getModDate(Module,date())++"
"++ "" ++ Content ++"
". getModDate(Module,{Year,Mon,Day})-> "
Module: " ++ atom_to_list(Module) ++ "
Date: " ++ integer_to_list(Day) ++ "/" ++ integer_to_list(Mon) ++" - "++ integer_to_list(Year) ++ "
". format_cover_coverage({error,_},_)-> "



The selected module is not Cover Compiled
"; format_cover_coverage({ok,{Mod,{Cov,Not_cov}}},mod)-> ["Module coverage\n", "Module\n", "Covered\n" "Not Covered\n", "\n", "", atom_to_list(Mod), "\n" "", integer_to_list(Cov), "\n" "", integer_to_list(Not_cov), "\n"]; format_cover_coverage({ok,Cov_res},func)-> ["Function coverage\n", "\n", "ModuleFunction", "Arity", "Covered", "Not Covered", "\n", lists:append( lists:map( fun({{Mod,Func,Arity},{Cov,Not_cov}})-> [""++ atom_to_list(Mod) ++" \n", "" ++ atom_to_list(Func) ++"\n", "", integer_to_list(Arity), "\n", "", integer_to_list(Cov), "\n" "", integer_to_list(Not_cov), "\n"] end, Cov_res))]; format_cover_coverage({ok,Cov_res},clause)-> ["Clause coverage\n", "ModuleFunction\n", "Arity\n", "Ordinal\n", "Covered\n", "Not Covered\n", lists:append( lists:map( fun({{Mod,Func,Arity,Ord},{Cov,Not_cov}})-> [""++ atom_to_list(Mod) ++"\n", "" ++ atom_to_list(Func) ++" \n", "", integer_to_list(Arity), "\n" "", integer_to_list(Ord), "\n" "", integer_to_list(Cov), "\n" "", integer_to_list(Not_cov), "\n"] end, Cov_res))]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % The functions that builds the body of the import page % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% import_body(Dir,Err) -> [reload_menu_script(Err), "

Import

\n", "\n", "\n", "
\n", "

You can import coverage data from a previous analysis. If you do so\n", "the imported data will be merged with the current coverage data.\n", "

You can export data from the current analysis from the \"Result\"\n", "page.\n", "

Select the file to import here.\n", "



\n", "
\n", "Change directory:
\n", "", "\n", "
\n", "
\n", browse_import(Dir), "
"]. browse_import(Dir) -> {ok,List} = file:list_dir(Dir), Sorted = lists:reverse(lists:sort(List)), {Dirs,Files} = filter_files(Dir,Sorted,[],[]), ["
\n" "\n", "\n", "
\n" "
\n"]. filter_files(Dir,[File|Files],Ds,Fs) -> case filename:extension(File) of ".coverdata" -> Fs1 = ["\n" | Fs], filter_files(Dir,Files,Ds,Fs1); _ -> FullName = filename:join(Dir,File), case filelib:is_dir(FullName) of true -> Ds1 = ["\n" | Ds], filter_files(Dir,Files,Ds1,Fs); false -> filter_files(Dir,Files,Ds,Fs) end end; filter_files(_Dir,[],Ds,Fs) -> {Ds,Fs}. do_import(Input) -> case parse(Input) of [{"file",File0},{"dir",Dir}] -> File = filename:join(Dir,File0), case filelib:is_dir(File) of true -> import_frame1(File); false -> case filelib:is_file(File) of true -> case cover:import(File) of ok -> import_frame1(Dir); {error,{cant_open_file,ExportFile,_Reason}} -> import_frame1(Dir, "Error importing file\\n\\\"" ++ ExportFile ++ "\\\"") end; false -> import_frame1(Dir, "Error importing file\\n\\\"" ++ File ++ "\\\"") end end; [{"dir",Dir}] -> import_frame1(Dir,"No file is selected") end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % Different private helper functions % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%Create the Header for the page If we now the mimetype use that type %% %%otherwise use text %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% header() -> header("text/html"). header(MimeType) -> "Pragma:no-cache\r\n" ++ "Content-type: " ++ MimeType ++ "\r\n\r\n". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%Create the Htmlheader set the title of the page %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% html_header(Title) -> "\n" ++ "\n" ++ "" ++ Title ++ "\n" ++ "\n" "\n". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Close the body- and Html tags %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% html_end()-> "". %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% A script which reloads the menu frame and possibly pops up an alert%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% reload_menu_script(Err) -> ["\n", ""]. fix_newline([$\n|Rest]) -> [$\\,$n|fix_newline(Rest)]; fix_newline([$"|Rest]) -> [$\\,$"|fix_newline(Rest)]; fix_newline([Char|Rest]) -> [Char|fix_newline(Rest)]; fix_newline([]) -> []. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Control the input data and return the intresting values or error % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% get_input_data(Input,Key)-> case lists:keysearch(Key,1,parse(Input)) of {value,{Key,Value}} -> Value; false -> undefined end. parse(Input) -> httpd:parse_query(Input). get_warnings() -> cover_group_leader_proc ! {self(), get_warnings}, receive {warnings,Warnings} -> Warnings end.