parlov-elicit 0.5.0

Elicitation engine: strategy selection and probe plan generation for parlov.
Documentation
use super::super::*;
use crate::types::ProbeSpec;
use crate::types::RiskLevel;

fn make_full_ctx_with_body() -> crate::context::ScanContext {
    let mut ctx = super::make_full_ctx();
    ctx.body_template = Some("{\"id\": \"{id}\"}".to_string());
    ctx
}

#[test]
fn spec_count_by_strategy() {
    let ctx = make_full_ctx_with_body();
    let strategies = all_strategies();

    println!();
    println!(
        "{:<42}  {:<22}  {:>5}  variants (method)",
        "strategy-id", "risk", "specs"
    );
    println!("{}", "-".repeat(90));

    let mut total_specs = 0usize;
    let mut total_skipped = 0usize;

    for strategy in &strategies {
        let risk = strategy.risk();
        let risk_label = match risk {
            RiskLevel::Safe => "Safe",
            RiskLevel::MethodDestructive => "MethodDestructive",
            RiskLevel::OperationDestructive => "OperationDestructive",
        };

        if risk > ctx.max_risk {
            println!(
                "{:<42}  {:<22}  skipped (risk ceiling)",
                strategy.id(),
                risk_label,
            );
            total_skipped += 1;
            continue;
        }

        if !strategy.is_applicable(&ctx) {
            println!(
                "{:<42}  {:<22}  skipped (not applicable)",
                strategy.id(),
                risk_label,
            );
            total_skipped += 1;
            continue;
        }

        let specs = strategy.generate(&ctx);
        let spec_count = specs.len();
        total_specs += spec_count;

        let detail: Vec<String> = specs
            .iter()
            .map(|spec| {
                let (variant, method) = match spec {
                    ProbeSpec::Pair(p) => ("Pair", p.baseline.method.as_str()),
                    ProbeSpec::Burst(b) => ("Burst", b.baseline.method.as_str()),
                    ProbeSpec::HeaderDiff(p) => ("HeaderDiff", p.baseline.method.as_str()),
                };
                format!("{variant}({method})")
            })
            .collect();

        println!(
            "{:<42}  {:<22}  {:>5}  {}",
            strategy.id(),
            risk_label,
            spec_count,
            detail.join(", "),
        );
    }

    println!("{}", "-".repeat(90));
    println!(
        "{:<42}  {:<22}  {:>5}  ({} skipped)",
        "TOTAL", "", total_specs, total_skipped,
    );
    println!();
}