diff --git a/.Rbuildignore b/.Rbuildignore index 7dda684..8f445fa 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -19,3 +19,4 @@ ^CRAN-SUBMISSION$ ^CONTRIBUTING\.md$ ^\.claude$ +^.*\.stackdump$ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d5d1aeb..633a4eb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,14 @@ We are open to any contribution, from typos to new features. We will guide you t ## Package versions required to develop -- `{roxygen2}`: Version > `7.1.2` is required. +- `{roxygen2}`: Version `>= 7.3.0` is required, and the package is + documented with the version declared in `Config/roxygen2/version`. + Note that a package documented by `{roxygen2}` 8.x carries + `Config/roxygen2/version` instead of `RoxygenNote`, and that + `{usethis}` (<= 3.2.1) only looks at `RoxygenNote`: `usethis::use_pipe()`, + `use_import_from()`, `use_lifecycle()` and their siblings therefore + abort with "does not use roxygen2" on this repository. Edit + `NAMESPACE` roxygen tags by hand instead. ## Fixing typos diff --git a/DESCRIPTION b/DESCRIPTION index 1b95ece..e26d88b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: checkhelper Title: Deal with Check Outputs -Version: 1.0.0.9000 +Version: 1.0.1 Authors@R: c( person("Vincent", "Guyader", , "vincent@thinkr.fr", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-0671-9270")), @@ -19,7 +19,7 @@ URL: https://thinkr-open.github.io/checkhelper/, https://github.com/ThinkR-open/checkhelper BugReports: https://github.com/ThinkR-open/checkhelper/issues Depends: - R (>= 4.0) + R (>= 4.1) Imports: cli, covr, @@ -34,7 +34,7 @@ Imports: pkgload, purrr, rcmdcheck, - roxygen2, + roxygen2 (>= 7.3.0), stringi, stringr, tibble, @@ -51,8 +51,10 @@ Suggests: VignetteBuilder: knitr Config/Needs/website: ThinkR-open/thinkrtemplate +Config/testthat/edition: 3 +Config/testthat/start-first: checkhelper, fix-globals*, audit-globals, + check_as_cran, check_clean_userspace*, check_n_covr, audit-userspace Encoding: UTF-8 Language: en-US -LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.3 +Config/roxygen2/version: 8.1.0 diff --git a/NAMESPACE b/NAMESPACE index 2a7353b..1cd4bdd 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -28,28 +28,36 @@ export(get_no_visible) export(get_notes) export(print_globals) export(use_data_doc) -importFrom(dplyr,filter) -importFrom(dplyr,first) -importFrom(dplyr,group_by) -importFrom(dplyr,if_else) -importFrom(dplyr,left_join) -importFrom(dplyr,mutate) -importFrom(dplyr,n) -importFrom(dplyr,pull) -importFrom(dplyr,rename) -importFrom(dplyr,select) -importFrom(dplyr,summarise) -importFrom(dplyr,tibble) -importFrom(dplyr,ungroup) -importFrom(glue,glue) -importFrom(glue,glue_collapse) +importFrom(dplyr, + filter, + first, + group_by, + if_else, + left_join, + mutate, + n, + pull, + rename, + select, + summarise, + tibble, + ungroup +) +importFrom(glue, + glue, + glue_collapse +) importFrom(lifecycle,deprecated) importFrom(magrittr,"%>%") -importFrom(purrr,compact) -importFrom(purrr,keep) -importFrom(purrr,map) -importFrom(purrr,walk) +importFrom(purrr, + compact, + keep, + map, + walk +) importFrom(rcmdcheck,rcmdcheck) -importFrom(stringr,str_extract) -importFrom(stringr,str_extract_all) +importFrom(stringr, + str_extract, + str_extract_all +) importFrom(utils,getFromNamespace) diff --git a/NEWS.md b/NEWS.md index 09769a8..c95cd38 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,33 @@ -# checkhelper 1.0.0.9000 (development version, GitHub only) +# checkhelper 1.0.1 + +## Breaking changes + +- {checkhelper} now requires R >= 4.1: the {roxygen2} 8.x series + shipped by CRAN requires it, so the previous `R (>= 4.0)` claim was + not installable in practice with current dependencies. {roxygen2} + >= 7.3.0 (the oldest version the test suite supports) is now + declared explicitly in `Imports`. ## Bug fixes +- Compatibility with roxygen2 8.x. roxygen2 8.0.0 migrates the + DESCRIPTION `RoxygenNote` field to `Config/roxygen2/version`. On + every CRAN flavor that has picked up roxygen2 8.x (the four r-devel + Linux flavors, r-patched-linux, r-release-windows and + r-oldrel-windows) this made a + `find_missing_tags()` test abort: it used `usethis::use_pipe()` as + scaffolding, and usethis's internal roxygen detection + (`usethis:::uses_roxygen()`) still relies on + the now-removed `RoxygenNote` field, so `use_pipe()` failed with + *"Package ... does not use roxygen2"*. The scaffolding re-exported the + magrittr `%>%` purely to add functions to the fixture; it was never + part of the asserted contract, so it has been removed (modern packages + use the native `|>`, which needs no setup). The audit pipeline itself + (`audit_tags()` / `find_missing_tags()`), which reimplements + `roxygenise()` through roxygen2 internals, was verified to remain + correct under roxygen2 8.1.0. A dedicated regression test + (`test-roxygen2-8x-compat.R`) now guards the whole audit flow against + the roxygen2 8.x field migration and block-classification changes. - `fix_globals(write = TRUE)` no longer flattens the per-function `# :` grouping comments of an existing `R/globals.R` when a second run has nothing new to declare. When R CMD check surfaces diff --git a/R/audit_ascii.R b/R/audit_ascii.R index 0a47350..5bdb04b 100644 --- a/R/audit_ascii.R +++ b/R/audit_ascii.R @@ -13,9 +13,10 @@ #' @export #' @seealso [fix_ascii()] to apply the rewrite, [find_nonascii_files()]. #' @examples -#' \dontrun{ -#' pkg <- create_example_pkg() -#' audit_ascii(pkg) +#' if (requireNamespace("usethis", quietly = TRUE) && +#' requireNamespace("attachment", quietly = TRUE)) { +#' pkg <- create_example_pkg() +#' audit_ascii(pkg) #' } audit_ascii <- function(pkg = ".", scope = c("R", "tests", "vignettes", "man", @@ -64,9 +65,10 @@ audit_ascii <- function(pkg = ".", #' @export #' @seealso [audit_ascii()], [asciify_pkg()]. #' @examples -#' \dontrun{ -#' pkg <- create_example_pkg() -#' fix_ascii(pkg, dry_run = TRUE) +#' if (requireNamespace("usethis", quietly = TRUE) && +#' requireNamespace("attachment", quietly = TRUE)) { +#' pkg <- create_example_pkg() +#' fix_ascii(pkg, dry_run = TRUE) #' } fix_ascii <- function(pkg = ".", scope = c("R", "tests", "vignettes"), diff --git a/R/audit_tags.R b/R/audit_tags.R index 0cb5ed8..faa8837 100644 --- a/R/audit_tags.R +++ b/R/audit_tags.R @@ -10,9 +10,10 @@ #' @export #' @seealso [find_missing_tags()] #' @examples -#' \dontrun{ -#' pkg <- create_example_pkg() -#' audit_tags(pkg) +#' if (requireNamespace("usethis", quietly = TRUE) && +#' requireNamespace("attachment", quietly = TRUE)) { +#' pkg <- create_example_pkg() +#' audit_tags(pkg) #' } audit_tags <- function(pkg = ".") { out <- .find_missing_tags(package.dir = pkg) diff --git a/R/create_example_pkg.R b/R/create_example_pkg.R index f326840..0511e4b 100644 --- a/R/create_example_pkg.R +++ b/R/create_example_pkg.R @@ -14,7 +14,10 @@ #' @export #' @return Path where the example package is stored. #' @examples -#' create_example_pkg() +#' if (requireNamespace("usethis", quietly = TRUE) && +#' requireNamespace("attachment", quietly = TRUE)) { +#' create_example_pkg() +#' } create_example_pkg <- function(path = tempfile(pattern = "pkg-"), with_functions = TRUE, with_extra_notes = FALSE, diff --git a/R/globals.R b/R/globals.R index be05b9a..4ebc08b 100644 --- a/R/globals.R +++ b/R/globals.R @@ -1,4 +1,4 @@ -globalVariables( +utils::globalVariables( unique( c( "is_importfrom", "importfrom_function", "is_global_variable", diff --git a/cran-comments.md b/cran-comments.md index 6863884..8bc85db 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,26 +1,31 @@ ## Submission summary -This is a feature release of {checkhelper} (1.0.0). The previous CRAN -version was 0.1.0. The release introduces a uniform `audit_*` / -`fix_*` API for CRAN-blocking issues (globals, roxygen tags, -non-ASCII, userspace leaks, CRAN-settings checks, undocumented -datasets, old-style CITATION, `\dontrun{}` blocks, unquoted package -names in DESCRIPTION, network/download calls) plus a one-pass -`check_n_covr()` helper. The 10 historic functions remain callable -behind `lifecycle::deprecate_warn()` and delegate to the new -facades, so no reverse dependency breaks. See `NEWS.md` for the -full mapping. - -The maintainer changes from Sebastien Rochette to Vincent Guyader. -Sebastien Rochette stays in `Authors@R` with a `previous maintainer` -note in `comment =`. +This is a patch release of {checkhelper} (1.0.1). The previous CRAN +version was 1.0.0. + +It fixes the test failure that triggered the archival notice. The +failure is not flavor specific: it is currently reported on the four +r-devel Linux flavors (debian and fedora, clang and gcc), +r-patched-linux-x86_64, r-release-windows-x86_64 and +r-oldrel-windows-x86_64, that is on every flavor that has already +picked up {roxygen2} 8.x. + +The cause is {roxygen2} 8.0.0 migrating the `RoxygenNote` DESCRIPTION +field to `Config/roxygen2/version`. {usethis} (<= 3.2.1) still detects +roxygen through the old field, so a {usethis}-based test scaffolding +step aborted with "does not use roxygen2". The test suite has been +fixed, a regression test added, and the declared dependencies aligned +({roxygen2} >= 7.3.0, R >= 4.1). The test suite passes with both +{roxygen2} 8.1.0 and 7.3.3. See `NEWS.md` for details. ## Test environments -* local: Ubuntu Linux, R-release -* GitHub Actions: ubuntu-latest, macos-latest, windows-latest - (R-release and R-devel) -* win-builder: R-release and R-devel +* local: Windows 11, R 4.5.0, checked twice, once with roxygen2 7.3.3 + and once with roxygen2 8.1.0 +* GitHub Actions: ubuntu-latest (R-devel, R-release, R-oldrel), + macos-latest (R-release), windows-latest (R-release), all with + roxygen2 8.1.0 +* win-builder: R-devel ## R CMD check results @@ -28,7 +33,5 @@ note in `comment =`. ## Reverse dependencies -We checked the reverse dependencies of {checkhelper} on CRAN. No -breakage detected: the deprecated functions still dispatch to the -new facades with a `lifecycle::deprecate_warn()` and an unchanged -return shape. +No API change in this release: only tests, documentation, and +declared dependency floors were touched. diff --git a/man/audit_ascii.Rd b/man/audit_ascii.Rd index f89b46b..a65eaad 100644 --- a/man/audit_ascii.Rd +++ b/man/audit_ascii.Rd @@ -29,9 +29,10 @@ CRAN raises a NOTE when source code or documentation contains non-ASCII characters that are not properly escaped. Wraps \code{\link[=find_nonascii_files]{find_nonascii_files()}}. } \examples{ -\dontrun{ -pkg <- create_example_pkg() -audit_ascii(pkg) +if (requireNamespace("usethis", quietly = TRUE) && + requireNamespace("attachment", quietly = TRUE)) { + pkg <- create_example_pkg() + audit_ascii(pkg) } } \seealso{ diff --git a/man/audit_tags.Rd b/man/audit_tags.Rd index d4673a9..35b4193 100644 --- a/man/audit_tags.Rd +++ b/man/audit_tags.Rd @@ -18,9 +18,10 @@ functions that lack \verb{@noRd} (these trigger CRAN's \verb{Please add \\value to .Rd files} message). Wraps \code{\link[=find_missing_tags]{find_missing_tags()}}. } \examples{ -\dontrun{ -pkg <- create_example_pkg() -audit_tags(pkg) +if (requireNamespace("usethis", quietly = TRUE) && + requireNamespace("attachment", quietly = TRUE)) { + pkg <- create_example_pkg() + audit_tags(pkg) } } \seealso{ diff --git a/man/checkhelper-package.Rd b/man/checkhelper-package.Rd index 0ca0fdc..91244d8 100644 --- a/man/checkhelper-package.Rd +++ b/man/checkhelper-package.Rd @@ -22,6 +22,7 @@ Useful links: Authors: \itemize{ + \item Vincent Guyader \email{vincent@thinkr.fr} (\href{https://orcid.org/0000-0003-0671-9270}{ORCID}) \item Sebastien Rochette \email{sebastien@thinkr.fr} (\href{https://orcid.org/0000-0002-1565-9313}{ORCID}) (previous maintainer) \item Arthur Bréant \email{arthur@thinkr.fr} (\href{https://orcid.org/0000-0003-1668-0963}{ORCID}) \item Murielle Delmotte \email{murielle@thinkr.fr} (\href{https://orcid.org/0000-0002-1339-2424}{ORCID}) diff --git a/man/create_example_pkg.Rd b/man/create_example_pkg.Rd index f56647c..add67ef 100644 --- a/man/create_example_pkg.Rd +++ b/man/create_example_pkg.Rd @@ -34,5 +34,8 @@ Path where the example package is stored. Create a package example producing notes and errors } \examples{ -create_example_pkg() +if (requireNamespace("usethis", quietly = TRUE) && + requireNamespace("attachment", quietly = TRUE)) { + create_example_pkg() +} } diff --git a/man/find_missing_tags.Rd b/man/find_missing_tags.Rd index e35085c..1fbce10 100644 --- a/man/find_missing_tags.Rd +++ b/man/find_missing_tags.Rd @@ -15,9 +15,16 @@ find_missing_tags( \item{package.dir}{Location of package top level directory. Default is working directory.} -\item{roclets}{Character vector of roclet names to use with package. +\item{roclets}{Character vector of \link[roxygen2:roclet]{roclets} to use. + The default, \code{NULL}, uses the roxygen \code{roclets} option, -which defaults to \code{c("collate", "namespace", "rd")}.} +which defaults to \code{c("collate", "namespace", "rd")}. This will update +(if needed) the \code{Collate} field with \code{\link[roxygen2:update_collate]{update_collate()}}, +produce the \code{NAMESPACE} file with \code{\link[roxygen2:namespace_roclet]{namespace_roclet()}}, and +produce the Rd files with \code{\link[roxygen2:rd_roclet]{rd_roclet()}}. + +(Note that \code{update_collate()} is not technically a roclet but is still +controlled with this argument for historical reasons.)} \item{load_code}{A function used to load all the R code in the package directory. The default, \code{NULL}, uses the strategy defined by diff --git a/man/fix_ascii.Rd b/man/fix_ascii.Rd index 0e8b13f..05807e6 100644 --- a/man/fix_ascii.Rd +++ b/man/fix_ascii.Rd @@ -33,9 +33,10 @@ check. Dry-run by default: pass \code{dry_run = FALSE} to actually rewrite files. Wraps \code{\link[=asciify_pkg]{asciify_pkg()}}. } \examples{ -\dontrun{ -pkg <- create_example_pkg() -fix_ascii(pkg, dry_run = TRUE) +if (requireNamespace("usethis", quietly = TRUE) && + requireNamespace("attachment", quietly = TRUE)) { + pkg <- create_example_pkg() + fix_ascii(pkg, dry_run = TRUE) } } \seealso{ diff --git a/tests/testthat/helpers.R b/tests/testthat/helpers.R index 9d6f1d1..0d8cc35 100644 --- a/tests/testthat/helpers.R +++ b/tests/testthat/helpers.R @@ -1,24 +1,25 @@ -test_that("Package version required", { - - # Check the version of the package roxygen2 to take into account the breaking change. - expect_true(packageVersion("roxygen2") > "7.1.2") +# Silence expected lifecycle deprecations for the current test. +local_quiet_deprecation <- function(envir = parent.frame()) { + withr::local_options(lifecycle_verbosity = "quiet", .local_envir = envir) +} -}) +# Discard output and messages for the current test. +# For file-scope fixtures, use `quiet_create_example_pkg()` instead. +local_quiet <- function(envir = parent.frame()) { + if (sink.number(type = "message") == 2L) { + withr::local_message_sink(nullfile(), .local_envir = envir) + } + withr::local_output_sink(nullfile(), .local_envir = envir) + invisible() +} -# Silence lifecycle deprecation warnings globally; tests that explicitly -# exercise the deprecation layer override this with `withr::local_options()`. -options(lifecycle_verbosity = "quiet") +# Create the example package without toolchain output or expected warnings. +quiet_create_example_pkg <- function(...) { + local_quiet(environment()) + suppressWarnings(create_example_pkg(...)) +} -# Snapshot tempdir() at test entry and unlink anything new at teardown. -# Use this in tests that call rcmdcheck (audit_globals/fix_globals path) -# so they don't leak artefacts that downstream tests -# (test-check_clean_userspace) detect as pre-existing files. -# -# `envir` defaults to the caller's frame, which is the right thing inside -# a `test_that()` block. When called at FILE scope (e.g. before any -# `test_that` runs), pass `envir = testthat::teardown_env()` so the -# deferred cleanup ties to the file's documented teardown environment -# rather than to the source frame's lifetime. +# Remove files added to `tempdir()` when the test or file completes. local_tempdir_clean <- function(envir = parent.frame()) { before <- list.files(tempdir(), all.files = TRUE, no.. = TRUE) withr::defer( diff --git a/tests/testthat/test-asciify-edge-cases.R b/tests/testthat/test-asciify-edge-cases.R index 06b1c4f..d6bec27 100644 --- a/tests/testthat/test-asciify-edge-cases.R +++ b/tests/testthat/test-asciify-edge-cases.R @@ -96,6 +96,7 @@ test_that("asciify_file is byte-equivalent on a no-op pure-ASCII input", { # ---- return shape: n_tokens populated -------------------------------------- test_that("find_nonascii_files reports a real n_tokens for parseable R files", { + local_quiet_deprecation() withr::with_tempdir({ dir.create("R") writeLines( @@ -113,6 +114,7 @@ test_that("find_nonascii_files reports a real n_tokens for parseable R files", { }) test_that("find_nonascii_files sorts its output by file then line", { + local_quiet_deprecation() withr::with_tempdir({ dir.create("R") # Three files, intentionally created in non-alphabetical order @@ -137,6 +139,7 @@ test_that("find_nonascii_files sorts its output by file then line", { }) test_that("find_nonascii_files survives a NA file.size (e.g. broken symlink)", { + local_quiet_deprecation() skip_on_os("windows") # symlinks need elevated perms on Windows withr::with_tempdir({ dir.create("R") @@ -213,6 +216,7 @@ test_that("asciify_file on a .Rnw reports a real n_tokens (Sweave routed read-on # ---- return shape: asciify_pkg returns invisibly --------------------------- test_that("asciify_pkg() returns its summary invisibly", { + local_quiet_deprecation() pkg_path <- tempfile(pattern = "asciify-pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE) @@ -232,6 +236,7 @@ test_that("asciify_pkg() returns its summary invisibly", { # ---- interactive feedback: summary message --------------------------------- test_that("asciify_pkg() emits a 'would change' message in dry_run", { + local_quiet_deprecation() withr::with_tempdir({ dir.create("R") writeLines(paste0("x <- \"caf", e, "\""), "R/f.R", useBytes = FALSE) @@ -243,6 +248,7 @@ test_that("asciify_pkg() emits a 'would change' message in dry_run", { }) test_that("asciify_pkg() emits a 'rewrote' message in apply mode", { + local_quiet_deprecation() withr::with_tempdir({ dir.create("R") writeLines(paste0("x <- \"caf", e, "\""), "R/f.R", useBytes = FALSE) @@ -254,6 +260,7 @@ test_that("asciify_pkg() emits a 'rewrote' message in apply mode", { }) test_that("asciify_pkg() summary message reports correct counts", { + local_quiet_deprecation() withr::with_tempdir({ dir.create("R") writeLines(paste0("x <- \"caf", e, "\""), "R/f1.R", useBytes = FALSE) @@ -266,6 +273,7 @@ test_that("asciify_pkg() summary message reports correct counts", { }) test_that("asciify_pkg() summary counts every non-ASCII character, not parser tokens", { + local_quiet_deprecation() withr::with_tempdir({ dir.create("R") a <- "\u00e0"; e2 <- "\u00e9"; c2 <- "\u00e7"; e3 <- "\u00e8" @@ -281,6 +289,7 @@ test_that("asciify_pkg() summary counts every non-ASCII character, not parser to }) test_that("asciify_pkg() message is silenceable", { + local_quiet_deprecation() withr::with_tempdir({ dir.create("R") writeLines(paste0("x <- \"caf", e, "\""), "R/f.R", useBytes = FALSE) @@ -291,6 +300,7 @@ test_that("asciify_pkg() message is silenceable", { }) test_that("asciify_pkg() hints to re-run with dry_run = FALSE in dry-run with changes", { + local_quiet_deprecation() withr::with_tempdir({ dir.create("R") writeLines(paste0("x <- \"caf", e, "\""), "R/f.R", useBytes = FALSE) @@ -302,6 +312,7 @@ test_that("asciify_pkg() hints to re-run with dry_run = FALSE in dry-run with ch }) test_that("asciify_pkg() hints how to inspect the invisible result when there are changes", { + local_quiet_deprecation() withr::with_tempdir({ dir.create("R") writeLines(paste0("x <- \"caf", e, "\""), "R/f.R", useBytes = FALSE) @@ -313,6 +324,7 @@ test_that("asciify_pkg() hints how to inspect the invisible result when there ar }) test_that("asciify_pkg() does not show the apply hint when in apply mode", { + local_quiet_deprecation() withr::with_tempdir({ dir.create("R") writeLines(paste0("x <- \"caf", e, "\""), "R/f.R", useBytes = FALSE) @@ -322,6 +334,7 @@ test_that("asciify_pkg() does not show the apply hint when in apply mode", { }) test_that("asciify_pkg() does not show hints when nothing would change", { + local_quiet_deprecation() withr::with_tempdir({ dir.create("R") writeLines("x <- 1", "R/f.R", useBytes = FALSE) # ASCII-clean diff --git a/tests/testthat/test-asciify.R b/tests/testthat/test-asciify.R index 84b5bd2..8038a2a 100644 --- a/tests/testthat/test-asciify.R +++ b/tests/testthat/test-asciify.R @@ -147,7 +147,7 @@ test_that("asciify_r_source(identifiers='skip') stays silent and unchanged", { test_that("asciify_r_source rewrites strings even in a file with a non-ASCII id (warn)", { src <- "fa\u00e7on <- \"caf\u00e9\"" - out <- expect_warning(asciify_r_source(src, identifiers = "warn")) + expect_warning(out <- asciify_r_source(src, identifiers = "warn")) # the string was escaped expect_match(out, "\\\\u00e9", fixed = FALSE) # the identifier stays @@ -240,6 +240,8 @@ test_that("asciify_file rewrites only the R chunks of an Rmd, leaving prose alon # ---- asciify_pkg ------------------------------------------------------------ test_that("asciify_pkg(dry_run = TRUE) reports without writing", { + local_quiet_deprecation() + local_quiet() pkg_path <- tempfile(pattern = "asciify-pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE) @@ -257,6 +259,8 @@ test_that("asciify_pkg(dry_run = TRUE) reports without writing", { }) test_that("asciify_pkg(dry_run = FALSE) actually rewrites every R file in scope", { + local_quiet_deprecation() + local_quiet() pkg_path <- tempfile(pattern = "asciify-pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE) @@ -288,6 +292,8 @@ test_that("asciify_pkg(dry_run = FALSE) actually rewrites every R file in scope" }) test_that("asciify_pkg leaves a pure-ASCII file alone", { + local_quiet_deprecation() + local_quiet() pkg_path <- tempfile(pattern = "asciify-pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE) @@ -300,6 +306,7 @@ test_that("asciify_pkg leaves a pure-ASCII file alone", { # ---- find_nonascii_files ---------------------------------------------------- test_that("find_nonascii_files returns one row per offending line", { + local_quiet_deprecation() pkg_path <- tempfile(pattern = "asciify-pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE) @@ -314,6 +321,7 @@ test_that("find_nonascii_files returns one row per offending line", { }) test_that("find_nonascii_files returns an empty frame when there is nothing to flag", { + local_quiet_deprecation() pkg_path <- tempfile(pattern = "asciify-pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE) diff --git a/tests/testthat/test-audit-ascii.R b/tests/testthat/test-audit-ascii.R index ec042f8..46d1ae4 100644 --- a/tests/testthat/test-audit-ascii.R +++ b/tests/testthat/test-audit-ascii.R @@ -7,16 +7,18 @@ test_that("audit_ascii() exists with the expected signature", { }) test_that("audit_ascii() on an ASCII-clean fixture returns an empty data frame", { - path <- suppressWarnings(create_example_pkg()) - on.exit(unlink(path, recursive = TRUE)) + local_quiet() + path <- quiet_create_example_pkg() + on.exit(unlink(path, recursive = TRUE), add = TRUE) out <- suppressMessages(audit_ascii(path)) expect_s3_class(out, "data.frame") expect_equal(nrow(out), 0L) }) test_that("audit_ascii() flags non-ASCII bytes when present", { - path <- suppressWarnings(create_example_pkg()) - on.exit(unlink(path, recursive = TRUE)) + local_quiet() + path <- quiet_create_example_pkg() + on.exit(unlink(path, recursive = TRUE), add = TRUE) writeLines( "x <- \"café\"", file.path(path, "R", "nonascii.R") @@ -27,7 +29,8 @@ test_that("audit_ascii() flags non-ASCII bytes when present", { }) test_that("audit_ascii() emits a cli message", { - path <- suppressWarnings(create_example_pkg()) - on.exit(unlink(path, recursive = TRUE)) + local_quiet() + path <- quiet_create_example_pkg() + on.exit(unlink(path, recursive = TRUE), add = TRUE) expect_message(audit_ascii(path), regexp = "ASCII|ascii") }) diff --git a/tests/testthat/test-audit-check.R b/tests/testthat/test-audit-check.R index f4b2987..8a469fc 100644 --- a/tests/testthat/test-audit-check.R +++ b/tests/testthat/test-audit-check.R @@ -15,8 +15,8 @@ test_that("audit_check() summarises ERROR/WARNING/NOTE counts and returns the rc ) testthat::local_mocked_bindings(.check_as_cran = function(...) fake) - out <- expect_message( - audit_check("."), + expect_message( + out <- audit_check("."), regexp = "1 ERROR.*2 WARNING.*3 NOTE" ) expect_identical(out, fake) @@ -26,8 +26,8 @@ test_that("audit_check() handles the all-clean case (0/0/0) without choking on p fake <- list(errors = character(), warnings = character(), notes = character()) testthat::local_mocked_bindings(.check_as_cran = function(...) fake) - out <- expect_message( - audit_check("."), + expect_message( + out <- audit_check("."), regexp = "0 ERRORs.*0 WARNINGs.*0 NOTEs" ) expect_identical(out, fake) diff --git a/tests/testthat/test-audit-citation.R b/tests/testthat/test-audit-citation.R index b5e232f..606b8a4 100644 --- a/tests/testthat/test-audit-citation.R +++ b/tests/testthat/test-audit-citation.R @@ -16,6 +16,7 @@ local_pkg_with_citation <- function(content, envir = parent.frame()) { } test_that("audit_citation() flags personList(), as.personList() and citEntry()", { + local_quiet() pkg <- local_pkg_with_citation(c( 'citEntry(', ' entry = "Manual",', @@ -47,6 +48,7 @@ test_that("audit_citation() flags personList(), as.personList() and citEntry()", }) test_that("audit_citation() flags as.personList() too", { + local_quiet() pkg <- local_pkg_with_citation(c( 'bibentry(', ' bibtype = "Manual",', @@ -62,6 +64,7 @@ test_that("audit_citation() flags as.personList() too", { }) test_that("audit_citation() returns an empty tibble when CITATION is modern", { + local_quiet() pkg <- local_pkg_with_citation(c( 'bibentry(', ' bibtype = "Manual",', @@ -80,6 +83,7 @@ test_that("audit_citation() returns an empty tibble when CITATION is modern", { }) test_that("audit_citation() handles a missing inst/CITATION gracefully", { + local_quiet() pkg <- tempfile("pkg-no-cit-") dir.create(pkg) on.exit(unlink(pkg, recursive = TRUE), add = TRUE) @@ -90,11 +94,13 @@ test_that("audit_citation() handles a missing inst/CITATION gracefully", { }) test_that("audit_citation() emits a cli summary message", { + local_quiet() pkg <- local_pkg_with_citation('citEntry(entry = "Manual")') expect_message(audit_citation(pkg), regexp = "audit_citation") }) test_that("audit_citation() reports correct line numbers for nested calls", { + local_quiet() pkg <- local_pkg_with_citation(c( '# header comment', 'citHeader("My pkg")', @@ -127,6 +133,7 @@ local_pkg_with_citation <- function(citation, envir = parent.frame()) { } test_that("audit_citation() warns and returns empty on a syntactically broken CITATION", { + local_quiet() pkg <- local_pkg_with_citation(c( 'citEntry(entry = "Manual",', ' title = "no closing paren ever' @@ -140,6 +147,7 @@ test_that("audit_citation() warns and returns empty on a syntactically broken CI }) test_that("audit_citation() returns empty on an empty CITATION", { + local_quiet() pkg <- local_pkg_with_citation(character(0)) out <- audit_citation(pkg) diff --git a/tests/testthat/test-audit-dataset-doc.R b/tests/testthat/test-audit-dataset-doc.R index 785f69e..bd50f77 100644 --- a/tests/testthat/test-audit-dataset-doc.R +++ b/tests/testthat/test-audit-dataset-doc.R @@ -8,7 +8,7 @@ test_that("audit_dataset_doc() returns an empty tibble when data/ does not exist dir.create(path) dir.create(file.path(path, "R")) writeLines("Package: foo", file.path(path, "DESCRIPTION")) - on.exit(unlink(path, recursive = TRUE)) + on.exit(unlink(path, recursive = TRUE), add = TRUE) out <- suppressMessages(audit_dataset_doc(path)) expect_s3_class(out, "data.frame") expect_equal(nrow(out), 0L) @@ -23,7 +23,7 @@ test_that("audit_dataset_doc() reports datasets present in data/", { writeLines("Package: foo", file.path(path, "DESCRIPTION")) iris_path <- file.path(path, "data", "iris.rda") save(iris, file = iris_path) - on.exit(unlink(path, recursive = TRUE)) + on.exit(unlink(path, recursive = TRUE), add = TRUE) out <- suppressMessages(audit_dataset_doc(path)) expect_equal(nrow(out), 1L) expect_equal(out$name, "iris") @@ -35,7 +35,7 @@ test_that("audit_dataset_doc() emits a cli message", { dir.create(path) dir.create(file.path(path, "R")) writeLines("Package: foo", file.path(path, "DESCRIPTION")) - on.exit(unlink(path, recursive = TRUE)) + on.exit(unlink(path, recursive = TRUE), add = TRUE) expect_message(audit_dataset_doc(path), regexp = "dataset") }) diff --git a/tests/testthat/test-audit-dontrun.R b/tests/testthat/test-audit-dontrun.R index 61c1917..8ef26f8 100644 --- a/tests/testthat/test-audit-dontrun.R +++ b/tests/testthat/test-audit-dontrun.R @@ -18,6 +18,7 @@ local_pkg_with_rd <- function(rd_files, envir = parent.frame()) { } test_that("audit_dontrun() flags every \\dontrun{} block", { + local_quiet() pkg <- local_pkg_with_rd(list( "foo.Rd" = c( "\\name{foo}", @@ -55,6 +56,7 @@ test_that("audit_dontrun() flags every \\dontrun{} block", { }) test_that("audit_dontrun() returns empty tibble when no \\dontrun is present", { + local_quiet() pkg <- local_pkg_with_rd(list( "modern.Rd" = c( "\\name{modern}", @@ -75,6 +77,7 @@ test_that("audit_dontrun() returns empty tibble when no \\dontrun is present", { }) test_that("audit_dontrun() handles a missing man/ directory gracefully", { + local_quiet() pkg <- tempfile("pkg-no-man-") dir.create(pkg) on.exit(unlink(pkg, recursive = TRUE), add = TRUE) @@ -85,6 +88,7 @@ test_that("audit_dontrun() handles a missing man/ directory gracefully", { }) test_that("audit_dontrun() emits a cli summary message", { + local_quiet() pkg <- local_pkg_with_rd(list( "foo.Rd" = c( "\\name{foo}", @@ -101,6 +105,7 @@ test_that("audit_dontrun() emits a cli summary message", { }) test_that("audit_dontrun() reports correct line numbers", { + local_quiet() pkg <- local_pkg_with_rd(list( "foo.Rd" = c( "\\name{foo}", # 1 @@ -120,6 +125,7 @@ test_that("audit_dontrun() reports correct line numbers", { }) test_that("audit_dontrun() ignores commented-out \\dontrun mentions", { + local_quiet() # A `% \dontrun{` (Rd comment) must not trigger a false positive. pkg <- local_pkg_with_rd(list( "foo.Rd" = c( @@ -139,6 +145,7 @@ test_that("audit_dontrun() ignores commented-out \\dontrun mentions", { # --- Edge / coverage tests -------------------------------------------------- test_that("audit_dontrun() handles empty man/ directory (no Rd files)", { + local_quiet() pkg <- tempfile("pkg-empty-man-") dir.create(file.path(pkg, "man"), recursive = TRUE) on.exit(unlink(pkg, recursive = TRUE), add = TRUE) @@ -154,10 +161,12 @@ test_that(".scan_one_rd_for_dontrun() warns and skips when readLines fails", { dir.create(bad_path) on.exit(unlink(bad_path, recursive = TRUE), add = TRUE) - expect_warning( + # readLines() itself warns twice before erroring; the contract under test is + # the "Could not read" warning the internal turns that error into. + suppressWarnings(expect_warning( res <- checkhelper:::.scan_one_rd_for_dontrun(bad_path), regexp = "Could not read" - ) + )) expect_null(res) }) diff --git a/tests/testthat/test-audit-globals-coverage.R b/tests/testthat/test-audit-globals-coverage.R index b1f5b39..1bf6d9c 100644 --- a/tests/testthat/test-audit-globals-coverage.R +++ b/tests/testthat/test-audit-globals-coverage.R @@ -5,6 +5,7 @@ # audit_globals(): NULL path when the checker returns nothing ----------------- test_that("audit_globals() returns NULL with a verbose message when no globals", { + local_quiet() expect_message( out <- testthat::with_mocked_bindings( audit_globals("/tmp/anywhere"), @@ -19,6 +20,7 @@ test_that("audit_globals() returns NULL with a verbose message when no globals", # fix_globals(write = FALSE): print path ------------------------------------- test_that("fix_globals(write = FALSE) prints both blocks and operators block", { + local_quiet() globals <- list( globalVariables = tibble::tibble(fun = "f", variable = "var_a"), functions = tibble::tibble(fun = "f", variable = "extern_fn", proposed = "ns::extern_fn"), @@ -37,6 +39,7 @@ test_that("fix_globals(write = FALSE) prints both blocks and operators block", { # fix_globals(write = TRUE) without an R/ directory -------------------------- test_that("fix_globals(write = TRUE) creates R/ when it does not exist", { + local_quiet() pkg <- tempfile("pkg-no-r-") dir.create(pkg) on.exit(unlink(pkg, recursive = TRUE), add = TRUE) @@ -63,6 +66,7 @@ test_that("fix_globals(write = TRUE) creates R/ when it does not exist", { # fix_globals(write = TRUE) with operators ----------------------------------- test_that("fix_globals(write = TRUE) prints the operators block and informs", { + local_quiet() pkg <- tempfile("pkg-ops-") dir.create(file.path(pkg, "R"), recursive = TRUE) on.exit(unlink(pkg, recursive = TRUE), add = TRUE) @@ -88,6 +92,7 @@ test_that("fix_globals(write = TRUE) prints the operators block and informs", { # fix_globals(): NULL globals path ------------------------------------------- test_that("fix_globals() returns invisibly with no-op message when no globals", { + local_quiet() expect_message( res <- testthat::with_mocked_bindings( fix_globals("/tmp/anywhere"), @@ -142,6 +147,7 @@ test_that("is_globalVariables_call() recognises both bare and utils:: forms", { }) test_that("is_globalVariables_call() returns FALSE for other namespaced calls", { + local_quiet() expect_false(checkhelper:::is_globalVariables_call(quote(other::fn(x)))) expect_false(checkhelper:::is_globalVariables_call(quote(utils::other_fn(x)))) expect_false(checkhelper:::is_globalVariables_call(quote(some_fn(x)))) @@ -150,6 +156,7 @@ test_that("is_globalVariables_call() returns FALSE for other namespaced calls", # .print_globals(): malformed input ------------------------------------------ test_that(".print_globals() errors on a malformed globals list", { + local_quiet() expect_error( checkhelper:::.print_globals(globals = list()), regexp = "globals should be a list" @@ -157,6 +164,7 @@ test_that(".print_globals() errors on a malformed globals list", { }) test_that(".print_globals() fetches globals when called without the globals arg", { + local_quiet() res <- testthat::with_mocked_bindings( checkhelper:::.print_globals(path = "/tmp/anywhere", message = FALSE), .get_no_visible = function(path, ...) NULL, @@ -166,6 +174,7 @@ test_that(".print_globals() fetches globals when called without the globals arg" }) test_that(".print_globals() emits 'no globalVariable detected' when message = TRUE", { + local_quiet() expect_message( res <- testthat::with_mocked_bindings( checkhelper:::.print_globals(path = "/tmp/anywhere"), @@ -180,6 +189,7 @@ test_that(".print_globals() emits 'no globalVariable detected' when message = TR # .get_notes(): importfrom branch (line 372) --------------------------------- test_that(".get_notes() extracts importfrom_function names from quoted suggestions", { + local_quiet() fake_check <- list( notes = c(paste( "* checking R code for possible problems ... NOTE", @@ -198,6 +208,7 @@ test_that(".get_notes() extracts importfrom_function names from quoted suggestio # deprecated::print_globals(): bare call path (line 119) --------------------- test_that("deprecated print_globals() forwards to .print_globals when no globals arg", { + local_quiet() withr::local_options(lifecycle_verbosity = "quiet") res <- testthat::with_mocked_bindings( suppressMessages(suppressWarnings(print_globals(path = "/tmp/anywhere"))), diff --git a/tests/testthat/test-audit-globals.R b/tests/testthat/test-audit-globals.R index 9379303..c4627ab 100644 --- a/tests/testthat/test-audit-globals.R +++ b/tests/testthat/test-audit-globals.R @@ -7,7 +7,8 @@ test_that("audit_globals() exists with the expected signature", { test_that("audit_globals() returns either NULL or a list with globalVariables / functions / operators", { skip_on_cran() local_tempdir_clean() - path <- suppressWarnings(create_example_pkg()) + local_quiet() + path <- quiet_create_example_pkg() on.exit(unlink(path, recursive = TRUE), add = TRUE) out <- suppressMessages(suppressWarnings(audit_globals(path))) if (!is.null(out)) { @@ -21,7 +22,8 @@ test_that("audit_globals() returns either NULL or a list with globalVariables / test_that("audit_globals() emits a cli message", { skip_on_cran() local_tempdir_clean() - path <- suppressWarnings(create_example_pkg()) + local_quiet() + path <- quiet_create_example_pkg() on.exit(unlink(path, recursive = TRUE), add = TRUE) expect_message( suppressWarnings(audit_globals(path)), diff --git a/tests/testthat/test-audit-tags.R b/tests/testthat/test-audit-tags.R index b22f53d..6a50bfd 100644 --- a/tests/testthat/test-audit-tags.R +++ b/tests/testthat/test-audit-tags.R @@ -1,18 +1,22 @@ -path <- suppressWarnings(create_example_pkg()) +path <- quiet_create_example_pkg() withr::defer(unlink(path, recursive = TRUE), teardown_env()) test_that("audit_tags() exists and accepts pkg = path", { + local_quiet() expect_true(is.function(audit_tags)) expect_named(formals(audit_tags), c("pkg")) }) test_that("audit_tags() returns the same 3-element list as find_missing_tags()", { + local_quiet_deprecation() + local_quiet() out <- suppressMessages(suppressWarnings(audit_tags(path))) expect_type(out, "list") expect_named(out, c("package_doc", "data", "functions")) }) test_that("audit_tags() emits a cli message summarising the audit", { + local_quiet() expect_message( suppressWarnings(audit_tags(path)), regexp = "tag" diff --git a/tests/testthat/test-audit-userspace.R b/tests/testthat/test-audit-userspace.R index 37405b3..731d27d 100644 --- a/tests/testthat/test-audit-userspace.R +++ b/tests/testthat/test-audit-userspace.R @@ -7,7 +7,8 @@ test_that("audit_userspace() emits a cli message (smoke)", { skip_on_cran() skip_on_ci() local_tempdir_clean() - path <- suppressWarnings(create_example_pkg()) + local_quiet() + path <- quiet_create_example_pkg() on.exit(unlink(path, recursive = TRUE), add = TRUE) expect_message( suppressWarnings(audit_userspace(path)), @@ -18,7 +19,7 @@ test_that("audit_userspace() emits a cli message (smoke)", { test_that("audit_userspace() returns a tibble with the documented columns + summary attr", { # Mocked path: the rcmdcheck-driven internal is replaced by a fake that # returns the same shape `.check_clean_userspace()` does. Verifies the - # façade's contract (tibble + summary attr + cli line) without paying + # facade's contract (tibble + summary attr + cli line) without paying # the rcmdcheck cost. Runs on CI where the real path is skipped. fake <- data.frame( source = c("Unit tests", "Run examples"), @@ -29,8 +30,8 @@ test_that("audit_userspace() returns a tibble with the documented columns + summ ) testthat::local_mocked_bindings(.check_clean_userspace = function(...) fake) - out <- expect_message( - audit_userspace("."), + expect_message( + out <- audit_userspace("."), regexp = "2 files leaked" ) expect_s3_class(out, "tbl_df") @@ -47,6 +48,6 @@ test_that("audit_userspace() handles the no-leak case (0 files)", { ) testthat::local_mocked_bindings(.check_clean_userspace = function(...) fake) - out <- expect_message(audit_userspace("."), regexp = "0 files leaked") + expect_message(out <- audit_userspace("."), regexp = "0 files leaked") expect_equal(nrow(out), 0L) }) diff --git a/tests/testthat/test-check_as_cran.R b/tests/testthat/test-check_as_cran.R index 3b3fe8d..7f0ab8d 100644 --- a/tests/testthat/test-check_as_cran.R +++ b/tests/testthat/test-check_as_cran.R @@ -1,7 +1,8 @@ test_that("check_as_cran works", { local_tempdir_clean() - path <- suppressWarnings(create_example_pkg()) + local_quiet() + path <- quiet_create_example_pkg() check_output <- tempfile("example") if (interactive()) { diff --git a/tests/testthat/test-check_as_cran_args.R b/tests/testthat/test-check_as_cran_args.R index c2b4c07..c2b3124 100644 --- a/tests/testthat/test-check_as_cran_args.R +++ b/tests/testthat/test-check_as_cran_args.R @@ -9,7 +9,7 @@ test_that("check_as_cran() exposes a `repos` argument and a sensible default che # check_output default should resolve to a directory adjacent to `pkg`, # not the session tempdir, so the user can find their logs (#85). default_out <- paste(deparse(fmls[["check_output"]]), collapse = " ") - # We accept either dirname(pkg) or file.path(pkg, …) - anything that + # We accept either dirname(pkg) or file.path(pkg, ...) - anything that # references `pkg` works. The point is: not a session-only tempfile. expect_true(grepl("pkg", default_out, fixed = TRUE), info = "default check_output should reference the package path") diff --git a/tests/testthat/test-check_clean_userspace.R b/tests/testthat/test-check_clean_userspace.R index dfa12ff..a840dea 100644 --- a/tests/testthat/test-check_clean_userspace.R +++ b/tests/testthat/test-check_clean_userspace.R @@ -1,5 +1,6 @@ test_that("check_clean_userspace works", { + local_quiet_deprecation() # Invariants instead of an exact row count: R CMD check leaks slightly # different platform-specific artefacts (callr-*, foo.o, symbols.rds, # DESCRIPTION rewrite by document(), ...) so the historical cascade @@ -8,7 +9,8 @@ test_that("check_clean_userspace works", { # promises: the two seeded leaks are caught, every row has the right # shape, and any extra rows live in known noise locations. - path <- suppressWarnings(create_example_pkg()) + local_quiet() + path <- quiet_create_example_pkg() dir.create(file.path(path, "tests", "testthat"), recursive = TRUE) # A test that leaks a file in the testthat dir cat( diff --git a/tests/testthat/test-check_clean_userspace_robust.R b/tests/testthat/test-check_clean_userspace_robust.R index 2f79cf8..9acb3b8 100644 --- a/tests/testthat/test-check_clean_userspace_robust.R +++ b/tests/testthat/test-check_clean_userspace_robust.R @@ -9,7 +9,8 @@ test_that(".check_clean_userspace() survives a run_examples() crash and continues", { local_tempdir_clean() - path <- suppressWarnings(create_example_pkg()) + local_quiet() + path <- quiet_create_example_pkg() suppressWarnings(attachment::att_amend_desc(path = path)) # Counter env: each fake collaborator records that it was called so @@ -45,11 +46,12 @@ test_that(".check_clean_userspace() survives a run_examples() crash and continue NULL } - # The header contract is "surface a clear warning". Assert it - # explicitly with expect_warning() rather than swallowing it - # under suppressWarnings / suppressMessages. - out <- expect_warning( - suppressMessages( + # The header contract is "surface a clear warning". Assert that one + # explicitly rather than swallowing it under suppressWarnings / + # suppressMessages; the outer suppressWarnings only drops the *other* + # warning the run emits, about the file the fake leaked on purpose. + suppressWarnings(expect_warning( + out <- suppressMessages( testthat::with_mocked_bindings( testthat::with_mocked_bindings( checkhelper:::.check_clean_userspace(pkg = path, check_output = tempfile("check_output")), @@ -63,7 +65,7 @@ test_that(".check_clean_userspace() survives a run_examples() crash and continue ) ), regexp = "Skipping the 'Run examples' step" - ) + )) expect_s3_class(out, "tbl_df") expect_true(all(c("source", "problem", "where", "file") %in% names(out))) diff --git a/tests/testthat/test-checkhelper.R b/tests/testthat/test-checkhelper.R index 9842547..b372882 100644 --- a/tests/testthat/test-checkhelper.R +++ b/tests/testthat/test-checkhelper.R @@ -4,9 +4,14 @@ # file's teardown env (file-scope call needs the explicit envir; see # helpers.R). local_tempdir_clean(envir = testthat::teardown_env()) +# Every entry point exercised here (get_notes / get_no_visible / +# print_globals) is a deprecated wrapper; this file tests that they still +# work, not that they warn. Testthat resets the option per test, so the +# blocks below opt out again individually. +local_quiet_deprecation(envir = testthat::teardown_env()) # Warnings are ok with new version o -path <- suppressWarnings(create_example_pkg()) +path <- quiet_create_example_pkg() # get_no_visible ---- # Get globals @@ -38,6 +43,7 @@ globals <- get_no_visible(path, quiet = TRUE, args = c("--no-manual", "--as-cran # }) test_that("get_no_visible works", { + local_quiet_deprecation() # glue("\"", paste(globals$globalVariables$fun, collapse = "\", \""), "\"") expect_equal( globals$globalVariables$fun, @@ -58,6 +64,7 @@ test_that("get_no_visible works", { print_outputs <- print_globals(globals, message = FALSE) test_that("print_outputs works", { + local_quiet_deprecation() expect_equal( print_outputs$liste_funs, "--- Functions to add in NAMESPACE (with @importFrom ?) ---\n\nmy_long_fun_name_for_multiple_lines_globals: %>%, aes, geom_point, ggplot, mutate\nmy_plot: %>%, aes, geom_point, ggplot, mutate\nmy_plot_rdname: %>%, aes, geom_point, ggplot, mutate\n" @@ -73,11 +80,12 @@ test_that("print_outputs works", { unlink(path, recursive = TRUE) # Test when no notes at all ---- -path <- create_example_pkg(with_functions = FALSE, with_extra_notes = FALSE) +path <- quiet_create_example_pkg(with_functions = FALSE, with_extra_notes = FALSE) globals <- get_no_visible(path, quiet = TRUE, args = c("--no-manual", "--as-cran")) print_outputs <- print_globals(globals, message = FALSE) test_that("no notes works", { + local_quiet_deprecation() expect_null(globals) expect_null(print_outputs) expect_message(print_globals(globals, message = TRUE), "no globalVariable") @@ -87,8 +95,8 @@ unlink(path, recursive = TRUE) # Test when only extra notes ---- -path <- create_example_pkg(with_functions = FALSE, with_extra_notes = TRUE) -notes <- get_notes(path = path, args = c("--no-manual", "--as-cran")) +path <- quiet_create_example_pkg(with_functions = FALSE, with_extra_notes = TRUE) +notes <- get_notes(path = path, quiet = TRUE, args = c("--no-manual", "--as-cran")) test_that("extra notes only works", { expect_null(notes) @@ -97,7 +105,7 @@ test_that("extra notes only works", { unlink(path, recursive = TRUE) # Test when checks done before ---- -path <- suppressWarnings(create_example_pkg()) +path <- quiet_create_example_pkg() checks <- rcmdcheck::rcmdcheck(path = path, quiet = TRUE, args = c("--no-manual", "--as-cran")) notes <- get_notes(path = path, checks = checks) @@ -137,6 +145,7 @@ unlink(path, recursive = TRUE) # x[1]: iple_lines_globals" test_that("Check with path in outputs works", { + local_quiet_deprecation() notes_with_globals <- "checking R code for possible problems ... NOTE\nmy_long_fun_name_for_multiple_lines_globals: no visible global function\n definition for \u2018%>%\u2019\nmy_long_fun_name_for_multiple_lines_globals: no visible global function\n definition for \u2018mutate\u2019\nmy_long_fun_name_for_multiple_lines_globals: no visible global function\n definition for \u2018ggplot\u2019\nmy_long_fun_name_for_multiple_lines_globals: no visible global function\n definition for \u2018aes\u2019\nmy_long_fun_name_for_multiple_lines_globals: no visible binding for\n global variable \u2018x\u2019\nmy_long_fun_name_for_multiple_lines_globals: no visible binding for\n global variable \u2018y\u2019\nmy_long_fun_name_for_multiple_lines_globals: no visible binding for\n global variable \u2018new_col\u2019\nmy_long_fun_name_for_multiple_lines_globals: no visible global function\n definition for \u2018geom_point\u2019\nmy_plot: no visible global function definition for \u2018%>%\u2019\nmy_plot: no visible global function definition for \u2018mutate\u2019\nmy_plot: no visible global function definition for \u2018ggplot\u2019\nmy_plot: no visible global function definition for \u2018aes\u2019\nmy_plot: no visible binding for global variable \u2018x\u2019\nmy_plot: no visible binding for global variable \u2018y\u2019\nmy_plot: no visible binding for global variable \u2018new_col2\u2019\nmy_plot: no visible global function definition for \u2018geom_point\u2019\nmy_plot_rdname: no visible global function definition for \u2018%>%\u2019\nmy_plot_rdname: no visible global function definition for \u2018mutate\u2019\nmy_plot_rdname: no visible global function definition for \u2018ggplot\u2019\nmy_plot_rdname: no visible global function definition for \u2018aes\u2019\nmy_plot_rdname: no visible binding for global variable \u2018x\u2019\nmy_plot_rdname: no visible binding for global variable \u2018y\u2019\nmy_plot_rdname: no visible binding for global variable \u2018new_col2\u2019\nmy_plot_rdname: no visible global function definition for \u2018geom_point\u2019\nUndefined global functions or variables:\n %>% aes geom_point ggplot mutate new_col new_col2 x y" diff --git a/tests/testthat/test-create_example_pkg.R b/tests/testthat/test-create_example_pkg.R index 7c822d6..937d101 100644 --- a/tests/testthat/test-create_example_pkg.R +++ b/tests/testthat/test-create_example_pkg.R @@ -1,5 +1,6 @@ test_that("create_example_pkg works", { + local_quiet() expect_error(pkgdir <- create_example_pkg(), regexp = NA) if (requireNamespace("usethis", quietly = TRUE) & @@ -14,20 +15,22 @@ test_that("create_example_pkg works", { # --- Coverage tests for the with_* flags ------------------------------------ test_that("create_example_pkg(with_nonascii = TRUE) copies the non-ASCII fixture", { + local_quiet() skip_if_not_installed("usethis") skip_if_not_installed("attachment") - pkgdir <- suppressMessages(create_example_pkg(with_nonascii = TRUE)) + pkgdir <- quiet_create_example_pkg(with_nonascii = TRUE) on.exit(unlink(dirname(pkgdir), recursive = TRUE), add = TRUE) expect_true(file.exists(file.path(pkgdir, "R", "nonascii.R"))) }) test_that("create_example_pkg(with_undocumented_data = TRUE) writes a data/*.rda", { + local_quiet() skip_if_not_installed("usethis") skip_if_not_installed("attachment") - pkgdir <- suppressMessages(create_example_pkg(with_undocumented_data = TRUE)) + pkgdir <- quiet_create_example_pkg(with_undocumented_data = TRUE) on.exit(unlink(dirname(pkgdir), recursive = TRUE), add = TRUE) expect_true(file.exists(file.path(pkgdir, "data", "demo_dataset.rda"))) diff --git a/tests/testthat/test-deprecated.R b/tests/testthat/test-deprecated.R index a6332ea..a7aa783 100644 --- a/tests/testthat/test-deprecated.R +++ b/tests/testthat/test-deprecated.R @@ -5,12 +5,13 @@ ## "lifecycle_warning_deprecated") ## - calling it still returns a result of the expected shape ## -## The deprecation warning is gated by `lifecycle_verbosity`, which is set to -## "quiet" in helpers.R to keep other test files clean. Each test below -## locally bumps it to "warning". +## The deprecation warning is gated by `lifecycle_verbosity`. Tests elsewhere +## opt out of it with `local_quiet_deprecation()` (see helpers.R); each test +## below opts in, pinning it to "warning". setup_pkg <- function() { - path <- suppressWarnings(create_example_pkg()) + local_quiet(envir = parent.frame()) + path <- quiet_create_example_pkg() withr::defer_parent(unlink(path, recursive = TRUE)) path } @@ -52,6 +53,7 @@ test_that("get_no_visible() is deprecated", { }) test_that("print_globals() is deprecated", { + local_quiet() withr::local_options(lifecycle_verbosity = "warning") expect_warning( tryCatch(print_globals(NULL), error = function(e) NULL), @@ -69,18 +71,28 @@ test_that("find_missing_tags() is deprecated", { test_that("check_as_cran() is deprecated", { withr::local_options(lifecycle_verbosity = "warning") - expect_warning( - tryCatch(check_as_cran("nonexistent_path_xyz"), error = function(e) NULL), + # The bogus path also makes the wrapped function warn on its own; only the + # deprecation is under test, so let the rest go. + suppressWarnings(expect_warning( + tryCatch( + check_as_cran( + "nonexistent_path_xyz", + check_output = tempfile("check_output") + ), + error = function(e) NULL + ), class = "lifecycle_warning_deprecated" - ) + )) }) test_that("check_clean_userspace() is deprecated", { + local_quiet() withr::local_options(lifecycle_verbosity = "warning") - expect_warning( + # As above: the bogus path produces its own warnings on the way through. + suppressWarnings(expect_warning( tryCatch(check_clean_userspace("nonexistent_path_xyz"), error = function(e) NULL), class = "lifecycle_warning_deprecated" - ) + )) }) test_that("get_data_info() is deprecated", { diff --git a/tests/testthat/test-empty_package.R b/tests/testthat/test-empty_package.R index 27d9bd6..b49c4fe 100644 --- a/tests/testthat/test-empty_package.R +++ b/tests/testthat/test-empty_package.R @@ -1,4 +1,6 @@ test_that("find_missing_tags() handles a package with no R/ functions (#18)", { + local_quiet_deprecation() + local_quiet() pkg_path <- tempfile(pattern = "pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE) diff --git a/tests/testthat/test-env_pollution.R b/tests/testthat/test-env_pollution.R index a4629c3..463b463 100644 --- a/tests/testthat/test-env_pollution.R +++ b/tests/testthat/test-env_pollution.R @@ -1,4 +1,6 @@ test_that("find_missing_tags() does not leak the target package into the session (#77)", { + local_quiet_deprecation() + local_quiet() pkg_path <- tempfile(pattern = "pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE) diff --git a/tests/testthat/test-find_missing_values.R b/tests/testthat/test-find_missing_values.R index e714819..41cfc3a 100644 --- a/tests/testthat/test-find_missing_values.R +++ b/tests/testthat/test-find_missing_values.R @@ -2,17 +2,18 @@ # from downstream tempdir-snapshot tests. File-scope call needs the # explicit teardown env (see helpers.R). local_tempdir_clean(envir = testthat::teardown_env()) - -path <- suppressWarnings(create_example_pkg()) +path <- quiet_create_example_pkg() test_that("find_missing_tags works", { + local_quiet_deprecation() + local_quiet() # Check that the information transmitted by roxygen2 is correctly retransmitted by checkhelper if (packageVersion("roxygen2") >= "7.3.0") { # roxygen > 7.3.0 only generates messages - out <- expect_message( - find_missing_tags(path), + expect_message( + out <- find_missing_tags(path), "my_long_fun_name_for_multiple_lines_globals" ) @@ -24,8 +25,8 @@ test_that("find_missing_tags works", { } else { # roxygen > 7.1.2 generates warnings and messages expect_warning( - out <- expect_message( - find_missing_tags(path), + expect_message( + out <- find_missing_tags(path), "my_long_fun_name_for_multiple_lines_globals" ), regexp = "@return" @@ -76,7 +77,9 @@ test_that("find_missing_tags works", { usethis::with_project(path, { usethis::use_package_doc() - usethis::use_pipe() + # No usethis::use_pipe() scaffolding here: it aborts on packages + # documented by roxygen2 8.x, and the pipe reexport is not part of the + # asserted contract below (the audit parses source without executing it). usethis::use_data(iris) use_data_doc("iris") @@ -135,8 +138,8 @@ the_other_alias3 <- the_function", if (packageVersion("roxygen2") >= "7.3.0") { # roxygen > 7.3.0 only generates messages - out <- expect_message( - find_missing_tags(path), + expect_message( + out <- find_missing_tags(path), "my_long_fun_name_for_multiple_lines_globals" ) @@ -149,8 +152,8 @@ the_other_alias3 <- the_function", # roxygen > 7.1.2 generates warnings and messages expect_warning( - out <- expect_message( - find_missing_tags(path), + expect_message( + out <- find_missing_tags(path), "my_long_fun_name_for_multiple_lines_globals" ), regexp = "@return" diff --git a/tests/testthat/test-fix-ascii.R b/tests/testthat/test-fix-ascii.R index f4d78c4..6f47ad8 100644 --- a/tests/testthat/test-fix-ascii.R +++ b/tests/testthat/test-fix-ascii.R @@ -8,8 +8,9 @@ test_that("fix_ascii() exists with the expected signature", { }) test_that("fix_ascii(dry_run = TRUE) does not modify files", { - path <- suppressWarnings(create_example_pkg()) - on.exit(unlink(path, recursive = TRUE)) + local_quiet() + path <- quiet_create_example_pkg() + on.exit(unlink(path, recursive = TRUE), add = TRUE) target <- file.path(path, "R", "nonascii.R") writeLines("x <- \"café\"", target) before <- readLines(target) @@ -19,8 +20,9 @@ test_that("fix_ascii(dry_run = TRUE) does not modify files", { }) test_that("fix_ascii(dry_run = FALSE) rewrites non-ASCII literals", { - path <- suppressWarnings(create_example_pkg()) - on.exit(unlink(path, recursive = TRUE)) + local_quiet() + path <- quiet_create_example_pkg() + on.exit(unlink(path, recursive = TRUE), add = TRUE) target <- file.path(path, "R", "nonascii.R") writeLines("x <- \"café\"", target) suppressMessages(fix_ascii(path, dry_run = FALSE)) @@ -29,7 +31,8 @@ test_that("fix_ascii(dry_run = FALSE) rewrites non-ASCII literals", { }) test_that("fix_ascii() emits a cli message", { - path <- suppressWarnings(create_example_pkg()) - on.exit(unlink(path, recursive = TRUE)) + local_quiet() + path <- quiet_create_example_pkg() + on.exit(unlink(path, recursive = TRUE), add = TRUE) expect_message(fix_ascii(path, dry_run = TRUE), regexp = "ASCII|ascii") }) diff --git a/tests/testthat/test-fix-dataset-doc.R b/tests/testthat/test-fix-dataset-doc.R index fd74e3f..80f2b7d 100644 --- a/tests/testthat/test-fix-dataset-doc.R +++ b/tests/testthat/test-fix-dataset-doc.R @@ -13,7 +13,7 @@ test_that("fix_dataset_doc() generates a roxygen file under R/", { dir.create(file.path(path, "data")) writeLines("Package: foo", file.path(path, "DESCRIPTION")) save(iris, file = file.path(path, "data", "iris.rda")) - on.exit(unlink(path, recursive = TRUE)) + on.exit(unlink(path, recursive = TRUE), add = TRUE) doc_path <- suppressMessages(fix_dataset_doc("iris", pkg = path)) expect_true(file.exists(doc_path)) expect_match(doc_path, "doc_iris\\.R$") @@ -26,7 +26,7 @@ test_that("fix_dataset_doc() refuses to overwrite by default", { dir.create(file.path(path, "data")) writeLines("Package: foo", file.path(path, "DESCRIPTION")) save(iris, file = file.path(path, "data", "iris.rda")) - on.exit(unlink(path, recursive = TRUE)) + on.exit(unlink(path, recursive = TRUE), add = TRUE) suppressMessages(fix_dataset_doc("iris", pkg = path)) expect_error( suppressMessages(fix_dataset_doc("iris", pkg = path)), diff --git a/tests/testthat/test-fix-globals-merge.R b/tests/testthat/test-fix-globals-merge.R index f2fcc95..be23dfd 100644 --- a/tests/testthat/test-fix-globals-merge.R +++ b/tests/testthat/test-fix-globals-merge.R @@ -30,6 +30,7 @@ fake_globals <- function(vars) { } test_that("fix_globals(write = TRUE) preserves previously declared globals", { + local_quiet() path <- local_pkg_with_globals() globals_path <- file.path(path, "R", "globals.R") writeLines( @@ -55,6 +56,7 @@ test_that("fix_globals(write = TRUE) preserves previously declared globals", { }) test_that("fix_globals(write = TRUE) deduplicates across old / new", { + local_quiet() path <- local_pkg_with_globals() globals_path <- file.path(path, "R", "globals.R") writeLines( @@ -81,6 +83,7 @@ test_that("fix_globals(write = TRUE) deduplicates across old / new", { }) test_that("fix_globals(write = TRUE) handles empty fresh + non-empty preserved", { + local_quiet() # When R CMD check surfaces only function notes (no # `is_global_variable` rows), the freshly built # `globalVariables(unique(c(\n\n)))` body is empty. A naive merge @@ -134,6 +137,7 @@ test_that("fix_globals(write = TRUE) handles empty fresh + non-empty preserved", }) test_that("extract_existing_globals does NOT execute side effects from globals.R (RCE guard)", { + local_quiet() # Sanity guard against a known RCE shape: if extract_existing_globals # ever fell back to `eval()` under `baseenv()` (which exposes # `file.create`, `system`, `library`, `file`, ...), a malicious or @@ -175,6 +179,7 @@ test_that("extract_existing_globals does NOT execute side effects from globals.R }) test_that("extract_existing_globals tolerates `globalVariables()` with no arguments", { + local_quiet() # Degenerate but legal call shape: a `globals.R` containing just # `utils::globalVariables()` (no args) used to crash the extractor # with `subscript out of bounds` on `e[[2]]`, aborting the entire @@ -192,6 +197,7 @@ test_that("extract_existing_globals tolerates `globalVariables()` with no argume }) test_that("fix_globals(write = TRUE) handles the no-existing-file case", { + local_quiet() path <- local_pkg_with_globals() globals_path <- file.path(path, "R", "globals.R") expect_false(file.exists(globals_path)) @@ -207,6 +213,7 @@ test_that("fix_globals(write = TRUE) handles the no-existing-file case", { }) test_that("fix_globals(write = TRUE) preserves per-function grouping on re-run with no new variables", { + local_quiet() # Why: the 1st run produces a `globals.R` that groups names under # per-function `# :` comments (see `.print_globals()`). The user # then re-runs `fix_globals(write = TRUE)` after R CMD check still @@ -275,6 +282,7 @@ test_that("fix_globals(write = TRUE) preserves per-function grouping on re-run w }) test_that("fix_globals(write = TRUE) does not create a degenerate empty globals.R on a virgin package", { + local_quiet() # Why: when R CMD check surfaces only function / operator notes (no # variable notes) AND `R/globals.R` does not exist yet, the fresh # block is `utils::globalVariables(unique(c(\n\n)))` and `preserved` diff --git a/tests/testthat/test-fix-globals-multi-run.R b/tests/testthat/test-fix-globals-multi-run.R index 92985fc..03fa4af 100644 --- a/tests/testthat/test-fix-globals-multi-run.R +++ b/tests/testthat/test-fix-globals-multi-run.R @@ -54,6 +54,7 @@ declared_names <- function(path) { # every 1st-run name still declared, every new name added, no # duplicate at runtime. test_that("multi-run A: 2nd run with new vars accumulates without losing 1st-run names", { + local_quiet() path <- local_pkg_with_globals() globals_path <- file.path(path, "R", "globals.R") @@ -100,6 +101,7 @@ test_that("multi-run A: 2nd run with new vars accumulates without losing 1st-run # set that R CMD check actually sees, which `eval()` of the # `globalVariables(unique(c(...)))` body gives back deduplicated. test_that("multi-run B: overlap between runs collapses at runtime via the unique() wrapper", { + local_quiet() path <- local_pkg_with_globals() globals_path <- file.path(path, "R", "globals.R") @@ -146,6 +148,7 @@ test_that("multi-run B: overlap between runs collapses at runtime via the unique # the post-#125 early-return as idempotent across consecutive no-op # passes. test_that("multi-run C: consecutive no-op runs yield byte-identical globals.R (idempotence)", { + local_quiet() path <- local_pkg_with_globals() globals_path <- file.path(path, "R", "globals.R") @@ -186,6 +189,7 @@ test_that("multi-run C: consecutive no-op runs yield byte-identical globals.R (i # Comment preservation is NOT promised by the current AST-based # extractor; assert it explicitly so the contract is visible. test_that("multi-run D: user-curated names survive a subsequent fix_globals run", { + local_quiet() path <- local_pkg_with_globals() globals_path <- file.path(path, "R", "globals.R") @@ -248,7 +252,8 @@ test_that("multi-run D: user-curated names survive a subsequent fix_globals run" test_that("multi-run E: real round-trip with create_example_pkg converges on the 2nd pass", { skip_on_cran() local_tempdir_clean() - path <- suppressWarnings(create_example_pkg()) + local_quiet() + path <- quiet_create_example_pkg() on.exit(unlink(path, recursive = TRUE), add = TRUE) globals_path <- file.path(path, "R", "globals.R") @@ -269,6 +274,7 @@ test_that("multi-run E: real round-trip with create_example_pkg converges on the # created and `liste_funs` (and `liste_operators` if present) must # be surfaced on every run. test_that("multi-run F: function-only notes on N consecutive runs never write globals.R", { + local_quiet() path <- local_pkg_with_globals() globals_path <- file.path(path, "R", "globals.R") diff --git a/tests/testthat/test-fix-globals.R b/tests/testthat/test-fix-globals.R index 1dd8967..7a2ea27 100644 --- a/tests/testthat/test-fix-globals.R +++ b/tests/testthat/test-fix-globals.R @@ -8,7 +8,8 @@ test_that("fix_globals() exists with the expected signature", { test_that("fix_globals(write = FALSE) emits a message and does not modify R/globals.R", { skip_on_cran() local_tempdir_clean() - path <- suppressWarnings(create_example_pkg()) + local_quiet() + path <- quiet_create_example_pkg() on.exit(unlink(path, recursive = TRUE), add = TRUE) globals_file <- file.path(path, "R", "globals.R") before_exists <- file.exists(globals_file) @@ -24,7 +25,8 @@ test_that("fix_globals(write = TRUE) writes a parseable R/globals.R", { # it must contain the expected globalVariables(...) call. skip_on_cran() local_tempdir_clean() - path <- suppressWarnings(create_example_pkg()) + local_quiet() + path <- quiet_create_example_pkg() on.exit(unlink(path, recursive = TRUE), add = TRUE) out <- suppressWarnings(suppressMessages(fix_globals(path, write = TRUE))) diff --git a/tests/testthat/test-get_data_info.R b/tests/testthat/test-get_data_info.R index 392224a..cf196f7 100644 --- a/tests/testthat/test-get_data_info.R +++ b/tests/testthat/test-get_data_info.R @@ -1,4 +1,5 @@ test_that("my_function works properly", { + local_quiet_deprecation() temp_dir <- tempdir() path_data <- file.path(temp_dir, "data") suppressWarnings(dir.create(path_data)) @@ -10,7 +11,7 @@ test_that("my_function works properly", { result <- get_data_info("iris", "Iris data frame", source = "Thinkr") } ) - expect_is(result, "list") + expect_type(result, "list") expect_equal(length(result), 6) expect_true(all(c("name", "description", "rows", "cols", "items", "source") %in% names(result)), 6) }) diff --git a/tests/testthat/test-inherit_return.R b/tests/testthat/test-inherit_return.R index 3fba79c..10883b0 100644 --- a/tests/testthat/test-inherit_return.R +++ b/tests/testthat/test-inherit_return.R @@ -1,4 +1,6 @@ test_that("find_missing_tags() does not flag @inherit X return (#84)", { + local_quiet_deprecation() + local_quiet() pkg_path <- tempfile(pattern = "pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE) diff --git a/tests/testthat/test-namespace-shape.R b/tests/testthat/test-namespace-shape.R index 8d675f5..e914d20 100644 --- a/tests/testthat/test-namespace-shape.R +++ b/tests/testthat/test-namespace-shape.R @@ -5,7 +5,7 @@ ## otherwise. expected_exports <- c( - ## Public façades - audit_* + ## Public facades - audit_* "audit_ascii", "audit_check", "audit_citation", @@ -17,7 +17,7 @@ expected_exports <- c( "audit_tags", "audit_userspace", - ## Public façades - fix_* + ## Public facades - fix_* "fix_ascii", "fix_dataset_doc", "fix_globals", diff --git a/tests/testthat/test-rdname_topic_block.R b/tests/testthat/test-rdname_topic_block.R index b82748c..792f874 100644 --- a/tests/testthat/test-rdname_topic_block.R +++ b/tests/testthat/test-rdname_topic_block.R @@ -1,4 +1,6 @@ test_that("find_missing_tags() doesn't flag aliases pointing to a topic-only block (#82)", { + local_quiet_deprecation() + local_quiet() pkg_path <- tempfile(pattern = "pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE) diff --git a/tests/testthat/test-requirements.R b/tests/testthat/test-requirements.R new file mode 100644 index 0000000..a594316 --- /dev/null +++ b/tests/testthat/test-requirements.R @@ -0,0 +1,12 @@ +test_that("roxygen2 is recent enough for the audit-tags test expectations", { + # The test suite branches on roxygen2 behaviour at the 7.3.0 boundary + # (>= 7.3.0 emits messages, older versions emitted warnings) and is + # validated against the roxygen2 8.x line, on which checkhelper is now + # supported (see test-roxygen2-8x-compat.R). Anything older than 7.3.0 is + # untested and would break the message/warning expectations, so fail early + # with a clear signal rather than deep inside an audit-tags assertion. + expect_true( + packageVersion("roxygen2") >= "7.3.0", + info = "checkhelper's tests require roxygen2 >= 7.3.0" + ) +}) diff --git a/tests/testthat/test-returns_alias.R b/tests/testthat/test-returns_alias.R index ea97584..cf5f037 100644 --- a/tests/testthat/test-returns_alias.R +++ b/tests/testthat/test-returns_alias.R @@ -1,4 +1,6 @@ test_that("find_missing_tags() accepts @returns as well as @return (#81)", { + local_quiet_deprecation() + local_quiet() pkg_path <- tempfile(pattern = "pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE) diff --git a/tests/testthat/test-roxygen2-8x-compat.R b/tests/testthat/test-roxygen2-8x-compat.R new file mode 100644 index 0000000..7bf0b03 --- /dev/null +++ b/tests/testthat/test-roxygen2-8x-compat.R @@ -0,0 +1,90 @@ +# Regression guards for roxygen2 8.x: the DESCRIPTION field migration +# (RoxygenNote -> Config/roxygen2/version) must not break usethis-based +# scaffolding, and the getFromNamespace-based audit pipeline must keep +# working end-to-end on a package documented by the installed roxygen2. + +test_that("create_example_pkg produces a roxygen2-managed package regardless of field migration", { + skip_if_not_installed("usethis") + skip_if_not_installed("attachment") + + path <- quiet_create_example_pkg() + on.exit(unlink(dirname(path), recursive = TRUE), add = TRUE) + + d <- desc::desc(file.path(path, "DESCRIPTION")) + + # Which of the two version fields ends up in the scaffolded DESCRIPTION + # depends on the whole roxygen2/usethis/attachment combination on the + # machine, not on the roxygen2 version alone. The invariant checkhelper + # relies on is the same one usethis uses: the package counts as + # roxygen-managed when EITHER field is present. + expect_true( + any(d$has_fields(c("RoxygenNote", "Config/roxygen2/version"))) + ) + + # Where the toolchain did migrate the fixture, the migration must be + # complete: roxygen2 8.x replaces `RoxygenNote`, it does not duplicate it. + # A DESCRIPTION carrying both fields would mean the scaffolding is not + # exercising the 8.x path at all, and would silently weaken this file. + if (d$has_fields("Config/roxygen2/version")) { + expect_false(d$has_fields("RoxygenNote")) + } +}) + +test_that("find_missing_tags audits a package carrying only Config/roxygen2/version", { + skip_if_not_installed("usethis") + skip_if_not_installed("attachment") + + path <- quiet_create_example_pkg() + on.exit(unlink(dirname(path), recursive = TRUE), add = TRUE) + + # Force the post-8.x DESCRIPTION shape by hand instead of hoping the + # installed roxygen2/usethis/attachment combination produces it. This is + # the exact state that broke the suite on CRAN, and writing it explicitly + # makes the guard deterministic on every flavor, including the ones whose + # scaffolding still lands on the legacy `RoxygenNote` field. + desc_path <- file.path(path, "DESCRIPTION") + d <- desc::desc(desc_path) + d$del("RoxygenNote") + d$set("Config/roxygen2/version" = as.character(packageVersion("roxygen2"))) + d$write(desc_path) + + migrated <- desc::desc(desc_path) + expect_false(migrated$has_fields("RoxygenNote")) + expect_true(migrated$has_fields("Config/roxygen2/version")) + + out <- suppressWarnings(suppressMessages(find_missing_tags(path))) + + expect_named(out, c("package_doc", "data", "functions")) + expect_true( + "my_long_fun_name_for_multiple_lines_globals" %in% out[["functions"]][["topic"]] + ) + expect_true( + any(out[["functions"]][["test_has_export_and_return"]] == "not_ok") + ) +}) + +test_that("find_missing_tags audits an 8.x-documented example package without error", { + skip_if_not_installed("usethis") + skip_if_not_installed("attachment") + + path <- quiet_create_example_pkg() + on.exit(unlink(dirname(path), recursive = TRUE), add = TRUE) + + # The audit pipeline reimplements roxygenise() through roxygen2 internals + # (getFromNamespace). It must run end-to-end on a package documented by the + # installed roxygen2, whatever the DESCRIPTION field layout. + out <- suppressWarnings(suppressMessages(find_missing_tags(path))) + + expect_type(out, "list") + expect_length(out, 3) + expect_equal(names(out), c("package_doc", "data", "functions")) + # The exported-without-@return fixture must still be flagged: this is the + # core contract, and it is what proves the block classification survived the + # roxygen2 8.x changes to block/roclet handling. + expect_true( + "my_long_fun_name_for_multiple_lines_globals" %in% out[["functions"]][["topic"]] + ) + expect_true( + any(out[["functions"]][["test_has_export_and_return"]] == "not_ok") + ) +}) diff --git a/tests/testthat/test-s3_missing_value.R b/tests/testthat/test-s3_missing_value.R index 46dcfa4..f68dd8d 100644 --- a/tests/testthat/test-s3_missing_value.R +++ b/tests/testthat/test-s3_missing_value.R @@ -1,11 +1,12 @@ # Regression tests for #92: find_missing_tags() / audit_tags() must report # missing @return on S3 generics and on S3 methods that have their own Rd # file (block carries a title / description). It must NOT flag methods -# whose block is just `@export` (no doc → no own Rd, just a NAMESPACE +# whose block is just `@export` (no doc -> no own Rd, just a NAMESPACE # entry merged with the generic's Rd). local_s3_pkg <- function(envir = parent.frame()) { - path <- suppressWarnings(create_example_pkg()) + local_quiet(envir = envir) + path <- quiet_create_example_pkg() unlink(list.files(file.path(path, "R"), full.names = TRUE)) unlink(list.files(file.path(path, "man"), full.names = TRUE)) withr::defer(unlink(path, recursive = TRUE), envir = envir) diff --git a/tests/testthat/test-use_data_doc.R b/tests/testthat/test-use_data_doc.R index 58923e1..90d0e9f 100644 --- a/tests/testthat/test-use_data_doc.R +++ b/tests/testthat/test-use_data_doc.R @@ -1,6 +1,9 @@ -path <- suppressWarnings(create_example_pkg()) +path <- quiet_create_example_pkg() +withr::defer(unlink(dirname(path), recursive = TRUE), teardown_env()) test_that("use_doc_data", { + local_quiet_deprecation() + local_quiet() path_data <- file.path(path, "data") suppressWarnings(dir.create(path_data)) path_rda <- file.path(path_data, "iris.rda") diff --git a/tests/testthat/test-use_data_doc_overwrite.R b/tests/testthat/test-use_data_doc_overwrite.R index 1091f1a..81884b8 100644 --- a/tests/testthat/test-use_data_doc_overwrite.R +++ b/tests/testthat/test-use_data_doc_overwrite.R @@ -1,4 +1,6 @@ test_that("use_data_doc() refuses to overwrite by default and respects overwrite = TRUE (#19)", { + local_quiet_deprecation() + local_quiet() pkg_path <- tempfile(pattern = "pkg-") dir.create(pkg_path) on.exit(unlink(pkg_path, recursive = TRUE), add = TRUE)