use linreg_core::diagnostics::{harvey_collier_test, rainbow_test, reset_test, HarveyCollierMethod, RainbowMethod, ResetType};
use linreg_core::error::Error;
fn approx_eq(a: f64, b: f64, tol: f64) -> bool {
(a - b).abs() < tol
}
#[test]
fn test_rainbow_insufficient_data() {
let y = vec![1.0, 2.0, 3.0];
let x = vec![1.0, 2.0, 3.0];
let result = rainbow_test(&y, &[x], 0.5, RainbowMethod::R);
match result {
Err(Error::InsufficientData { .. }) => (),
_ => panic!("Expected InsufficientData error"),
}
}
#[test]
fn test_rainbow_linear_data() {
let y: Vec<f64> = (1..=20).map(|i| 2.0 * (i as f64) + 1.0).collect();
let x: Vec<f64> = (1..=20).map(|i| i as f64).collect();
let result = rainbow_test(&y, &[x], 0.5, RainbowMethod::R).unwrap();
if let Some(r_single) = result.r_result {
assert!(r_single.p_value > 0.05);
assert_eq!(r_single.passed, r_single.p_value > 0.05);
}
assert!(result.test_name.contains("Rainbow"));
}
#[test]
fn test_rainbow_nonlinear_data() {
let y: Vec<f64> = (1..=20).map(|i| (i as f64).powi(2)).collect();
let x: Vec<f64> = (1..=20).map(|i| i as f64).collect();
let result = rainbow_test(&y, &[x], 0.5, RainbowMethod::R).unwrap();
if let Some(r_single) = result.r_result {
assert!(r_single.p_value < 0.05);
assert_eq!(r_single.passed, false);
}
}
#[test]
fn test_rainbow_fraction_parameter() {
let y: Vec<f64> = (1..=20).map(|i| 2.0 * (i as f64) + 1.0).collect();
let x: Vec<f64> = (1..=20).map(|i| i as f64).collect();
let result_30 = rainbow_test(&y, &[x.clone()], 0.3, RainbowMethod::R);
let result_50 = rainbow_test(&y, &[x], 0.5, RainbowMethod::R);
assert!(result_30.is_ok());
assert!(result_50.is_ok());
let r30 = result_30.unwrap();
let r50 = result_50.unwrap();
if let Some(r30_single) = r30.r_result {
assert!(r30_single.p_value > 0.05);
}
if let Some(r50_single) = r50.r_result {
assert!(r50_single.p_value > 0.05);
}
}
#[test]
fn test_rainbow_methods_consistency() {
let y: Vec<f64> = (1..=20).map(|i| (i as f64) * 1.5 + 5.0).collect();
let x: Vec<f64> = (1..=20).map(|i| i as f64).collect();
let result_r = rainbow_test(&y, &[x.clone()], 0.5, RainbowMethod::R).unwrap();
let result_python = rainbow_test(&y, &[x.clone()], 0.5, RainbowMethod::Python).unwrap();
let result_both = rainbow_test(&y, &[x], 0.5, RainbowMethod::Both).unwrap();
assert!(!result_r.test_name.is_empty());
assert!(!result_python.test_name.is_empty());
assert!(!result_both.test_name.is_empty());
if let (Some(r_single), Some(py_single)) =
(result_r.r_result, result_python.python_result)
{
assert_eq!(r_single.passed, r_single.p_value > 0.05);
assert_eq!(py_single.passed, py_single.p_value > 0.05);
}
}
#[test]
fn test_rainbow_output_structure() {
let y = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
let x = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
let result = rainbow_test(&y, &[x], 0.5, RainbowMethod::R).unwrap();
assert!(!result.test_name.is_empty());
if let Some(r_single) = result.r_result {
assert!(r_single.statistic.is_finite());
assert!(r_single.p_value.is_finite());
assert!(r_single.p_value >= 0.0 && r_single.p_value <= 1.0);
}
assert!(!result.interpretation.is_empty());
assert!(!result.guidance.is_empty());
}
#[test]
fn test_harvey_collier_insufficient_data() {
let y = vec![1.0, 2.0, 3.0];
let x = vec![1.0, 2.0, 3.0];
let result = harvey_collier_test(&y, &[x], HarveyCollierMethod::R);
match result {
Err(Error::InsufficientData { .. }) => (),
_ => panic!("Expected InsufficientData error"),
}
}
#[test]
fn test_harvey_collier_linear_data() {
let y: Vec<f64> = (1..=20).map(|i| 2.0 * (i as f64) + 1.0 + 0.01 * ((i % 5) as f64 - 2.0)).collect();
let x: Vec<f64> = (1..=20).map(|i| i as f64).collect();
let result = harvey_collier_test(&y, &[x], HarveyCollierMethod::R).unwrap();
assert!(result.p_value > 0.05);
assert_eq!(result.passed, result.p_value > 0.05);
assert!(result.test_name.contains("Harvey-Collier"));
}
#[test]
fn test_harvey_collier_nonlinear_data() {
let y: Vec<f64> = (1..=20).map(|i| (i as f64).powi(2) * 0.5 + (i as f64)).collect();
let x: Vec<f64> = (1..=20).map(|i| i as f64).collect();
let result = harvey_collier_test(&y, &[x], HarveyCollierMethod::R).unwrap();
assert!(result.statistic.is_finite());
assert!(result.p_value.is_finite());
}
#[test]
fn test_harvey_collier_output_structure() {
let y: Vec<f64> = (1..=10).map(|i| i as f64 + 0.01 * ((i % 3) as f64 - 1.0)).collect();
let x: Vec<f64> = (1..=10).map(|i| i as f64).collect();
let result = harvey_collier_test(&y, &[x], HarveyCollierMethod::R).unwrap();
assert!(!result.test_name.is_empty());
assert!(result.statistic.is_finite());
assert!(result.p_value.is_finite());
assert!(result.p_value >= 0.0 && result.p_value <= 1.0);
assert!(!result.interpretation.is_empty());
assert!(!result.guidance.is_empty());
}
#[test]
fn test_reset_insufficient_data() {
let y = vec![1.0, 2.0, 3.0];
let x = vec![1.0, 2.0, 3.0];
let result = reset_test(&y, &[x], &[2, 3], ResetType::Fitted);
match result {
Err(Error::InsufficientData { .. }) => (),
_ => panic!("Expected InsufficientData error"),
}
}
#[test]
fn test_reset_correct_specification() {
let y: Vec<f64> = (1..=30).map(|i| 2.0 * (i as f64) + 1.0 + 0.5 * (i as f64).ln()).collect();
let x: Vec<f64> = (1..=30).map(|i| i as f64).collect();
let result = reset_test(&y, &[x], &[2, 3], ResetType::Fitted).unwrap();
assert!(result.statistic.is_finite());
assert!(result.p_value.is_finite());
}
#[test]
fn test_reset_omitted_variable() {
let y: Vec<f64> = (1..=20).map(|i| (i as f64).powi(2) + (i as f64) + 1.0).collect();
let x: Vec<f64> = (1..=20).map(|i| i as f64).collect();
let result = reset_test(&y, &[x], &[2, 3], ResetType::Fitted).unwrap();
assert!(result.statistic.is_finite());
assert!(result.p_value.is_finite());
}
#[test]
fn test_reset_types() {
let y: Vec<f64> = (1..=20).map(|i| (i as f64) * 2.0 + 1.0).collect();
let x: Vec<f64> = (1..=20).map(|i| i as f64).collect();
let result_fitted = reset_test(&y, &[x.clone()], &[2], ResetType::Fitted);
let result_regressor = reset_test(&y, &[x.clone()], &[2], ResetType::Regressor);
let result_pc = reset_test(&y, &[x], &[2], ResetType::PrincipalComponent);
assert!(result_fitted.is_ok());
assert!(result_regressor.is_ok());
assert!(result_pc.is_ok());
let r_fitted = result_fitted.unwrap();
assert!(r_fitted.statistic.is_finite());
assert!(r_fitted.p_value.is_finite());
}
#[test]
fn test_reset_multiple_powers() {
let y: Vec<f64> = (1..=30).map(|i| (i as f64) * 2.0 + 1.0).collect();
let x: Vec<f64> = (1..=30).map(|i| i as f64).collect();
let result = reset_test(&y, &[x], &[2, 3, 4], ResetType::Fitted).unwrap();
assert!(result.statistic.is_finite());
assert!(result.p_value.is_finite());
}
#[test]
fn test_reset_output_structure() {
let y = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
let x = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
let result = reset_test(&y, &[x], &[2], ResetType::Fitted).unwrap();
assert!(!result.test_name.is_empty());
assert!(result.statistic.is_finite());
assert!(result.p_value.is_finite());
assert!(result.p_value >= 0.0 && result.p_value <= 1.0);
assert!(!result.interpretation.is_empty());
assert!(!result.guidance.is_empty());
}
#[test]
fn test_linearity_tests_agree_on_linear_data() {
let y: Vec<f64> = (1..=20).map(|i| 2.0 * (i as f64) + 1.0 + 0.01 * ((i % 5) as f64 - 2.0)).collect();
let x: Vec<f64> = (1..=20).map(|i| i as f64).collect();
let rainbow = rainbow_test(&y, &[x.clone()], 0.5, RainbowMethod::R).unwrap();
let hc = harvey_collier_test(&y, &[x.clone()], HarveyCollierMethod::R).unwrap();
let reset = reset_test(&y, &[x], &[2], ResetType::Fitted).unwrap();
if let Some(r_single) = rainbow.r_result {
assert!(r_single.p_value > 0.05);
}
assert!(hc.p_value > 0.05);
assert!(reset.p_value > 0.05);
}
#[test]
fn test_linearity_tests_agree_on_nonlinear_data() {
let y: Vec<f64> = (1..=20).map(|i| (i as f64).powi(2)).collect();
let x: Vec<f64> = (1..=20).map(|i| i as f64).collect();
let rainbow = rainbow_test(&y, &[x.clone()], 0.5, RainbowMethod::R).unwrap();
let reset = reset_test(&y, &[x], &[2, 3], ResetType::Fitted).unwrap();
if let Some(r_single) = rainbow.r_result {
assert!(r_single.p_value < 0.05);
}
assert!(reset.p_value < 0.05);
}