Package 'covr'

Title: Test Coverage for Packages
Description: Track and report code coverage for your package and (optionally) upload the results to a coverage service like 'Codecov' <https://about.codecov.io> or 'Coveralls' <https://coveralls.io>. Code coverage is a measure of the amount of code being exercised by a set of tests. It is an indirect measure of test quality and completeness. This package is compatible with any testing methodology or framework and tracks coverage of both R code and compiled C, C++, Fortran and Rust code.
Authors: Jim Hester [aut, cre], Willem Ligtenberg [ctb], Kirill Müller [ctb], Henrik Bengtsson [ctb], Steve Peak [ctb], Kirill Sevastyanenko [ctb], Jon Clayden [ctb], Robert Flight [ctb], Eric Brown [ctb], Brodie Gaslam [ctb], Will Beasley [ctb], Robert Krzyzanowski [ctb], Markus Wamser [ctb], Karl Forner [ctb], Gergely Daróczi [ctb], Jouni Helske [ctb], Kun Ren [ctb], Jeroen Ooms [ctb], Ken Williams [ctb], Chris Campbell [ctb], David Hugh-Jones [ctb], Qin Wang [ctb], Doug Kelkhoff [ctb], Ivan Sagalaev [ctb, cph] (highlight.js library)
Maintainer: Jim Hester <[email protected]>
License: MIT + file LICENSE
Version: 3.6.5.9002
Built: 2026-11-11 22:11:22 UTC
Source: https://github.com/r-lib/covr

Help Index


covr: Test coverage for packages

Description

covr tracks and reports code coverage for your package and (optionally) upload the results to a coverage service like 'Codecov' https://about.codecov.io or 'Coveralls' https://coveralls.io. Code coverage is a measure of the amount of code being exercised by a set of tests. It is an indirect measure of test quality and completeness. This package is compatible with any testing methodology or framework and tracks coverage of both R code and compiled C, C++, Fortran and Rust code.

Details

A coverage report can be used to inspect coverage for each line in your package. Using report() requires the additional dependency htmltools.

# If run with no arguments `report()` implicitly calls `package_coverage()`
report()

Package options

covr uses the following options() to configure behaviour:

  • covr.branch_coverage: If TRUE (default FALSE), also record which branches of each if and switch() in R code were taken. This is experimental. It must be set before the code is instrumented, e.g. before calling package_coverage(). For more details, see ?covr.branch_coverage.

  • covr.covrignore: A filename to use as an ignore file, listing glob-style wildcarded paths of files to ignore for coverage calculations. Defaults to the value of environment variable COVR_COVRIGNORE, or ".covrignore" if the neither the option nor the environment variable are set.

  • covr.exclude_end: Used along with covr.exclude_start, an optional regular expression which ends a line-exclusion region. For more details, see ?exclusions.

  • covr.exclude_pattern: An optional line-exclusion pattern. Lines which match the pattern will be excluded from coverage. For more details, see ?exclusions.

  • covr.exclude_start: Used along with covr.exclude_end, an optional regular expression which starts a line-exclusion region. For more details, see ?exclusions.

  • covr.filter_non_package: If TRUE (the default behavior), coverage of files outside the target package are filtered from coverage output.

  • covr.failure_lines: The number of trailing lines of test output shown in the message and print() method of a covr_error when tests, vignettes, examples or code fail (default 50). The full output is always available in the condition's ⁠$output⁠ field.

  • covr.annotate_max_lines: The maximum number of source lines shown by annotate_coverage() (default 200), the default of its max_lines argument. Inf shows everything.

  • covr.print_max_ranges: The maximum number of missed ranges, and of missed branches, listed per file or function by print(x, missing = TRUE) (default 10). More are summarised as ⁠... (<k> more)⁠. Inf lists them all.

  • covr.fix_parallel_mcexit: Whether to include code run in processes forked by parallel's mclapply(), mcparallel() and related functions, by patching parallel:::mcexit. By default package_coverage() does this if the package uses parallel, and the functions that measure coverage in the current session, such as file_coverage(), always do. The environment variable COVR_FIX_PARALLEL_MCEXIT takes precedence over this option. Not supported on Windows.

  • covr.flags:

  • covr.gcov: Path to the gcov executable. Defaults to the gcov found on your PATH, or NA if there is none. If the appropriate gcov version is not on your path you can use this option to set the appropriate location. If set to "" it will turn off coverage of compiled code. If NA, covr throws an error if any compiled coverage files (.gcno) exist.

  • covr.gcov_additional_paths:

  • covr.gcov_args:

  • covr.gcov_partial: How to count compiled code lines that gcov reports as only partially executed (e.g. if (x) f(); when f() never runs). "covered" (the default) counts them as covered, "uncovered" counts them as not covered, for requiring every part of a line to run. This works with both gcc's gcov and llvm-cov (the gcov on macOS). llvm-cov can't tell apart code that only runs when a C++ exception is thrown, so lines that create objects with destructors may also count as partially executed.

  • covr.llvm_cov: Path to the llvm-cov used to read the coverage of Rust code. Defaults to the one of the Rust toolchain, installed with ⁠rustup component add llvm-tools⁠, or for Rust installed without rustup (e.g. with ⁠apt-get install cargo rustc⁠), to the one on the PATH with the same LLVM version as rustc, e.g. llvm-cov-18. If set to "" the Rust code isn't instrumented, which turns off its coverage.

  • covr.llvm_profdata: Path to the llvm-profdata used to merge the coverage counts of Rust code. Found like covr.llvm_cov.

  • covr.report_colors: A named character vector with the colors of covered and missed lines in report() and file_report(), and of the coverage percentages printed in the console, e.g. c(covered = "#0072B2", missed = "#D55E00"). colorblind_palette has colors that are easier to tell apart than the default green and red with color vision deficiency. Either element can be left out to keep its default. An optional partial element sets the color of partial coverage (at least 75% but less than 90%), which otherwise follows covered, or is yellow in the console if covered isn't set either, and of lines with a branch that wasn't taken in reports with branch coverage, which are otherwise yellow. Transparency is ignored. In terminals with only 8 colors, the console uses the closest of those colors.

  • covr.rstudio_source_markers: A logical value. If TRUE (the default behavior), source markers are displayed within the RStudio IDE when using zero_coverage.

  • covr.record_tests: If TRUE (default NULL), record a listing of top level test expressions and associate tests with covr traces evaluated during the test's execution. For more details, see ?covr.record_tests.

  • covr.full_traversal: If TRUE (default FALSE), also trace functions nested inside lists and environments, such as fns <- list(a = function(x) x) or functions defined inside local(). This walks every object in the package, so it is off by default. For package_coverage() it can also be enabled for a package by adding Config/covr/full_traversal: true to its DESCRIPTION; the option takes precedence when set.

  • covr.install_instrument: If FALSE (default TRUE, or the value of the environment variable COVR_INSTALL_INSTRUMENT), package_coverage() installs a package as usual and instruments it each time a process loads it, rather than once after installing it.

  • covr.showCfunctions:

Author(s)

Maintainer: Jim Hester [email protected]

Authors:

Other contributors:

  • Willem Ligtenberg [contributor]

  • Kirill Müller [contributor]

  • Henrik Bengtsson [contributor]

  • Steve Peak [contributor]

  • Kirill Sevastyanenko [contributor]

  • Jon Clayden [contributor]

  • Robert Flight [contributor]

  • Eric Brown [contributor]

  • Brodie Gaslam [contributor]

  • Will Beasley [contributor]

  • Robert Krzyzanowski [contributor]

  • Markus Wamser [contributor]

  • Karl Forner [contributor]

  • Gergely Daróczi [contributor]

  • Jouni Helske [contributor]

  • Kun Ren [contributor]

  • Jeroen Ooms [contributor]

  • Ken Williams [contributor]

  • Chris Campbell [contributor]

  • David Hugh-Jones [contributor]

  • Qin Wang [contributor]

  • Doug Kelkhoff [contributor]

  • Ivan Sagalaev (highlight.js library) [contributor, copyright holder]

See Also

Useful links:


Annotate source code with line and branch coverage

Description

Produces plain text showing source lines together with their coverage counts, in a form that is easy to read in a terminal or to paste into a prompt. By default the missed lines are shown with context surrounding lines.

