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

nordisk/gunnar

crates/gunnar-build-thing/tests/the_door.rs

//! **The `gunnar-build-thing` binary's doors**, run as the operator runs them (lane
//! OSSF-SILVER-CODE, 2026-10-31): `--list`, `toml`, `emit`, a composing variant, an unknown
//! name and the usage. Every answer is read off the process: its exit status, its stdout
//! and the file it wrote. Building a variant (`cargo build`) is not exercised here; the
//! forge's release rows do that.

use std::process::{Command, Output};

fn door(args: &[&str]) -> Output {
    Command::new(env!("CARGO_BIN_EXE_gunnar-build-thing"))
        .args(args)
        .output()
        .expect("run gunnar-build-thing")
}

fn text(bytes: &[u8]) -> String {
    String::from_utf8_lossy(bytes).into_owned()
}

/// No argument and `--help` print the usage and fail: a build tool asked to build
/// nothing has not succeeded.
#[test]
fn no_argument_and_help_print_the_usage_and_fail() {
    for args in [&[][..], &["--help"][..], &["toml", "-h"][..]] {
        let out = door(args);
        assert!(!out.status.success(), "{args:?} succeeded");
        assert!(
            text(&out.stderr).contains("usage: gunnar-build <variant>"),
            "{args:?}: {}",
            text(&out.stderr)
        );
    }
}

/// `--list` names every declared build point once, with its cargo selector or the note
/// that it composes others.
#[test]
fn the_list_names_every_declared_build_point() {
    let out = door(&["--list"]);
    assert!(out.status.success());
    let listed = text(&out.stdout);
    for variant in gunnar_build_thing::VARIANTS {
        let line = listed
            .lines()
            .find(|l| l.split_whitespace().next() == Some(variant.name))
            .unwrap_or_else(|| panic!("{} is not listed:\n{listed}", variant.name));
        match (variant.package, variant.bin) {
            (Some(p), Some(b)) => assert!(line.contains(&format!("-p {p} --bin {b}")), "{line}"),
            (Some(p), None) => assert!(line.contains(&format!("-p {p}")), "{line}"),
            _ => assert!(line.contains("runs no cargo"), "{line}"),
        }
    }
    assert_eq!(listed.lines().count(), gunnar_build_thing::VARIANTS.len());
}

/// `toml` prints the emitted declaration and `emit <root>` writes the same bytes to
/// `<root>/.nornir/build-variants.toml`; `emit` onto a root it cannot write fails by name.
#[test]
fn toml_and_emit_write_the_one_declaration() {
    let printed = door(&["toml"]);
    assert!(printed.status.success(), "{}", text(&printed.stderr));
    let expected = gunnar_build_thing::emitted_toml().expect("the declaration emits");
    assert_eq!(text(&printed.stdout), expected);

    let root = std::env::temp_dir().join(format!("gunnar-build-emit-{}", std::process::id()));
    let _ = std::fs::remove_dir_all(&root);
    std::fs::create_dir_all(&root).unwrap();
    let emitted = door(&["emit", root.to_str().unwrap()]);
    assert!(emitted.status.success(), "{}", text(&emitted.stderr));
    assert!(
        text(&emitted.stdout).starts_with("emitted "),
        "{}",
        text(&emitted.stdout)
    );
    let written = std::fs::read_to_string(root.join(".nornir/build-variants.toml"))
        .expect("the file emit wrote");
    assert_eq!(written, expected);

    // A root that is a file: `.nornir` cannot be made under it.
    let file = root.join("a-file");
    std::fs::write(&file, b"not a directory").unwrap();
    let refused = door(&["emit", file.to_str().unwrap()]);
    assert!(!refused.status.success(), "emit under a file succeeded");
    assert!(
        text(&refused.stderr).contains("gunnar-build-thing:"),
        "{}",
        text(&refused.stderr)
    );
    let _ = std::fs::remove_dir_all(&root);
}

/// An unknown name is refused before anything is built, and points at `--list`; a
/// variant that composes others runs no cargo and succeeds.
#[test]
fn an_unknown_name_is_refused_and_a_composing_variant_runs_no_cargo() {
    let out = door(&["no-such-build-point"]);
    assert!(!out.status.success());
    let err = text(&out.stderr);
    assert!(
        err.contains("no build point named `no-such-build-point`") && err.contains("--list"),
        "{err}"
    );

    let composing = gunnar_build_thing::VARIANTS
        .iter()
        .find(|v| v.package.is_none())
        .expect("a variant that composes others");
    let out = door(&[composing.name]);
    assert!(out.status.success(), "{}", text(&out.stderr));
    assert!(
        text(&out.stderr).contains("runs no cargo; skipping"),
        "{}",
        text(&out.stderr)
    );
}