use super::*;
use parlov_core::{
BlockFamily, BlockSummary, EndpointVerdict, ObservabilityStatus, OracleClass, OracleVerdict,
};
fn make_rule(id: &str) -> ReportingDescriptor {
ReportingDescriptor::builder().id(id).build()
}
fn blocked_endpoint_verdict() -> EndpointVerdict {
EndpointVerdict {
oracle_class: OracleClass::Existence,
posterior_probability: 0.50,
verdict: OracleVerdict::Inconclusive,
severity: None,
strategies_run: 8,
strategies_total: 8,
stop_reason: None,
first_threshold_crossed_by: None,
final_confirming_strategy: None,
contributing_findings: vec![],
observability_status: ObservabilityStatus::BlockedBeforeOracleLayer,
block_summary: Some(BlockSummary {
expected_observation_opportunities: 8,
blocked_before_oracle_layer: 8,
blocked_fraction: 1.0,
dominant_block_family: BlockFamily::Authorization,
dominant_block_reasons: vec![
"auth gate fired before technique (no credential provided)".to_owned(),
],
operator_action: Some(
r#"Retry with --header "Authorization: Bearer <token>""#.to_owned(),
),
}),
}
}
#[test]
fn deduplicate_rules_removes_duplicates() {
let rules = vec![
make_rule("b"),
make_rule("a"),
make_rule("b"),
make_rule("a"),
];
let deduped = deduplicate_rules(rules);
assert_eq!(deduped.len(), 2);
let ids: Vec<&str> = deduped.iter().map(|r| r.id.as_str()).collect();
assert!(ids.contains(&"a"));
assert!(ids.contains(&"b"));
}
#[test]
fn deduplicate_rules_stable_with_no_duplicates() {
let rules = vec![make_rule("z"), make_rule("a"), make_rule("m")];
let deduped = deduplicate_rules(rules);
assert_eq!(deduped.len(), 3);
}
#[test]
fn deduplicate_rules_empty_input_returns_empty() {
let deduped = deduplicate_rules(vec![]);
assert!(deduped.is_empty());
}
#[test]
fn blocked_verdict_run_properties_contain_observability_status() {
let verdict = blocked_endpoint_verdict();
let props = build_verdict_run_properties("https://api.example.com/users/1", &verdict);
let additional = &props.additional_properties;
let status_val = additional
.get("observability_status")
.expect("observability_status must be present in run properties");
assert_eq!(
status_val.as_str().unwrap_or(""),
"BlockedBeforeOracleLayer",
"observability_status must be 'BlockedBeforeOracleLayer'"
);
}
#[test]
fn blocked_verdict_run_properties_contain_operator_action() {
let verdict = blocked_endpoint_verdict();
let props = build_verdict_run_properties("https://api.example.com/users/1", &verdict);
let additional = &props.additional_properties;
let action_val = additional
.get("operator_action")
.expect("operator_action must be present when block_summary has Some(operator_action)");
assert!(
action_val
.as_str()
.unwrap_or("")
.contains("Authorization: Bearer"),
"operator_action must mention 'Authorization: Bearer'; got: {action_val}"
);
}