Usage

annotate_coverage(
  x,
  lines = NULL,
  context = 2,
  files = NULL,
  max_lines = getOption("covr.annotate_max_lines", 200)
)

Arguments

x

A coverage object, e.g. from package_coverage() or code_coverage().

lines

A data frame with filename and line columns identifying the lines to show, e.g. the result of zero_coverage() or the lines changed in a pull request. Other columns are ignored. The default is all missed code lines in x, and the lines with a missed branch if branch coverage was measured.

context

Number of lines to show before and after each line in lines. Use Inf to show whole files.

files

Optional character vector of file names (as they appear in the coverage, e.g. "R/foo.R") to restrict the output to.

max_lines

The maximum number of source lines to show, 200 by default (option covr.annotate_max_lines). Whole chunks of lines are added until the next one would go over the limit, but the first chunk is always shown. If anything is left out, the last line says how many of the missed or requested lines in how many files are not shown. Use Inf for no limit.

Details

Each shown line has the line number, a count column and the source. Missed lines are marked !!0, covered code lines show their hit count, and lines without coverage data (blank lines, comments, ...) have an empty count. Non-adjacent chunks are separated by ....

If branch coverage was measured (see covr.branch_coverage), lines with a branch that was not taken are also shown by default, followed by ⁠<- not taken:⁠ and the labels of their missed branches. Only if and switch() calls that were evaluated count; the others are covered by the missed lines. Such a line keeps its count if it was run.

Value

A character vector of class covr_annotation, with one element per output line. If there is nothing to show it is "No missed lines.".

Examples

source <- "
f <- function(x) {
  if (x) {
    'yes'
  } else {
    'no'
  }
}
"
cov <- code_coverage(source, "f(TRUE)")
annotate_coverage(cov)
annotate_coverage(cov, context = Inf)

Convert a counters object to a coverage object

Description

Convert a counters object to a coverage object

Usage

as_coverage(counters, ...)

Arguments

counters

An environment of covr trace results to convert to a coverage object.

...

Additional attributes to include with the coverage object.


Clean and restructure counter tests for a coverage object

Description

For tests produced with options(covr.record_tests), prune any unused records in the $tests$tally matrices of each trace and get rid of the wrapping $tests environment (reassigning with value of $tests$tally)

Usage

as_coverage_with_tests(counters)

Arguments

counters

An environment of covr trace results to convert to a coverage object.


Convert a coverage object to a data frame

Description

Convert a coverage object to a data frame

Usage

## S3 method for class 'coverage'
as.data.frame(x, row.names = NULL, optional = FALSE, sort = TRUE, ...)

Arguments

x

a coverage object.

row.names, optional

ignored, for compatibility with base::as.data.frame().

sort

if TRUE (the default), sum the counts of identical expressions and sort the rows by file and position. If FALSE, there is one row for each element of x, in the same order.

...

ignored.

Value

A data frame with one row for each traced expression of R code and each line of compiled code, and the columns:

  • filename: the source file, relative to the root attribute of x (the package directory, for package_coverage()) if there is one.

  • functions: the name of the function containing the expression, or NA for compiled code.

  • first_line, last_line: the lines the expression starts and ends on.

  • first_byte, last_byte: the bytes of those lines the expression starts and ends at.

  • first_column, last_column: the columns the expression starts and ends at. These differ from the bytes when the line contains multibyte characters.

  • first_parsed, last_parsed: the lines as seen by the parser. These differ from first_line and last_line when the source uses ⁠#line⁠ directives.

  • value: the number of times the expression was executed.

Use tally_coverage() for one row for each line instead.

Examples

cov <- code_coverage("add <- function(x, y) { x + y }", "add(1, 2)")
as.data.frame(cov)

Run covr on a package and output the result so it is available on Azure Pipelines

Description

Deprecated. Use cobertura(), which this function calls, instead.

Usage

azure(
  ...,
  coverage = package_coverage(..., quiet = quiet),
  filename = "coverage.xml",
  quiet = TRUE
)

Arguments

...

arguments passed to package_coverage()

coverage

an existing coverage object to submit, if NULL, package_coverage() will be called with the arguments from ...

filename

the name of the Cobertura XML file

quiet

if FALSE, print the coverage before submission.


Create a coverage badge

Description

Write an SVG badge showing the percent coverage, in the style of the badges made by Codecov and shields.io, so a README can show the coverage of a package without uploading it to a coverage service. The badge is made locally and doesn't need a network connection.

Usage

badge(cov, filename = "coverage.svg", label = "coverage")

Arguments

cov

the coverage object returned from package_coverage()

filename

the name of the SVG file

label

the text on the left side of the badge

Details

The coverage is that of percent_coverage(), rounded down to a whole percent so that only fully covered code shows 100%. The badge is green for coverage of 90% or more, yellow for 75% or more and red below that, the same thresholds used by report(). Coverage without any lines of code, such as that of a package with no R code, shows as unknown on a gray badge.

The badge is a plain file, so on a continuous integration service it needs to be stored somewhere that the README can link to, e.g. committed to a separate branch of the repository. system.file("workflows", "test-coverage-badge.yaml", package = "covr") is a GitHub Actions workflow that does this.

Value

The lines of the SVG file, invisibly.

Examples

cov <- code_coverage(
  "f <- function(x) {\n  y <- x + 1\n  if (y > 0) {\n    'yes'\n  } else {\n    'no'\n  }\n}",
  "f(1)"
)
tmp <- tempfile(fileext = ".svg")
badge(cov, tmp)
cat(readLines(tmp), sep = "\n")

Combine coverage objects

Description

Combine the coverage of several runs, e.g. of tests in different directories, into a single coverage object. The counts of traces present in more than one object are added, and traces only in some of the objects are appended. Tests recorded with options(covr.record_tests = TRUE) are combined as well.

Usage

## S3 method for class 'coverage'
c(...)

Arguments

...

Coverage objects, e.g. from package_coverage() or file_coverage(). They must all be for the same package, or all have no package, like the results of file_coverage() and code_coverage(). NULL arguments are dropped.

Details

The result keeps the attributes of the first object, such as the package and root used for relative paths, except that the lines excluded from line coverage are the union of the excluded lines of all objects. As with package_coverage(type = c("tests", "examples")), the result only has a type if all objects have the same type.

As with any S3 method for c(), this method is only used when the first argument is a coverage object.

Value

A coverage object.

Examples

source_file <- tempfile(fileext = ".R")
writeLines(
  c(
    "add <- function(x, y) {",
    "  x + y",
    "}",
    "subtract <- function(x, y) {",
    "  x - y",
    "}"
  ),
  source_file
)
add_test <- tempfile(fileext = ".R")
writeLines("add(1, 2)", add_test)
subtract_test <- tempfile(fileext = ".R")
writeLines("subtract(2, 1)", subtract_test)

add_cov <- file_coverage(source_file, add_test)
subtract_cov <- file_coverage(source_file, subtract_test)
percent_coverage(add_cov)
percent_coverage(c(add_cov, subtract_cov))

Create a Cobertura XML file

Description

Create a cobertura-compliant XML report following this DTD. Because there are two DTDs called ⁠coverage-04.dtd⁠ and some tools do not seem to adhere to either of them, the parser you're using may balk at the file. Please see this github discussion for context. Where covr doesn't provide a coverage metric (complexity), a zero is reported.

Usage

cobertura(cov, filename = "cobertura.xml")

Arguments

cov

the coverage object returned from package_coverage()

filename

the name of the Cobertura XML file

Details

Branch rates are only reported if branches were measured with options(covr.branch_coverage = TRUE) (see covr.branch_coverage), otherwise they are zero. Each line where an if or switch() starts then has branch="true" and a condition-coverage such as "50% (1/2)", the percentage and number of the branches of the if and switch() calls on the line that were taken. The branch rate of code without branches is one.

Note: This functionality requires the xml2 package be installed.


Calculate coverage of code directly

Description

This function is useful for testing, and is a thin wrapper around file_coverage() because parseData is not populated properly unless the functions are defined in a file.

Usage

code_coverage(
  source_code,
  test_code,
  line_exclusions = NULL,
  function_exclusions = NULL,
  ...
)

Arguments

source_code

A character vector of source code

test_code

A character vector of test code

