├── .Rbuildignore ├── .gitattributes ├── .github ├── .gitignore └── workflows │ ├── R-CMD-check.yaml │ ├── pkgdown.yaml │ ├── pr-commands.yaml │ └── test-coverage.yaml ├── .gitignore ├── .lintr ├── CODE_OF_CONDUCT.md ├── DESCRIPTION ├── LICENSE ├── LICENSE.md ├── Makefile ├── NAMESPACE ├── NEWS.md ├── R ├── R6.R ├── RC.R ├── S4.R ├── S7.R ├── azure.R ├── box.R ├── cobertura.R ├── codecov.R ├── compiled.R ├── coveralls.R ├── covr.R ├── data_frame.R ├── display_name.R ├── exclusions.R ├── gitlab.R ├── icc.R ├── parallel.R ├── parse_data.R ├── replace.R ├── report.R ├── sonarqube.R ├── summary_functions.R ├── system.R ├── trace_calls.R ├── trace_tests.R ├── utils.R ├── value.R ├── vectorized.R └── zzz.R ├── README.md ├── SECURITY.md ├── _pkgdown.yml ├── codecov.yml ├── covr.Rproj ├── cran-comments.md ├── docker_checker └── Dockerfile ├── inst ├── rstudio │ └── addins.dcf └── www │ ├── report.css │ └── shared │ ├── bootstrap │ ├── css │ │ ├── bootstrap-theme.min.css │ │ └── bootstrap.min.css │ ├── js │ │ └── bootstrap.min.js │ └── shim │ │ ├── html5shiv.min.js │ │ └── respond.min.js │ └── highlight.js │ ├── LICENSE │ ├── highlight.pack.js │ └── rstudio.css ├── man ├── as_coverage.Rd ├── as_coverage_with_tests.Rd ├── azure.Rd ├── clear_counters.Rd ├── code_coverage.Rd ├── codecov.Rd ├── count.Rd ├── count_test.Rd ├── coverage_to_list.Rd ├── coveralls.Rd ├── covr-package.Rd ├── covr.record_tests.Rd ├── current_test_call_count.Rd ├── current_test_index.Rd ├── current_test_key.Rd ├── display_name.Rd ├── environment_coverage.Rd ├── exclusions.Rd ├── figures │ └── logo.png ├── file_coverage.Rd ├── file_report.Rd ├── function_coverage.Rd ├── gitlab.Rd ├── has_srcref.Rd ├── in_covr.Rd ├── is_covr_count_call.Rd ├── is_current_test_finished.Rd ├── key.Rd ├── new_counter.Rd ├── new_test_counter.Rd ├── package_coverage.Rd ├── percent_coverage.Rd ├── print.coverage.Rd ├── report.Rd ├── system_check.Rd ├── system_output.Rd ├── tally_coverage.Rd ├── to_cobertura.Rd ├── to_sonarqube.Rd ├── trace_calls.Rd ├── truncate_call.Rd ├── update_current_test.Rd ├── value.Rd └── zero_coverage.Rd ├── revdep ├── .gitignore ├── README.md ├── check.R ├── checks.rds ├── email.yml ├── failures.md ├── problems.md └── timing.md ├── shim_package.sh ├── src └── reassign.c ├── tests ├── testthat.R └── testthat │ ├── Test+Char │ └── TestCompiled │ │ ├── DESCRIPTION │ │ ├── NAMESPACE │ │ ├── R │ │ └── TestCompiled.R │ │ ├── man │ │ └── simple.Rd │ │ ├── src │ │ └── simple.cc │ │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-TestCompiled.R │ ├── TestCompiled │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── TestCompiled.R │ ├── man │ │ └── simple.Rd │ ├── src │ │ ├── simple-header.h │ │ ├── simple.cc │ │ └── simple4.cc │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-TestCompiled.R │ ├── TestCompiledSubdir │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── TestCompiledSubdir.R │ ├── man │ │ └── simple.Rd │ ├── src │ │ ├── Makevars │ │ └── lib │ │ │ └── simple.c │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-TestCompiledSubdir.R │ ├── TestExclusion │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── TestExclusion.R │ ├── man │ │ └── test_me.Rd │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-TestExclusion.R │ ├── TestFunctional │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── a.R │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-a.R │ ├── TestNestedTestDirs │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── a.R │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ ├── nested_tests │ │ └── test-a.R │ │ ├── test-a.R │ │ └── test-nested-dir.R │ ├── TestParallel │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── TestParallel.R │ ├── man │ │ └── test_me.Rd │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-TestParallel.R │ ├── TestPrint │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── TestPrint.R │ ├── man │ │ └── test_me.Rd │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-TestSummary.R │ ├── TestR6 │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── TestR6.R │ ├── man │ │ └── a.Rd │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-TestR6.R │ ├── TestRC │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── TestRC.R │ ├── man │ │ └── a.Rd │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-TestRC.R │ ├── TestS4 │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── TestS4.R │ ├── codecov.yml │ ├── man │ │ └── a.Rd │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-TestS4.R │ ├── TestS7 │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── foo.R │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-foo.R │ ├── TestSummary │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── TestSummary.R │ ├── man │ │ └── test_me.Rd │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-TestSummary.R │ ├── TestUseTry │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── notry.R │ └── tests │ │ ├── tests.R │ │ └── testthat │ │ └── test-notry.R │ ├── Testbox │ ├── app │ │ ├── app.R │ │ └── modules │ │ │ └── module.R │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-module.R │ ├── Testbox_R6 │ ├── app │ │ ├── app.R │ │ └── modules │ │ │ └── moduleR6.R │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-moduleR6.R │ ├── Testbox_attached_modules_functions │ ├── app │ │ ├── app.R │ │ └── modules │ │ │ └── module.R │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ ├── test-aliased_functions.R │ │ ├── test-aliased_modules.R │ │ ├── test-attached_functions.R │ │ └── test-three_dots.R │ ├── Testbox_attached_modules_functions_R6 │ ├── app │ │ ├── app.R │ │ └── modules │ │ │ └── moduleR6.R │ └── tests │ │ ├── testthat.R │ │ └── testthat │ │ └── test-attached_R6.R │ ├── _snaps │ ├── Compiled.md │ └── S7.md │ ├── a │ ├── b │ ├── cobertura.xml │ ├── corner-cases-test.R │ ├── corner-cases.R │ ├── corner-cases.Rds │ ├── helper.R │ ├── sonarqube.xml │ ├── test-Compiled.R │ ├── test-R6.R │ ├── test-RC.R │ ├── test-S4.R │ ├── test-S7.R │ ├── test-azure.R │ ├── test-box-R6.R │ ├── test-box.R │ ├── test-box_attached_modules_functions-R6.R │ ├── test-box_attached_modules_functions.R │ ├── test-braceless.R │ ├── test-cobertura.R │ ├── test-codecov.R │ ├── test-corner-cases.R │ ├── test-coveralls.R │ ├── test-covr.R │ ├── test-exclusions.R │ ├── test-file_coverage.R │ ├── test-functions.R │ ├── test-gcov.R │ ├── test-gitlab.R │ ├── test-memoised.R │ ├── test-null.R │ ├── test-package_coverage.R │ ├── test-parallel.R │ ├── test-print.R │ ├── test-record_tests.R │ ├── test-report.R │ ├── test-report.htm │ ├── test-sonarqube.R │ ├── test-summary.R │ ├── test-trace_calls.R │ ├── test-utils.R │ └── test-vectorized.R ├── unshim_package.sh └── vignettes └── how_it_works.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^covr\.Rproj$ 2 | \.tar\.gz$ 3 | ^travis-tool\.sh$ 4 | ^LICENSE\.md$ 5 | ^covr\.Rcheck$ 6 | ^\.travis\.yml$ 7 | ^shim_package\.sh$ 8 | ^unshim_package\.sh$ 9 | Makefile 10 | docker_checker 11 | _dev\.R$ 12 | ^\.lintr$ 13 | ^appveyor\.yml$ 14 | ^wercker\.yml$ 15 | ^\.Rproj\.user$ 16 | ^tests/testthat/.*/.*(o|sl|so|dylib|a|dll|def)$ 17 | ^covr.*$ 18 | ^cran_comments\.md$ 19 | ^revdep/ 20 | ^cran-comments\.md$ 21 | ^cache$ 22 | ^data.Rmd$ 23 | ^covr_performance.Rmd$ 24 | ^revdep$ 25 | ^CRAN-RELEASE$ 26 | ^docs$ 27 | ^_pkgdown\.yml$ 28 | ^pkgdown$ 29 | ^script.R$ 30 | ^azure-pipelines\.yml$ 31 | ^[.]github$ 32 | ^codecov\.yml$ 33 | ^CODE_OF_CONDUCT\.md$ 34 | ^\.github$ 35 | ^SECURITY\.md$ 36 | ^CRAN-SUBMISSION$ 37 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /NEWS.md merge=union 2 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | # 4 | # NOTE: This workflow is overkill for most R packages and 5 | # check-standard.yaml is likely a better choice. 6 | # usethis::use_github_action("check-standard") will install it. 7 | on: 8 | workflow_dispatch: 9 | push: 10 | branches: [main, master] 11 | pull_request: 12 | branches: [main, master] 13 | 14 | name: R-CMD-check 15 | 16 | jobs: 17 | R-CMD-check: 18 | runs-on: ${{ matrix.config.os }} 19 | 20 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | config: 26 | - {os: macos-latest, r: 'release'} 27 | 28 | - {os: windows-latest, r: 'release'} 29 | # Use 3.6 to trigger usage of RTools35 30 | - {os: windows-latest, r: '3.6'} 31 | # use 4.1 to check with rtools40's older compiler 32 | - {os: windows-latest, r: '4.1'} 33 | 34 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 35 | - {os: ubuntu-latest, r: 'release'} 36 | - {os: ubuntu-latest, r: 'oldrel-1'} 37 | - {os: ubuntu-latest, r: 'oldrel-2'} 38 | - {os: ubuntu-latest, r: 'oldrel-3'} 39 | - {os: ubuntu-latest, r: 'oldrel-4'} 40 | 41 | env: 42 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 43 | R_KEEP_PKG_SOURCE: yes 44 | 45 | steps: 46 | - uses: actions/checkout@v3 47 | 48 | - uses: r-lib/actions/setup-pandoc@v2 49 | 50 | - uses: r-lib/actions/setup-r@v2 51 | with: 52 | r-version: ${{ matrix.config.r }} 53 | http-user-agent: ${{ matrix.config.http-user-agent }} 54 | use-public-rspm: true 55 | 56 | - uses: r-lib/actions/setup-r-dependencies@v2 57 | with: 58 | extra-packages: any::rcmdcheck 59 | needs: check 60 | 61 | - uses: r-lib/actions/check-r-package@v2 62 | with: 63 | upload-snapshots: true 64 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown 13 | 14 | jobs: 15 | pkgdown: 16 | runs-on: ubuntu-latest 17 | # Only restrict concurrency for non-PR jobs 18 | concurrency: 19 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 20 | env: 21 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 22 | permissions: 23 | contents: write 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - uses: r-lib/actions/setup-pandoc@v2 28 | 29 | - uses: r-lib/actions/setup-r@v2 30 | with: 31 | use-public-rspm: true 32 | 33 | - uses: r-lib/actions/setup-r-dependencies@v2 34 | with: 35 | extra-packages: any::pkgdown, local::. 36 | needs: website 37 | 38 | - name: Build site 39 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 40 | shell: Rscript {0} 41 | 42 | - name: Deploy to GitHub pages 🚀 43 | if: github.event_name != 'pull_request' 44 | uses: JamesIves/github-pages-deploy-action@v4.4.1 45 | with: 46 | clean: false 47 | branch: gh-pages 48 | folder: docs 49 | -------------------------------------------------------------------------------- /.github/workflows/pr-commands.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | name: Commands 8 | 9 | jobs: 10 | document: 11 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }} 12 | name: document 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - uses: r-lib/actions/pr-fetch@v2 20 | with: 21 | repo-token: ${{ secrets.GITHUB_TOKEN }} 22 | 23 | - uses: r-lib/actions/setup-r@v2 24 | with: 25 | use-public-rspm: true 26 | 27 | - uses: r-lib/actions/setup-r-dependencies@v2 28 | with: 29 | extra-packages: any::roxygen2 30 | needs: pr-document 31 | 32 | - name: Document 33 | run: roxygen2::roxygenise() 34 | shell: Rscript {0} 35 | 36 | - name: commit 37 | run: | 38 | git config --local user.name "$GITHUB_ACTOR" 39 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 40 | git add man/\* NAMESPACE 41 | git commit -m 'Document' 42 | 43 | - uses: r-lib/actions/pr-push@v2 44 | with: 45 | repo-token: ${{ secrets.GITHUB_TOKEN }} 46 | 47 | style: 48 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }} 49 | name: style 50 | runs-on: ubuntu-latest 51 | env: 52 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 53 | steps: 54 | - uses: actions/checkout@v3 55 | 56 | - uses: r-lib/actions/pr-fetch@v2 57 | with: 58 | repo-token: ${{ secrets.GITHUB_TOKEN }} 59 | 60 | - uses: r-lib/actions/setup-r@v2 61 | 62 | - name: Install dependencies 63 | run: install.packages("styler") 64 | shell: Rscript {0} 65 | 66 | - name: Style 67 | run: styler::style_pkg() 68 | shell: Rscript {0} 69 | 70 | - name: commit 71 | run: | 72 | git config --local user.name "$GITHUB_ACTOR" 73 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 74 | git add \*.R 75 | git commit -m 'Style' 76 | 77 | - uses: r-lib/actions/pr-push@v2 78 | with: 79 | repo-token: ${{ secrets.GITHUB_TOKEN }} 80 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage 10 | 11 | jobs: 12 | test-coverage: 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - uses: r-lib/actions/setup-r@v2 21 | with: 22 | use-public-rspm: true 23 | 24 | - uses: r-lib/actions/setup-r-dependencies@v2 25 | with: 26 | needs: coverage 27 | 28 | - name: Setup 29 | run: | 30 | R CMD INSTALL . 31 | source shim_package.sh 32 | 33 | - name: Test coverage 34 | run: | 35 | covr::codecov( 36 | quiet = FALSE, 37 | clean = FALSE, 38 | install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package") 39 | ) 40 | shell: Rscript {0} 41 | 42 | - name: Show testthat output 43 | if: always() 44 | run: | 45 | ## -------------------------------------------------------------------- 46 | find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true 47 | shell: bash 48 | 49 | - name: Upload test results 50 | if: failure() 51 | uses: actions/upload-artifact@v4 52 | with: 53 | name: coverage-test-failures 54 | path: ${{ runner.temp }}/package 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | inst/doc 4 | .Rproj.user 5 | covr.Rproj 6 | cache/ 7 | data.Rmd 8 | vignettes/covr_performance.Rmd 9 | revdep/checks 10 | revdep/library 11 | docs/ 12 | script.R 13 | .Rhistory 14 | -------------------------------------------------------------------------------- /.lintr: -------------------------------------------------------------------------------- 1 | linters: linters_with_defaults(line_length_linter(120)) 2 | exclusions: list("inst/doc/how_it_works.R") 3 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Encoding: UTF-8 2 | Package: covr 3 | Title: Test Coverage for Packages 4 | Version: 3.6.4.9004 5 | Authors@R: c( 6 | person("Jim", "Hester", email = "james.f.hester@gmail.com", role = c("aut", "cre")), 7 | person("Willem", "Ligtenberg", role = "ctb"), 8 | person("Kirill", "Müller", role = "ctb"), 9 | person("Henrik", "Bengtsson", role = "ctb"), 10 | person("Steve", "Peak", role = "ctb"), 11 | person("Kirill", "Sevastyanenko", role = "ctb"), 12 | person("Jon", "Clayden", role = "ctb"), 13 | person("Robert", "Flight", role = "ctb"), 14 | person("Eric", "Brown", role = "ctb"), 15 | person("Brodie", "Gaslam", role = "ctb"), 16 | person("Will", "Beasley", role = "ctb"), 17 | person("Robert", "Krzyzanowski", role = "ctb"), 18 | person("Markus", "Wamser", role = "ctb"), 19 | person("Karl", "Forner", role = "ctb"), 20 | person("Gergely", "Daróczi", role = "ctb"), 21 | person("Jouni", "Helske", role = "ctb"), 22 | person("Kun", "Ren", role = "ctb"), 23 | person("Jeroen", "Ooms", role = "ctb"), 24 | person("Ken", "Williams", role = "ctb"), 25 | person("Chris", "Campbell", role = "ctb"), 26 | person("David", "Hugh-Jones", role = "ctb"), 27 | person("Qin", "Wang", role = "ctb"), 28 | person("Doug", "Kelkhoff", role = "ctb"), 29 | person("Ivan", "Sagalaev", role = c("ctb", "cph"), comment = "highlight.js library"), 30 | person("Mark", "Otto", role = "ctb", comment = "Bootstrap library"), 31 | person("Jacob", "Thornton", role = "ctb", comment = "Bootstrap library"), 32 | person(family = "Bootstrap contributors", role = "ctb", comment = "Bootstrap library"), 33 | person(family = "Twitter, Inc", role = "cph", comment = "Bootstrap library") 34 | ) 35 | Description: Track and report code coverage for your package and (optionally) 36 | upload the results to a coverage service like 'Codecov' or 37 | 'Coveralls' . Code coverage is a measure of the amount of 38 | code being exercised by a set of tests. It is an indirect measure of test 39 | quality and completeness. This package is compatible with any testing 40 | methodology or framework and tracks coverage of both R code and compiled 41 | C/C++/FORTRAN code. 42 | URL: https://covr.r-lib.org, https://github.com/r-lib/covr 43 | BugReports: https://github.com/r-lib/covr/issues 44 | Depends: 45 | R (>= 3.1.0), 46 | methods 47 | Imports: 48 | digest, 49 | stats, 50 | utils, 51 | jsonlite, 52 | rex, 53 | httr, 54 | cli, 55 | withr (>= 1.0.2), 56 | yaml 57 | Suggests: 58 | R6, 59 | S7 (>= 0.2.0), 60 | curl, 61 | knitr, 62 | rmarkdown, 63 | htmltools, 64 | DT (>= 0.2), 65 | testthat (>= 3.0.0), 66 | rlang, 67 | rstudioapi (>= 0.2), 68 | xml2 (>= 1.0.0), 69 | parallel, 70 | memoise, 71 | covr, 72 | box (>= 1.2.0) 73 | License: MIT + file LICENSE 74 | VignetteBuilder: knitr 75 | RoxygenNote: 7.3.2 76 | Roxygen: list(markdown = TRUE) 77 | Config/testthat/edition: 3 78 | Config/testthat/parallel: TRUE 79 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2022 2 | COPYRIGHT HOLDER: covr authors 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2022 covr authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | RCHECKER=docker_checker 2 | FILTER= 3 | 4 | # to install test packages, code must be compiled inside src/ dir, 5 | # that may cause problems for docker user docker 6 | # so we grant all permissions 7 | fix-permission-tests: 8 | chmod -R a+rwx tests 9 | 10 | 11 | build-docker-checker: 12 | docker build -t $(RCHECKER) docker_checker 13 | 14 | run-rocker: build-docker-checker 15 | -docker rm $(RCHECKER) 16 | docker run --rm -ti -v $(PWD)/..:/home/docker $(RCHECKER) bash 17 | 18 | test: build-docker-checker fix-permission-tests 19 | docker run --rm -ti -v $(PWD)/..:/home/docker $(RCHECKER) Rscript -e 'library(devtools);install("covr");test("covr", "$(FILTER)")' 20 | 21 | 22 | check: build-docker-checker fix-permission-tests 23 | docker run --rm -ti -v $(PWD)/..:/home/docker $(RCHECKER) Rscript -e 'library(devtools);install("covr");devtools::check("covr")' 24 | 25 | 26 | rox: build-docker-checker 27 | docker run --rm -ti -v $(PWD)/..:/home/docker $(RCHECKER) Rscript -e 'devtools::document("covr")' 28 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method("[",coverage) 4 | S3method(as.data.frame,coverage) 5 | S3method(markers,coverage) 6 | S3method(markers,coverages) 7 | S3method(markers,data.frame) 8 | S3method(merge_coverage,character) 9 | S3method(merge_coverage,list) 10 | S3method(print,coverage) 11 | S3method(print,coverages) 12 | S3method(value,coverage) 13 | S3method(value,expression_coverage) 14 | S3method(value,expression_coverages) 15 | S3method(value,line_coverage) 16 | S3method(value,line_coverages) 17 | export(azure) 18 | export(code_coverage) 19 | export(codecov) 20 | export(coverage_to_list) 21 | export(coveralls) 22 | export(display_name) 23 | export(environment_coverage) 24 | export(file_coverage) 25 | export(file_report) 26 | export(function_coverage) 27 | export(gitlab) 28 | export(in_covr) 29 | export(package_coverage) 30 | export(percent_coverage) 31 | export(report) 32 | export(tally_coverage) 33 | export(to_cobertura) 34 | export(to_sonarqube) 35 | export(value) 36 | export(zero_coverage) 37 | import(methods) 38 | importFrom(httr,RETRY) 39 | importFrom(httr,content) 40 | importFrom(httr,upload_file) 41 | importFrom(stats,aggregate) 42 | importFrom(stats,na.omit) 43 | importFrom(stats,na.pass) 44 | importFrom(stats,setNames) 45 | importFrom(utils,capture.output) 46 | importFrom(utils,getParseData) 47 | importFrom(utils,getSrcDirectory) 48 | importFrom(utils,getSrcFilename) 49 | importFrom(utils,getSrcref) 50 | importFrom(utils,head) 51 | importFrom(utils,relist) 52 | importFrom(utils,str) 53 | importFrom(utils,tail) 54 | useDynLib(covr, .registration = TRUE) 55 | -------------------------------------------------------------------------------- /R/R6.R: -------------------------------------------------------------------------------- 1 | replacements_R6 <- function(env) { 2 | unlist(recursive = FALSE, eapply(env, all.names = TRUE, 3 | function(obj) { 4 | if (inherits(obj, "R6ClassGenerator")) { 5 | traverse_R6(obj, env) 6 | } 7 | })) 8 | } 9 | 10 | traverse_R6 <- function(obj, env) { 11 | unlist(recursive = FALSE, eapply(obj, 12 | function(o) { 13 | if (inherits(o, "list")) { 14 | lapply(names(o), 15 | function(f_name) { 16 | f <- get(f_name, o) 17 | if (inherits(f, "function")) { 18 | replacement(f_name, env = env, target_value = f) 19 | } 20 | }) 21 | } 22 | })) 23 | } 24 | -------------------------------------------------------------------------------- /R/RC.R: -------------------------------------------------------------------------------- 1 | replacements_RC <- function(env) { 2 | pat <- paste0("^", classMetaName("")) 3 | unlist(recursive = FALSE, lapply(ls(env, pattern = pat, all.names = TRUE), 4 | function(name) { 5 | class <- get(name, env) 6 | if (extends(class, "envRefClass")) { 7 | lapply(ls(class@refMethods, all.names = TRUE), replacement, env = class@refMethods) 8 | } 9 | })) 10 | } 11 | -------------------------------------------------------------------------------- /R/S4.R: -------------------------------------------------------------------------------- 1 | replacements_S4 <- function(env) { 2 | generics <- getGenerics(env) 3 | 4 | unlist(recursive = FALSE, 5 | Map(generics@.Data, generics@package, USE.NAMES = FALSE, 6 | f = function(name, package) { 7 | what <- methodsPackageMetaName("T", paste(name, package, sep = ":")) 8 | 9 | table <- get(what, envir = env) 10 | 11 | lapply(ls(table, all.names = TRUE), replacement, env = table) 12 | }) 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /R/S7.R: -------------------------------------------------------------------------------- 1 | replacements_S7 <- function(env) { 2 | bindings <- unlist(recursive = FALSE, use.names = FALSE, eapply(env, all.names = TRUE, 3 | function(obj) { 4 | if (inherits(obj, "S7_generic")) { 5 | traverse_S7_generic(obj) 6 | } else if (inherits(obj, "S7_class")) { 7 | traverse_S7_class(obj) 8 | } 9 | })) 10 | 11 | S7_methods_tbl <- attr(env[[".__S3MethodsTable__."]], "S7methods", exact = TRUE) 12 | external_methods <- lapply(seq_along(S7_methods_tbl), function(i) { 13 | entry <- S7_methods_tbl[[i]] 14 | name <- external_generic_method_signature(entry$generic, entry$signature) 15 | 16 | replacement( 17 | # `name` is for informative printouts only. 18 | # It is not used by covr, and does not need to be unique, 19 | name = name, 20 | env = entry, 21 | target_value = entry$method) 22 | }) 23 | 24 | c(bindings, external_methods) 25 | } 26 | 27 | traverse_S7_generic <- function(x) { 28 | # Each binding in the environment at x@methods is either a function or, for 29 | # generics that dispatch on multiple arguments, another environment. 30 | get_replacements <- function(env) { 31 | replacements <- lapply(names(env), function(name) { 32 | target_value <- get(name, envir = env) 33 | if (is.environment(target_value)) { 34 | # Recurse for nested environments 35 | get_replacements(target_value) 36 | } else { 37 | name <- as.character(attr(target_value, "name", exact = TRUE) %||% name) 38 | list(replacement(name, env, target_value)) 39 | } 40 | }) 41 | unlist(replacements, recursive = FALSE, use.names = FALSE) 42 | } 43 | get_replacements(S7::prop(x, "methods")) 44 | } 45 | 46 | traverse_S7_class <- function(x) { 47 | class_name <- S7::prop(x, "name") 48 | prop_fun_replacements <- 49 | lapply(S7::prop(x, "properties"), function(p) { 50 | lapply(c("getter", "setter", "validator"), function(prop_fun) { 51 | if (!is.null(p[[prop_fun]])) { 52 | replacement( 53 | sprintf("%s@properties$%s$%s", class_name, p$name, prop_fun), 54 | env = p, 55 | target_value = p[[prop_fun]]) 56 | } 57 | }) 58 | }) 59 | prop_fun_replacements <- unlist(prop_fun_replacements, recursive = FALSE, use.names = FALSE) 60 | 61 | c( 62 | list( 63 | replacement(paste0(class_name, "@constructor"), env = x, target_value = S7::prop(x, "constructor")), 64 | replacement(paste0(class_name, "@validator") , env = x, target_value = S7::prop(x, "validator")) 65 | ), 66 | prop_fun_replacements 67 | ) 68 | } 69 | 70 | 71 | external_generic_method_signature <- function(generic, signature) { 72 | # This function is a lightly modified copy of S7:::method_signature() for external generics 73 | display_generic <- paste0(c(generic$package, generic$name), collapse = "::") 74 | class_deparse <- asNamespace("S7")$class_deparse # not exported from S7 :/ 75 | single <- length(generic$dispatch_args) == 1 76 | if (single) { 77 | signature <- class_deparse(signature[[1]]) 78 | } else { 79 | classes <- vapply(signature, class_deparse, "", USE.NAMES = FALSE) 80 | signature <- paste0("list(", paste0(classes, collapse = ", "), ")") 81 | } 82 | 83 | sprintf("method(%s, %s)", display_generic, signature) 84 | } 85 | -------------------------------------------------------------------------------- /R/azure.R: -------------------------------------------------------------------------------- 1 | #' Run covr on a package and output the result so it is available on Azure Pipelines 2 | #' @inheritParams codecov 3 | #' @inheritParams to_cobertura 4 | #' @export 5 | azure <- function( 6 | ..., 7 | coverage = package_coverage(..., quiet = quiet), filename = "coverage.xml", quiet = TRUE) { 8 | 9 | to_cobertura(coverage, filename = filename) 10 | } 11 | -------------------------------------------------------------------------------- /R/box.R: -------------------------------------------------------------------------------- 1 | replacements_box <- function(env) { 2 | unlist(recursive = FALSE, eapply(env, all.names = TRUE, 3 | function(obj) { 4 | if (inherits(attr(obj, "spec"), "box$mod_spec")) { 5 | obj_impl <- attr(obj, "namespace") 6 | compact( 7 | c( 8 | lapply(ls(obj_impl), 9 | function(f_name) { 10 | f <- get(f_name, obj_impl) 11 | if (inherits(f, "function")) { 12 | replacement(f_name, env = obj, target_value = f) 13 | } 14 | } 15 | ), 16 | unlist(recursive = FALSE, 17 | lapply(ls(obj_impl), 18 | function(f_name) { 19 | f <- get(f_name, obj_impl) 20 | if (inherits(f, "R6ClassGenerator")) { 21 | traverse_R6(f, obj) 22 | } 23 | } 24 | ) 25 | ) 26 | ) 27 | ) 28 | } 29 | } 30 | ) 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /R/cobertura.R: -------------------------------------------------------------------------------- 1 | #' Create a Cobertura XML file 2 | #' 3 | #' Create a 4 | #' cobertura-compliant XML report following [this 5 | #' DTD](https://github.com/cobertura/cobertura/blob/master/cobertura/src/site/htdocs/xml/coverage-04.dtd). 6 | #' Because there are _two_ DTDs called `coverage-04.dtd` and some tools do not seem to 7 | #' adhere to either of them, the parser you're using may balk at the file. Please see 8 | #' [this github discussion](https://github.com/cobertura/cobertura/issues/425) for 9 | #' context. Where `covr` doesn't provide a coverage metric (branch coverage, 10 | #' complexity), a zero is reported. 11 | #' 12 | #' *Note*: This functionality requires the xml2 package be installed. 13 | #' 14 | #' @param cov the coverage object returned from [package_coverage()] 15 | #' @param filename the name of the Cobertura XML file 16 | #' @export 17 | to_cobertura <- function(cov, filename = "cobertura.xml") { 18 | 19 | loadNamespace("xml2") 20 | 21 | df <- tally_coverage(cov, by = "line") 22 | percent_overall <- percent_coverage(df, by = "line") / 100 23 | percent_per_file <- tapply(df$value, df$filename, FUN = function(x) (sum(x > 0) / length(x))) 24 | percent_per_function <- tapply(df$value, df$functions, FUN = function(x) (sum(x > 0) / length(x))) 25 | lines_valid <- nrow(df) 26 | lines_covered <- sum(df$value > 0) 27 | 28 | d <- xml2::xml_new_document() 29 | 30 | xml2::xml_add_child(d, xml2::xml_dtd( 31 | name = "coverage", 32 | system_id = "https://raw.githubusercontent.com/cobertura/cobertura/master/cobertura/src/site/htdocs/xml/coverage-04.dtd" 33 | )) 34 | top <- xml2::xml_add_child(d, 35 | "coverage", 36 | "line-rate" = as.character(percent_overall), 37 | "branch-rate" = "0", 38 | `lines-covered` = as.character(lines_covered), 39 | `lines-valid` = as.character(lines_valid), 40 | `branches-covered` = "0", 41 | `branches-valid` = "0", 42 | complexity = 0, 43 | version = as.character(utils::packageVersion("covr")), 44 | timestamp = as.character(Sys.time())) 45 | 46 | # Add sources 47 | sources <- xml2::xml_add_child(top, "sources") 48 | source_pth <- attr(cov, "package")$path %||% attr(cov, "root") 49 | if (!is.null(source_pth)) { 50 | xml2::xml_add_child(sources, "source", xml2::xml_cdata(source_pth)) 51 | } 52 | 53 | files <- unique(df$filename) 54 | #for (f in files){ 55 | #xml2::xml_add_child(sources, "source", f) 56 | #} 57 | 58 | # Add packages 59 | packages <- xml2::xml_add_child(top, "packages") 60 | package <- xml2::xml_add_child(packages, "package", 61 | name = attr(cov, "package")$package, 62 | "line-rate" = as.character(percent_overall), 63 | "branch-rate" = "0", 64 | complexity = "0") 65 | 66 | classes <- xml2::xml_add_child(package, "classes") 67 | 68 | # Add classes (for which we will use files for now) 69 | for (f in files){ 70 | class <- xml2::xml_add_child(classes, "class", 71 | name = basename(f), 72 | filename = f, 73 | "line-rate" = as.character(percent_per_file[f]), 74 | "branch-rate" = "0", 75 | complexity = "0") 76 | 77 | # Add methods for all lines with functions 78 | methods <- xml2::xml_add_child(class, "methods") 79 | 80 | for (fun_name in unique(na.omit(df[df$filename == f, "functions"]))) { 81 | fun <- xml2::xml_add_child(methods, "method", 82 | name = fun_name, 83 | signature = "", 84 | "line-rate" = as.character(percent_per_function[fun_name]), 85 | "branch-rate" = "0", 86 | "complexity" = "0") 87 | 88 | # Add lines 89 | lines <- xml2::xml_add_child(fun, "lines") 90 | fun_lines <- which(df$functions == fun_name) 91 | for (i in fun_lines){ 92 | line <- df[i, ] 93 | xml2::xml_add_child(lines, "line", 94 | number = as.character(line$line), 95 | hits = as.character(line$value), 96 | branch = "false") 97 | } 98 | } 99 | 100 | # Add lines for "class" 101 | class_lines <- xml2::xml_add_child(class, "lines") 102 | file_lines <- which(df$filename == f) 103 | for (i in file_lines) { 104 | line <- df[i, ] 105 | xml2::xml_add_child(class_lines, "line", 106 | number = as.character(line$line), 107 | hits = as.character(line$value), 108 | branch = "false") 109 | } 110 | } 111 | 112 | xml2::write_xml(d, file = filename) 113 | 114 | invisible(d) 115 | } 116 | -------------------------------------------------------------------------------- /R/compiled.R: -------------------------------------------------------------------------------- 1 | # this does not handle LCOV_EXCL_START ect. 2 | parse_gcov <- function(file, package_path = "") { 3 | if (!file.exists(file)) { 4 | return(NULL) 5 | } 6 | 7 | lines <- readLines(file) 8 | source_file <- rex::re_matches(lines[1], rex::rex("Source:", capture(name = "source", anything)))$source 9 | 10 | # retrieve full path to the source files 11 | source_file <- normalize_path(source_file) 12 | 13 | # If the source file does not start with the package path or does not exist ignore it. 14 | if (!file.exists(source_file) || !grepl(rex::rex(start, rex::regex(paste0(rex::escape(package_path), collapse = "|"))), source_file)) { 15 | return(NULL) 16 | } 17 | 18 | re <- rex::rex(any_spaces, 19 | capture(name = "coverage", some_of(digit, "-", "#", "=")), 20 | ":", any_spaces, 21 | capture(name = "line", digits), 22 | ":" 23 | ) 24 | 25 | matches <- rex::re_matches(lines, re) 26 | 27 | # Exclude lines with no match to the pattern 28 | lines <- lines[!is.na(matches$coverage)] 29 | matches <- na.omit(matches) 30 | 31 | # gcov lines which have no coverage 32 | matches$coverage[matches$coverage == "#####"] <- 0 # nolint 33 | 34 | # gcov lines which have parse error, so make untracked 35 | matches$coverage[matches$coverage == "====="] <- "-" 36 | 37 | coverage_lines <- matches$line != "0" & matches$coverage != "-" 38 | matches <- matches[coverage_lines, ] 39 | 40 | values <- as.numeric(matches$coverage) 41 | 42 | if (any(is.na(values))) { 43 | stop("values could not be coerced to numeric ", matches$coverage) 44 | } 45 | 46 | # There are no functions for gcov, so we set everything to NA 47 | functions <- rep(NA_character_, length(values)) 48 | 49 | line_coverages(source_file, matches, values, functions) 50 | } 51 | 52 | # for mocking 53 | readLines <- NULL 54 | file.exists <- NULL 55 | 56 | clean_gcov <- function(path) { 57 | src_dir <- file.path(path, "src") 58 | 59 | gcov_files <- list.files(src_dir, 60 | pattern = rex::rex(or(".gcda", ".gcno", ".gcov"), end), 61 | full.names = TRUE, 62 | recursive = TRUE) 63 | 64 | unlink(gcov_files) 65 | } 66 | 67 | run_gcov <- function(path, quiet = TRUE, clean = TRUE, 68 | gcov_path = getOption("covr.gcov", ""), 69 | gcov_args = getOption("covr.gcov_args", NULL)) { 70 | src_path <- normalize_path(file.path(path, "src")) 71 | if (!file.exists(src_path)) { 72 | return() 73 | } 74 | 75 | gcov_inputs <- list.files(path, pattern = rex::rex(".gcno", end), recursive = TRUE, full.names = TRUE) 76 | if (!nzchar(gcov_path)) { 77 | if (length(gcov_inputs)) stop('gcov not found') 78 | return() 79 | } 80 | run_gcov_one <- function(src) { 81 | system_check(gcov_path, 82 | args = c(gcov_args, src, "-p", "-o", dirname(src)), 83 | quiet = quiet, echo = !quiet) 84 | gcov_outputs <- list.files(path, pattern = rex::rex(".gcov", end), recursive = TRUE, full.names = TRUE) 85 | if (clean) { 86 | on.exit(unlink(gcov_outputs)) 87 | } 88 | unlist(lapply(gcov_outputs, parse_gcov, package_path = c(path, getOption("covr.gcov_additional_paths", NULL))), recursive = FALSE) 89 | } 90 | 91 | res <- withr::with_dir(src_path, { 92 | compact(unlist(lapply(gcov_inputs, run_gcov_one), recursive = FALSE)) 93 | }) 94 | if (!length(res) && length(gcov_inputs)) 95 | warning('parsed gcov output was empty') 96 | res 97 | } 98 | 99 | line_coverages <- function(source_file, matches, values, functions) { 100 | 101 | # create srcfile reference from the source file 102 | src_file <- srcfilecopy(source_file, readLines(source_file)) 103 | 104 | line_lengths <- vapply(src_file$lines[as.numeric(matches$line)], nchar, numeric(1)) 105 | 106 | res <- Map(function(line, length, value, func) { 107 | src_ref <- srcref(src_file, c(line, 1, line, length)) 108 | res <- list(srcref = src_ref, value = value, functions = func) 109 | class(res) <- "line_coverage" 110 | res 111 | }, 112 | matches$line, line_lengths, values, functions) 113 | 114 | if (!length(res)) { 115 | return(NULL) 116 | } 117 | 118 | names(res) <- lapply(res, function(x) key(x$srcref)) 119 | 120 | class(res) <- "line_coverages" 121 | res 122 | } 123 | -------------------------------------------------------------------------------- /R/coveralls.R: -------------------------------------------------------------------------------- 1 | #' Run covr on a package and upload the result to coveralls 2 | #' @param coverage an existing coverage object to submit, if `NULL`, 3 | #' [package_coverage()] will be called with the arguments from 4 | #' `...` 5 | #' @param ... arguments passed to [package_coverage()] 6 | #' @param repo_token The secret repo token for your repository, 7 | #' found at the bottom of your repository's page on Coveralls. This is useful 8 | #' if your job is running on a service Coveralls doesn't support out-of-the-box. 9 | #' If set to NULL, it is assumed that the job is running on travis-ci 10 | #' @param service_name the CI service to use, if environment variable 11 | #' \sQuote{CI_NAME} is set that is used, otherwise \sQuote{travis-ci} is used. 12 | #' @param quiet if `FALSE`, print the coverage before submission. 13 | #' @export 14 | coveralls <- function(..., coverage = NULL, 15 | repo_token = Sys.getenv("COVERALLS_TOKEN"), 16 | service_name = Sys.getenv("CI_NAME", "travis-ci"), 17 | quiet = TRUE) { 18 | 19 | if (is.null(coverage)) { 20 | coverage <- package_coverage(..., quiet = quiet) 21 | } 22 | 23 | if (!quiet) { 24 | print(coverage) 25 | } 26 | 27 | service <- tolower(service_name) 28 | 29 | coveralls_url <- "https://coveralls.io/api/v1/jobs" 30 | coverage_json <- to_coveralls(coverage, 31 | repo_token = repo_token, service_name = service) 32 | 33 | result <- RETRY("POST", url = coveralls_url, 34 | body = list(json_file = upload_file(to_file(coverage_json)))) 35 | 36 | content <- content(result) 37 | if (isTRUE(content$error)) { 38 | stop("Failed to upload coverage data. Reply by Coveralls: ", content$message) 39 | } 40 | content 41 | } 42 | 43 | to_file <- function(x) { 44 | name <- temp_file() 45 | con <- file(name) 46 | writeChar(con = con, x, eos = NULL) 47 | close(con) 48 | name 49 | } 50 | 51 | to_coveralls <- function(x, service_job_id = Sys.getenv("TRAVIS_JOB_ID"), 52 | service_name, repo_token = "") { 53 | 54 | coverages <- per_line(x) 55 | 56 | res <- Map(function(coverage, name) { 57 | source_code <- paste(collapse = "\n", coverage$file$file_lines) 58 | list( 59 | "name" = jsonlite::unbox(name), 60 | "source" = jsonlite::unbox(source_code), 61 | "source_digest" = jsonlite::unbox(digest::digest(source_code, algo = "md5", serialize = FALSE)), 62 | "coverage" = coverage$coverage) 63 | }, coverages, names(coverages), USE.NAMES = FALSE) 64 | 65 | git_info <- switch(service_name, 66 | drone = jenkins_git_info(), # drone has the same env vars as jenkins 67 | jenkins = jenkins_git_info(), 68 | 'travis-pro' = jenkins_git_info(), 69 | list(NULL) 70 | ) 71 | 72 | payload <- if (!nzchar(repo_token)) { 73 | list( 74 | "service_job_id" = jsonlite::unbox(service_job_id), 75 | "service_name" = jsonlite::unbox(service_name), 76 | "source_files" = res) 77 | } else { 78 | tmp <- list( 79 | "repo_token" = jsonlite::unbox(repo_token), 80 | "service_name" = jsonlite::unbox(service_name), 81 | "source_files" = res) 82 | tmp$git <- git_info 83 | tmp 84 | } 85 | 86 | jsonlite::toJSON(na = "null", payload) 87 | } 88 | 89 | jenkins_git_info <- function() { 90 | # check https://coveralls.zendesk.com/hc/en-us/articles/201350799-API-Reference 91 | # for why and how we are doing this 92 | formats <- c( 93 | id = "%H", 94 | author_name = "%an", 95 | author_email = "%ae", 96 | commiter_name = "%cn", 97 | commiter_email = "%ce", 98 | message = "%s" 99 | ) 100 | head <- lapply(structure( 101 | scan( 102 | sep = "\n", 103 | what = "character", 104 | text = system_output("git", c("log", "-n", "1", 105 | paste0("--pretty=format:", paste(collapse = "%n", formats))) 106 | ), 107 | quiet = TRUE 108 | ), 109 | names = names(formats) 110 | ), jsonlite::unbox) 111 | 112 | remotes <- list(list( 113 | name = jsonlite::unbox("origin"), 114 | url = jsonlite::unbox(Sys.getenv("CI_REMOTE")) 115 | )) 116 | 117 | c(list(branch = jsonlite::unbox(Sys.getenv("CI_BRANCH"))), 118 | head = list(head), 119 | remotes = list(remotes)) 120 | } 121 | -------------------------------------------------------------------------------- /R/data_frame.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | as.data.frame.coverage <- function(x, row.names = NULL, optional = FALSE, sort = TRUE, ...) { 3 | column_names <- c("filename", "functions", "first_line", "first_byte", "last_line", "last_byte", 4 | "first_column", "last_column", "first_parsed", 5 | "last_parsed", "value") 6 | 7 | res <- setNames(c(list(character(0)), rep(list(numeric(0)), times = length(column_names) - 1)), 8 | column_names) 9 | if (length(x)) { 10 | res$filename <- display_name(x) 11 | res$functions <- vcapply(x, function(xx) xx$functions[1]) 12 | 13 | vals <- t(vapply(x, 14 | function(xx) c(xx$srcref, xx$value), 15 | numeric(9), USE.NAMES = FALSE)) 16 | for (i in seq_len(NCOL(vals))) { 17 | res[[i + 2]] <- vals[, i] 18 | } 19 | } 20 | 21 | df <- data.frame(res, stringsAsFactors = FALSE, check.names = FALSE) 22 | 23 | if (sort) { 24 | # if we are sorting we no longer need to preserve the order of the input and can merge values together 25 | df <- merge_values(df) 26 | 27 | df <- df[order(df$filename, df$first_line, df$first_byte, df$last_line, df$last_byte), ] 28 | } 29 | 30 | rownames(df) <- NULL 31 | 32 | df 33 | } 34 | 35 | merge_values <- function(x, sentinel = "___NA___") { 36 | if (NROW(x) == 0) { 37 | return(x) 38 | } 39 | # We can't use aggregate directly, because it doesn't allow missing values in 40 | # grouping variables... 41 | x$functions[is.na(x$functions)] <- sentinel 42 | res <- aggregate(value ~ ., x, sum) 43 | res$functions[res$functions == sentinel] <- NA_character_ 44 | res 45 | } 46 | -------------------------------------------------------------------------------- /R/display_name.R: -------------------------------------------------------------------------------- 1 | #' Retrieve the path name (filename) for each coverage object 2 | #' 3 | #' @param x A coverage object 4 | #' @keywords internal 5 | #' @export 6 | display_name <- function(x) { 7 | stopifnot(inherits(x, "coverage")) 8 | if (length(x) == 0) { 9 | return() 10 | } 11 | 12 | filenames <- vcapply(x, function(x) get_source_filename(x$srcref, full.names = TRUE)) 13 | to_relative_path(filenames, attr(x, "root")) 14 | } 15 | 16 | to_relative_path <- function(path, base) { 17 | if (is.null(base)) { 18 | return(path) 19 | } 20 | rex::re_substitutes(path, rex::rex(base, "/"), "") 21 | } 22 | 23 | filter_non_package_files <- function(x) { 24 | filenames <- vcapply(x, function(x) get_source_filename(x$srcref, full.names = TRUE)) 25 | x[rex::re_matches(filenames, rex::rex(attr(x, "package")$path, "/"), "")] 26 | } 27 | -------------------------------------------------------------------------------- /R/gitlab.R: -------------------------------------------------------------------------------- 1 | #' Run covr on package and create report for GitLab 2 | #' 3 | #' Utilize internal GitLab static pages to publish package coverage. 4 | #' Creates local covr report in a package subdirectory. 5 | #' Uses the [pages](https://docs.gitlab.com/ee/ci/yaml/README.html#pages) 6 | #' GitLab job to publish the report. 7 | #' @inheritParams codecov 8 | #' @inheritParams report 9 | #' @export 10 | gitlab <- function(..., coverage = NULL, file = "public/coverage.html", quiet = TRUE) { 11 | if (is.null(coverage)) { 12 | coverage <- package_coverage(quiet = quiet, ...) 13 | } 14 | if (!quiet) { 15 | print(coverage) 16 | } 17 | 18 | out_file <- file.path(tempfile(), file) 19 | on.exit(unlink(out_dir, recursive = TRUE), add = TRUE) 20 | 21 | out_dir <- dirname(out_file) 22 | 23 | pkg_path <- attributes(coverage)$package$path 24 | 25 | report(coverage, file = out_file, browse = FALSE) 26 | 27 | file.copy(out_dir, pkg_path, recursive = TRUE) 28 | } 29 | -------------------------------------------------------------------------------- /R/icc.R: -------------------------------------------------------------------------------- 1 | parse_icov <- function(lines, package_path = "") { 2 | 3 | source_file <- trim_ws(lines[1L]) 4 | # If the source file does not start with the package path ignore it. 5 | if (!grepl(rex::rex(start, package_path), source_file)) { 6 | return(NULL) 7 | } 8 | 9 | # remove source file lines and empty/white space lines 10 | lines <- trim_ws(lines[-1L]) 11 | lines <- lines[lines != ""] 12 | 13 | # get line, values, and functions 14 | r1 <- rex::re_matches(lines, rex::rex("function - ", 15 | capture(name = "source", anything), 16 | "\t", digits, "\t", digits, "\t", digits, anything))$source 17 | idx1 <- which(!is.na(r1)) 18 | 19 | re <- rex::rex( 20 | capture(name = "instance", digits), "\t", 21 | capture(name = "line", digits), "\t", 22 | capture(name = "idcol", digits), "\t", any_spaces, 23 | capture(name = "coverage", digits)) 24 | 25 | show_C_functions <- getOption("covr.showCfunctions", FALSE) 26 | if (length(idx1) == 0L) { 27 | m1 <- rex::re_matches(lines, re) 28 | m1$functions <- rep(NA_character_, nrow(m1)) 29 | } else { 30 | m1 <- rex::re_matches(lines[-idx1], re) 31 | if (isTRUE(show_C_functions)) { 32 | # get function names 33 | if (length(idx1) == 1L) { 34 | m1$functions <- rep(r1[idx1], nrow(m1)) 35 | } else { 36 | stopifnot(idx1[1L] == 1L) 37 | nums <- c(idx1[2L:length(idx1)]-1L, length(r1)) - idx1 38 | stopifnot(sum(nums) == nrow(m1)) 39 | m1$functions <- unlist(mapply(rep, r1[idx1], nums, 40 | SIMPLIFY=FALSE, USE.NAMES=FALSE)) 41 | } 42 | } 43 | } 44 | # remove invalid rows if exists 45 | m1 <- na.omit(m1) 46 | m1$line <- as.numeric(m1$line) 47 | m1$coverage <- as.numeric(m1$coverage) 48 | if (is.null(m1$functions)) { 49 | m2 <- aggregate(m1$coverage, by = list(line=m1$line), sum) 50 | names(m2) <- c("line", "coverage") 51 | m2$functions <- NA_character_ 52 | } else { 53 | m2 <- aggregate(m1$coverage, 54 | by = list(line=m1$line, functions=m1$functions), sum) 55 | names(m2) <- c("line", "functions", "coverage") 56 | } 57 | matches <- m2[order(m2$line), ] 58 | 59 | values <- as.numeric(matches$coverage > 0L) 60 | functions <- matches$functions 61 | 62 | line_coverages(source_file, matches, values, functions) 63 | } 64 | 65 | run_icov <- function(path, quiet = TRUE, 66 | icov_path = getOption("covr.icov", ""), 67 | icov_args = getOption("covr.icov_args", NULL)) { 68 | 69 | src_path <- normalize_path(file.path(path, "src")) 70 | if (!file.exists(src_path)) { 71 | return() 72 | } 73 | 74 | if (!nzchar(icov_path)) { 75 | warning("icc codecov not available") 76 | return() 77 | } 78 | 79 | icov_profmerge <- getOption("covr.icov_prof", "") 80 | if (!nzchar(icov_profmerge)) { 81 | warning("icc profmerge not available") 82 | return() 83 | } 84 | 85 | icov_inputs <- list.files(path, pattern = rex::rex(".dyn", end), 86 | recursive = TRUE, full.names = TRUE) 87 | if (length(icov_inputs) == 0L) { 88 | warning("no icc .dyn files are generated") 89 | return() 90 | } 91 | 92 | system_check(icov_profmerge, 93 | args = c("-prof_dir", src_path), 94 | quiet = quiet, echo = !quiet) 95 | 96 | withr::with_dir(src_path, { 97 | system_check(icov_path, 98 | args = c("-prj", "tmp", "-spi", file.path(src_path, "pgopti.spi"), 99 | "-dpi", file.path(src_path, "pgopti.dpi"), 100 | "-include-nonexec", 101 | "-txtbcvrg", "bcovg.log"), 102 | quiet = quiet, echo = !quiet) 103 | }) 104 | 105 | lines <- readLines(file.path(src_path, "bcovg.log")) 106 | 107 | # generate line coverage 108 | re <- rex::re_matches(lines, rex::rex("Covered Functions in File: \"", 109 | capture(name = "source", anything), "\""))$source 110 | idx1 <- which(!is.na(re)) 111 | idx2 <- c(idx1[2:length(idx1)]-1, length(re)) 112 | srcfilenms <- re[idx1] 113 | lines[idx1] <- srcfilenms 114 | icov_outputs <- lapply(seq_along(idx1), function(i) lines[idx1[i]:idx2[i]]) 115 | 116 | structure( 117 | unlist(recursive = FALSE, 118 | lapply(icov_outputs, parse_icov, package_path = path)), 119 | class = "coverage") 120 | } 121 | 122 | # check if icc is used 123 | uses_icc <- function() { 124 | compiler <- tryCatch( 125 | { 126 | system2(file.path(R.home("bin"), "R"), 127 | args = c("--vanilla", "CMD", "config", "CC"), 128 | stdout = TRUE) 129 | }, 130 | warning = function(e) NA_character_) 131 | isTRUE(any(grepl("\\bicc\\b", compiler))) 132 | } 133 | -------------------------------------------------------------------------------- /R/parallel.R: -------------------------------------------------------------------------------- 1 | # utility function to replace a symbol in a locked loaded package/namespace 2 | replace_binding <- function(package, name, value) { 3 | ns <- getNamespace(package) 4 | unlock <- get('unlockBinding') # to fool r CMD check 5 | lock <- get('lockBinding') 6 | unlock(name, ns) 7 | assign(name, value, ns) 8 | lock(name, ns) 9 | } 10 | 11 | 12 | # patch parallel:::mcexit to force it to save the covr trace on exit 13 | fix_mcexit <- function(trace_dir) { 14 | get_from_ns <- `:::` # trick to fool R CMD check 15 | mcexit <- get_from_ns('parallel', 'mcexit') 16 | 17 | trace_dir <- parse(text = trace_dir)[[1]] 18 | 19 | # directly patch mcexit 20 | body(mcexit) <- as.call(append(after = 1, as.list(body(mcexit)), 21 | as.call(list(call(":::", as.symbol("covr"), as.symbol("save_trace")), trace_dir)))) 22 | 23 | replace_binding('parallel', 'mcexit', mcexit) 24 | } 25 | 26 | 27 | uses_parallel <- function(pkg) { 28 | any(grepl("\\bparallel\\b", 29 | pkg[c("depends", "imports", "suggests", "enhances", "linkingto")])) 30 | } 31 | 32 | on_windows <- function() { 33 | "windows" %in% tolower(Sys.info()[["sysname"]]) 34 | } 35 | 36 | # consider in that order: the environment variable COVR_FIX_PARALLEL_MCEXIT, 37 | # the option covr.fix_parallel_mcexit, or auto-detection of the usage of 38 | # parallel by the package (cf uses_parallel()). 39 | should_enable_parallel_mcexit_fix <- function(pkg) { 40 | isTRUE(!on_windows() && 41 | as.logical(Sys.getenv("COVR_FIX_PARALLEL_MCEXIT", 42 | getOption("covr.fix_parallel_mcexit", 43 | uses_parallel(pkg))))) 44 | } 45 | -------------------------------------------------------------------------------- /R/parse_data.R: -------------------------------------------------------------------------------- 1 | #' @importFrom utils getParseData getSrcref tail 2 | impute_srcref <- function(x, parent_ref) { 3 | if (!is_conditional_or_loop(x)) return(NULL) 4 | if (is.null(parent_ref)) return(NULL) 5 | 6 | pd <- get_tokens(parent_ref) 7 | pd_expr <- 8 | ( 9 | (pd$line1 == parent_ref[[1L]] & pd$line2 == parent_ref[[3L]]) | 10 | (pd$line1 == parent_ref[[7L]] & pd$line2 == parent_ref[[8L]]) 11 | ) & 12 | pd$col1 == parent_ref[[2L]] & 13 | pd$col2 == parent_ref[[4L]] & 14 | pd$token == "expr" 15 | pd_expr_idx <- which(pd_expr) 16 | if (length(pd_expr_idx) == 0L) return(NULL) # srcref not found in parse data 17 | 18 | if (length(pd_expr_idx) > 1) pd_expr_idx <- pd_expr_idx[[1]] 19 | 20 | expr_id <- pd$id[pd_expr_idx] 21 | pd_child <- pd[pd$parent == expr_id, ] 22 | pd_child <- pd_child[order(pd_child$line1, pd_child$col1), ] 23 | 24 | # exclude comments 25 | pd_child <- pd_child[pd_child$token != "COMMENT", ] 26 | 27 | if (pd$line1[pd_expr_idx] == parent_ref[[7L]] & pd$line2[pd_expr_idx] == parent_ref[[8L]]) { 28 | line_offset <- parent_ref[[7L]] - parent_ref[[1L]] 29 | } else { 30 | line_offset <- 0 31 | } 32 | 33 | make_srcref <- function(from, to = from) { 34 | if (length(from) == 0) { 35 | return(NULL) 36 | } 37 | 38 | srcref( 39 | attr(parent_ref, "srcfile"), 40 | c(pd_child$line1[from] - line_offset, 41 | pd_child$col1[from], 42 | pd_child$line2[to] - line_offset, 43 | pd_child$col2[to], 44 | pd_child$col1[from], 45 | pd_child$col2[to], 46 | pd_child$line1[from], 47 | pd_child$line2[to] 48 | ) 49 | ) 50 | } 51 | 52 | switch( 53 | as.character(x[[1L]]), 54 | "if" = { 55 | src_ref <- list( 56 | NULL, 57 | make_srcref(3), 58 | make_srcref(5), 59 | make_srcref(7) 60 | ) 61 | # the fourth component isn't used for an "if" without "else" 62 | src_ref[seq_along(x)] 63 | }, 64 | 65 | "for" = { 66 | list( 67 | NULL, 68 | NULL, 69 | make_srcref(2), 70 | make_srcref(3) 71 | ) 72 | }, 73 | 74 | "while" = { 75 | list( 76 | NULL, 77 | make_srcref(3), 78 | make_srcref(5) 79 | ) 80 | }, 81 | 82 | "switch" = { 83 | exprs <- tail(which(pd_child$token == "expr"), n = -1) 84 | 85 | # Add NULLs for drop through conditions 86 | token <- pd_child$token 87 | next_token <- c(tail(token, n = -1), NA_character_) 88 | drops <- which(token == "EQ_SUB" & next_token != "expr") 89 | 90 | exprs <- sort(c(exprs, drops)) 91 | 92 | ignore_drop_through <- function(x) { 93 | if (x %in% drops) { 94 | return(NULL) 95 | } 96 | x 97 | } 98 | 99 | exprs <- lapply(exprs, ignore_drop_through) 100 | 101 | # Don't create srcrefs for ... conditions 102 | ignore_dots <- function(x) { 103 | if (identical("...", pd$text[pd$parent == pd_child$id[x]])) { 104 | return(NULL) 105 | } 106 | x 107 | } 108 | 109 | exprs <- lapply(exprs, ignore_dots) 110 | 111 | c(list(NULL), lapply(exprs, make_srcref)) 112 | }, 113 | 114 | NULL 115 | ) 116 | } 117 | 118 | is_conditional_or_loop <- function(x) is.symbol(x[[1L]]) && as.character(x[[1L]]) %in% c("if", "for", "else", "switch") 119 | 120 | package_parse_data <- new.env() 121 | 122 | get_parse_data <- function(srcfile) { 123 | if (length(package_parse_data) == 0) { 124 | lines <- getSrcLines(srcfile, 1L, Inf) 125 | lines_split <- split_on_line_directives(lines) 126 | if (!length(lines_split)) { 127 | return(NULL) 128 | } 129 | 130 | res <- lapply(lines_split, 131 | function(x) getParseData(parse(text = x, keep.source = TRUE), includeText = TRUE)) 132 | for (i in seq_along(res)) { 133 | package_parse_data[[names(res)[[i]]]] <- res[[i]] 134 | } 135 | } 136 | package_parse_data[[srcfile[["filename"]]]] 137 | } 138 | 139 | clean_parse_data <- function() { 140 | rm(list = ls(package_parse_data), envir = package_parse_data) 141 | } 142 | 143 | get_tokens <- function(srcref) { 144 | # Before R 4.4.0, covr's custom get_parse_data is necessary because 145 | # utils::getParseData returns parse data for only the last file in the 146 | # package. That issue (bug#16756) is fixed in R 4.4.0 (r84538). 147 | # 148 | # On R 4.4.0, continue to use get_parse_data because covr's code expects the 149 | # result to be limited to the srcref file. getParseData will return parse data 150 | # for all of the package's files. 151 | get_parse_data(attr(getSrcref(srcref), "srcfile")) %||% 152 | # This covers the non-installed file case where the source file isn't a 153 | # concatenated file with "line N" directives. 154 | getParseData(srcref) 155 | } 156 | -------------------------------------------------------------------------------- /R/replace.R: -------------------------------------------------------------------------------- 1 | #' @useDynLib covr, .registration = TRUE 2 | replacement <- function(name, env = as.environment(-1), target_value = get(name, envir = env)) { 3 | if (is.function(target_value) && !is.primitive(target_value)) { 4 | if (is_vectorized(target_value)) { 5 | new_value <- target_value 6 | environment(new_value)$FUN <- trace_calls(environment(new_value)$FUN, name) 7 | } else if (is.function(target_value) && inherits(target_value, "memoised")) { 8 | new_value <- target_value 9 | environment(new_value)$`_f` <- trace_calls(environment(new_value)$`_f`, name) 10 | } else { 11 | new_value <- trace_calls(target_value, name) 12 | attributes(body(new_value)) <- attributes(body(target_value)) 13 | } 14 | attributes(new_value) <- attributes(target_value) 15 | 16 | if (isS4(target_value)) { 17 | new_value <- asS4(new_value) 18 | } 19 | 20 | list( 21 | env = env, 22 | name = as.name(name), 23 | orig_value = .Call(covr_duplicate_, target_value), 24 | target_value = target_value, 25 | new_value = new_value 26 | ) 27 | } 28 | } 29 | 30 | replace <- function(replacement) { 31 | .Call(covr_reassign_function, replacement$target_value, replacement$new_value) 32 | } 33 | 34 | reset <- function(replacement) { 35 | .Call(covr_reassign_function, replacement$target_value, replacement$orig_value) 36 | } 37 | -------------------------------------------------------------------------------- /R/sonarqube.R: -------------------------------------------------------------------------------- 1 | #' Create a SonarQube Generic XML file for test coverage according to 2 | #' https://docs.sonarqube.org/latest/analysis/generic-test/ 3 | #' Based on cobertura.R 4 | #' 5 | #' This functionality requires the xml2 package be installed. 6 | #' @param cov the coverage object returned from [package_coverage()] 7 | #' @param filename the name of the SonarQube Generic XML file 8 | #' @author Talkdesk Inc. 9 | #' @export 10 | to_sonarqube <- function(cov, filename = "sonarqube.xml"){ 11 | 12 | loadNamespace("xml2") 13 | 14 | df <- tally_coverage(cov, by = "line") 15 | 16 | d <- xml2::xml_new_document() 17 | 18 | top <- xml2::xml_add_child(d, "coverage", version = "1") 19 | 20 | files <- unique(df$filename) 21 | 22 | for (f in files){ 23 | file <- xml2::xml_add_child(top, "file", path = paste(attr(cov, "package")$package, "/", as.character(f), sep="")) 24 | 25 | for (fun_name in unique(na.omit(df[df$filename == f, "functions"]))) { 26 | fun_lines <- which(df$functions == fun_name & df$filename == f) 27 | for (i in fun_lines){ 28 | line <- df[i, ] 29 | xml2::xml_add_child(file, "lineToCover", lineNumber = as.character(line$line), 30 | covered = tolower(as.character(line$value>0))) 31 | } 32 | } 33 | } 34 | 35 | xml2::write_xml(d, file = filename) 36 | 37 | invisible(d) 38 | } 39 | -------------------------------------------------------------------------------- /R/system.R: -------------------------------------------------------------------------------- 1 | #' Run a system command and check if it succeeds. 2 | #' 3 | #' This function automatically quotes both the command and each 4 | #' argument so they are properly protected from shell expansion. 5 | #' @param cmd the command to run. 6 | #' @param args a vector of command arguments. 7 | #' @param env a named character vector of environment variables. Will be quoted 8 | #' @param quiet if `TRUE`, the command output will be echoed. 9 | #' @param echo if `TRUE`, the command to run will be echoed. 10 | #' @param ... additional arguments passed to [base::system()] 11 | #' @return `TRUE` if the command succeeds, an error will be thrown if the 12 | #' command fails. 13 | #' @keywords internal 14 | system_check <- function(cmd, args = character(), env = character(), 15 | quiet = FALSE, echo = FALSE, ...) { 16 | full <- paste(c(shQuote(cmd), lapply(args, shQuote)), collapse = " ") 17 | 18 | if (echo) { 19 | message(wrap_command(full), "\n") 20 | } 21 | 22 | status <- withr::with_envvar(env, 23 | system(full, intern = FALSE, ignore.stderr = quiet, ignore.stdout = quiet, ...) 24 | ) 25 | 26 | if (!identical(as.character(status), "0")) { 27 | stop("Command ", sQuote(full), " failed (", status, ")", call. = FALSE) 28 | } 29 | 30 | invisible(TRUE) 31 | } 32 | 33 | #' Run a system command and capture the output. 34 | #' 35 | #' This function automatically quotes both the command and each 36 | #' argument so they are properly protected from shell expansion. 37 | #' @inheritParams system_check 38 | #' @return command output if the command succeeds, an error will be thrown if 39 | #' the command fails. 40 | #' @keywords internal 41 | system_output <- function(cmd, args = character(), env = character(), 42 | quiet = FALSE, echo = FALSE, ...) { 43 | full <- paste(c(shQuote(cmd), lapply(args, shQuote)), collapse = " ") 44 | 45 | if (echo) { 46 | message(wrap_command(full), "\n") 47 | } 48 | result <- withCallingHandlers(withr::with_envvar(env, 49 | system(full, intern = TRUE, ignore.stderr = quiet, ...) 50 | ), warning = function(w) stop(w)) 51 | 52 | result 53 | } 54 | 55 | wrap_command <- function(x) { 56 | lines <- strwrap(x, getOption("width") - 2, exdent = 2) 57 | continue <- c(rep(" \\", length(lines) - 1), "") 58 | paste(lines, continue, collapse = "\n") 59 | } 60 | -------------------------------------------------------------------------------- /R/trace_calls.R: -------------------------------------------------------------------------------- 1 | #' trace each call with a srcref attribute 2 | #' 3 | #' This function calls itself recursively so it can properly traverse the AST. 4 | #' @param x the call 5 | #' @param parent_functions the functions which this call is a child of. 6 | #' @param parent_ref argument used to set the srcref of the current call during 7 | #' the recursion. 8 | #' @seealso 9 | #' @return a modified expression with count calls inserted before each previous 10 | #' call. 11 | #' @keywords internal 12 | trace_calls <- function (x, parent_functions = NULL, parent_ref = NULL) { 13 | 14 | # Construct the calls by hand to avoid a NOTE from R CMD check 15 | count <- function(key, val) { 16 | call("if", TRUE, 17 | call("{", 18 | as.call(list(call(":::", as.symbol("covr"), as.symbol("count")), key)), 19 | val 20 | ) 21 | ) 22 | } 23 | 24 | if (is.null(parent_functions)) { 25 | parent_functions <- deparse(substitute(x)) 26 | } 27 | recurse <- function(y) { 28 | lapply(y, trace_calls, parent_functions = parent_functions) 29 | } 30 | 31 | if (is.atomic(x) || is.name(x) || is.null(x)) { 32 | if (is.null(parent_ref)) { 33 | x 34 | } else { 35 | if (is_na(x) || is_brace(x)) { 36 | x 37 | } else { 38 | key <- new_counter(parent_ref, parent_functions) # nolint 39 | count(key, x) 40 | } 41 | } 42 | } else if (is.call(x)) { 43 | src_ref <- attr(x, "srcref") %||% impute_srcref(x, parent_ref) 44 | if ((identical(x[[1]], as.name("<-")) || identical(x[[1]], as.name("="))) && # nolint 45 | (is.call(x[[3]]) && identical(x[[3]][[1]], as.name("function")))) { 46 | parent_functions <- c(parent_functions, as.character(x[[2]])) 47 | } 48 | 49 | # do not try to trace curly curly 50 | if (identical(x[[1]], as.name("{")) && length(x) == 2 && is.call(x[[2]]) && identical(x[[2]][[1]], as.name("{"))) { 51 | as.call(x) 52 | } else if (!is.null(src_ref)) { 53 | as.call(Map(trace_calls, x, src_ref, MoreArgs = list(parent_functions = parent_functions))) 54 | } else if (!is.null(parent_ref)) { 55 | key <- new_counter(parent_ref, parent_functions) 56 | count(key, as.call(recurse(x))) 57 | } else { 58 | as.call(recurse(x)) 59 | } 60 | } else if (is.function(x)) { 61 | 62 | # We cannot trace primitive functions 63 | if (is.primitive(x)) { 64 | return(x) 65 | } 66 | 67 | fun_body <- body(x) 68 | 69 | if (!is.null(attr(x, "srcref")) && 70 | (is.symbol(fun_body) || !identical(fun_body[[1]], as.name("{")))) { 71 | src_ref <- attr(x, "srcref") 72 | key <- new_counter(src_ref, parent_functions) 73 | fun_body <- count(key, trace_calls(fun_body, parent_functions)) 74 | } else { 75 | fun_body <- trace_calls(fun_body, parent_functions) 76 | } 77 | 78 | new_formals <- trace_calls(formals(x), parent_functions) 79 | if (is.null(new_formals)) new_formals <- list() 80 | formals(x) <- new_formals 81 | body(x) <- fun_body 82 | x 83 | } else if (is.pairlist(x)) { 84 | as.pairlist(recurse(x)) 85 | } else if (is.expression(x)) { 86 | as.expression(recurse(x)) 87 | } else if (is.list(x)) { 88 | recurse(x) 89 | } else { 90 | message("Unknown language class: ", paste(class(x), collapse = "/")) 91 | x 92 | } 93 | } 94 | 95 | .counters <- new.env(parent = emptyenv()) 96 | .current_test <- new.env(parent = emptyenv()) 97 | 98 | #' initialize a new counter 99 | #' 100 | #' @param src_ref a [base::srcref()] 101 | #' @param parent_functions the functions that this srcref is contained in. 102 | #' @keywords internal 103 | new_counter <- function(src_ref, parent_functions) { 104 | key <- key(src_ref) 105 | .counters[[key]]$value <- 0 106 | .counters[[key]]$srcref <- src_ref 107 | .counters[[key]]$functions <- parent_functions 108 | if (isTRUE(getOption("covr.record_tests", FALSE))) new_test_counter(key) 109 | key 110 | } 111 | 112 | #' increment a given counter 113 | #' 114 | #' @param key generated with [key()] 115 | #' @keywords internal 116 | count <- function(key) { 117 | .counters[[key]]$value <- .counters[[key]]$value + 1L 118 | if (isTRUE(.current_test$record)) count_test(key) 119 | } 120 | 121 | #' clear all previous counters 122 | #' 123 | #' @keywords internal 124 | clear_counters <- function() { 125 | rm(envir = .counters, list = ls(envir = .counters)) 126 | rm(envir = .current_test, list = ls(envir = .current_test)) 127 | .current_test$record <- isTRUE(getOption("covr.record_tests", FALSE)) 128 | } 129 | 130 | #' Generate a key for a call 131 | #' 132 | #' @param x the srcref of the call to create a key for 133 | #' @keywords internal 134 | key <- function(x) { 135 | paste(collapse = ":", c(get_source_filename(x), x)) 136 | } 137 | -------------------------------------------------------------------------------- /R/value.R: -------------------------------------------------------------------------------- 1 | #' Retrieve the value from an object 2 | #' @export 3 | #' @param x object from which to retrieve the value 4 | #' @param ... additional arguments passed to methods 5 | value <- function(x, ...) UseMethod("value") 6 | 7 | #' @export 8 | value.coverage <- function(x, ...) { 9 | vdapply(x, value, ...) 10 | } 11 | 12 | #' @export 13 | value.expression_coverage <- function(x, ...) { 14 | x$value 15 | } 16 | 17 | #' @export 18 | value.expression_coverages <- value.coverage 19 | 20 | #' @export 21 | value.line_coverage <- value.expression_coverage 22 | 23 | #' @export 24 | value.line_coverages <- value.expression_coverages 25 | -------------------------------------------------------------------------------- /R/vectorized.R: -------------------------------------------------------------------------------- 1 | # simple function to test if a function is Vectorized 2 | is_vectorized <- function(x) { 3 | is.function(x) && exists("FUN", environment(x), mode = "function") && exists("vectorize.args", environment(x)) 4 | } 5 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | .onLoad <- function(libname, pkgname) { # nolint 2 | rex::register_shortcuts("covr") 3 | op <- options() 4 | op_covr <- list( 5 | covr.covrignore = Sys.getenv("COVR_COVRIGNORE", ".covrignore"), 6 | covr.gcov = Sys.which("gcov"), 7 | covr.gcov_args = NULL, 8 | covr.gcov_additional_paths = NULL, 9 | covr.exclude_pattern = rex::rex("#", any_spaces, "nocov"), 10 | covr.exclude_start = rex::rex("#", any_spaces, "nocov", any_spaces, "start"), 11 | covr.exclude_end = rex::rex("#", any_spaces, "nocov", any_spaces, "end"), 12 | covr.flags = c(CFLAGS = "-O0 --coverage", 13 | CXXFLAGS = "-O0 --coverage", 14 | CXX1XFLAGS = "-O0 --coverage", 15 | CXX11FLAGS = "-O0 --coverage", 16 | CXX14FLAGS = "-O0 --coverage", 17 | CXX17FLAGS = "-O0 --coverage", 18 | CXX20FLAGS = "-O0 --coverage", 19 | 20 | FFLAGS = "-O0 --coverage", 21 | FCFLAGS = "-O0 --coverage", 22 | FLIBS = "-lgcov", 23 | 24 | # LDFLAGS is ignored on windows and visa versa 25 | LDFLAGS = if (!is_windows()) "--coverage" else NULL, 26 | SHLIB_LIBADD = if (is_windows()) "--coverage" else NULL) 27 | ) 28 | 29 | # add icc code coverage settings 30 | icov_flag <- "-O0 -prof-gen=srcpos" 31 | op_covr <- c(op_covr, list( 32 | covr.icov = Sys.which("codecov"), 33 | covr.icov_args = NULL, 34 | covr.icov_prof = Sys.which("profmerge"), 35 | covr.icov_flags = c(CFLAGS = icov_flag, 36 | CXXFLAGS = icov_flag, 37 | CXX1XFLAGS = icov_flag, 38 | CXX11FLAGS = icov_flag, 39 | CXX14FLAGS = icov_flag, 40 | CXX17FLAGS = icov_flag, 41 | CXX20FLAGS = icov_flag, 42 | 43 | FFLAGS = icov_flag, 44 | FCFLAGS = icov_flag, 45 | 46 | # LDFLAGS is ignored on windows and visa versa 47 | LDFLAGS = icov_flag, 48 | SHLIB_LIBADD = icov_flag) 49 | )) 50 | 51 | toset <- !(names(op_covr) %in% names(op)) 52 | if (any(toset)) options(op_covr[toset]) 53 | 54 | invisible() 55 | } 56 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | Send an email to james.f.hester@gmail.com to report a vulnerability. 6 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://covr.r-lib.org 2 | 3 | authors: 4 | "Jim Hester": 5 | href: https://www.jimhester.com/ 6 | 7 | destination: docs 8 | 9 | development: 10 | mode: auto 11 | 12 | template: 13 | bootstrap: 5 14 | params: 15 | ganalytics: UA-115082821-1 16 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /covr.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | This is a patch release to fix a change made in R-devel 2 | 3 | ## R CMD check results 4 | There were no NOTEs, ERRORs or WARNINGs. 5 | -------------------------------------------------------------------------------- /docker_checker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rocker/hadleyverse 2 | MAINTAINER james.f.hester@gmail.com 3 | 4 | # install deps from current github master 5 | RUN Rscript -e 'devtools::install_github("jimhester/covr", dependencies = TRUE)' 6 | 7 | # remove installed covr to be sure not to conflict with current source version 8 | RUN Rscript -e 'remove.packages("covr")' 9 | 10 | # docker user setup 11 | RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo && \ 12 | chmod -R a+rwx /usr/local/lib/R/site-library 13 | 14 | USER docker 15 | WORKDIR /home/docker 16 | -------------------------------------------------------------------------------- /inst/rstudio/addins.dcf: -------------------------------------------------------------------------------- 1 | Name: Calculate package test coverage 2 | Description: Calculates the package test coverage and opens a report, using `covr::report()` 3 | Binding: addin_report 4 | Interactive: false 5 | -------------------------------------------------------------------------------- /inst/www/report.css: -------------------------------------------------------------------------------- 1 | table tr:hover td { 2 | font-weight:bold;text-decoration:none 3 | } 4 | table tr.covered td{ 5 | background-color:rgba(95,151,68,0.3) 6 | } 7 | 8 | table tr:hover.covered .num{ 9 | background-color:rgba(95,151,68,0.7) 10 | } 11 | table tr.missed td{ 12 | background-color:rgba(185,73,71,0.3) 13 | } 14 | table tr:hover.missed .num{ 15 | background-color:rgba(185,73,71,0.7) 16 | } 17 | 18 | table tr.missed:hover td{ 19 | -webkit-box-shadow:0 -2px 0 0 #b94947 inset; 20 | -moz-box-shadow:0 -2px 0 0 #b94947 inset; 21 | box-shadow:0 -2px 0 0 #b94947 inset 22 | } 23 | table tr.covered:hover td{ 24 | -webkit-box-shadow:0 -2px 0 0 #5f9744 inset; 25 | -moz-box-shadow:0 -2px 0 0 #5f9744 inset; 26 | box-shadow:0 -2px 0 0 #5f9744 inset 27 | } 28 | 29 | table tr.never td{ 30 | background-color:transparent 31 | } 32 | 33 | table tbody { 34 | border-style: solid; 35 | border: 1px solid rgba(0,0,0,0.1) 36 | } 37 | 38 | table .num { 39 | border-right: 1px solid rgba(0,0,0,0.1) 40 | } 41 | 42 | td.coverage em { 43 | opacity: 0.5; 44 | } 45 | 46 | table td.coverage { 47 | border-right: 1px solid rgba(0,0,0,0.1); 48 | font-weight: bold; 49 | text-align: center; 50 | } 51 | table.table-condensed pre { 52 | background-color: transparent; 53 | margin: 0; 54 | padding: 0; 55 | border: 0; 56 | font-size: 11px; 57 | } 58 | div#files td { 59 | padding: 0; 60 | padding-left: 5px; 61 | } 62 | 63 | div#files td.num { 64 | padding-right: 5px; 65 | } 66 | 67 | table.table-condensed { 68 | font-size: 11px; 69 | } 70 | -------------------------------------------------------------------------------- /inst/www/shared/bootstrap/shim/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | // Only run this code in IE 8 5 | if (!!window.navigator.userAgent.match("MSIE 8")) { 6 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document); 7 | }; 8 | -------------------------------------------------------------------------------- /inst/www/shared/bootstrap/shim/respond.min.js: -------------------------------------------------------------------------------- 1 | /*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl 2 | * Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT 3 | * */ 4 | 5 | // Only run this code in IE 8 6 | if (!!window.navigator.userAgent.match("MSIE 8")) { 7 | !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b$tests}: For each srcref count in the coverage object, a 27 | \verb{$tests} field is now included which contains a matrix with three columns, 28 | "test", "call", "depth" and "i" which specify the test number 29 | (corresponding to the index of the test in \code{attr(,"tests")}, the number 30 | of times the test expression was evaluated to produce the trace hit, the 31 | stack depth into the target code where the trace was executed, and the 32 | order of execution for each test. 33 | } 34 | } 35 | 36 | \section{Test traces}{ 37 | 38 | 39 | The content of test traces are dependent on the unit testing framework that 40 | is used by the target package. The behavior is contingent on the available 41 | information in the sources kept for the testing files. 42 | 43 | Test traces are extracted by the following criteria: 44 | \enumerate{ 45 | \item If any \code{srcref} files are are provided by a file within \link{covr}'s temporary 46 | library, all calls from those files are kept as a test trace. This will 47 | collect traces from tests run with common testing frameworks such as 48 | \code{testthat} and \code{RUnit}. 49 | \item Otherwise, as a conservative fallback in situations where no source 50 | references are found, or when none are from within the temporary 51 | directory, the entire call stack is collected. 52 | } 53 | 54 | These calls are subsequently subset for only those up until the call to 55 | \link{covr}'s internal \code{count} function, and will always include the last call in 56 | the call stack prior to a call to \code{count}. 57 | } 58 | 59 | \examples{ 60 | fcode <- ' 61 | f <- function(x) { 62 | if (x) 63 | f(!x) 64 | else 65 | FALSE 66 | }' 67 | 68 | options(covr.record_tests = TRUE) 69 | cov <- code_coverage(fcode, "f(TRUE)") 70 | 71 | # extract executed test code for the first test 72 | tail(attr(cov, "tests")[[1L]], 1L) 73 | # [[1]] 74 | # f(TRUE) 75 | 76 | # extract test itemization per trace 77 | cov[[3]][c("srcref", "tests")] 78 | # $srcref 79 | # f(!x) 80 | # 81 | # $tests 82 | # test call depth i 83 | # [1,] 1 1 2 4 84 | 85 | # reconstruct the code path of a test by ordering test traces by [,"i"] 86 | lapply(cov, `[[`, "tests") 87 | # $`source.Ref2326138c55:4:6:4:10:6:10:4:4` 88 | # test call depth i 89 | # [1,] 1 1 1 2 90 | # 91 | # $`source.Ref2326138c55:3:8:3:8:8:8:3:3` 92 | # test call depth i 93 | # [1,] 1 1 1 1 94 | # [2,] 1 1 2 3 95 | # 96 | # $`source.Ref2326138c55:6:6:6:10:6:10:6:6` 97 | # test call depth i 98 | # [1,] 1 1 2 4 99 | 100 | } 101 | -------------------------------------------------------------------------------- /man/current_test_call_count.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_tests.R 3 | \name{current_test_call_count} 4 | \alias{current_test_call_count} 5 | \title{Retrieve the number of times the test call was called} 6 | \usage{ 7 | current_test_call_count() 8 | } 9 | \value{ 10 | An integer value representing the number of calls of the current 11 | call into the package from the testing suite. 12 | } 13 | \description{ 14 | A single test expression might be evaluated many times. Each time the same 15 | expression is called, the call count is incremented. 16 | } 17 | -------------------------------------------------------------------------------- /man/current_test_index.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_tests.R 3 | \name{current_test_index} 4 | \alias{current_test_index} 5 | \title{Retrieve the index for the test in \code{.counters$tests}} 6 | \usage{ 7 | current_test_index() 8 | } 9 | \value{ 10 | An integer index for the test call 11 | } 12 | \description{ 13 | If the test was encountered before, the index will be the index of the test 14 | in the logged tests list. Otherwise, the index will be the next index beyond 15 | the length of the tests list. 16 | } 17 | \keyword{internal} 18 | -------------------------------------------------------------------------------- /man/current_test_key.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_tests.R 3 | \name{current_test_key} 4 | \alias{current_test_key} 5 | \title{Build key for the current test} 6 | \usage{ 7 | current_test_key() 8 | } 9 | \value{ 10 | A unique character string if the test call has a srcref, or an empty 11 | string otherwise. 12 | } 13 | \description{ 14 | If the current test has a srcref, a unique character key is built from its 15 | srcref. Otherwise, an empty string is returned. 16 | } 17 | \keyword{internal} 18 | -------------------------------------------------------------------------------- /man/display_name.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/display_name.R 3 | \name{display_name} 4 | \alias{display_name} 5 | \title{Retrieve the path name (filename) for each coverage object} 6 | \usage{ 7 | display_name(x) 8 | } 9 | \arguments{ 10 | \item{x}{A coverage object} 11 | } 12 | \description{ 13 | Retrieve the path name (filename) for each coverage object 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/environment_coverage.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/covr.R 3 | \name{environment_coverage} 4 | \alias{environment_coverage} 5 | \title{Calculate coverage of an environment} 6 | \usage{ 7 | environment_coverage( 8 | env = parent.frame(), 9 | test_files, 10 | line_exclusions = NULL, 11 | function_exclusions = NULL 12 | ) 13 | } 14 | \arguments{ 15 | \item{env}{The environment to be instrumented.} 16 | 17 | \item{test_files}{Character vector of test files with code to test the 18 | functions} 19 | 20 | \item{line_exclusions}{a named list of files with the lines to exclude from 21 | each file.} 22 | 23 | \item{function_exclusions}{a vector of regular expressions matching function 24 | names to exclude. Example \verb{print\\\\\\.} to match print methods.} 25 | } 26 | \description{ 27 | Calculate coverage of an environment 28 | } 29 | -------------------------------------------------------------------------------- /man/exclusions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/exclusions.R 3 | \name{exclusions} 4 | \alias{exclusions} 5 | \title{Exclusions} 6 | \description{ 7 | covr supports a couple of different ways of excluding some or all of a file. 8 | } 9 | \section{Line Exclusions}{ 10 | 11 | 12 | The \code{line_exclusions} argument to \code{package_coverage()} can be used 13 | to exclude some or all of a file. This argument takes a list of filenames 14 | or named ranges to exclude. 15 | } 16 | 17 | \section{Function Exclusions}{ 18 | 19 | 20 | Alternatively \code{function_exclusions} can be used to exclude R functions 21 | based on regular expression(s). For example \verb{print\\\\\\.*} can be used to 22 | exclude all the print methods defined in a package from coverage. 23 | } 24 | 25 | \section{Exclusion Comments}{ 26 | 27 | 28 | In addition you can exclude lines from the coverage by putting special comments 29 | in your source code. This can be done per line or by specifying a range. 30 | The patterns used can be specified by the \code{exclude_pattern}, \code{exclude_start}, 31 | \code{exclude_end} arguments to \code{package_coverage()} or by setting the global 32 | options \code{covr.exclude_pattern}, \code{covr.exclude_start}, \code{covr.exclude_end}. 33 | } 34 | 35 | \examples{ 36 | \dontrun{ 37 | # exclude whole file of R/test.R 38 | package_coverage(exclusions = "R/test.R") 39 | 40 | # exclude lines 1 to 10 and 15 from R/test.R 41 | package_coverage(line_exclusions = list("R/test.R" = c(1:10, 15))) 42 | 43 | # exclude lines 1 to 10 from R/test.R, all of R/test2.R 44 | package_coverage(line_exclusions = list("R/test.R" = 1:10, "R/test2.R")) 45 | 46 | # exclude all print and format methods from the package. 47 | package_coverage(function_exclusions = c("print\\\\.", "format\\\\.")) 48 | 49 | # single line exclusions 50 | f1 <- function(x) { 51 | x + 1 # nocov 52 | } 53 | 54 | # ranged exclusions 55 | f2 <- function(x) { # nocov start 56 | x + 2 57 | } # nocov end 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/covr/40122df12bc9ef1e577dd0720a895b5340b1516f/man/figures/logo.png -------------------------------------------------------------------------------- /man/file_coverage.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/covr.R 3 | \name{file_coverage} 4 | \alias{file_coverage} 5 | \title{Calculate test coverage for sets of files} 6 | \usage{ 7 | file_coverage( 8 | source_files, 9 | test_files, 10 | line_exclusions = NULL, 11 | function_exclusions = NULL, 12 | parent_env = parent.frame() 13 | ) 14 | } 15 | \arguments{ 16 | \item{source_files}{Character vector of source files with function 17 | definitions to measure coverage} 18 | 19 | \item{test_files}{Character vector of test files with code to test the 20 | functions} 21 | 22 | \item{line_exclusions}{a named list of files with the lines to exclude from 23 | each file.} 24 | 25 | \item{function_exclusions}{a vector of regular expressions matching function 26 | names to exclude. Example \verb{print\\\\\\.} to match print methods.} 27 | 28 | \item{parent_env}{The parent environment to use when sourcing the files.} 29 | } 30 | \description{ 31 | The files in \code{source_files} are first sourced into a new environment 32 | to define functions to be checked. Then they are instrumented to track 33 | coverage and the files in \code{test_files} are sourced. 34 | } 35 | \examples{ 36 | # For the purpose of this example, save code containing code and tests to files 37 | cat("add <- function(x, y) { x + y }", file="add.R") 38 | cat("add(1, 2) == 3", file="add_test.R") 39 | 40 | # Use file_coverage() to calculate test coverage 41 | file_coverage(source_files = "add.R", test_files = "add_test.R") 42 | 43 | # cleanup 44 | file.remove(c("add.R", "add_test.R")) 45 | } 46 | -------------------------------------------------------------------------------- /man/file_report.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/report.R 3 | \name{file_report} 4 | \alias{file_report} 5 | \title{A coverage report for a specific file} 6 | \usage{ 7 | file_report( 8 | x = package_coverage(), 9 | file = NULL, 10 | out_file = file.path(tempdir(), paste0(get_package_name(x), "-file-report.html")), 11 | browse = interactive() 12 | ) 13 | } 14 | \arguments{ 15 | \item{x}{a coverage dataset, defaults to running \code{package_coverage()}.} 16 | 17 | \item{file}{The file to report on, if \code{NULL}, use the first file in the 18 | coverage output.} 19 | 20 | \item{out_file}{The output file} 21 | 22 | \item{browse}{whether to open a browser to view the report.} 23 | } 24 | \description{ 25 | A coverage report for a specific file 26 | } 27 | -------------------------------------------------------------------------------- /man/function_coverage.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/covr.R 3 | \name{function_coverage} 4 | \alias{function_coverage} 5 | \title{Calculate test coverage for a specific function.} 6 | \usage{ 7 | function_coverage(fun, code = NULL, env = NULL, enc = parent.frame()) 8 | } 9 | \arguments{ 10 | \item{fun}{name of the function.} 11 | 12 | \item{code}{expressions to run.} 13 | 14 | \item{env}{environment the function is defined in.} 15 | 16 | \item{enc}{the enclosing environment which to run the expressions.} 17 | } 18 | \description{ 19 | Calculate test coverage for a specific function. 20 | } 21 | \examples{ 22 | add <- function(x, y) { x + y } 23 | function_coverage(fun = add, code = NULL) # 0\% coverage 24 | function_coverage(fun = add, code = add(1, 2) == 3) # 100\% coverage 25 | } 26 | -------------------------------------------------------------------------------- /man/gitlab.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/gitlab.R 3 | \name{gitlab} 4 | \alias{gitlab} 5 | \title{Run covr on package and create report for GitLab} 6 | \usage{ 7 | gitlab(..., coverage = NULL, file = "public/coverage.html", quiet = TRUE) 8 | } 9 | \arguments{ 10 | \item{...}{arguments passed to \code{\link[=package_coverage]{package_coverage()}}} 11 | 12 | \item{coverage}{an existing coverage object to submit, if \code{NULL}, 13 | \code{\link[=package_coverage]{package_coverage()}} will be called with the arguments from 14 | \code{...}} 15 | 16 | \item{file}{The report filename.} 17 | 18 | \item{quiet}{if \code{FALSE}, print the coverage before submission.} 19 | } 20 | \description{ 21 | Utilize internal GitLab static pages to publish package coverage. 22 | Creates local covr report in a package subdirectory. 23 | Uses the \href{https://docs.gitlab.com/ee/ci/yaml/README.html#pages}{pages} 24 | GitLab job to publish the report. 25 | } 26 | -------------------------------------------------------------------------------- /man/has_srcref.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_tests.R 3 | \name{has_srcref} 4 | \alias{has_srcref} 5 | \title{Is the source bound to the expression} 6 | \usage{ 7 | has_srcref(expr) 8 | } 9 | \arguments{ 10 | \item{expr}{A language object which may have a \code{srcref} attribute} 11 | } 12 | \value{ 13 | A logical value indicating whether the language object has source 14 | } 15 | \description{ 16 | Is the source bound to the expression 17 | } 18 | -------------------------------------------------------------------------------- /man/in_covr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/covr.R 3 | \name{in_covr} 4 | \alias{in_covr} 5 | \title{Determine if code is being run in covr} 6 | \usage{ 7 | in_covr() 8 | } 9 | \description{ 10 | covr functions set the environment variable \code{R_COVR} when they are running. 11 | \code{\link[=in_covr]{in_covr()}} returns \code{TRUE} if this environment variable is set and \code{FALSE} 12 | otherwise. 13 | } 14 | \examples{ 15 | if (require(testthat)) { 16 | testthat::skip_if(in_covr()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /man/is_covr_count_call.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_tests.R 3 | \name{is_covr_count_call} 4 | \alias{is_covr_count_call} 5 | \title{Is the expression a call to covr:::count} 6 | \usage{ 7 | is_covr_count_call(expr) 8 | } 9 | \arguments{ 10 | \item{expr}{A language object} 11 | } 12 | \value{ 13 | A logical value indicating whether the object is a call to 14 | \code{covr:::count}. 15 | } 16 | \description{ 17 | Is the expression a call to covr:::count 18 | } 19 | -------------------------------------------------------------------------------- /man/is_current_test_finished.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_tests.R 3 | \name{is_current_test_finished} 4 | \alias{is_current_test_finished} 5 | \title{Returns TRUE if we've moved on from test reflected in .current_test} 6 | \usage{ 7 | is_current_test_finished() 8 | } 9 | \description{ 10 | Quickly dismiss the need to update the current test if we can. To test if 11 | we're still in the last test, check if the same srcref (or call, if source is 12 | not kept) exists at the last recorded calling frame prior to entering a covr 13 | trace. If this has changed, do a more comprehensive test to see if any of the 14 | test call stack has changed, in which case we are onto a new test. 15 | } 16 | -------------------------------------------------------------------------------- /man/key.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_calls.R 3 | \name{key} 4 | \alias{key} 5 | \title{Generate a key for a call} 6 | \usage{ 7 | key(x) 8 | } 9 | \arguments{ 10 | \item{x}{the srcref of the call to create a key for} 11 | } 12 | \description{ 13 | Generate a key for a call 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/new_counter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_calls.R 3 | \name{new_counter} 4 | \alias{new_counter} 5 | \title{initialize a new counter} 6 | \usage{ 7 | new_counter(src_ref, parent_functions) 8 | } 9 | \arguments{ 10 | \item{src_ref}{a \code{\link[base:srcfile]{base::srcref()}}} 11 | 12 | \item{parent_functions}{the functions that this srcref is contained in.} 13 | } 14 | \description{ 15 | initialize a new counter 16 | } 17 | \keyword{internal} 18 | -------------------------------------------------------------------------------- /man/new_test_counter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_tests.R 3 | \name{new_test_counter} 4 | \alias{new_test_counter} 5 | \title{Initialize a new test counter for a coverage trace} 6 | \usage{ 7 | new_test_counter(key) 8 | } 9 | \arguments{ 10 | \item{key}{generated with \code{\link[=key]{key()}}} 11 | } 12 | \description{ 13 | Initialize a test counter, a matrix used to tally tests, their stack depth 14 | and the execution order as the trace associated with \code{key} is hit. Each 15 | test trace is an environment, which allows assignment into a pre-allocated 16 | \code{tests} matrix with minimall reallocation. 17 | } 18 | \details{ 19 | The \code{tests} matrix has columns \code{tests}, \code{depth} and \code{i}, 20 | corresponding to the test index (the index of the associated test in 21 | \code{.counters$tests}), the stack depth when the trace is evaluated and the 22 | number of traces that have been hit so far during test evaluation. 23 | } 24 | -------------------------------------------------------------------------------- /man/package_coverage.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/covr.R 3 | \name{package_coverage} 4 | \alias{package_coverage} 5 | \title{Calculate test coverage for a package} 6 | \usage{ 7 | package_coverage( 8 | path = ".", 9 | type = c("tests", "vignettes", "examples", "all", "none"), 10 | combine_types = TRUE, 11 | relative_path = TRUE, 12 | quiet = TRUE, 13 | clean = TRUE, 14 | line_exclusions = NULL, 15 | function_exclusions = NULL, 16 | code = character(), 17 | install_path = temp_file("R_LIBS"), 18 | ..., 19 | exclusions, 20 | pre_clean = TRUE 21 | ) 22 | } 23 | \arguments{ 24 | \item{path}{file path to the package.} 25 | 26 | \item{type}{run the package \sQuote{tests}, \sQuote{vignettes}, 27 | \sQuote{examples}, \sQuote{all}, or \sQuote{none}. The default is 28 | \sQuote{tests}.} 29 | 30 | \item{combine_types}{If \code{TRUE} (the default) the coverage for all types 31 | is simply summed into one coverage object. If \code{FALSE} separate objects 32 | are used for each type of coverage.} 33 | 34 | \item{relative_path}{whether to output the paths as relative or absolute 35 | paths. If a string, it is interpreted as a root path and all paths will be 36 | relative to that root.} 37 | 38 | \item{quiet}{whether to load and compile the package quietly, useful for 39 | debugging errors.} 40 | 41 | \item{clean}{whether to clean temporary output files after running, mainly 42 | useful for debugging errors.} 43 | 44 | \item{line_exclusions}{a named list of files with the lines to exclude from 45 | each file.} 46 | 47 | \item{function_exclusions}{a vector of regular expressions matching function 48 | names to exclude. Example \verb{print\\\\\\.} to match print methods.} 49 | 50 | \item{code}{A character vector of additional test code to run.} 51 | 52 | \item{install_path}{The path the instrumented package will be installed to 53 | and tests run in. By default it is a path in the R sessions temporary 54 | directory. It can sometimes be useful to set this (along with \code{clean = FALSE}) to help debug test failures.} 55 | 56 | \item{...}{Additional arguments passed to \code{\link[tools:testInstalledPackage]{tools::testInstalledPackage()}}.} 57 | 58 | \item{exclusions}{\sQuote{Deprecated}, please use \sQuote{line_exclusions} instead.} 59 | 60 | \item{pre_clean}{whether to delete all objects present in the src directory before recompiling} 61 | } 62 | \description{ 63 | This function calculates the test coverage for a development package on the 64 | \code{path}. By default it runs only the package tests, but it can also run 65 | vignette and example code. 66 | } 67 | \details{ 68 | This function uses \code{\link[tools:testInstalledPackage]{tools::testInstalledPackage()}} to run the 69 | code, if you would like to test your package in another way you can set 70 | \code{type = "none"} and pass the code to run as a character vector to the 71 | \code{code} parameter. 72 | 73 | #ifdef unix 74 | Parallelized code using \pkg{parallel}'s \code{\link[=mcparallel]{mcparallel()}} needs to 75 | use a patched \code{parallel:::mcexit}. This is done automatically if the 76 | package depends on \pkg{parallel}, but can also be explicitly set using the 77 | environment variable \code{COVR_FIX_PARALLEL_MCEXIT} or the global option 78 | \code{covr.fix_parallel_mcexit}. 79 | #endif 80 | } 81 | \seealso{ 82 | \code{\link[=exclusions]{exclusions()}} For details on excluding parts of the 83 | package from the coverage calculations. 84 | } 85 | -------------------------------------------------------------------------------- /man/percent_coverage.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/summary_functions.R 3 | \name{percent_coverage} 4 | \alias{percent_coverage} 5 | \title{Provide percent coverage of package} 6 | \usage{ 7 | percent_coverage(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{the coverage object returned from \code{\link[=package_coverage]{package_coverage()}}} 11 | 12 | \item{...}{additional arguments passed to \code{\link[=tally_coverage]{tally_coverage()}}} 13 | } 14 | \value{ 15 | The total percentage as a \code{numeric(1)}. 16 | } 17 | \description{ 18 | Calculate the total percent coverage from a coverage result object. 19 | } 20 | -------------------------------------------------------------------------------- /man/print.coverage.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/summary_functions.R 3 | \name{print.coverage} 4 | \alias{print.coverage} 5 | \title{Print a coverage object} 6 | \usage{ 7 | \method{print}{coverage}(x, group = c("filename", "functions"), by = "line", ...) 8 | } 9 | \arguments{ 10 | \item{x}{the coverage object to be printed} 11 | 12 | \item{group}{whether to group coverage by filename or function} 13 | 14 | \item{by}{whether to count coverage by line or expression} 15 | 16 | \item{...}{additional arguments ignored} 17 | } 18 | \value{ 19 | The coverage object (invisibly). 20 | } 21 | \description{ 22 | Print a coverage object 23 | } 24 | -------------------------------------------------------------------------------- /man/report.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/report.R 3 | \name{report} 4 | \alias{report} 5 | \title{Display covr results using a standalone report} 6 | \usage{ 7 | report( 8 | x = package_coverage(), 9 | file = file.path(tempdir(), paste0(get_package_name(x), "-report.html")), 10 | browse = interactive() 11 | ) 12 | } 13 | \arguments{ 14 | \item{x}{a coverage dataset, defaults to running \code{package_coverage()}.} 15 | 16 | \item{file}{The report filename.} 17 | 18 | \item{browse}{whether to open a browser to view the report.} 19 | } 20 | \description{ 21 | Display covr results using a standalone report 22 | } 23 | \examples{ 24 | \dontrun{ 25 | x <- package_coverage() 26 | report(x) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /man/system_check.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/system.R 3 | \name{system_check} 4 | \alias{system_check} 5 | \title{Run a system command and check if it succeeds.} 6 | \usage{ 7 | system_check( 8 | cmd, 9 | args = character(), 10 | env = character(), 11 | quiet = FALSE, 12 | echo = FALSE, 13 | ... 14 | ) 15 | } 16 | \arguments{ 17 | \item{cmd}{the command to run.} 18 | 19 | \item{args}{a vector of command arguments.} 20 | 21 | \item{env}{a named character vector of environment variables. Will be quoted} 22 | 23 | \item{quiet}{if \code{TRUE}, the command output will be echoed.} 24 | 25 | \item{echo}{if \code{TRUE}, the command to run will be echoed.} 26 | 27 | \item{...}{additional arguments passed to \code{\link[base:system]{base::system()}}} 28 | } 29 | \value{ 30 | \code{TRUE} if the command succeeds, an error will be thrown if the 31 | command fails. 32 | } 33 | \description{ 34 | This function automatically quotes both the command and each 35 | argument so they are properly protected from shell expansion. 36 | } 37 | \keyword{internal} 38 | -------------------------------------------------------------------------------- /man/system_output.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/system.R 3 | \name{system_output} 4 | \alias{system_output} 5 | \title{Run a system command and capture the output.} 6 | \usage{ 7 | system_output( 8 | cmd, 9 | args = character(), 10 | env = character(), 11 | quiet = FALSE, 12 | echo = FALSE, 13 | ... 14 | ) 15 | } 16 | \arguments{ 17 | \item{cmd}{the command to run.} 18 | 19 | \item{args}{a vector of command arguments.} 20 | 21 | \item{env}{a named character vector of environment variables. Will be quoted} 22 | 23 | \item{quiet}{if \code{TRUE}, the command output will be echoed.} 24 | 25 | \item{echo}{if \code{TRUE}, the command to run will be echoed.} 26 | 27 | \item{...}{additional arguments passed to \code{\link[base:system]{base::system()}}} 28 | } 29 | \value{ 30 | command output if the command succeeds, an error will be thrown if 31 | the command fails. 32 | } 33 | \description{ 34 | This function automatically quotes both the command and each 35 | argument so they are properly protected from shell expansion. 36 | } 37 | \keyword{internal} 38 | -------------------------------------------------------------------------------- /man/tally_coverage.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/summary_functions.R 3 | \name{tally_coverage} 4 | \alias{tally_coverage} 5 | \title{Tally coverage by line or expression} 6 | \usage{ 7 | tally_coverage(x, by = c("line", "expression")) 8 | } 9 | \arguments{ 10 | \item{x}{the coverage object returned from \code{\link[=package_coverage]{package_coverage()}}} 11 | 12 | \item{by}{whether to tally coverage by line or expression} 13 | } 14 | \value{ 15 | a \code{data.frame} of coverage tallied by line or expression. 16 | } 17 | \description{ 18 | Tally coverage by line or expression 19 | } 20 | -------------------------------------------------------------------------------- /man/to_cobertura.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cobertura.R 3 | \name{to_cobertura} 4 | \alias{to_cobertura} 5 | \title{Create a Cobertura XML file} 6 | \usage{ 7 | to_cobertura(cov, filename = "cobertura.xml") 8 | } 9 | \arguments{ 10 | \item{cov}{the coverage object returned from \code{\link[=package_coverage]{package_coverage()}}} 11 | 12 | \item{filename}{the name of the Cobertura XML file} 13 | } 14 | \description{ 15 | Create a 16 | cobertura-compliant XML report following \href{https://github.com/cobertura/cobertura/blob/master/cobertura/src/site/htdocs/xml/coverage-04.dtd}{this DTD}. 17 | Because there are \emph{two} DTDs called \verb{coverage-04.dtd} and some tools do not seem to 18 | adhere to either of them, the parser you're using may balk at the file. Please see 19 | \href{https://github.com/cobertura/cobertura/issues/425}{this github discussion} for 20 | context. Where \code{covr} doesn't provide a coverage metric (branch coverage, 21 | complexity), a zero is reported. 22 | } 23 | \details{ 24 | \emph{Note}: This functionality requires the xml2 package be installed. 25 | } 26 | -------------------------------------------------------------------------------- /man/to_sonarqube.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sonarqube.R 3 | \name{to_sonarqube} 4 | \alias{to_sonarqube} 5 | \title{Create a SonarQube Generic XML file for test coverage according to 6 | https://docs.sonarqube.org/latest/analysis/generic-test/ 7 | Based on cobertura.R} 8 | \usage{ 9 | to_sonarqube(cov, filename = "sonarqube.xml") 10 | } 11 | \arguments{ 12 | \item{cov}{the coverage object returned from \code{\link[=package_coverage]{package_coverage()}}} 13 | 14 | \item{filename}{the name of the SonarQube Generic XML file} 15 | } 16 | \description{ 17 | This functionality requires the xml2 package be installed. 18 | } 19 | \author{ 20 | Talkdesk Inc. 21 | } 22 | -------------------------------------------------------------------------------- /man/trace_calls.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_calls.R 3 | \name{trace_calls} 4 | \alias{trace_calls} 5 | \title{trace each call with a srcref attribute} 6 | \usage{ 7 | trace_calls(x, parent_functions = NULL, parent_ref = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{the call} 11 | 12 | \item{parent_functions}{the functions which this call is a child of.} 13 | 14 | \item{parent_ref}{argument used to set the srcref of the current call during 15 | the recursion.} 16 | } 17 | \value{ 18 | a modified expression with count calls inserted before each previous 19 | call. 20 | } 21 | \description{ 22 | This function calls itself recursively so it can properly traverse the AST. 23 | } 24 | \seealso{ 25 | \url{http://adv-r.had.co.nz/Expressions.html} 26 | } 27 | \keyword{internal} 28 | -------------------------------------------------------------------------------- /man/truncate_call.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_tests.R 3 | \name{truncate_call} 4 | \alias{truncate_call} 5 | \title{Truncate call objects to limit the number of arguments} 6 | \usage{ 7 | truncate_call(call_obj, limit = 10000) 8 | } 9 | \arguments{ 10 | \item{call_obj}{A (possibly large) \code{call} object} 11 | 12 | \item{limit}{A \code{call} length limit to impose} 13 | } 14 | \value{ 15 | The \code{call_obj} with arguments trimmed 16 | } 17 | \description{ 18 | A helper to circumvent R errors when deserializing large call objects from 19 | Rds. Trims the number of arguments in a call object, and replaces the last 20 | argument with a \verb{} symbol. 21 | } 22 | -------------------------------------------------------------------------------- /man/update_current_test.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trace_tests.R 3 | \name{update_current_test} 4 | \alias{update_current_test} 5 | \title{Update current test if unit test expression has progressed} 6 | \usage{ 7 | update_current_test() 8 | } 9 | \description{ 10 | Updating a test logs some metadata regarding the current call stack, noteably 11 | trying to capture information about the call stack prior to the covr::count 12 | call being traced. 13 | } 14 | \details{ 15 | There are a couple patterns of behavior, which try to accommodate a variety 16 | of testing suites: 17 | 18 | \itemize{ 19 | \item \code{testthat}: During execution of \code{testthat}'s \verb{test_*} functions, 20 | files are sourced and the working directory is temporarily changed to the 21 | package \verb{/tests} directory. Knowing this, calls in the call stack which 22 | are relative to this directory are extracted and recorded. 23 | \item \code{RUnit}: 24 | \item \code{custom}: Any other custom test suites may not have source kept with 25 | their execution, in which case the entire test call stack is kept. 26 | } 27 | 28 | checks to see if the current call stack has the same 29 | \code{srcref} (or expression, if no source is available) at the same frame prior 30 | to entering into a package where \code{covr:::count} is called. 31 | } 32 | \keyword{internal} 33 | -------------------------------------------------------------------------------- /man/value.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/value.R 3 | \name{value} 4 | \alias{value} 5 | \title{Retrieve the value from an object} 6 | \usage{ 7 | value(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{object from which to retrieve the value} 11 | 12 | \item{...}{additional arguments passed to methods} 13 | } 14 | \description{ 15 | Retrieve the value from an object 16 | } 17 | -------------------------------------------------------------------------------- /man/zero_coverage.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/summary_functions.R 3 | \name{zero_coverage} 4 | \alias{zero_coverage} 5 | \title{Provide locations of zero coverage} 6 | \usage{ 7 | zero_coverage(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{a coverage object returned \code{\link[=package_coverage]{package_coverage()}}} 11 | 12 | \item{...}{additional arguments passed to 13 | \code{\link[=tally_coverage]{tally_coverage()}}} 14 | } 15 | \value{ 16 | A \code{data.frame} with coverage data where the coverage is 0. 17 | } 18 | \description{ 19 | When examining the test coverage of a package, it is useful to know if there are 20 | any locations where there is \strong{0} test coverage. 21 | } 22 | \details{ 23 | if used within RStudio this function outputs the results using the 24 | Marker API. 25 | } 26 | -------------------------------------------------------------------------------- /revdep/.gitignore: -------------------------------------------------------------------------------- 1 | **/ 2 | *.noindex 3 | -------------------------------------------------------------------------------- /revdep/README.md: -------------------------------------------------------------------------------- 1 | # Platform 2 | 3 | |field |value | 4 | |:--------|:----------------------------| 5 | |version |R version 3.6.0 (2019-04-26) | 6 | |os |macOS Mojave 10.14.4 | 7 | |system |x86_64, darwin15.6.0 | 8 | |ui |X11 | 9 | |language |(EN) | 10 | |collate |en_US.UTF-8 | 11 | |ctype |en_US.UTF-8 | 12 | |tz |America/New_York | 13 | |date |2019-08-05 | 14 | 15 | # Dependencies 16 | 17 | |package |old |new |Δ | 18 | |:--------|:-----|:----------|:--| 19 | |covr |3.2.1 |3.2.1.9000 |* | 20 | |curl |NA |4.0 |* | 21 | |digest |NA |0.6.20 |* | 22 | |lazyeval |0.2.2 |0.2.2 | | 23 | |mime |NA |0.7 |* | 24 | |openssl |NA |1.4.1 |* | 25 | |rex |1.1.2 |1.1.2 | | 26 | 27 | # Revdeps 28 | 29 | -------------------------------------------------------------------------------- /revdep/check.R: -------------------------------------------------------------------------------- 1 | library("devtools") 2 | 3 | revdep_check_resume() 4 | revdep_check_save_summary() 5 | revdep_check_print_problems() 6 | -------------------------------------------------------------------------------- /revdep/checks.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/covr/40122df12bc9ef1e577dd0720a895b5340b1516f/revdep/checks.rds -------------------------------------------------------------------------------- /revdep/email.yml: -------------------------------------------------------------------------------- 1 | release_date: ??? 2 | rel_release_date: ??? 3 | my_news_url: ??? 4 | release_version: ??? 5 | -------------------------------------------------------------------------------- /revdep/failures.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /revdep/problems.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /shim_package.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | perl -i -pe 's/\bcovr\b/covrShim/g;s/\bcovr_/covrShim_/g;s/_covr/_covrShim/g;' DESCRIPTION NAMESPACE R/* src/* tests/*R tests/testthat/*R 4 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | # This file is part of the standard setup for testthat. 2 | # It is recommended that you do not modify it. 3 | # 4 | # Where should you do additional test configuration? 5 | # Learn more about the roles of various files in: 6 | # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview 7 | # * https://testthat.r-lib.org/articles/special-files.html 8 | 9 | library(testthat) 10 | library(covr) 11 | 12 | test_check("covr") 13 | -------------------------------------------------------------------------------- /tests/testthat/Test+Char/TestCompiled/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestCompiled 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | Suggests: 11 | testthat 12 | RoxygenNote: 7.1.1 13 | -------------------------------------------------------------------------------- /tests/testthat/Test+Char/TestCompiled/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | useDynLib(TestCompiled,simple_) 4 | -------------------------------------------------------------------------------- /tests/testthat/Test+Char/TestCompiled/R/TestCompiled.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @useDynLib TestCompiled simple_ 4 | simple <- function(x) { 5 | .Call(simple_, x) # nolint 6 | } 7 | -------------------------------------------------------------------------------- /tests/testthat/Test+Char/TestCompiled/man/simple.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/TestCompiled.R 3 | \name{simple} 4 | \alias{simple} 5 | \title{an example function} 6 | \usage{ 7 | simple(x) 8 | } 9 | \description{ 10 | an example function 11 | } 12 | -------------------------------------------------------------------------------- /tests/testthat/Test+Char/TestCompiled/src/simple.cc: -------------------------------------------------------------------------------- 1 | #define USE_RINTERNALS 2 | #include 3 | #include 4 | #include 5 | 6 | extern "C" SEXP simple_(SEXP x) { 7 | double *px, *pout; 8 | 9 | SEXP out = PROTECT(Rf_allocVector(REALSXP, 1)); 10 | 11 | px = REAL(x); 12 | pout = REAL(out); 13 | 14 | if (px[0] >= 1) { 15 | pout[0] = 1; 16 | } 17 | else if (px[0] == 0) { 18 | pout[0] = 0; 19 | } else { 20 | pout[0] = -1; 21 | } 22 | UNPROTECT(1); 23 | 24 | return out; 25 | } 26 | -------------------------------------------------------------------------------- /tests/testthat/Test+Char/TestCompiled/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library("TestCompiled") 3 | 4 | test_check("TestCompiled") 5 | -------------------------------------------------------------------------------- /tests/testthat/Test+Char/TestCompiled/tests/testthat/test-TestCompiled.R: -------------------------------------------------------------------------------- 1 | test_that("compiled function simple works", { 2 | expect_equal(simple(1), 1) 3 | expect_equal(simple(2), 1) 4 | expect_equal(simple(3), 1) 5 | expect_equal(simple(-1), -1) 6 | }) 7 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiled/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestCompiled 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | Suggests: 11 | testthat 12 | RoxygenNote: 5.0.1 13 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiled/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | useDynLib(TestCompiled,simple_) 4 | useDynLib(TestCompiled,simple3_) 5 | useDynLib(TestCompiled,simple4_) 6 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiled/R/TestCompiled.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @useDynLib TestCompiled simple_ 4 | simple <- function(x) { 5 | .Call(simple_, x) # nolint 6 | } 7 | 8 | simple3 <- function(x) { 9 | .Call(simple3_, x) # nolint 10 | } 11 | 12 | simple4 <- function(x) { 13 | .Call(simple4_, x) # nolint 14 | } 15 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiled/man/simple.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/TestCompiled.R 3 | \name{simple} 4 | \alias{simple} 5 | \title{an example function} 6 | \usage{ 7 | simple(x) 8 | } 9 | \description{ 10 | an example function 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiled/src/simple-header.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define USE_RINTERNALS 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | SEXP simple2_(SEXP x) { 10 | R *px, *pout; 11 | 12 | SEXP out = PROTECT(Rf_allocVector(R_SXP, 1)); 13 | 14 | px = (R *) DATAPTR(x); 15 | pout = (R *) DATAPTR(out); 16 | 17 | if (px[0] >= 1) { 18 | pout[0] = 1; 19 | } 20 | else if (px[0] == 0) { 21 | pout[0] = 0; 22 | } else { 23 | pout[0] = -1; 24 | } 25 | UNPROTECT(1); 26 | 27 | return out; 28 | } 29 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiled/src/simple.cc: -------------------------------------------------------------------------------- 1 | #define USE_RINTERNALS 2 | #include 3 | #include 4 | #include 5 | #include "simple-header.h" 6 | 7 | extern "C" SEXP simple_(SEXP x) { 8 | double *px, *pout; 9 | 10 | SEXP out = PROTECT(Rf_allocVector(REALSXP, 1)); 11 | 12 | px = REAL(x); 13 | pout = REAL(out); 14 | 15 | if (px[0] >= 1) { 16 | pout[0] = 1; 17 | } 18 | else if (px[0] == 0) { 19 | pout[0] = 0; 20 | } else { 21 | pout[0] = -1; 22 | } 23 | UNPROTECT(1); 24 | 25 | return out; 26 | } 27 | 28 | extern "C" SEXP simple3_(SEXP x) { 29 | return simple2_(x); 30 | } 31 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiled/src/simple4.cc: -------------------------------------------------------------------------------- 1 | #define USE_RINTERNALS 2 | #include 3 | #include 4 | #include 5 | #include "simple-header.h" 6 | 7 | extern "C" SEXP simple4_(SEXP x) { 8 | return simple2_(x); 9 | } 10 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiled/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library("TestCompiled") 3 | 4 | test_check("TestCompiled") 5 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiled/tests/testthat/test-TestCompiled.R: -------------------------------------------------------------------------------- 1 | test_that("compiled function simple works", { 2 | expect_equal(simple(1), 1) 3 | expect_equal(simple(2), 1) 4 | expect_equal(simple(3), 1) 5 | expect_equal(simple(-1), -1) 6 | }) 7 | 8 | test_that("compiled function simple3 works", { 9 | expect_equal(simple3(1), 1) 10 | expect_equal(simple3(2), 1) 11 | }) 12 | 13 | test_that("compiled function simple4 works", { 14 | expect_equal(simple4(3L), 1L) 15 | expect_equal(simple4(-1L), -1L) 16 | }) 17 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiledSubdir/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestCompiledSubdir 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | Suggests: 11 | testthat 12 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiledSubdir/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2 (4.1.1): do not edit by hand 2 | 3 | useDynLib(TestCompiledSubdir,simple_) 4 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiledSubdir/R/TestCompiledSubdir.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @useDynLib TestCompiledSubdir simple_ 4 | simple <- function(x) { 5 | .Call(simple_, x) # nolint 6 | } 7 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiledSubdir/man/simple.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/TestCompiledSubdir.R 3 | \name{simple} 4 | \alias{simple} 5 | \title{an example function} 6 | \usage{ 7 | simple(x) 8 | } 9 | \description{ 10 | an example function 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiledSubdir/src/Makevars: -------------------------------------------------------------------------------- 1 | OBJECTS = lib/simple.o 2 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiledSubdir/src/lib/simple.c: -------------------------------------------------------------------------------- 1 | #define USE_RINTERNALS 2 | #include 3 | #include 4 | #include 5 | 6 | SEXP simple_(SEXP x) { 7 | double *px, *pout; 8 | 9 | SEXP out = PROTECT(Rf_allocVector(REALSXP, 1)); 10 | 11 | px = REAL(x); 12 | pout = REAL(out); 13 | 14 | if (px[0] >= 1) { 15 | pout[0] = 1; 16 | } 17 | else if (px[0] == 0) { 18 | pout[0] = 0; 19 | } else { 20 | pout[0] = -1; 21 | } 22 | UNPROTECT(1); 23 | 24 | return out; 25 | } 26 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiledSubdir/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library("TestCompiledSubdir") 3 | 4 | test_check("TestCompiledSubdir") 5 | -------------------------------------------------------------------------------- /tests/testthat/TestCompiledSubdir/tests/testthat/test-TestCompiledSubdir.R: -------------------------------------------------------------------------------- 1 | test_that("compiled function simple works", { 2 | expect_equal(simple(1), 1) 3 | expect_equal(simple(2), 1) 4 | expect_equal(simple(3), 1) 5 | expect_equal(simple(-1), -1) 6 | }) 7 | -------------------------------------------------------------------------------- /tests/testthat/TestExclusion/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestExclusion 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | -------------------------------------------------------------------------------- /tests/testthat/TestExclusion/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2 (4.1.1): do not edit by hand 2 | 3 | export(dont_test_me) 4 | export(test_exclusion) 5 | export(test_me) 6 | -------------------------------------------------------------------------------- /tests/testthat/TestExclusion/R/TestExclusion.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @export 4 | test_me <- function(x, y){ 5 | x + y 6 | } 7 | 8 | # nocov start 9 | #' @export 10 | dont_test_me <- function(x, y){ 11 | x * y 12 | } 13 | # nocov end 14 | 15 | #' @export 16 | test_exclusion <- function(x) { 17 | if (x > 5) { 18 | 1 # nocov 19 | } else { 20 | 2 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/testthat/TestExclusion/man/test_me.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/TestExclusion.R 3 | \name{test_me} 4 | \alias{test_me} 5 | \title{an example function} 6 | \usage{ 7 | test_me(x, y) 8 | } 9 | \description{ 10 | an example function 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat/TestExclusion/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library("TestExclusion") 3 | 4 | test_check("TestExclusion") 5 | -------------------------------------------------------------------------------- /tests/testthat/TestExclusion/tests/testthat/test-TestExclusion.R: -------------------------------------------------------------------------------- 1 | test_that("test_me works", { 2 | expect_equal(test_me(2, 2), 4) 3 | expect_equal(test_exclusion(1), 2) 4 | }) 5 | -------------------------------------------------------------------------------- /tests/testthat/TestFunctional/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestFunctional 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | Suggests: 11 | testthat 12 | RoxygenNote: 6.1.1 13 | -------------------------------------------------------------------------------- /tests/testthat/TestFunctional/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(a) 4 | export(b) 5 | -------------------------------------------------------------------------------- /tests/testthat/TestFunctional/R/a.R: -------------------------------------------------------------------------------- 1 | foo <- function(x) { 2 | force(x) 3 | function() { 4 | if (x < 1) 5 | { 6 | return(TRUE) 7 | } else { 8 | return(FALSE) 9 | } 10 | } 11 | } 12 | 13 | #' @export 14 | a <- foo(0) 15 | 16 | #' @export 17 | b <- foo(1) 18 | -------------------------------------------------------------------------------- /tests/testthat/TestFunctional/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library("TestFunctional") 3 | 4 | test_check("TestFunctional") 5 | -------------------------------------------------------------------------------- /tests/testthat/TestFunctional/tests/testthat/test-a.R: -------------------------------------------------------------------------------- 1 | test_that("regular function `a` works as expected", { 2 | expect_equal(a(), TRUE) 3 | expect_equal(b(), FALSE) 4 | }) 5 | -------------------------------------------------------------------------------- /tests/testthat/TestNestedTestDirs/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestNestedTestDirs 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | Suggests: 11 | testthat 12 | RoxygenNote: 6.1.1 13 | -------------------------------------------------------------------------------- /tests/testthat/TestNestedTestDirs/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(a) 4 | export(b) 5 | -------------------------------------------------------------------------------- /tests/testthat/TestNestedTestDirs/R/a.R: -------------------------------------------------------------------------------- 1 | foo <- function(x) { 2 | force(x) 3 | function() { 4 | if (x < 1) 5 | { 6 | return(TRUE) 7 | } else { 8 | return(FALSE) 9 | } 10 | } 11 | } 12 | 13 | #' @export 14 | a <- foo(0) 15 | 16 | #' @export 17 | b <- foo(1) 18 | -------------------------------------------------------------------------------- /tests/testthat/TestNestedTestDirs/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library("TestNestedTestDirs") 3 | 4 | test_check("TestNestedTestDirs") 5 | -------------------------------------------------------------------------------- /tests/testthat/TestNestedTestDirs/tests/testthat/nested_tests/test-a.R: -------------------------------------------------------------------------------- 1 | test_that("regular function `a` works as expected", { 2 | expect_equal(a(), TRUE) 3 | expect_equal(b(), FALSE) 4 | }) 5 | -------------------------------------------------------------------------------- /tests/testthat/TestNestedTestDirs/tests/testthat/test-a.R: -------------------------------------------------------------------------------- 1 | test_that("regular function `a` works as expected", { 2 | expect_equal(a(), TRUE) 3 | expect_equal(b(), FALSE) 4 | }) 5 | -------------------------------------------------------------------------------- /tests/testthat/TestNestedTestDirs/tests/testthat/test-nested-dir.R: -------------------------------------------------------------------------------- 1 | # used for testing the extraction of srcrefs pertaining to tests, which assumes 2 | # srcrefs within working directory 3 | 4 | if (Sys.getenv("COVR_TEST_NESTED") == "TRUE") { 5 | test_dir("./nested_tests") 6 | 7 | # keep.source needed to extract test trace 8 | source("./nested_tests/test-a.R", keep.source = TRUE) 9 | } 10 | 11 | -------------------------------------------------------------------------------- /tests/testthat/TestParallel/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestParallel 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | Suggests: parallel 9 | License: What license is it under? 10 | LazyData: true 11 | -------------------------------------------------------------------------------- /tests/testthat/TestParallel/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2 (4.1.1): do not edit by hand 2 | 3 | export(test1) 4 | export(test2) 5 | export(test3) -------------------------------------------------------------------------------- /tests/testthat/TestParallel/R/TestParallel.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @export 4 | test1 <- function(x, y){ 5 | x + y 6 | } 7 | 8 | #' @export 9 | test2 <- function(x, y){ 10 | x * y 11 | } 12 | 13 | #' @export 14 | test3 <- function(x, y){ 15 | x - y 16 | } -------------------------------------------------------------------------------- /tests/testthat/TestParallel/man/test_me.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/TestSummary.R 3 | \name{test_me} 4 | \alias{test_me} 5 | \title{an example function} 6 | \usage{ 7 | test_me(x, y) 8 | } 9 | \description{ 10 | an example function 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat/TestParallel/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library("TestParallel") 3 | 4 | test_check("TestParallel") 5 | -------------------------------------------------------------------------------- /tests/testthat/TestParallel/tests/testthat/test-TestParallel.R: -------------------------------------------------------------------------------- 1 | test_that("test_me works", { 2 | library(parallel) 3 | 4 | mccollect(mcparallel( 5 | expect_equal(test1(2, 2), 4) 6 | )) 7 | 8 | mccollect(mcparallel( 9 | expect_equal(test2(2, 2), 4) 10 | )) 11 | 12 | expect_equal(test3(2, 2), 0) 13 | }) 14 | -------------------------------------------------------------------------------- /tests/testthat/TestPrint/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestPrint 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | -------------------------------------------------------------------------------- /tests/testthat/TestPrint/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2 (4.1.1): do not edit by hand 2 | 3 | export(test_me) 4 | -------------------------------------------------------------------------------- /tests/testthat/TestPrint/R/TestPrint.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @export 4 | test_me <- function(x, y) { 5 | if (TRUE) { x + y } else { 0 } # nolint 6 | } 7 | -------------------------------------------------------------------------------- /tests/testthat/TestPrint/man/test_me.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/TestPrint.R 3 | \name{test_me} 4 | \alias{test_me} 5 | \title{an example function} 6 | \usage{ 7 | test_me(x, y) 8 | } 9 | \description{ 10 | an example function 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat/TestPrint/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library("TestPrint") 3 | 4 | test_check("TestPrint") 5 | -------------------------------------------------------------------------------- /tests/testthat/TestPrint/tests/testthat/test-TestSummary.R: -------------------------------------------------------------------------------- 1 | test_that("test_me works", { 2 | expect_equal(test_me(2, 2), 4) 3 | }) 4 | -------------------------------------------------------------------------------- /tests/testthat/TestR6/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestR6 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | Imports: 11 | R6 12 | Suggests: 13 | testthat 14 | -------------------------------------------------------------------------------- /tests/testthat/TestR6/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2 (4.1.1): do not edit by hand 2 | 3 | export(TestR6) 4 | export(a) 5 | -------------------------------------------------------------------------------- /tests/testthat/TestR6/R/TestR6.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @export 4 | a <- function(x) { 5 | if (x <= 1) { 6 | 1 7 | } else { 8 | 2 9 | } 10 | } 11 | 12 | #' @export 13 | TestR6 <- R6::R6Class("TestR6", # nolint 14 | public = list( 15 | show = function(x) { 16 | 1 + 3 17 | }, 18 | print2 = function(x) { 19 | 1 + 2 20 | } 21 | ) 22 | ) 23 | 24 | .InternalTestR6 <- R6::R6Class("InternalTestR6", # nolint 25 | public = list( 26 | some_method = function(x){ 27 | 1 + 2 28 | } 29 | ) 30 | ) 31 | -------------------------------------------------------------------------------- /tests/testthat/TestR6/man/a.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/TestR6.R 3 | \name{a} 4 | \alias{a} 5 | \title{an example function} 6 | \usage{ 7 | a(x) 8 | } 9 | \description{ 10 | an example function 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat/TestR6/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library("TestR6") 3 | 4 | test_check("TestR6") 5 | -------------------------------------------------------------------------------- /tests/testthat/TestR6/tests/testthat/test-TestR6.R: -------------------------------------------------------------------------------- 1 | test_that("regular function `a` works as expected", { 2 | expect_equal(a(1), 1) 3 | expect_equal(a(2), 2) 4 | expect_equal(a(3), 2) 5 | expect_equal(a(4), 2) 6 | expect_equal(a(0), 1) 7 | }) 8 | 9 | test_that("TestR6 class can be instantiated", { 10 | t1 <- TestR6$new() # nolint 11 | }) 12 | 13 | test_that("TestR6 Methods can be evaluated", { 14 | t1 <- TestR6$new() # nolint 15 | 16 | t1$show() 17 | print(t1$print2()) 18 | }) 19 | -------------------------------------------------------------------------------- /tests/testthat/TestRC/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestRC 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | Suggests: 11 | testthat 12 | -------------------------------------------------------------------------------- /tests/testthat/TestRC/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2 (4.1.1): do not edit by hand 2 | 3 | export(a) 4 | exportClasses(TestRC) 5 | -------------------------------------------------------------------------------- /tests/testthat/TestRC/R/TestRC.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @export 4 | a <- function(x) { 5 | if (x <= 1) { 6 | 1 7 | } else { 8 | 2 9 | } 10 | } 11 | 12 | #' @export 13 | TestRC <- setRefClass("TestRC", # nolint 14 | fields = list(name = "character", enabled = "logical"), 15 | methods = list( 16 | show = function(x) { 17 | 1 + 3 18 | }, 19 | print2 = function(x) { 20 | 1 + 2 21 | } 22 | ) 23 | ) 24 | -------------------------------------------------------------------------------- /tests/testthat/TestRC/man/a.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/TestRC.R 3 | \name{a} 4 | \alias{a} 5 | \title{an example function} 6 | \usage{ 7 | a(x) 8 | } 9 | \description{ 10 | an example function 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat/TestRC/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library("TestRC") 3 | 4 | test_check("TestRC") 5 | -------------------------------------------------------------------------------- /tests/testthat/TestRC/tests/testthat/test-TestRC.R: -------------------------------------------------------------------------------- 1 | test_that("regular function `a` works as expected", { 2 | expect_equal(a(1), 1) 3 | expect_equal(a(2), 2) 4 | expect_equal(a(3), 2) 5 | expect_equal(a(4), 2) 6 | expect_equal(a(0), 1) 7 | }) 8 | 9 | test_that("TestRC class can be instantiated", { 10 | t1 <- TestRC() # nolint 11 | }) 12 | 13 | test_that("TestRC Methods can be evaluated", { 14 | t1 <- TestRC() # nolint 15 | 16 | t1$show() 17 | print(t1$print2()) 18 | }) 19 | -------------------------------------------------------------------------------- /tests/testthat/TestS4/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestS4 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | RoxygenNote: 5.0.1 11 | -------------------------------------------------------------------------------- /tests/testthat/TestS4/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(a) 4 | export(print2) 5 | exportClasses(TestS4) 6 | -------------------------------------------------------------------------------- /tests/testthat/TestS4/R/TestS4.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @export 4 | #' @examples 5 | #' a(1) 6 | a <- function(x) { 7 | if (x <= 1) { 8 | 1 9 | } else { 10 | 2 11 | } 12 | } 13 | 14 | #' @export 15 | TestS4 <- setClass("TestS4", # nolint 16 | slots = list(name = "character", enabled = "logical")) 17 | 18 | #' @export 19 | setGeneric("print2", function(x, y) { 20 | }) 21 | 22 | setMethod("print2", 23 | c(x = "TestS4"), 24 | function(x) { 25 | 1 + 1 26 | }) 27 | 28 | setMethod("print2", 29 | c(x = "TestS4", y = "character"), 30 | function(x, y) { 31 | 1 + 2 32 | }) 33 | 34 | setMethod("show", 35 | c(object = "TestS4"), 36 | function(object) { 37 | 1 + 3 38 | }) 39 | -------------------------------------------------------------------------------- /tests/testthat/TestS4/codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | token: codecov_token_from_yaml 3 | -------------------------------------------------------------------------------- /tests/testthat/TestS4/man/a.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/TestS4.R 3 | \name{a} 4 | \alias{a} 5 | \title{an example function} 6 | \usage{ 7 | a(x) 8 | } 9 | \description{ 10 | an example function 11 | } 12 | \examples{ 13 | a(1) 14 | } 15 | 16 | -------------------------------------------------------------------------------- /tests/testthat/TestS4/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | 3 | suppressPackageStartupMessages(test_check("TestS4")) 4 | -------------------------------------------------------------------------------- /tests/testthat/TestS4/tests/testthat/test-TestS4.R: -------------------------------------------------------------------------------- 1 | test_that("regular function `a` works as expected", { 2 | expect_equal(a(1), 1) 3 | expect_equal(a(2), 2) 4 | expect_equal(a(3), 2) 5 | expect_equal(a(4), 2) 6 | expect_equal(a(0), 1) 7 | }) 8 | 9 | test_that("TestS4 class can be instantiated", { 10 | t1 <- TestS4() # nolint 11 | }) 12 | 13 | test_that("TestS4 Methods can be evaluated", { 14 | t1 <- TestS4() # nolint 15 | 16 | show(t1) 17 | print(print2(t1)) 18 | 19 | print(print2(t1, "hi")) 20 | }) 21 | -------------------------------------------------------------------------------- /tests/testthat/TestS7/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestS7 2 | Title: What the Package Does (One Line, Title Case) 3 | Version: 0.0.0.9000 4 | Authors@R: c( 5 | person("Jim", "Hester", , "james.f.hester@gmail.com", role = c("aut", "cre"), 6 | comment = c(ORCID = "0000-0002-2739-7082")), 7 | person("RStudio", role = c("cph", "fnd")) 8 | ) 9 | Description: What the package does (one paragraph). 10 | License: MIT + file LICENSE 11 | Encoding: UTF-8 12 | Roxygen: list(markdown = TRUE) 13 | RoxygenNote: 7.3.2 14 | Imports: S7 15 | Suggests: 16 | testthat (>= 3.0.0) 17 | Config/testthat/edition: 3 18 | -------------------------------------------------------------------------------- /tests/testthat/TestS7/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(Range) 4 | export(inside) 5 | if (getRversion() < "4.3.0") importFrom("S7", "@") 6 | import(S7) 7 | -------------------------------------------------------------------------------- /tests/testthat/TestS7/R/foo.R: -------------------------------------------------------------------------------- 1 | #' @import S7 2 | #' @export 3 | Range <- new_class("Range", 4 | properties = list( 5 | start = class_double, 6 | end = class_double, 7 | length = new_property( 8 | class = class_double, 9 | getter = function(self) self@end - self@start, 10 | setter = function(self, value) { 11 | self@end <- self@start + value 12 | self 13 | } 14 | ) 15 | ), 16 | constructor = function(x) { 17 | new_object(S7_object(), start = as.double(min(x, na.rm = TRUE)), end = as.double(max(x, na.rm = TRUE))) 18 | }, 19 | validator = function(self) { 20 | if (length(self@start) != 1) { 21 | "@start must be length 1" 22 | } else if (length(self@end) != 1) { 23 | "@end must be length 1" 24 | } else if (self@end < self@start) { 25 | "@end must be greater than or equal to @start" 26 | } 27 | } 28 | ) 29 | 30 | #' @export 31 | inside <- new_generic("inside", "x") 32 | 33 | method(inside, Range) <- function(x, y) { 34 | y >= x@start & y <= x@end 35 | } 36 | 37 | # enable usage of @name in package code 38 | #' @rawNamespace if (getRversion() < "4.3.0") importFrom("S7", "@") 39 | NULL 40 | 41 | # test external S3 generics 42 | method(format, Range) <- function(x) { 43 | sprintf("Range(%s, %s)", x@start, x@end) 44 | } 45 | 46 | testthat_print <- new_external_generic("testthat", "testthat_print", "x") 47 | method(testthat_print, Range) <- function(x, ...) { 48 | cat(format(x)) 49 | invisible(x) 50 | } 51 | 52 | .onLoad <- function(libname, pkgname) { 53 | S7::methods_register() 54 | } 55 | -------------------------------------------------------------------------------- /tests/testthat/TestS7/tests/testthat.R: -------------------------------------------------------------------------------- 1 | # This file is part of the standard setup for testthat. 2 | # It is recommended that you do not modify it. 3 | # 4 | # Where should you do additional test configuration? 5 | # Learn more about the roles of various files in: 6 | # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview 7 | # * https://testthat.r-lib.org/articles/special-files.html 8 | 9 | library(testthat) 10 | library(TestS7) 11 | 12 | test_check("TestS7") 13 | -------------------------------------------------------------------------------- /tests/testthat/TestS7/tests/testthat/test-foo.R: -------------------------------------------------------------------------------- 1 | test_that("Range works", { 2 | x <- Range(1:10) 3 | 4 | x@end <- 20 5 | 6 | expect_error(x@end <- "x", "must be ") 7 | 8 | expect_error(x@end <- -1, "greater than or equal") 9 | 10 | expect_equal(inside(x, c(0, 5, 10, 15)), c(FALSE, TRUE, TRUE, TRUE)) 11 | 12 | x@length <- 5 13 | 14 | expect_equal(x@length, 5) 15 | expect_equal(x@end, 6) 16 | }) 17 | 18 | test_that("Range methods work", { 19 | x <- Range(1:10) 20 | expect_equal(base::format(x), "Range(1, 10)") 21 | 22 | # Test external generic method for testthat::testthat_print() 23 | expect_equal(testthat::capture_output(x, print = TRUE), "Range(1, 10)") 24 | }) 25 | -------------------------------------------------------------------------------- /tests/testthat/TestSummary/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestSummary 2 | Title: What the Package Does (one line, title case) 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | -------------------------------------------------------------------------------- /tests/testthat/TestSummary/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2 (4.1.1): do not edit by hand 2 | 3 | export(dont_test_me) 4 | export(test_me) 5 | -------------------------------------------------------------------------------- /tests/testthat/TestSummary/R/TestSummary.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @export 4 | test_me <- function(x, y){ 5 | if (TRUE) 6 | x + y 7 | else 8 | x - y 9 | } 10 | 11 | #' @export 12 | dont_test_me <- function(x, y){ 13 | x * y 14 | } 15 | -------------------------------------------------------------------------------- /tests/testthat/TestSummary/man/test_me.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2 (4.1.1): do not edit by hand 2 | % Please edit documentation in R/TestSummary.R 3 | \name{test_me} 4 | \alias{test_me} 5 | \title{an example function} 6 | \usage{ 7 | test_me(x, y) 8 | } 9 | \description{ 10 | an example function 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat/TestSummary/tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library("TestSummary") 3 | 4 | test_check("TestSummary") 5 | -------------------------------------------------------------------------------- /tests/testthat/TestSummary/tests/testthat/test-TestSummary.R: -------------------------------------------------------------------------------- 1 | test_that("test_me works", { 2 | expect_equal(test_me(2, 2), 4) 3 | }) 4 | -------------------------------------------------------------------------------- /tests/testthat/TestUseTry/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: TestUseTry 2 | Title: Test That `use_try` Parameter works 3 | Version: 0.0.0.9000 4 | Authors@R: "First Last [aut, cre]" 5 | Description: What the package does (one paragraph) 6 | Depends: 7 | R (>= 3.1.2) 8 | License: What license is it under? 9 | LazyData: true 10 | Suggests: 11 | testthat 12 | -------------------------------------------------------------------------------- /tests/testthat/TestUseTry/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2 (4.1.1): do not edit by hand 2 | 3 | export(fun) 4 | -------------------------------------------------------------------------------- /tests/testthat/TestUseTry/R/notry.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | 3 | fun <- function() { 4 | withCallingHandlers( 5 | signalCondition(simpleError("This Will Exit if `!isTRUE(use_try)`")), 6 | error = function(e) TRUE 7 | ) 8 | 1 + 1 9 | 2 + 2 10 | "hello" 11 | "welcome" 12 | TRUE 13 | } 14 | -------------------------------------------------------------------------------- /tests/testthat/TestUseTry/tests/tests.R: -------------------------------------------------------------------------------- 1 | TestUseTry::fun() 2 | -------------------------------------------------------------------------------- /tests/testthat/TestUseTry/tests/testthat/test-notry.R: -------------------------------------------------------------------------------- 1 | expect_true(TestUseTry::fun()) 2 | -------------------------------------------------------------------------------- /tests/testthat/Testbox/app/app.R: -------------------------------------------------------------------------------- 1 | options(box.path = file.path(getwd())) 2 | # remove box cache 3 | loaded_mods <- loadNamespace("box")$loaded_mods 4 | rm(list = ls(loaded_mods), envir = loaded_mods) 5 | 6 | box::use( 7 | app/modules/module 8 | ) 9 | -------------------------------------------------------------------------------- /tests/testthat/Testbox/app/modules/module.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @export 4 | a <- function(x) { 5 | if (x <= 1) { 6 | 1 7 | } else { 8 | 2 9 | } 10 | } 11 | 12 | private_function <- function(x) { 13 | x ^ 2 14 | } 15 | -------------------------------------------------------------------------------- /tests/testthat/Testbox/tests/testthat.R: -------------------------------------------------------------------------------- 1 | options(box.path = file.path(getwd())) 2 | # remove box cache 3 | loaded_mods <- loadNamespace("box")$loaded_mods 4 | rm(list = ls(loaded_mods), envir = loaded_mods) 5 | 6 | library(testthat) 7 | 8 | test_dir("tests/testthat") 9 | -------------------------------------------------------------------------------- /tests/testthat/Testbox/tests/testthat/test-module.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | testthat[test_that, expect_equal] 3 | ) 4 | 5 | box::use( 6 | app/modules/module 7 | ) 8 | 9 | impl <- attr(module, "namespace") 10 | 11 | test_that("regular function `a` works as expected", { 12 | expect_equal(module$a(1), 1) 13 | expect_equal(module$a(2), 2) 14 | expect_equal(module$a(3), 2) 15 | expect_equal(module$a(4), 2) 16 | expect_equal(module$a(0), 1) 17 | }) 18 | 19 | test_that("private function works as expected", { 20 | expect_equal(impl$private_function(2), 4) 21 | expect_equal(impl$private_function(3), 9) 22 | expect_equal(impl$private_function(4), 16) 23 | }) 24 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_R6/app/app.R: -------------------------------------------------------------------------------- 1 | options(box.path = file.path(getwd())) 2 | # remove box cache 3 | loaded_mods <- loadNamespace("box")$loaded_mods 4 | rm(list = ls(loaded_mods), envir = loaded_mods) 5 | 6 | box::use( 7 | app/modules/moduleR6 8 | ) 9 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_R6/app/modules/moduleR6.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | TestR6 <- R6::R6Class("TestR6", # nolint 3 | public = list( 4 | show = function(x) { 5 | 1 + 3 6 | }, 7 | print2 = function(x) { 8 | 1 + 2 9 | } 10 | ) 11 | ) 12 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_R6/tests/testthat.R: -------------------------------------------------------------------------------- 1 | options(box.path = file.path(getwd())) 2 | # remove box cache 3 | loaded_mods <- loadNamespace("box")$loaded_mods 4 | rm(list = ls(loaded_mods), envir = loaded_mods) 5 | 6 | library(testthat) 7 | 8 | test_dir("tests/testthat") 9 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_R6/tests/testthat/test-moduleR6.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | testthat[test_that, expect_equal, expect_s3_class] 3 | ) 4 | 5 | box::use( 6 | app/modules/moduleR6 7 | ) 8 | 9 | test_that("TestR6 class can be instantiated", { 10 | skip_if(is_r_devel()) 11 | t1 <- moduleR6$TestR6$new() # nolint 12 | 13 | expect_s3_class(t1, "R6") 14 | expect_s3_class(t1, "TestR6") 15 | }) 16 | 17 | test_that("TestR6 Methods can be evaluated", { 18 | skip_if(is_r_devel()) 19 | t1 <- moduleR6$TestR6$new() # nolint 20 | 21 | expect_equal(t1$show(), 4) 22 | expect_equal(print(t1$print2()), 3) 23 | }) 24 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_attached_modules_functions/app/app.R: -------------------------------------------------------------------------------- 1 | options(box.path = file.path(getwd())) 2 | # remove box cache 3 | loaded_mods <- loadNamespace("box")$loaded_mods 4 | rm(list = ls(loaded_mods), envir = loaded_mods) 5 | 6 | box::use( 7 | app/modules/module 8 | ) 9 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_attached_modules_functions/app/modules/module.R: -------------------------------------------------------------------------------- 1 | #' an example function 2 | #' 3 | #' @export 4 | a <- function(x) { 5 | if (x <= 1) { 6 | 1 7 | } else { 8 | 2 9 | } 10 | } 11 | 12 | #' @export 13 | b <- function(x) { 14 | return(x * 2) 15 | } 16 | 17 | private_function <- function(x) { 18 | x ^ 2 19 | } 20 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_attached_modules_functions/tests/testthat.R: -------------------------------------------------------------------------------- 1 | options(box.path = file.path(getwd())) 2 | # remove box cache 3 | loaded_mods <- loadNamespace("box")$loaded_mods 4 | rm(list = ls(loaded_mods), envir = loaded_mods) 5 | 6 | library(testthat) 7 | 8 | test_dir("tests/testthat") 9 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_attached_modules_functions/tests/testthat/test-aliased_functions.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | testthat[test_that, expect_equal] 3 | ) 4 | 5 | box::use( 6 | app/modules/module[x = a] 7 | ) 8 | 9 | test_that("attached regular function `a` works as expected", { 10 | expect_equal(x(1), 1) 11 | expect_equal(x(2), 2) 12 | expect_equal(x(3), 2) 13 | expect_equal(x(4), 2) 14 | expect_equal(x(0), 1) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_attached_modules_functions/tests/testthat/test-aliased_modules.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | testthat[test_that, expect_equal] 3 | ) 4 | 5 | box::use( 6 | x = app/modules/module 7 | ) 8 | 9 | test_that("attached regular function `a` works as expected", { 10 | expect_equal(x$a(1), 1) 11 | expect_equal(x$a(2), 2) 12 | expect_equal(x$a(3), 2) 13 | expect_equal(x$a(4), 2) 14 | expect_equal(x$a(0), 1) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_attached_modules_functions/tests/testthat/test-attached_functions.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | testthat[test_that, expect_equal] 3 | ) 4 | 5 | box::use( 6 | app/modules/module[a] 7 | ) 8 | 9 | test_that("attached regular function `a` works as expected", { 10 | expect_equal(a(1), 1) 11 | expect_equal(a(2), 2) 12 | expect_equal(a(3), 2) 13 | expect_equal(a(4), 2) 14 | expect_equal(a(0), 1) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_attached_modules_functions/tests/testthat/test-three_dots.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | testthat[test_that, expect_equal] 3 | ) 4 | 5 | box::use( 6 | app/modules/module[...] 7 | ) 8 | 9 | test_that("attached regular function `a` works as expected", { 10 | expect_equal(a(1), 1) 11 | expect_equal(a(2), 2) 12 | expect_equal(a(3), 2) 13 | expect_equal(a(4), 2) 14 | expect_equal(a(0), 1) 15 | }) 16 | 17 | test_that("attached regular function `b` works as expected", { 18 | expect_equal(b(1), 2) 19 | expect_equal(b(2), 4) 20 | expect_equal(b(3), 6) 21 | }) 22 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_attached_modules_functions_R6/app/app.R: -------------------------------------------------------------------------------- 1 | options(box.path = file.path(getwd())) 2 | # remove box cache 3 | loaded_mods <- loadNamespace("box")$loaded_mods 4 | rm(list = ls(loaded_mods), envir = loaded_mods) 5 | 6 | box::use( 7 | app/modules/moduleR6 8 | ) 9 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_attached_modules_functions_R6/app/modules/moduleR6.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | TestR6 <- R6::R6Class("TestR6", # nolint 3 | public = list( 4 | show = function(x) { 5 | 1 + 3 6 | }, 7 | print2 = function(x) { 8 | 1 + 2 9 | } 10 | ) 11 | ) 12 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_attached_modules_functions_R6/tests/testthat.R: -------------------------------------------------------------------------------- 1 | options(box.path = file.path(getwd())) 2 | # remove box cache 3 | loaded_mods <- loadNamespace("box")$loaded_mods 4 | rm(list = ls(loaded_mods), envir = loaded_mods) 5 | 6 | library(testthat) 7 | 8 | test_dir("tests/testthat") 9 | -------------------------------------------------------------------------------- /tests/testthat/Testbox_attached_modules_functions_R6/tests/testthat/test-attached_R6.R: -------------------------------------------------------------------------------- 1 | box::use( 2 | testthat[test_that, expect_equal, expect_s3_class] 3 | ) 4 | 5 | box::use( 6 | app/modules/moduleR6[TestR6] 7 | ) 8 | 9 | test_that("TestR6 class can be instantiated", { 10 | skip_if(is_r_devel()) 11 | t1 <- TestR6$new() # nolint 12 | 13 | expect_s3_class(t1, "R6") 14 | expect_s3_class(t1, "TestR6") 15 | }) 16 | 17 | test_that("TestR6 Methods can be evaluated", { 18 | skip_if(is_r_devel()) 19 | t1 <- TestR6$new() # nolint 20 | 21 | expect_equal(t1$show(), 4) 22 | expect_equal(t1$print2(), 3) 23 | }) 24 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/Compiled.md: -------------------------------------------------------------------------------- 1 | # Error thrown for missing gcov 2 | 3 | Code 4 | package_coverage("TestCompiled", relative_path = TRUE) 5 | Condition 6 | Error in `run_gcov()`: 7 | ! gcov not found 8 | 9 | # Warning thrown for empty gcov output 10 | 11 | Code 12 | . <- package_coverage("TestCompiled", relative_path = TRUE) 13 | Condition 14 | Warning in `run_gcov()`: 15 | parsed gcov output was empty 16 | 17 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/S7.md: -------------------------------------------------------------------------------- 1 | # S7 coverage is reported 2 | 3 | Code 4 | cov[, c("functions", "first_line", "last_line", "value")] 5 | Output 6 | functions first_line last_line value 7 | 1 Range@properties$length$getter 9 9 1 8 | 2 Range@properties$length$setter 11 11 1 9 | 3 Range@properties$length$setter 12 12 1 10 | 4 Range 17 17 2 11 | 5 Range@validator 20 20 5 12 | 6 Range@validator 21 21 0 13 | 7 Range@validator 22 22 5 14 | 8 Range@validator 23 23 0 15 | 9 Range@validator 24 24 5 16 | 10 Range@validator 25 25 1 17 | 11 method(inside, TestS7::Range) 34 34 1 18 | 12 method(base::format, TestS7::Range) 43 43 2 19 | 13 method(testthat::testthat_print, TestS7::Range) 48 48 1 20 | 14 method(testthat::testthat_print, TestS7::Range) 49 49 1 21 | 15 .onLoad 53 53 0 22 | 23 | -------------------------------------------------------------------------------- /tests/testthat/a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/covr/40122df12bc9ef1e577dd0720a895b5340b1516f/tests/testthat/a -------------------------------------------------------------------------------- /tests/testthat/b: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/covr/40122df12bc9ef1e577dd0720a895b5340b1516f/tests/testthat/b -------------------------------------------------------------------------------- /tests/testthat/cobertura.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | /dummy/directory 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /tests/testthat/corner-cases-test.R: -------------------------------------------------------------------------------- 1 | fun1() 2 | fun2() 3 | fun3() 4 | fun4(1) 5 | fun4(1L) 6 | -------------------------------------------------------------------------------- /tests/testthat/corner-cases.R: -------------------------------------------------------------------------------- 1 | make_fun_1 <- function() { 2 | function(x) { 3 | 2 + 2 4 | 1 + 1 5 | cat("fun1\n") 6 | } 7 | } 8 | make_fun_2 <- function() { 9 | function(x) { 10 | 3 + 3 11 | 4 + 4 12 | cat("fun2\n") 13 | } 14 | } 15 | #' @export 16 | 17 | fun1 <- make_fun_1() 18 | 19 | #' @export 20 | 21 | fun2 <- function(x) { 22 | 2 + 2 23 | 1 + 1 24 | cat("fun2\n") 25 | } 26 | #' @export 27 | 28 | fun3 <- function() { 29 | 30 | if(FALSE) 31 | 1 32 | else 33 | 2 34 | 35 | 1 + 36 | 1; if(TRUE) 1 else 2 37 | 38 | if(FALSE) 3 else 4 39 | if(FALSE) {3} else {4} 40 | 41 | if(TRUE) 3 else {1 + 1 42 | 2 + 2 43 | } 44 | {1 + 1; 2 + 2}; if(FALSE) 1 else 2; {TRUE} 45 | {1 + 1; 2 + 2}; "hello"; {TRUE} 46 | if(TRUE) { 47 | {1 + 1; 2 + 2}; "hello"; {TRUE} 48 | {1 + 1; 2 + 2}; if(FALSE) 1 else 2; {TRUE} 49 | } else { 50 | {1 + 1; 2 + 2}; "hello"; {TRUE} 51 | {1 + 1; 2 + 2}; if(FALSE) 1 else 2; {TRUE} 52 | } 53 | } 54 | #' @export 55 | 56 | setGeneric("fun4", function(x) StandardGeneric("fun2")) 57 | 58 | setMethod("fun4", "integer", make_fun_2()) 59 | setMethod("fun4", "numeric", make_fun_1()) 60 | -------------------------------------------------------------------------------- /tests/testthat/corner-cases.Rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/covr/40122df12bc9ef1e577dd0720a895b5340b1516f/tests/testthat/corner-cases.Rds -------------------------------------------------------------------------------- /tests/testthat/helper.R: -------------------------------------------------------------------------------- 1 | is_r_devel <- function() { 2 | startsWith(R.version$status, "Under development") 3 | } 4 | 5 | is_win_r41 <- function() { 6 | x <- getRversion() 7 | is_windows() && x$major == 4 && x$minor == 1 8 | } 9 | -------------------------------------------------------------------------------- /tests/testthat/sonarqube.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/testthat/test-Compiled.R: -------------------------------------------------------------------------------- 1 | test_that("Compiled code coverage is reported including code in headers", { 2 | skip_on_cran() 3 | skip_if(is_win_r41()) 4 | 5 | cov <- as.data.frame(package_coverage("TestCompiled", relative_path = TRUE)) 6 | 7 | simple_cc <- cov[cov$filename == "src/simple.cc", ] 8 | expect_equal(simple_cc[simple_cc$first_line == "10", "value"], 4) 9 | 10 | expect_equal(simple_cc[simple_cc$first_line == "16", "value"], 3) 11 | 12 | expect_equal(simple_cc[simple_cc$first_line == "19", "value"], 0) 13 | 14 | expect_equal(simple_cc[simple_cc$first_line == "21", "value"], 1) 15 | 16 | expect_equal(simple_cc[simple_cc$first_line == "23", "value"], 4) 17 | 18 | # This header contains a C++ template, which requires you to run gcov for 19 | # each object file separately and merge the results together. 20 | simple_h <- cov[cov$filename == "src/simple-header.h", ] 21 | expect_equal(simple_h[simple_h$first_line == "12", "value"], 4) 22 | 23 | expect_equal(simple_h[simple_h$first_line == "18", "value"], 3) 24 | 25 | expect_equal(simple_h[simple_h$first_line == "21", "value"], 0) 26 | 27 | expect_equal(simple_h[simple_h$first_line == "23", "value"], 1) 28 | 29 | expect_equal(simple_h[simple_h$first_line == "25", "value"], 4) 30 | 31 | expect_true(all(unique(cov$filename) %in% c("R/TestCompiled.R", "src/simple-header.h", "src/simple.cc", "src/simple4.cc"))) 32 | }) 33 | 34 | test_that("Can pass path to relative_path argument", { 35 | skip_on_cran() 36 | skip_if(is_win_r41()) 37 | cov <- as.data.frame(package_coverage("TestCompiled", relative_path = ".")) 38 | 39 | expect_true(all(unique(cov$filename) %in% c( 40 | "TestCompiled/R/TestCompiled.R", 41 | "TestCompiled/src/simple-header.h", 42 | "TestCompiled/src/simple.cc", 43 | "TestCompiled/src/simple4.cc" 44 | ))) 45 | }) 46 | 47 | test_that("Source code subdirectories are found", { 48 | skip_on_cran() 49 | skip_if(is_win_r41()) 50 | cov <- as.data.frame(package_coverage("TestCompiledSubdir", relative_path = TRUE)) 51 | 52 | expect_equal(cov[cov$first_line == "9", "value"], 4) 53 | 54 | expect_equal(cov[cov$first_line == "15", "value"], 3) 55 | 56 | expect_equal(cov[cov$first_line == "18", "value"], 0) 57 | 58 | expect_equal(cov[cov$first_line == "20", "value"], 1) 59 | 60 | expect_equal(cov[cov$first_line == "22", "value"], 4) 61 | }) 62 | 63 | test_that("Compiled code coverage is reported under non-standard char's", { 64 | skip_on_cran() 65 | skip_if(is_win_r41()) 66 | cov <- as.data.frame(package_coverage("Test+Char/TestCompiled", relative_path = TRUE)) 67 | 68 | expect_equal(cov[cov$first_line == "9", "value"], 4) 69 | 70 | expect_equal(cov[cov$first_line == "15", "value"], 3) 71 | 72 | expect_equal(cov[cov$first_line == "18", "value"], 0) 73 | 74 | expect_equal(cov[cov$first_line == "20", "value"], 1) 75 | 76 | expect_equal(cov[cov$first_line == "22", "value"], 4) 77 | }) 78 | 79 | test_that("Error thrown for missing gcov", { 80 | skip_on_cran() 81 | 82 | withr::local_options(covr.gcov='') 83 | expect_snapshot(package_coverage("TestCompiled", relative_path=TRUE), error = TRUE) 84 | }) 85 | 86 | test_that("Warning thrown for empty gcov output", { 87 | skip_on_cran() 88 | 89 | withr::local_options(covr.gcov_args='-n') 90 | expect_snapshot( 91 | . <- package_coverage("TestCompiled", relative_path=TRUE), 92 | transform = function(x) gsub(getwd(), "", x) 93 | ) 94 | }) 95 | 96 | test_that("tally_coverage includes compiled code", { 97 | skip_on_cran() 98 | skip_if(is_win_r41()) 99 | 100 | cov <- package_coverage(test_path("TestCompiled")) 101 | tall <- tally_coverage(cov) 102 | 103 | expect_named(tall, c("filename", "functions", "line", "value")) 104 | 105 | expect_equal( 106 | unique(tall$filename), 107 | c("R/TestCompiled.R", "src/simple-header.h", "src/simple.cc", "src/simple4.cc")) 108 | }) 109 | -------------------------------------------------------------------------------- /tests/testthat/test-R6.R: -------------------------------------------------------------------------------- 1 | test_that("R6 methods coverage is reported", { 2 | # There is some sort of bug that causes this test to fail during R CMD check 3 | # in R-devel, not sure why, and can't reproduce it interactively 4 | skip_if(is_r_devel()) 5 | cov <- as.data.frame(package_coverage(test_path("TestR6"))) 6 | 7 | expect_equal(cov$value, c(5, 2, 3, 1, 1, 0)) 8 | expect_equal(cov$first_line, c(5, 6, 8, 16, 19, 27)) 9 | expect_equal(cov$last_line, c(5, 6, 8, 16, 19, 27)) 10 | expect_true("some_method" %in% cov$functions) 11 | }) 12 | -------------------------------------------------------------------------------- /tests/testthat/test-RC.R: -------------------------------------------------------------------------------- 1 | test_that("RC methods coverage is reported", { 2 | cov <- as.data.frame(package_coverage("TestRC")) 3 | 4 | expect_equal(cov$value, c(5, 2, 3, 1, 1)) 5 | expect_equal(cov$first_line, c(5, 6, 8, 17, 20)) 6 | expect_equal(cov$last_line, c(5, 6, 8, 17, 20)) 7 | }) 8 | -------------------------------------------------------------------------------- /tests/testthat/test-S4.R: -------------------------------------------------------------------------------- 1 | test_that("S4 methods coverage is reported", { 2 | cov <- as.data.frame(package_coverage("TestS4")) 3 | 4 | expect_equal(cov$first_line, c(7, 8, 10, 25, 31, 37)) 5 | 6 | expect_equal(cov$value, c(5, 2, 3, 1, 1, 1)) 7 | }) 8 | -------------------------------------------------------------------------------- /tests/testthat/test-S7.R: -------------------------------------------------------------------------------- 1 | test_that("S7 coverage is reported", { 2 | skip_if_not_installed("S7") 3 | cov <- as.data.frame(package_coverage(test_path("TestS7"))) 4 | 5 | expect_equal(cov$value, c(1, 1, 1, 2, 5, 0, 5, 0, 5, 1, 1, 2, 1, 1, 0)) 6 | expect_snapshot(cov[, c("functions", "first_line", "last_line", "value")]) 7 | }) 8 | -------------------------------------------------------------------------------- /tests/testthat/test-azure.R: -------------------------------------------------------------------------------- 1 | test_that("azure_pipelines calls package_coverage and to_cobertura", { 2 | 3 | tf <- tempfile() 4 | on.exit(unlink(tf)) 5 | 6 | azure(test_path("TestS4"), filename = tf) 7 | 8 | expect_true(file.exists(tf)) 9 | }) 10 | -------------------------------------------------------------------------------- /tests/testthat/test-box-R6.R: -------------------------------------------------------------------------------- 1 | loaded_mods <- loadNamespace("box")$loaded_mods 2 | rm(list = ls(loaded_mods), envir = loaded_mods) 3 | 4 | test_that("R6 box module coverage is reported", { 5 | # Similar to test-R6.R, there is some sort of bug that causes this test 6 | # to fail during R CMD check in R-devel, not sure why, and can't reproduce 7 | # it interactively 8 | skip_if(is_r_devel()) 9 | withr::with_dir("Testbox_R6", { 10 | cov <- as.data.frame(file_coverage( 11 | source_files = "app/app.R", 12 | test_files = list.files("tests/testthat", full.names = TRUE))) 13 | 14 | expect_equal(cov$value, c(1, 1)) 15 | expect_equal(cov$first_line, c(5, 8)) 16 | expect_equal(cov$last_line, c(5, 8)) 17 | expect_true("show" %in% cov$functions) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /tests/testthat/test-box.R: -------------------------------------------------------------------------------- 1 | loaded_mods <- loadNamespace("box")$loaded_mods 2 | rm(list = ls(loaded_mods), envir = loaded_mods) 3 | 4 | test_that("box module coverage is reported", { 5 | withr::with_dir("Testbox", { 6 | cov <- as.data.frame(file_coverage( 7 | source_files = "app/app.R", 8 | test_files = list.files("tests/testthat", full.names = TRUE))) 9 | 10 | expect_equal(cov$value, c(5, 2, 3, 3)) 11 | expect_equal(cov$first_line, c(5, 6, 8, 13)) 12 | expect_equal(cov$last_line, c(5, 6, 8, 13)) 13 | expect_true("a" %in% cov$functions) 14 | expect_true("private_function" %in% cov$functions) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /tests/testthat/test-box_attached_modules_functions-R6.R: -------------------------------------------------------------------------------- 1 | loaded_mods <- loadNamespace("box")$loaded_mods 2 | rm(list = ls(loaded_mods), envir = loaded_mods) 3 | 4 | test_that("R6 box attached module coverage is reported", { 5 | # Similar to test-R6.R, there is some sort of bug that causes this test 6 | # to fail during R CMD check in R-devel, not sure why, and can't reproduce 7 | # it interactively 8 | skip_if(is_r_devel()) 9 | withr::with_dir("Testbox_attached_modules_functions_R6", { 10 | cov <- as.data.frame(file_coverage( 11 | source_files = "app/app.R", 12 | test_files = list.files("tests/testthat", full.names = TRUE))) 13 | 14 | expect_equal(cov$value, c(1, 1)) 15 | expect_equal(cov$first_line, c(5, 8)) 16 | expect_equal(cov$last_line, c(5, 8)) 17 | expect_true("show" %in% cov$functions) 18 | }) 19 | 20 | }) 21 | -------------------------------------------------------------------------------- /tests/testthat/test-box_attached_modules_functions.R: -------------------------------------------------------------------------------- 1 | loaded_mods <- loadNamespace("box")$loaded_mods 2 | rm(list = ls(loaded_mods), envir = loaded_mods) 3 | 4 | test_that("box attached module coverage is reported", { 5 | withr::with_dir("Testbox_attached_modules_functions", { 6 | cov <- as.data.frame(file_coverage( 7 | source_files = "app/app.R", 8 | test_files = list.files("tests/testthat", full.names = TRUE))) 9 | 10 | expect_equal(cov$value, c(20, 8, 12, 3, 0)) 11 | expect_equal(cov$first_line, c(5, 6, 8, 14, 18)) 12 | expect_equal(cov$last_line, c(5, 6, 8, 14, 18)) 13 | expect_true("a" %in% cov$functions) 14 | expect_true("private_function" %in% cov$functions) 15 | }) 16 | 17 | }) 18 | -------------------------------------------------------------------------------- /tests/testthat/test-braceless.R: -------------------------------------------------------------------------------- 1 | test_that("if", { 2 | f <- 3 | 'f <- function(x) { 4 | if (FALSE) 5 | FALSE # never covered, used as anchor 6 | if (x) 7 | TRUE 8 | else 9 | FALSE 10 | }' 11 | 12 | cov <- code_coverage(f, "f(TRUE)") 13 | expect_equal(zero_coverage(code_coverage(f, "f(TRUE)"))$line, c(3, 7)) 14 | expect_equal(zero_coverage(code_coverage(f, "f(FALSE)"))$line, c(3, 5)) 15 | expect_equal(zero_coverage(code_coverage(f, "f(TRUE);f(FALSE)"))$line, 3) 16 | }) 17 | test_that("nested if else", { 18 | f <- 19 | 'f <- function(x) { 20 | if (FALSE) 21 | FALSE # never covered, used as anchor 22 | else if (x) 23 | TRUE 24 | else 25 | FALSE 26 | }' 27 | 28 | cov <- code_coverage(f, "f(TRUE)") 29 | expect_equal(zero_coverage(code_coverage(f, "f(TRUE)"))$line, c(3, 7)) 30 | expect_equal(zero_coverage(code_coverage(f, "f(FALSE)"))$line, c(3, 5)) 31 | expect_equal(zero_coverage(code_coverage(f, "f(TRUE);f(FALSE)"))$line, 3) 32 | }) 33 | 34 | test_that("switch", { 35 | f <- 36 | 'f <- function(x) { 37 | switch(x, 38 | a = 1, 39 | b = 2, 40 | c = d <- 1 41 | ) 42 | }' 43 | 44 | expect_equal(length(zero_coverage(code_coverage(f, "f(\"a\"); f(\"b\")"))$line), 45 | 1) 46 | expect_equal(length(zero_coverage(code_coverage(f, "f(\"a\"); f(\"c\")"))$line), 47 | 1) 48 | expect_equal(diff(zero_coverage(code_coverage(f, "f(\"a\"); f(\"d\")"))$line), 49 | 1) 50 | }) 51 | 52 | test_that("switch with default value", { 53 | f <- 54 | 'f <- function(x) { 55 | switch(x, 56 | a = 1, 57 | b = 2, 58 | c = d <- 1, 59 | NULL 60 | ) 61 | }' 62 | 63 | expect_equal(length(zero_coverage(code_coverage(f, "f(\"a\"); f(\"b\"); f(\"c\")"))$line), 64 | 1) 65 | 66 | expect_equal(length(zero_coverage(code_coverage(f, "f(\"a\"); f(\"c\")"))$line), 67 | 2) 68 | }) 69 | 70 | test_that("switch with drop through", { 71 | f <- 72 | 'f <- function(x) { 73 | switch(x, 74 | a = , 75 | b = 2, 76 | c = d <- 1, 77 | NULL 78 | ) 79 | }' 80 | 81 | res <- as.data.frame(code_coverage(f, 'f("a");f("b");f("c")')) 82 | expect_equal(res$first_line, c(2, 4, 5, 6)) 83 | expect_equal(res$value, c(3, 2, 1, 0)) 84 | 85 | }) 86 | 87 | test_that("switch with ellipses", { 88 | f <- 89 | 'f <- function(x, ...) { 90 | switch(typeof(x), ...) 91 | }' 92 | 93 | res <- as.data.frame(code_coverage(f, "f(\"a\", character = TRUE)")) 94 | expect_equal(res$first_line, 2) 95 | expect_equal(res$value, 1) 96 | 97 | f <- 98 | 'f <- function(x, ...) { 99 | switch(typeof(x), 100 | ..., 101 | character = TRUE) 102 | }' 103 | 104 | res <- as.data.frame(code_coverage(f, "f(\"a\")")) 105 | expect_equal(res$first_line, c(2, 4)) 106 | expect_equal(res$value, c(1, 1)) 107 | }) 108 | -------------------------------------------------------------------------------- /tests/testthat/test-cobertura.R: -------------------------------------------------------------------------------- 1 | test_that("it works with coverage objects", { 2 | tmp <- tempfile() 3 | cov <- package_coverage(test_path("TestSummary")) 4 | 5 | attr(cov, "package")$path <- "/dummy/directory" 6 | to_cobertura(cov, filename = tmp) 7 | 8 | expect_equal( 9 | readLines(tmp)[c(-1, -2, -3)], 10 | readLines(test_path("cobertura.xml"))[c(-1, -2, -3)] 11 | ) 12 | }) 13 | -------------------------------------------------------------------------------- /tests/testthat/test-corner-cases.R: -------------------------------------------------------------------------------- 1 | test_that("corner-cases are handled as expected", { 2 | expect_warning(withr::with_output_sink(tempfile(), { 3 | cov <- file_coverage("corner-cases.R", "corner-cases-test.R") 4 | })) 5 | 6 | expect_equal(as.data.frame(cov), readRDS("corner-cases.Rds")) 7 | }) 8 | -------------------------------------------------------------------------------- /tests/testthat/test-covr.R: -------------------------------------------------------------------------------- 1 | test_that("function_coverage", { 2 | 3 | withr::with_options(c(keep.source = TRUE), { 4 | f <- function(x) { 5 | x + 1 6 | } 7 | expect_equal(as.numeric(function_coverage("f", env = environment(f))[[1]]$value), 0) 8 | 9 | expect_equal(as.numeric(function_coverage("f", env = environment(f), f(1))[[1]]$value), 1) 10 | 11 | expect_equal(as.numeric(function_coverage("f", env = environment(f), f(1), f(1))[[1]]$value), 2) 12 | }) 13 | }) 14 | 15 | test_that("function_coverage identity function", { 16 | 17 | withr::with_options(c(keep.source = TRUE), { 18 | fun <- function(x) { 19 | x 20 | } 21 | 22 | cov_num <- function(...) { 23 | as.numeric(function_coverage("fun", env = environment(fun), ...)[[1]]$value) 24 | } 25 | 26 | expect_equal(cov_num(), 0) 27 | expect_equal(cov_num(fun(1)), 1) 28 | }) 29 | }) 30 | 31 | test_that("function_coverage return last expr", { 32 | 33 | withr::with_options(c(keep.source = TRUE), { 34 | fun <- function(x = 1) { 35 | x 36 | x <- 1 37 | } 38 | 39 | cov_fun <- function(...) { 40 | vdapply(function_coverage("fun", env = environment(fun), ...), "[[", "value") 41 | } 42 | 43 | expect_equal(as.numeric(cov_fun()), c(0L, 0L)) 44 | expect_equal(as.numeric(cov_fun(fun())), c(1L, 1L)) 45 | }) 46 | }) 47 | 48 | test_that("duplicated first_line", { 49 | withr::with_options(c(keep.source = TRUE), { 50 | 51 | fun <- function() { 52 | res <- lapply(1:2, function(x) { x + 1 }) # nolint 53 | } 54 | cov <- function_coverage("fun", env = environment(fun)) 55 | first_lines <- as.data.frame(cov)$first_line 56 | expect_equal(length(first_lines), 2) 57 | expect_equal(first_lines[1], first_lines[2]) 58 | }) 59 | }) 60 | 61 | test_that("trace calls handles all possibilities", { 62 | expr <- expression(y <- x * 10) 63 | 64 | expect_equal(trace_calls(expr), expr) 65 | 66 | expect_equal(trace_calls(list(expr)), list(expr)) 67 | }) 68 | 69 | test_that("show_failures shows as much text as it can from the end", { 70 | withr::with_options(c(warning.length = 300), { 71 | td <- tempfile() 72 | dir.create(td) 73 | 74 | out <- file.path(td, "test.Rout.fail") 75 | on.exit(unlink(td, recursive = TRUE)) 76 | writeLines( 77 | "Lorem ipsum dolor sit amet, at erat praesent est mi ultrices. Eget in platea ac auctor et eu et venenatis. Tellus volutpat pellentesque. Dis nulla sem dignissim venenatis. Consequat montes maecenas congue donec ac himenaeos sed sed tempus. Ipsum risus lacus? Malesuada lectus, lacus egestas et lacus, in in ut sed. Tempus ligula dignissim a elementum semper maecenas eu. Enim pellentesque turpis at et ligula in est ut. Accumsan quis fermentum convallis proin ligula primis ut, curabitur. Sociosqu, fringilla, eu lacus eleifend conubia pellentesque viverra.", 78 | out 79 | ) 80 | 81 | # Expect the error to contain the end of the file 82 | expect_error(show_failures(td), "eleifend conubia pellentesque viverra.", fixed = TRUE, class = "covr_error") 83 | }) 84 | }) 85 | -------------------------------------------------------------------------------- /tests/testthat/test-file_coverage.R: -------------------------------------------------------------------------------- 1 | s1 <- tempfile() 2 | t1 <- tempfile() 3 | writeLines(con = s1, 4 | "a <- function(x) { 5 | x + 1 6 | } 7 | 8 | b <- function(x) { 9 | if (x > 1) TRUE 10 | else FALSE 11 | }") 12 | 13 | writeLines(con = t1, 14 | "a(1) 15 | a(2) 16 | a(3) 17 | b(0) 18 | b(1) 19 | b(2)") 20 | 21 | on.exit(unlink(c(s1, t1))) 22 | 23 | test_that("it works on single files", { 24 | cov <- file_coverage(s1, t1) 25 | cov_d <- as.data.frame(cov) 26 | 27 | expect_equal(cov_d$functions, c("a", "b", "b", "b")) 28 | expect_equal(cov_d$value, c(3, 3, 1, 2)) 29 | }) 30 | -------------------------------------------------------------------------------- /tests/testthat/test-functions.R: -------------------------------------------------------------------------------- 1 | test_that("function_coverage generates output", { 2 | env <- new.env() 3 | withr::with_options(c("keep.source" = TRUE), { 4 | eval(parse(text = 5 | "fun <- function(x) { 6 | if (isTRUE(x)) { 7 | 1 8 | } else { 9 | 2 10 | } 11 | }"), envir = env) 12 | }) 13 | 14 | t1 <- function_coverage("fun", env = env) 15 | 16 | expect_equal(length(t1), 3) 17 | 18 | expect_equal(length(exclude(t1)), 3) 19 | 20 | expect_equal(length(exclude(t1, "")), 0) 21 | 22 | expect_equal(length(exclude(t1, list("" = 3))), 2) 23 | }) 24 | -------------------------------------------------------------------------------- /tests/testthat/test-gcov.R: -------------------------------------------------------------------------------- 1 | test_that("parse_gcov parses files properly", { 2 | local_mocked_bindings( 3 | # functions called within parse_gcov 4 | file.exists = function(path) TRUE, 5 | normalize_path = function(path) "simple.c", 6 | line_coverages = function(source_file, matches, values, ...) values 7 | ) 8 | 9 | with_mocked_bindings( 10 | readLines = function(x) { 11 | " -: 0:Source:simple.c" 12 | }, 13 | expect_equal(parse_gcov("hi.c.gcov"), numeric()) 14 | ) 15 | 16 | with_mocked_bindings( 17 | readLines = function(x) { 18 | c( 19 | " -: 0:Source:simple.c", 20 | " -: 1:#define USE_RINTERNALS" 21 | ) 22 | }, 23 | expect_equal(parse_gcov("hi.c.gcov"), numeric()) 24 | ) 25 | 26 | with_mocked_bindings( 27 | readLines = function(x) { 28 | c( 29 | " -: 0:Source:simple.c", 30 | " -: 0:Graph:simple.gcno", 31 | " -: 0:Data:simple.gcda", 32 | " -: 0:Runs:1", 33 | " -: 0:Programs:1", 34 | " -: 1:#define USE_RINTERNALS", 35 | " -: 2:#include ", 36 | " -: 3:#include ", 37 | " -: 4:#include ", 38 | " -: 5:", 39 | " 4: 6:SEXP simple_(SEXP x) {" 40 | ) 41 | }, 42 | expect_equal(parse_gcov("hi.c.gcov"), 4) 43 | ) 44 | with_mocked_bindings( 45 | readLines = function(x) { 46 | c( 47 | " -: 0:Source:simple.c", 48 | " -: 0:Graph:simple.gcno", 49 | " -: 0:Data:simple.gcda", 50 | " -: 0:Runs:1", 51 | " -: 0:Programs:1", 52 | " -: 1:#define USE_RINTERNALS", 53 | " -: 2:#include ", 54 | " -: 3:#include ", 55 | " -: 4:#include ", 56 | " -: 5:", 57 | " 4: 6:SEXP simple_(SEXP x) {", 58 | " -: 7: }", 59 | " #####: 8: pout[0] = 0;" 60 | ) 61 | }, 62 | expect_equal(parse_gcov("hi.c.gcov"), c(4, 0)) 63 | ) 64 | }) 65 | 66 | test_that("clean_gcov correctly clears files", { 67 | 68 | dir <- file.path(tempfile(), "src") 69 | 70 | dir.create(dir, recursive = TRUE) 71 | file.create(file.path(dir, c("simple.c", "Makevars", "simple.c.gcov", "simple.gcda", "simple.gcno"))) 72 | expect_identical(list.files(dir), sort(c("simple.c", "Makevars", "simple.c.gcov", "simple.gcda", "simple.gcno"))) 73 | 74 | clean_gcov(dirname(dir)) 75 | expect_identical(list.files(dir), sort(c("simple.c", "Makevars"))) 76 | }) 77 | -------------------------------------------------------------------------------- /tests/testthat/test-gitlab.R: -------------------------------------------------------------------------------- 1 | test_that("gitlab", { 2 | cov <- package_coverage("TestS4") 3 | 4 | on.exit(unlink("TestS4/public", recursive = TRUE), add = TRUE) 5 | 6 | expect_error(gitlab(coverage = cov), NA) 7 | 8 | expect_true(file.exists("TestS4/public/coverage.html")) 9 | }) 10 | -------------------------------------------------------------------------------- /tests/testthat/test-memoised.R: -------------------------------------------------------------------------------- 1 | s1 <- tempfile() 2 | t1 <- tempfile() 3 | writeLines(con = s1, 4 | "a <- memoise::memoise(function(x) { 5 | x + 1 6 | })") 7 | 8 | writeLines(con = t1, 9 | " 10 | a(1) 11 | a(1) 12 | a(1) 13 | a(1) 14 | a(2) 15 | a(3)") 16 | 17 | on.exit(unlink(c(s1, t1))) 18 | 19 | test_that("it works on Vectorized functions", { 20 | cov <- file_coverage(s1, t1) 21 | cov_d <- as.data.frame(cov) 22 | 23 | expect_equal(cov_d$functions, "a") 24 | expect_equal(cov_d$value, 3) 25 | }) 26 | -------------------------------------------------------------------------------- /tests/testthat/test-null.R: -------------------------------------------------------------------------------- 1 | test_that("coverage of functions with NULL constructs", { 2 | f1 <- function() NULL 3 | f2 <- function() { 4 | NULL 5 | } 6 | f3 <- function() { 7 | if (FALSE) { 8 | NULL 9 | } 10 | } 11 | f4 <- function() { 12 | if (FALSE) 13 | NULL 14 | } 15 | 16 | cv1 <- function_coverage(f1, f1()) 17 | expect_equal(percent_coverage(cv1), 100) 18 | cv2 <- function_coverage(f2, f2()) 19 | expect_equal(percent_coverage(cv2), 100) 20 | cv3 <- function_coverage(f3, f3()) 21 | expect_equal(percent_coverage(cv3), 50) 22 | cv4 <- function_coverage(f4, f4()) 23 | expect_equal(percent_coverage(cv4), 50) 24 | }) 25 | -------------------------------------------------------------------------------- /tests/testthat/test-package_coverage.R: -------------------------------------------------------------------------------- 1 | test_that("package_coverage returns an error if the path does not exist", { 2 | expect_error(package_coverage("blah")) 3 | }) 4 | 5 | test_that("package_coverage returns an error if the type is incorrect", { 6 | expect_error( 7 | package_coverage("TestPrint", type = "blah"), 8 | "'arg' should be one of") 9 | 10 | expect_error(package_coverage("TestPrint", type = c("blah", "test")), 11 | "'arg' should be one of") 12 | }) 13 | 14 | test_that("package_coverage can return just tests and vignettes", { 15 | cov <- package_coverage("TestPrint", type = c("tests", "vignettes"), combine_types = FALSE) 16 | 17 | expect_equal(names(cov), c("tests", "vignettes")) 18 | }) 19 | 20 | test_that("package_coverage with type == 'all' returns test, vignette and example coverage", { 21 | cov <- package_coverage("TestPrint", type = "all", combine_types = FALSE) 22 | 23 | expect_equal(names(cov), c("tests", "vignettes", "examples")) 24 | }) 25 | 26 | test_that("package_coverage with type == 'none' runs no test code", { 27 | cov <- package_coverage("TestS4", type = "none") 28 | 29 | expect_equal(percent_coverage(cov), 0.00) 30 | }) 31 | 32 | test_that("package_coverage runs additional test code", { 33 | cov <- package_coverage("TestS4", type = "none", code = c("a(1)", "a(2)")) 34 | 35 | expect_gt(percent_coverage(cov), 0.00) 36 | }) 37 | -------------------------------------------------------------------------------- /tests/testthat/test-parallel.R: -------------------------------------------------------------------------------- 1 | test_that("mcparallel without the fix", { 2 | skip_on_os("windows") 3 | 4 | cov <- withr::with_options(list(covr.fix_parallel_mcexit = FALSE), 5 | package_coverage("TestParallel", type = "test")) 6 | # only the non parallel code is covered 7 | expect_equal(floor(percent_coverage(cov)), 33) 8 | }) 9 | 10 | 11 | 12 | test_that("mcparallel with the fix", { 13 | skip_on_os("windows") 14 | 15 | # using auto detection 16 | cov <- package_coverage(test_path("TestParallel"), type = "test") 17 | # only the non parallel code is covered 18 | expect_equal(percent_coverage(cov), 100) 19 | }) 20 | 21 | 22 | 23 | test_that("uses_parallel", { 24 | pkg <- covr:::as_package("TestParallel") 25 | expect_true(covr:::uses_parallel(pkg)) 26 | 27 | pkg <- covr:::as_package("TestSummary") 28 | expect_false(covr:::uses_parallel(pkg)) 29 | }) 30 | 31 | 32 | 33 | test_that("should_enable_parallel_mcexit_fix", { 34 | skip_on_os("windows") 35 | on.exit({ 36 | Sys.unsetenv('COVR_FIX_PARALLEL_MCEXIT') 37 | options(covr.fix_parallel_mcexit = NULL) 38 | }, add = TRUE 39 | ) 40 | 41 | grid <- expand.grid( 42 | var = c(NA, TRUE, FALSE), 43 | option = c(NA, TRUE, FALSE), 44 | pkg = c("TestParallel", "TestSummary"), stringsAsFactors = FALSE) 45 | 46 | grid$res <- with(grid, ifelse(!is.na(var), 47 | var, 48 | ifelse(!is.na(option), option, pkg == "TestParallel") 49 | )) 50 | 51 | .test_config <- function(var, option, pkgname) { 52 | if (is.na(var)) 53 | Sys.unsetenv('COVR_FIX_PARALLEL_MCEXIT') 54 | else 55 | Sys.setenv(COVR_FIX_PARALLEL_MCEXIT = var) 56 | 57 | 58 | if (is.na(option)) 59 | options(covr.fix_parallel_mcexit = NULL) 60 | else 61 | options(covr.fix_parallel_mcexit = option) 62 | 63 | pkg <- covr:::as_package(pkgname) 64 | covr:::should_enable_parallel_mcexit_fix(pkg) 65 | } 66 | 67 | res <- with(grid, vapply(1:nrow(grid), 68 | function(i) .test_config(var[i], option[i], pkg[i]), TRUE)) 69 | 70 | expect_identical(res, grid$res) 71 | 72 | }) 73 | -------------------------------------------------------------------------------- /tests/testthat/test-print.R: -------------------------------------------------------------------------------- 1 | test_that("format_percentage works as expected", { 2 | expect_equal(format_percentage(0), cli::col_red("0.00%")) 3 | 4 | expect_equal(format_percentage(25), cli::col_red("25.00%")) 5 | 6 | expect_equal(format_percentage(51), cli::col_red("51.00%")) 7 | 8 | expect_equal(format_percentage(76.5), cli::col_yellow("76.50%")) 9 | 10 | expect_equal(format_percentage(86.5), cli::col_yellow("86.50%")) 11 | 12 | expect_equal(format_percentage(96.5), cli::col_green("96.50%")) 13 | }) 14 | 15 | test_that("print.coverage prints by = \"line\" by default", { 16 | cov <- package_coverage(test_path("TestPrint")) 17 | 18 | expect_message(print(cov, by = "expression"), 19 | rex::rex("R/TestPrint.R: ", anything, "66.67%")) 20 | 21 | expect_message(print(cov, by = "line"), 22 | rex::rex("TestPrint Coverage: ", anything, "0.00%")) 23 | 24 | expect_message(print(cov, by = "line"), 25 | rex::rex("R/TestPrint.R: ", anything, "0.00%")) 26 | 27 | # test default 28 | expect_message(print(cov), 29 | rex::rex("TestPrint Coverage: ", anything, "0.00%")) 30 | 31 | expect_message(print(cov), 32 | rex::rex("R/TestPrint.R: ", anything, "0.00%")) 33 | 34 | expect_message(print(cov, group = "functions"), 35 | rex::rex("test_me", anything, "0.00%")) 36 | 37 | expect_message(print(cov, group = "functions", by = "expression"), 38 | rex::rex("test_me", anything, "66.67%")) 39 | }) 40 | -------------------------------------------------------------------------------- /tests/testthat/test-report.R: -------------------------------------------------------------------------------- 1 | skip_on_ci <- function() { 2 | if (!identical(Sys.getenv("CI"), "true")) { 3 | return(invisible(TRUE)) 4 | } 5 | 6 | skip("On CI") 7 | } 8 | 9 | #test_that("it works with coverage objects", { 10 | #skip_on_cran() 11 | #skip_on_ci() 12 | 13 | #tmp <- tempfile() 14 | #set.seed(42) 15 | #cov <- package_coverage(test_path("TestS4")) 16 | ## Shiny uses its own seed which is not affected by set.seed, so we need to 17 | ## set that as well to have reproducibility 18 | #g <- shiny:::.globals 19 | #g$ownSeed <- .Random.seed 20 | #htmlwidgets::setWidgetIdSeed(42) 21 | #report(cov, file = tmp, browse = FALSE) 22 | #simplify_link <- function(x) { 23 | #rex::re_substitutes(x, 24 | #rex::rex(capture(or("src", "href")), "=", quote, non_quotes, quote), "\\1=\"\">") 25 | #} 26 | #expect_equal(simplify_link(readLines(tmp)), simplify_link(readLines("test-report.htm"))) 27 | #}) 28 | -------------------------------------------------------------------------------- /tests/testthat/test-sonarqube.R: -------------------------------------------------------------------------------- 1 | test_that("it works with coverage objects", { 2 | tmp <- tempfile() 3 | cov <- package_coverage(test_path("TestSummary")) 4 | to_sonarqube(cov, filename = tmp) 5 | expect_equal(readLines(tmp), readLines(test_path("sonarqube.xml"))) 6 | }) 7 | -------------------------------------------------------------------------------- /tests/testthat/test-summary.R: -------------------------------------------------------------------------------- 1 | test_that("Summary gives 50% coverage and two lines with zero coverage", { 2 | cv <- package_coverage(test_path("TestSummary")) 3 | expect_equal(percent_coverage(cv), 50) 4 | expect_equal(nrow(zero_coverage(cv)), 2) 5 | }) 6 | 7 | test_that("percent_coverage", { 8 | old <- getOption("keep.source") 9 | options(keep.source = TRUE) 10 | on.exit(options(keep.source = old), add = TRUE) 11 | 12 | fun <- function() { 13 | x <- 1 14 | if (x > 2) { 15 | print(x) 16 | } 17 | res <- lapply(1:2, function(x) { 18 | x + 1 19 | }) 20 | } 21 | cov <- function_coverage("fun", env = environment(fun), fun()) 22 | 23 | res <- percent_coverage(cov) 24 | expect_equal(res, 83.333333, tolerance = .01) 25 | }) 26 | -------------------------------------------------------------------------------- /tests/testthat/test-trace_calls.R: -------------------------------------------------------------------------------- 1 | test_that("one-line functions are traced correctly", { 2 | old <- getOption("keep.source") 3 | options(keep.source = TRUE) 4 | on.exit(options(keep.source = old)) 5 | 6 | fun <- function(x) x + 1 7 | 8 | expect_equal(as.character(body(trace_calls(fun))[[3]][[2]][[1]]), 9 | c(":::", "covr", "count")) 10 | 11 | fun <- function() 1 12 | 13 | expect_equal(as.character(body(trace_calls(fun))[[3]][[2]][[1]]), 14 | c(":::", "covr", "count")) 15 | 16 | expect_equal(body(trace_calls(fun))[[3]][[3]], body(fun)) 17 | }) 18 | test_that("one-line functions with no calls are traced correctly", { 19 | old <- getOption("keep.source") 20 | options(keep.source = TRUE) 21 | on.exit(options(keep.source = old)) 22 | 23 | fun <- function(x) x 24 | 25 | expect_equal(as.character(body(trace_calls(fun))[[3]][[2]][[1]]), 26 | c(":::", "covr", "count")) 27 | 28 | expect_equal(body(trace_calls(fun))[[3]][[3]], body(fun)) 29 | }) 30 | test_that("one-line functions with braces are traced correctly", { 31 | old <- getOption("keep.source") 32 | options(keep.source = TRUE) 33 | on.exit(options(keep.source = old)) 34 | 35 | fun <- function(x) { 36 | x + 1 37 | } 38 | 39 | expect_equal(as.character(body(trace_calls(fun))[[2]][[3]][[2]][[1]]), 40 | c(":::", "covr", "count")) 41 | 42 | expect_equal(body(trace_calls(fun))[[2]][[3]][[3]], body(fun)[[2]]) 43 | }) 44 | 45 | test_that("one-line functions with no calls and braces are traced correctly", { 46 | old <- getOption("keep.source") 47 | options(keep.source = TRUE) 48 | on.exit(options(keep.source = old)) 49 | 50 | fun <- function() { 51 | 1 52 | } 53 | 54 | e2 <- body(trace_calls(fun))[[2]][[3]] 55 | expect_true(length(e2) > 1 && 56 | identical(as.character(e2[[2]][[1]]), c(":::", "covr", "count"))) 57 | 58 | fun <- function(x) { 59 | x 60 | } 61 | 62 | e2 <- body(trace_calls(fun))[[2]][[3]] 63 | 64 | # the second expr should be a block 65 | expect_true(length(e2) > 1 && 66 | identical(as.character(e2[[2]][[1]]), c(":::", "covr", "count"))) 67 | }) 68 | 69 | 70 | test_that("last evaled expression is traced", { 71 | old <- getOption("keep.source") 72 | options(keep.source = TRUE) 73 | on.exit(options(keep.source = old)) 74 | 75 | fun <- function() { 76 | x <- 1 77 | x 78 | } 79 | 80 | body <- body(trace_calls(fun)) 81 | 82 | expect_equal(length(body), 3) 83 | 84 | # last expression: the implicit return expression 85 | e3 <- body[[3]][[3]] 86 | expect_true(length(e3) > 1 && 87 | identical(as.character(e3[[2]][[1]]), c(":::", "covr", "count"))) 88 | 89 | }) 90 | 91 | test_that("functions with NULL bodies are traced correctly", { 92 | old <- options(keep.source = TRUE) 93 | on.exit(options(old)) 94 | 95 | fun <- function() NULL 96 | 97 | expect_null(trace_calls(fun)()) 98 | }) 99 | 100 | test_that("functions with curly curly syntax are traced correctly", { 101 | my_capture <- function(x) { 102 | rlang::expr({{ x }}) 103 | } 104 | expect_equal(my_capture(5 == 1), rlang::quo(5 == 1)) 105 | 106 | # behavior not changed by covr 107 | my_capture2 <- trace_calls(my_capture) 108 | expect_equal(my_capture2(5 == 1), rlang::quo(5 == 1)) 109 | 110 | # outer code traced traced with ({ }) 111 | expect_equal(as.character(body(my_capture2)[[2]][[1]]), "if") 112 | expect_equal(as.character(body(my_capture2)[[2]][[3]][[1]]), "{") 113 | expect_equal(as.character(body(my_capture2)[[2]][[3]][[2]][[1]]), c(":::", "covr", "count")) 114 | 115 | # no trace in the internal {{ }} 116 | expect_equal(as.character(body(my_capture2)[[2]][[3]][[3]][[2]][[1]]), "{") 117 | expect_equal(as.character(body(my_capture2)[[2]][[3]][[3]][[2]][[2]][[1]]), "{") 118 | }) 119 | 120 | 121 | test_that("functions that rely on implicit invisibility work the same", { 122 | f <- function(x) { 123 | x <- 1 124 | } 125 | 126 | f2 <- trace_calls(f) 127 | 128 | expect_equal(withVisible(f2(1)), withVisible(f(1))) 129 | 130 | f3 <- function(x) { 131 | x + 1 132 | } 133 | 134 | f4 <- trace_calls(f3) 135 | 136 | expect_equal(withVisible(f3(1)), withVisible(f4(1))) 137 | }) 138 | 139 | 140 | test_that("functions that use S3 dispatch work", { 141 | cov <- code_coverage( source_code = ' 142 | foo <- function(x) { 143 | UseMethod("foo") 144 | } 145 | 146 | foo.bar <- function(x) { x[[1]] + 1 } 147 | 148 | bar <- function(x) { 149 | structure(list(x), class = "bar") 150 | } 151 | ', test_code = ' 152 | stopifnot(foo(bar(1)) == 2) 153 | ') 154 | expect_equal(percent_coverage(cov), 100) 155 | }) 156 | -------------------------------------------------------------------------------- /tests/testthat/test-utils.R: -------------------------------------------------------------------------------- 1 | test_that("it throws error if no package", { 2 | expect_error(as_package("arst11234"), "`path` is invalid:.*arst11234") 3 | }) 4 | 5 | test_that("it returns the package if given the root or child directory", { 6 | 7 | expect_equal(as_package("TestS4")$package, "TestS4") 8 | expect_equal(as_package("TestS4/")$package, "TestS4") 9 | 10 | expect_equal(as_package("TestS4/R")$package, "TestS4") 11 | 12 | expect_equal(as_package("TestS4/tests")$package, "TestS4") 13 | 14 | expect_equal(as_package("TestS4/tests/testthat")$package, "TestS4") 15 | }) 16 | 17 | test_that("it works as expected", { 18 | with_mocked_bindings( 19 | system_output = function(...) {"test_branch "}, 20 | expect_equal(local_branch("TestSummary"), "test_branch") 21 | ) 22 | }) 23 | 24 | test_that("it works as expected", { 25 | with_mocked_bindings( 26 | system_output = function(...) {" test_hash"}, 27 | expect_equal(current_commit("TestSummary"), "test_hash") 28 | ) 29 | }) 30 | 31 | test_that("it works", { 32 | # R 4.0.0 changes this behavior so `getSrcFilename()` will actually return 33 | # "test-utils.R" 34 | 35 | skip_if(getRversion() >= "4.0.0") 36 | 37 | x <- eval(bquote(function() 1)) 38 | 39 | expect_identical(getSrcFilename(x), character()) 40 | expect_identical(get_source_filename(x), "") 41 | }) 42 | 43 | test_that("per_line removes blank lines and lines with only punctuation (#387)", { 44 | skip_on_cran() 45 | 46 | cov <- package_coverage(test_path("TestFunctional")) 47 | 48 | line_cov <- per_line(cov) 49 | 50 | expect_equal(line_cov[[1]]$coverage, c(NA, 0, 0, 2, NA, 1, NA, 1, NA, NA, NA, NA, NA, NA, NA, NA, NA)) 51 | }) 52 | 53 | test_that("split_on_line_directives returns NULL for input without directive (#588)", { 54 | expect_identical( 55 | split_on_line_directives(NULL), 56 | NULL 57 | ) 58 | expect_identical( 59 | split_on_line_directives(character()), 60 | NULL 61 | ) 62 | expect_identical( 63 | split_on_line_directives("aa"), 64 | NULL 65 | ) 66 | expect_identical( 67 | split_on_line_directives(c("abc", "def")), 68 | NULL 69 | ) 70 | }) 71 | 72 | test_that("split_on_line_directives does not simplify the result (#588)", { 73 | expect_identical( 74 | split_on_line_directives( 75 | c( 76 | '#line 1 "foo.R"', 77 | "abc", 78 | "def" 79 | ) 80 | ), 81 | list( 82 | "foo.R" = c("abc", "def") 83 | ) 84 | ) 85 | expect_identical( 86 | split_on_line_directives( 87 | c( 88 | '#line 1 "foo.R"', 89 | "abc", 90 | "def", 91 | '#line 4 "bar.R"', 92 | "ghi", 93 | "jkl" 94 | ) 95 | ), 96 | list( 97 | "foo.R" = c("abc", "def"), 98 | "bar.R" = c("ghi", "jkl") 99 | ) 100 | ) 101 | }) 102 | -------------------------------------------------------------------------------- /tests/testthat/test-vectorized.R: -------------------------------------------------------------------------------- 1 | s1 = tempfile() 2 | t1 = tempfile() 3 | writeLines(con = s1, 4 | 'scalar_func <- function(x,y) { 5 | z <- x + y 6 | } 7 | 8 | vector_func <- Vectorize(scalar_func,vectorize.args=c("x","y"),SIMPLIFY=TRUE)') 9 | 10 | writeLines(con = t1, 11 | "vector_func(1:10, 2)") 12 | 13 | on.exit(unlink(c(s1, t1))) 14 | 15 | test_that("it works on Vectorized functions", { 16 | cov <- file_coverage(s1, t1) 17 | cov_d <- as.data.frame(cov) 18 | 19 | expect_equal(cov_d$functions, "vector_func") 20 | expect_equal(cov_d$value, 10) 21 | }) 22 | -------------------------------------------------------------------------------- /unshim_package.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | perl -i -pe 's/\bcovrShim\b/covr/g;s/\bcovrShim_/covr_/g;s/_covrShim/_covr/g;' DESCRIPTION NAMESPACE R/* src/* tests/*R tests/testthat/*R 4 | --------------------------------------------------------------------------------