---
name: "cover"
section: "3erl"
platform: "linux"
package: "erlang-manpages"
version: "1:25.2.3+dfsg-1+deb12u4"
release: "Debian 12 (Bookworm)"
platforms: ["linux"]
url: "https://new.carta.tech/cover/3erl"
---

# cover(3erl)

A Coverage Analysis Tool for Erlang

## NAME

cover - A Coverage Analysis Tool for Erlang

## DESCRIPTION

The module *cover* provides a set of functions for coverage analysis of Erlang programs, counting how many times each *executable line* of code is executed when a program is run. \
 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 *case*- or *receive* statement is not executable.

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.

Before any analysis can take place, the involved modules must be *Cover compiled*. 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 *.beam* file is created.

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 *Answer* is determined by two parameters, *Level* and *Analysis*.

- \*

  *Level = module*

  *Answer = {Module,Value}*, where *Module* is the module name.

- \*

  *Level = function*

  *Answer = \[{Function,Value}\]*, one tuple for each function in the module. A function is specified by its module name *M*, function name *F* and arity *A* as a tuple *{M,F,A}*.

- \*

  *Level = clause*

  *Answer = \[{Clause,Value}\]*, one tuple for each clause in the module. A clause is specified by its module name *M*, function name *F*, arity *A* and position in the function definition *C* as a tuple *{M,F,A,C}*.

- \*

  *Level = line*

  *Answer = \[{Line,Value}\]*, one tuple for each executable line in the module. A line is specified by its module name *M* and line number in the source file *N* as a tuple *{M,N}*.

- \*

  *Analysis = coverage*

  *Value = {Cov,NotCov}* where *Cov* is the number of executable lines in the module, function, clause or line that have been executed at least once and *NotCov* is the number of executable lines that have not been executed.

- \*

  *Analysis = calls*

  *Value = Calls* which is the number of times the module, function, or clause has been called. In the case of line level analysis, *Calls* is the number of times the line has been executed.

*Distribution*

Cover can be used in a distributed Erlang system. One of the nodes in the system must then be selected as the *main node*, and all Cover commands must be executed from this node. The error reason *not\_main\_node* is returned if an interface function is called on one of the remote nodes.

Use *cover:start/1* and *cover:stop/1* 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.

To only collect data from remote nodes without stopping *cover* on those nodes, use *cover:flush/1*

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.

## EXPORTS

```
start() -> {ok, pid()} | {error, Reason}
```

Types:

Reason = {already\_started, pid()} \| term()\

Starts the Cover server which owns the Cover internal database. This function is called automatically by the other functions in the module.

```
local_only() -> ok | {error, too_late}
```

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.

```
start(Nodes) ->
         {ok, StartedNodes} |
         {error, not_main_node} |
         {error, local_only}
```

Types:

Nodes = node() \| \[node()\]\
 StartedNodes = \[node()\]\

Starts a Cover server on the each of given nodes, and loads all cover compiled modules. This call will fail if *cover:local\_only/0* has been called.

```
compile(ModFiles) -> Result | [Result]
```

```
compile(ModFiles, Options) -> Result | [Result]
```

```
compile_module(ModFiles) -> Result | [Result]
```

```
compile_module(ModFiles, Options) -> Result | [Result]
```

Types:

ModFiles = mod\_files()\
 Options = \[option()\]\
 Result = compile\_result()\

```
mod_files() = mod_file() | [mod_file()]
```

```
mod_file() = (Module :: module()) | (File :: file:filename())
```

```
option() =
    {i, Dir :: file:filename()} |
    {d, Macro :: atom()} |
    {d, Macro :: atom(), Value :: term()} |
    export_all
```

See *compile:file/2*.

```
compile_result() =
    {ok, Module :: module()} |
    {error, file:filename()} |
    {error, not_main_node}
```

Compiles a module for Cover analysis. The module is given by its module name *Module* or by its file name *File*. The *.erl* extension may be omitted. If the module is located in another directory, the path has to be specified.

*Options* is a list of compiler options which defaults to *\[\]*. Only options defining include file directories and macros are passed to *compile:file/2*, everything else is ignored.

If the module is successfully Cover compiled, the function returns *{ok, Module}*. Otherwise the function returns *{error, File}*. Errors and warnings are printed as they occur.

If a list of *ModFiles* is given as input, a list of *Result* will be returned. The order of the returned list is undefined.

