diff --git a/R/to_integer.R b/R/to_integer.R index 44bb9fb6..fc20180b 100644 --- a/R/to_integer.R +++ b/R/to_integer.R @@ -16,10 +16,38 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -#' Rounds sample size to an even number for equal design +#' Round sample size and events #' #' @param x An object returned by fixed_design_xxx() and gs_design_xxx(). #' @param ... Additional parameters (not used). +#' @details +#' For the sample size of the fixed design: +#' - When `ratio` is a positive integer, the sample size is rounded up to a multiple of `ratio + 1` +#' if `round_up_final = TRUE`, and just rounded to a multiple of `ratio + 1` if `round_up_final = FALSE`. +#' - When `ratio` is a positive non-integer, the sample size is rounded up if `round_up_final = TRUE`, +#' (may not be a multiple of `ratio + 1`), and just rounded if `round_up_final = FALSE` (may not be a multiple of `ratio + 1`). +#' Note the default `ratio` is taken from `x$input$ratio`. +#' +#' For the number of events of the fixed design: +#' - If the continuous event is very close to an integer within 0.01 differences, say 100.001 or 99.999, then the integer events is 100. +#' - Otherwise, round up if `round_up_final = TRUE` and round if `round_up_final = FALSE`. +#' +#' For the sample size of group sequential designs: +#' - When `ratio` is a positive integer, the final sample size is rounded to a multiple of `ratio + 1`. +#' + For 1:1 randomization (experimental:control), set `ratio = 1` to round to an even sample size. +#' + For 2:1 randomization, set `ratio = 2` to round to a multiple of 3. +#' + For 3:2 randomization, set `ratio = 4` to round to a multiple of 5. +#' + Note that for the final analysis, the sample size is rounded up to the nearest multiple of `ratio + 1` if `round_up_final = TRUE`. +#' If `round_up_final = FALSE`, the final sample size is rounded to the nearest multiple of `ratio + 1`. +#' - When `ratio` is positive non-integer, the final sample size MAY NOT be rounded to a multiple of `ratio + 1`. +#' + The final sample size is rounded up if `round_up_final = TRUE`. +#' + Otherwise, it is just rounded. +#' +#' For the events of group sequential designs: +#' - For events at interim analysis, it is rounded. +#' - For events at final analysis: +#' + If the continuous event is very close to an integer within 0.01 differences, say 100.001 or 99.999, then the integer events is 100. +#' + Otherwise, final events is rounded up if `round_up_final = TRUE` and rounded if `round_up_final = FALSE`. #' #' @return A list similar to the output of fixed_design_xxx() and gs_design_xxx(), #' except the sample size is an integer. @@ -30,10 +58,6 @@ to_integer <- function(x, ...) { } #' @rdname to_integer -#' -#' @param sample_size Logical, indicting if ceiling -#' sample size to an even integer. -#' #' @export #' #' @examples @@ -89,22 +113,55 @@ to_integer <- function(x, ...) { #' to_integer() |> #' summary() #' } -to_integer.fixed_design <- function(x, sample_size = TRUE, ...) { +to_integer.fixed_design <- function(x, round_up_final = TRUE, ratio = x$input$ratio, ...) { + + if (ratio < 0) { + stop("The ratio must be non-negative.") + } + + if (!is_wholenumber(ratio)) { + message("The output sample size is just rounded, may not a multiple of (ratio + 1).") + } + output_n <- x$analysis$n input_n <- expected_accrual(time = x$analysis$time, enroll_rate = x$input$enroll_rate) - multiply_factor <- x$input$ratio + 1 - enroll_rate_new <- x$enroll_rate %>% - mutate(rate = rate * ceiling(output_n / multiply_factor) * multiply_factor / output_n) + multiply_factor <- ratio + 1 + ss <- output_n / multiply_factor + if (is_wholenumber(ratio)) { + if (round_up_final) { + sample_size_new <- ceiling(ss) * multiply_factor + } else { + sample_size_new <- round(ss, 0) * multiply_factor + } + } else { + if (round_up_final) { + sample_size_new <- ceiling(output_n) + } else { + sample_size_new <- round(output_n, 0) + } + } - # Round up the FA events - event_ceiling <- ceiling(x$analysis$event) + enroll_rate_new <- x$enroll_rate %>% + mutate(rate = rate * sample_size_new / output_n) + + # Round events + # if events is very close to an integer, set it as this integer + if (abs(x$analysis$event - round(x$analysis$event)) < 0.01) { + event_new <- round(x$analysis$event) + # ceiling the FA events as default + } else if (round_up_final) { + event_new <- ceiling(x$analysis$event) + # otherwise, round the FA events + } else{ + event_new <- round(x$analysis$event, 0) + } if ((x$design == "ahr") && (input_n != output_n)) { x_new <- gs_power_ahr( enroll_rate = enroll_rate_new, fail_rate = x$input$fail_rate, - event = event_ceiling, + event = event_new, analysis_time = NULL, ratio = x$input$ratio, upper = gs_b, lower = gs_b, @@ -131,7 +188,7 @@ to_integer.fixed_design <- function(x, sample_size = TRUE, ...) { x_new <- gs_power_wlr( enroll_rate = enroll_rate_new, fail_rate = x$input$fail_rate, - event = event_ceiling, + event = event_new, analysis_time = NULL, ratio = x$input$ratio, upper = gs_b, lower = gs_b, @@ -164,7 +221,7 @@ to_integer.fixed_design <- function(x, sample_size = TRUE, ...) { x_new <- gs_power_wlr( enroll_rate = enroll_rate_new, fail_rate = x$input$fail_rate, - event = event_ceiling, + event = event_new, analysis_time = NULL, ratio = x$input$ratio, weight = function(s, arm0, arm1) { @@ -210,6 +267,11 @@ to_integer.fixed_design <- function(x, sample_size = TRUE, ...) { #' @rdname to_integer #' @param round_up_final Events at final analysis is rounded up if `TRUE`; #' otherwise, just rounded, unless it is very close to an integer. +#' @param ratio Positive integer for randomization ratio (experimental:control). +#' A positive integer will result in rounded sample size, which is a multiple of (ratio + 1). +#' A positive non-integer will result in round sample size, which may not be a multiple of (ratio + 1). +#' A negative number will result in an error. +#' #' @export #' #' @examples @@ -265,7 +327,7 @@ to_integer.fixed_design <- function(x, sample_size = TRUE, ...) { #' x$bound$`nominal p`[1] #' gsDesign::sfLDOF(alpha = 0.025, t = 18 / 30)$spend #' } -to_integer.gs_design <- function(x, sample_size = TRUE, round_up_final = TRUE, ...) { +to_integer.gs_design <- function(x, round_up_final = TRUE, ratio = x$input$ratio, ...) { is_ahr <- inherits(x, "ahr") is_wlr <- inherits(x, "wlr") is_rd <- inherits(x, "rd") @@ -274,8 +336,16 @@ to_integer.gs_design <- function(x, sample_size = TRUE, round_up_final = TRUE, . return(x) } + if (ratio < 0) { + stop("The ratio must be non-negative.") + } + + if (!is_wholenumber(ratio)) { + message("The output sample size is just rounded, may not a multiple of (ratio + 1).") + } + n_analysis <- length(x$analysis$analysis) - multiply_factor <- x$input$ratio + 1 + multiply_factor <- ratio + 1 if (!is_rd) { # Updated events to integer @@ -292,16 +362,35 @@ to_integer.gs_design <- function(x, sample_size = TRUE, round_up_final = TRUE, . # ceiling the FA events as default } else if (round_up_final) { event_fa_new <- ceiling(event[n_analysis]) - # otherwise, floor the FA events + # otherwise, round the FA events } else{ - event_fa_new <- floor(event_fa_new) + event_fa_new <- round(event[n_analysis], 0) } event_new <- c(event_ia_new, event_fa_new) } # Updated sample size to integer and enroll rates - sample_size_new <- (ceiling(x$analysis$n[n_analysis] / multiply_factor) * multiply_factor) %>% as.integer() + # if the randomization ratio is a whole number, round the sample size as a multiplier of ratio + 1 + if(is_wholenumber(ratio)) { + ss <- x$analysis$n[n_analysis] / multiply_factor + + if (round_up_final) { + sample_size_new <- ceiling(ss) * multiply_factor + } else { + sample_size_new <- round(ss, 0) * multiply_factor + } + # if the randomization ratio is NOT a whole number, just round it + } else { + if (round_up_final) { + sample_size_new <- ceiling(x$analysis$n[n_analysis]) + } else { + sample_size_new <- round(x$analysis$n[n_analysis], 0) + } + } + + sample_size_new <- as.integer(sample_size_new) + enroll_rate <- x$enroll_rate enroll_rate_new <- enroll_rate %>% mutate(rate = rate * sample_size_new / x$analysis$n[n_analysis]) @@ -319,7 +408,7 @@ to_integer.gs_design <- function(x, sample_size = TRUE, round_up_final = TRUE, . info_with_new_event <- gs_info_ahr( enroll_rate = enroll_rate_new, fail_rate = x$input$fail_rate, - ratio = x$input$ratio, + ratio = ratio, event = event_new, analysis_time = NULL ) @@ -327,7 +416,7 @@ to_integer.gs_design <- function(x, sample_size = TRUE, round_up_final = TRUE, . info_with_new_event <- gs_info_wlr( enroll_rate = enroll_rate_new, fail_rate = x$input$fail_rate, - ratio = x$input$ratio, + ratio = ratio, event = event_new, analysis_time = NULL, weight = x$input$weight @@ -336,7 +425,7 @@ to_integer.gs_design <- function(x, sample_size = TRUE, round_up_final = TRUE, . # ensure info0 is based on integer sample size calculation # as as they become a slight different number due to the `enroll_rate` - q_e <- x$input$ratio / (1 + x$input$ratio) + q_e <- ratio / (1 + ratio) q_c <- 1 - q_e info_with_new_event$info0 <- event_new * q_e * q_c @@ -369,7 +458,7 @@ to_integer.gs_design <- function(x, sample_size = TRUE, round_up_final = TRUE, . fail_rate = x$input$fail_rate, event = event_new, analysis_time = NULL, - ratio = x$input$ratio, + ratio = ratio, upper = x$input$upper, upar = upar_new, lower = x$input$lower, lpar = lpar_new, test_upper = x$input$test_upper, @@ -385,12 +474,24 @@ to_integer.gs_design <- function(x, sample_size = TRUE, round_up_final = TRUE, . n_stratum <- length(x$input$p_c$stratum) # Update unstratified sample size to integer + sample_size_new_ia <- round(x$analysis$n[1:(n_analysis - 1)], 0) + if (round_up_final) { + if (is_wholenumber(ratio)) { + sample_size_new_fa <- ceiling(x$analysis$n[n_analysis] / multiply_factor) * multiply_factor + } else { + sample_size_new_fa <- ceiling(x$analysis$n[n_analysis]) + } + } else { + if (is_wholenumber(ratio)) { + sample_size_new_fa <- round(x$analysis$n[n_analysis] / multiply_factor, 0) * multiply_factor + } else { + sample_size_new_fa <- round(x$analysis$n[n_analysis], 0) + } + } + sample_size_new <- tibble( analysis = 1:n_analysis, - n = c( - floor(x$analysis$n[1:(n_analysis - 1)] / multiply_factor), - ceiling(x$analysis$n[n_analysis] / multiply_factor) - ) * multiply_factor + n = c(sample_size_new_ia, sample_size_new_fa) ) # Update sample size per stratum @@ -425,7 +526,7 @@ to_integer.gs_design <- function(x, sample_size = TRUE, round_up_final = TRUE, . p_e = x$input$p_e, n = tbl_n, rd0 = x$input$rd, - ratio = x$input$ratio, + ratio = ratio, weight = x$input$weight ) @@ -449,7 +550,7 @@ to_integer.gs_design <- function(x, sample_size = TRUE, round_up_final = TRUE, . p_e = x$input$p_e, n = tbl_n, rd0 = x$input$rd0, - ratio = x$input$ratio, + ratio = ratio, weight = x$input$weight, upper = x$input$upper, lower = x$input$lower, diff --git a/R/utils.R b/R/utils.R index 901c9281..5257379b 100644 --- a/R/utils.R +++ b/R/utils.R @@ -40,3 +40,9 @@ replace_names <- function(x, ...) { round2 <- function(x, digits, ...) { if (is.numeric(x) && !is.na(digits)) round(x, digits, ...) else x } + +# test if it is whole number +is_wholenumber <- function (x, tol = .Machine$double.eps^0.5) { + abs(x - round(x)) < tol +} + diff --git a/man/to_integer.Rd b/man/to_integer.Rd index 83d0d56a..9e61c6a7 100644 --- a/man/to_integer.Rd +++ b/man/to_integer.Rd @@ -4,31 +4,76 @@ \alias{to_integer} \alias{to_integer.fixed_design} \alias{to_integer.gs_design} -\title{Rounds sample size to an even number for equal design} +\title{Round sample size and events} \usage{ to_integer(x, ...) -\method{to_integer}{fixed_design}(x, sample_size = TRUE, ...) +\method{to_integer}{fixed_design}(x, round_up_final = TRUE, ratio = x$input$ratio, ...) -\method{to_integer}{gs_design}(x, sample_size = TRUE, round_up_final = TRUE, ...) +\method{to_integer}{gs_design}(x, round_up_final = TRUE, ratio = x$input$ratio, ...) } \arguments{ \item{x}{An object returned by fixed_design_xxx() and gs_design_xxx().} \item{...}{Additional parameters (not used).} -\item{sample_size}{Logical, indicting if ceiling -sample size to an even integer.} - \item{round_up_final}{Events at final analysis is rounded up if \code{TRUE}; otherwise, just rounded, unless it is very close to an integer.} + +\item{ratio}{Positive integer for randomization ratio (experimental:control). +A positive integer will result in rounded sample size, which is a multiple of (ratio + 1). +A positive non-integer will result in round sample size, which may not be a multiple of (ratio + 1). +A negative number will result in an error.} } \value{ A list similar to the output of fixed_design_xxx() and gs_design_xxx(), except the sample size is an integer. } \description{ -Rounds sample size to an even number for equal design +Round sample size and events +} +\details{ +For the sample size of the fixed design: +\itemize{ +\item When \code{ratio} is a positive integer, the sample size is rounded up to a multiple of \code{ratio + 1} +if \code{round_up_final = TRUE}, and just rounded to a multiple of \code{ratio + 1} if \code{round_up_final = FALSE}. +\item When \code{ratio} is a positive non-integer, the sample size is rounded up if \code{round_up_final = TRUE}, +(may not be a multiple of \code{ratio + 1}), and just rounded if \code{round_up_final = FALSE} (may not be a multiple of \code{ratio + 1}). +Note the default \code{ratio} is taken from \code{x$input$ratio}. +} + +For the number of events of the fixed design: +\itemize{ +\item If the continuous event is very close to an integer within 0.01 differences, say 100.001 or 99.999, then the integer events is 100. +\item Otherwise, round up if \code{round_up_final = TRUE} and round if \code{round_up_final = FALSE}. +} + +For the sample size of group sequential designs: +\itemize{ +\item When \code{ratio} is a positive integer, the final sample size is rounded to a multiple of \code{ratio + 1}. +\itemize{ +\item For 1:1 randomization (experimental:control), set \code{ratio = 1} to round to an even sample size. +\item For 2:1 randomization, set \code{ratio = 2} to round to a multiple of 3. +\item For 3:2 randomization, set \code{ratio = 4} to round to a multiple of 5. +\item Note that for the final analysis, the sample size is rounded up to the nearest multiple of \code{ratio + 1} if \code{round_up_final = TRUE}. +If \code{round_up_final = FALSE}, the final sample size is rounded to the nearest multiple of \code{ratio + 1}. +} +\item When \code{ratio} is positive non-integer, the final sample size MAY NOT be rounded to a multiple of \code{ratio + 1}. +\itemize{ +\item The final sample size is rounded up if \code{round_up_final = TRUE}. +\item Otherwise, it is just rounded. +} +} + +For the events of group sequential designs: +\itemize{ +\item For events at interim analysis, it is rounded. +\item For events at final analysis: +\itemize{ +\item If the continuous event is very close to an integer within 0.01 differences, say 100.001 or 99.999, then the integer events is 100. +\item Otherwise, final events is rounded up if \code{round_up_final = TRUE} and rounded if \code{round_up_final = FALSE}. +} +} } \examples{ library(dplyr) diff --git a/tests/testthat/test-developer-to_integer.R b/tests/testthat/test-developer-to_integer.R index 700530a6..0bfc7cef 100644 --- a/tests/testthat/test-developer-to_integer.R +++ b/tests/testthat/test-developer-to_integer.R @@ -51,3 +51,200 @@ test_that("The statistcial information under null equals to event/4 udner equal expect_true(all(x$analysis$info0 - x$analysis$event / 4 == 0)) }) + +test_that("Validate the sample size rounding under equal randomization (1:1) for TTE endpoint. -- GSD", { + + x <- gs_design_ahr(analysis_time = c(24, 36)) + + # ----------------------- # + # round_up_final = TRUE # + # ----------------------- # + y1 <- x |> to_integer(round_up_final = TRUE) + # test the sample size at FA is rounded up and multiple of 2 + expect_equal(ceiling(x$analysis$n[2] / 2) * 2, y1$analysis$n[2]) + # test the event at FA is rounded up + expect_equal(ceiling(x$analysis$event[2]), y1$analysis$event[2]) + # test the event at IA is rounded + expect_equal(round(x$analysis$event[1], 0), y1$analysis$event[1]) + + + # ----------------------- # + # round_up_final = FALSE # + # ----------------------- # + y2 <- x |> to_integer(round_up_final = FALSE) + # test the sample size at FA is rounded up and multiple of 2 + expect_equal(round(x$analysis$n[2] / 2, 0) * 2, y2$analysis$n[2]) + # test the event at FA is rounded + expect_equal(round(x$analysis$event[2], 0), y2$analysis$event[2]) + # test the event at IA is rounded + expect_equal(round(x$analysis$event[1], 0), y2$analysis$event[1]) + + expect_error(x |> to_integer(ratio = -2)) +}) + +test_that("Validate the sample size rounding under unequal randomization (3:2) for TTE endpoint. -- GSD", { + + x <- gs_design_ahr(analysis_time = c(24, 36), ratio = 1.5, + alpha = 0.025, + upper = gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025)) + + # ---------------------------------------------- # + # round_up_final = TRUE & ratio is NOT integer # + # ---------------------------------------------- # + y1 <- x |> to_integer(round_up_final = TRUE) + # test the FA sample size is rounded up, but may not be a multiplier of 5 + expect_equal(ceiling(x$analysis$n[2]), y1$analysis$n[2]) + # test the FA events is rounded up + expect_equal(ceiling(x$analysis$event[2]), y1$analysis$event[2]) + # test the IA events is rounded + expect_equal(round(x$analysis$event[1], 0), y1$analysis$event[1]) + + # ---------------------------------------------- # + # round_up_final = TRUE & ratio is integer # + # ---------------------------------------------- # + y2 <- x |> to_integer(round_up_final = TRUE, ratio = 4) + # test the FA sample size is round up, and is a multiplier of 5 + expect_equal(ceiling(x$analysis$n[2] / 5) * 5, y2$analysis$n[2]) + # test the FA events is rounded up + expect_equal(ceiling(x$analysis$event[2]), y2$analysis$event[2]) + # test the IA events is rounded + expect_equal(round(x$analysis$event[1], 0), y2$analysis$event[1]) + + # ---------------------------------------------- # + # round_up_final = FALSE & ratio is NOT integer # + # ---------------------------------------------- # + y3 <- x |> to_integer(round_up_final = FALSE) + # test the sample size at FA is rounded, but may not a multiplier of 5 + expect_equal(round(x$analysis$n[2]), y3$analysis$n[2]) + # test the FA events is rounded + expect_equal(round(x$analysis$event[2], 0), y2$analysis$event[2]) + # test the IA events is rounded + expect_equal(round(x$analysis$event[1], 0), y2$analysis$event[1]) + + # ---------------------------------------------- # + # round_up_final = FALSE & ratio is integer # + # ---------------------------------------------- # + y4 <- x |> to_integer(round_up_final = FALSE, ratio = 4) + # test the FA sample size is rounded, but may not is a multiplier of 5 + expect_equal(round(x$analysis$n[2] / 5, 0) * 5, y4$analysis$n[2]) + # test the FA events is rounded + expect_equal(round(x$analysis$event[2], 0), y2$analysis$event[2]) + # test the IA events is rounded + expect_equal(round(x$analysis$event[1], 0), y2$analysis$event[1]) + + # error when ratio is negative + expect_error(x |> to_integer(ratio = -2)) +}) + +test_that("Validate the sample size rounding under equal randomization (1:1) for binary endpoint. -- GSD", { + + x <- gs_design_rd(ratio = 1, + alpha = 0.025, + info_frac = 1:3/3, + upper = gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025)) + + y1 <- x |> to_integer(round_up_final = TRUE) + y2 <- x |> to_integer(round_up_final = FALSE) + + expect_equal(c(round(x$analysis$n[1:2], 0), ceiling(x$analysis$n[3] / 2) * 2), y1$analysis$n) + expect_equal(c(round(x$analysis$n[1:2], 0), round(x$analysis$n[3] / 2, 0) * 2), y2$analysis$n) + + expect_error(x |> to_integer(ratio = -2)) +}) + +test_that("Validate the sample size rounding under unequal randomization (3:2) for binary endpoint. -- GSD", { + + x <- gs_design_rd(ratio = 1.5, + alpha = 0.025, + info_frac = 1:3/3, + upper = gs_spending_bound, + upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025)) + + # ceiling the sample size at FA, but may not be a multiplier of 5 + y1 <- x |> to_integer(round_up_final = TRUE) + expect_equal(ceiling(x$analysis$n[3]) , y1$analysis$n[3]) + + # ceiling the sample size at FA, and is a multiplier of 5 + y2 <- x |> to_integer(round_up_final = TRUE, ratio = 4) + expect_equal(ceiling(x$analysis$n[3] / 4) * 4, y2$analysis$n[3]) + + # round the sample size at FA, but may not a multiplier of 5 + y3 <- x |> to_integer(round_up_final = FALSE) + expect_equal(round(x$analysis$n[3], 0), y3$analysis$n[3]) + + # round the sample size at FA, and is a multiplier of 5 + y4 <- x |> to_integer(round_up_final = FALSE, ratio = 4) + expect_equal(round(x$analysis$n[3] / 5, 0) * 5, y4$analysis$n[3]) + + # error when ratio is negative + expect_error(x |> to_integer(ratio = -2)) +}) + +test_that("Validate the sample size rounding under equal randomization (1:1) for TTE endpoint -- fixed design.", { + + x <- fixed_design_ahr(alpha = .025, power = .9, ratio = 1, + enroll_rate = define_enroll_rate(duration = 18, rate = 1), + fail_rate = define_fail_rate(duration = c(4, 100), + fail_rate = log(2) / 10, hr = c(1, .6), + dropout_rate = .001), + study_duration = 36) + + y1 <- x |> to_integer(round_up_final = TRUE) + y2 <- x |> to_integer(round_up_final = FALSE) + + expect_equal(ceiling(x$analysis$n / 2) * 2, y1$analysis$n) + expect_equal(round(x$analysis$n / 2, 0) * 2, y2$analysis$n) + + expect_error(x |> to_integer(ratio = -2)) +}) + +test_that("Validate the sample size rounding under unequal randomization (3:2) for TTE endpoint.", { + + x <- fixed_design_ahr(alpha = .025, power = .9, ratio = 1.5, + enroll_rate = define_enroll_rate(duration = 18, rate = 1), + fail_rate = define_fail_rate(duration = c(4, 100), + fail_rate = log(2) / 10, hr = c(1, .6), + dropout_rate = .001), + study_duration = 36) + + # ---------------------------------------------- # + # round_up_final = TRUE & ratio is NOT integer # + # ---------------------------------------------- # + y1 <- x |> to_integer(round_up_final = TRUE) + # test the sample size is rounded up, but may not be a multiplier of 5 + expect_equal(ceiling(x$analysis$n), y1$analysis$n) + # test the event is rounded up + expect_equal(ceiling(x$analysis$event), y1$analysis$event) + + # ---------------------------------------------- # + # round_up_final = TRUE & ratio is integer # + # ---------------------------------------------- # + y2 <- x |> to_integer(round_up_final = TRUE, ratio = 4) + # test the sample size is rounded up, and is a multiplier of 5 + expect_equal(ceiling(x$analysis$n / 5) * 5, y2$analysis$n) + # test the event is rounded up + expect_equal(ceiling(x$analysis$event), y2$analysis$event) + + # ---------------------------------------------- # + # round_up_final = FALSE & ratio is NOT integer # + # ---------------------------------------------- # + y3 <- x |> to_integer(round_up_final = FALSE) + # test the sample size is rounded, but may not a multiplier of 5 + expect_equal(round(x$analysis$n), y3$analysis$n) + # test the event is rounded + expect_equal(round(x$analysis$event, 0), y3$analysis$event) + + # ---------------------------------------------- # + # round_up_final = FALSE & ratio is integer # + # ---------------------------------------------- # + y4 <- x |> to_integer(round_up_final = FALSE, ratio = 4) + # test the sample size is rounded, and is a multiplier of 5 + expect_equal(round(x$analysis$n / 5, 0) * 5, y4$analysis$n) + # test the event is rounded + expect_equal(ceiling(x$analysis$event), y4$analysis$event) + + # error when ratio is negative + expect_error(x |> to_integer(ratio = -2)) +})