use http::{HeaderMap, HeaderName, HeaderValue};
use parlov_core::{
always_applicable, NormativeStrength, OracleClass, OracleResult, OracleVerdict, SignalSurface,
StrategyOutcome, Vector,
};
fn make_technique(oracle_class: OracleClass, vector: Vector) -> parlov_core::Technique {
parlov_core::Technique {
id: "test-tech",
name: "Test technique",
oracle_class,
vector,
strength: NormativeStrength::Must,
normalization_weight: None,
inverted_signal_weight: None,
method_relevant: false,
parser_relevant: false,
applicability: always_applicable,
contradiction_surface: SignalSurface::Status,
}
}
fn inner_result(outcome: &StrategyOutcome) -> &OracleResult {
match outcome {
StrategyOutcome::Positive(r)
| StrategyOutcome::NoSignal(r)
| StrategyOutcome::Contradictory(r, _) => r,
StrategyOutcome::Inapplicable(_) => panic!("unexpected Inapplicable in test"),
}
}
fn make_header_map(pairs: &[(&str, &str)]) -> HeaderMap {
let mut map = HeaderMap::new();
for &(name, value) in pairs {
map.insert(
HeaderName::from_bytes(name.as_bytes()).expect("valid header name"),
HeaderValue::from_str(value).expect("valid header value"),
);
}
map
}
fn make_result(verdict: OracleVerdict) -> OracleResult {
OracleResult {
class: OracleClass::Existence,
verdict,
severity: None,
confidence: 0,
impact_class: None,
reasons: vec![],
signals: vec![],
technique_id: None,
vector: Some(Vector::StatusCodeDiff),
normative_strength: Some(NormativeStrength::Must),
label: None,
leaks: None,
rfc_basis: None,
}
}
#[test]
fn into_outcome_confirmed_maps_to_positive() {
use parlov_core::StrategyOutcome;
let result = make_result(OracleVerdict::Confirmed);
let outcome = result.into_outcome();
assert!(matches!(outcome, StrategyOutcome::Positive(_)));
}
#[test]
fn into_outcome_not_present_maps_to_no_signal() {
use parlov_core::StrategyOutcome;
let result = make_result(OracleVerdict::NotPresent);
let outcome = result.into_outcome();
assert!(matches!(outcome, StrategyOutcome::NoSignal(_)));
}
#[test]
fn into_outcome_likely_maps_to_no_signal() {
use parlov_core::StrategyOutcome;
let result = make_result(OracleVerdict::Likely);
let outcome = result.into_outcome();
assert!(matches!(outcome, StrategyOutcome::NoSignal(_)));
}
#[test]
fn burst_result_produces_status_code_diff_signal() {
use parlov_core::SignalKind;
let technique = make_technique(OracleClass::Existence, Vector::StatusCodeDiff);
let outcome = parlov_analysis::burst_result(
5,
0,
&technique,
parlov_analysis::ModifierResult {
modifiers: parlov_analysis::EvidenceModifiers::default(),
block_reason: None,
},
);
let r = inner_result(&outcome);
assert_eq!(r.signals.len(), 1);
assert_eq!(r.signals[0].kind, SignalKind::StatusCodeDiff);
}
#[test]
fn burst_result_confirmed_has_nonzero_confidence() {
let technique = make_technique(OracleClass::Existence, Vector::StatusCodeDiff);
let outcome = parlov_analysis::burst_result(
1,
0,
&technique,
parlov_analysis::ModifierResult {
modifiers: parlov_analysis::EvidenceModifiers::default(),
block_reason: None,
},
);
assert!(matches!(outcome, StrategyOutcome::Positive(_)));
let r = inner_result(&outcome);
assert_eq!(r.verdict, OracleVerdict::Confirmed);
assert_eq!(r.confidence, 80);
}
#[test]
fn burst_result_not_present_has_zero_confidence() {
let technique = make_technique(OracleClass::Existence, Vector::StatusCodeDiff);
let outcome = parlov_analysis::burst_result(
0,
0,
&technique,
parlov_analysis::ModifierResult {
modifiers: parlov_analysis::EvidenceModifiers::default(),
block_reason: None,
},
);
assert!(matches!(outcome, StrategyOutcome::NoSignal(_)));
let r = inner_result(&outcome);
assert_eq!(r.verdict, OracleVerdict::NotPresent);
assert_eq!(r.confidence, 0);
}
#[test]
fn header_diff_result_produces_header_presence_signal() {
use parlov_core::SignalKind;
let technique = make_technique(OracleClass::Existence, Vector::StatusCodeDiff);
let baseline = make_header_map(&[("x-ratelimit-remaining", "99")]);
let probe = HeaderMap::new();
let outcome = parlov_analysis::header_diff_result(
&baseline,
&probe,
&technique,
parlov_analysis::ModifierResult {
modifiers: parlov_analysis::EvidenceModifiers::default(),
block_reason: None,
},
);
let r = inner_result(&outcome);
assert_eq!(r.signals.len(), 1);
assert_eq!(r.signals[0].kind, SignalKind::HeaderPresence);
}
#[test]
fn header_diff_result_confirmed_has_nonzero_confidence() {
let technique = make_technique(OracleClass::Existence, Vector::StatusCodeDiff);
let baseline = make_header_map(&[("x-ratelimit-limit", "100")]);
let probe = HeaderMap::new();
let outcome = parlov_analysis::header_diff_result(
&baseline,
&probe,
&technique,
parlov_analysis::ModifierResult {
modifiers: parlov_analysis::EvidenceModifiers::default(),
block_reason: None,
},
);
assert!(matches!(outcome, StrategyOutcome::Positive(_)));
let r = inner_result(&outcome);
assert_eq!(r.verdict, OracleVerdict::Confirmed);
assert_eq!(r.confidence, 80);
}
#[test]
fn header_diff_result_not_present_has_zero_confidence() {
let technique = make_technique(OracleClass::Existence, Vector::StatusCodeDiff);
let outcome = parlov_analysis::header_diff_result(
&HeaderMap::new(),
&HeaderMap::new(),
&technique,
parlov_analysis::ModifierResult {
modifiers: parlov_analysis::EvidenceModifiers::default(),
block_reason: None,
},
);
assert!(matches!(outcome, StrategyOutcome::NoSignal(_)));
let r = inner_result(&outcome);
assert_eq!(r.verdict, OracleVerdict::NotPresent);
assert_eq!(r.confidence, 0);
}
#[test]
fn burst_result_uses_oracle_class_from_technique() {
let technique = make_technique(OracleClass::Existence, Vector::StatusCodeDiff);
let outcome = parlov_analysis::burst_result(
5,
0,
&technique,
parlov_analysis::ModifierResult {
modifiers: parlov_analysis::EvidenceModifiers::default(),
block_reason: None,
},
);
assert_eq!(inner_result(&outcome).class, OracleClass::Existence);
}