use datasynth_eval::{
AccountType, BalanceSheetEvaluator, BalanceSnapshot, BenfordAnalyzer, ComprehensiveEvaluation,
EvaluationConfig, EvaluationThresholds, Evaluator,
};
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use std::collections::HashMap;
#[test]
fn test_comprehensive_evaluation_creation() {
let eval = ComprehensiveEvaluation::new();
assert!(eval.passes, "New evaluation should pass by default");
assert!(
eval.failures.is_empty(),
"New evaluation should have no failures"
);
assert!(eval.statistical.passes);
assert!(eval.coherence.passes);
assert!(eval.quality.passes);
assert!(eval.ml_readiness.passes);
assert!(eval.privacy.is_none());
assert!(eval.banking.is_none());
assert!(eval.process_mining.is_none());
assert!(eval.causal.is_none());
assert!(eval.enrichment_quality.is_none());
assert!(eval.tuning_opportunities.is_empty());
assert!(eval.config_suggestions.is_empty());
}
#[test]
fn test_evaluator_with_defaults() {
let evaluator = Evaluator::with_defaults();
let config = evaluator.config();
assert!(
(config.thresholds.benford_p_value_min - 0.05).abs() < f64::EPSILON,
"Default Benford p-value threshold should be 0.05"
);
assert!(
(config.thresholds.benford_mad_max - 0.015).abs() < f64::EPSILON,
"Default Benford MAD threshold should be 0.015"
);
assert_eq!(config.thresholds.balance_tolerance, dec!(0.01));
assert!(config.statistical.benford_enabled);
assert!(config.coherence.balance_enabled);
assert!(config.quality.uniqueness_enabled);
}
#[test]
fn test_evaluator_run_produces_passing_empty_evaluation() {
let evaluator = Evaluator::with_defaults();
let result = evaluator.run_evaluation();
assert!(
result.passes,
"Empty evaluation should pass all threshold checks"
);
assert!(result.failures.is_empty());
}
#[test]
fn test_evaluation_thresholds_with_benford_failure() {
let mut eval = ComprehensiveEvaluation::new();
let uniform_amounts: Vec<Decimal> = (1..=500)
.map(|i| Decimal::new(i * 2, 0)) .collect();
let analyzer = BenfordAnalyzer::new(0.05);
let benford_result = analyzer.analyze(&uniform_amounts).expect("should succeed");
eval.statistical.benford = Some(benford_result);
let thresholds = EvaluationThresholds::default();
eval.check_all_thresholds(&thresholds);
assert!(
!eval.failures.is_empty(),
"Uniform data should cause Benford threshold failures"
);
assert!(
!eval.passes,
"Evaluation should not pass with Benford failures"
);
let has_benford_failure = eval.failures.iter().any(|f| f.contains("Benford"));
assert!(
has_benford_failure,
"Should have a Benford-related failure message, got: {:?}",
eval.failures
);
}
#[test]
fn test_evaluation_thresholds_with_balance_failure() {
let mut eval = ComprehensiveEvaluation::new();
let evaluator = BalanceSheetEvaluator::default();
let mut balances = HashMap::new();
balances.insert(AccountType::Asset, dec!(1000));
balances.insert(AccountType::Liability, dec!(500));
balances.insert(AccountType::Equity, dec!(300));
let snapshot = BalanceSnapshot {
company_code: "C001".to_string(),
fiscal_year: 2024,
fiscal_period: 1,
balances,
};
let balance_result = evaluator.evaluate(&[snapshot]).expect("should succeed");
eval.coherence.balance = Some(balance_result);
let thresholds = EvaluationThresholds::default();
eval.check_all_thresholds(&thresholds);
assert!(
!eval.passes,
"Evaluation should fail with imbalanced balance sheet"
);
let has_balance_failure = eval.failures.iter().any(|f| f.contains("Balance sheet"));
assert!(
has_balance_failure,
"Should have a balance-related failure message, got: {:?}",
eval.failures
);
}
#[test]
fn test_evaluation_thresholds_all_passing() {
let mut eval = ComprehensiveEvaluation::new();
let amounts: Vec<Decimal> = (1..=1000)
.map(|i| {
let digit = match i % 100 {
0..=29 => 1,
30..=46 => 2,
47..=59 => 3,
60..=69 => 4,
70..=77 => 5,
78..=84 => 6,
85..=90 => 7,
91..=95 => 8,
_ => 9,
};
Decimal::new(digit * 100 + (i % 100) as i64, 2)
})
.collect();
let analyzer = BenfordAnalyzer::new(0.05);
if let Ok(benford_result) = analyzer.analyze(&amounts) {
if benford_result.passes {
eval.statistical.benford = Some(benford_result);
}
}
let balance_evaluator = BalanceSheetEvaluator::default();
let mut balances = HashMap::new();
balances.insert(AccountType::Asset, dec!(1000));
balances.insert(AccountType::Liability, dec!(600));
balances.insert(AccountType::Equity, dec!(400));
let snapshot = BalanceSnapshot {
company_code: "C001".to_string(),
fiscal_year: 2024,
fiscal_period: 1,
balances,
};
let balance_result = balance_evaluator
.evaluate(&[snapshot])
.expect("should succeed");
eval.coherence.balance = Some(balance_result);
let thresholds = EvaluationThresholds::default();
eval.check_all_thresholds(&thresholds);
assert!(
eval.passes,
"Evaluation with all-passing sub-evaluations should pass, but got failures: {:?}",
eval.failures
);
assert!(eval.failures.is_empty());
}
#[test]
fn test_evaluator_custom_config() {
let mut config = EvaluationConfig {
thresholds: EvaluationThresholds::strict(),
..Default::default()
};
config.statistical.significance_level = 0.10;
let evaluator = Evaluator::new(config);
let config_ref = evaluator.config();
assert!(
(config_ref.statistical.significance_level - 0.10).abs() < f64::EPSILON,
"Custom significance level should be 0.10"
);
assert!(
(config_ref.thresholds.benford_p_value_min - 0.10).abs() < f64::EPSILON,
"Strict threshold Benford p-value should be 0.10"
);
assert_eq!(
config_ref.thresholds.balance_tolerance,
Decimal::new(1, 4),
"Strict balance tolerance should be 0.0001"
);
}