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

mikronova/modgunn

tests/manifests_ingest.rs

//! Out-of-crate proof for the multi-ecosystem manifest ingest seam
//! ([`modgunn::manifests`]).
//!
//! Drives the PUBLIC dispatch ([`parse_manifest`]) once per ecosystem with a
//! small real-shaped fixture and asserts the EXACT components/versions parsed —
//! red-when-broken, one fixture per ecosystem (cargo/pip/npm/maven/go/nuget/gem).
//! The module's in-crate unit tests cover each format variant; this proves the
//! whole seam works through the crate's public API a consumer actually calls.
//!
//! Under `--features testmatrix` it ALSO drains the process-global functional
//! buffer and asserts the ingest surface lit one GREEN row per ecosystem, so
//! `nornir test` SEES the seam. A single test owns the buffer (no parallel race).
#![cfg(feature = "manifests")]

use modgunn::manifests::parse_manifest;
use modgunn::sbom::SbomComponent;

fn rows(comps: &[SbomComponent]) -> Vec<(String, String, String)> {
    comps
        .iter()
        .map(|c| (c.ecosystem.clone(), c.name.clone(), c.version.clone()))
        .collect()
}

fn parse(filename: &str, content: &str) -> Vec<SbomComponent> {
    parse_manifest(filename, content)
        .unwrap_or_else(|| panic!("no ecosystem parser owns {filename}"))
        .unwrap_or_else(|e| panic!("{filename} failed to parse: {e}"))
}

fn eco_row(eco: &str, name: &str, ver: &str) -> (String, String, String) {
    (eco.into(), name.into(), ver.into())
}

#[test]
fn all_ecosystems_parse_via_public_dispatch() {
    #[cfg(feature = "testmatrix")]
    let _ = nornir_testmatrix::drain_functional_rows(); // start from a clean buffer

    // cargo — Cargo.lock
    assert_eq!(
        rows(&parse(
            "Cargo.lock",
            "[[package]]\nname = \"serde\"\nversion = \"1.0.203\"\n"
        )),
        vec![eco_row("cargo", "serde", "1.0.203")],
    );

    // pip — requirements.txt (a pin and a range; only the pin resolves)
    assert_eq!(
        rows(&parse(
            "requirements.txt",
            "requests==2.31.0\nurllib3>=1.26\n"
        )),
        vec![eco_row("pip", "requests", "2.31.0")],
    );

    // npm — package-lock.json (v3 packages map, root skipped)
    assert_eq!(
        rows(&parse(
            "package-lock.json",
            r#"{"lockfileVersion":3,"packages":{"":{"name":"r","version":"1.0.0"},"node_modules/left-pad":{"version":"1.3.0"}}}"#,
        )),
        vec![eco_row("npm", "left-pad", "1.3.0")],
    );

    // maven — pom.xml (groupId:artifactId name)
    assert_eq!(
        rows(&parse(
            "pom.xml",
            "<project><dependencies><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>33.0.0-jre</version></dependency></dependencies></project>",
        )),
        vec![eco_row("maven", "com.google.guava:guava", "33.0.0-jre")],
    );

    // go — go.mod (single require, version keeps its `v`)
    assert_eq!(
        rows(&parse(
            "go.mod",
            "module x\n\nrequire github.com/pkg/errors v0.9.1\n"
        )),
        vec![eco_row("go", "github.com/pkg/errors", "v0.9.1")],
    );

    // nuget — packages.lock.json (resolved version)
    assert_eq!(
        rows(&parse(
            "packages.lock.json",
            r#"{"dependencies":{"net6.0":{"Newtonsoft.Json":{"resolved":"13.0.3"}}}}"#,
        )),
        vec![eco_row("nuget", "Newtonsoft.Json", "13.0.3")],
    );

    // gem — Gemfile.lock (a spec, its constraint children skipped)
    assert_eq!(
        rows(&parse(
            "Gemfile.lock",
            "GEM\n  specs:\n    rake (13.0.6)\n      other (>= 1.0)\n",
        )),
        vec![eco_row("gem", "rake", "13.0.6")],
    );

    // Unknown filename ⇒ no parser owns it.
    assert!(parse_manifest("mystery.lock", "").is_none());

    // ── functional_status: one GREEN ingest row per ecosystem ────────────────
    #[cfg(feature = "testmatrix")]
    {
        use nornir_testmatrix::{drain_functional_rows, status};
        let rows = drain_functional_rows();
        for eco in ["cargo", "pip", "npm", "maven", "go", "nuget", "gem"] {
            let suite = format!("modgunn/manifest-ingest-{eco}");
            let hit = rows
                .iter()
                .find(|r| r.suite == suite && r.test_name == "parse_manifest")
                .unwrap_or_else(|| panic!("no ingest row for {eco}: {rows:#?}"));
            assert!(
                status::is_green(&hit.status),
                "{eco} parsed OK ⇒ GREEN row: {hit:#?}"
            );
            assert_eq!(
                hit.aspect, "functional",
                "ingest markers ride the `functional` aspect"
            );
        }
    }
}