Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

xtask/tests/guard_report.rs

//! The dependency guard's verdict as data: every rule prints its own name, the report
//! prints every finding under its own heading, and the appliance-growth budget is held
//! from both sides (`xtask/src/guard.rs`).

use xtask::guard::{
    check_appliance_growth, Report, Rule, Violation, APPLIANCE, APPLIANCE_HTTP, HTTP_GROWTH_BUDGET,
};

fn v(profile: &str, rule: Rule, item: &str) -> Violation {
    Violation {
        profile: profile.to_string(),
        rule,
        item: item.to_string(),
        why: format!("because of {item}"),
    }
}

fn sized(plain: usize, with_http: usize) -> Report {
    Report {
        sizes: vec![
            (APPLIANCE.to_string(), plain + 40, plain),
            (APPLIANCE_HTTP.to_string(), with_http + 40, with_http),
        ],
        ..Report::default()
    }
}

#[test]
fn every_rule_and_violation_prints_what_it_is() {
    let names: Vec<String> = [
        Rule::VacuousGraph,
        Rule::ForbiddenAnywhere,
        Rule::ForbiddenInServerGraph,
        Rule::GixPorcelainFeature,
        Rule::StaleDeviation,
        Rule::PhantomRule,
        Rule::SlackBudget,
    ]
    .iter()
    .map(|r| r.to_string())
    .collect();
    assert_eq!(
        names,
        [
            "vacuous graph",
            "forbidden anywhere",
            "forbidden in the S graph",
            "gix porcelain feature in the S graph",
            "stale tracked deviation",
            "phantom rule name",
            "slack budget",
        ]
    );
    assert_eq!(
        v("appliance", Rule::ForbiddenAnywhere, "openssl-sys").to_string(),
        "[appliance] forbidden anywhere: openssl-sys — because of openssl-sys"
    );
}

/// Each kind of finding is printed under its own heading, and only a report with no
/// violation, no stale deviation and no phantom rule is clean.
#[test]
fn the_report_prints_every_finding_and_only_an_empty_one_is_clean() {
    let mut r = sized(310, 310);
    assert!(r.is_clean());
    assert_eq!(r.size(APPLIANCE), Some((350, 310)));
    assert_eq!(r.size("no-such-profile"), None);
    r.tracked
        .push(v("S", Rule::ForbiddenInServerGraph, "tracked-crate"));
    assert!(r.is_clean(), "a tracked deviation is printed, not failed");
    r.stale_deviations
        .push(v("S", Rule::StaleDeviation, "old-excuse"));
    r.phantom_rules
        .push(v("*", Rule::PhantomRule, "never-built"));
    r.violations.push(v(
        "S",
        Rule::GixPorcelainFeature,
        "gix:blocking-network-client",
    ));
    assert!(!r.is_clean());
    let page = r.render();
    let lines: Vec<&str> = page.lines().collect();
    assert_eq!(lines.len(), 6, "{page}");
    assert!(
        lines[0].starts_with("  size     appliance")
            && lines[0].ends_with("350 crates (310 third-party)"),
        "{page}"
    );
    assert!(
        lines[2].starts_with("  tracked  [S] forbidden in the S graph: tracked-crate"),
        "{page}"
    );
    assert!(
        lines[3].starts_with("  STALE    [S] stale tracked deviation: old-excuse"),
        "{page}"
    );
    assert!(
        lines[4].starts_with("  PHANTOM  [*] phantom rule name: never-built"),
        "{page}"
    );
    assert!(
        lines[5].starts_with("  VIOLATION [S] gix porcelain feature"),
        "{page}"
    );
    let mut empty = Report::default();
    assert_eq!(empty.render(), "");
    empty.violations.push(v("x", Rule::VacuousGraph, "y"));
    assert!(!empty.is_clean());
}

/// The smart-HTTP growth budget: a run that did not resolve both graphs checked
/// nothing and says so; growth over the budget is forbidden; growth under it is slack.
#[test]
fn the_growth_budget_is_held_from_both_sides() {
    let missing = check_appliance_growth(&Report::default());
    assert_eq!(missing.len(), 1);
    assert_eq!(missing[0].rule, Rule::VacuousGraph);
    assert!(
        missing[0].why.contains("not both resolved"),
        "{}",
        missing[0].why
    );

    assert_eq!(
        check_appliance_growth(&sized(310, 310 + HTTP_GROWTH_BUDGET)),
        Vec::new()
    );

    let over = check_appliance_growth(&sized(310, 311 + HTTP_GROWTH_BUDGET));
    assert_eq!(over.len(), 1);
    assert_eq!(over[0].rule, Rule::ForbiddenAnywhere);
    assert!(
        over[0]
            .why
            .contains(&format!("adds {} third-party", HTTP_GROWTH_BUDGET + 1)),
        "{}",
        over[0].why
    );

    // with http resolving FEWER third-party crates the growth saturates at zero
    let shrunk = check_appliance_growth(&sized(310, 300));
    if HTTP_GROWTH_BUDGET == 0 {
        assert_eq!(shrunk, Vec::new());
    } else {
        assert_eq!(shrunk.len(), 1);
        assert_eq!(shrunk[0].rule, Rule::SlackBudget);
    }
}