#[cfg(test)]
mod tests {
use llmosafe::{
calculate_halo_signal, get_bias_breakdown, CusumDetector, DynamicStabilityMonitor,
SiftedSynapse, StabilityResult, Synapse, WorkingMemory,
};
#[test]
fn test_cusum_math_correctness() {
let mut detector = CusumDetector::new(100.0, 10.0, 50.0);
assert!(!detector.update(100.0), "At reference, no detection");
assert!(!detector.update(150.0), "First deviation, s_high=40");
let detected_after_second = detector.update(150.0);
assert!(
detected_after_second,
"Second deviation should trigger (s_high=80 > 50)"
);
}
#[test]
fn test_cusum_symmetric_detection() {
let mut detector_high = CusumDetector::new(100.0, 10.0, 100.0);
let mut detector_low = CusumDetector::new(100.0, 10.0, 100.0);
for _ in 0..10 {
detector_high.update(200.0);
}
assert!(detector_high.detected(), "High shift should be detected");
for _ in 0..10 {
detector_low.update(0.0);
}
assert!(detector_low.detected(), "Low shift should be detected");
}
#[test]
fn test_dynamic_stability_math_correctness() {
let mut monitor = DynamicStabilityMonitor::new(2);
let result1 = monitor.update(100);
assert_eq!(
result1,
StabilityResult::Stable,
"First value initializes baseline"
);
let result2 = monitor.update(100);
assert_eq!(result2, StabilityResult::Stable, "Similar value is stable");
let result3 = monitor.update(10000);
assert!(
matches!(result3, StabilityResult::High | StabilityResult::Both),
"Large increase should be detected"
);
}
#[test]
fn test_surprise_gating_formula() {
let mut memory = WorkingMemory::<64>::new(500);
let mut synapse1 = Synapse::new();
synapse1.set_raw_entropy(100);
synapse1.set_raw_surprise(500);
let sifted1 = SiftedSynapse::new(synapse1);
assert!(
memory.update(sifted1).is_ok(),
"surprise == threshold should pass"
);
let mut synapse2 = Synapse::new();
synapse2.set_raw_entropy(100);
synapse2.set_raw_surprise(501);
let sifted2 = SiftedSynapse::new(synapse2);
assert!(
memory.update(sifted2).is_err(),
"surprise > threshold should fail"
);
}
#[test]
fn test_entropy_accumulation_correctness() {
let mut memory = WorkingMemory::<4>::new(1000);
let values = [100u16, 200, 300, 400];
for &v in &values {
let mut synapse = Synapse::new();
synapse.set_raw_entropy(v);
let sifted = SiftedSynapse::new(synapse);
memory.update(sifted).unwrap();
}
let mean = memory.mean_entropy();
let expected_mean = (100.0 + 200.0 + 300.0 + 400.0) / 4.0;
assert!(
(mean - expected_mean).abs() < 1.0,
"Mean should be {}, got {}",
expected_mean,
mean
);
}
#[test]
fn test_variance_calculation_correctness() {
let mut memory = WorkingMemory::<2>::new(1000);
let mut s1 = Synapse::new();
s1.set_raw_entropy(100);
memory.update(SiftedSynapse::new(s1)).unwrap();
let mut s2 = Synapse::new();
s2.set_raw_entropy(200);
memory.update(SiftedSynapse::new(s2)).unwrap();
let variance = memory.entropy_variance();
assert!(
(variance - 2500.0).abs() < 1.0,
"Variance should be 2500, got {}",
variance
);
}
#[test]
fn test_trend_calculation_correctness() {
let mut memory = WorkingMemory::<4>::new(1000);
for i in 1..=4u16 {
let mut synapse = Synapse::new();
synapse.set_raw_entropy(i * 100);
let sifted = SiftedSynapse::new(synapse);
memory.update(sifted).unwrap();
}
let trend = memory.trend();
assert!(
(trend - 100.0).abs() < 1.0,
"Trend should be 100, got {}",
trend
);
}
#[test]
fn test_bias_breakdown_sum_correctness() {
let test_texts = vec![
"normal text",
"expert recommendation",
"popular limited offer",
"expert says this is popular",
];
for text in test_texts {
let breakdown = get_bias_breakdown(text);
let halo = calculate_halo_signal(text);
assert_eq!(
breakdown.total(),
halo,
"Breakdown total should equal halo signal for: {}",
text
);
}
}
#[test]
fn test_msb_index_computation() {
let test_cases: Vec<(u32, u8)> = vec![
(1, 0),
(2, 1),
(4, 2),
(8, 3),
(255, 7),
(256, 8),
(1024, 10),
(65535, 15),
];
for (value, expected_msb) in test_cases {
let msb = 31u8.wrapping_sub(value.leading_zeros() as u8);
assert_eq!(
msb, expected_msb,
"MSB of {} should be {}, got {}",
value, expected_msb, msb
);
}
}
}