Nothing
# ==============================================================================
# tests/testthat/test-edge_cases.R
# ==============================================================================
# Create test data
create_test_data <- function(n = 1000) {
set.seed(123)
data.frame(
id = 1:n,
outcome = rbinom(n, 1, 0.2),
exposure = factor(sample(c("No", "Yes"), n, replace = TRUE)),
age = rnorm(n, 40, 10),
sex = factor(sample(c("Male", "Female"), n, replace = TRUE)),
stratum = factor(sample(c("A", "B"), n, replace = TRUE))
)
}
test_that("handles data with missing values correctly", {
data <- create_test_data()
data$outcome[1:50] <- NA
data$exposure[51:100] <- NA
result <- calc_risk_diff(data, "outcome", "exposure")
expect_s3_class(result, "riskdiff_result")
expect_true(result$n_obs < nrow(data)) # Should use complete cases only
})
test_that("handles constant outcomes gracefully", {
data <- create_test_data()
data$outcome <- 0 # All zeros
result <- calc_risk_diff(data, "outcome", "exposure")
expect_s3_class(result, "riskdiff_result")
# Should handle gracefully even if model fails
expect_true(nrow(result) == 1)
expect_true(result$model_type %in% c("insufficient_data", "failed"))
})
test_that("handles single-level exposures", {
data <- create_test_data()
data$exposure <- factor("Yes") # Only one level
expect_error(
calc_risk_diff(data, "outcome", "exposure"),
"at least 2 levels"
)
})
test_that("handles exposures with rare levels", {
data <- create_test_data(n = 1000)
# Make "Yes" very rare (only 2 observations)
data$exposure <- factor(c(rep("No", 998), rep("Yes", 2)))
result <- calc_risk_diff(data, "outcome", "exposure")
expect_s3_class(result, "riskdiff_result")
# Should still return a result, though it may not be reliable
expect_true(nrow(result) == 1)
})
test_that("model convergence issues are handled", {
# Create data likely to cause convergence issues
data <- data.frame(
outcome = c(rep(0, 100), rep(1, 10)),
exposure = factor(c(rep("No", 100), rep("Yes", 10))),
confounder = c(rep(0, 100), rep(1, 10)) # Perfect separation
)
result <- calc_risk_diff(data, "outcome", "exposure", adjust_vars = "confounder")
expect_s3_class(result, "riskdiff_result")
# Should handle convergence failure gracefully
expect_true(nrow(result) == 1)
})
test_that("verbose output works", {
data <- create_test_data()
expect_message(
calc_risk_diff(data, "outcome", "exposure", verbose = TRUE),
"Formula"
)
})
test_that("different alpha levels work", {
data <- create_test_data()
result_99 <- calc_risk_diff(data, "outcome", "exposure", alpha = 0.01)
result_90 <- calc_risk_diff(data, "outcome", "exposure", alpha = 0.10)
# 99% CI should be wider than 90% CI
width_99 <- result_99$ci_upper - result_99$ci_lower
width_90 <- result_90$ci_upper - result_90$ci_lower
expect_true(width_99 > width_90)
})
test_that("logical outcomes are handled correctly", {
data <- create_test_data()
data$outcome_logical <- as.logical(data$outcome)
result <- calc_risk_diff(data, "outcome_logical", "exposure")
expect_s3_class(result, "riskdiff_result")
expect_true(!is.na(result$rd))
})
test_that("character exposures are converted to factors", {
data <- create_test_data()
data$exposure_char <- as.character(data$exposure)
result <- calc_risk_diff(data, "outcome", "exposure_char")
expect_s3_class(result, "riskdiff_result")
expect_true(!is.na(result$rd))
})
test_that("handles very small datasets", {
# Dataset with minimal size
small_data <- data.frame(
outcome = c(0, 1, 0, 1, 1),
exposure = factor(c("No", "No", "Yes", "Yes", "Yes"))
)
result <- calc_risk_diff(small_data, "outcome", "exposure")
expect_s3_class(result, "riskdiff_result")
# Should return insufficient data result
expect_true(result$model_type == "insufficient_data")
})
test_that("handles datasets with extreme proportions", {
data <- create_test_data()
# Make outcome very rare (only 1% prevalence)
data$outcome <- rbinom(nrow(data), 1, 0.01)
result <- calc_risk_diff(data, "outcome", "exposure")
expect_s3_class(result, "riskdiff_result")
expect_true(nrow(result) == 1)
})
test_that("handles continuous adjustment variables", {
data <- create_test_data()
result <- calc_risk_diff(
data = data,
outcome = "outcome",
exposure = "exposure",
adjust_vars = "age"
)
expect_s3_class(result, "riskdiff_result")
expect_true(!is.na(result$rd))
})
test_that("handles multiple adjustment variables", {
data <- create_test_data()
result <- calc_risk_diff(
data = data,
outcome = "outcome",
exposure = "exposure",
adjust_vars = c("age", "sex")
)
expect_s3_class(result, "riskdiff_result")
expect_true(!is.na(result$rd))
})
test_that("handles stratification with small strata", {
data <- create_test_data()
data$rare_stratum <- factor(c(rep("Common", 990), rep("Rare", 10)))
# Test that it runs without error
result <- calc_risk_diff(
data = data,
outcome = "outcome",
exposure = "exposure",
strata = "rare_stratum"
)
# Basic structure checks
expect_s3_class(result, "riskdiff_result")
expect_true(nrow(result) >= 1)
# All model types should be valid
valid_types <- c("insufficient_data", "failed", "identity", "log", "logit")
expect_true(all(result$model_type %in% valid_types))
})
test_that("handles factor levels in different orders", {
data <- create_test_data()
# Reorder factor levels
data$exposure <- factor(data$exposure, levels = c("Yes", "No"))
result <- calc_risk_diff(data, "outcome", "exposure")
expect_s3_class(result, "riskdiff_result")
expect_true(!is.na(result$rd))
})
test_that("handles missing data in adjustment variables", {
data <- create_test_data()
data$age[1:100] <- NA # Missing adjustment variable
result <- calc_risk_diff(
data = data,
outcome = "outcome",
exposure = "exposure",
adjust_vars = "age"
)
expect_s3_class(result, "riskdiff_result")
expect_true(result$n_obs <= nrow(data)) # Should use complete cases
})
test_that("handles missing data in stratification variables", {
data <- create_test_data()
data$sex[1:100] <- NA # Missing stratification variable
result <- calc_risk_diff(
data = data,
outcome = "outcome",
exposure = "exposure",
strata = "sex"
)
expect_s3_class(result, "riskdiff_result")
# Should have results for the non-missing strata only
expect_true(nrow(result) >= 1)
})
test_that("handles data with unusual variable names", {
data <- create_test_data()
# Rename variables to have spaces and special characters
names(data)[names(data) == "outcome"] <- "my outcome"
names(data)[names(data) == "exposure"] <- "my.exposure"
expect_error(
calc_risk_diff(data, "my outcome", "my.exposure"),
# This should work actually, but let's test with backticks
NA
)
# Test that it works
result <- calc_risk_diff(data, "my outcome", "my.exposure")
expect_s3_class(result, "riskdiff_result")
})
test_that("all link functions can be forced", {
data <- create_test_data()
# Test that all link functions can be specified
result_identity <- calc_risk_diff(data, "outcome", "exposure", link = "identity")
result_log <- calc_risk_diff(data, "outcome", "exposure", link = "log")
result_logit <- calc_risk_diff(data, "outcome", "exposure", link = "logit")
expect_s3_class(result_identity, "riskdiff_result")
expect_s3_class(result_log, "riskdiff_result")
expect_s3_class(result_logit, "riskdiff_result")
# Check that the correct model types are used (when they converge)
if (result_logit$model_type != "failed") {
expect_equal(result_logit$model_type, "logit")
}
})
test_that("extreme confidence levels work", {
data <- create_test_data()
# Test very narrow CI
result_narrow <- calc_risk_diff(data, "outcome", "exposure", alpha = 0.50) # 50% CI
# Test very wide CI
result_wide <- calc_risk_diff(data, "outcome", "exposure", alpha = 0.001) # 99.9% CI
expect_s3_class(result_narrow, "riskdiff_result")
expect_s3_class(result_wide, "riskdiff_result")
# Wide CI should be wider than narrow CI
width_narrow <- result_narrow$ci_upper - result_narrow$ci_lower
width_wide <- result_wide$ci_upper - result_wide$ci_lower
expect_true(width_wide > width_narrow)
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.