@@ -4,10 +4,12 @@ test_that("sim_failures returns correct output structure", {
44 result <- sim_failures(2 , runtimes )
55
66 expect_s3_class(result , " data.frame" )
7- expect_named(result , c(" index" , " runtime" ))
8- expect_equal(nrow(result ), 2 )
7+ expect_named(result , c(" index" , " runtime" , " type " ))
8+ expect_equal(nrow(result ), 5 )
99 expect_type(result $ index , " integer" )
1010 expect_type(result $ runtime , " double" )
11+ expect_type(result $ type , " character" )
12+ expect_true(all(result $ type %in% c(" Failure" , " Suspension" )))
1113 # sorted ascending by runtime
1214 expect_true(all(diff(result $ runtime ) > = 0 ))
1315})
@@ -17,7 +19,8 @@ test_that("sim_failures PPS bias: higher-runtime units selected more often", {
1719 runtimes <- c(10 , 1000 )
1820 N <- 10000
1921 draws <- replicate(N , {
20- sim_failures(1 , runtimes , replace = FALSE )$ index
22+ res <- sim_failures(1 , runtimes , replace = FALSE )
23+ res $ index [res $ type == " Failure" ]
2124 })
2225 # unit 2 has 100x the runtime of unit 1, so it should be chosen ~99% of the time
2326 prop_unit2 <- mean(draws == 2 )
@@ -72,10 +75,10 @@ test_that("sim_failures errors: n > length(runtimes) without replacement", {
7275 sim_failures(4 , c(100 , 200 , 300 ), replace = FALSE ),
7376 " 'n' cannot exceed the number of units in 'runtimes' when replace = FALSE."
7477 )
75- # Same call with replace = TRUE should succeed
78+ # Same call with replace = TRUE should succeed (returns full fleet of 3 rows)
7679 set.seed(1 )
7780 result <- sim_failures(4 , c(100 , 200 , 300 ), replace = TRUE )
78- expect_equal(nrow(result ), 4 )
81+ expect_equal(nrow(result ), 3 )
7982})
8083
8184test_that(" sim_failures is reproducible with the same seed" , {
@@ -90,12 +93,12 @@ test_that("sim_failures is reproducible with the same seed", {
9093 expect_equal(r1 , r2 )
9194})
9295
93- test_that(" sim_failures edge case: n = 1 returns a 1-row data frame " , {
96+ test_that(" sim_failures edge case: n = 1 returns full fleet (3 rows) " , {
9497 set.seed(7 )
9598 runtimes <- c(100 , 500 , 200 )
9699 result <- sim_failures(1 , runtimes )
97- expect_equal(nrow(result ), 1 )
98- expect_named(result , c(" index" , " runtime" ))
100+ expect_equal(nrow(result ), 3 )
101+ expect_named(result , c(" index" , " runtime" , " type " ))
99102})
100103
101104test_that(" sim_failures edge case: n = length(runtimes) returns all units without replacement" , {
@@ -105,3 +108,96 @@ test_that("sim_failures edge case: n = length(runtimes) returns all units withou
105108 expect_equal(nrow(result ), length(runtimes ))
106109 expect_equal(sort(result $ index ), seq_along(runtimes ))
107110})
111+
112+ test_that(" sim_failures type labels: correct counts of Failure and Suspension" , {
113+ set.seed(42 )
114+ runtimes <- c(100 , 500 , 200 , 800 , 300 )
115+ n <- 2
116+ result <- sim_failures(n , runtimes , replace = FALSE )
117+
118+ n_failures <- sum(result $ type == " Failure" )
119+ n_suspensions <- sum(result $ type == " Suspension" )
120+
121+ # With replace = FALSE and n unique draws, exactly n failures and rest suspensions
122+ expect_equal(n_failures , n )
123+ expect_equal(n_suspensions , length(runtimes ) - n )
124+ })
125+
126+ test_that(" sim_failures window: failure times are in (runtime, runtime + window]" , {
127+ set.seed(42 )
128+ runtimes <- c(100 , 500 , 200 , 800 , 300 )
129+ w <- 50
130+ result <- sim_failures(2 , runtimes , window = w )
131+
132+ failures <- result [result $ type == " Failure" , ]
133+ for (i in seq_len(nrow(failures ))) {
134+ orig <- runtimes [failures $ index [i ]]
135+ expect_gt(failures $ runtime [i ], orig )
136+ expect_lte(failures $ runtime [i ], orig + w )
137+ }
138+ })
139+
140+ test_that(" sim_failures window: suspension times equal runtime + window exactly" , {
141+ set.seed(42 )
142+ runtimes <- c(100 , 500 , 200 , 800 , 300 )
143+ w <- 50
144+ result <- sim_failures(2 , runtimes , window = w )
145+
146+ suspensions <- result [result $ type == " Suspension" , ]
147+ for (i in seq_len(nrow(suspensions ))) {
148+ orig <- runtimes [suspensions $ index [i ]]
149+ expect_equal(suspensions $ runtime [i ], orig + w )
150+ }
151+ })
152+
153+ test_that(" sim_failures window = NULL: runtimes unchanged" , {
154+ set.seed(42 )
155+ runtimes <- c(100 , 500 , 200 , 800 , 300 )
156+ result <- sim_failures(2 , runtimes , window = NULL )
157+
158+ for (i in seq_len(nrow(result ))) {
159+ expect_equal(result $ runtime [i ], runtimes [result $ index [i ]])
160+ }
161+ })
162+
163+ test_that(" sim_failures window validation errors" , {
164+ runtimes <- c(100 , 500 , 200 )
165+
166+ expect_error(
167+ sim_failures(1 , runtimes , window = " 50" ),
168+ " 'window' must be a single positive numeric value."
169+ )
170+ expect_error(
171+ sim_failures(1 , runtimes , window = c(10 , 20 )),
172+ " 'window' must be a single positive numeric value."
173+ )
174+ expect_error(
175+ sim_failures(1 , runtimes , window = NA_real_ ),
176+ " 'window' must be a finite positive numeric value."
177+ )
178+ expect_error(
179+ sim_failures(1 , runtimes , window = Inf ),
180+ " 'window' must be a finite positive numeric value."
181+ )
182+ expect_error(
183+ sim_failures(1 , runtimes , window = 0 ),
184+ " 'window' must be a positive numeric value."
185+ )
186+ expect_error(
187+ sim_failures(1 , runtimes , window = - 5 ),
188+ " 'window' must be a positive numeric value."
189+ )
190+ })
191+
192+ test_that(" sim_failures reproducibility with window" , {
193+ runtimes <- c(100 , 500 , 200 , 800 , 300 )
194+ w <- 50
195+
196+ set.seed(42 )
197+ r1 <- sim_failures(2 , runtimes , window = w )
198+
199+ set.seed(42 )
200+ r2 <- sim_failures(2 , runtimes , window = w )
201+
202+ expect_equal(r1 , r2 )
203+ })
0 commit comments