#include "cpp11/as.hpp" #include "cpp11/environment.hpp" #include "cpp11/function.hpp" #include "cpp11/strings.hpp" #include context("environment-C++") { test_that("environment works") { auto new_env = cpp11::package("base")["new.env"]; SEXP x_sxp = PROTECT(new_env()); cpp11::environment x(x_sxp); expect_true(x.size() == 0); x["foo"] = 1; expect_true(x.size() == 1); expect_true(cpp11::as_cpp(x["foo"]) == 1); x["bar"] = "hi"; expect_true(x.size() == 2); expect_true(cpp11::strings(x["bar"])[0] == "hi"); x.remove("bar"); expect_true(x.size() == 1); // Object must exist in the environment when we convert to SEXP auto bar_proxy = x["bar"]; expect_error_as(static_cast(bar_proxy), cpp11::unwind_exception); x.remove("foo"); expect_true(x.size() == 0); // Object must exist in the environment when we convert to SEXP auto foo_proxy = x["foo"]; expect_error_as(static_cast(foo_proxy), cpp11::unwind_exception); expect_true(static_cast(x) == x_sxp); UNPROTECT(1); } test_that("environment doesn't leak `R_MissingArg`") { auto new_env = cpp11::package("base")["new.env"]; SEXP x_sxp = PROTECT(new_env()); // Install `R_MissingArg` as a value in the environment Rf_defineVar(Rf_install("missing"), R_MissingArg, x_sxp); cpp11::environment x(x_sxp); expect_true(x.size() == 1); // Upon conversion to SEXP, we error on `R_MissingArg`. // Base R's `R_getVar()` tries hard not to leak this, so we do too. auto proxy = x["missing"]; expect_error_as(static_cast(proxy), cpp11::unwind_exception); UNPROTECT(1); } }