Note that the internal database is (re-)initiated during the compilation, meaning any previously collected coverage data for the module will be lost.

```
compile_directory() -> [Result] | {error, Reason}
```

```
compile_directory(Dir) -> [Result] | {error, Reason}
```

```
compile_directory(Dir, Options) -> [Result] | {error, Reason}
```

Types:

Dir = file:filename()\
 Options = \[option()\]\
 Reason = file\_error()\
 Result = compile\_result()\

```
option() =
    {i, Dir :: file:filename()} |
    {d, Macro :: atom()} |
    {d, Macro :: atom(), Value :: term()} |
    export_all
```

See *compile:file/2*.

```
file_error() = eacces | enoent
```

```
compile_result() =
    {ok, Module :: module()} |
    {error, file:filename()} |
    {error, not_main_node}
```

Compiles all modules (*.erl* files) in a directory *Dir* for Cover analysis the same way as *compile\_module/1,2* and returns a list with the return values.

*Dir* defaults to the current working directory.

The function returns *{error, eacces}* if the directory is not readable or *{error, enoent}* if the directory does not exist.

```
compile_beam(ModFiles) -> Result | [Result]
```

Types:

ModFiles = beam\_mod\_files()\
 Result = compile\_beam\_result()\

```
beam_mod_files() = beam_mod_file() | [beam_mod_file()]
```

```
beam_mod_file() =
    (Module :: module()) | (BeamFile :: file:filename())
```

```
compile_beam_result() =
    {ok, module()} |
    {error, BeamFile :: file:filename()} |
    {error, Reason :: compile_beam_rsn()}
```

```
compile_beam_rsn() =
    non_existing |
    {no_abstract_code, BeamFile :: file:filename()} |
    {encrypted_abstract_code, BeamFile :: file:filename()} |
    {already_cover_compiled, no_beam_found, module()} |
    {{missing_backend, module()}, BeamFile :: file:filename()} |
    {no_file_attribute, BeamFile :: file:filename()} |
    not_main_node
```

Does the same as *compile/1,2*, but uses an existing *.beam* file as base, that is, the module is not compiled from source. Thus *compile\_beam/1* is faster than *compile/1,2*.

Note that the existing *.beam* file must contain *abstract code*, that is, it must have been compiled with the *debug\_info* option. If not, the error reason *{no\_abstract\_code, BeamFile}* is returned. If the abstract code is encrypted, and no key is available for decrypting it, the error reason *{encrypted\_abstract\_code, BeamFile}* is returned.

If only the module name (that is, not the full name of the *.beam* file) is given to this function, the *.beam* file is found by calling *code:which(Module)*. If no *.beam* file is found, the error reason *non\_existing* is returned. If the module is already cover compiled with *compile\_beam/1*, the *.beam* file will be picked from the same location as the first time it was compiled. If the module is already cover compiled with *compile/1,2*, there is no way to find the correct *.beam* file, so the error reason *{already\_cover\_compiled, no\_beam\_found, Module}* is returned.

*{error, BeamFile}* is returned if the compiled code cannot be loaded on the node.

If a list of *ModFiles* is given as input, a list of *Result* will be returned. The order of the returned list is undefined.

```
compile_beam_directory() -> [Result] | {error, Reason}
```

```
compile_beam_directory(Dir) -> [Result] | {error, Reason}
```

Types:

Dir = file:filename()\
 Reason = file\_error()\
 Result = compile\_beam\_result()\

```
compile_beam_result() =
    {ok, module()} |
    {error, BeamFile :: file:filename()} |
    {error, Reason :: compile_beam_rsn()}
```

```
compile_beam_rsn() =
    non_existing |
    {no_abstract_code, BeamFile :: file:filename()} |
    {encrypted_abstract_code, BeamFile :: file:filename()} |
    {already_cover_compiled, no_beam_found, module()} |
    {{missing_backend, module()}, BeamFile :: file:filename()} |
    {no_file_attribute, BeamFile :: file:filename()} |
    not_main_node
```

```
file_error() = eacces | enoent
```

Compiles all modules (*.beam* files) in a directory *Dir* for Cover analysis the same way as *compile\_beam/1* and returns a list with the return values.

*Dir* defaults to the current working directory.

The function returns *{error, eacces}* if the directory is not readable or *{error, enoent}* if the directory does not exist.

```
analyse() ->
           {result, analyse_ok(), analyse_fail()} |
           {error, not_main_node}
```

