#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ttest_1samp() {
let sample = vec![2.3, 2.5, 2.7, 2.9, 3.1];
let result = ttest_1samp(&sample, 2.5).expect("Valid t-test");
assert!(result.statistic > 0.0, "t-statistic should be positive");
assert!(result.pvalue > 0.0 && result.pvalue < 1.0);
assert_eq!(result.df, 4.0);
}
#[test]
fn test_ttest_ind_equal_var() {
let group1 = vec![2.3, 2.5, 2.7, 2.9, 3.1];
let group2 = vec![3.2, 3.4, 3.6, 3.8, 4.0];
let result = ttest_ind(&group1, &group2, true).expect("Valid t-test");
assert!(result.statistic < 0.0, "t-statistic should be negative");
assert!(result.pvalue > 0.0 && result.pvalue < 1.0);
assert_eq!(result.df, 8.0); }
#[test]
fn test_ttest_ind_unequal_var() {
let group1 = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let group2 = vec![10.0, 11.0, 12.0];
let result = ttest_ind(&group1, &group2, false).expect("Valid Welch's t-test");
assert!(result.statistic < 0.0); assert!(result.pvalue > 0.0 && result.pvalue < 1.0);
assert!(result.df > 0.0); }
#[test]
fn test_ttest_rel() {
let before = vec![120.0, 122.0, 125.0, 128.0, 130.0];
let after = vec![115.0, 118.0, 120.0, 123.0, 125.0];
let result = ttest_rel(&before, &after).expect("Valid paired t-test");
assert!(result.statistic > 0.0);
assert!(result.pvalue > 0.0 && result.pvalue < 1.0);
assert_eq!(result.df, 4.0); }
#[test]
fn test_ttest_rel_dimension_mismatch() {
let sample1 = vec![1.0, 2.0, 3.0];
let sample2 = vec![4.0, 5.0];
let result = ttest_rel(&sample1, &sample2);
assert!(result.is_err());
let err = result.expect_err("Should be a dimension mismatch error");
assert!(matches!(err, AprenderError::DimensionMismatch { .. }));
}
#[test]
fn test_ttest_insufficient_data() {
let sample = vec![1.0]; let result = ttest_1samp(&sample, 0.0);
assert!(result.is_err());
}
#[test]
fn test_chisquare_goodness_of_fit() {
let observed = vec![8.0, 12.0, 10.0, 15.0, 9.0, 6.0];
let expected = vec![10.0, 10.0, 10.0, 10.0, 10.0, 10.0];
let result = chisquare(&observed, &expected).expect("Valid chi-square test");
assert!(result.statistic > 0.0);
assert!(result.pvalue > 0.0 && result.pvalue < 1.0);
assert_eq!(result.df, 5); }
#[test]
fn test_chisquare_dimension_mismatch() {
let observed = vec![10.0, 20.0, 30.0];
let expected = vec![15.0, 25.0];
let result = chisquare(&observed, &expected);
assert!(result.is_err());
let err = result.expect_err("Should be a dimension mismatch error");
assert!(matches!(err, AprenderError::DimensionMismatch { .. }));
}
#[test]
fn test_chisquare_invalid_expected() {
let observed = vec![10.0, 20.0, 30.0];
let expected = vec![15.0, 0.0, 25.0];
let result = chisquare(&observed, &expected);
assert!(result.is_err());
}
#[test]
fn test_f_oneway() {
let group1 = vec![2.0, 2.5, 3.0, 2.8, 2.7];
let group2 = vec![3.5, 3.8, 4.0, 3.7, 3.9];
let group3 = vec![5.0, 5.2, 4.8, 5.1, 4.9];
let result = f_oneway(&[group1, group2, group3]).expect("Valid ANOVA");
assert!(result.statistic > 0.0);
assert!(result.pvalue > 0.0 && result.pvalue < 1.0);
assert_eq!(result.df_between, 2); assert_eq!(result.df_within, 12); }
#[test]
fn test_f_oneway_no_difference() {
let group1 = vec![3.0, 3.0, 3.0];
let group2 = vec![3.0, 3.0, 3.0];
let group3 = vec![3.0, 3.0, 3.0];
let result = f_oneway(&[group1, group2, group3]).expect("Valid ANOVA");
assert!(result.statistic >= 0.0 || result.statistic.is_nan());
}
#[test]
fn test_f_oneway_insufficient_groups() {
let group1 = vec![1.0, 2.0, 3.0];
let result = f_oneway(&[group1]);
assert!(result.is_err());
}
#[test]
fn test_f_oneway_empty_group() {
let group1 = vec![1.0, 2.0, 3.0];
let group2 = vec![]; let group3 = vec![4.0, 5.0, 6.0];
let result = f_oneway(&[group1, group2, group3]);
assert!(result.is_err());
}
#[test]
fn test_normal_cdf() {
assert!((normal_cdf(0.0) - 0.5).abs() < 0.01);
assert!(normal_cdf(1.96) > 0.97); assert!(normal_cdf(-1.96) < 0.03); }
#[test]
fn test_erf() {
assert!((erf(0.0) - 0.0).abs() < 0.01);
assert!(erf(1.0) > 0.8); assert!(erf(-1.0) < -0.8); }
#[test]
fn test_gamma() {
assert!((gamma(1.0) - 1.0).abs() < 0.1);
assert!((gamma(2.0) - 1.0).abs() < 0.1);
assert!((gamma(3.0) - 2.0).abs() < 0.2);
assert!((gamma(4.0) - 6.0).abs() < 0.5);
}
#[test]
fn test_real_world_treatment_comparison() {
let control = vec![5.0, 7.0, 6.0, 8.0, 5.5, 6.5];
let treatment = vec![12.0, 14.0, 13.0, 15.0, 11.0, 13.5];
let result = ttest_ind(&control, &treatment, true).expect("Valid comparison");
assert!(result.statistic < 0.0);
assert!(result.pvalue < 0.1, "Should show significant difference");
}
#[test]
fn test_ttest_result_debug_clone() {
let result = ttest_1samp(&[2.0, 3.0, 4.0, 5.0, 6.0], 4.0).expect("Valid t-test");
let debug_str = format!("{:?}", result);
assert!(debug_str.contains("TTestResult"));
assert!(debug_str.contains("statistic"));
let cloned = result.clone();
assert!((cloned.statistic - result.statistic).abs() < 1e-10);
assert!((cloned.pvalue - result.pvalue).abs() < 1e-10);
assert!((cloned.df - result.df).abs() < 1e-10);
}
#[test]
fn test_chi_square_result_debug_clone() {
let observed = vec![10.0, 20.0, 30.0];
let expected = vec![20.0, 20.0, 20.0];
let result = chisquare(&observed, &expected).expect("Valid chi-square");
let debug_str = format!("{:?}", result);
assert!(debug_str.contains("ChiSquareResult"));
let cloned = result.clone();
assert!((cloned.statistic - result.statistic).abs() < 1e-10);
assert_eq!(cloned.df, result.df);
}
#[test]
fn test_anova_result_debug_clone() {
let g1 = vec![1.0, 2.0, 3.0];
let g2 = vec![4.0, 5.0, 6.0];
let result = f_oneway(&[g1, g2]).expect("Valid ANOVA");
let debug_str = format!("{:?}", result);
assert!(debug_str.contains("AnovaResult"));
let cloned = result.clone();
assert!((cloned.statistic - result.statistic).abs() < 1e-10);
assert_eq!(cloned.df_between, result.df_between);
assert_eq!(cloned.df_within, result.df_within);
}
#[test]
fn test_ttest_ind_first_sample_too_small() {
let s1 = vec![1.0]; let s2 = vec![2.0, 3.0, 4.0];
let result = ttest_ind(&s1, &s2, true);
assert!(result.is_err());
}
#[test]
fn test_ttest_ind_second_sample_too_small() {
let s1 = vec![1.0, 2.0, 3.0];
let s2 = vec![4.0]; let result = ttest_ind(&s1, &s2, false);
assert!(result.is_err());
}
#[test]
fn test_chisquare_too_few_categories() {
let observed = vec![10.0];
let expected = vec![10.0];
let result = chisquare(&observed, &expected);
assert!(result.is_err());
}
#[test]
fn test_chisquare_negative_expected() {
let observed = vec![10.0, 20.0, 30.0];
let expected = vec![15.0, -5.0, 20.0]; let result = chisquare(&observed, &expected);
assert!(result.is_err());
}
#[test]
fn test_f_oneway_zero_groups() {
let groups: &[Vec<f32>] = &[];
let result = f_oneway(groups);
assert!(result.is_err());
}
#[test]
fn test_f_oneway_single_observation_per_group() {
let g1 = vec![1.0];
let g2 = vec![5.0];
let result = f_oneway(&[g1, g2]);
assert!(result.is_err());
}
#[test]
fn test_t_distribution_large_df_uses_normal_approx() {
let large_sample: Vec<f32> = (0..50).map(|i| i as f32 * 0.1).collect();
let result = ttest_1samp(&large_sample, 0.0).expect("Valid t-test with large n");
assert!(result.df > 30.0);
assert!(result.pvalue >= 0.0 && result.pvalue <= 1.0);
}
#[test]
fn test_incomplete_beta_boundary_zero() {
let val = incomplete_beta(1.0, 1.0, 0.0);
assert!((val - 0.0).abs() < 1e-6);
}
#[test]
fn test_incomplete_beta_boundary_one() {
let val = incomplete_beta(1.0, 1.0, 1.0);
assert!((val - 1.0).abs() < 1e-6);
}
#[test]
fn test_incomplete_beta_else_branch() {
let val = incomplete_beta(1.0, 1.0, 0.8);
assert!(val > 0.0 && val <= 1.0);
}
#[test]
fn test_incomplete_beta_if_branch() {
let val = incomplete_beta(1.0, 1.0, 0.2);
assert!(val > 0.0 && val < 1.0);
}
#[test]
fn test_incomplete_gamma_zero_x() {
let val = incomplete_gamma(1.0, 0.0);
assert!((val - 0.0).abs() < 1e-6);
}
#[test]
fn test_incomplete_gamma_negative_x() {
let val = incomplete_gamma(1.0, -1.0);
assert!((val - 0.0).abs() < 1e-6);
}
#[test]
fn test_incomplete_gamma_zero_a() {
let val = incomplete_gamma(0.0, 1.0);
assert!((val - 1.0).abs() < 1e-6);
}
#[test]
fn test_incomplete_gamma_negative_a() {
let val = incomplete_gamma(-1.0, 1.0);
assert!((val - 1.0).abs() < 1e-6);
}
#[test]
fn test_gamma_reflection_formula() {
let val = gamma(0.3);
assert!(
val > 2.5 && val < 3.5,
"Gamma(0.3) should be ~2.99, got {val}"
);
}
#[test]
fn test_gamma_half() {
let val = gamma(0.5);
let sqrt_pi = std::f32::consts::PI.sqrt();
assert!(
(val - sqrt_pi).abs() < 0.2,
"Gamma(0.5) should be ~sqrt(pi)={sqrt_pi}, got {val}"
);
}
#[test]
fn test_erf_large_positive() {
let val = erf(3.0);
assert!(val > 0.99, "erf(3.0) should be ~1.0, got {val}");
}
#[test]
fn test_erf_large_negative() {
let val = erf(-3.0);
assert!(val < -0.99, "erf(-3.0) should be ~-1.0, got {val}");
}
#[test]
fn test_normal_cdf_extreme_positive() {
let val = normal_cdf(5.0);
assert!(val > 0.999, "Normal CDF at z=5 should be ~1.0");
}
#[test]
fn test_normal_cdf_extreme_negative() {
let val = normal_cdf(-5.0);
assert!(val < 0.001, "Normal CDF at z=-5 should be ~0.0");
}
#[test]
fn test_chi_square_pvalue_range() {
let pval = chi_square_pvalue(5.0, 3);
assert!(pval >= 0.0 && pval <= 1.0);
}
#[test]
fn test_f_distribution_pvalue_range() {
let pval = f_distribution_pvalue(3.0, 2, 10);
assert!(pval >= 0.0 && pval <= 1.0);
}
#[test]
fn test_beta_function_basic() {
let val = beta_function(1.0, 1.0);
assert!((val - 1.0).abs() < 0.2, "B(1,1) should be ~1.0, got {val}");
}
#[test]
fn test_ttest_1samp_mean_equals_population_mean() {
let sample = vec![10.0, 10.0, 10.0, 10.0, 10.0];
let result = ttest_1samp(&sample, 10.0).expect("Valid t-test");
assert!(
result.statistic.abs() < 1e-6 || result.statistic.is_nan(),
"t-stat should be ~0 when means match"
);
}
#[test]
fn test_ttest_ind_equal_var_identical_samples() {
let s = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let result = ttest_ind(&s, &s, true).expect("Valid t-test");
assert!(
result.statistic.abs() < 1e-6,
"t-stat should be 0 for identical samples"
);
}
#[test]
fn test_ttest_ind_welch_identical_samples() {
let s = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let result = ttest_ind(&s, &s, false).expect("Valid Welch's t-test");
assert!(
result.statistic.abs() < 1e-6,
"t-stat should be 0 for identical samples"
);
}
}