line_exclusions

a named list of files with the lines to exclude from each file.

function_exclusions

a vector of regular expressions matching function names to exclude. Example ⁠print\\\.⁠ to match print methods.

...

Additional arguments passed to file_coverage()

Value

A coverage object.

Parallel code

Code run in processes forked by parallel::mclapply(), parallel::mcparallel() and related functions (not available on Windows) is included in the coverage. While the code runs, parallel:::mcfork and parallel:::mcexit are patched so that the forked processes save their counts when they exit. To turn this off, set the environment variable COVR_FIX_PARALLEL_MCEXIT or the option covr.fix_parallel_mcexit to FALSE.

Examples

source <- "add <- function(x, y) { x + y }"
test <- "add(1, 2) == 3"
code_coverage(source, test)

Run covr on a package and upload the result to codecov.io

Description

Uploads coverage to Codecov with the current upload protocol, the one used by the Codecov CLI and the codecov/codecov-action GitHub Action. This takes two requests:

Usage

codecov(
  ...,
  coverage = NULL,
  base_url = "https://ingest.codecov.io",
  token = NULL,
  commit = NULL,
  branch = NULL,
  pr = NULL,
  flags = NULL,
  quiet = TRUE
)

Arguments

...

arguments passed to package_coverage()

coverage

an existing coverage object to submit, if NULL, package_coverage() will be called with the arguments from ...

base_url

the url coverage is uploaded to. The default is Codecov's upload API; change it for Codecov Enterprise. The former default "https://codecov.io" is the website, not the API, so it (and "https://app.codecov.io") is replaced by the default.

token

a codecov upload token, if NULL then following external sources will be checked in this order:

  1. the environment variable ‘CODECOV_TOKEN’. If it is empty, then

  2. package will look at directory of the package for a file codecov.yml. File must have codecov section where field token is set to a token that will be used.

If there is no token, the upload is sent without one, see the section “Tokens”.

commit

explicitly set the commit this coverage result object corresponds to. Is looked up from the service or locally if it is NULL.

branch

explicitly set the branch this coverage result object corresponds to, this is looked up from the service or locally if it is NULL.

pr

explicitly set the pr this coverage result object corresponds to, this is looked up from the service if it is NULL.

flags

A flag to use for this coverage upload see https://docs.codecov.com/docs/flags for details.

quiet

if FALSE, print the coverage before submission.

Details

  1. ⁠POST <base_url>/upload/<git service>/<owner>::::<repo>/upload-coverage⁠ (for a repository in nested groups, owner/group/repo is ⁠owner:::group::::repo⁠) tells Codecov about the commit, branch, pull request and CI job. The response contains a url for the upload on Codecov and a pre-signed location to send the coverage report to.

  2. PUT sends the report, covr's JSON coverage format (processed by Codecov as an R report), to that location. With branch coverage (see covr.branch_coverage), the report uses Codecov's generic JSON format instead, as the R format only takes line hits. A line with branches then has the number of its branches taken and the number of branches, e.g. "1/2", so Codecov shows it as partly covered unless all were taken.

If quiet is FALSE, the url of the upload on Codecov is printed after a successful upload.

The commit, branch, pull request, job, build URL and repository are looked up from the environment variables of the CI service, which is one of Jenkins, Travis, CircleCI, Drone, AppVeyor, GitLab CI, GitHub Actions or Google Cloud Build. Anywhere else, or for values the service does not provide, they are looked up from the local git repository in the working directory. The repository (owner/repo) and the git service (github, gitlab, bitbucket, ...) come from the CI service when it provides them, otherwise from the origin remote of the local git repository, otherwise the git service is assumed to be github.

Value

The response of Codecov to the request for an upload, invisibly: a list that includes url, the url of the upload on Codecov. If Codecov rejects either request, codecov() throws an error of class covr_codecov_error with the response of Codecov in its message, except when Codecov is rate limiting requests (HTTP 429) or is unavailable (HTTP 5xx), when it gives a warning of class covr_codecov_warning and returns NULL instead, so CI does not fail because of a transient Codecov problem.

Tokens

Codecov authenticates uploads with an upload token, passed in the Authorization header. Both the token of a repository and an organization (global) upload token, which is shared by all of an organization's repositories, can be used. The token is looked up as described for token. See https://docs.codecov.com/docs/codecov-tokens.

Without a token, Codecov only accepts uploads for public repositories, and only for an unprotected branch, which is a branch name with an owner prefix such as owner:branch. Pull requests from forks do not have access to the token as a CI secret, so on GitHub Actions, when there is no token, branch is NULL and the head repository of the pull request (the pull_request.head.repo.full_name of the event in GITHUB_EVENT_PATH) differs from GITHUB_REPOSITORY, codecov() uses the label of the head of the pull request, owner:branch, as the branch name, as codecov/codecov-action does. Pull requests from the same repository, other CI services and uploads from other branches use the plain branch name, so without a token Codecov rejects them unless the branch is already unprotected.

Alternative

Instead of uploading from R, write the coverage to a file and upload it with the codecov/codecov-action GitHub Action, or any other Codecov uploader. lcov() has no dependencies and writes lcov.info, which the action uploads without further configuration:

- name: Test coverage
  run: covr::lcov(covr::package_coverage())
  shell: Rscript {0}

- uses: codecov/codecov-action@v5
  with:
    token: ${{ secrets.CODECOV_TOKEN }}

cobertura() writes the Cobertura XML format, for which the xml2 package is needed.

Examples

## Not run: 
codecov(path = "test")

## End(Not run)

Colors for color vision deficiency

Description

colorblind_palette has colors for the covr.report_colors option that are easier to tell apart with color vision deficiency than the default green and red: blue for covered code, yellow for partial coverage and vermillion for missed code, from the Okabe-Ito palette. They are used in report(), file_report() and the coverage percentages printed in the console.

Usage

colorblind_palette

Format

A named character vector with elements covered, partial and missed.

Details

To set the colors in your .Rprofile without loading covr, copy the values.

Examples

colorblind_palette
## Not run: 
options(covr.report_colors = covr::colorblind_palette)
report()

## End(Not run)

Coverage objects

Description

package_coverage(), file_coverage(), code_coverage(), function_coverage() and environment_coverage() return a coverage object, which records how many times each part of the code was executed.

Working with coverage objects

Rather than using the list directly, you will usually want to:

Structure

A coverage object is a named list with one element for each traced expression of R code and each line of compiled code. Each element is a list with:

  • value: the number of times the expression or line was executed.

  • srcref: a srcref with its location. Its srcfile attribute holds the name and lines of the source file.

  • functions: the name of the function containing it, or NA for compiled code.

  • tests: only present with options(covr.record_tests = TRUE), see covr.record_tests.

The names of the elements are the base name of the file followed by the eight numbers of the srcref, separated by :. For example foo.R:10:3:12:4:3:4:10:12 is an expression from line 10 column 3 to line 12 column 4 of foo.R (see as.data.frame.coverage() for the meaning of each number). The srcfile of the srcref, or the filename column of as.data.frame(), gives the path of the file.

Coverage objects from package_coverage() also have the attributes package (information about the package, such as its package name and path), root (the directory file names are relative to, or NULL) and, if clean = FALSE, library (the install_path).

With options(covr.record_tests = TRUE), coverage objects also have a tests attribute with the test calls, see covr.record_tests.

With options(covr.branch_coverage = TRUE), coverage objects also have a branches attribute with the branches of each if and switch(), see covr.branch_coverage.

Examples

cov <- code_coverage("add <- function(x, y) { x + y }", "add(1, 2)")
cov
as.data.frame(cov)
names(cov)
cov[[1]]$value

Convert a coverage dataset to a list

Description

Convert a coverage dataset to a list

Usage

coverage_to_list(x = package_coverage())

Arguments

x

a coverage dataset, defaults to running package_coverage().

Value

A list containing coverage result for each individual file and the whole package


Convert a coverage dataset to a markdown table

Description

Creates a markdown table with the total coverage and the coverage of each file, suitable for a GitHub Actions job summary or a pull request comment. If base is given, the table also includes the coverage of base and the change from it.

Usage

coverage_to_markdown(x = package_coverage(), base = NULL)

Arguments

x

a coverage dataset, defaults to running package_coverage().

