diff --git a/NAMESPACE b/NAMESPACE index 634b60815..8d29d8f7f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -189,6 +189,7 @@ export(skip_on_covr) export(skip_on_cran) export(skip_on_os) export(skip_on_travis) +export(skip_unless_r) export(snapshot_accept) export(snapshot_review) export(source_dir) diff --git a/NEWS.md b/NEWS.md index 60085f5fc..af1344472 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ * `expect_s4_class()` now supports unquoting (@stibu81, #2064). * `it()` now finds the correct evaluation environment in more cases (@averissimo, #2085). * Fixed an issue preventing compilation from succeeding due to deprecation / removal of `std::uncaught_exception()` (@kevinushey, #2047). +* New `skip_unless_r()` to skip running tests on unsuitable versions of R, e.g. `skip_unless_r(">= 4.1.0")` to skip tests that require, say, `...names` (@MichaelChirico, #2022) # testthat 3.2.3 diff --git a/R/expect-self-test.R b/R/expect-self-test.R index 0cd8dbbe7..74e220e9d 100644 --- a/R/expect-self-test.R +++ b/R/expect-self-test.R @@ -94,6 +94,9 @@ expect_no_failure <- function(expr) { expect_snapshot_skip <- function(x, cran = FALSE) { expect_snapshot_error(x, class = "skip", cran = cran) } +expect_skip <- function(code) { + expect_condition(code, class = "skip") +} expect_no_skip <- function(code) { expect_no_condition(code, class = "skip") } diff --git a/R/skip.R b/R/skip.R index 6dba4885b..1ad1de7ed 100644 --- a/R/skip.R +++ b/R/skip.R @@ -126,6 +126,30 @@ package_version <- function(x) { utils::packageVersion(x) } +#' @export +#' @param spec A version specification like '>= 4.1.0' denoting that this test +#' should only be run on R versions 4.1.0 and later. +#' @rdname skip +skip_unless_r <- function(spec) { + parts <- unlist(strsplit(spec, " ", fixed = TRUE)) + if (length(parts) != 2L) { + cli::cli_abort("{.arg spec} should be a comparison like '>=' and an R version separated by a space.") + } + comparator <- match.fun(parts[1L]) + required_version <- numeric_version(parts[2L]) + + current_version <- getRversion() + skip_if_not( + comparator(current_version, required_version), + sprintf( + "Current R version (%s) does not satisfy requirement (%s %s)", + current_version, parts[1L], required_version + ) + ) +} +# for mocking +getRversion <- NULL + #' @export #' @rdname skip skip_if_offline <- function(host = "captive.apple.com") { diff --git a/man/skip.Rd b/man/skip.Rd index 2537a96f4..911db42f2 100644 --- a/man/skip.Rd +++ b/man/skip.Rd @@ -5,6 +5,7 @@ \alias{skip_if_not} \alias{skip_if} \alias{skip_if_not_installed} +\alias{skip_unless_r} \alias{skip_if_offline} \alias{skip_on_cran} \alias{skip_on_os} @@ -22,6 +23,8 @@ skip_if(condition, message = NULL) skip_if_not_installed(pkg, minimum_version = NULL) +skip_unless_r(spec) + skip_if_offline(host = "captive.apple.com") skip_on_cran() @@ -46,6 +49,9 @@ skip_if_translated(msgid = "'\%s' not found") \item{minimum_version}{Minimum required version for the package} +\item{spec}{A version specification like '>= 4.1.0' denoting that this test +should only be run on R versions 4.1.0 and later.} + \item{host}{A string with a hostname to lookup} \item{os}{Character vector of one or more operating systems to skip on. diff --git a/tests/testthat/_snaps/skip.md b/tests/testthat/_snaps/skip.md index 4756a3cbb..c9247c7d4 100644 --- a/tests/testthat/_snaps/skip.md +++ b/tests/testthat/_snaps/skip.md @@ -88,3 +88,11 @@ Reason: On Windows i386 +# skip_unless_r gives the expected output + + Reason: Current R version (4.5.0) does not satisfy requirement (>= 999.999.999) + +--- + + Reason: Current R version (4.5.0) does not satisfy requirement (== 0.0.0) + diff --git a/tests/testthat/test-skip.R b/tests/testthat/test-skip.R index cd224d96d..ff970078e 100644 --- a/tests/testthat/test-skip.R +++ b/tests/testthat/test-skip.R @@ -135,3 +135,22 @@ test_that("can refine os with arch", { expect_no_skip(skip_on_os("windows", "x86_64")) expect_no_skip(skip_on_os("linux", "i386")) }) + +test_that("skip_unless_r works as expected", { + expect_no_skip(skip_unless_r(">= 0.0.0")) + expect_no_skip(skip_unless_r(paste("==", getRversion()))) + expect_no_skip(skip_unless_r("<= 999.999.999")) + + expect_skip(skip_unless_r(">= 999.999.999")) + expect_skip(skip_unless_r("== 0.0.0")) + expect_skip(skip_unless_r("<= 0.0.0")) + + expect_error(skip_unless_r("idfjdij"), "should be a comparison like '>='", fixed = TRUE) +}) + +test_that("skip_unless_r gives the expected output", { + local_mocked_bindings(getRversion = \() numeric_version("4.5.0")) + + expect_snapshot_skip(skip_unless_r(">= 999.999.999")) + expect_snapshot_skip(skip_unless_r("== 0.0.0")) +})