#![allow(clippy::float_cmp)]
use super::*;
#[test]
fn test_financial_returns_bootstrap() {
let returns = vec![
0.05, -0.02, 0.08, 0.03, -0.05, 0.12, 0.01, -0.01, 0.06, 0.04, 0.02, -0.03, 0.07, 0.04,
-0.02, 0.09, 0.00, -0.04, 0.05, 0.03,
];
let config = BootstrapConfig::new()
.with_data(returns)
.with_iterations(10000)
.with_seed(12345)
.with_confidence_levels(vec![0.90, 0.95, 0.99]);
let mut engine = BootstrapEngine::new(config).unwrap();
let result = engine.analyze().unwrap();
let expected_mean: f64 = vec![
0.05, -0.02, 0.08, 0.03, -0.05, 0.12, 0.01, -0.01, 0.06, 0.04, 0.02, -0.03, 0.07, 0.04,
-0.02, 0.09, 0.00, -0.04, 0.05, 0.03,
]
.iter()
.sum::<f64>()
/ 20.0;
assert!(
(result.original_estimate - expected_mean).abs() < 0.001,
"Original estimate should match calculated mean"
);
assert_eq!(result.confidence_intervals.len(), 3);
let widths: Vec<f64> = result
.confidence_intervals
.iter()
.map(super::engine::ConfidenceInterval::width)
.collect();
for i in 0..widths.len() - 1 {
let ci_current = &result.confidence_intervals[i];
let ci_next = &result.confidence_intervals[i + 1];
if ci_current.level < ci_next.level {
assert!(
widths[i] <= widths[i + 1],
"Higher confidence should mean wider interval"
);
}
}
}
#[test]
fn test_std_bootstrap() {
let data = vec![10.0, 12.0, 23.0, 23.0, 16.0, 23.0, 21.0, 16.0];
let config = BootstrapConfig::new()
.with_data(data.clone())
.with_statistic(BootstrapStatistic::Std)
.with_iterations(5000)
.with_seed(42);
let mut engine = BootstrapEngine::new(config).unwrap();
let result = engine.analyze().unwrap();
let mean = data.iter().sum::<f64>() / data.len() as f64;
let var = data.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (data.len() - 1) as f64;
let expected_std = var.sqrt();
assert!(
(result.original_estimate - expected_std).abs() < 0.01,
"Original std should match"
);
}
#[test]
fn test_variance_bootstrap() {
let data = vec![2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
let config = BootstrapConfig::new()
.with_data(data.clone())
.with_statistic(BootstrapStatistic::Var)
.with_iterations(5000)
.with_seed(42);
let mut engine = BootstrapEngine::new(config).unwrap();
let result = engine.analyze().unwrap();
let mean = data.iter().sum::<f64>() / data.len() as f64;
let expected_var =
data.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (data.len() - 1) as f64;
assert!(
(result.original_estimate - expected_var).abs() < 0.01,
"Original variance should match"
);
}
#[test]
fn test_percentile_bootstrap() {
let data: Vec<f64> = (1..=100).map(f64::from).collect();
let config = BootstrapConfig::new()
.with_data(data)
.with_percentile(75.0)
.with_iterations(5000)
.with_seed(42);
let mut engine = BootstrapEngine::new(config).unwrap();
let result = engine.analyze().unwrap();
assert!(
(result.original_estimate - 75.0).abs() < 2.0,
"75th percentile should be around 75"
);
}
#[test]
fn test_bias_estimation() {
let data: Vec<f64> = vec![-5.0, -3.0, -1.0, 0.0, 1.0, 3.0, 5.0];
let config = BootstrapConfig::new()
.with_data(data)
.with_iterations(10000)
.with_seed(42);
let mut engine = BootstrapEngine::new(config).unwrap();
let result = engine.analyze().unwrap();
assert!(
result.bias.abs() < 0.5,
"Bias should be small for symmetric data: {}",
result.bias
);
}
#[test]
fn test_skewed_data() {
let data = vec![
20_000.0, 25_000.0, 30_000.0, 32_000.0, 35_000.0, 40_000.0, 45_000.0, 50_000.0, 80_000.0,
150_000.0,
];
let config = BootstrapConfig::new()
.with_data(data)
.with_iterations(10000)
.with_seed(42)
.with_confidence_levels(vec![0.95]);
let mut engine = BootstrapEngine::new(config).unwrap();
let result = engine.analyze().unwrap();
let ci = &result.confidence_intervals[0];
assert!(
ci.lower <= result.original_estimate && result.original_estimate <= ci.upper,
"CI should contain original estimate"
);
}
#[test]
fn test_min_max_bootstrap() {
let data = vec![1.0, 5.0, 3.0, 9.0, 2.0, 8.0, 4.0, 7.0, 6.0, 10.0];
let config_min = BootstrapConfig::new()
.with_data(data.clone())
.with_statistic(BootstrapStatistic::Min)
.with_iterations(1000)
.with_seed(42);
let mut engine_min = BootstrapEngine::new(config_min).unwrap();
let result_min = engine_min.analyze().unwrap();
assert_eq!(result_min.original_estimate, 1.0);
let config_max = BootstrapConfig::new()
.with_data(data)
.with_statistic(BootstrapStatistic::Max)
.with_iterations(1000)
.with_seed(42);
let mut engine_max = BootstrapEngine::new(config_max).unwrap();
let result_max = engine_max.analyze().unwrap();
assert_eq!(result_max.original_estimate, 10.0);
}
#[test]
fn test_bias_corrected() {
let data: Vec<f64> = (1..=50).map(f64::from).collect();
let config = BootstrapConfig::new()
.with_data(data)
.with_iterations(5000)
.with_seed(42);
let mut engine = BootstrapEngine::new(config).unwrap();
let result = engine.analyze().unwrap();
let bc_estimate = result.bias_corrected_estimate();
assert!(
(bc_estimate - result.original_estimate).abs() < 1.0,
"Bias-corrected should be close to original"
);
}
#[test]
fn test_r_boot_package_validation() {
let data = vec![49.0, 52.0, 53.0, 54.0, 54.0, 54.0, 55.0, 56.0, 57.0, 57.0];
let config = BootstrapConfig::new()
.with_data(data)
.with_iterations(10000)
.with_seed(12345)
.with_confidence_levels(vec![0.95]);
let mut engine = BootstrapEngine::new(config).unwrap();
let result = engine.analyze().unwrap();
assert!(
(result.original_estimate - 54.1).abs() < 0.01,
"Original mean should be 54.1"
);
let ci = &result.confidence_intervals[0];
assert!(
ci.lower > 50.0 && ci.lower < 54.0,
"Lower bound should be reasonable"
);
assert!(
ci.upper > 54.0 && ci.upper < 58.0,
"Upper bound should be reasonable"
);
}
#[test]
fn test_json_export() {
let config = BootstrapConfig::new()
.with_data(vec![1.0, 2.0, 3.0, 4.0, 5.0])
.with_iterations(100)
.with_seed(42);
let mut engine = BootstrapEngine::new(config).unwrap();
let result = engine.analyze().unwrap();
let json = result.to_json().unwrap();
assert!(json.contains("\"original_estimate\""));
assert!(json.contains("\"bootstrap_std_error\""));
assert!(json.contains("\"confidence_intervals\""));
}