base

an optional coverage dataset to compare against, e.g. the coverage of the main branch.

Value

A character vector of markdown lines, with class "covr_markdown".

Examples

## Not run: 
# In a GitHub Actions step
md <- coverage_to_markdown(package_coverage())
cat(md, file = Sys.getenv("GITHUB_STEP_SUMMARY"), sep = "\n", append = TRUE)

## End(Not run)

Run covr on a package and upload the result to coveralls

Description

On GitHub Actions, use the official Coveralls action instead of this function: write the coverage with cobertura() and upload cobertura.xml with coverallsapp/github-action@v2. See the README for an example workflow. With branch coverage, upload the LCOV file written by lcov() instead, as the action reads which branches were taken from it.

Usage

coveralls(
  ...,
  coverage = NULL,
  repo_token = Sys.getenv("COVERALLS_TOKEN"),
  service_name = NULL,
  quiet = TRUE
)

Arguments

...

arguments passed to package_coverage()

coverage

an existing coverage object to submit, if NULL, package_coverage() will be called with the arguments from ...

repo_token

The secret repo token for your repository, found on your repository's page on Coveralls. Without a token ("" or NULL), only the CI service and job are submitted, which Coveralls only accepts from Travis CI. With a token, information about the git commit, branch and remote is also submitted.

service_name

The name of the CI service. If NULL, the environment variable CI_NAME is used if it is set, otherwise the CI service is detected from the environment, e.g. ‘github’ on GitHub Actions and ‘travis-ci’ on Travis CI. Outside a supported CI service it is ‘local’.

quiet

if FALSE, print the coverage before submission.

Details

With branch coverage (see covr.branch_coverage), each source file sent to Coveralls also has its branches: the line, block, branch and count of each branch, as in lcov(). A branch that was never taken has a count of zero.

The CI service, job, pull request, branch and commit are detected from the environment variables of the services codecov() supports. Anywhere else, the branch, commit and remote are looked up from the local git repository. The environment variables CI_BRANCH and CI_REMOTE override the detected branch and remote.


Branch coverage

Description

By setting options(covr.branch_coverage = TRUE) before measuring coverage, covr also records which branches of each if and switch() in R code were taken. Line and expression coverage are the same as without it. Branch coverage is experimental: what counts as a branch, and how branches are stored and reported, may change.

Details

The option is read when the code is instrumented, so it has no cost when it is not set. When it is set, every if and switch() that runs calls a function of covr, which makes the code slower.

Branches

  • An if has two branches, "TRUE" and "FALSE". The "FALSE" branch of an if without an ⁠else⁠ is taken when the condition is FALSE. Nothing is recorded if the condition is NA or otherwise signals an error.

  • A switch() has a branch for each of its arms, labelled with the name of the arm. Arms that fall through to the next arm (switch(x, a = , b = 1)) share its branch, labelled "a, b". An unnamed arm is labelled "<default>", or with its position if all arms are unnamed. A switch() without a default arm has another branch, "<no match>", taken when no arm matches, including a number that selects no arm. A switch() with arms in ... has no branches.

&&, || and loops have no branches, nor does compiled code.

If the line where an if or switch() starts is excluded, e.g. with ⁠# nocov⁠ (see exclusions), all its branches are excluded too.

Results

The branches are in the branches attribute of the coverage object, a list with an element for each if and switch(), named like the elements of the coverage object (see coverage). Each is a list with the srcref of the if or switch(), its functions, the labels of its branches, and value, the number of times each branch was taken. Use tally_coverage(by = "branch") for a data frame with one row for each branch, and percent_coverage(by = "branch") for the percentage of branches taken.

report(), file_report(), lcov(), cobertura(), codecov() and coveralls() include the branches. The reports show the number of branches taken on each line and the percentage of branches taken in each file, and show a line with branches that weren't all taken as partly covered. Codecov shows such lines as partly covered too, and counts them as not covered in the coverage percentage, so the percentage on Codecov is lower with branch coverage. sonarqube() doesn't include the branches yet.

Examples

withr::with_options(list(covr.branch_coverage = TRUE), {
  cov <- code_coverage(
    "f <- function(x) {\n  if (x > 0) 'positive'\n  'done'\n}",
    "f(1)"
  )
})
tally_coverage(cov, by = "branch")
percent_coverage(cov, by = "branch")

Record Test Traces During Coverage Execution

Description

By setting options(covr.record_tests = TRUE), the result of covr coverage collection functions will include additional data pertaining to the tests which are executed and an index of which tests, at what stack depth, trigger the execution of each trace.

Details

This functionality requires that the package code and tests are installed and sourced with the source. For more details, refer to R options, keep.source, keep.source.pkgs and keep.parse.data.pkgs.

Additional fields

