# ------------------------------------------------------------------------------ # furrr_options(globals =) test_that("can export globals using a named list", { plan(multisession, workers = 2) on.exit(plan(sequential), add = TRUE) opts <- furrr_options(globals = list(y = 1)) fn <- function(x) { exists("y") } expect_identical(future_map_lgl(1:2, fn, .options = opts), c(TRUE, TRUE)) }) test_that("can detect globals from the caller environment (HenrikBengtsson/future.apply#62)", { plan(multisession, workers = 2) on.exit(plan(sequential), add = TRUE) fn <- function(x) { exists("y") } wrapper <- function(options = furrr_options()) { y <- 1 future_map_lgl(1, fn, .options = options) } expect_identical(wrapper(), FALSE) options <- furrr_options(globals = "y") expect_identical(wrapper(options), TRUE) }) test_that("can export globals with sequential futures", { plan(sequential) fn <- function(x) { exists("y") } environment(fn) <- .GlobalEnv # With named list opts <- furrr_options(globals = list(y = 1)) expect_identical(future_map_lgl(1:2, fn, .options = opts), c(TRUE, TRUE)) # With character lookup in caller env wrapper <- function(fn) { y <- 1 future_map_lgl(1, fn, .options = furrr_options(globals = "y")) } environment(wrapper) <- .GlobalEnv expect_identical(wrapper(fn), TRUE) }) test_that("validates `globals`", { expect_error(furrr_options(globals = 1)) expect_error(furrr_options(globals = c(TRUE, TRUE))) expect_error(furrr_options(globals = list(a = 1, 2))) }) # ------------------------------------------------------------------------------ # furrr_options(packages =) test_that("can selectively export packages on multisession", { plan(multisession, workers = 2) on.exit(plan(sequential), add = TRUE) opts <- furrr_options(packages = "dplyr") # TODO: Reenable this test after future issue is fixed # https://github.com/futureverse/future/issues/820 # https://github.com/futureverse/furrr/issues/307 # expect_error( # future_map(1:2, ~ tibble(x = .x)) # ) expect_identical( future_map(1:2, ~ tibble(x = .x), .options = opts), list(dplyr::tibble(x = 1L), dplyr::tibble(x = 2L)) ) }) test_that("validates `packages`", { expect_error(furrr_options(packages = 1)) }) # ------------------------------------------------------------------------------ # furrr_options(stdout =) furrr_test_that("can use `stdout = FALSE`", { opts <- furrr_options(stdout = FALSE) fn <- function(x) { con <- stdout() write("hello", con) x } expect_silent(future_map(1:5, fn, .options = opts)) }) test_that("can use `stdout = NA` to not intercept at all", { opts <- furrr_options(stdout = NA) fn <- function(x) { con <- stdout() write("hello", con) x } # Output is likely shown for sequential backends plan(sequential) expect_snapshot(future_map(1:2, fn, .options = opts)) # Output is likely not passed back from the other R session # (because it isn't handled or captured at all) plan(multisession, workers = supported_max_cores("multisession")) on.exit(plan(sequential), add = TRUE) expect_snapshot(future_map(1:2, fn, .options = opts)) }) test_that("validates `stdout`", { expect_snapshot({ (expect_error(furrr_options(stdout = "x"))) (expect_error(furrr_options(stdout = c(TRUE, TRUE)))) }) }) # ------------------------------------------------------------------------------ # furrr_options(conditions =) furrr_test_that("can capture no conditions", { fn <- function(x) { warning("hello") x } opts <- furrr_options(conditions = character()) expect_warning(future_map(1:5, fn, .options = opts), NA) }) test_that("can avoid handling conditions altogether", { fn <- function(x) { warning("hello") x } opts <- furrr_options(conditions = NULL) # Warning is likely shown for sequential backends plan(sequential) expect_snapshot(future_map(1:5, fn, .options = opts)) # Warning is likely not passed back from the other R session # (because it isn't handled or captured at all) plan(multisession, workers = supported_max_cores("multisession")) on.exit(plan(sequential), add = TRUE) expect_snapshot(future_map(1:5, fn, .options = opts)) }) furrr_test_that("can selectively avoid conditions", { fn <- function(x) { rlang::warn("classed warning", class = "ignore_me") rlang::warn("unclassed warning", class = "dont_ignore_me") x } # Both warnings are shown expect_warning( expect_warning(future_map(1, fn), class = "ignore_me"), class = "dont_ignore_me" ) # Only dont_ignore_me is shown opts <- furrr_options( conditions = structure("condition", exclude = "ignore_me") ) expect_warning(future_map(1, fn, .options = opts), class = "dont_ignore_me") }) test_that("validates `conditions`", { expect_snapshot({ (expect_error(furrr_options(conditions = 1))) }) }) # ------------------------------------------------------------------------------ # furrr_options(seed =) furrr_test_that("can use integer `seed` of size 1", { old_seed <- get_random_seed() opts <- furrr_options(seed = 123) x <- future_map(5, runif, .options = opts) expect_false(identical(old_seed, get_random_seed())) y <- future_map(5, runif, .options = opts) expect_identical(x, y) }) furrr_test_that("can use integer `seed` of size 7", { old_rngkind <- RNGkind("L'Ecuyer-CMRG") lecuyer_seed <- get_random_seed() # Reset RNGkind(old_rngkind[[1]]) old_seed <- get_random_seed() opts <- furrr_options(seed = lecuyer_seed) x <- future_map(5, runif, .options = opts) expect_false(identical(old_seed, get_random_seed())) y <- future_map(5, runif, .options = opts) expect_identical(x, y) }) furrr_test_that("`TRUE` advances `.Random.seed` but `FALSE` doesn't", { old_seed <- get_random_seed() opts <- furrr_options(seed = FALSE) future_map(1:5, ~.x, .options = opts) expect_identical(old_seed, get_random_seed()) opts <- furrr_options(seed = TRUE) future_map(1:5, ~.x, .options = opts) expect_false(identical(old_seed, get_random_seed())) }) furrr_test_that("`NULL` seed doesn't advance `.Random.seed`", { old_seed <- get_random_seed() opts <- furrr_options(seed = NULL) future_map(1:5, ~.x, .options = opts) expect_identical(old_seed, get_random_seed()) }) test_that("must use valid L'Ecuyer-CMRG seed", { opts <- furrr_options(seed = 1:7) expect_error(future_map(1:5, ~.x, .options = opts), "must be") }) test_that("validates `seed`", { expect_error(furrr_options(seed = "x")) expect_error(furrr_options(seed = c(1, 2))) expect_error(furrr_options(seed = c(TRUE, FALSE))) expect_error(furrr_options(seed = 1.5)) expect_error(furrr_options(seed = NA)) }) # ------------------------------------------------------------------------------ # furrr_options(scheduling =) test_that("can specify `scheduling`", { x <- furrr_options(scheduling = TRUE) expect_identical(x$scheduling, TRUE) x <- furrr_options(scheduling = FALSE) expect_identical(x$scheduling, FALSE) x <- furrr_options(scheduling = 0) expect_identical(x$scheduling, 0L) x <- furrr_options(scheduling = 5) expect_identical(x$scheduling, 5L) x <- furrr_options(scheduling = Inf) expect_identical(x$scheduling, Inf) }) test_that("validates `scheduling`", { expect_error(furrr_options(scheduling = c(1, 2))) expect_error(furrr_options(scheduling = c(TRUE, FALSE))) expect_error(furrr_options(scheduling = "x")) expect_error(furrr_options(scheduling = 1.5)) expect_error(furrr_options(scheduling = NA)) expect_error(furrr_options(scheduling = -Inf)) expect_error(furrr_options(scheduling = lm(1 ~ 1))) }) test_that("`scheduling` supports an `ordering` attribute (#289)", { # Integer `scheduling` x <- furrr_options(scheduling = structure(2L, ordering = "random")) expect_identical(x$scheduling, structure(2L, ordering = "random")) # Double `scheduling` x <- furrr_options(scheduling = structure(2, ordering = "random")) expect_identical(x$scheduling, structure(2L, ordering = "random")) # Inf `scheduling` x <- furrr_options(scheduling = structure(Inf, ordering = "random")) expect_identical(x$scheduling, structure(Inf, ordering = "random")) # Logical `scheduling` x <- furrr_options(scheduling = structure(TRUE, ordering = "random")) expect_identical(x$scheduling, structure(TRUE, ordering = "random")) }) # ------------------------------------------------------------------------------ # furrr_options(chunk_size =) test_that("can specify `chunk_size`", { x <- furrr_options(chunk_size = 2) expect_identical(x$chunk_size, 2L) x <- furrr_options(chunk_size = Inf) expect_identical(x$chunk_size, Inf) }) test_that("validates `chunk_size`", { expect_error(furrr_options(chunk_size = 0)) expect_error(furrr_options(chunk_size = c(1, 2))) expect_error(furrr_options(chunk_size = "x")) expect_error(furrr_options(chunk_size = 1.5)) expect_error(furrr_options(chunk_size = NA)) expect_error(furrr_options(chunk_size = -Inf)) expect_error(furrr_options(chunk_size = lm(1 ~ 1))) }) test_that("`chunk_size` supports an `ordering` attribute (#290)", { # Integer `chunk_size` x <- furrr_options(chunk_size = structure(2L, ordering = "random")) expect_identical(x$chunk_size, structure(2L, ordering = "random")) # Double `chunk_size` x <- furrr_options(chunk_size = structure(2, ordering = "random")) expect_identical(x$chunk_size, structure(2L, ordering = "random")) # Inf `chunk_size` x <- furrr_options(chunk_size = structure(Inf, ordering = "random")) expect_identical(x$chunk_size, structure(Inf, ordering = "random")) }) # ------------------------------------------------------------------------------ # furrr_options(prefix =) furrr_test_that("labels can be passed through without erroring", { opts <- furrr_options(prefix = "foo") expect_error(future_map(1:5, ~.x, .options = opts), NA) }) test_that("validates `prefix`", { expect_error(furrr_options(prefix = 1)) expect_error(furrr_options(prefix = c("x", "y"))) }) # ------------------------------------------------------------------------------ # validation test_that("option object is validated", { expect_error(future_map(1:5, ~.x, .options = 1)) expect_error(future_map2(1:5, 1:5, ~.x, .options = 1)) expect_error(future_pmap(list(1:5), ~.x, .options = 1)) })