use crate::runtime::config::*;
use proptest::prelude::*;
#[test]
fn mr1_validation_consistency() {
proptest!(|(
worker_threads in 1usize..=64,
stack_size_mb in 1usize..=64,
poll_budget in 1u32..=1000
)| {
let direct_config = RuntimeConfig {
worker_threads,
thread_stack_size: stack_size_mb * 1024 * 1024,
poll_budget,
..Default::default()
};
let is_valid_workers = worker_threads > 0 && worker_threads <= 64;
let is_valid_stack = stack_size_mb >= 1;
let is_valid_budget = poll_budget > 0;
let _expected_valid = is_valid_workers && is_valid_stack && is_valid_budget;
prop_assert_eq!(direct_config.worker_threads, worker_threads,
"Worker threads should be preserved");
prop_assert_eq!(direct_config.thread_stack_size, stack_size_mb * 1024 * 1024,
"Stack size should be preserved");
prop_assert_eq!(direct_config.poll_budget, poll_budget,
"Poll budget should be preserved");
});
}
#[test]
fn mr2_default_stability() {
proptest!(|(_dummy in 0..10u32)| {
let default1 = RuntimeConfig::default();
let default2 = RuntimeConfig::default();
prop_assert_eq!(default1.worker_threads, default2.worker_threads,
"Default worker threads should be stable");
prop_assert_eq!(default1.thread_stack_size, default2.thread_stack_size,
"Default stack size should be stable");
prop_assert_eq!(default1.poll_budget, default2.poll_budget,
"Default poll budget should be stable");
prop_assert!(default1.worker_threads > 0 && default1.worker_threads <= 128,
"Default worker threads should be reasonable: {}", default1.worker_threads);
prop_assert!(default1.thread_stack_size >= 1024 * 1024,
"Default stack size should be at least 1MB: {}", default1.thread_stack_size);
prop_assert!(default1.poll_budget > 0,
"Default poll budget should be positive: {}", default1.poll_budget);
});
}
#[test]
fn mr3_constraint_relationships() {
proptest!(|(
base_workers in 1usize..=16,
multiplier in 1usize..=4,
batch_size in 1usize..=64
)| {
let mut config = RuntimeConfig::default();
config.worker_threads = base_workers;
config.steal_batch_size = batch_size;
let scaled_workers = base_workers * multiplier;
let scaled_config = RuntimeConfig {
worker_threads: scaled_workers,
steal_batch_size: batch_size,
..config
};
prop_assert!(scaled_config.worker_threads > 0,
"Worker threads must be positive");
prop_assert!(scaled_config.steal_batch_size > 0,
"Steal batch size must be positive");
if scaled_workers > base_workers {
prop_assert!(scaled_config.steal_batch_size >= 1,
"Steal batch size should be at least 1 with more workers");
}
});
}
#[test]
fn mr4_config_composition() {
proptest!(|(
base_workers in 1usize..=8,
override_stack_mb in 2usize..=16,
override_budget in 32u32..=512
)| {
let base_config = RuntimeConfig {
worker_threads: base_workers,
..Default::default()
};
let composed_config = RuntimeConfig {
worker_threads: base_config.worker_threads,
thread_stack_size: override_stack_mb * 1024 * 1024,
poll_budget: override_budget,
..base_config
};
prop_assert_eq!(composed_config.worker_threads, base_config.worker_threads,
"Worker threads should be preserved in composition");
prop_assert_eq!(composed_config.thread_stack_size, override_stack_mb * 1024 * 1024,
"Stack size should be overridden in composition");
prop_assert_eq!(composed_config.poll_budget, override_budget,
"Poll budget should be overridden in composition");
prop_assert!(composed_config.worker_threads > 0,
"Composed config should have positive worker threads");
prop_assert!(composed_config.thread_stack_size >= 1024 * 1024,
"Composed config should have reasonable stack size");
prop_assert!(composed_config.poll_budget > 0,
"Composed config should have positive poll budget");
});
}
#[test]
fn mr5_scale_invariance() {
proptest!(|(
base_workers in 2usize..=8,
base_batch in 4usize..=32,
scale_factor in 2usize..=4
)| {
let base_config = RuntimeConfig {
worker_threads: base_workers,
steal_batch_size: base_batch,
..Default::default()
};
let scaled_config = RuntimeConfig {
worker_threads: base_workers * scale_factor,
steal_batch_size: base_batch * scale_factor,
..base_config
};
let base_ratio = base_config.steal_batch_size as f64 / base_config.worker_threads as f64;
let scaled_ratio = scaled_config.steal_batch_size as f64 / scaled_config.worker_threads as f64;
let ratio_diff = (base_ratio - scaled_ratio).abs();
prop_assert!(ratio_diff < 1e-10,
"Scaling should preserve ratios: {} vs {} (diff: {})",
base_ratio, scaled_ratio, ratio_diff);
prop_assert!(scaled_config.worker_threads > 0,
"Scaled worker threads should be positive");
prop_assert!(scaled_config.steal_batch_size > 0,
"Scaled steal batch size should be positive");
});
}
#[test]
fn mr6_boundary_behavior() {
proptest!(|(test_cases in prop::collection::vec((0usize..=2_000, 0u32..=2_000), 1..=10))| {
prop_assume!(!test_cases.is_empty() && test_cases.len() <= 10);
for (workers, budget) in test_cases {
let config = RuntimeConfig {
worker_threads: workers,
poll_budget: budget,
..Default::default()
};
prop_assert_eq!(config.worker_threads, workers);
prop_assert_eq!(config.poll_budget, budget);
}
});
}
#[cfg(test)]
mod integration_tests {
use super::*;
#[test]
fn mr_composition_default_with_overrides() {
let base = RuntimeConfig::default();
let custom = RuntimeConfig {
worker_threads: 8,
poll_budget: 256,
..base
};
assert_eq!(custom.worker_threads, 8);
assert_eq!(custom.poll_budget, 256);
assert_eq!(custom.thread_stack_size, base.thread_stack_size);
assert_eq!(custom.steal_batch_size, base.steal_batch_size);
}
#[test]
fn mr_validation_comprehensive_properties() {
let config = RuntimeConfig {
worker_threads: 4,
thread_stack_size: 2 * 1024 * 1024, poll_budget: 128,
steal_batch_size: 16,
..Default::default()
};
assert!(config.worker_threads > 0);
assert!(config.thread_stack_size >= 1024 * 1024);
assert!(config.poll_budget > 0);
assert!(config.steal_batch_size > 0);
assert!(config.worker_threads <= 128);
assert!(config.thread_stack_size <= 64 * 1024 * 1024);
assert!(config.poll_budget <= 10000);
assert!(config.steal_batch_size <= 1000);
}
}