Within the covr result, you can explore this information in two places:

  • attr(,"tests"): A list of call stacks, which results in target code execution.

  • ⁠$<srcref>$tests⁠: For each srcref count in the coverage object, a ⁠$tests⁠ field is now included which contains a matrix with three columns, "test", "call", "depth" and "i" which specify the test number (corresponding to the index of the test in attr(,"tests"), the number of times the test expression was evaluated to produce the trace hit, the stack depth into the target code where the trace was executed, and the order of execution for each test.

Test traces

The content of test traces are dependent on the unit testing framework that is used by the target package. The behavior is contingent on the available information in the sources kept for the testing files.

Test traces are extracted by the following criteria:

  1. If any srcref files are are provided by a file within covr's temporary library, all calls from those files are kept as a test trace. This will collect traces from tests run with common testing frameworks such as testthat and RUnit.

  2. Otherwise, as a conservative fallback in situations where no source references are found, or when none are from within the temporary directory, the entire call stack is collected.

These calls are subsequently subset for only those up until the call to covr's internal count function, and will always include the last call in the call stack prior to a call to count.

Functions in the recorded calls, such as the function of an R6 active binding or a function passed to do.call(), have their environment replaced with emptyenv(), so that the objects they enclose aren't saved with the coverage.

Examples

fcode <- '
f <- function(x) {
  if (x)
    f(!x)
  else
    FALSE
}'

options(covr.record_tests = TRUE)
cov <- code_coverage(fcode, "f(TRUE)")

# extract executed test code for the first test
tail(attr(cov, "tests")[[1L]], 1L)
# [[1]]
# f(TRUE)

# extract test itemization per trace
cov[[3]][c("srcref", "tests")]
# $srcref
# f(!x)
#
# $tests
#      test call depth i
# [1,]    1    1     2 4

# reconstruct the code path of a test by ordering test traces by [,"i"]
lapply(cov, `[[`, "tests")
# $`source.Ref2326138c55:4:6:4:10:6:10:4:4`
#      test call depth i
# [1,]    1    1     1 2
#
# $`source.Ref2326138c55:3:8:3:8:8:8:3:3`
#      test call depth i
# [1,]    1    1     1 1
# [2,]    1    1     2 3
#
# $`source.Ref2326138c55:6:6:6:10:6:10:6:6`
#      test call depth i
# [1,]    1    1     2 4

Retrieve the number of times the test call was called

Description

A single test expression might be evaluated many times. Each time the same expression is called, the call count is incremented.

Usage

current_test_call_count()

Value

An integer value representing the number of calls of the current call into the package from the testing suite.


Calculate coverage of an environment

Description

The functions in env are instrumented, then the files in test_files are run with sys.source() in a child environment of env, from the current working directory. Nothing else is set up, so testthat tests that rely on its test runner, e.g. for setup files, snapshots, or the test directory as the working directory (which testthat::test_path() uses to find fixtures while testing), should instead be run with testthat::test_file() inside with_coverage().

Usage

environment_coverage(
  env = parent.frame(),
  test_files,
  line_exclusions = NULL,
  function_exclusions = NULL
)

Arguments

env

The environment to be instrumented.

test_files

Character vector of test files with code to test the functions

line_exclusions

a named list of files with the lines to exclude from each file.

function_exclusions

a vector of regular expressions matching function names to exclude. Example ⁠print\\\.⁠ to match print methods.

Value

A coverage object.

Parallel code

Code run in processes forked by parallel::mclapply(), parallel::mcparallel() and related functions (not available on Windows) is included in the coverage. While the code runs, parallel:::mcfork and parallel:::mcexit are patched so that the forked processes save their counts when they exit. To turn this off, set the environment variable COVR_FIX_PARALLEL_MCEXIT or the option covr.fix_parallel_mcexit to FALSE.

Compiled code

environment_coverage() and with_coverage() include the compiled code in the coverage of the namespace of a package loaded with pkgload::load_all() (e.g. by devtools::load_all()), so devtools::test_coverage_active_file() also works for files in ⁠src/⁠. With compiled files in source_files, file_coverage() loads their package with pkgload::load_all() and reports the coverage of those files, without needing devtools:

file_coverage("src/foo.c", "tests/testthat/test-foo.R")
file_coverage("src/rust/src/lib.rs", "tests/testthat/test-foo.R")

The compiled code is measured in the current session, which is much faster than package_coverage(): C, C++, Fortran and Objective-C code with gcov, and Rust code (e.g. of packages using extendr or savvy) with LLVM's source-based coverage, which needs the llvm tools described in package_coverage(). An instrumented copy of the package is built in the session's temporary directory, leaving the package's own build untouched, and later runs only recompile the files that changed, with cargo's incremental build in the copy's own target directory for Rust code. While the code runs, the namespace's native routines use the instrumented DLL instead of the package's own. Routines that were looked up some other way, e.g. stored by .onLoad() or found by other packages with R_GetCCallable(), keep using the package's DLL, so their code isn't counted. Set options(covr.gcov = "") to leave out C, C++, Fortran and Objective-C code, and options(covr.llvm_cov = "") to leave out Rust code.

See Also

with_coverage()


Exclusions

Description

covr supports a couple of different ways of excluding some or all of a file.

Line Exclusions

The line_exclusions argument to package_coverage() can be used to exclude some or all of a file. This argument takes a list of filenames or named ranges to exclude.

Function Exclusions

Alternatively function_exclusions can be used to exclude R functions based on regular expression(s). For example ⁠print\\\.*⁠ can be used to exclude all the print methods defined in a package from coverage.

Exclusion Comments

In addition you can exclude lines from the coverage by putting special comments in your source code. This can be done per line or by specifying a range. The patterns used can be specified by setting the global options covr.exclude_pattern, covr.exclude_start, covr.exclude_end.

Examples

## Not run: 
# exclude whole file of R/test.R
package_coverage(line_exclusions = list("R/test.R"))

# exclude lines 1 to 10 and 15 from R/test.R
package_coverage(line_exclusions = list("R/test.R" = c(1:10, 15)))

# exclude lines 1 to 10 from R/test.R, all of R/test2.R
package_coverage(line_exclusions = list("R/test.R" = 1:10, "R/test2.R"))

# exclude all print and format methods from the package.
package_coverage(function_exclusions = c("print\\.", "format\\."))

# single line exclusions
f1 <- function(x) {
  x + 1 # nocov
}

# ranged exclusions
f2 <- function(x) { # nocov start
  x + 2
} # nocov end

## End(Not run)

Calculate test coverage for sets of files

Description

The files in source_files are first sourced into a new environment to define functions to be checked. Then they are instrumented to track coverage and the files in test_files are run with runner.

Usage

file_coverage(
  source_files,
  test_files,
  line_exclusions = NULL,
  function_exclusions = NULL,
  parent_env = parent.frame(),
  runner = source_test_file
)

Arguments

source_files

Character vector of source files with function definitions to measure coverage. Can also include compiled files from a package's ⁠src/⁠ directory; see the compiled code section.

test_files

Character vector of test files with code to test the functions

line_exclusions

a named list of files with the lines to exclude from each file.

function_exclusions

a vector of regular expressions matching function names to exclude. Example ⁠print\\\.⁠ to match print methods.

parent_env

The parent environment to use when sourcing the files. If source_files includes compiled files, the default is the namespace of their package.

runner

A function used to run each test file, called as runner(file, env = env), where env is the environment the source_files were sourced into. The default sources the file into env with sys.source(). Use runner = testthat::test_file to run testthat tests with testthat's test runner; see the testthat tests section.

Value

A coverage object.

Parallel code

Code run in processes forked by parallel::mclapply(), parallel::mcparallel() and related functions (not available on Windows) is included in the coverage. While the code runs, parallel:::mcfork and parallel:::mcexit are patched so that the forked processes save their counts when they exit. To turn this off, set the environment variable COVR_FIX_PARALLEL_MCEXIT or the option covr.fix_parallel_mcexit to FALSE.

testthat tests

By default the test files are run with sys.source(), not with testthat's test runner, so features that need the runner don't work. In particular, testthat::expect_snapshot() is skipped ("Can't compare snapshot to reference when testing interactively").

To use these features, run the test files with testthat::test_file():

file_coverage(
  "R/my_functions.R",
  "tests/test-my_functions.R",
  runner = testthat::test_file
)

The tests then run in a child of the environment the source files were sourced into, and snapshots are saved in a ⁠_snaps⁠ directory next to the test file. expect_snapshot() also needs testthat's 3rd edition (e.g. testthat::local_edition(3) in the tests), and is skipped unless the NOT_CRAN environment variable is "true".

For more control, source the files yourself and use with_coverage().

Files from a package

To make the package's other functions available, load the package (e.g. with pkgload::load_all()) and use parent_env = asNamespace("pkg"). Calls from other package files use the namespace's untraced functions, so don't count. devtools::test_coverage_active_file() measures the coverage of one file of a package without this limitation.

Compiled code

environment_coverage() and with_coverage() include the compiled code in the coverage of the namespace of a package loaded with pkgload::load_all() (e.g. by devtools::load_all()), so devtools::test_coverage_active_file() also works for files in ⁠src/⁠. With compiled files in source_files, file_coverage() loads their package with pkgload::load_all() and reports the coverage of those files, without needing devtools:

file_coverage("src/foo.c", "tests/testthat/test-foo.R")
file_coverage("src/rust/src/lib.rs", "tests/testthat/test-foo.R")

The compiled code is measured in the current session, which is much faster than package_coverage(): C, C++, Fortran and Objective-C code with gcov, and Rust code (e.g. of packages using extendr or savvy) with LLVM's source-based coverage, which needs the llvm tools described in package_coverage(). An instrumented copy of the package is built in the session's temporary directory, leaving the package's own build untouched, and later runs only recompile the files that changed, with cargo's incremental build in the copy's own target directory for Rust code. While the code runs, the namespace's native routines use the instrumented DLL instead of the package's own. Routines that were looked up some other way, e.g. stored by .onLoad() or found by other packages with R_GetCCallable(), keep using the package's DLL, so their code isn't counted. Set options(covr.gcov = "") to leave out C, C++, Fortran and Objective-C code, and options(covr.llvm_cov = "") to leave out Rust code.

Examples

# For the purpose of this example, save code containing code and tests to files
cat("add <- function(x, y) { x + y }", file="add.R")
cat("add(1, 2) == 3", file="add_test.R")

# Use file_coverage() to calculate test coverage
file_coverage(source_files = "add.R", test_files = "add_test.R")

# cleanup
file.remove(c("add.R", "add_test.R"))

A coverage report for a specific file

Description

file_report() saves the coverage of one file as a standalone HTML file and opens it. file_report_html() creates the same report as HTML that can be included in a larger document, like report_html().

Usage

file_report(
  x = package_coverage(),
  file = NULL,
  out_file = file.path(tempdir(), paste0(get_package_name(x), "-file-report.html")),
  browse = interactive()
)

file_report_html(x = package_coverage(), file = NULL)

Arguments

x

a coverage dataset, defaults to running package_coverage().

file

The file to report on, if NULL, use the first file in the coverage output.

out_file

The output file

browse

whether to open a browser to view the report.

Details

With branch coverage, the report shows the branches of the file as described in the "Branches" section of report().

Value

file_report_html() returns an htmltools::tagList(), with the dependencies of the report attached.


Calculate test coverage for a specific function.

Description

Calculate test coverage for a specific function.

Usage

function_coverage(fun, code = NULL, env = NULL, enc = parent.frame())

Arguments

fun

name of the function.

code

expressions to run.

env

environment the function is defined in.

enc

the enclosing environment which to run the expressions.

Value

A coverage object.

Parallel code

Code run in processes forked by parallel::mclapply(), parallel::mcparallel() and related functions (not available on Windows) is included in the coverage. While the code runs, parallel:::mcfork and parallel:::mcexit are patched so that the forked processes save their counts when they exit. To turn this off, set the environment variable COVR_FIX_PARALLEL_MCEXIT or the option covr.fix_parallel_mcexit to FALSE.

Examples

add <- function(x, y) { x + y }
function_coverage(fun = add, code = NULL) # 0% coverage
function_coverage(fun = add, code = add(1, 2) == 3) # 100% coverage

Run covr on package and create report for GitLab

Description

Utilize internal GitLab static pages to publish package coverage. Creates local covr report in a package subdirectory. Uses the pages GitLab job to publish the report.

Usage

gitlab(..., coverage = NULL, file = "public/coverage.html", quiet = TRUE)

Arguments

...

arguments passed to package_coverage()

coverage

an existing coverage object to submit, if NULL, package_coverage() will be called with the arguments from ...

file

The report filename.

quiet

if FALSE, print the coverage before submission.


Is the source bound to the expression

Description

Is the source bound to the expression

Usage

has_srcref(expr)

Arguments

expr

A language object which may have a srcref attribute

Value

A logical value indicating whether the language object has source


Determine if code is being run in covr

Description

covr functions set the environment variable R_COVR when they are running. in_covr() returns TRUE if this environment variable is set and FALSE otherwise.

Usage

in_covr()

Examples

if (require(testthat)) {
  testthat::skip_if(in_covr())
}

Is the expression a call to covr:::count

Description

Is the expression a call to covr:::count

Usage

is_covr_count_call(expr)

Arguments

expr

A language object

Value

A logical value indicating whether the object is a call to covr:::count or covr:::count_and_record.


Returns TRUE if we've moved on from test reflected in .current_test

Description

Quickly dismiss the need to update the current test if we can. To test if we're still in the last test, check if the same srcref (or call, if source is not kept) exists at the last recorded calling frame prior to entering a covr trace. If this has changed, do a more comprehensive test to see if any of the test call stack has changed, in which case we are onto a new test.

Usage

is_current_test_finished()

Create an LCOV tracefile

Description

Write coverage in the LCOV tracefile format described in geninfo(1), which is read by genhtml, Codecov, Coveralls, SonarQube and editor plugins such as Coverage Gutters.

Usage

lcov(cov, filename = "lcov.info")

Arguments

cov

the coverage object returned from package_coverage()

filename

the name of the LCOV file

Details

Each source file gets a record with its functions (FN, FNDA, FNF, FNH) and lines (DA, LF, LH). Line counts are those of tally_coverage() with by = "line", combined so that each source line has a single DA record: when several functions share a line, the line's count is the smallest of theirs, so a line only counts as covered if all its code was run, as in report(), percent_coverage() and codecov(). A function's count is the largest count of any of its expressions.

Branches are only recorded if they were measured with options(covr.branch_coverage = TRUE) (see covr.branch_coverage). Each branch gets a BRDA record on the line where its if or switch() starts, numbered from zero within each if or switch(). Its count is - if the if or switch() never ran. BRF and BRH give the number of branches and the number of branches taken.

Source file paths (SF) are written as covr reports them, for a package relative to the package root, so tools such as genhtml should be run from that directory.

Value

The lines of the LCOV file, invisibly.

Examples

cov <- code_coverage(
  "f <- function(x) {\n  y <- x + 1\n  y * 2\n}\ng <- function() 1",
  "f(1)"
)
tmp <- tempfile(fileext = ".info")
lcov(cov, tmp)
cat(readLines(tmp), sep = "\n")

Initialize a new test counter for a coverage trace

Description

Initialize a test counter, a matrix used to tally tests, their stack depth and the execution order as the trace associated with key is hit. Each test trace is an environment, which allows assignment into a pre-allocated tests matrix with minimall reallocation.

Usage

new_test_counter(key)

Arguments

key

generated with key()

Details

The tests matrix has columns tests, depth and i, corresponding to the test index (the index of the associated test in .counters$tests), the stack depth when the trace is evaluated and the number of traces that have been hit so far during test evaluation.


Calculate test coverage for a package

Description

This function calculates the test coverage for a development package on the path. By default it runs only the package tests, but it can also run vignette and example code.

Usage

package_coverage(
  path = ".",
  type = c("tests", "vignettes", "examples", "all", "none"),
  combine_types = TRUE,
  relative_path = TRUE,
  quiet = TRUE,
  clean = TRUE,
  line_exclusions = NULL,
  function_exclusions = NULL,
  code = character(),
  install_path = temp_file("R_LIBS"),
  ...,
  pre_clean,
  allow_failures = getOption("covr.allow_failures", FALSE),
  show_code_output = FALSE
)

Arguments

path

file path to the package, or to an installed package.

type

run the package ‘tests’, ‘vignettes’, ‘examples’, ‘all’, or ‘none’. The default is ‘tests’.

combine_types

If TRUE (the default) the coverage for all types is simply summed into one coverage object. If FALSE separate objects are used for each type of coverage.

relative_path

whether to output the paths as relative or absolute paths. If a string, it is interpreted as a root path and all paths will be relative to that root.

quiet

whether to load and compile the package quietly, useful for debugging errors.

clean

whether to clean temporary output files after running, mainly useful for debugging errors. If coverage fails, or failures are reported as warnings with allow_failures = TRUE, install_path is kept even when clean = TRUE, so the test output can be inspected.

line_exclusions

a named list of files with the lines to exclude from each file.

function_exclusions

a vector of regular expressions matching function names to exclude. Example ⁠print\\\.⁠ to match print methods.

code

A character vector of additional test code to run.

install_path

The path the instrumented package will be installed to and tests run in. By default it is a path in the R sessions temporary directory. It can sometimes be useful to set this (along with clean = FALSE) to help debug test failures. It is not removed if coverage fails.

...

Additional arguments passed to tools::testInstalledPackage(). Use outDir to save the output of the tests and examples to a directory which is kept after coverage finishes; by default it is written to install_path.

pre_clean

Deprecated and ignored. Objects present in the src directory are always deleted before recompiling.

allow_failures

If TRUE, failures or errors when running tests, vignettes, examples or code are reported as warnings (with class covr_warning) and coverage is still returned. Coverage may be incomplete in this case, as code which would have run after the failure is not tracked. The default, FALSE, throws an error (with class covr_error) on the first failure. The default can be changed with the covr.allow_failures option, e.g. options(covr.allow_failures = TRUE).

show_code_output

If TRUE, the output of code is shown on the console while it runs, e.g. to follow it in the logs of a CI job. The default, FALSE, only saves it to a file in install_path, which is shown if code fails.

Details

This function uses tools::testInstalledPackage() to run the code, if you would like to test your package in another way you can set type = "none" and pass the code to run as a character vector to the code parameter.

Coverage is also recorded in other R processes that load the package, such as callr sessions, future or parallel cluster workers, or Shiny apps run by shinytest2. Each process saves its coverage when it exits normally, so the coverage is lost if a process is killed (e.g. with SIGKILL or SIGTERM) or is still running when the tests finish, and package_coverage() warns (with class covr_unsaved_trace). Stop these processes gracefully and wait for them to exit, e.g. call ⁠$stop()⁠ on a shinytest2 AppDriver, which waits longer for the app to exit when run by covr. See vignette("shiny", package = "covr") for measuring the coverage of Shiny apps.

path can also be an installed package, e.g. system.file(package = "pkg"), to compute coverage without the package source. The package must have been installed with its tests and source references, e.g. with remotes::install_github("user/pkg", INSTALL_opts = c("--install-tests", "--with-keep.source")). File names are those of the source it was installed from, and compiled code isn't covered.

The coverage of Rust code, built by cargo into a static library that is linked into the package, is measured with LLVM's source-based coverage. This needs the llvm tools of the Rust toolchain (⁠rustup component add llvm-tools⁠), or for Rust installed by a Linux distribution, those of the LLVM version rustc uses (e.g. ⁠apt-get install llvm-18⁠); without them package_coverage() warns and reports no coverage for the Rust code. covr instruments the crates of the package's cargo workspace by having cargo run rustc through a wrapper (with RUSTC_WORKSPACE_WRAPPER) that adds ⁠-C instrument-coverage⁠, so it works however the package sets RUSTFLAGS, and dependencies are built as usual. Vendored crates, including the C code they compile, and code generated in cargo's target directory aren't included. The code that macros such as ⁠#[extendr]⁠ and ⁠#[savvy]⁠ generate is counted on the macro's line, so the line isn't covered if parts of the generated code never run, e.g. the handling of arguments that can't be converted. The coverage of Rust code isn't measured on Windows, as rustup's Rust for the x86_64-pc-windows-gnu target that Rtools uses has no profiler runtime.

Parallelized code using parallel's mcparallel() needs to use a patched parallel:::mcexit. This is done automatically if the package depends on parallel, but can also be explicitly set using the environment variable COVR_FIX_PARALLEL_MCEXIT or the global option covr.fix_parallel_mcexit.

Value

A coverage object. If combine_types = FALSE and more than one type is run, a list of class coverages with one coverage object for each type, named by type.

See Also

exclusions() For details on excluding parts of the package from the coverage calculations.


Provide percent coverage of package

Description

Calculate the total percent coverage from a coverage result object.

Usage

percent_coverage(x, ...)

Arguments

x

the coverage object returned from package_coverage()

...

additional arguments passed to tally_coverage(), such as by = "branch" for the percentage of branches taken (see covr.branch_coverage).

Value

The total percentage as a numeric(1).


Print a coverage object

Description

Print a coverage object

Usage

## S3 method for class 'coverage'
print(
  x,
  group = c("filename", "functions"),
  by = "line",
  n = Inf,
  missing = FALSE,
  ...
)

Arguments

x

the coverage object to be printed

group

whether to group coverage by filename or function

by

whether to count coverage by line, expression or function

n

the maximum number of files or functions to print. They are sorted from least to most covered, so the least covered are shown first.

missing

whether to list the lines that were not run after each file or function that has any, as ranges such as ⁠missed 41-48, 112⁠. Lines are joined into a range when only blank lines, comments and lines with only punctuation, such as closing braces, are between them. Code that was run, or that has no coverage data, such as the line a function is defined on, ends the range. Only used with by = "line", and ignored otherwise.

If branch coverage was measured (see covr.branch_coverage), the missed branches of each file or function are also listed, as ⁠missed branches 12 FALSE, 30 b⁠: the line of the if or switch() and the label of the branch that was not taken. Only if and switch() calls that were evaluated are listed; the others are covered by the missed lines.

...

additional arguments ignored

Value

The coverage object (invisibly).

Branches

If branch coverage was measured (see covr.branch_coverage), the percentage of branches taken is also shown after the overall coverage, e.g. ⁠Coverage: 87.40% (branches 72.00%)⁠.

Examples

cov <- code_coverage(
  "f <- function(x) x + 1; g <- function(x) x - 1; h <- function(x) 0",
  "f(1)"
)
print(cov, group = "functions", n = 2)

cov <- code_coverage(
  "f <- function(x) {\n  if (x) {\n    1\n\n    # no\n    2\n  }\n}",
  "f(FALSE)"
)
print(cov, missing = TRUE)

Display covr results using a standalone report

Description

report() saves the coverage report as a standalone HTML file and opens it. To include the report in a larger document, such as an R Markdown or Quarto document, use report_html() instead.

Usage

report(
  x = package_coverage(),
  file = file.path(tempdir(), paste0(get_package_name(x), "-report.html")),
  browse = interactive()
)

Arguments

x

a coverage dataset, defaults to running package_coverage().

file

The report filename.

browse

whether to open a browser to view the report.

Branches

If branch coverage was measured with options(covr.branch_coverage = TRUE) (see covr.branch_coverage), the report also shows the branches of each if and switch(). The title has the percentage of branches taken after the line coverage, and the list of files has a "Branches" column with the percentage of the branches of each file that were taken. In the source, a line with branches has the number of its branches taken out of the total, e.g. 1/2; hovering over it or focusing it shows the label and count of each branch. A line with a branch that wasn't taken is shown as partly covered, unless its if or switch() never ran, which leaves it missed.

Colors

Covered lines are shown in green and missed lines in red. To use other colors, set the covr.report_colors option to a named character vector of R colors (anything accepted by grDevices::col2rgb(); transparency is ignored) with elements covered, missed and/or partial. The colors are used for the highlighted lines and the coverage bars in the file list; partial is used for the bars of files with at least 75% but less than 90% coverage, which otherwise follow covered, and for the partly covered lines of reports with branches, which are otherwise yellow.

colorblind_palette has colors that are easier to tell apart with color vision deficiency:

options(covr.report_colors = covr::colorblind_palette)

Dark mode

The report uses a dark theme if the browser or operating system is set to prefer one. The moon (or sun) button at the top right switches between the light and dark themes; the browser remembers the choice for other reports until it is switched back.

Examples

## Not run: 
x <- package_coverage()
report(x)

# Colors that are distinguishable with most kinds of color blindness
old <- options(covr.report_colors = colorblind_palette)
report(x)
options(old)

## End(Not run)

A coverage report to include in other documents

Description

report_html() creates the coverage report shown by report() as HTML that can be included in a larger document, such as an R Markdown or Quarto document or a page made with htmltools. Printing it in an R Markdown or Quarto chunk includes the report in the document; printing it in the console shows it in the viewer.

Usage

report_html(x = package_coverage())

Arguments

x

a coverage dataset, defaults to running package_coverage().

Details

The report takes the width of the element it is in, and its styles and scripts only apply to the report, so they don't change the rest of the document. A document can include several reports.

The colors and the dark theme can be changed as described in report().

Value

An htmltools::tagList(), with the dependencies of the report attached.

Examples

## Not run: 
# In an R Markdown or Quarto chunk
report_html(package_coverage())

# Save it with other content
htmltools::save_html(
  htmltools::tagList(
    htmltools::h1("Package review"),
    report_html(package_coverage())
  ),
  "review.html"
)

## End(Not run)

Calculate test coverage for a Shiny app

Description

Measures the coverage of the functions of a Shiny app that is not part of a package, while code runs its tests, by default with shinytest2::test_app(). This includes the code run by the app in the R processes that shinytest2 starts to run it. For apps in a package, use package_coverage() instead.

Usage

shiny_app_coverage(
  app_dir = ".",
  code = shinytest2::test_app(app_dir),
  line_exclusions = NULL,
  function_exclusions = NULL
)

Arguments

app_dir

The directory of the Shiny app.

code

The code to run the app's tests, evaluated in the calling environment.

line_exclusions

a named list of files with the lines to exclude from each file.

function_exclusions

a vector of regular expressions matching function names to exclude. Example ⁠print\\\.⁠ to match print methods.

Details

The functions defined by the app's files (app.R, ui.R, server.R, global.R and the files in ⁠R/⁠) are instrumented when Shiny loads them, in this R process and in the R processes started while code runs. This includes a server function that isn't assigned to a name, such as the one in server.R or one defined inline, e.g. shinyApp(ui, function(input, output) ...). Code outside functions, such as building the UI, is not counted, as in package_coverage().

This works by adding covr to the default packages of R processes started while code runs (the R_DEFAULT_PACKAGES environment variable), and relies on internal hooks of Shiny which may change in future versions.

An app process saves its coverage when it exits normally, so stop it gracefully, e.g. with ⁠$stop()⁠ on a shinytest2 AppDriver, which waits longer for the app to exit when run by covr. If an app process is killed or is still running when code finishes, its coverage is lost and shiny_app_coverage() warns (with class covr_unsaved_trace).

AppDriver$new() skips tests on CRAN unless the NOT_CRAN environment variable is "true".

Value

A coverage object.

See Also

vignette("shiny", package = "covr")

Examples

## Not run: 
Sys.setenv(NOT_CRAN = "true")
shiny_app_coverage("path/to/app")

## End(Not run)

Create a SonarQube Generic XML file for test coverage according to https://docs.sonarsource.com/sonarqube-server/analyzing-source-code/test-coverage/generic-test-data Based on cobertura.R

Description

This functionality requires the xml2 package be installed.

Usage

sonarqube(cov, filename = "sonarqube.xml", path_prefix = NULL)

Arguments

cov

the coverage object returned from package_coverage()

filename

the name of the SonarQube Generic XML file

path_prefix

SonarQube expects file paths relative to the project's base directory. By default the paths are relative to the package root (e.g. R/foo.R), which is correct when the package is the root of the SonarQube project. If the package is in a subdirectory of the project, set path_prefix to that subdirectory (e.g. "pkg" gives pkg/R/foo.R).

Author(s)

Talkdesk Inc.


Tally coverage by line, expression, function or branch

Description

Tally coverage by line, expression, function or branch

Usage

tally_coverage(x, by = c("line", "expression", "function", "branch"))

Arguments

x

the coverage object returned from package_coverage()

by

whether to tally coverage by line, expression, function or branch

Value

A data.frame. With by = "expression" it is the same as as.data.frame.coverage(). With by = "line" it has one row for each function on each line of code (excluding blank lines, comments and lines with only punctuation such as ⁠}⁠) and the columns filename, functions, line and value, where value is the smallest execution count of the expressions on that line, so a line only counts as covered if all its expressions were run. An expression spanning several lines, such as a loop, only counts for the lines that none of the expressions inside it are on. percent_coverage(), report() and the other line based outputs count each line once, with the smallest count of its functions.

