use super::{DecisionTrace, SourceSpan};
use crate::citl::FixSuggestion;
#[derive(Debug, Clone)]
pub struct ErrorCorrelation {
pub error_code: String,
pub error_span: SourceSpan,
pub suspicious_decisions: Vec<SuspiciousDecision>,
pub fix_suggestions: Vec<FixSuggestion>,
}
#[derive(Debug, Clone)]
pub struct SuspiciousDecision {
pub decision: DecisionTrace,
pub suspiciousness: f32,
pub reason: String,
}
impl SuspiciousDecision {
#[must_use]
pub fn new(decision: DecisionTrace, suspiciousness: f32, reason: impl Into<String>) -> Self {
Self { decision, suspiciousness: suspiciousness.clamp(0.0, 1.0), reason: reason.into() }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_suspicious_decision_new() {
let trace = DecisionTrace::new("d1", "type", "desc");
let suspicious = SuspiciousDecision::new(trace, 0.8, "high suspicion");
assert_eq!(suspicious.suspiciousness, 0.8);
}
#[test]
fn test_suspicious_decision_clamped() {
let trace = DecisionTrace::new("d1", "type", "desc");
let suspicious = SuspiciousDecision::new(trace, 1.5, "over max");
assert_eq!(suspicious.suspiciousness, 1.0);
}
}
#[cfg(test)]
mod prop_tests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn prop_suspiciousness_clamped(score in -10.0f32..10.0) {
let trace = DecisionTrace::new("d", "type", "desc");
let suspicious = SuspiciousDecision::new(trace, score, "reason");
prop_assert!(suspicious.suspiciousness >= 0.0);
prop_assert!(suspicious.suspiciousness <= 1.0);
}
}
}