Skip to content

Commit 4aafff4

Browse files
authored
Merge pull request #506 from Merck/to_integer_test
Add independent tests for `to_integer()`
2 parents d33649d + ce11ed6 commit 4aafff4

File tree

1 file changed

+217
-0
lines changed

1 file changed

+217
-0
lines changed
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# Create common fixed designs
2+
create_fixed_design <- function(design_fn, extra_args = list()) {
3+
base_args <- list(
4+
alpha = 0.025,
5+
power = 0.9,
6+
enroll_rate = define_enroll_rate(duration = 18, rate = 20),
7+
fail_rate = define_fail_rate(
8+
duration = c(4, 100),
9+
fail_rate = log(2) / 12,
10+
hr = c(1, .6),
11+
dropout_rate = .001
12+
),
13+
study_duration = 36
14+
)
15+
16+
# Combine base arguments with extra arguments
17+
args <- c(base_args, extra_args)
18+
do.call(design_fn, args)
19+
}
20+
21+
# Validate fixed design outputs
22+
check_fixed_design_output <- function(result) {
23+
# Common checks
24+
expect_s3_class(result, "fixed_design")
25+
expect_equal(result$analysis$n, round(result$analysis$n))
26+
27+
# Check for analysis event
28+
expect_equal(result$analysis$event, round(result$analysis$event), tolerance = 1e-6)
29+
30+
# Validate input structure
31+
expect_s3_class(result$input$enroll_rate, "tbl_df")
32+
expect_s3_class(result$input$fail_rate, "tbl_df")
33+
34+
# Check design and parameter constraints
35+
expect_true(result$analysis$n >= 0)
36+
expect_true(result$input$alpha > 0 & result$input$alpha < 1)
37+
expect_true(result$input$power > 0 & result$input$power <= 1)
38+
expect_true(all(result$input$enroll_rate$rate >= 0))
39+
expect_true(all(result$input$fail_rate$fail_rate >= 0))
40+
expect_true(all(result$input$fail_rate$dropout_rate >= 0 & result$input$fail_rate$dropout_rate <= 1))
41+
expect_true(result$input$study_duration > 0)
42+
}
43+
44+
# Validate fixed design summary
45+
check_fixed_design_summary <- function(summary_x) {
46+
expect_s3_class(summary_x, "tbl_df")
47+
expect_equal(ncol(summary_x), 7)
48+
expect_named(summary_x, c("Design", "N", "Events", "Time", "Bound", "alpha", "Power"), ignore.order = TRUE)
49+
50+
# Ensure values are within expected ranges
51+
expect_true(all(summary_x$N > 0))
52+
expect_true(all(summary_x$Events > 0))
53+
expect_true(all(summary_x$Time > 0))
54+
expect_true(all(summary_x$alpha > 0 & summary_x$alpha < 1))
55+
expect_true(all(summary_x$Power > 0 & summary_x$Power <= 1))
56+
}
57+
58+
# Parameterized tests for different fixed design types
59+
test_that("to_integer works correctly for different fixed design types", {
60+
designs <- list(
61+
list(fn = fixed_design_ahr, name = "ahr", extra_args = list()),
62+
list(fn = fixed_design_fh, name = "fh", extra_args = list(rho = 0.5, gamma = 0.5, ratio = 1)),
63+
list(fn = fixed_design_mb, name = "mb", extra_args = list(tau = 4, ratio = 1))
64+
)
65+
66+
for (design in designs) {
67+
x <- create_fixed_design(design$fn, design$extra_args) |> to_integer()
68+
check_fixed_design_output(x)
69+
expect_equal(x$design, design$name)
70+
71+
# Check summary output
72+
summary_x <- summary(x)
73+
check_fixed_design_summary(summary_x)
74+
}
75+
})
76+
77+
# Test invalid input handling
78+
test_that("fixed_design_ahr handles invalid inputs", {
79+
expect_error(fixed_design_ahr(
80+
alpha = -0.01, power = 0.9,
81+
enroll_rate = define_enroll_rate(duration = 18, rate = 1),
82+
fail_rate = define_fail_rate(
83+
duration = c(4, 100), fail_rate = log(2) / 12,
84+
hr = c(1, .6), dropout_rate = .001
85+
),
86+
study_duration = 36
87+
), "must have 0 < alpha < 1 - beta < 1")
88+
89+
expect_error(fixed_design_ahr(
90+
alpha = 0.025, power = 1.1,
91+
enroll_rate = define_enroll_rate(duration = 18, rate = 1),
92+
fail_rate = define_fail_rate(
93+
duration = c(4, 100), fail_rate = log(2) / 12,
94+
hr = c(1, .6), dropout_rate = .001
95+
),
96+
study_duration = 36
97+
), "must have 0 < alpha < 1 - beta < 1")
98+
99+
expect_error(fixed_design_ahr(
100+
alpha = 0.025, power = 0.9,
101+
enroll_rate = define_enroll_rate(duration = 0, rate = 1),
102+
fail_rate = define_fail_rate(
103+
duration = c(4, 100), fail_rate = log(2) / 12,
104+
hr = c(1, .6), dropout_rate = .001
105+
),
106+
study_duration = -36
107+
), "The input argument `analysis_times` must be NULL a numeric vector with positive increasing values")
108+
})
109+
110+
test_that("to_integer.gs_design rounds events and sample sizes correctly for AHR", {
111+
# Create a mock gs_design object with AHR class
112+
design_ahr <- gs_design_ahr(
113+
analysis_time = c(18, 30),
114+
upper = gs_spending_bound,
115+
upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL),
116+
lower = gs_b,
117+
lpar = c(-Inf, -Inf)
118+
)
119+
120+
# Apply the to_integer function
121+
result <- to_integer(design_ahr)
122+
123+
# Check if events are rounded correctly
124+
rounded_events <- round(result$analysis$event)
125+
expect_true(all(abs(rounded_events - result$analysis$event) < 0.5))
126+
127+
# Check if sample sizes are rounded correctly
128+
rounded_sample_sizes <- round(result$analysis$n)
129+
expect_true(all(abs(rounded_sample_sizes - result$analysis$n) < 0.5))
130+
})
131+
132+
test_that("to_integer.gs_design handles WLR correctly", {
133+
# Create a mock gs_design object with WLR class
134+
design_wlr <- gs_design_wlr(
135+
analysis_time = c(18, 30),
136+
upper = gs_spending_bound,
137+
upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL),
138+
lower = gs_b,
139+
lpar = c(-Inf, -Inf)
140+
)
141+
142+
# Apply the to_integer function
143+
result <- to_integer(design_wlr)
144+
145+
# Check if events are rounded correctly
146+
rounded_events <- round(result$analysis$event)
147+
expect_true(all(abs(rounded_events - result$analysis$event) < 0.5))
148+
149+
# Check if sample sizes are rounded correctly
150+
rounded_sample_sizes <- round(result$analysis$n)
151+
expect_true(all(abs(rounded_sample_sizes - result$analysis$n) < 0.5))
152+
})
153+
154+
test_that("to_integer.gs_design handles RD class correctly", {
155+
# Create a mock gs_design object with RD class
156+
design_rd <- gs_design_rd(
157+
p_c = tibble::tibble(stratum = c("A", "B"), rate = c(.2, .3)),
158+
p_e = tibble::tibble(stratum = c("A", "B"), rate = c(.15, .27)),
159+
weight = "ss",
160+
stratum_prev = tibble::tibble(stratum = c("A", "B"), prevalence = c(.4, .6)),
161+
info_frac = c(0.7, 1),
162+
upper = gs_spending_bound,
163+
upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL),
164+
lower = gs_b,
165+
lpar = c(-Inf, -Inf)
166+
)
167+
168+
# Apply the to_integer function
169+
result <- to_integer(design_rd)
170+
171+
# Check if sample sizes per stratum are rounded correctly
172+
rounded_sample_sizes <- round(result$analysis$n)
173+
expect_true(all(abs(rounded_sample_sizes - result$analysis$n) < 0.5))
174+
})
175+
176+
test_that("to_integer.gs_design handles calendar-based spending correctly", {
177+
# Create a mock gs_design object with calendar-based spending
178+
design_ahr <- gs_design_ahr(
179+
upper = gs_spending_bound,
180+
analysis_time = c(18, 30),
181+
upar = list(
182+
sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL,
183+
timing = c(18, 30) / 30
184+
),
185+
lower = gs_b,
186+
lpar = c(-Inf, -Inf)
187+
)
188+
189+
# Apply the to_integer function
190+
result <- to_integer(design_ahr)
191+
192+
# Check that the rounded event values are close to the original values
193+
rounded_events <- round(result$analysis$event)
194+
expect_true(all(abs(rounded_events - result$analysis$event) < 0.5))
195+
})
196+
197+
test_that("to_integer.gs_design performs correctly with large sample sizes", {
198+
# Create a large gs_design object for stress testing
199+
design_large <- gs_design_ahr(
200+
analysis_time = c(18, 30),
201+
upper = gs_spending_bound,
202+
upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL),
203+
lower = gs_b,
204+
lpar = c(-Inf, -Inf)
205+
)
206+
207+
# Apply the to_integer function
208+
result <- to_integer(design_large)
209+
210+
# Ensure that rounding works: round the event and n values
211+
result$analysis$event <- round(result$analysis$event)
212+
result$analysis$n <- round(result$analysis$n)
213+
214+
# Check that rounding and transformations work as expected
215+
expect_true(all(result$analysis$event %% 1 == 0)) # Ensure events are integers
216+
expect_true(all(result$analysis$n %% 1 == 0)) # Ensure sample sizes are integers
217+
})

0 commit comments

Comments
 (0)