diff --git a/R/tm_a_pca.R b/R/tm_a_pca.R index 8d7ef14e2..f2073ee2c 100644 --- a/R/tm_a_pca.R +++ b/R/tm_a_pca.R @@ -106,14 +106,38 @@ tm_a_pca <- function(label = "Principal Component Analysis", pre_output = NULL, post_output = NULL) { logger::log_info("Initializing tm_a_pca") + + # Normalize the parameters if (inherits(dat, "data_extract_spec")) dat <- list(dat) if (inherits(ggplot2_args, "ggplot2_args")) ggplot2_args <- list(default = ggplot2_args) + # Start of assertions checkmate::assert_string(label) checkmate::assert_list(dat, types = "data_extract_spec") + + checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) + checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") + checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) + checkmate::assert_numeric( + plot_width[1], + lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" + ) + ggtheme <- match.arg(ggtheme) + + plot_choices <- c("Elbow plot", "Circle plot", "Biplot", "Eigenvector plot") + checkmate::assert_list(ggplot2_args, types = "ggplot2_args") + checkmate::assert_subset(names(ggplot2_args), c("default", plot_choices)) + checkmate::assert_flag(rotate_xaxis_labels) + if (length(font_size) == 1) { + checkmate::assert_numeric(font_size, any.missing = FALSE, finite = TRUE, lower = 8, upper = 20) + } else { + checkmate::assert_numeric(font_size, len = 3, any.missing = FALSE, finite = TRUE, lower = 8, upper = 20) + checkmate::assert_numeric(font_size[1], lower = font_size[2], upper = font_size[3], .var.name = "font_size") + } + if (length(alpha) == 1) { checkmate::assert_numeric(alpha, any.missing = FALSE, finite = TRUE, lower = 0, upper = 1) } else { @@ -128,25 +152,11 @@ tm_a_pca <- function(label = "Principal Component Analysis", checkmate::assert_numeric(size[1], lower = size[2], upper = size[3], .var.name = "size") } - if (length(font_size) == 1) { - checkmate::assert_numeric(font_size, any.missing = FALSE, finite = TRUE, lower = 8, upper = 20) - } else { - checkmate::assert_numeric(font_size, len = 3, any.missing = FALSE, finite = TRUE, lower = 8, upper = 20) - checkmate::assert_numeric(font_size[1], lower = font_size[2], upper = font_size[3], .var.name = "font_size") - } - - checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) - checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") - checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) - checkmate::assert_numeric( - plot_width[1], - lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" - ) - - plot_choices <- c("Elbow plot", "Circle plot", "Biplot", "Eigenvector plot") - checkmate::assert_list(ggplot2_args, types = "ggplot2_args") - checkmate::assert_subset(names(ggplot2_args), c("default", plot_choices)) + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + # End of assertions + # Make UI args args <- as.list(environment()) data_extract_list <- list(dat = dat) diff --git a/R/tm_a_regression.R b/R/tm_a_regression.R index 9093d3919..dc06b8ef0 100644 --- a/R/tm_a_regression.R +++ b/R/tm_a_regression.R @@ -162,9 +162,7 @@ tm_a_regression <- function(label = "Regression Analysis", checkmate::assert_list(regressor, types = "data_extract_spec") checkmate::assert_list(response, types = "data_extract_spec") - if (!all(vapply(response, function(x) !(x$select$multiple), logical(1)))) { - stop("'response' should not allow multiple selection") - } + assert_single_selection(response) checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") @@ -203,7 +201,7 @@ tm_a_regression <- function(label = "Regression Analysis", checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) - checkmate::assert_integerish(default_plot_type, lower = 1, upper = 7) + checkmate::assert_choice(default_plot_type, seq.int(1L, length(plot_choices))) checkmate::assert_string(default_outlier_label) if (length(label_segment_threshold) == 1) { @@ -219,7 +217,7 @@ tm_a_regression <- function(label = "Regression Analysis", } # End of assertions - # Send ui args + # Make UI args args <- as.list(environment()) args[["plot_choices"]] <- plot_choices data_extract_list <- list( diff --git a/R/tm_data_table.R b/R/tm_data_table.R index 33a88db34..9116fd34d 100644 --- a/R/tm_data_table.R +++ b/R/tm_data_table.R @@ -91,7 +91,10 @@ tm_data_table <- function(label = "Data Table", pre_output = NULL, post_output = NULL) { logger::log_info("Initializing tm_data_table") + + # Start of assertions checkmate::assert_string(label) + checkmate::assert_list(variables_selected, min.len = 0, types = "character", names = "named") if (length(variables_selected) > 0) { lapply(seq_along(variables_selected), function(i) { @@ -101,14 +104,17 @@ tm_data_table <- function(label = "Data Table", } }) } + checkmate::assert_character(datasets_selected, min.len = 0, min.chars = 1) - checkmate::assert_list(dt_options, names = "named") checkmate::assert( checkmate::check_list(dt_args, len = 0), checkmate::check_subset(names(dt_args), choices = names(formals(DT::datatable))) ) - + checkmate::assert_list(dt_options, names = "named") checkmate::assert_flag(server_rendering) + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + # End of assertions module( label, diff --git a/R/tm_file_viewer.R b/R/tm_file_viewer.R index edcc354d4..48ec04162 100644 --- a/R/tm_file_viewer.R +++ b/R/tm_file_viewer.R @@ -42,25 +42,24 @@ tm_file_viewer <- function(label = "File Viewer Module", input_path = list("Current Working Directory" = ".")) { logger::log_info("Initializing tm_file_viewer") - if (length(label) == 0 || identical(label, "")) { - label <- " " - } - if (length(input_path) == 0 || identical(input_path, "")) { - input_path <- list() - } + # Normalize the parameters + if (length(label) == 0 || identical(label, "")) label <- " " + if (length(input_path) == 0 || identical(input_path, "")) input_path <- list() + + # Start of assertions checkmate::assert_string(label) + checkmate::assert( checkmate::check_list(input_path, types = "character", min.len = 0), checkmate::check_character(input_path, min.len = 1) ) - if (length(input_path) > 0) { valid_url <- function(url_input, timeout = 2) { con <- try(url(url_input), silent = TRUE) check <- suppressWarnings(try(open.connection(con, open = "rt", timeout = timeout), silent = TRUE)[1]) try(close.connection(con), silent = TRUE) - ifelse(is.null(check), TRUE, FALSE) + is.null(check) } idx <- vapply(input_path, function(x) file.exists(x) || valid_url(x), logical(1)) @@ -78,8 +77,9 @@ tm_file_viewer <- function(label = "File Viewer Module", "No file or url paths were provided." ) } + # End of assertions - + # Make UI args args <- as.list(environment()) module( diff --git a/R/tm_front_page.R b/R/tm_front_page.R index 6371a069a..ab251fc1d 100644 --- a/R/tm_front_page.R +++ b/R/tm_front_page.R @@ -67,14 +67,18 @@ tm_front_page <- function(label = "Front page", additional_tags = tagList(), footnotes = character(0), show_metadata = FALSE) { + logger::log_info("Initializing tm_front_page") + + # Start of assertions checkmate::assert_string(label) checkmate::assert_character(header_text, min.len = 0, any.missing = FALSE) checkmate::assert_list(tables, types = "data.frame", names = "named", any.missing = FALSE) checkmate::assert_multi_class(additional_tags, classes = c("shiny.tag.list", "html")) checkmate::assert_character(footnotes, min.len = 0, any.missing = FALSE) checkmate::assert_flag(show_metadata) + # End of assertions - logger::log_info("Initializing tm_front_page") + # Make UI args args <- as.list(environment()) module( diff --git a/R/tm_g_association.R b/R/tm_g_association.R index 6e93f4a24..eb47b00d7 100644 --- a/R/tm_g_association.R +++ b/R/tm_g_association.R @@ -133,17 +133,23 @@ tm_g_association <- function(label = "Association", post_output = NULL, ggplot2_args = teal.widgets::ggplot2_args()) { logger::log_info("Initializing tm_g_association") + + # Normalize the parameters if (inherits(ref, "data_extract_spec")) ref <- list(ref) if (inherits(vars, "data_extract_spec")) vars <- list(vars) if (inherits(ggplot2_args, "ggplot2_args")) ggplot2_args <- list(default = ggplot2_args) + # Start of assertions checkmate::assert_string(label) + checkmate::assert_list(ref, types = "data_extract_spec") if (!all(vapply(ref, function(x) !x$select$multiple, logical(1)))) { stop("'ref' should not allow multiple selection") } + checkmate::assert_list(vars, types = "data_extract_spec") checkmate::assert_flag(show_association) + checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) @@ -151,12 +157,19 @@ tm_g_association <- function(label = "Association", plot_width[1], lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" ) + distribution_theme <- match.arg(distribution_theme) association_theme <- match.arg(association_theme) + + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + plot_choices <- c("Bivariate1", "Bivariate2") checkmate::assert_list(ggplot2_args, types = "ggplot2_args") checkmate::assert_subset(names(ggplot2_args), c("default", plot_choices)) + # End of assertions + # Make UI args args <- as.list(environment()) data_extract_list <- list( diff --git a/R/tm_g_bivariate.R b/R/tm_g_bivariate.R index a879c3e1b..122d2e1b2 100644 --- a/R/tm_g_bivariate.R +++ b/R/tm_g_bivariate.R @@ -194,6 +194,8 @@ tm_g_bivariate <- function(label = "Bivariate Plots", pre_output = NULL, post_output = NULL) { logger::log_info("Initializing tm_g_bivariate") + + # Normalize the parameters if (inherits(x, "data_extract_spec")) x <- list(x) if (inherits(y, "data_extract_spec")) y <- list(y) if (inherits(row_facet, "data_extract_spec")) row_facet <- list(row_facet) @@ -202,52 +204,36 @@ tm_g_bivariate <- function(label = "Bivariate Plots", if (inherits(fill, "data_extract_spec")) fill <- list(fill) if (inherits(size, "data_extract_spec")) size <- list(size) + # Start of assertions + checkmate::assert_string(label) + checkmate::assert_list(x, types = "data_extract_spec") - if (!all(vapply(x, function(x) !x$select$multiple, logical(1)))) { - stop("'x' should not allow multiple selection") - } + assert_single_selection(x) + checkmate::assert_list(y, types = "data_extract_spec") - if (!all(vapply(y, function(x) !x$select$multiple, logical(1)))) { - stop("'y' should not allow multiple selection") - } + assert_single_selection(y) + checkmate::assert_list(row_facet, types = "data_extract_spec", null.ok = TRUE) - if (!all(vapply(row_facet, function(x) !x$select$multiple, logical(1)))) { - stop("'row_facet' should not allow multiple selection") - } + assert_single_selection(row_facet) + checkmate::assert_list(col_facet, types = "data_extract_spec", null.ok = TRUE) - if (!all(vapply(col_facet, function(x) !x$select$multiple, logical(1)))) { - stop("'col_facet' should not allow multiple selection") - } + assert_single_selection(col_facet) + + checkmate::assert_flag(facet) + checkmate::assert_list(color, types = "data_extract_spec", null.ok = TRUE) - if (!all(vapply(color, function(x) !x$select$multiple, logical(1)))) { - stop("'color' should not allow multiple selection") - } + assert_single_selection(color) + checkmate::assert_list(fill, types = "data_extract_spec", null.ok = TRUE) - if (!all(vapply(fill, function(x) !x$select$multiple, logical(1)))) { - stop("'fill' should not allow multiple selection") - } + assert_single_selection(fill) + checkmate::assert_list(size, types = "data_extract_spec", null.ok = TRUE) - if (!all(vapply(size, function(x) !x$select$multiple, logical(1)))) { - stop("'size' should not allow multiple selection") - } + assert_single_selection(size) - ggtheme <- match.arg(ggtheme) - checkmate::assert_string(label) checkmate::assert_flag(use_density) - checkmate::assert_flag(color_settings) - checkmate::assert_flag(free_x_scales) - checkmate::assert_flag(free_y_scales) - checkmate::assert_flag(rotate_xaxis_labels) - checkmate::assert_flag(swap_axes) - checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) - checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") - checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) - checkmate::assert_numeric( - plot_width[1], - lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" - ) - checkmate::assert_class(ggplot2_args, "ggplot2_args") + # Determines color, fill & size if they are not explicitly set + checkmate::assert_flag(color_settings) if (color_settings) { if (is.null(color)) { color <- x @@ -267,6 +253,28 @@ tm_g_bivariate <- function(label = "Bivariate Plots", } } + checkmate::assert_flag(free_x_scales) + checkmate::assert_flag(free_y_scales) + + checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) + checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") + checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) + checkmate::assert_numeric( + plot_width[1], + lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" + ) + + checkmate::assert_flag(rotate_xaxis_labels) + checkmate::assert_flag(swap_axes) + + ggtheme <- match.arg(ggtheme) + checkmate::assert_class(ggplot2_args, "ggplot2_args") + + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + # End of assertions + + # Make UI args args <- as.list(environment()) data_extract_list <- list( diff --git a/R/tm_g_distribution.R b/R/tm_g_distribution.R index edac703e8..66d524784 100644 --- a/R/tm_g_distribution.R +++ b/R/tm_g_distribution.R @@ -121,6 +121,7 @@ tm_g_distribution <- function(label = "Distribution Module", post_output = NULL) { logger::log_info("Initializing tm_g_distribution") + # Requires Suggested packages extra_packages <- c("ggpmisc", "ggpp", "goftest", "MASS", "broom") missing_packages <- Filter(function(x) !requireNamespace(x, quietly = TRUE), extra_packages) if (length(missing_packages) > 0L) { @@ -130,28 +131,47 @@ tm_g_distribution <- function(label = "Distribution Module", )) } + # Normalize the parameters if (inherits(dist_var, "data_extract_spec")) dist_var <- list(dist_var) if (inherits(strata_var, "data_extract_spec")) strata_var <- list(strata_var) if (inherits(group_var, "data_extract_spec")) group_var <- list(group_var) if (inherits(ggplot2_args, "ggplot2_args")) ggplot2_args <- list(default = ggplot2_args) - ggtheme <- match.arg(ggtheme) - if (length(bins) == 1) { - checkmate::assert_numeric(bins, any.missing = FALSE, lower = 1) - } else { - checkmate::assert_numeric(bins, len = 3, any.missing = FALSE, lower = 1) - checkmate::assert_numeric(bins[1], lower = bins[2], upper = bins[3], .var.name = "bins") - } + # Start of assertions checkmate::assert_string(label) + checkmate::assert_list(dist_var, "data_extract_spec") - checkmate::assert_false(dist_var[[1]]$select$multiple) + checkmate::assert_false(dist_var[[1L]]$select$multiple) + checkmate::assert_list(strata_var, types = "data_extract_spec", null.ok = TRUE) checkmate::assert_list(group_var, types = "data_extract_spec", null.ok = TRUE) checkmate::assert_flag(freq) + ggtheme <- match.arg(ggtheme) + plot_choices <- c("Histogram", "QQplot") checkmate::assert_list(ggplot2_args, types = "ggplot2_args") checkmate::assert_subset(names(ggplot2_args), c("default", plot_choices)) + if (length(bins) == 1) { + checkmate::assert_numeric(bins, any.missing = FALSE, lower = 1) + } else { + checkmate::assert_numeric(bins, len = 3, any.missing = FALSE, lower = 1) + checkmate::assert_numeric(bins[1], lower = bins[2], upper = bins[3], .var.name = "bins") + } + + checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) + checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") + checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) + checkmate::assert_numeric( + plot_width[1], + lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" + ) + + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + # End of assertions + + # Make UI args args <- as.list(environment()) data_extract_list <- list( diff --git a/R/tm_g_response.R b/R/tm_g_response.R index 3abba6266..12beb4f94 100644 --- a/R/tm_g_response.R +++ b/R/tm_g_response.R @@ -152,32 +152,35 @@ tm_g_response <- function(label = "Response Plot", pre_output = NULL, post_output = NULL) { logger::log_info("Initializing tm_g_response") + + # Normalize the parameters if (inherits(response, "data_extract_spec")) response <- list(response) if (inherits(x, "data_extract_spec")) x <- list(x) if (inherits(row_facet, "data_extract_spec")) row_facet <- list(row_facet) if (inherits(col_facet, "data_extract_spec")) col_facet <- list(col_facet) + + # Start of assertions checkmate::assert_string(label) - ggtheme <- match.arg(ggtheme) + checkmate::assert_list(response, types = "data_extract_spec") if (!all(vapply(response, function(x) !("" %in% x$select$choices), logical(1)))) { stop("'response' should not allow empty values") } - if (!all(vapply(response, function(x) !x$select$multiple, logical(1)))) { - stop("'response' should not allow multiple selection") - } + assert_single_selection(response) + checkmate::assert_list(x, types = "data_extract_spec") if (!all(vapply(x, function(x) !("" %in% x$select$choices), logical(1)))) { stop("'x' should not allow empty values") } - if (!all(vapply(x, function(x) !x$select$multiple, logical(1)))) { - stop("'x' should not allow multiple selection") - } + assert_single_selection(x) + checkmate::assert_list(row_facet, types = "data_extract_spec", null.ok = TRUE) checkmate::assert_list(col_facet, types = "data_extract_spec", null.ok = TRUE) checkmate::assert_flag(coord_flip) checkmate::assert_flag(count_labels) checkmate::assert_flag(rotate_xaxis_labels) checkmate::assert_flag(freq) + checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) @@ -186,8 +189,14 @@ tm_g_response <- function(label = "Response Plot", lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" ) + ggtheme <- match.arg(ggtheme) checkmate::assert_class(ggplot2_args, "ggplot2_args") + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + # End of assertions + + # Make UI args args <- as.list(environment()) data_extract_list <- list( diff --git a/R/tm_g_scatterplot.R b/R/tm_g_scatterplot.R index 00efed7cf..d90f6c43a 100644 --- a/R/tm_g_scatterplot.R +++ b/R/tm_g_scatterplot.R @@ -229,6 +229,7 @@ tm_g_scatterplot <- function(label = "Scatterplot", ggplot2_args = teal.widgets::ggplot2_args()) { logger::log_info("Initializing tm_g_scatterplot") + # Requires Suggested packages extra_packages <- c("ggpmisc", "ggExtra", "colourpicker") missing_packages <- Filter(function(x) !requireNamespace(x, quietly = TRUE), extra_packages) if (length(missing_packages) > 0L) { @@ -238,6 +239,7 @@ tm_g_scatterplot <- function(label = "Scatterplot", )) } + # Normalize the parameters if (inherits(x, "data_extract_spec")) x <- list(x) if (inherits(y, "data_extract_spec")) y <- list(y) if (inherits(color_by, "data_extract_spec")) color_by <- list(color_by) @@ -246,26 +248,27 @@ tm_g_scatterplot <- function(label = "Scatterplot", if (inherits(col_facet, "data_extract_spec")) col_facet <- list(col_facet) if (is.double(max_deg)) max_deg <- as.integer(max_deg) - ggtheme <- match.arg(ggtheme) + # Start of assertions checkmate::assert_string(label) checkmate::assert_list(x, types = "data_extract_spec") checkmate::assert_list(y, types = "data_extract_spec") checkmate::assert_list(color_by, types = "data_extract_spec", null.ok = TRUE) checkmate::assert_list(size_by, types = "data_extract_spec", null.ok = TRUE) + checkmate::assert_list(row_facet, types = "data_extract_spec", null.ok = TRUE) + assert_single_selection(row_facet) + checkmate::assert_list(col_facet, types = "data_extract_spec", null.ok = TRUE) - checkmate::assert_list(row_facet, types = "data_extract_spec", null.ok = TRUE) - if (!all(vapply(row_facet, function(x) !x$select$multiple, logical(1)))) { - stop("'row_facet' should not allow multiple selection") - } - if (!all(vapply(col_facet, function(x) !x$select$multiple, logical(1)))) { - stop("'col_facet' should not allow multiple selection") - } - checkmate::assert_character(shape) + assert_single_selection(col_facet) + + checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) + checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") + checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) + checkmate::assert_numeric( + plot_width[1], + lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" + ) - checkmate::assert_int(max_deg, lower = 1L) - checkmate::assert_scalar(table_dec) - checkmate::assert_flag(rotate_xaxis_labels) if (length(alpha) == 1) { checkmate::assert_numeric(alpha, any.missing = FALSE, finite = TRUE) } else { @@ -273,6 +276,8 @@ tm_g_scatterplot <- function(label = "Scatterplot", checkmate::assert_numeric(alpha[1], lower = alpha[2], upper = alpha[3], .var.name = "alpha") } + checkmate::assert_character(shape) + if (length(size) == 1) { checkmate::assert_numeric(size, any.missing = FALSE, finite = TRUE) } else { @@ -280,16 +285,18 @@ tm_g_scatterplot <- function(label = "Scatterplot", checkmate::assert_numeric(size[1], lower = size[2], upper = size[3], .var.name = "size") } - checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) - checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") - checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) - checkmate::assert_numeric( - plot_width[1], - lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" - ) + checkmate::assert_int(max_deg, lower = 1L) + checkmate::assert_flag(rotate_xaxis_labels) + ggtheme <- match.arg(ggtheme) + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + + checkmate::assert_scalar(table_dec) checkmate::assert_class(ggplot2_args, "ggplot2_args") + # End of assertions + # Make UI args args <- as.list(environment()) data_extract_list <- list( diff --git a/R/tm_g_scatterplotmatrix.R b/R/tm_g_scatterplotmatrix.R index 68115ddff..a9af072ac 100644 --- a/R/tm_g_scatterplotmatrix.R +++ b/R/tm_g_scatterplotmatrix.R @@ -163,13 +163,19 @@ tm_g_scatterplotmatrix <- function(label = "Scatterplot Matrix", pre_output = NULL, post_output = NULL) { logger::log_info("Initializing tm_g_scatterplotmatrix") + + # Requires Suggested packages if (!requireNamespace("lattice", quietly = TRUE)) { stop("Cannot load lattice - please install the package or restart your session.") } + + # Normalize the parameters if (inherits(variables, "data_extract_spec")) variables <- list(variables) + # Start of assertions checkmate::assert_string(label) checkmate::assert_list(variables, types = "data_extract_spec") + checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) @@ -178,7 +184,13 @@ tm_g_scatterplotmatrix <- function(label = "Scatterplot Matrix", lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" ) + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + # End of assertions + + # Make UI args args <- as.list(environment()) + module( label = label, server = srv_g_scatterplotmatrix, diff --git a/R/tm_missing_data.R b/R/tm_missing_data.R index 9af5189f5..a0c60829e 100644 --- a/R/tm_missing_data.R +++ b/R/tm_missing_data.R @@ -89,17 +89,22 @@ tm_missing_data <- function(label = "Missing data", ), pre_output = NULL, post_output = NULL) { + logger::log_info("Initializing tm_missing_data") + + # Requires Suggested packages if (!requireNamespace("gridExtra", quietly = TRUE)) { stop("Cannot load gridExtra - please install the package or restart your session.") } if (!requireNamespace("rlang", quietly = TRUE)) { stop("Cannot load rlang - please install the package or restart your session.") } - logger::log_info("Initializing tm_missing_data") + + # Normalize the parameters if (inherits(ggplot2_args, "ggplot2_args")) ggplot2_args <- list(default = ggplot2_args) + # Start of assertions checkmate::assert_string(label) - checkmate::assert_character(parent_dataname, min.len = 0, max.len = 1) + checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) @@ -107,11 +112,18 @@ tm_missing_data <- function(label = "Missing data", plot_width[1], lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" ) + + checkmate::assert_character(parent_dataname, min.len = 0, max.len = 1) ggtheme <- match.arg(ggtheme) + plot_choices <- c("Summary Obs", "Summary Patients", "Combinations Main", "Combinations Hist", "By Subject") checkmate::assert_list(ggplot2_args, types = "ggplot2_args") checkmate::assert_subset(names(ggplot2_args), c("default", plot_choices)) + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + # End of assertions + module( label, server = srv_page_missing_data, diff --git a/R/tm_outliers.R b/R/tm_outliers.R index b09b680ed..52031ce98 100644 --- a/R/tm_outliers.R +++ b/R/tm_outliers.R @@ -132,13 +132,16 @@ tm_outliers <- function(label = "Outliers Module", pre_output = NULL, post_output = NULL) { logger::log_info("Initializing tm_outliers") + + # Normalize the parameters if (inherits(outlier_var, "data_extract_spec")) outlier_var <- list(outlier_var) if (inherits(categorical_var, "data_extract_spec")) categorical_var <- list(categorical_var) if (inherits(ggplot2_args, "ggplot2_args")) ggplot2_args <- list(default = ggplot2_args) - ggtheme <- match.arg(ggtheme) + # Start of assertions checkmate::assert_string(label) checkmate::assert_list(outlier_var, types = "data_extract_spec") + checkmate::assert_list(categorical_var, types = "data_extract_spec", null.ok = TRUE) if (is.list(categorical_var)) { lapply(categorical_var, function(x) { @@ -147,10 +150,26 @@ tm_outliers <- function(label = "Outliers Module", } }) } + + ggtheme <- match.arg(ggtheme) + plot_choices <- c("Boxplot", "Density Plot", "Cumulative Distribution Plot") checkmate::assert_list(ggplot2_args, types = "ggplot2_args") checkmate::assert_subset(names(ggplot2_args), c("default", plot_choices)) + checkmate::assert_numeric(plot_height, len = 3, any.missing = FALSE, finite = TRUE) + checkmate::assert_numeric(plot_height[1], lower = plot_height[2], upper = plot_height[3], .var.name = "plot_height") + checkmate::assert_numeric(plot_width, len = 3, any.missing = FALSE, null.ok = TRUE, finite = TRUE) + checkmate::assert_numeric( + plot_width[1], + lower = plot_width[2], upper = plot_width[3], null.ok = TRUE, .var.name = "plot_width" + ) + + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + # End of assertions + + # Make UI args args <- as.list(environment()) data_extract_list <- list( diff --git a/R/tm_t_crosstable.R b/R/tm_t_crosstable.R index 102c93176..ccd442129 100644 --- a/R/tm_t_crosstable.R +++ b/R/tm_t_crosstable.R @@ -139,22 +139,31 @@ tm_t_crosstable <- function(label = "Cross Table", post_output = NULL, basic_table_args = teal.widgets::basic_table_args()) { logger::log_info("Initializing tm_t_crosstable") + + # Requires Suggested packages if (!requireNamespace("rtables", quietly = TRUE)) { stop("Cannot load rtables - please install the package or restart your session.") } + + # Normalize the parameters if (inherits(x, "data_extract_spec")) x <- list(x) if (inherits(y, "data_extract_spec")) y <- list(y) + # Start of assertions checkmate::assert_string(label) checkmate::assert_list(x, types = "data_extract_spec") + checkmate::assert_list(y, types = "data_extract_spec") - if (any(vapply(y, function(x) x$select$multiple, logical(1)))) { - stop("'y' should not allow multiple selection") - } + assert_single_selection(y) + checkmate::assert_flag(show_percentage) checkmate::assert_flag(show_total) + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) checkmate::assert_class(basic_table_args, classes = "basic_table_args") + # End of assertions + # Make UI args ui_args <- as.list(environment()) server_args <- list( diff --git a/R/tm_variable_browser.R b/R/tm_variable_browser.R index c90b029c5..6d602bcdb 100644 --- a/R/tm_variable_browser.R +++ b/R/tm_variable_browser.R @@ -77,6 +77,8 @@ tm_variable_browser <- function(label = "Variable Browser", post_output = NULL, ggplot2_args = teal.widgets::ggplot2_args()) { logger::log_info("Initializing tm_variable_browser") + + # Requires Suggested packages if (!requireNamespace("sparkline", quietly = TRUE)) { stop("Cannot load sparkline - please install the package or restart your session.") } @@ -86,10 +88,16 @@ tm_variable_browser <- function(label = "Variable Browser", if (!requireNamespace("jsonlite", quietly = TRUE)) { stop("Cannot load jsonlite - please install the package or restart your session.") } + + # Start of assertions checkmate::assert_string(label) checkmate::assert_character(datasets_selected) checkmate::assert_character(parent_dataname, min.len = 0, max.len = 1) + checkmate::assert_multi_class(pre_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) + checkmate::assert_multi_class(post_output, c("shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE) checkmate::assert_class(ggplot2_args, "ggplot2_args") + # End of assertions + datasets_selected <- unique(datasets_selected) module( diff --git a/R/utils.R b/R/utils.R index 71f822ff4..d4b155cf3 100644 --- a/R/utils.R +++ b/R/utils.R @@ -266,3 +266,15 @@ is_tab_active_js <- function(id, name) { id, name ) } + +#' Assert single selection on `data_extract_spec` object +#' Helper to reduce code in assertions +#' @noRd +#' +assert_single_selection <- function(x, + .var.name = checkmate::vname(x)) { # nolint: object_name. + if (any(vapply(x, function(.x) .x$select$multiple, logical(1)))) { + stop("'", .var.name, "' should not allow multiple selection") + } + invisible(TRUE) +} diff --git a/tests/testthat/helper-functions.R b/tests/testthat/helper-functions.R new file mode 100644 index 000000000..8ae39cb2a --- /dev/null +++ b/tests/testthat/helper-functions.R @@ -0,0 +1,22 @@ +local_logger_threshold <- function(threshold, envir = parent.frame()) { + old <- logger::log_threshold(namespace = "teal.modules.general") + + # Equivalent to withr::defer + thunk <- as.call(list(function() logger::log_threshold(old, namespace = "teal.modules.general"))) + do.call(base::on.exit, list(thunk, TRUE, FALSE), envir = envir) + logger::log_threshold(threshold, namespace = "teal.modules.general") + invisible(old) +} + +# Create a mock data extact spec for tests +mock_data_extract_spec <- function(dataname = "MOCK_DATASET", + select_choices = sample(LETTERS, sample(2:10, 1)), + select_multiple = FALSE) { + teal.transform::data_extract_spec( + dataname = dataname, + select = teal.transform::select_spec( + choices = select_choices, + multiple = select_multiple + ) + ) +} diff --git a/tests/testthat/test-tm_g_bivariate.R b/tests/testthat/test-tm_g_bivariate.R new file mode 100644 index 000000000..1d97a37fc --- /dev/null +++ b/tests/testthat/test-tm_g_bivariate.R @@ -0,0 +1,287 @@ +testthat::test_that("tm_g_bivariate creates a `teal_module` object", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_s3_class( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE), + row_facet = mock_data_extract_spec(select_multiple = FALSE), + col_facet = mock_data_extract_spec(select_multiple = FALSE), + facet = TRUE, + color_setting = TRUE, + use_density = TRUE, + free_x_scales = TRUE, + free_y_scales = TRUE, + plot_height = c(400, 100, 600), + plot_width = c(600, 100, 600), + rotate_xaxis_labels = TRUE, + swap_axes = TRUE + ), + "teal_module" + ) +}) + +testthat::test_that("tm_g_bivariate creates a `teal_module` object with default options", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_s3_class( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE) + ), + "teal_module" + ) +}) + +testthat::test_that("tm_g_bivariate creates a `teal_module` object with multiple data extract specs", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_s3_class( + tm_g_bivariate( + "a label", + list(mock_data_extract_spec(select_multiple = FALSE), mock_data_extract_spec(select_multiple = FALSE)), + list(mock_data_extract_spec(select_multiple = FALSE), mock_data_extract_spec(select_multiple = FALSE)), + plot_height = c(400, 100, 600), + plot_width = c(600, 100, 600) + ), + "teal_module" + ) +}) + +testthat::test_that("tm_g_bivariate creates a module with datanames taken from data extracts", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + mod <- tm_g_bivariate( + "a label", + list( + mock_data_extract_spec(dataname = "A", select_multiple = FALSE), + mock_data_extract_spec(dataname = "B", select_multiple = FALSE) + ), + mock_data_extract_spec(dataname = "C", select_multiple = FALSE) + ) + + expect_setequal( + mod$datanames, + c("A", "B", "C") + ) +}) + +# Test `x` and `y` arguments with invalid data_extract_spec + +testthat::test_that("tm_g_bivariate fails when `x` contains a spec with multiple selection", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + list( + mock_data_extract_spec(select_multiple = TRUE) + ), + list() + ), + "'x' should not allow multiple selection" + ) +}) + +testthat::test_that("tm_g_bivariate fails when `x` contains multiple spec with (at least one ) multiple selection", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + list( + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = TRUE) + ), + list(mock_data_extract_spec(select_multiple = FALSE)) + ), + "'x' should not allow multiple selection" + ) +}) + +testthat::test_that("tm_g_bivariate fails when `x` contains multiple spec with (at least one ) multiple selection", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + list( + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = TRUE) + ) + ), + "'y' should not allow multiple selection" + ) +}) + +testthat::test_that("tm_g_bivariate fails when `y` contains multiple spec with (at least one ) multiple selection", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + list( + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = TRUE) + ) + ), + "'y' should not allow multiple selection" + ) +}) + +# Test `plot_height` and `plot_width` arguments + +testthat::test_that("tm_g_bivariate fails when `plot_height` is not valid", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE), + plot_height = c(100, 10, 20) + ), + "Assertion on 'plot_height' failed: Element 1 is not <= 20" + ) +}) + +testthat::test_that("tm_g_bivariate fails when `plot_height` is not valid", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE), + plot_height = c(1, 10, 20) + ), + "Assertion on 'plot_height' failed: Element 1 is not >= 10" + ) +}) + +testthat::test_that("tm_g_bivariate fails when `plot_height` is not valid", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE), + plot_height = 100 + ), + "Assertion on 'plot_height' failed: Must have length 3, but has length 1" + ) +}) + +testthat::test_that("tm_g_bivariate fails when `plot_width` is not valid", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE), + plot_width = c(100, 10, 20) + ), + "Assertion on 'plot_width' failed: Element 1 is not <= 20" + ) +}) + +testthat::test_that("tm_g_bivariate fails when `plot_width` is not valid", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE), + plot_width = c(1, 10, 20) + ), + "Assertion on 'plot_width' failed: Element 1 is not >= 10" + ) +}) + +testthat::test_that("tm_g_bivariate fails when `plot_width` is not valid", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE), + plot_width = 100 + ), + "Assertion on 'plot_width' failed: Must have length 3, but has length 1" + ) +}) + +# Test `color_settings` argument + +testthat::test_that("tm_g_bivariate fails when `color_setting` is FALSE and `color` is supplied", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE), + color_setting = FALSE, + color = mock_data_extract_spec() + ), + "'color_settings' argument needs to be set to TRUE if 'color', 'fill', and/or 'size' is/are supplied." + ) +}) + +testthat::test_that("tm_g_bivariate fails when `color_setting` is FALSE and `size` is supplied", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE), + color_setting = FALSE, + size = mock_data_extract_spec() + ), + "'color_settings' argument needs to be set to TRUE if 'color', 'fill', and/or 'size' is/are supplied." + ) +}) + +testthat::test_that("tm_g_bivariate fails when `color_setting` is FALSE and `fill` is supplied", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + testthat::expect_error( + tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE), + color_setting = FALSE, + fill = mock_data_extract_spec() + ), + "'color_settings' argument needs to be set to TRUE if 'color', 'fill', and/or 'size' is/are supplied." + ) +}) + +testthat::test_that("tm_g_bivariate determines `color`, `size` and `fill` when `color_setting` is TRUE", { + local_logger_threshold(logger::FATAL) # Suppress logger messages + + mod <- tm_g_bivariate( + "a label", + mock_data_extract_spec(select_multiple = FALSE), + mock_data_extract_spec(select_multiple = FALSE), + color_setting = TRUE + ) + + testthat::expect_contains( + vapply( + unlist(mod$ui_args[c("color", "size", "fill")], recursive = FALSE), + class, + character(1) + ), + "data_extract_spec" + ) +})