use super::*;
use parlov_core::{ImpactClass, NormativeStrength, OracleVerdict, Severity, Signal, SignalKind};
fn pattern(base_confidence: u8, base_impact: u8) -> PatternMatch {
PatternMatch {
base_confidence,
base_impact,
label: Some("Test pattern"),
leaks: Some("Test leak"),
rfc_basis: Some("RFC 9110"),
}
}
#[test]
fn zero_base_returns_not_present() {
let p = PatternMatch {
base_confidence: 0,
base_impact: 0,
label: None,
leaks: None,
rfc_basis: None,
};
let out = compute(&p, &[], NormativeStrength::Must, 404);
assert_eq!(out.verdict, OracleVerdict::NotPresent);
assert_eq!(out.confidence, 0);
assert!(out.severity.is_none());
}
#[test]
fn high_base_confidence_yields_confirmed() {
let out = compute(&pattern(90, 50), &[], NormativeStrength::Must, 200);
assert_eq!(out.verdict, OracleVerdict::Confirmed);
assert_eq!(out.confidence, 90);
}
#[test]
fn moderate_base_confidence_yields_likely() {
let out = compute(&pattern(70, 35), &[], NormativeStrength::Must, 403);
assert_eq!(out.verdict, OracleVerdict::Likely);
assert_eq!(out.confidence, 70);
}
#[test]
fn low_base_confidence_yields_not_present() {
let out = compute(&pattern(40, 15), &[], NormativeStrength::Must, 418);
assert_eq!(out.verdict, OracleVerdict::NotPresent);
assert_eq!(out.confidence, 40);
}
#[test]
fn confirmed_verdict_gets_full_severity() {
let out = compute(&pattern(90, 50), &[], NormativeStrength::Must, 200);
assert_eq!(out.severity, Some(Severity::Medium));
}
#[test]
fn likely_verdict_caps_severity_one_below() {
let out = compute(&pattern(70, 50), &[], NormativeStrength::Must, 200);
assert_eq!(out.severity, Some(Severity::Low));
}
#[test]
fn signals_add_to_confidence() {
let signals = vec![Signal {
kind: SignalKind::HeaderPresence,
evidence: "etag present in baseline, absent in probe".into(),
rfc_basis: None,
}];
let out = compute(&pattern(75, 35), &signals, NormativeStrength::Must, 403);
assert!(out.confidence >= 80);
assert_eq!(out.verdict, OracleVerdict::Confirmed);
}
#[test]
fn confidence_clamped_to_100() {
let signals = vec![
Signal {
kind: SignalKind::HeaderPresence,
evidence: "etag present in baseline".into(),
rfc_basis: None,
},
Signal {
kind: SignalKind::HeaderPresence,
evidence: "content-range present in baseline".into(),
rfc_basis: None,
},
Signal {
kind: SignalKind::MetadataLeak,
evidence: "Content-Range leaks total resource size: 500 bytes".into(),
rfc_basis: None,
},
];
let out = compute(&pattern(90, 55), &signals, NormativeStrength::Must, 206);
assert!(out.confidence <= 100);
}
#[test]
fn content_range_size_leak_yields_high_impact() {
let signals = vec![Signal {
kind: SignalKind::MetadataLeak,
evidence: "Content-Range leaks total resource size: 1024 bytes".into(),
rfc_basis: None,
}];
let out = compute(&pattern(85, 55), &signals, NormativeStrength::Must, 206);
assert_eq!(out.impact_class, Some(ImpactClass::High));
}
#[test]
fn verdict_from_confidence_thresholds() {
assert_eq!(verdict_from_confidence(100), OracleVerdict::Confirmed);
assert_eq!(verdict_from_confidence(80), OracleVerdict::Confirmed);
assert_eq!(verdict_from_confidence(79), OracleVerdict::Likely);
assert_eq!(verdict_from_confidence(60), OracleVerdict::Likely);
assert_eq!(verdict_from_confidence(59), OracleVerdict::NotPresent);
assert_eq!(verdict_from_confidence(0), OracleVerdict::NotPresent);
}