tests/testthat/test-interpretive_rules.R

# ==================================================================== #
# TITLE:                                                               #
# AMR: An R Package for Working with Antimicrobial Resistance Data     #
#                                                                      #
# SOURCE CODE:                                                         #
# https://github.com/msberends/AMR                                     #
#                                                                      #
# PLEASE CITE THIS SOFTWARE AS:                                        #
# Berends MS, Luz CF, Friedrich AW, et al. (2022).                     #
# AMR: An R Package for Working with Antimicrobial Resistance Data.    #
# Journal of Statistical Software, 104(3), 1-31.                       #
# https://doi.org/10.18637/jss.v104.i03                                #
#                                                                      #
# Developed at the University of Groningen and the University Medical  #
# Center Groningen in the Netherlands, in collaboration with many      #
# colleagues from around the world, see our website.                   #
#                                                                      #
# This R package is free software; you can freely use and distribute   #
# it for both personal and commercial purposes under the terms of the  #
# GNU General Public License version 2.0 (GNU GPL-2), as published by  #
# the Free Software Foundation.                                        #
# We created this package for both routine data analysis and academic  #
# research and it was publicly released in the hope that it will be    #
# useful, but it comes WITHOUT ANY WARRANTY OR LIABILITY.              #
#                                                                      #
# Visit our website for the full manual and a complete tutorial about  #
# how to conduct AMR data analysis: https://amr-for-r.org              #
# ==================================================================== #

