Nothing
# ==============================================================================
# Tests for Stochastic Simulation (Chapter 10)
# ==============================================================================
# ------------------------------------------------------------------------------
# Test Haldane's Mapping Function
# ------------------------------------------------------------------------------
test_that("haldane_mapping basic functionality works", {
# Test single value
r <- haldane_mapping(0.1)
expect_type(r, "double")
expect_length(r, 1)
expect_true(r >= 0 && r <= 0.5)
# Test vector input
distances <- c(0.05, 0.1, 0.2, 0.5)
r_vec <- haldane_mapping(distances)
expect_length(r_vec, 4)
expect_true(all(r_vec >= 0 & r_vec <= 0.5))
})
test_that("haldane_mapping edge cases work", {
# Zero distance should give zero recombination
expect_equal(haldane_mapping(0), 0)
# Infinite distance should give 0.5 recombination
expect_equal(haldane_mapping(Inf), 0.5)
# Very small distance
r_small <- haldane_mapping(0.001)
expect_true(r_small > 0 && r_small < 0.001)
# 1 Morgan should give specific value
r_1morgan <- haldane_mapping(1)
expected <- 0.5 * (1 - exp(-2))
expect_equal(r_1morgan, expected, tolerance = 1e-10)
})
test_that("haldane_mapping validates input", {
skip_on_cran() # error handling test or warning test
# Negative distance should error
expect_error(haldane_mapping(-0.1), "non-negative")
})
# ------------------------------------------------------------------------------
# Test Inverse Haldane's Mapping Function
# ------------------------------------------------------------------------------
test_that("inverse_haldane_mapping basic functionality works", {
# Test single value
d <- inverse_haldane_mapping(0.1)
expect_type(d, "double")
expect_length(d, 1)
expect_true(d >= 0)
# Test vector input
r_values <- c(0.05, 0.1, 0.2, 0.4)
d_vec <- inverse_haldane_mapping(r_values)
expect_length(d_vec, 4)
expect_true(all(d_vec >= 0))
})
test_that("inverse_haldane_mapping edge cases work", {
# Zero recombination should give zero distance
expect_equal(inverse_haldane_mapping(0), 0)
# 0.5 recombination should give infinite distance (with warning)
expect_warning(
result <- inverse_haldane_mapping(0.5),
"infinite genetic distance"
)
expect_equal(result, Inf)
# Very small recombination
d_small <- inverse_haldane_mapping(0.001)
expect_true(d_small > 0 && d_small < 0.01)
})
test_that("inverse_haldane_mapping validates input", {
skip_on_cran() # error handling test or warning test
# Negative r should error
expect_error(inverse_haldane_mapping(-0.1), "between 0 and 0.5")
# r > 0.5 should error
expect_error(inverse_haldane_mapping(0.6), "between 0 and 0.5")
})
test_that("haldane and inverse are true inverses", {
# Forward then backward
distances <- c(0.01, 0.1, 0.5, 1.0)
r_values <- haldane_mapping(distances)
d_recovered <- inverse_haldane_mapping(r_values)
expect_equal(d_recovered, distances, tolerance = 1e-10)
# Backward then forward
r_values2 <- c(0.01, 0.1, 0.2, 0.4)
d_values <- inverse_haldane_mapping(r_values2)
r_recovered <- haldane_mapping(d_values)
expect_equal(r_recovered, r_values2, tolerance = 1e-10)
})
# ------------------------------------------------------------------------------
# Test simulate_selection_cycles Basic Functionality
# ------------------------------------------------------------------------------
test_that("simulate_selection_cycles basic functionality works", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(123)
# Small test case
result <- simulate_selection_cycles(
n_cycles = 5,
n_individuals = 100,
n_loci = 20,
n_traits = 2,
heritability = 0.6,
selection_proportion = 0.1,
economic_weights = c(10, 5),
seed = 123
)
# Check result structure
expect_type(result, "list")
expect_s3_class(result, "selection_simulation")
# Check required components
expect_true("lpsi_gain" %in% names(result))
expect_true("esim_gain" %in% names(result))
expect_true("rlpsi_gain" %in% names(result))
expect_true("resim_gain" %in% names(result))
expect_true("lpsi_mean" %in% names(result))
expect_true("esim_mean" %in% names(result))
expect_true("rlpsi_mean" %in% names(result))
expect_true("resim_mean" %in% names(result))
expect_true("parameters" %in% names(result))
# Check dimensions
expect_equal(dim(result$lpsi_gain), c(5, 2))
expect_equal(dim(result$lpsi_mean), c(5, 2))
})
test_that("simulate_selection_cycles with restrictions works", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(456)
result <- simulate_selection_cycles(
n_cycles = 5,
n_individuals = 100,
n_loci = 20,
n_traits = 3,
heritability = 0.6,
selection_proportion = 0.1,
economic_weights = c(10, 5, 3),
restricted_traits = 2,
seed = 456
)
# Check result structure
expect_s3_class(result, "selection_simulation")
expect_equal(dim(result$rlpsi_gain), c(5, 3))
# RLPSI and RESIM should restrict trait 2 gain
# Total gain for trait 2 should be close to zero
total_gain_rlpsi_trait2 <- sum(result$rlpsi_gain[, 2])
total_gain_resim_trait2 <- sum(result$resim_gain[, 2])
expect_true(abs(total_gain_rlpsi_trait2) < 5) # Should be near zero
expect_true(abs(total_gain_resim_trait2) < 5) # Should be near zero
})
test_that("simulate_selection_cycles reproduces with same seed", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
result1 <- simulate_selection_cycles(
n_cycles = 3,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
seed = 789
)
result2 <- simulate_selection_cycles(
n_cycles = 3,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
seed = 789
)
# Results should be identical with same seed
expect_equal(result1$lpsi_mean, result2$lpsi_mean)
expect_equal(result1$esim_gain, result2$esim_gain)
})
# ------------------------------------------------------------------------------
# Test Bulmer Effect (Environmental Variance Constant)
# ------------------------------------------------------------------------------
test_that("Bulmer effect is present (gains decline over time)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(2026)
result <- simulate_selection_cycles(
n_cycles = 20,
n_individuals = 200,
n_loci = 40,
n_traits = 2,
heritability = 0.6,
selection_proportion = 0.05, # High selection intensity
seed = 2026
)
# Check that gains decline over time (Bulmer effect)
# Early cycles should have higher gains than late cycles
early_gains <- mean(result$lpsi_gain[2:5, 1])
late_gains <- mean(result$lpsi_gain[16:20, 1])
expect_true(early_gains > late_gains)
# Late gains should be substantially smaller
decline_ratio <- late_gains / early_gains
expect_true(decline_ratio < 0.5) # At least 50% decline
})
# ------------------------------------------------------------------------------
# Test Robustness to Long Simulations
# ------------------------------------------------------------------------------
test_that("simulate_selection_cycles handles extended cycles without errors", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(2027)
# This should complete without matrix singularity errors
# Thanks to MASS::ginv() robustness
expect_silent({
result <- simulate_selection_cycles(
n_cycles = 30,
n_individuals = 150,
n_loci = 30,
n_traits = 2,
heritability = 0.6,
selection_proportion = 0.05,
seed = 2027
)
})
# Should complete all cycles
expect_equal(nrow(result$lpsi_mean), 30)
expect_equal(nrow(result$esim_gain), 30)
})
# ------------------------------------------------------------------------------
# Test S3 Methods
# ------------------------------------------------------------------------------
test_that("print.selection_simulation works", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(999)
result <- simulate_selection_cycles(
n_cycles = 3,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
seed = 999
)
# Should print without error
expect_output(print(result), "Stochastic Selection")
expect_output(print(result), "LPSI")
expect_output(print(result), "ESIM")
})
test_that("summary.selection_simulation works", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(1000)
result <- simulate_selection_cycles(
n_cycles = 3,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
seed = 1000
)
# Should produce summary without error
expect_output(summary(result), "Simulation Summary")
expect_output(summary(result), "Total Genetic Gain")
expect_output(summary(result), "Mean Genetic Gain per Cycle")
})
test_that("plot.selection_simulation works", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(1001)
result <- simulate_selection_cycles(
n_cycles = 5,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
seed = 1001
)
# Should plot without error
expect_silent(plot(result))
expect_silent(plot(result, trait = 2))
})
# ------------------------------------------------------------------------------
# Test Parameter Validation
# ------------------------------------------------------------------------------
test_that("simulate_selection_cycles validates parameters", {
skip_on_cran() # error handling test or warning test
# n_cycles must be at least 1
expect_error(
simulate_selection_cycles(n_cycles = 0),
"at least 1"
)
# n_individuals must be at least 10
expect_error(
simulate_selection_cycles(n_individuals = 0),
"at least 10"
)
# heritability must be between 0 and 1
expect_error(
simulate_selection_cycles(heritability = 1.5),
"between 0 and 1"
)
# selection_proportion must be between 0 and 1
expect_error(
simulate_selection_cycles(selection_proportion = 1.5),
"between 0 and 1"
)
})
# ------------------------------------------------------------------------------
# Test Restricted vs Unrestricted Indices
# ------------------------------------------------------------------------------
test_that("RLPSI equals LPSI when no restrictions", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(2028)
result <- simulate_selection_cycles(
n_cycles = 5,
n_individuals = 100,
n_loci = 20,
n_traits = 2,
heritability = 0.6,
restricted_traits = NULL, # No restrictions
seed = 2028
)
# Without restrictions, RLPSI should be very similar to LPSI
# (small differences due to sampling)
lpsi_total <- sum(result$lpsi_mean[5, ])
rlpsi_total <- sum(result$rlpsi_mean[5, ])
# Should be within 20% of each other
relative_diff <- abs(lpsi_total - rlpsi_total) / abs(lpsi_total)
expect_true(relative_diff < 0.2)
})
test_that("RESIM behavior when no restrictions", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(2029)
result <- simulate_selection_cycles(
n_cycles = 10,
n_individuals = 200,
n_loci = 40,
n_traits = 2,
heritability = 0.6,
restricted_traits = NULL, # No restrictions
seed = 2029
)
# Without restrictions, both ESIM and RESIM should complete successfully
# (they may give different results due to stochastic variation and different algorithms)
expect_true(all(!is.na(result$esim_mean)))
expect_true(all(!is.na(result$resim_mean)))
# Both should show positive gains overall
esim_final <- sum(result$esim_mean[10, ])
resim_final <- sum(result$resim_mean[10, ])
# Check that both indices produce results (no NAs or infinities)
expect_true(is.finite(esim_final))
expect_true(is.finite(resim_final))
})
# ------------------------------------------------------------------------------
# Test Multiple Traits
# ------------------------------------------------------------------------------
test_that("simulate_selection_cycles works with multiple traits", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(3000)
result <- simulate_selection_cycles(
n_cycles = 5,
n_individuals = 100,
n_loci = 20,
n_traits = 5, # Multiple traits
heritability = 0.6,
economic_weights = c(10, 8, 6, 4, 2),
seed = 3000
)
# Check dimensions
expect_equal(dim(result$lpsi_gain), c(5, 5))
expect_equal(dim(result$lpsi_mean), c(5, 5))
# All indices should work
expect_true(all(!is.na(result$lpsi_gain)))
expect_true(all(!is.na(result$esim_gain)))
expect_true(all(!is.na(result$rlpsi_gain)))
expect_true(all(!is.na(result$resim_gain)))
})
# ------------------------------------------------------------------------------
# Test Different Heritabilities
# ------------------------------------------------------------------------------
test_that("simulate_selection_cycles works with different heritabilities", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(3001)
# High heritability
result_high <- simulate_selection_cycles(
n_cycles = 5,
n_individuals = 100,
n_loci = 20,
n_traits = 2,
heritability = 0.9,
seed = 3001
)
# Low heritability
result_low <- simulate_selection_cycles(
n_cycles = 5,
n_individuals = 100,
n_loci = 20,
n_traits = 2,
heritability = 0.3,
seed = 3001
)
# High heritability should lead to more total gain
gain_high <- sum(abs(result_high$lpsi_gain))
gain_low <- sum(abs(result_low$lpsi_gain))
expect_true(gain_high > gain_low)
})
# ------------------------------------------------------------------------------
# Test Selection Intensity Effects
# ------------------------------------------------------------------------------
test_that("higher selection intensity increases gains", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(3002)
# High selection intensity
result_high <- simulate_selection_cycles(
n_cycles = 5,
n_individuals = 100,
n_loci = 20,
n_traits = 2,
heritability = 0.6,
selection_proportion = 0.05, # Top 5%
seed = 3002
)
# Low selection intensity
result_low <- simulate_selection_cycles(
n_cycles = 5,
n_individuals = 100,
n_loci = 20,
n_traits = 2,
heritability = 0.6,
selection_proportion = 0.3, # Top 30%
seed = 3002
)
# High intensity should lead to more gain per cycle (early cycles)
early_gain_high <- mean(result_high$lpsi_gain[2:3, 1])
early_gain_low <- mean(result_low$lpsi_gain[2:3, 1])
expect_true(early_gain_high > early_gain_low)
})
# ------------------------------------------------------------------------------
# Test Linkage Effects
# ------------------------------------------------------------------------------
test_that("simulate_selection_cycles models linkage correctly", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(3003)
# Tight linkage (small distances)
result_tight <- simulate_selection_cycles(
n_cycles = 10,
n_individuals = 100,
n_loci = 20,
n_traits = 2,
heritability = 0.6,
genetic_distances = rep(0.01, 19), # 0.01 Morgan = 1 cM
seed = 3003
)
# Loose linkage (large distances)
result_loose <- simulate_selection_cycles(
n_cycles = 10,
n_individuals = 100,
n_loci = 20,
n_traits = 2,
heritability = 0.6,
genetic_distances = rep(0.5, 19), # 0.5 Morgan = 50 cM
seed = 3003
)
# Both should complete without error
expect_equal(nrow(result_tight$lpsi_mean), 10)
expect_equal(nrow(result_loose$lpsi_mean), 10)
# Linkage affects recombination and response
# (Detailed test would require more sophisticated genetic analysis)
})
# ------------------------------------------------------------------------------
# Test Error Handling in Eigenvalue Computation
# ------------------------------------------------------------------------------
test_that("eigenvalue checks work (no warnings with valid data)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(3004)
# Normal simulation should not produce eigenvalue warnings
expect_silent({
result <- simulate_selection_cycles(
n_cycles = 5,
n_individuals = 100,
n_loci = 20,
n_traits = 2,
heritability = 0.6,
seed = 3004
)
})
# All eigenvalues should be computed successfully
expect_true(all(!is.na(result$esim_gain)))
expect_true(all(!is.na(result$resim_gain)))
})
# ==============================================================================
# NEW COVERAGE TESTS — targeting previously uncovered lines
# ==============================================================================
# --- .compute_phenotypes: line 285 – scalar environmental_variance expansion --
# Triggered when length(environmental_variance) == 1 → rep(env_var, n_traits).
test_that(".compute_phenotypes expands scalar environmental_variance (line 285)", {
# The helper is internal; access via selection.index:::
set.seed(42)
g_vals <- matrix(rnorm(30), nrow = 10, ncol = 3)
# Pass scalar (not vector) → line 284 check fires, line 285 executes
phenos <- selection.index:::.compute_phenotypes(g_vals, environmental_variance = 2.0)
expect_equal(dim(phenos), c(10, 3))
expect_true(all(is.finite(phenos)))
})
# --- simulate_selection_cycles: line 472 – n_loci < 1 stop -------------------
test_that("simulate_selection_cycles stops when n_loci < 1 (line 472)", {
skip_on_cran() # error handling test or warning test
expect_error(
simulate_selection_cycles(n_loci = 0),
"n_loci must be at least 1"
)
})
# --- simulate_selection_cycles: line 473 – n_traits < 1 stop -----------------
test_that("simulate_selection_cycles stops when n_traits < 1 (line 473)", {
skip_on_cran() # error handling test or warning test
expect_error(
simulate_selection_cycles(n_traits = 0),
"n_traits must be at least 1"
)
})
# --- LPSI tryCatch error handler: lines 579-580 --------------------------------
# Mock cpp_symmetric_solve so it always throws; tryCatch on lines 553-581
# catches it, messages "LPSI failed at cycle ...", and carries last mean forward.
test_that("LPSI error handler fires and carries forward the previous mean (lines 579-580)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(5001)
r <- NULL
# suppressMessages wraps expect_message so that unmatched sibling-index
# messages (e.g. RLPSI also fails when cpp_symmetric_solve is mocked) are
# muffled. expect_message's handler fires first and captures the matched
# message; unmatched ones propagate to suppressMessages which muffles them.
suppressMessages(
expect_message(
{
r <- with_mocked_bindings(
cpp_symmetric_solve = function(...) stop("mocked LPSI failure"),
.package = "selection.index",
simulate_selection_cycles(
n_cycles = 2,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
seed = 5001
)
)
},
"LPSI failed at cycle"
)
)
# Cycle 1 fallback: colMeans(g_lpsi); cycle 2 fallback: lpsi_mean[1, ]
expect_true(all(is.finite(r$lpsi_mean)))
})
# --- ESIM tryCatch error handler: lines 632-633 --------------------------------
# Mock MASS::ginv to throw when called from simulate_selection_cycles context;
# the tryCatch on lines 593-634 catches → message "ESIM failed".
test_that("ESIM error handler fires and carries forward the previous mean (lines 632-633)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(5002)
r <- NULL
suppressMessages(
expect_message(
{
r <- with_mocked_bindings(
eigen = function(x, ...) stop("mocked eigen failure"),
.package = "base",
simulate_selection_cycles(
n_cycles = 2,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
seed = 5002
)
)
},
"ESIM failed at cycle"
)
)
expect_true(all(is.finite(r$esim_mean)))
})
# --- RLPSI tryCatch error handler: lines 691-692 ------------------------------
# Mock cpp_symmetric_solve to throw AND mock MASS::ginv to throw, forcing the
# RLPSI computation (which uses ginv internally) to fail.
test_that("RLPSI error handler fires and carries forward the previous mean (lines 691-692)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(5003)
r <- NULL
suppressMessages(
expect_message(
{
r <- with_mocked_bindings(
cpp_symmetric_solve = function(...) stop("mocked RLPSI failure"),
.package = "selection.index",
simulate_selection_cycles(
n_cycles = 2,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
restricted_traits = NULL,
seed = 5003
)
)
},
"RLPSI failed at cycle"
)
)
expect_true(all(is.finite(r$rlpsi_mean)))
})
# --- RESIM tryCatch error handler: lines 778-779 ------------------------------
# Mock eigen() so the RESIM eigenproblem always throws.
test_that("RESIM error handler fires and carries forward the previous mean (lines 778-779)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(5004)
r <- NULL
suppressMessages(
expect_message(
{
r <- with_mocked_bindings(
eigen = function(x, ...) stop("mocked RESIM eigen failure"),
.package = "base",
simulate_selection_cycles(
n_cycles = 2,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
restricted_traits = NULL,
seed = 5004
)
)
},
"RESIM failed at cycle"
)
)
expect_true(all(is.finite(r$resim_mean)))
})
# --- ESIM imaginary eigenvalue warning: lines 602-603 -------------------------
# Mock eigen() to return a result with large imaginary eigenvalue parts.
# The check `if (max_imag > 1e-5)` then fires the warning at line 602-603.
test_that("ESIM fires imaginary eigenvalue warning when max_imag > 1e-5 (lines 602-603)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(5005)
real_eigen <- base::eigen
first_esim_call <- TRUE
expect_warning(
{
r <- with_mocked_bindings(
eigen = function(x, symmetric = FALSE, ...) {
res <- real_eigen(x, symmetric = symmetric, ...)
if (first_esim_call) {
first_esim_call <<- FALSE
# Inject large imaginary parts into eigenvalues
res$values <- res$values + 1i * 0.01
}
res
},
.package = "base",
simulate_selection_cycles(
n_cycles = 2,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
restricted_traits = NULL,
seed = 5005
)
)
},
"Eigenvalues have significant imaginary parts"
)
expect_s3_class(r, "selection_simulation")
})
# --- RESIM (restricted) imaginary eigenvalue warning: lines 732-733 -----------
# --- RESIM (restricted) imaginary eigenvalue warning: lines 732-733 -----------
# Same approach with restricted_traits and first RESIM call.
test_that("RESIM (restricted) fires imaginary eigenvalue warning (lines 732-733)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(5006)
real_eigen <- base::eigen
eigen_call_count <- 0L
expect_warning(
{
r <- with_mocked_bindings(
eigen = function(x, symmetric = FALSE, ...) {
eigen_call_count <<- eigen_call_count + 1L
res <- real_eigen(x, symmetric = symmetric, ...)
# First call is ESIM, second is restricted RESIM
if (eigen_call_count == 2L) {
res$values <- res$values + 1i * 0.01
}
res
},
.package = "base",
simulate_selection_cycles(
n_cycles = 1,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
restricted_traits = 1L, # forces the restricted RESIM branch
seed = 5006
)
)
},
"RESIM \\(restricted\\).*Eigenvalues have significant imaginary parts"
)
expect_s3_class(r, "selection_simulation")
})
# --- RESIM (unrestricted) imaginary eigenvalue warning: lines 748-749 ---------
# With restricted_traits = NULL, RESIM uses the else branch (lines 740-752).
# Inject imaginary parts specifically for the RESIM unrestricted eigen call.
test_that("RESIM (unrestricted) fires imaginary eigenvalue warning (lines 748-749)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(5007)
real_eigen <- base::eigen
# ESIM calls eigen first; RESIM (unrestricted) calls it second.
# Use a counter to inject imag parts only on the second call per cycle.
eigen_call_count <- 0L
expect_warning(
{
r <- with_mocked_bindings(
eigen = function(x, symmetric = FALSE, ...) {
eigen_call_count <<- eigen_call_count + 1L
res <- real_eigen(x, symmetric = symmetric, ...)
# Second eigen call in each cycle = RESIM unrestricted branch
if (eigen_call_count == 2L) {
res$values <- res$values + 1i * 0.01
}
res
},
.package = "base",
simulate_selection_cycles(
n_cycles = 1,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
restricted_traits = NULL, # unrestricted RESIM path
seed = 5007
)
)
},
"RESIM.*unrestricted.*Eigenvalues have significant imaginary parts|Eigenvalues have significant imaginary parts"
)
expect_s3_class(r, "selection_simulation")
})
# --- print.selection_simulation: line 835 – restricted_traits != NULL ---------
# When restricted_traits is specified, line 834's if-check fires and line 835
# prints the restricted trait indices. Existing tests use NULL restricted_traits.
test_that("print.selection_simulation prints restricted traits line (line 835)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(5008)
r <- simulate_selection_cycles(
n_cycles = 2,
n_individuals = 50,
n_loci = 10,
n_traits = 3,
restricted_traits = 2L,
seed = 5008
)
# Line 834 `if (!is.null(x$parameters$restricted_traits))` fires → line 835
out <- capture.output(print(r))
expect_true(any(grepl("Restricted traits", out, fixed = TRUE)))
expect_true(any(grepl("2", out, fixed = TRUE)))
})
# --- plot.selection_simulation type="gain": lines 906-915 --------------------
# The default plot type is "mean" (lines 892-902). "gain" hits the else branch
# at lines 904-915.
test_that("plot.selection_simulation type='gain' branch works (lines 906-915)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
set.seed(5009)
r <- simulate_selection_cycles(
n_cycles = 5,
n_individuals = 50,
n_loci = 10,
n_traits = 2,
seed = 5009
)
# Should plot without error on the "gain" branch
expect_silent(plot(r, type = "gain"))
# Also test trait_index != 1 within gain branch
expect_silent(plot(r, type = "gain", trait_index = 2))
})
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.