```
analyse(Analysis) ->
           {result, analyse_ok(), analyse_fail()} |
           {error, not_main_node}
```

```
analyse(Level) ->
           {result, analyse_ok(), analyse_fail()} |
           {error, not_main_node}
```

```
analyse(Modules) ->
           OneResult |
           {result, analyse_ok(), analyse_fail()} |
           {error, not_main_node}
```

```
analyse(Analysis, Level) ->
           {result, analyse_ok(), analyse_fail()} |
           {error, not_main_node}
```

```
analyse(Modules, Analysis) ->
           OneResult |
           {result, analyse_ok(), analyse_fail()} |
           {error, not_main_node}
```

```
analyse(Modules, Level) ->
           OneResult |
           {result, analyse_ok(), analyse_fail()} |
           {error, not_main_node}
```

```
analyse(Modules, Analysis, Level) ->
           OneResult |
           {result, analyse_ok(), analyse_fail()} |
           {error, not_main_node}
```

Types:

Analysis = analysis()\
 Level = level()\
 Modules = modules()\
 OneResult = one\_result()\

```
analysis() = coverage | calls
```

```
level() = line | clause | function | module
```

```
modules() = module() | [module()]
```

```
one_result() =
    {ok, {Module :: module(), Value :: analyse_value()}} |
    {ok, [{Item :: analyse_item(), Value :: analyse_value()}]} |
    {error, {not_cover_compiled, module()}}
```

```
analyse_fail() = [{not_cover_compiled, module()}]
```

```
analyse_ok() =
    [{Module :: module(), Value :: analyse_value()}] |
    [{Item :: analyse_item(), Value :: analyse_value()}]
```

```
analyse_value() =
    {Cov :: integer() >= 0, NotCov :: integer() >= 0} |
    (Calls :: integer() >= 0)
```

```
analyse_item() =
    (Line :: {M :: module(), N :: integer() >= 0}) |
    (Clause ::
         {M :: module(),
          F :: atom(),
          A :: arity(),
          C :: integer() >= 0}) |
    (Function :: {M :: module(), F :: atom(), A :: arity()})
```

Performs analysis of one or more Cover compiled modules, as specified by *Analysis* and *Level* (see above), by examining the contents of the internal database.

*Analysis* defaults to *coverage* and *Level* defaults to *function*.

If *Modules* is an atom (one module), the return will be *OneResult*, else the return will be *{result, Ok, Fail}*.

If *Modules* 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.

If a given module is not Cover compiled, this is indicated by the error reason *{not\_cover\_compiled, Module}*.

```
analyse_to_file() ->
                   {result,
                    analyse_file_ok(),
                    analyse_file_fail()} |
                   {error, not_main_node}
```

```
analyse_to_file(Modules) ->
                   Answer |
                   {result,
                    analyse_file_ok(),
                    analyse_file_fail()} |
                   {error, not_main_node}
```

```
analyse_to_file(Options) ->
                   {result,
                    analyse_file_ok(),
                    analyse_file_fail()} |
                   {error, not_main_node}
```

```
analyse_to_file(Modules, Options) ->
                   Answer |
                   {result,
                    analyse_file_ok(),
                    analyse_file_fail()} |
                   {error, not_main_node}
```

Types:

Modules = modules()\
 Options = \[analyse\_option()\]\
 Answer = analyse\_answer()\

```
modules() = module() | [module()]
```

```
analyse_option() =
    html |
    {outfile, OutFile :: file:filename()} |
    {outdir, OutDir :: file:filename()}
```

```
analyse_answer() =
    {ok, OutFile :: file:filename()} | {error, analyse_rsn()}
```

```
analyse_file_ok() = [OutFile :: file:filename()]
```

```
analyse_file_fail() = [analyse_rsn()]
```

```
analyse_rsn() =
    {not_cover_compiled, Module :: module()} |
    {file, File :: file:filename(), Reason :: term()} |
    {no_source_code_found, Module :: module()}
```

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.

The output file *OutFile* defaults to *Module.COVER.out*, or *Module.COVER.html* if the option *html* was used.

If *Modules* is an atom (one module), the return will be *Answer*, else the return will be a list, *{result, Ok, Fail}*.

If *Modules* 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.

If a module is not Cover compiled, this is indicated by the error reason *{not\_cover\_compiled, Module}*.

If the source file and/or the output file cannot be opened using *file:open/2*, the function returns *{error, {file, File, Reason}}* where *File* is the file name and *Reason* is the error reason.

