parlov-core 0.7.0

Shared types, error types, and oracle class definitions for parlov.
Documentation
use super::{
    always_applicable, Applicability, NormativeStrength, OracleClass, SignalSurface, Technique,
    Vector,
};

fn base_technique() -> Technique {
    Technique {
        id: "test",
        name: "test",
        oracle_class: OracleClass::Existence,
        vector: Vector::StatusCodeDiff,
        strength: NormativeStrength::Must,
        normalization_weight: Some(0.2),
        inverted_signal_weight: None,
        method_relevant: false,
        parser_relevant: false,
        applicability: always_applicable,
        contradiction_surface: SignalSurface::Status,
    }
}

#[test]
fn normalization_weight_some_roundtrips() {
    let t = base_technique();
    assert_eq!(t.normalization_weight, Some(0.2));
}

#[test]
fn normalization_weight_none_roundtrips() {
    let t = Technique {
        vector: Vector::CacheProbing,
        strength: NormativeStrength::May,
        normalization_weight: None,
        ..base_technique()
    };
    assert_eq!(t.normalization_weight, None);
}

#[test]
fn inverted_signal_weight_some_roundtrips() {
    let t = Technique {
        strength: NormativeStrength::May,
        inverted_signal_weight: Some(0.2),
        ..base_technique()
    };
    assert_eq!(t.inverted_signal_weight, Some(0.2));
}

#[test]
fn inverted_signal_weight_none_roundtrips() {
    let t = base_technique();
    assert_eq!(t.inverted_signal_weight, None);
}

#[test]
fn applicability_strong_confidence_is_one() {
    assert!((Applicability::Strong.confidence() - 1.0).abs() < f64::EPSILON);
}

#[test]
fn applicability_weak_confidence_is_three_tenths() {
    assert!((Applicability::Weak.confidence() - 0.3).abs() < f64::EPSILON);
}

#[test]
fn applicability_missing_confidence_is_zero() {
    assert!(Applicability::Missing.confidence().abs() < f64::EPSILON);
}

#[test]
fn always_applicable_returns_strong() {
    let surface = crate::ResponseSurface {
        status: http::StatusCode::OK,
        headers: http::HeaderMap::new(),
        body: bytes::Bytes::new(),
        timing_ns: 0,
    };
    assert_eq!(always_applicable(&surface, &surface), Applicability::Strong);
}

#[test]
fn default_method_relevant_is_false() {
    assert!(!base_technique().method_relevant);
}

#[test]
fn default_parser_relevant_is_false() {
    assert!(!base_technique().parser_relevant);
}

#[test]
fn vector_display() {
    assert_eq!(format!("{}", Vector::StatusCodeDiff), "StatusCodeDiff");
    assert_eq!(format!("{}", Vector::CacheProbing), "CacheProbing");
    assert_eq!(
        format!("{}", Vector::ErrorMessageGranularity),
        "ErrorMessageGranularity"
    );
    assert_eq!(format!("{}", Vector::RedirectDiff), "RedirectDiff");
}

#[test]
fn normative_strength_display() {
    assert_eq!(format!("{}", NormativeStrength::Must), "Must");
    assert_eq!(format!("{}", NormativeStrength::MustNot), "MustNot");
    assert_eq!(format!("{}", NormativeStrength::Should), "Should");
    assert_eq!(format!("{}", NormativeStrength::May), "May");
}

#[test]
fn error_message_granularity_variant_exists() {
    let v = Vector::ErrorMessageGranularity;
    assert_ne!(v, Vector::StatusCodeDiff);
    assert_ne!(v, Vector::CacheProbing);
}

#[test]
fn error_message_granularity_serializes() {
    let original = Vector::ErrorMessageGranularity;
    let json = serde_json::to_string(&original).expect("serialization must succeed");
    let roundtrip: Vector = serde_json::from_str(&json).expect("deserialization must succeed");
    assert_eq!(original, roundtrip);
}

#[test]
fn error_message_granularity_is_copy() {
    let a = Vector::ErrorMessageGranularity;
    let b = a;
    assert_eq!(a, b);
}

#[test]
fn redirect_diff_variant_exists() {
    let v = Vector::RedirectDiff;
    assert_ne!(v, Vector::StatusCodeDiff);
    assert_ne!(v, Vector::CacheProbing);
    assert_ne!(v, Vector::ErrorMessageGranularity);
}

#[test]
fn redirect_diff_serializes() {
    let original = Vector::RedirectDiff;
    let json = serde_json::to_string(&original).expect("serialization must succeed");
    let roundtrip: Vector = serde_json::from_str(&json).expect("deserialization must succeed");
    assert_eq!(original, roundtrip);
}

#[test]
fn redirect_diff_is_copy() {
    let a = Vector::RedirectDiff;
    let b = a;
    assert_eq!(a, b);
}