#![allow(clippy::unwrap_used)]
use datasynth_core::models::{JournalEntry, JournalEntryHeader, JournalEntryLine};
use datasynth_eval::coherence::sampling_validation::{validate_sampling, Stratum};
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
fn date(y: i32, m: u32, d: u32) -> chrono::NaiveDate {
chrono::NaiveDate::from_ymd_opt(y, m, d).unwrap()
}
fn make_entry(amount: Decimal, anomaly: bool, company: &str, period: u8) -> JournalEntry {
let posting_date = date(2024, period.clamp(1, 12) as u32, 1);
let mut header = JournalEntryHeader::new(company.to_string(), posting_date);
header.fiscal_period = period;
header.is_anomaly = anomaly;
let doc_id = header.document_id;
let mut entry = JournalEntry::new(header);
entry.add_line(JournalEntryLine::debit(
doc_id,
1,
"6000".to_string(),
amount,
));
entry.add_line(JournalEntryLine::credit(
doc_id,
2,
"2000".to_string(),
amount,
));
entry
}
fn make_fraud_entry(amount: Decimal, company: &str, period: u8) -> JournalEntry {
let posting_date = date(2024, period.clamp(1, 12) as u32, 1);
let mut header = JournalEntryHeader::new(company.to_string(), posting_date);
header.fiscal_period = period;
header.is_fraud = true;
let doc_id = header.document_id;
let mut entry = JournalEntry::new(header);
entry.add_line(JournalEntryLine::debit(
doc_id,
1,
"6000".to_string(),
amount,
));
entry.add_line(JournalEntryLine::credit(
doc_id,
2,
"2000".to_string(),
amount,
));
entry
}
#[test]
fn test_above_materiality_stratum() {
let entries = vec![make_entry(dec!(200_000), false, "C001", 1)];
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
let above = result
.strata
.iter()
.find(|s| s.stratum == Stratum::AboveMateriality)
.unwrap();
assert_eq!(above.item_count, 1);
assert_eq!(result.total_population, 1);
}
#[test]
fn test_between_stratum() {
let entries = vec![make_entry(dec!(80_000), false, "C001", 1)];
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
let between = result
.strata
.iter()
.find(|s| s.stratum == Stratum::BetweenPerformanceAndOverall)
.unwrap();
assert_eq!(between.item_count, 1);
}
#[test]
fn test_below_performance_stratum() {
let entries = vec![make_entry(dec!(10_000), false, "C001", 1)];
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
let below = result
.strata
.iter()
.find(|s| s.stratum == Stratum::BelowPerformanceMateriality)
.unwrap();
assert_eq!(below.item_count, 1);
}
#[test]
fn test_clearly_trivial_stratum() {
let entries = vec![make_entry(dec!(100), false, "C001", 1)];
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
let trivial = result
.strata
.iter()
.find(|s| s.stratum == Stratum::ClearlyTrivial)
.unwrap();
assert_eq!(trivial.item_count, 1);
}
#[test]
fn test_all_strata_present() {
let entries = vec![
make_entry(dec!(200_000), true, "C001", 1), make_entry(dec!(80_000), false, "C001", 2), make_entry(dec!(10_000), false, "C001", 3), make_entry(dec!(500), false, "C001", 4), ];
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
assert_eq!(result.total_population, 4);
assert_eq!(result.strata.len(), 4);
for stratum_result in &result.strata {
assert_eq!(stratum_result.item_count, 1);
}
}
#[test]
fn test_above_materiality_coverage_all_anomalous() {
let entries: Vec<JournalEntry> = (0..5)
.map(|_| make_entry(dec!(200_000), true, "C001", 1))
.collect();
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
assert!((result.above_materiality_coverage - 1.0).abs() < 1e-9);
assert!(result.passes);
}
#[test]
fn test_above_materiality_coverage_none_anomalous() {
let entries: Vec<JournalEntry> = (0..5)
.map(|_| make_entry(dec!(200_000), false, "C001", 1))
.collect();
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
assert!((result.above_materiality_coverage - 0.0).abs() < 1e-9);
assert!(!result.passes);
}
#[test]
fn test_above_materiality_coverage_partial() {
let mut entries: Vec<JournalEntry> = (0..4)
.map(|_| make_entry(dec!(200_000), true, "C001", 1))
.collect();
entries.push(make_entry(dec!(200_000), false, "C001", 1));
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
assert!((result.above_materiality_coverage - 0.8).abs() < 1e-9);
assert!(!result.passes);
}
#[test]
fn test_no_above_materiality_items_passes_vacuously() {
let entries: Vec<JournalEntry> = (0..5)
.map(|_| make_entry(dec!(50_000), false, "C001", 1))
.collect();
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
assert!((result.above_materiality_coverage - 1.0).abs() < 1e-9);
assert!(result.passes);
}
#[test]
fn test_entity_coverage_single_company() {
let entries = vec![
make_entry(dec!(200_000), true, "C001", 1),
make_entry(dec!(50_000), false, "C001", 2),
];
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
assert!((result.entity_coverage - 1.0).abs() < 1e-9);
}
#[test]
fn test_entity_coverage_partial() {
let entries = vec![
make_entry(dec!(200_000), true, "C001", 1), make_entry(dec!(50_000), false, "C002", 1), ];
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
assert!((result.entity_coverage - 0.5).abs() < 1e-9);
}
#[test]
fn test_temporal_coverage() {
let entries = vec![
make_entry(dec!(200_000), true, "C001", 1), make_entry(dec!(50_000), true, "C001", 2), make_entry(dec!(50_000), false, "C001", 3), ];
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
assert!((result.temporal_coverage - 2.0 / 3.0).abs() < 1e-9);
}
#[test]
fn test_anomaly_stratum_coverage() {
let entries = vec![
make_entry(dec!(200_000), true, "C001", 1), make_entry(dec!(80_000), true, "C001", 2), make_entry(dec!(10_000), true, "C001", 3), make_entry(dec!(100), false, "C001", 4), ];
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
assert!((result.anomaly_stratum_coverage - 1.0).abs() < 1e-9);
}
#[test]
fn test_fraud_flag_also_counted() {
let entries = vec![make_fraud_entry(dec!(200_000), "C001", 1)];
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
assert!((result.above_materiality_coverage - 1.0).abs() < 1e-9);
assert!(result.passes);
}
#[test]
fn test_empty_population() {
let result = validate_sampling(&[], dec!(100_000), dec!(60_000));
assert_eq!(result.total_population, 0);
assert!(result.passes);
}
#[test]
fn test_zero_amount_entries() {
let entries: Vec<JournalEntry> = (0..3)
.map(|_| make_entry(dec!(0), false, "C001", 1))
.collect();
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
let trivial = result
.strata
.iter()
.find(|s| s.stratum == Stratum::ClearlyTrivial)
.unwrap();
assert_eq!(trivial.item_count, 3);
assert!(result.passes);
}
#[test]
fn test_anomaly_rate_in_stratum() {
let entries = vec![
make_entry(dec!(200_000), true, "C001", 1),
make_entry(dec!(200_000), false, "C001", 2),
];
let result = validate_sampling(&entries, dec!(100_000), dec!(60_000));
let above = result
.strata
.iter()
.find(|s| s.stratum == Stratum::AboveMateriality)
.unwrap();
assert_eq!(above.item_count, 2);
assert_eq!(above.anomaly_count, 1);
assert!((above.anomaly_rate - 0.5).abs() < 1e-9);
}