tests/test_import/test_from.R

# We use the testthat library to evaluate expectations.
# Tests must nevertheless be run outside the standard testthat
# test harness, because import::from changes environments that
# are protected when run inside the harness. See the contents
# of the testthat directory to examine the custom test harness
# that is used instead. These tests can also be run manually.
library(testthat)

# Printing the directory helps with fixing any problems if tests fail
print(getwd())

# Source cleanup script
# (we do not use import::from because then the script would clean itself up)
source("cleanup_environment.R")

## IMPORTANT:
## Remember to run the cleanup script after each test sequence with:
## > cleanup_environment()


## Tests begin


test_that("Imports from libraries work", {
  expect_error ( normal_print("OK") )
  expect_silent( import::from(knitr, normal_print) )
  expect_output( normal_print("OK"), "OK" )
  cleanup_environment()
})

test_that("Imports from modules work", {
  expect_error ( fun1() )
  expect_silent( import::from(module_base.R, fun1) )
  expect_equal ( fun1(), "fun1" )
  cleanup_environment()
})

test_that("Subsequent imports from modules work", {
  expect_error ( fun1() )
  expect_error ( fun7() )
  expect_silent( import::from(module_base.R, .all=TRUE) )
  expect_silent( import::from(module_subsequent.R, .all=TRUE) )
  expect_equal ( fun1(), "fun1" )
  expect_equal ( fun7(), "fun7" )
  cleanup_environment()
})

test_that("Passing values as characters works", {
  char_package   <- "knitr"
  char_functions <- c("normal_print","knit_print")
  expect_error ( normal_print("OK") )
  expect_silent( import::from(char_package, char_functions, .character_only=TRUE) )
  expect_output( normal_print("OK"), "OK" )
  expect_output( knit_print("OK"),   "OK" )
  cleanup_environment()
})

test_that("Importing modules by absolute path works", {
  abs_module <- file.path(tempdir(),"module_base.R")
  file.copy("module_base.R",abs_module)
  expect_error ( fun1() )
  expect_silent( import::from(abs_module, "fun1", .character_only=TRUE) )
  expect_equal ( fun1(), "fun1" )
  cleanup_environment()
})

test_that("The .all parameter works", {
  expect_error ( fun1() )
  expect_silent( import::from(module_base.R, .all=TRUE) )
  expect_equal ( fun1(), "fun1" )
  expect_equal ( fun2(), "fun2" )
  cleanup_environment()
})

# The .all parameter should work with individual objects for renaming
# Renamed functions should not be found under their original names
test_that("The .all parameter works with renamings", {
  expect_error ( fun1() )
  expect_silent( import::from(module_base.R, hansolo=fun1, luke=fun6, .all=TRUE) )
  expect_equal ( hansolo(), "fun1" )
  expect_equal ( fun2(),    "fun2" )
  expect_equal ( luke(),    "fun6" )
  expect_error ( fun1()            )
  expect_error ( fun6()            )
  cleanup_environment()
})

test_that("The .all and .except parameters work together", {
  expect_error ( fun1() )
  expect_silent( import::from(module_base.R, .all=TRUE, .except=c("fun2","fun3")) )
  expect_equal ( fun1(), "fun1" )
  expect_error ( fun2()         )
  expect_error ( fun3()         )
  expect_equal ( fun4(), "fun4" )
  cleanup_environment()
})

test_that("The .all parmeter is smart about whether .except is being used", {
  expect_error ( fun1() )
  expect_silent( import::from(module_base.R, .except=c("fun1","fun4")) )
  expect_error ( fun1()         )
  expect_equal ( fun2(), "fun2" )
  expect_equal ( fun3(), "fun3" )
  expect_error ( fun4()         )
  expect_equal ( fun5(), "fun5" )
  expect_equal ( fun6(), "fun6" )
  cleanup_environment()
})

test_that("Using .all or .except with import::: should throw an error", {
  expect_error( import:::from(module_base.R, .all=TRUE) )
  expect_error( import:::from(module_base.R, .except=c("fun1","fun4")) )
  expect_error( import:::from(module_base.R, .all=TRUE, .except=c("fun2","fun3")) )
  cleanup_environment()
})