With by = "function" it has one row for each top level R function and the columns filename, functions, first_line, last_line and value, where first_line and last_line span the function's traced code and value is the largest execution count of its expressions, so a function counts as covered if any of its code was run. Compiled code has no function names, so it is left out.

With by = "branch" it has one row for each branch measured with options(covr.branch_coverage = TRUE) (see covr.branch_coverage), and the columns filename, functions, line and column (where the if or switch() starts), branch (the index of the branch in its if or switch()), label and value, the number of times the branch was taken. It has no rows if branch coverage wasn't measured.

Examples

cov <- code_coverage(
  "f <- function(x) {\n  if (x) 'yes' else 'no'\n}\ng <- function() 1",
  "f(TRUE)"
)
tally_coverage(cov)
tally_coverage(cov, by = "expression")
tally_coverage(cov, by = "function")

Tally which tests ran each line

Description

Builds a traceability matrix from coverage recorded with options(covr.record_tests = TRUE): which tests ran each line of code. Use it to find the tests to rerun after changing some lines, or the tests exercising a function.

Usage

tally_tests(x)

Arguments

x

a coverage object computed with options(covr.record_tests = TRUE).

Details

Lines are those of tally_coverage() with by = "line", so blank lines, comments, lines with only punctuation and excluded lines are left out. A test is a top level call in a test file that ran package code, such as an expectation; see covr.record_tests.

