cargo-allow 0.1.3

Source-tree exception ledger and policy scanner for Rust repositories.
use super::test_support::test_finding_at_line;
use super::*;
use crate::artifact_contract_support::{assert_inventory_contract, parse_json_artifact};
use serde_json::Value;

#[test]
fn render_add_summary_json_records_entry_and_selected_finding() {
    let mut finding = test_finding_at_line(
        FindingKind::Panic,
        Some("unwrap"),
        "src/lib.rs",
        "method_call",
        42,
    );
    finding.identity.crate_name = Some("parser".to_string());
    finding.identity.container = Some("parse_span".to_string());
    finding.identity.callee = Some("unwrap".to_string());
    let mut entry = allow_entry_from_finding(AddEntryRequest {
        finding: &finding,
        id: "allow-0101".to_string(),
        owner: "parser".to_string(),
        classification: "validated_invariant".to_string(),
        reason: "Parser validates the span before unwrapping.".to_string(),
        evidence: vec!["test:parser_validates_span".to_string()],
        review_after: "2026-11-01".to_string(),
        expires: Some("2027-01-01".to_string()),
    });
    entry.selector.normalized_snippet_hash = Some("fnv1a64:1234".to_string());

    let json = render_add_summary_json(
        &entry,
        &finding,
        Some(Path::new("policy/allow.proposed.toml")),
        true,
        AddContext {
            inventory: allow_report::InventoryContext::source_syntax(
                "git_tracked",
                Some("H:/Code/Rust/cargo-allow"),
                Some(52),
            ),
        },
    );
    let value = parse_json_artifact("add", &json, allow_report::ADD_SCHEMA_ID, "add");

    assert_inventory_contract(
        "add",
        &value,
        "git_tracked",
        Some("H:/Code/Rust/cargo-allow"),
        Some(52),
    );
    assert_eq!(
        value
            .pointer("/options/policy_output")
            .and_then(Value::as_str),
        Some("policy/allow.proposed.toml"),
        "add policy output"
    );
    assert_eq!(
        value.pointer("/options/force").and_then(Value::as_bool),
        Some(true),
        "add force"
    );
    assert_eq!(
        value.pointer("/summary/entry_id").and_then(Value::as_str),
        Some("allow-0101"),
        "add summary entry id"
    );
    assert_eq!(
        value
            .pointer("/summary/human_review_required")
            .and_then(Value::as_bool),
        Some(true),
        "add human_review_required"
    );
    assert_eq!(
        value.pointer("/allow_entry/id").and_then(Value::as_str),
        Some("allow-0101"),
        "add allow id"
    );
    assert_eq!(
        value
            .pointer("/allow_entry/evidence_count")
            .and_then(Value::as_u64),
        Some(1),
        "add evidence count"
    );
    assert_eq!(
        value
            .pointer("/selected_finding/source_package")
            .and_then(Value::as_str),
        Some("parser"),
        "add selected finding source package"
    );
}

#[test]
fn render_add_summary_human_records_inventory_context() {
    let finding = test_finding_at_line(
        FindingKind::Panic,
        Some("unwrap"),
        "src/lib.rs",
        "method_call",
        42,
    );
    let entry = allow_entry_from_finding(AddEntryRequest {
        finding: &finding,
        id: "allow-0101".to_string(),
        owner: "parser".to_string(),
        classification: "validated_invariant".to_string(),
        reason: "Parser validates the span before unwrapping.".to_string(),
        evidence: vec!["test:parser_validates_span".to_string()],
        review_after: "2026-11-01".to_string(),
        expires: Some("2027-01-01".to_string()),
    });

    let text = render_add_summary(
        &entry,
        &finding,
        Some(Path::new("policy/allow.proposed.toml")),
        AddContext {
            inventory: allow_report::InventoryContext::source_syntax(
                "git_tracked",
                Some("H:/Code/Rust/cargo-allow"),
                Some(52),
            ),
        },
    );

    assert!(
        text.contains("inventory: source_tree/source_syntax via git_tracked; files scanned: 52")
    );
    assert!(text.contains("source_tree_root: H:/Code/Rust/cargo-allow"));
    assert!(text.contains("matched finding: src/lib.rs:42:1"));
    assert!(text.contains("Claim boundary: scanned source-tree/source syntax only"));
}