.TH cover 3erl "tools 3.5.3" "Ericsson AB" "Erlang Module Definition" .SH NAME cover \- A Coverage Analysis Tool for Erlang .SH DESCRIPTION .LP The module \fIcover\fR\& provides a set of functions for coverage analysis of Erlang programs, counting how many times each \fIexecutable line\fR\& of code is executed when a program is run\&. .br An executable line contains an Erlang expression such as a matching or a function call\&. A blank line or a line containing a comment, function head or pattern in a \fIcase\fR\&- or \fIreceive\fR\& statement is not executable\&. .LP Coverage analysis can be used to verify test cases, making sure all relevant code is covered, and may also be helpful when looking for bottlenecks in the code\&. .LP Before any analysis can take place, the involved modules must be \fICover compiled\fR\&\&. This means that some extra information is added to the module before it is compiled into a binary which then is loaded\&. The source file of the module is not affected and no \fI\&.beam\fR\& file is created\&. .LP Each time a function in a Cover compiled module is called, information about the call is added to an internal database of Cover\&. The coverage analysis is performed by examining the contents of the Cover database\&. The output \fIAnswer\fR\& is determined by two parameters, \fILevel\fR\& and \fIAnalysis\fR\&\&. .RS 2 .TP 2 * \fILevel = module\fR\& .RS 2 .LP \fIAnswer = {Module,Value}\fR\&, where \fIModule\fR\& is the module name\&. .RE .LP .TP 2 * \fILevel = function\fR\& .RS 2 .LP \fIAnswer = [{Function,Value}]\fR\&, one tuple for each function in the module\&. A function is specified by its module name \fIM\fR\&, function name \fIF\fR\& and arity \fIA\fR\& as a tuple \fI{M,F,A}\fR\&\&. .RE .LP .TP 2 * \fILevel = clause\fR\& .RS 2 .LP \fIAnswer = [{Clause,Value}]\fR\&, one tuple for each clause in the module\&. A clause is specified by its module name \fIM\fR\&, function name \fIF\fR\&, arity \fIA\fR\& and position in the function definition \fIC\fR\& as a tuple \fI{M,F,A,C}\fR\&\&. .RE .LP .TP 2 * \fILevel = line\fR\& .RS 2 .LP \fIAnswer = [{Line,Value}]\fR\&, one tuple for each executable line in the module\&. A line is specified by its module name \fIM\fR\& and line number in the source file \fIN\fR\& as a tuple \fI{M,N}\fR\&\&. .RE .LP .TP 2 * \fIAnalysis = coverage\fR\& .RS 2 .LP \fIValue = {Cov,NotCov}\fR\& where \fICov\fR\& is the number of executable lines in the module, function, clause or line that have been executed at least once and \fINotCov\fR\& is the number of executable lines that have not been executed\&. .RE .LP .TP 2 * \fIAnalysis = calls\fR\& .RS 2 .LP \fIValue = Calls\fR\& which is the number of times the module, function, or clause has been called\&. In the case of line level analysis, \fICalls\fR\& is the number of times the line has been executed\&. .RE .LP .RE .LP \fIDistribution\fR\& .LP Cover can be used in a distributed Erlang system\&. One of the nodes in the system must then be selected as the \fImain node\fR\&, and all Cover commands must be executed from this node\&. The error reason \fInot_main_node\fR\& is returned if an interface function is called on one of the remote nodes\&. .LP Use \fIcover:start/1\fR\& and \fIcover:stop/1\fR\& to add or remove nodes\&. The same Cover compiled code will be loaded on each node, and analysis will collect and sum up coverage data results from all nodes\&. .LP To only collect data from remote nodes without stopping \fIcover\fR\& on those nodes, use \fIcover:flush/1\fR\& .LP If the connection to a remote node goes down, the main node will mark it as lost\&. If the node comes back it will be added again\&. If the remote node was alive during the disconnected period, cover data from before and during this period will be included in the analysis\&. .SH EXPORTS .LP .nf .B start() -> {ok, pid()} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Reason = {already_started, pid()} | term() .br .RE .RE .RS .LP Starts the Cover server which owns the Cover internal database\&. This function is called automatically by the other functions in the module\&. .RE .LP .nf .B local_only() -> ok | {error, too_late} .br .fi .br .RS .LP Only support running Cover on the local node\&. This function must be called before any modules have been compiled or any nodes added\&. When running in this mode, modules will be Cover compiled in a more efficient way, but the resulting code will only work on the same node they were compiled on\&. .RE .LP .nf .B start(Nodes) -> .B {ok, StartedNodes} | .B {error, not_main_node} | .B {error, local_only} .br .fi .br .RS .LP Types: .RS 3 Nodes = node() | [node()] .br StartedNodes = [node()] .br .RE .RE .RS .LP Starts a Cover server on the each of given nodes, and loads all cover compiled modules\&. This call will fail if \fIcover:local_only/0\fR\& has been called\&. .RE .LP .nf .B compile(ModFiles) -> Result | [Result] .br .fi .br .nf .B compile(ModFiles, Options) -> Result | [Result] .br .fi .br .nf .B compile_module(ModFiles) -> Result | [Result] .br .fi .br .nf .B compile_module(ModFiles, Options) -> Result | [Result] .br .fi .br .RS .LP Types: .RS 3 ModFiles = mod_files() .br Options = [option()] .br Result = compile_result() .br .nf \fBmod_files()\fR\& = mod_file() | [mod_file()] .fi .br .nf \fBmod_file()\fR\& = (Module :: module()) | (File :: file:filename()) .fi .br .nf \fBoption()\fR\& = .br {i, Dir :: file:filename()} | .br {d, Macro :: atom()} | .br {d, Macro :: atom(), Value :: term()} | .br export_all .fi .br .RS 2 See \fIcompile:file/2\fR\&\&. .RE .nf \fBcompile_result()\fR\& = .br {ok, Module :: module()} | .br {error, file:filename()} | .br {error, not_main_node} .fi .br .RE .RE .RS .LP Compiles a module for Cover analysis\&. The module is given by its module name \fIModule\fR\& or by its file name \fIFile\fR\&\&. The \fI\&.erl\fR\& extension may be omitted\&. If the module is located in another directory, the path has to be specified\&. .LP \fIOptions\fR\& is a list of compiler options which defaults to \fI[]\fR\&\&. Only options defining include file directories and macros are passed to \fIcompile:file/2\fR\&, everything else is ignored\&. .LP If the module is successfully Cover compiled, the function returns \fI{ok, Module}\fR\&\&. Otherwise the function returns \fI{error, File}\fR\&\&. Errors and warnings are printed as they occur\&. .LP If a list of \fIModFiles\fR\& is given as input, a list of \fIResult\fR\& will be returned\&. The order of the returned list is undefined\&. .LP Note that the internal database is (re-)initiated during the compilation, meaning any previously collected coverage data for the module will be lost\&. .RE .LP .nf .B compile_directory() -> [Result] | {error, Reason} .br .fi .br .nf .B compile_directory(Dir) -> [Result] | {error, Reason} .br .fi .br .nf .B compile_directory(Dir, Options) -> [Result] | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Dir = file:filename() .br Options = [option()] .br Reason = file_error() .br Result = compile_result() .br .nf \fBoption()\fR\& = .br {i, Dir :: file:filename()} | .br {d, Macro :: atom()} | .br {d, Macro :: atom(), Value :: term()} | .br export_all .fi .br .RS 2 See \fIcompile:file/2\fR\&\&. .RE .nf \fBfile_error()\fR\& = eacces | enoent .fi .br .nf \fBcompile_result()\fR\& = .br {ok, Module :: module()} | .br {error, file:filename()} | .br {error, not_main_node} .fi .br .RE .RE .RS .LP Compiles all modules (\fI\&.erl\fR\& files) in a directory \fIDir\fR\& for Cover analysis the same way as \fIcompile_module/1,2\fR\& and returns a list with the return values\&. .LP \fIDir\fR\& defaults to the current working directory\&. .LP The function returns \fI{error, eacces}\fR\& if the directory is not readable or \fI{error, enoent}\fR\& if the directory does not exist\&. .RE .LP .nf .B compile_beam(ModFiles) -> Result | [Result] .br .fi .br .RS .LP Types: .RS 3 ModFiles = beam_mod_files() .br Result = compile_beam_result() .br .nf \fBbeam_mod_files()\fR\& = beam_mod_file() | [beam_mod_file()] .fi .br .nf \fBbeam_mod_file()\fR\& = .br (Module :: module()) | (BeamFile :: file:filename()) .fi .br .nf \fBcompile_beam_result()\fR\& = .br {ok, module()} | .br {error, BeamFile :: file:filename()} | .br {error, Reason :: compile_beam_rsn()} .fi .br .nf \fBcompile_beam_rsn()\fR\& = .br non_existing | .br {no_abstract_code, BeamFile :: file:filename()} | .br {encrypted_abstract_code, BeamFile :: file:filename()} | .br {already_cover_compiled, no_beam_found, module()} | .br {{missing_backend, module()}, BeamFile :: file:filename()} | .br {no_file_attribute, BeamFile :: file:filename()} | .br not_main_node .fi .br .RE .RE .RS .LP Does the same as \fIcompile/1,2\fR\&, but uses an existing \fI\&.beam\fR\& file as base, that is, the module is not compiled from source\&. Thus \fIcompile_beam/1\fR\& is faster than \fIcompile/1,2\fR\&\&. .LP Note that the existing \fI\&.beam\fR\& file must contain \fIabstract code\fR\&, that is, it must have been compiled with the \fIdebug_info\fR\& option\&. If not, the error reason \fI{no_abstract_code, BeamFile}\fR\& is returned\&. If the abstract code is encrypted, and no key is available for decrypting it, the error reason \fI{encrypted_abstract_code, BeamFile}\fR\& is returned\&. .LP If only the module name (that is, not the full name of the \fI\&.beam\fR\& file) is given to this function, the \fI\&.beam\fR\& file is found by calling \fIcode:which(Module)\fR\&\&. If no \fI\&.beam\fR\& file is found, the error reason \fInon_existing\fR\& is returned\&. If the module is already cover compiled with \fIcompile_beam/1\fR\&, the \fI\&.beam\fR\& file will be picked from the same location as the first time it was compiled\&. If the module is already cover compiled with \fIcompile/1,2\fR\&, there is no way to find the correct \fI\&.beam\fR\& file, so the error reason \fI{already_cover_compiled, no_beam_found, Module}\fR\& is returned\&. .LP \fI{error, BeamFile}\fR\& is returned if the compiled code cannot be loaded on the node\&. .LP If a list of \fIModFiles\fR\& is given as input, a list of \fIResult\fR\& will be returned\&. The order of the returned list is undefined\&. .RE .LP .nf .B compile_beam_directory() -> [Result] | {error, Reason} .br .fi .br .nf .B compile_beam_directory(Dir) -> [Result] | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Dir = file:filename() .br Reason = file_error() .br Result = compile_beam_result() .br .nf \fBcompile_beam_result()\fR\& = .br {ok, module()} | .br {error, BeamFile :: file:filename()} | .br {error, Reason :: compile_beam_rsn()} .fi .br .nf \fBcompile_beam_rsn()\fR\& = .br non_existing | .br {no_abstract_code, BeamFile :: file:filename()} | .br {encrypted_abstract_code, BeamFile :: file:filename()} | .br {already_cover_compiled, no_beam_found, module()} | .br {{missing_backend, module()}, BeamFile :: file:filename()} | .br {no_file_attribute, BeamFile :: file:filename()} | .br not_main_node .fi .br .nf \fBfile_error()\fR\& = eacces | enoent .fi .br .RE .RE .RS .LP Compiles all modules (\fI\&.beam\fR\& files) in a directory \fIDir\fR\& for Cover analysis the same way as \fIcompile_beam/1\fR\& and returns a list with the return values\&. .LP \fIDir\fR\& defaults to the current working directory\&. .LP The function returns \fI{error, eacces}\fR\& if the directory is not readable or \fI{error, enoent}\fR\& if the directory does not exist\&. .RE .LP .nf .B analyse() -> .B {result, analyse_ok(), analyse_fail()} | .B {error, not_main_node} .br .fi .br .nf .B analyse(Analysis) -> .B {result, analyse_ok(), analyse_fail()} | .B {error, not_main_node} .br .fi .br .nf .B analyse(Level) -> .B {result, analyse_ok(), analyse_fail()} | .B {error, not_main_node} .br .fi .br .nf .B analyse(Modules) -> .B OneResult | .B {result, analyse_ok(), analyse_fail()} | .B {error, not_main_node} .br .fi .br .nf .B analyse(Analysis, Level) -> .B {result, analyse_ok(), analyse_fail()} | .B {error, not_main_node} .br .fi .br .nf .B analyse(Modules, Analysis) -> .B OneResult | .B {result, analyse_ok(), analyse_fail()} | .B {error, not_main_node} .br .fi .br .nf .B analyse(Modules, Level) -> .B OneResult | .B {result, analyse_ok(), analyse_fail()} | .B {error, not_main_node} .br .fi .br .nf .B analyse(Modules, Analysis, Level) -> .B OneResult | .B {result, analyse_ok(), analyse_fail()} | .B {error, not_main_node} .br .fi .br .RS .LP Types: .RS 3 Analysis = analysis() .br Level = level() .br Modules = modules() .br OneResult = one_result() .br .nf \fBanalysis()\fR\& = coverage | calls .fi .br .nf \fBlevel()\fR\& = line | clause | function | module .fi .br .nf \fBmodules()\fR\& = module() | [module()] .fi .br .nf \fBone_result()\fR\& = .br {ok, {Module :: module(), Value :: analyse_value()}} | .br {ok, [{Item :: analyse_item(), Value :: analyse_value()}]} | .br {error, {not_cover_compiled, module()}} .fi .br .nf \fBanalyse_fail()\fR\& = [{not_cover_compiled, module()}] .fi .br .nf \fBanalyse_ok()\fR\& = .br [{Module :: module(), Value :: analyse_value()}] | .br [{Item :: analyse_item(), Value :: analyse_value()}] .fi .br .nf \fBanalyse_value()\fR\& = .br {Cov :: integer() >= 0, NotCov :: integer() >= 0} | .br (Calls :: integer() >= 0) .fi .br .nf \fBanalyse_item()\fR\& = .br (Line :: {M :: module(), N :: integer() >= 0}) | .br (Clause :: .br {M :: module(), .br F :: atom(), .br A :: arity(), .br C :: integer() >= 0}) | .br (Function :: {M :: module(), F :: atom(), A :: arity()}) .fi .br .RE .RE .RS .LP Performs analysis of one or more Cover compiled modules, as specified by \fIAnalysis\fR\& and \fILevel\fR\& (see above), by examining the contents of the internal database\&. .LP \fIAnalysis\fR\& defaults to \fIcoverage\fR\& and \fILevel\fR\& defaults to \fIfunction\fR\&\&. .LP If \fIModules\fR\& is an atom (one module), the return will be \fIOneResult\fR\&, else the return will be \fI{result, Ok, Fail}\fR\&\&. .LP If \fIModules\fR\& is not given, all modules that have data in the cover data table, are analysed\&. Note that this includes both cover compiled modules and imported modules\&. .LP If a given module is not Cover compiled, this is indicated by the error reason \fI{not_cover_compiled, Module}\fR\&\&. .RE .LP .nf .B analyse_to_file() -> .B {result, .B analyse_file_ok(), .B analyse_file_fail()} | .B {error, not_main_node} .br .fi .br .nf .B analyse_to_file(Modules) -> .B Answer | .B {result, .B analyse_file_ok(), .B analyse_file_fail()} | .B {error, not_main_node} .br .fi .br .nf .B analyse_to_file(Options) -> .B {result, .B analyse_file_ok(), .B analyse_file_fail()} | .B {error, not_main_node} .br .fi .br .nf .B analyse_to_file(Modules, Options) -> .B Answer | .B {result, .B analyse_file_ok(), .B analyse_file_fail()} | .B {error, not_main_node} .br .fi .br .RS .LP Types: .RS 3 Modules = modules() .br Options = [analyse_option()] .br Answer = analyse_answer() .br .nf \fBmodules()\fR\& = module() | [module()] .fi .br .nf \fBanalyse_option()\fR\& = .br html | .br {outfile, OutFile :: file:filename()} | .br {outdir, OutDir :: file:filename()} .fi .br .nf \fBanalyse_answer()\fR\& = .br {ok, OutFile :: file:filename()} | {error, analyse_rsn()} .fi .br .nf \fBanalyse_file_ok()\fR\& = [OutFile :: file:filename()] .fi .br .nf \fBanalyse_file_fail()\fR\& = [analyse_rsn()] .fi .br .nf \fBanalyse_rsn()\fR\& = .br {not_cover_compiled, Module :: module()} | .br {file, File :: file:filename(), Reason :: term()} | .br {no_source_code_found, Module :: module()} .fi .br .RE .RE .RS .LP Makes copies of the source file for the given modules, where it for each executable line is specified how many times it has been executed\&. .LP The output file \fIOutFile\fR\& defaults to \fIModule\&.COVER\&.out\fR\&, or \fIModule\&.COVER\&.html\fR\& if the option \fIhtml\fR\& was used\&. .LP If \fIModules\fR\& is an atom (one module), the return will be \fIAnswer\fR\&, else the return will be a list, \fI{result, Ok, Fail}\fR\&\&. .LP If \fIModules\fR\& is not given, all modules that have da ta in the cover data table, are analysed\&. Note that this includes both cover compiled modules and imported modules\&. .LP If a module is not Cover compiled, this is indicated by the error reason \fI{not_cover_compiled, Module}\fR\&\&. .LP If the source file and/or the output file cannot be opened using \fIfile:open/2\fR\&, the function returns \fI{error, {file, File, Reason}}\fR\& where \fIFile\fR\& is the file name and \fIReason\fR\& is the error reason\&. .LP If a module was cover compiled from the \fI\&.beam\fR\& file, that is, using \fIcompile_beam/1\fR\& or \fIcompile_beam_directory/0,1\fR\&,it is assumed that the source code can be found in the same directory as the \fI\&.beam\fR\& file, in \fI\&.\&./src\fR\& relative to that directory, or using the source path in \fIModule:module_info(compile)\fR\&\&. When using the latter, two paths are examined: first the one constructed by joining \fI\&.\&./src\fR\& and the tail of the compiled path below a trailing \fIsrc\fR\& component, then the compiled path itself\&. If no source code is found, this is indicated by the error reason \fI{no_source_code_found, Module}\fR\&\&. .RE .LP .nf .B async_analyse_to_file(Module) -> pid() .br .fi .br .nf .B async_analyse_to_file(Module, OutFile) -> pid() .br .fi .br .nf .B async_analyse_to_file(Module, Options) -> pid() .br .fi .br .nf .B async_analyse_to_file(Module, OutFile, Options) -> pid() .br .fi .br .RS .LP Types: .RS 3 Module = module() .br OutFile = file:filename() .br Options = [Option] .br Option = html .br .nf \fBanalyse_rsn()\fR\& = .br {not_cover_compiled, Module :: module()} | .br {file, File :: file:filename(), Reason :: term()} | .br {no_source_code_found, Module :: module()} .fi .br .RE .RE .RS .LP This function works exactly the same way as \fIanalyse_to_file\fR\& except that it is asynchronous instead of synchronous\&. The spawned process will link with the caller when created\&. If an error of type \fIanalyse_rsn()\fR\& occurs while doing the cover analysis the process will crash with the same error reason as \fIanalyse_to_file\fR\& would return\&. .RE .LP .nf .B modules() -> [module()] | {error, not_main_node} .br .fi .br .RS .LP Returns a list with all modules that are currently Cover compiled\&. .RE .LP .nf .B imported_modules() -> [module()] | {error, not_main_node} .br .fi .br .RS .LP Returns a list with all modules for which there are imported data\&. .RE .LP .nf .B imported() -> [file:filename()] | {error, not_main_node} .br .fi .br .RS .LP Returns a list with all imported files\&. .RE .LP .nf .B which_nodes() -> [node()] .br .fi .br .RS .LP Returns a list with all nodes that are part of the coverage analysis\&. Note that the current node is not returned\&. This node is always part of the analysis\&. .RE .LP .nf .B is_compiled(Module) -> .B {file, File :: file:filename()} | .B false | .B {error, not_main_node} .br .fi .br .RS .LP Types: .RS 3 Module = module() .br .RE .RE .RS .LP Returns \fI{file, File}\fR\& if the module \fIModule\fR\& is Cover compiled, or \fIfalse\fR\& otherwise\&. \fIFile\fR\& is the \fI\&.erl\fR\& file used by \fIcompile_module/1,2\fR\& or the \fI\&.beam\fR\& file used by \fIcompile_beam/1\fR\&\&. .RE .LP .nf .B reset() -> ok | {error, not_main_node} .br .fi .br .nf .B reset(Module) -> .B ok | .B {error, not_main_node} | .B {error, {not_cover_compiled, Module}} .br .fi .br .RS .LP Types: .RS 3 Module = module() .br .RE .RE .RS .LP Resets all coverage data for a Cover compiled module \fIModule\fR\& in the Cover database on all nodes\&. If the argument is omitted, the coverage data will be reset for all modules known by Cover\&. .LP If \fIModule\fR\& is not Cover compiled, the function returns \fI{error, {not_cover_compiled, Module}}\fR\&\&. .RE .LP .nf .B export(File) -> ok | {error, Reason} .br .fi .br .nf .B export(File, Module) -> ok | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 File = file:filename() .br Module = module() .br Reason = export_reason() .br .nf \fBexport_reason()\fR\& = .br {not_cover_compiled, Module :: module()} | .br {cant_open_file, .br ExportFile :: file:filename(), .br FileReason :: term()} | .br not_main_node .fi .br .RE .RE .RS .LP Exports the current coverage data for \fIModule\fR\& to the file \fIExportFile\fR\&\&. It is recommended to name the \fIExportFile\fR\& with the extension \fI\&.coverdata\fR\&, since other filenames cannot be read by the web based interface to cover\&. .LP If \fIModule\fR\& is not given, data for all Cover compiled or earlier imported modules is exported\&. .LP This function is useful if coverage data from different systems is to be merged\&. .LP See also \fIimport/1\fR\&\&. .RE .LP .nf .B import(ExportFile) -> ok | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 ExportFile = file:filename() .br Reason = .br {cant_open_file, ExportFile, FileReason :: term()} | .br not_main_node .br .RE .RE .RS .LP Imports coverage data from the file \fIExportFile\fR\& created with \fIexport/1,2\fR\&\&. Any analysis performed after this will include the imported data\&. .LP Note that when compiling a module \fIall existing coverage data is removed\fR\&, including imported data\&. If a module is already compiled when data is imported, the imported data is \fIadded\fR\& to the existing coverage data\&. .LP Coverage data from several export files can be imported into one system\&. The coverage data is then added up when analysing\&. .LP Coverage data for a module cannot be imported from the same file twice unless the module is first reset or compiled\&. The check is based on the filename, so you can easily fool the system by renaming your export file\&. .LP See also \fIexport/1,2\fR\&\&. .RE .LP .nf .B stop() -> ok | {error, not_main_node} .br .fi .br .RS .LP Stops the Cover server and unloads all Cover compiled code\&. .RE .LP .nf .B stop(Nodes) -> ok | {error, not_main_node} .br .fi .br .RS .LP Types: .RS 3 Nodes = node() | [node()] .br .RE .RE .RS .LP Stops the Cover server and unloads all Cover compiled code on the given nodes\&. Data stored in the Cover database on the remote nodes is fetched and stored on the main node\&. .RE .LP .nf .B flush(Nodes) -> ok | {error, not_main_node} .br .fi .br .RS .LP Types: .RS 3 Nodes = node() | [node()] .br .RE .RE .RS .LP Fetch data from the Cover database on the remote nodes and stored on the main node\&. .RE .SH "SEE ALSO" .LP code(3erl), compile(3erl)