If a module was cover compiled from the *.beam* file, that is, using *compile\_beam/1* or *compile\_beam\_directory/0,1*,it is assumed that the source code can be found in the same directory as the *.beam* file, in *../src* relative to that directory, or using the source path in *Module:module\_info(compile)*. When using the latter, two paths are examined: first the one constructed by joining *../src* and the tail of the compiled path below a trailing *src* component, then the compiled path itself. If no source code is found, this is indicated by the error reason *{no\_source\_code\_found, Module}*.

```
async_analyse_to_file(Module) -> pid()
```

```
async_analyse_to_file(Module, OutFile) -> pid()
```

```
async_analyse_to_file(Module, Options) -> pid()
```

```
async_analyse_to_file(Module, OutFile, Options) -> pid()
```

Types:

Module = module()\
 OutFile = file:filename()\
 Options = \[Option\]\
 Option = html\

```
analyse_rsn() =
    {not_cover_compiled, Module :: module()} |
    {file, File :: file:filename(), Reason :: term()} |
    {no_source_code_found, Module :: module()}
```

This function works exactly the same way as *analyse\_to\_file* except that it is asynchronous instead of synchronous. The spawned process will link with the caller when created. If an error of type *analyse\_rsn()* occurs while doing the cover analysis the process will crash with the same error reason as *analyse\_to\_file* would return.

```
modules() -> [module()] | {error, not_main_node}
```

Returns a list with all modules that are currently Cover compiled.

```
imported_modules() -> [module()] | {error, not_main_node}
```

Returns a list with all modules for which there are imported data.

```
imported() -> [file:filename()] | {error, not_main_node}
```

Returns a list with all imported files.

```
which_nodes() -> [node()]
```

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.

```
is_compiled(Module) ->
               {file, File :: file:filename()} |
               false |
               {error, not_main_node}
```

Types:

Module = module()\

Returns *{file, File}* if the module *Module* is Cover compiled, or *false* otherwise. *File* is the *.erl* file used by *compile\_module/1,2* or the *.beam* file used by *compile\_beam/1*.

```
reset() -> ok | {error, not_main_node}
```

```
reset(Module) ->
         ok |
         {error, not_main_node} |
         {error, {not_cover_compiled, Module}}
```

Types:

Module = module()\

Resets all coverage data for a Cover compiled module *Module* in the Cover database on all nodes. If the argument is omitted, the coverage data will be reset for all modules known by Cover.

If *Module* is not Cover compiled, the function returns *{error, {not\_cover\_compiled, Module}}*.

```
export(File) -> ok | {error, Reason}
```

```
export(File, Module) -> ok | {error, Reason}
```

Types:

File = file:filename()\
 Module = module()\
 Reason = export\_reason()\

```
export_reason() =
    {not_cover_compiled, Module :: module()} |
    {cant_open_file,
     ExportFile :: file:filename(),
     FileReason :: term()} |
    not_main_node
```

Exports the current coverage data for *Module* to the file *ExportFile*. It is recommended to name the *ExportFile* with the extension *.coverdata*, since other filenames cannot be read by the web based interface to cover.

If *Module* is not given, data for all Cover compiled or earlier imported modules is exported.

This function is useful if coverage data from different systems is to be merged.

See also *import/1*.

```
import(ExportFile) -> ok | {error, Reason}
```

Types:

ExportFile = file:filename()\
 Reason = \
\
     {cant\_open\_file, ExportFile, FileReason :: term()} \|\
\
     not\_main\_node\

Imports coverage data from the file *ExportFile* created with *export/1,2*. Any analysis performed after this will include the imported data.

Note that when compiling a module *all existing coverage data is removed*, including imported data. If a module is already compiled when data is imported, the imported data is *added* to the existing coverage data.

Coverage data from several export files can be imported into one system. The coverage data is then added up when analysing.

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.

See also *export/1,2*.

```
stop() -> ok | {error, not_main_node}
```

Stops the Cover server and unloads all Cover compiled code.

```
stop(Nodes) -> ok | {error, not_main_node}
```

Types:

Nodes = node() \| \[node()\]\

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.

```
flush(Nodes) -> ok | {error, not_main_node}
```

Types:

Nodes = node() \| \[node()\]\

Fetch data from the Cover database on the remote nodes and stored on the main node.

## SEE ALSO

[code(3erl)](/code/3erl.md), [compile(3erl)](/compile/3erl.md)
