.TH cover 3erl "tools 2.9" "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 periode, cover data from before and during this periode will be included in the analysis\&. .SH EXPORTS .LP .B start() -> {ok,Pid} | {error,Reason} .br .RS .LP Types: .RS 3 Pid = pid() .br Reason = {already_started,Pid} .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 .B start(Nodes) -> {ok,StartedNodes} | {error,not_main_node} .br .RS .LP Types: .RS 3 Nodes = StartedNodes = [atom()] .br .RE .RE .RS .LP Starts a Cover server on the each of given nodes, and loads all cover compiled modules\&. .RE .LP .B compile(ModFiles) -> Result | [Result] .br .B compile(ModFiles, Options) -> Result | [Result] .br .B compile_module(ModFiles) -> Result | [Result] .br .B compile_module(ModFiles, Options) -> Result | [Result] .br .RS .LP Types: .RS 3 ModFiles = ModFile | [ModFile] .br ModFile = Module | File .br Module = atom() .br File = string() .br Options = [Option] .br Option = {i,Dir} | {d,Macro} | {d,Macro,Value} | export_all .br .RS 2 See \fIcompile:file/2\&.\fR\& .RE Result = {ok,Module} | {error,File} | {error,not_main_node} .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 .B compile_directory() -> [Result] | {error,Reason} .br .B compile_directory(Dir) -> [Result] | {error,Reason} .br .B compile_directory(Dir, Options) -> [Result] | {error,Reason} .br .RS .LP Types: .RS 3 Dir = string() .br Options = [Option] .br .RS 2 See \fIcompile_module/1,2\fR\& .RE Result = {ok,Module} | {error,File} | {error,not_main_node} .br .RS 2 See \fIcompile_module/1,2\fR\& .RE Reason = eacces | enoent .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 .B compile_beam(ModFiles) -> Result | [Result] .br .RS .LP Types: .RS 3 ModFiles = ModFile | [ModFile] .br ModFile = Module | BeamFile .br Module = atom() .br BeamFile = string() .br Result = {ok,Module} | {error,BeamFile} | {error,Reason} .br Reason = non_existing | {no_abstract_code,BeamFile} | {encrypted_abstract_code,BeamFile} | {already_cover_compiled,no_beam_found,Module} | not_main_node .br .RE .RE .RS .LP Does the same as \fIcompile/1,2\fR\&, but uses an existing \fI\&.beam\fR\& file as base, i\&.e\&. 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\&, i\&.e\&. 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 (i\&.e\&. 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 can not 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 .B compile_beam_directory() -> [Result] | {error,Reason} .br .B compile_beam_directory(Dir) -> [Result] | {error,Reason} .br .RS .LP Types: .RS 3 Dir = string() .br Result = See compile_beam/1 .br Reason = eacces | enoent .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 .B analyse() -> {result,Ok,Fail} | {error,not_main_node} .br .B analyse(Modules) -> OneResult | {result,Ok,Fail} | {error,not_main_node} .br .B analyse(Analysis) -> {result,Ok,Fail} | {error,not_main_node} .br .B analyse(Level) -> {result,Ok,Fail} | {error,not_main_node} .br .B analyse(Modules, Analysis) -> OneResult | {result,Ok,Fail} | {error,not_main_node} .br .B analyse(Modules, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node} .br .B analyse(Analysis, Level) -> {result,Ok,Fail} | {error,not_main_node} .br .B analyse(Modules, Analysis, Level) -> OneResult | {result,Ok,Fail} | {error,not_main_node} .br .RS .LP Types: .RS 3 Modules = Module | [Module] .br Module = atom() .br Analysis = coverage | calls .br Level = line | clause | function | module .br OneResult = {ok,{Module,Value}} | {ok,[{Item,Value}]} | {error, Error} .br Item = Line | Clause | Function .br Line = {M,N} .br Clause = {M,F,A,C} .br Function = {M,F,A} .br M = F = atom() .br N = A = C = integer() .br Value = {Cov,NotCov} | Calls .br Cov = NotCov = Calls = integer() .br Error = {not_cover_compiled,Module} .br Ok = [{Module,Value}] | [{Item,Value}] .br Fail = [Error] .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 .B analyse_to_file() -> {result,Ok,Fail} | {error,not_main_node} .br .B analyse_to_file(Modules) -> Answer | {result,Ok,Fail} | {error,not_main_node} .br .B analyse_to_file(Options) -> {result,Ok,Fail} | {error,not_main_node} .br .B analyse_to_file(Modules,Options) -> Answer | {result,Ok,Fail} | {error,not_main_node} .br .RS .LP Types: .RS 3 Modules = Module | [Module] .br Module = atom() .br OutFile = OutDir = string() .br Options = [Option] .br Option = html | {outfile,OutFile} | {outdir,OutDir} .br Answer = {ok,OutFile} | {error,Error} .br Ok = [OutFile] .br Fail = [Error] .br Error = {not_cover_compiled,Module} | {file,File,Reason} | {no_source_code_found,Module} .br File = string() .br Reason = term() .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 data 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, i\&.e\&. 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 .B async_analyse_to_file(Module) -> .br .B async_analyse_to_file(Module,Options) -> .br .B async_analyse_to_file(Module, OutFile) -> .br .B async_analyse_to_file(Module, OutFile, Options) -> pid() .br .RS .LP Types: .RS 3 Module = atom() .br OutFile = string() .br Options = [Option] .br Option = html .br Error = {not_cover_compiled,Module} | {file,File,Reason} | {no_source_code_found,Module} | not_main_node .br File = string() .br Reason = term() .br .RE .RE .RS .LP This function works exactly the same way as \fBanalyse_to_file\fR\& except that it is asynchronous instead of synchronous\&. The spawned process will link with the caller when created\&. If an \fIError\fR\& occurs while doing the cover analysis the process will crash with the same error reason as \fBanalyse_to_file\fR\& would return\&. .RE .LP .B modules() -> [Module] | {error,not_main_node} .br .RS .LP Types: .RS 3 Module = atom() .br .RE .RE .RS .LP Returns a list with all modules that are currently Cover compiled\&. .RE .LP .B imported_modules() -> [Module] | {error,not_main_node} .br .RS .LP Types: .RS 3 Module = atom() .br .RE .RE .RS .LP Returns a list with all modules for which there are imported data\&. .RE .LP .B imported() -> [File] | {error,not_main_node} .br .RS .LP Types: .RS 3 File = string() .br .RE .RE .RS .LP Returns a list with all imported files\&. .RE .LP .B which_nodes() -> [Node] | {error,not_main_node} .br .RS .LP Types: .RS 3 Node = atom() .br .RE .RE .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 .B is_compiled(Module) -> {file,File} | false | {error,not_main_node} .br .RS .LP Types: .RS 3 Module = atom() .br Beam = string() .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 \fIcover:compile_module/1,2\fR\& or the \fI\&.beam\fR\& file used by \fIcompile_beam/1\fR\&\&. .RE .LP .B reset(Module) -> .br .B reset() -> ok | {error,not_main_node} .br .RS .LP Types: .RS 3 Module = atom() .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 .B export(ExportFile) .br .B export(ExportFile,Module) -> ok | {error,Reason} .br .RS .LP Types: .RS 3 ExportFile = string() .br Module = atom() .br Reason = {not_cover_compiled,Module} | {cant_open_file,ExportFile,Reason} | not_main_node .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 can not 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 \fIcover:import/1\fR\& .RE .LP .B import(ExportFile) -> ok | {error,Reason} .br .RS .LP Types: .RS 3 ExportFile = string() .br Reason = {cant_open_file,ExportFile,Reason} | not_main_node .br .RE .RE .RS .LP Imports coverage data from the file \fIExportFile\fR\& created with \fIcover:export/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 can not 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 \fIcover:export/1,2\fR\& .RE .LP .B stop() -> ok | {error,not_main_node} .br .RS .LP Stops the Cover server and unloads all Cover compiled code\&. .RE .LP .B stop(Nodes) -> ok | {error,not_main_node} .br .RS .LP Types: .RS 3 Nodes = [atom()] .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 .B flush(Nodes) -> ok | {error,not_main_node} .br .RS .LP Types: .RS 3 Nodes = [atom()] .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)