From 04d9f4a8034d614a594654da20fa1c2e14df0b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Fri, 25 Oct 2024 16:59:35 +0100 Subject: [PATCH 1/3] fix: skip tests if mirai/renv are not installed --- tests/testthat/test-module_teal.R | 4 ++++ tests/testthat/test-utils.R | 1 + 2 files changed, 5 insertions(+) diff --git a/tests/testthat/test-module_teal.R b/tests/testthat/test-module_teal.R index b8878e5661..c70a4b6b92 100644 --- a/tests/testthat/test-module_teal.R +++ b/tests/testthat/test-module_teal.R @@ -70,6 +70,8 @@ testthat::describe("srv_teal lockfile", { "creation process is invoked for teal.lockfile.mode = \"enabled\" ", "and snapshot is copied to teal_app.lock and removed after session ended" ), { + testthat::skip_if_not_installed("mirai") + testthat::skip_if_not_installed("renv") withr::with_options( list(teal.lockfile.mode = "enabled"), { @@ -95,6 +97,8 @@ testthat::describe("srv_teal lockfile", { ) }) testthat::it("creation process is not invoked for teal.lockfile.mode = \"disabled\"", { + testthat::skip_if_not_installed("mirai") + testthat::skip_if_not_installed("renv") withr::with_options( list(teal.lockfile.mode = "disabled"), { diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 4904c46461..41c06581b6 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -1,4 +1,5 @@ testthat::test_that("get_teal_bs_theme", { + testthat::skip_if_not_installed("bslib") testthat::expect_true(is.null(get_teal_bs_theme())) withr::with_options(list("teal.bs_theme" = bslib::bs_theme(version = "5")), { testthat::expect_s3_class(get_teal_bs_theme(), "bs_theme") From b06054dafa50803fa921cadbfa17384ad135e4e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:02:25 +0100 Subject: [PATCH 2/3] fix: Prevents rlang::hash to use environment of objects --- R/module_init_data.R | 13 +++- tests/testthat/test-module_teal.R | 119 +++++++++++++++++++++--------- 2 files changed, 94 insertions(+), 38 deletions(-) diff --git a/R/module_init_data.R b/R/module_init_data.R index 8c09936a75..f2a39ce6e0 100644 --- a/R/module_init_data.R +++ b/R/module_init_data.R @@ -126,11 +126,18 @@ srv_init_data <- function(id, data) { vapply( datanames, function(dataname, datasets) { - hash <- rlang::hash(data[[dataname]]) + x <- data[[dataname]] + + code <- if (is.function(x) && !is.primitive(x)) { + x <- deparse1(x) + bquote(rlang::hash(deparse1(.(as.name(dataname))))) + } else { + bquote(rlang::hash(.(as.name(dataname)))) + } sprintf( "stopifnot(%s == %s) # @linksto %s", - deparse1(bquote(rlang::hash(.(as.name(dataname))))), - deparse1(hash), + deparse1(code), + deparse1(rlang::hash(x)), dataname ) }, diff --git a/tests/testthat/test-module_teal.R b/tests/testthat/test-module_teal.R index c70a4b6b92..254bfa8b29 100644 --- a/tests/testthat/test-module_teal.R +++ b/tests/testthat/test-module_teal.R @@ -2284,44 +2284,93 @@ testthat::describe("Datanames with special symbols", { }) testthat::it("(when used as non-native pipe) are present in datanames in the pre-processing code", { - testthat::expect_warning( - shiny::testServer( - app = srv_teal, - args = list( - id = "test", - data = within( - teal.data::teal_data(), - { - iris <- iris - mtcars <- mtcars - `%cbind%` <- function(lhs, rhs) cbind(lhs, rhs) - iris <- iris %cbind% data.frame("new_column") - } - ), - modules = modules( - module("module_1", server = function(id, data) data, , datanames = c("iris")) - ), - filter = teal_slices( - module_specific = TRUE - ) + shiny::testServer( + app = srv_teal, + args = list( + id = "test", + data = within( + teal.data::teal_data(), + { + iris <- iris + mtcars <- mtcars + `%cbind%` <- function(lhs, rhs) cbind(lhs, rhs) + iris <- iris %cbind% data.frame("new_column") + } ), - expr = { - session$setInputs("teal_modules-active_tab" = "module_1") - session$flushReact() + modules = modules( + module("module_1", server = function(id, data) data, , datanames = c("iris")) + ), + filter = teal_slices( + module_specific = TRUE + ) + ), + expr = { + session$setInputs("teal_modules-active_tab" = "module_1") + session$flushReact() - testthat::expect_contains( - strsplit( - x = teal.code::get_code(modules_output$module_1()()), - split = "\n" - )[[1]], - c( - "`%cbind%` <- function(lhs, rhs) cbind(lhs, rhs)", - ".raw_data <- list2env(list(iris = iris))" - ) + testthat::expect_contains( + strsplit( + x = teal.code::get_code(modules_output$module_1()()), + split = "\n" + )[[1]], + c( + "`%cbind%` <- function(lhs, rhs) cbind(lhs, rhs)", + ".raw_data <- list2env(list(iris = iris))" ) - } - ), - "'package:teal' may not be available when loading" + ) + } ) }) }) + +testthat::test_that("Show R Code is reproducible with a function defined in teal_data", { + shiny::testServer( + app = srv_teal, + args = list( + id = "test", + data = reactive(within(teal.data::teal_data(), { + fun <- function(x) { + y <- x + 1 + y + 3 + } + })), + modules = modules(module("module_1", server = function(id, data) data)) + ), , + expr = { + session$setInputs("teal_modules-active_tab" = "module_1") + session$flushReact() + + # Need to evaluate characters to preserve indentation + fun_env <- new.env(parent = .GlobalEnv) + eval( + parse( + text = paste( + sep = "\n", + "fun <- function(x) {", + " y <- x + 1", + " y + 3", + "}" + ) + ), + envir = fun_env + ) + local(hash <- rlang::hash(deparse1(fun_env$fun)), envir = fun_env) + + testthat::expect_setequal( + trimws(strsplit( + x = teal.code::get_code(modules_output$module_1()()), + split = "\n" + )[[1]]), + c( + "fun <- function(x) {", + "y <- x + 1", + "y + 3", + "}", + sprintf("stopifnot(rlang::hash(deparse1(fun)) == \"%s\")", fun_env$hash), + ".raw_data <- list2env(list(fun = fun))", + "lockEnvironment(.raw_data)" + ) + ) + } + ) +}) From 1078e02b220621973092835a1381f7d16f077e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Mon, 28 Oct 2024 10:47:36 +0000 Subject: [PATCH 3/3] fix: adds one more test that executes the code inside teal data --- tests/testthat/test-module_teal.R | 128 +++++++++++++++++++----------- 1 file changed, 81 insertions(+), 47 deletions(-) diff --git a/tests/testthat/test-module_teal.R b/tests/testthat/test-module_teal.R index 254bfa8b29..ed01caaef4 100644 --- a/tests/testthat/test-module_teal.R +++ b/tests/testthat/test-module_teal.R @@ -2323,54 +2323,88 @@ testthat::describe("Datanames with special symbols", { }) }) -testthat::test_that("Show R Code is reproducible with a function defined in teal_data", { - shiny::testServer( - app = srv_teal, - args = list( - id = "test", - data = reactive(within(teal.data::teal_data(), { - fun <- function(x) { - y <- x + 1 - y + 3 - } - })), - modules = modules(module("module_1", server = function(id, data) data)) - ), , - expr = { - session$setInputs("teal_modules-active_tab" = "module_1") - session$flushReact() - - # Need to evaluate characters to preserve indentation - fun_env <- new.env(parent = .GlobalEnv) - eval( - parse( - text = paste( - sep = "\n", +testthat::describe("teal.data code with a function defined", { + testthat::it("is fully reproducible", { + shiny::testServer( + app = srv_teal, + args = list( + id = "test", + data = reactive(within(teal.data::teal_data(), { + fun <- function(x) { + y <- x + 1 + y + 3 + } + })), + modules = modules(module("module_1", server = function(id, data) data)) + ), , + expr = { + session$setInputs("teal_modules-active_tab" = "module_1") + session$flushReact() + + # Need to evaluate characters to preserve indentation + local_env <- new.env(parent = .GlobalEnv) + dat <- modules_output$module_1()() + + eval( + parse(text = teal.code::get_code(dat)), + envir = local_env + ) + + testthat::expect_identical(local_env$fun(1), 5) + testthat::expect_identical(local_env$fun(1), dat[["fun"]](1)) + } + ) + }) + + testthat::it("has the correct code (with hash)", { + shiny::testServer( + app = srv_teal, + args = list( + id = "test", + data = reactive(within(teal.data::teal_data(), { + fun <- function(x) { + y <- x + 1 + y + 3 + } + })), + modules = modules(module("module_1", server = function(id, data) data)) + ), , + expr = { + session$setInputs("teal_modules-active_tab" = "module_1") + session$flushReact() + + # Need to evaluate characters to preserve indentation + local_env <- new.env(parent = .GlobalEnv) + eval( + parse( + text = paste( + sep = "\n", + "fun <- function(x) {", + " y <- x + 1", + " y + 3", + "}" + ) + ), + envir = local_env + ) + local(hash <- rlang::hash(deparse1(fun)), envir = local_env) + + testthat::expect_setequal( + trimws(strsplit( + x = teal.code::get_code(modules_output$module_1()()), + split = "\n" + )[[1]]), + c( "fun <- function(x) {", - " y <- x + 1", - " y + 3", - "}" + "y <- x + 1", + "y + 3", + "}", + sprintf("stopifnot(rlang::hash(deparse1(fun)) == \"%s\")", local_env$hash), + ".raw_data <- list2env(list(fun = fun))", + "lockEnvironment(.raw_data)" ) - ), - envir = fun_env - ) - local(hash <- rlang::hash(deparse1(fun_env$fun)), envir = fun_env) - - testthat::expect_setequal( - trimws(strsplit( - x = teal.code::get_code(modules_output$module_1()()), - split = "\n" - )[[1]]), - c( - "fun <- function(x) {", - "y <- x + 1", - "y + 3", - "}", - sprintf("stopifnot(rlang::hash(deparse1(fun)) == \"%s\")", fun_env$hash), - ".raw_data <- list2env(list(fun = fun))", - "lockEnvironment(.raw_data)" ) - ) - } - ) + } + ) + }) })