context('basic')
is_module_loaded = function (mod) {
box:::is_mod_loaded(attr(mod, 'info'))
}
test_teardown(clear_mods())
module_source_path = function (mod) {
attr(mod, 'info')$source_path
}
test_that('module can be imported', {
box::use(mod/a)
expect_true(is_module_loaded(a))
expect_in('double', ls(a))
})
test_that('import works in global namespace', {
in_globalenv({
box::use(mod/a)
expect_true(box:::is_mod_loaded(attr(a, 'info')))
# `expect_in` isn’t found here.
expect_true('double' %in% ls(a))
})
})
test_that('module is uniquely identified by path', {
box::use(mod/a)
box::use(ba = mod/b/a)
expect_true(is_module_loaded(a))
expect_true(is_module_loaded(ba))
expect_not_identical(module_source_path(a), module_source_path(ba))
expect_in('double', ls(a))
expect_not_in('double', ls(ba))
})
test_that('can use imported function', {
box::use(mod/a)
expect_equal(a$double(42), 42 * 2)
})
test_that('modules export all objects', {
box::use(mod/a)
expect_gt(length(lsf.str(a)), 0L)
expect_gt(length(ls(a)), length(lsf.str(a)))
a_namespace = environment(a$double)
expect_equal(a$get_counter(), 1L)
})
test_that('module can modify its variables', {
box::use(mod/a)
counter = a$get_counter()
a$inc()
expect_equal(a$get_counter(), counter + 1L)
})
test_that('hidden objects are not exported', {
box::use(mod/a)
ns = environment(a$get_counter)
expect_true(exists('modname', envir = a))
expect_true(exists('make_counter', envir = ns))
expect_false(exists('make_counter', envir = a))
expect_true(exists('private_modname', envir = ns))
expect_false(exists('private_modname', envir = a))
})
test_that('module bindings are locked', {
box::use(mod/a)
expect_true(environmentIsLocked(a))
expect_true(bindingIsLocked('get_counter', a))
expect_true(bindingIsLocked('modname', a))
err = try({a$counter = 2L}, silent = TRUE)
expect_s3_class(err, 'try-error')
})
test_that('modules don’t need exports', {
expect_equal(ls(), character(0L))
expect_error(box::use(mod/no_exports), NA)
expect_error(capture.output(box::use(mod/no_names)), NA)
expect_setequal(ls(), c('no_exports', 'no_names'))
})
test_that('modules can be empty', {
expect_error(box::use(mod/empty), NA)
expect_error(box::use(mod/export_empty), NA)
})
test_that('global scope is not leaking into modules', {
in_globalenv({
x = 1L
expect_error(box::use(mod/issue151), 'object .* not found')
})
})
test_that('package exports do not leak into modules', {
expect_true('package:stats' %in% search())
box::use(mod/a)
ns_a = attr(a, 'namespace')
# First, ensure this is run in the right environment:
expect_equal(get0('modname', envir = ns_a, inherits = FALSE), 'a')
expect_true(get0('T', envir = ns_a))
expect_null(get0('t.test', envir = ns_a))
expect_not_null(get0('t.test', envir = .GlobalEnv))
})
test_that('partial name causes error', {
box::use(mod/a)
expect_error(a$double, NA)
expect_error(a$doubl, "name 'doubl' not found in 'a'")
# Check whether error call is correct:
error = tryCatch(a$doubl, error = identity)
expect_s3_class(error, 'simpleError')
expect_identical(error$call, quote(a$doubl))
})
test_that('trailing comma is accepted', {
expect_error(box::use(mod/a, ), NA)
expect_error(box::use(mod/a, mod/b, ), NA)
expect_error(box::use(mod/a[modname, double, ]), NA)
})
test_that('nested module can use parent', {
box::use(mod/b/b)
expect_true(exists('z', b))
expect_equal(b$z, 1)
})
test_that('using legacy functions raises warning', {
on.exit({
box::unload(library)
box::unload(require)
box::unload(source)
})
expect_warning(box::use(mod/legacy/library), '.+library.+ inside a module')
expect_warning(box::use(mod/legacy/require), '.+require.+ inside a module')
expect_false(exists('source_test', envir = .GlobalEnv))
on.exit(rm(source_test, envir = .GlobalEnv))
expect_warning(box::use(mod/legacy/source), '.+source.+ inside a module')
expect_true(exists('source_test', envir = .GlobalEnv))
})
test_that('legacy function warning can be silenced', {
old_opts = options(box.warn.legacy = FALSE)
box:::set_import_env_parent()
on.exit({
options(old_opts)
box:::set_import_env_parent()
})
expect_warning(box::use(mod/legacy/library), NA)
expect_warning(box::use(mod/legacy/require), NA)
expect_false(exists('source_test', envir = .GlobalEnv))
on.exit(rm(source_test, envir = .GlobalEnv), add = TRUE)
expect_warning(box::use(mod/legacy/source), NA)
expect_true(exists('source_test', envir = .GlobalEnv))
})
test_that('r/core can be imported', {
# All the test case logic is inside the `core_test` module.
box::use(mod/core_test)
# Ensure tests were actually run:
expect_gt(core_test$tests_run, 0L)
})
test_that('modules can be imported and exported by different local names', {
expect_error(box::use(mod/issue211), NA)
})
test_that('legacy modules export all names', {
is_legacy = function (mod) {
box:::namespace_info(attr(mod, 'namespace'), 'legacy', default = FALSE)
}
box::use(
mod/a,
mod/legacy,
mod/no_exports
)
expect_false(is_legacy(a))
expect_true(is_legacy(legacy))
expect_false(is_legacy(no_exports))
expect_setequal(ls(legacy), c('a', 'b'))
expect_setequal(ls(no_exports), character())
})
test_that('modules can specify explicit exports', {
box::use(ex = mod/explicit_exports)
expect_setequal(ls(ex), c('a', 'double', 'modname'))
expect_identical(ex$double, attr(ex, 'namespace')$double)
expect_equal(ex$modname, ex$a$modname)
})
test_that('`box::export()` checks its arguments', {
# Create a test module namespace since `box::export()` can only be called inside a module.
test_spec = box:::mod_spec(list(mod = 'test', name = 'test', explicit = FALSE))
test_info = box:::mod_info(test_spec, '.')
test_ns = box:::make_namespace(test_info)
test_ns$a = 1
expect_error(local(box::export(a), envir = test_ns), NA)
expect_error(
local(box::export(a = a), envir = test_ns),
'unexpected named argument'
)
})
test_that('legcay modules do not call hooks', {
# Ensure module is first unloaded:
box::use(mod/legacy)
box::unload(legacy)
expect_messages(
box::use(mod/legacy),
has = 'legacy module loaded',
has_not = '\\.on_load is not called'
)
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.