Value

A data.frame with one row for each line and each test that ran it, and the columns:

  • filename, functions, line: the line of code, as in tally_coverage().

  • test_file, test_line: where the test call is. For package_coverage(), test files are relative to the package directory, e.g. tests/testthat/test-foo.R. NA if the test has no source references.

  • test: the description of the enclosing test_that() or it() call, or NA.

  • value: the number of times the test ran the line.

Examples

cov <- withr::with_options(
  list(covr.record_tests = TRUE),
  code_coverage(
    "f <- function(x) {\n  if (x) 'yes' else 'no'\n}",
    "f(TRUE)\nf(FALSE)"
  )
)
tests <- tally_tests(cov)
tests

# The tests that ran lines 1 to 2
unique(tests[tests$line %in% 1:2, c("test_file", "test_line")])

Truncate call objects to limit the number of arguments

Description

A helper to circumvent R errors when deserializing large call objects from Rds. Trims the number of arguments in a call object, and replaces the last argument with a ⁠<truncated>⁠ symbol.

Usage

truncate_call(call_obj, limit = 10000)

Arguments

call_obj

A (possibly large) call object

limit

A call length limit to impose

Value

The call_obj with arguments trimmed


Retrieve the execution counts from a coverage object

Description

Retrieve the execution counts from a coverage object

