parlov 0.8.0

HTTP oracle detection tool — systematic probing for RFC-compliant information leakage.
Documentation
use super::*;

#[test]
fn vector_and_risk_mutually_exclusive() {
    let mut args = minimal_args("https://api.example.com/users/{id}", "1001");
    args.risk = "method-destructive".to_owned();
    args.vectors = vec!["cache-probing".to_owned()];
    let filters = parse_vector_flags(&args.vectors).unwrap();
    assert!(validate_vector_risk_exclusivity(&args, &filters).is_err());
}

#[test]
fn vector_with_default_risk_is_not_exclusive() {
    let mut args = minimal_args("https://api.example.com/users/{id}", "1001");
    args.vectors = vec!["cache-probing".to_owned()];
    let filters = parse_vector_flags(&args.vectors).unwrap();
    assert!(validate_vector_risk_exclusivity(&args, &filters).is_ok());
}

#[test]
fn strategy_filter_keeps_only_matching_specs() {
    let args = minimal_args("https://api.example.com/users/{id}", "1001");
    let ctx = build_scan_context(&args, &[]).unwrap();
    let strategy_ids = vec!["rd-percent-encoding".to_owned()];
    let plan = build_filtered_plan(&ctx, &[], &strategy_ids);
    assert!(
        !plan.is_empty(),
        "expected at least one spec for rd-percent-encoding"
    );
    for spec in &plan {
        assert_eq!(
            spec_strategy_id(spec),
            "rd-percent-encoding",
            "all specs must have strategy_id == rd-percent-encoding"
        );
    }
}

#[test]
fn strategy_filter_unknown_id_yields_empty_plan() {
    let args = minimal_args("https://api.example.com/users/{id}", "1001");
    let ctx = build_scan_context(&args, &[]).unwrap();
    let strategy_ids = vec!["this-strategy-does-not-exist".to_owned()];
    let plan = build_filtered_plan(&ctx, &[], &strategy_ids);
    assert!(plan.is_empty());
}

#[test]
fn strategy_and_risk_mutually_exclusive() {
    let mut args = minimal_args("https://api.example.com/users/{id}", "1001");
    args.risk = "method-destructive".to_owned();
    args.strategies = vec!["rd-percent-encoding".to_owned()];
    assert!(validate_strategy_exclusivity(&args, &[]).is_err());
}

#[test]
fn strategy_and_vector_mutually_exclusive() {
    let mut args = minimal_args("https://api.example.com/users/{id}", "1001");
    args.strategies = vec!["rd-percent-encoding".to_owned()];
    let filters = parse_vector_flags(&["cache-probing".to_owned()]).unwrap();
    assert!(validate_strategy_exclusivity(&args, &filters).is_err());
}

#[test]
fn multiple_strategy_flags_produce_union_plan() {
    let args = minimal_args("https://api.example.com/users/{id}", "1001");
    let ctx = build_scan_context(&args, &[]).unwrap();
    let strategy_ids = vec![
        "rd-percent-encoding".to_owned(),
        "rd-double-slash".to_owned(),
    ];
    let plan = build_filtered_plan(&ctx, &[], &strategy_ids);
    let has_percent = plan
        .iter()
        .any(|s| spec_strategy_id(s) == "rd-percent-encoding");
    let has_double = plan
        .iter()
        .any(|s| spec_strategy_id(s) == "rd-double-slash");
    assert!(has_percent, "expected rd-percent-encoding spec");
    assert!(has_double, "expected rd-double-slash spec");
    for spec in &plan {
        let id = spec_strategy_id(spec);
        assert!(
            id == "rd-percent-encoding" || id == "rd-double-slash",
            "unexpected strategy_id: {id}"
        );
    }
}

#[test]
fn strategy_with_default_risk_is_valid() {
    let mut args = minimal_args("https://api.example.com/users/{id}", "1001");
    args.strategies = vec!["rd-percent-encoding".to_owned()];
    // risk stays "safe" (the default) — must not error
    assert!(validate_strategy_exclusivity(&args, &[]).is_ok());
}