test_that("The .into paremeter is honored", {
  expect_error ( normal_print("OK") )
  expect_silent( import::from(knitr, normal_print, .into="custom_env") )
  expect_output( normal_print("OK"), "OK" )
  cleanup_environment("custom_env")
})

test_that("The .into paremeter is honored w/ .character_only=TRUE", {
  expect_error ( normal_print("OK") )
  expect_silent( import::from('knitr', "normal_print", .into="custom_env", .character_only=TRUE) )
  expect_output( normal_print("OK"), "OK" )
  cleanup_environment("custom_env")
})

test_that("Importing .into={....} (curly brackets) works", {
  expect_error ( normal_print("OK") )
  expect_false ( "normal_print" %in% ls() )
  expect_silent( import::from(knitr, normal_print, .into={environment()}) )
  expect_output( normal_print("OK"), "OK" )
  expect_true  ("normal_print" %in% ls() )
  cleanup_environment(cleanup_here=TRUE)
})

test_that("Importing .into={....} (curly brackets) works w/ .character_only=TRUE", {
  expect_error ( normal_print("OK") )
  expect_false ( "normal_print" %in% ls() )
  expect_silent( import::from("knitr", "normal_print", .into={environment()}, .character_only=TRUE) )
  expect_output( normal_print("OK"), "OK" )
  expect_true  ("normal_print" %in% ls() )
  cleanup_environment(cleanup_here=TRUE)
})

test_that("Importing .into=\"\" (empty string) works", {
  expect_error ( normal_print("OK") )
  expect_false ( "normal_print" %in% ls() )
  expect_silent( import::from(knitr, normal_print, .into="") )
  expect_output( normal_print("OK"), "OK" )
  expect_true  ("normal_print" %in% ls() )
  cleanup_environment(cleanup_here=TRUE)
})

test_that("Importing .into=\"\" (empty string) works w/ .character_only=TRUE", {
  expect_error ( normal_print("OK") )
  expect_false ( "normal_print" %in% ls() )
  expect_silent( import::from("knitr", "normal_print", .into="", .character_only=TRUE) )
  expect_output( normal_print("OK"), "OK" )
  expect_true  ("normal_print" %in% ls() )
  cleanup_environment(cleanup_here=TRUE)
})

test_that("Importing .into a symbol works", {
  expect_error ( normal_print("OK") )
  expect_false ( "normal_print" %in% ls() )
  symbol_env <- "custom_env"
  expect_silent( import::from(knitr, normal_print, .into=symbol_env) )
  expect_output( normal_print("OK"), "OK" )
  expect_true  ("normal_print" %in% ls(name = symbol_env) )
  cleanup_environment(environments = symbol_env)
})

test_that("Importing .into a symbol works w/ .character_only=TRUE", {
  expect_error ( normal_print("OK") )
  expect_false ( "normal_print" %in% ls() )
  symbol_env <- "custom_env"
  expect_silent( import::from("knitr", "normal_print", .into=symbol_env, .character_only=TRUE) )
  expect_output( normal_print("OK"), "OK" )
  expect_true  ("normal_print" %in% ls(name = symbol_env) )
  cleanup_environment(environments = symbol_env)
})

test_that("Imports from libraries NOT defined in .libPaths work", {
  tmp_install_dir <- tempdir()
  if (!file.exists("packageToTest_0.1.0.tar.gz")) {
    system("R CMD build packageToTest")
  }
  install.packages("packageToTest_0.1.0.tar.gz",
    lib = tmp_install_dir,
    repos = NULL,
    type = "source",
    quiet = TRUE
  )
  expect_true("packageToTest" %in% list.files(tmp_install_dir))
  expect_silent(import::from(.from = packageToTest, .library = tmp_install_dir, hello))
  expect_equal(hello(), "Hello, world!")
})

test_that("Functions named `get` in the calling environment do not mask base::get", {
  get <- function(...) stop("import incorrectly used function `get` defined in calling env.")
  expect_silent(import::from(module_base.R, fun1))
  expect_silent(import::from(knitr, normal_print))
  cleanup_environment()
})