test_that("test-interpretive_rules.R", {
  skip_on_cran()
  # these tests are based on EUCAST rules, which must also hold when another guideline is set with the AMR_guideline option
  old_opts <- options(AMR_guideline = "EUCAST")
  on.exit(options(old_opts), add = TRUE)

  # thoroughly check input table
  expect_equal(
    sort(colnames(AMR:::INTERPRETIVE_RULES_DF)),
    sort(c(
      "rule.provider",
      "if_mo_property", "like.is.one_of", "this_value",
      "and_these_antibiotics", "have_these_values",
      "then_change_these_antibiotics", "to_value",
      "reference.rule", "reference.rule_group",
      "reference.version",
      "note"
    ))
  )
  MOs_mentioned <- unique(AMR:::INTERPRETIVE_RULES_DF$this_value)
  MOs_mentioned <- sort(trimws(unlist(strsplit(MOs_mentioned[!AMR:::is_valid_regex(MOs_mentioned)], ",", fixed = TRUE))))
  MOs_test <- suppressWarnings(
    trimws(paste(
      mo_genus(MOs_mentioned, keep_synonyms = TRUE, language = NULL),
      mo_species(MOs_mentioned, keep_synonyms = TRUE, language = NULL),
      mo_subspecies(MOs_mentioned, keep_synonyms = TRUE, language = NULL)
    ))
  )
  MOs_test[MOs_test == ""] <- mo_fullname(MOs_mentioned[MOs_test == ""], keep_synonyms = TRUE, language = NULL)
  expect_equal(MOs_mentioned, MOs_test)

  expect_error(suppressWarnings(interpretive_rules(example_isolates, col_mo = "Non-existing")))
  expect_error(interpretive_rules(x = "text"))
  expect_error(interpretive_rules(data.frame(a = "test")))
  expect_error(interpretive_rules(data.frame(mo = "test"), rules = "invalid rules set"))

  # expect_warning(interpretive_rules(data.frame(mo = "Escherichia coli", vancomycin = "S", stringsAsFactors = TRUE)))

  expect_identical(
    colnames(example_isolates),
    colnames(suppressWarnings(interpretive_rules(example_isolates, info = FALSE)))
  )

  expect_output(suppressMessages(interpretive_rules(example_isolates, info = TRUE)))

  a <- data.frame(
    mo = c(
      "Klebsiella pneumoniae",
      "Pseudomonas aeruginosa",
      "Enterobacter cloacae"
    ),
    amox = "-", # Amoxicillin
    stringsAsFactors = FALSE
  )
  b <- data.frame(
    mo = c(
      "Klebsiella pneumoniae",
      "Pseudomonas aeruginosa",
      "Enterobacter cloacae"
    ),
    amox = "R", # Amoxicillin
    stringsAsFactors = FALSE
  )
  expect_identical(suppressWarnings(interpretive_rules(a, "mo", info = FALSE)), b)
  expect_output(suppressMessages(suppressWarnings(interpretive_rules(a, "mo", info = TRUE))))

  a <- data.frame(
    mo = c(
      "Staphylococcus aureus",
      "Streptococcus group A"
    ),
    COL = "-", # Colistin
    stringsAsFactors = FALSE
  )
  b <- data.frame(
    mo = c(
      "Staphylococcus aureus",
      "Streptococcus group A"
    ),
    COL = "R", # Colistin
    stringsAsFactors = FALSE
  )
  expect_equal(suppressWarnings(interpretive_rules(a, "mo", info = FALSE)), b)

  # piperacillin must be R in E. coli when ampi is R
  if (AMR:::pkg_is_available("dplyr", min_version = "1.0.0", also_load = TRUE)) {
    expect_equal(
      suppressWarnings(
        example_isolates %>%
          filter(mo_name(mo) == "Escherichia coli") %>%
          mutate(
            AMP = as.sir("R"),
            PIP = as.sir(NA)
          ) %>%
          interpretive_rules(col_mo = "mo", version_expertrules = 3.3, rules = "expert", info = FALSE, overwrite = TRUE) %>%
          pull(PIP) %>%
          unique() %>%
          as.character()
      ),
      "R"
    )
  }

  # azithromycin and clarythromycin must be equal to Erythromycin
  a <- suppressWarnings(as.sir(interpretive_rules(
    data.frame(
      mo = rep(as.mo("Campylobacter jejuni"), nrow(example_isolates)),
      ERY = example_isolates$ERY,
      AZM = as.sir("R"),
      CLR = factor("R"),
      stringsAsFactors = FALSE
    ),
    version_expertrules = 3.3,
    rules = "expert",
    overwrite = TRUE,
    only_sir_columns = FALSE
  )$CLR))
  b <- example_isolates$ERY
  expect_identical(
    a[!is.na(b) & b != "I"],
    b[!is.na(b) & b != "I"]
  )

  # amox is inferred by benzylpenicillin in Kingella kingae
  expect_equal(
    suppressWarnings(
      as.list(interpretive_rules(
        data.frame(
          mo = as.mo("Kingella kingae"),
          PEN = "S",
          AMX = "-",
          stringsAsFactors = FALSE
        ),
        info = FALSE
      ))$AMX
    ),
    "S"
  )

  # also test norf
  if (AMR:::pkg_is_available("dplyr", min_version = "1.0.0", also_load = TRUE)) {
    expect_output(suppressWarnings(interpretive_rules(example_isolates %>% mutate(NOR = "S", NAL = "S"), info = TRUE)))
  }

  # check verbose output
  expect_output(suppressWarnings(interpretive_rules(example_isolates, verbose = TRUE, rules = "all", info = TRUE)))

  # AmpC de-repressed cephalo mutants

  expect_identical(
    interpretive_rules(
      data.frame(
        mo = c("Escherichia coli", "Enterobacter cloacae"),
        cefotax = as.sir(c("S", "S"))
      ),
      ampc_cephalosporin_resistance = TRUE,
      rules = "expert",
      overwrite = TRUE,
      info = FALSE
    )$cefotax,
    as.sir(c("S", "R"))
  )

  expect_identical(
    interpretive_rules(
      data.frame(
        mo = c("Escherichia coli", "Enterobacter cloacae"),
        cefotax = as.sir(c("S", "S"))
      ),
      ampc_cephalosporin_resistance = NA,
      rules = "expert",
      overwrite = TRUE,
      info = FALSE
    )$cefotax,
    as.sir(c("S", NA))
  )

  expect_identical(
    interpretive_rules(
      data.frame(
        mo = c("Escherichia coli", "Enterobacter cloacae"),
        cefotax = as.sir(c("S", "S"))
      ),
      rules = "expert",
      ampc_cephalosporin_resistance = NULL,
      overwrite = TRUE,
      info = FALSE
    )$cefotax,
    as.sir(c("S", "S"))
  )

  # EUCAST dosage -----------------------------------------------------------
  expect_equal(nrow(eucast_dosage(c("tobra", "genta", "cipro"))), 3)
  expect_inherits(eucast_dosage(c("tobra", "genta", "cipro")), "data.frame")


  x <- custom_interpretive_rules(
    AMC == "R" & genus == "Klebsiella" ~ aminopenicillins == "R",
    AMC == "I" & genus == "Klebsiella" ~ aminopenicillins == "I",
    AMX == "S" ~ AMC == "S"
  )
  expect_output(print(x))
  expect_output(print(c(x, x)))
  expect_output(print(as.list(x, x)))

  # this custom rules makes 8 changes
  expect_equal(
    nrow(interpretive_rules(example_isolates,
      rules = "custom",
      custom_rules = x,
      info = FALSE,
      overwrite = TRUE,
      verbose = TRUE
    )),
    8,
    tolerance = 0.5
  )

  # 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)),
    if (AMR:::pkg_is_available("tibble")) example_isolates else as.data.frame(example_isolates, stringsAsFactors = FALSE)
  )
})

Try the AMR package in your browser

Any scripts or data that you put into this service are public.

AMR documentation built on Oct. 16, 2026, 5:10 p.m.