Usage

value(x, ...)

Arguments

x

a coverage object, or one of its elements.

...

additional arguments passed to methods.

Value

For a coverage object, a named numeric vector with the number of times each traced expression or line was executed, named like the elements of x (see coverage). For a single element, its count.

Examples

cov <- code_coverage("add <- function(x, y) { x + y }", "add(1, 2)")
value(cov)

Calculate coverage of arbitrary code run against an environment

Description

with_coverage() instruments the functions in env, evaluates code, and returns the coverage that code produced. Unlike environment_coverage(), which sys.source()s a set of files, code can be any expression. This makes it possible to measure coverage while running tests with a test runner such as testthat::test_file(), without having to recreate the runner's infrastructure (reporters, snapshot handling, test environment, ...).

Usage

with_coverage(
  code,
  env = parent.frame(),
  line_exclusions = NULL,
  function_exclusions = NULL
)

Arguments

code

The code to evaluate while measuring coverage. It is evaluated lazily, in the calling environment, after env has been instrumented.

env

The environment to be instrumented, e.g. a package namespace.

line_exclusions

a named list of files with the lines to exclude from each file.

function_exclusions

a vector of regular expressions matching function names to exclude. Example ⁠print\\\.⁠ to match print methods.

Details

Functions are instrumented in place, so every existing reference to them, including ones captured by an environment created by code (e.g. the child environment of the namespace that testthat::test_file() evaluates tests in), runs the instrumented version. The only requirement is that code must not re-create the functions in env, e.g. when using testthat::test_file() with package set the package must not be reloaded (use load_package = "none"), as reloading would replace the instrumented functions with fresh, uninstrumented ones.

The instrumentation is removed and the counters are cleared when with_coverage() exits, even if code fails.

Value

A coverage object.

Parallel code

Code run in processes forked by parallel::mclapply(), parallel::mcparallel() and related functions (not available on Windows) is included in the coverage. While the code runs, parallel:::mcfork and parallel:::mcexit are patched so that the forked processes save their counts when they exit. To turn this off, set the environment variable COVR_FIX_PARALLEL_MCEXIT or the option covr.fix_parallel_mcexit to FALSE.

Compiled code

environment_coverage() and with_coverage() include the compiled code in the coverage of the namespace of a package loaded with pkgload::load_all() (e.g. by devtools::load_all()), so devtools::test_coverage_active_file() also works for files in ⁠src/⁠. With compiled files in source_files, file_coverage() loads their package with pkgload::load_all() and reports the coverage of those files, without needing devtools:

file_coverage("src/foo.c", "tests/testthat/test-foo.R")
file_coverage("src/rust/src/lib.rs", "tests/testthat/test-foo.R")

The compiled code is measured in the current session, which is much faster than package_coverage(): C, C++, Fortran and Objective-C code with gcov, and Rust code (e.g. of packages using extendr or savvy) with LLVM's source-based coverage, which needs the llvm tools described in package_coverage(). An instrumented copy of the package is built in the session's temporary directory, leaving the package's own build untouched, and later runs only recompile the files that changed, with cargo's incremental build in the copy's own target directory for Rust code. While the code runs, the namespace's native routines use the instrumented DLL instead of the package's own. Routines that were looked up some other way, e.g. stored by .onLoad() or found by other packages with R_GetCCallable(), keep using the package's DLL, so their code isn't counted. Set options(covr.gcov = "") to leave out C, C++, Fortran and Objective-C code, and options(covr.llvm_cov = "") to leave out Rust code.

See Also

environment_coverage()

Examples

## Not run: 
# With a package loaded by pkgload::load_all()
ns <- asNamespace("mypkg")
with_coverage(
  testthat::test_file(
    "tests/testthat/test-foo.R",
    package = "mypkg",
    load_package = "none"
  ),
  env = ns
)

## End(Not run)

Provide locations of zero coverage

Description

When examining the test coverage of a package, it is useful to know if there are any locations where there is 0 test coverage.

Usage

zero_coverage(x, ...)

Arguments

x

a coverage object returned package_coverage()

...

additional arguments passed to tally_coverage(), such as by = "function" to list the functions that were never run.

Details

if used within RStudio this function outputs the results using the Marker API.

Value

A data.frame with coverage data where the coverage is 0.

Examples

cov <- code_coverage(
  "f <- function(x) {\n  if (x) 'yes' else 'no'\n}\ng <- function() 1",
  "f(TRUE)"
)
zero_coverage(cov)
zero_coverage(cov, by = "function")