test_that("Functions named `get` in arbitrary environment on search path do not mask base::get", {
  attach(what = new.env(parent = emptyenv()), pos = 2, name = "custom")
  assign(x = "get", value = function(...) stop("import incorrectly used function `get` defined in custom env on search path."), pos = "custom")
  expect_silent(import::from(module_base.R, fun1))
  expect_silent(import::from(knitr, normal_print))
  cleanup_environment()
  detach("custom")
})

test_that("Functions named `get` exported from packages do not mask base::get", {
  tmp_install_dir <- tempdir()
  library(packageToTest, lib.loc = tmp_install_dir)
  expect_true("get" %in% getNamespaceExports("packageToTest"))
  expect_silent(import::from(module_base.R, fun1))
  expect_silent(import::from(knitr, normal_print))
  cleanup_environment()
  detach("package:packageToTest", unload = TRUE)
})


test_that("Imports from specific version work",{

  # Base case, no version
  expect_silent( import::from(magrittr, "%>%") )# no version, quotes are unnecessary.

  # Variable spacing before parenthesis or around comparator operator
  expect_silent( import::from("magrittr (>=1.5)", "%>%")      )
  expect_silent( import::from("magrittr(>= 1.5)", "%>%")      )
  expect_silent( import::from("magrittr( >=1.5)", "%>%")      )
  expect_silent( import::from("magrittr  (  >=1.5  )", "%>%")      )

  # Variable specificity
  expect_silent( import::from("magrittr(>=1)", "%>%")   )
  expect_silent( import::from("magrittr(>=1.5)", "%>%")      )
  expect_silent( import::from("magrittr(>=1.5.0)", "%>%")      )

  # Maximum version
  expect_silent( import::from("magrittr(<= 100.0.1)", "%>%") )

  # Non-equality
  expect_silent( import::from("magrittr(!= 1.0.1)", "%>%")    )
  expect_silent( import::from("magrittr(!= 1.0.1)", "%>%")   )

  # Cleanup before testing failures
  cleanup_environment()

  # If the version is not available, the import should fail with erro
  # Variable spacing before parenthesis or around comparator operator
  expect_error( import::from("magrittr (>=100.5)", "%>%")      )
  expect_error( import::from("magrittr(>= 100.5)", "%>%")      )
  expect_error( import::from("magrittr( >=100.5)", "%>%")      )
  expect_error( import::from("magrittr  (  >=100.5  )", "%>%")      )

  # Variable specificity
  expect_error( import::from("magrittr(>=100)", "%>%")   )
  expect_error( import::from("magrittr(>=100.5)", "%>%")      )
  expect_error( import::from("magrittr(>=100.5.0)", "%>%")      )

  # Maximum version
  expect_error( import::from("magrittr(<= 0.0.1)", "%>%") )


  # Test equality/non-equality with the version currently installed
  # (1.5.0 at time of writing. The test could be updated to choose an
  # available version automatically, but we'll put that on the backburner
  # for now. So we skip these tests when running automatically.)
  skip("It is too fragile to test specific versions")

  # Non-equality
  expect_error( import::from("magrittr(!= 1.5)", "%>%")    )
  expect_error( import::from("magrittr(!= 1.5.0)", "%>%")   )

  # Equality
  expect_silent( import::from("magrittr(== 1.5)", "%>%") )
  expect_silent( import::from("magrittr(== 1.5.0)", "%>%") )
  expect_silent( import::from("magrittr(1.5)", "%>%")    )  # same as (==1.5)
  expect_silent( import::from("magrittr(1.5.0)", "%>%")    )
})

## .chdir parameter is tested in a separate file (test_param_chdir.R)

test_that("Script errors are caught and allow manual retry", {
  expect_error ( foo() )
  expect_true  ( is.na(Sys.getenv("SOMECONFIG", NA)) )
  expect_error ( import::from(module_script_error.R, foo) )
  expect_error ( foo() )
  Sys.setenv   ( "SOMECONFIG"="any" )
  expect_silent( import::from(module_script_error.R, foo) )
  expect_equal ( foo(), "foo" )
  Sys.unsetenv ( "SOMECONFIG" )
  cleanup_environment()
})

## Tests end


## IMPORTANT:
## The following line must be printed exactly as is,
## it is used by the custom harness to check if the tests worked:
print("Import tests completed successfully ...")
smbache/import documentation built on Jan. 27, 2024, 10:49 a.m.