(v3.0.1.9114) Fix errors without cli and on R 3.0, and make the tinytest pipeline actually run the unit tests

Package:
- stop_() called cli::ansi_has_hyperlink_support() before checking that cli is available, so without cli every error became "there is no package called 'cli'"
- interpretive_rules() failed on R 3.0 for guidelines without AmpC rules (assignment to zero rows)
- Guard the ggplot2 example of wisca_plot()

CI:
- check-old: R 3.0 could not install tinytest over HTTPS, so no unit tests ran; install it with curl, and fail when tinytest is missing or any test fails
- tinytest shim: record expectations in the test file environment, support skips and errors per test_that() block, add missing testthat equivalents, source helper files
- Add R 4.0 (oldrel-6) to check-old, and oldrel-5 to check-recent
This commit is contained in:
dr. M.S. (Matthijs) Berends committed 2026-10-10 14:54:15 +02:00
1 parent f0699c6584
commit 9e609dae83
13 files changed
+68 -32

No files matched your search

@@ -53,7 +53,7 @@ jobs:
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo 'matrix={"config":[{"os":"ubuntu-latest","r":"release","allowfail":false}]}' >> "$GITHUB_OUTPUT"
else
echo 'matrix={"config":[{"os":"windows-latest","r":"devel","allowfail":false},{"os":"ubuntu-latest","r":"devel","allowfail":false,"http-user-agent":"release"},{"os":"macOS-latest","r":"release","allowfail":true},{"os":"windows-latest","r":"release","allowfail":false},{"os":"ubuntu-latest","r":"release","allowfail":false},{"os":"ubuntu-latest","r":"oldrel-1","allowfail":false},{"os":"ubuntu-latest","r":"oldrel-2","allowfail":false},{"os":"ubuntu-latest","r":"oldrel-3","allowfail":false},{"os":"ubuntu-latest","r":"oldrel-4","allowfail":false}]}' >> "$GITHUB_OUTPUT"
echo 'matrix={"config":[{"os":"windows-latest","r":"devel","allowfail":false},{"os":"ubuntu-latest","r":"devel","allowfail":false,"http-user-agent":"release"},{"os":"macOS-latest","r":"release","allowfail":true},{"os":"windows-latest","r":"release","allowfail":false},{"os":"ubuntu-latest","r":"release","allowfail":false},{"os":"ubuntu-latest","r":"oldrel-1","allowfail":false},{"os":"ubuntu-latest","r":"oldrel-2","allowfail":false},{"os":"ubuntu-latest","r":"oldrel-3","allowfail":false},{"os":"ubuntu-latest","r":"oldrel-4","allowfail":false},{"os":"ubuntu-latest","r":"oldrel-5","allowfail":false}]}' >> "$GITHUB_OUTPUT"
fi
R-code-check:
+13 -9
View File
@@ -48,7 +48,9 @@ jobs:
config:
# Test all old versions of R >= 3.0, we support them all!
# For these old versions, dependencies and vignettes will not be checked.
# For recent R versions, see check-recent.yaml (r-lib and tidyverse support the latest 5 major R releases).
# For recent R versions, see check-current-testthat.yaml (r-lib and tidyverse support the latest 5 major R releases).
# R 4.0 (oldrel-6) is tested here, since current testthat and its dependencies cannot be installed on it.
- {os: ubuntu-latest, r: '4.0', allowfail: false}
# - {os: ubuntu-latest, r: '3.6', allowfail: false}
# - {os: windows-latest, r: '3.5', allowfail: false} # always fails, horrible with UTF-8
# - {os: ubuntu-latest, r: '3.4', allowfail: false} # 3.1-3.4 now always fails with Error in grep(warn_re, lines, invert = TRUE, value = TRUE) attempt to set index 46/46 in SET_STRING_ELT
@@ -76,15 +78,17 @@ jobs:
- uses: r-lib/actions/setup-pandoc@v2
- name: Install suggested pkgs (and tinytest) from CRAN
- name: Install tinytest from CRAN
# R < 3.2 cannot download over HTTPS, so install.packages() fails silently on CRAN;
# download the source with curl instead (suggested packages require much newer R versions anyway)
run: |
desc_lines <- readLines('DESCRIPTION')
suggests <- readLines('DESCRIPTION')[grepl("^(Suggests:| )", readLines('DESCRIPTION'))]
suggests <- suggests[(which(grepl("^Suggests", suggests)) + 1):length(suggests)]
suggests <- gsub("[ ,]", "", suggests)
pkgs <- unique(c(suggests, "tinytest"))
for (p in pkgs) try(install.packages(p, repos = "https://cran.r-project.org"), silent = TRUE)
shell: Rscript {0}
set -euo pipefail
mkdir -p "$R_LIBS_USER"
pkg=$(curl -sSL https://cran.r-project.org/src/contrib/ | grep -oE 'tinytest_[0-9.-]+\.tar\.gz' | head -1)
curl -sSLo "/tmp/$pkg" "https://cran.r-project.org/src/contrib/$pkg"
R CMD INSTALL -l "$R_LIBS_USER" "/tmp/$pkg"
Rscript -e "library(tinytest, lib.loc = Sys.getenv('R_LIBS_USER'))"
shell: bash
- name: Show session info
if: always()
+1 -1
View File
@@ -1,5 +1,5 @@
Package: AMR
Version: 3.0.1.9113
Version: 3.0.1.9114
Date: 2026-10-10
Title: Antimicrobial Resistance Data Analysis
Description: Functions to simplify and standardise antimicrobial resistance (AMR)
+1 -1
View File
@@ -1,4 +1,4 @@
# AMR 3.0.1.9113
# AMR 3.0.1.9114
Planned as v3.1.0, mid October 2026.
+3 -3
View File
@@ -650,10 +650,10 @@ stop_ <- function(...,
}
# prevent errors with single opening curly brackets, we don't evaluate cli's/glue's {} in AMR anyway
msg <- gsub("\\{(?!\\.)", "", msg, perl = TRUE)
if (!cli::ansi_has_hyperlink_support()) {
msg <- simplify_help_markup(msg)
}
if (has_cli_rlang()) {
if (!cli::ansi_has_hyperlink_support()) {
msg <- simplify_help_markup(msg)
}
if (isTRUE(call)) {
call_obj <- sys.call(-1)
} else if (!isFALSE(call)) {
+3 -1
View File
@@ -214,7 +214,9 @@
#' syndromic_group = "ward"
#' )
#' out
#' wisca_plot(out)
#' if (requireNamespace("ggplot2")) {
#' wisca_plot(out)
#' }
#'
#' # stratified using grouped tibbles (e.g. by age and gender)
#' if (requireNamespace("dplyr")) {
+4 -2
View File
@@ -663,8 +663,10 @@ interpretive_rules <- function(x,
if (isTRUE(ampc_cephalosporin_resistance)) {
ampc_cephalosporin_resistance <- "R"
}
if (!is.null(interpretive_rules_df$reference.rule)) {
interpretive_rules_df[which(interpretive_rules_df$reference.rule %like% "ampc"), "to_value"] <- as.character(ampc_cephalosporin_resistance)
# old R versions (at least 3.0) give an error when assigning to no rows of a data.frame without rows
ampc_rows <- if (is.null(interpretive_rules_df$reference.rule)) integer(0) else which(interpretive_rules_df$reference.rule %like% "ampc")
if (length(ampc_rows) > 0) {
interpretive_rules_df[ampc_rows, "to_value"] <- as.character(ampc_cephalosporin_resistance)
}
}
+3 -1
View File
@@ -313,7 +313,9 @@ out <- wisca(example_isolates,
syndromic_group = "ward"
)
out
wisca_plot(out)
if (requireNamespace("ggplot2")) {
wisca_plot(out)
}
# stratified using grouped tibbles (e.g. by age and gender)
if (requireNamespace("dplyr")) {
+1 -1
View File
@@ -98,7 +98,7 @@ mo_repository_root <- function() {
NULL
}
skip_if_no_mo_repository <- function() {
testthat::skip_if(is.null(mo_repository_root()), "Source repository not available (data-raw/ does not ship with the package)")
skip_if(is.null(mo_repository_root()), "Source repository not available (data-raw/ does not ship with the package)")
}
# names without a rank suffix, e.g. "Kapabacteria {class}" and "Nitrospira (class)" are both the class
+1 -1
View File
@@ -37,7 +37,7 @@ test_that("test-_deprecated.R", {
# deprecated custom_interpretive_rules() still works and emits a warning
expect_warning(
x_old <- custom_eucast_rules(AMC == "R" ~ aminopenicillins == "R"),
regexp = "custom_eucast_rules"
"custom_eucast_rules"
)
expect_inherits(x_old, "custom_interpretive_rules")
}
+4 -2
View File
@@ -62,8 +62,10 @@ test_that("test-misc.R", {
check_df <- function(check_element, return_val = 0) {
is_right <<- FALSE
for (env in sys.frames()) {
if (!is.null(env[[check_element]]) && is.data.frame(env[[check_element]])) {
is_right <<- all(colnames(example_isolates) %in% colnames(env[[check_element]]))
# in R < 4.2, reading a promise that is still being evaluated (such as `x` in tibble's `[`) gives an error
val <- tryCatch(env[[check_element]], error = function(e) NULL)
if (!is.null(val) && is.data.frame(val)) {
is_right <<- all(colnames(example_isolates) %in% colnames(val))
}
}
return_val
+3 -2
View File
@@ -242,9 +242,10 @@ test_that("test-interpretive_rules.R", {
tolerance = 0.5
)
# clsi_rules() no longer errors (returns data unchanged until CLSI rows are added)
# clsi_rules() no longer errors (returns data unchanged until CLSI rows are added);
# without the tibble package, a plain data.frame is returned
expect_identical(
suppressWarnings(clsi_rules(example_isolates, info = FALSE)),
example_isolates
if (AMR:::pkg_is_available("tibble")) example_isolates else as.data.frame(example_isolates, stringsAsFactors = FALSE)
)
})
+30 -7
View File
@@ -34,16 +34,30 @@ if (identical(Sys.getenv("R_RUN_TINYTEST"), "true")) {
# env var 'R_LIBS_USER' gets overwritten during 'R CMD check' in GitHub Actions, so:
.libPaths(c(Sys.getenv("R_LIBS_USER_GH_ACTIONS"), .libPaths()))
if (AMR:::pkg_is_available("tinytest", also_load = TRUE)) {
if (!AMR:::pkg_is_available("tinytest", also_load = TRUE)) {
stop("R_RUN_TINYTEST is 'true', but the tinytest package could not be loaded, so no unit tests were run")
} else {
# load the package
library(AMR)
# testthat equivalents; tinytest only records expectations that are called from the environment
# of a test file, so these call the expectations found there (via `env`) instead of tinytest::
test_that <- function(desc, code) {
code
env <- parent.frame()
tryCatch(code,
skip_test = function(s) invisible(NULL),
error = function(e) get("expect_true", envir = env)(FALSE, info = paste0("Error in '", desc, "': ", conditionMessage(e)))
)
}
skip_if <- function(condition, message = "") {
if (isTRUE(condition)) stop(structure(class = c("skip_test", "condition"), list(message = message, call = NULL)))
}
expect_output <- tinytest::expect_stdout
skip_on_cran <- function() invisible(NULL)
expect_output <- function(...) get("expect_stdout", envir = parent.frame())(...)
expect_named <- function(object, expected, ...) get("expect_identical", envir = parent.frame())(names(object), expected, ...)
expect_setequal <- function(object, expected, ...) get("expect_true", envir = parent.frame())(setequal(object, expected), ...)
expect_lte <- function(object, expected, ...) get("expect_true", envir = parent.frame())(isTRUE(all(object <= expected)), ...)
# set language
set_AMR_locale("English")
@@ -75,17 +89,26 @@ if (identical(Sys.getenv("R_RUN_TINYTEST"), "true")) {
`%||%` <- AMR:::`%||%`
}
testdir <- ifelse(dir.exists("inst/testthat"), "inst/testthat", "testthat")
# helper files are sourced by testthat, but not by tinytest; helper-functions.R only contains expect_inherits(), which tinytest has itself
helpers <- list.files(system.file(testdir, package = "AMR"), pattern = "^helper.*[.]R$", full.names = TRUE)
for (helper in helpers[basename(helpers) != "helper-functions.R"]) {
source(helper)
}
suppressMessages(
out <- test_package("AMR",
testdir = ifelse(dir.exists("inst/testthat"),
"inst/testthat",
"testthat"
),
testdir = testdir,
verbose = FALSE,
color = FALSE
)
)
cat("\n\nSUMMARY:\n")
print(summary(out))
if (!all_pass(out)) {
cat("\n\nFAILURES:\n")
print(out, passes = FALSE, limit = 100)
stop("Unit tests failed, see above")
}
}
}