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

nordisk/gunnar

xtask/tests/cli_verbs.rs

//! `cargo xtask <task>`: what the binary answers before any task does real work.
//! A task with no name, an unknown task and every malformed argument stop with a
//! failing exit code and a sentence that names what was wrong; a mistyped flag
//! must never run a different task than the operator asked for.

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

const EXE: &str = env!("CARGO_BIN_EXE_xtask");

fn xtask(args: &[&str]) -> Output {
    Command::new(EXE)
        .args(args)
        .output()
        .expect("the xtask binary runs")
}

/// The run failed, and its stderr says `want`.
fn refused(args: &[&str], want: &str) {
    let out = xtask(args);
    let err = String::from_utf8_lossy(&out.stderr);
    assert!(
        !out.status.success(),
        "`xtask {}` succeeded",
        args.join(" ")
    );
    assert!(
        err.contains(want),
        "`xtask {}` did not say {want:?}:\n{err}",
        args.join(" ")
    );
}

#[test]
fn no_task_and_an_unknown_task_print_the_usage_and_fail() {
    refused(&[], "usage: cargo xtask <task>");
    refused(&["frobnicate"], "xtask: unknown task `frobnicate`");
    refused(&["frobnicate"], "usage: cargo xtask <task>");
}

#[test]
fn siblings_is_a_successful_no_op_that_says_why() {
    let out = xtask(&["siblings"]);
    assert!(out.status.success());
    assert!(String::from_utf8_lossy(&out.stderr).contains("nothing to switch on"));
}

/// `fmt --all` is refused BY NAME: it follows path dependencies out of the repository.
#[test]
fn fmt_refuses_all_and_unknown_arguments() {
    refused(&["fmt", "--all"], "refusing `--all`");
    refused(
        &["fmt", "--all"],
        "`cargo xtask fmt` with no argument already covers",
    );
    refused(&["fmt", "--diff"], "xtask fmt: unknown argument `--diff`");
}

#[test]
fn malformed_arguments_are_refused_by_each_task() {
    refused(
        &["trailer-guard", "--commits", "many"],
        "--commits needs a number",
    );
    refused(&["trailer-guard", "--commits"], "--commits needs a number");
    refused(
        &["trailer-guard", "--all"],
        "xtask trailer-guard: unknown argument `--all`",
    );
    refused(
        &["publish", "--force"],
        "usage: cargo xtask publish [--push]",
    );
    refused(
        &["bench-build", "--fast"],
        "usage: cargo xtask bench-build [--check | --build]",
    );
    refused(
        &["roundtrip", "--no-mutat"],
        "roundtrip: unknown flag `--no-mutat`",
    );
    refused(
        &["roundtrip", "--seed", "abc"],
        "--seed `abc` is not a number",
    );
    refused(
        &["roundtrip", "--donor", "no-equals-sign"],
        "--donor wants `<name>=<url>`",
    );
    refused(&["roundtrip", "--work"], "--work needs a value");
    refused(&["wireproxy", "--to"], "--to needs a value");
    refused(
        &["wireproxy", "--bogus"],
        "wireproxy: unknown argument `--bogus`",
    );
    refused(
        &["wireproxy", "--listen", "127.0.0.1:1"],
        "--to is required",
    );
    refused(&["payload"], "--variant <installer cell> is required");
    refused(&["payload", "--variant"], "--variant needs a value");
    refused(
        &["payload", "--variant", "x", "--frob"],
        "unknown flag `--frob`",
    );
}

/// `bench` with no suite lists the suites; an unknown one is named with the known ones.
#[test]
fn bench_lists_its_suites_and_refuses_an_unknown_one() {
    let first = xtask::benchrun::SUITES
        .first()
        .expect("a declared suite")
        .name;
    refused(&["bench"], "usage: cargo xtask bench <suite>");
    refused(&["bench"], first);
    refused(
        &["bench", "no-such-suite"],
        "xtask bench: unknown suite `no-such-suite`",
    );
    refused(&["bench", "no-such-suite"], &format!("known: {first}"));
}

/// `iso-installer --help` answers without building anything.
#[test]
fn iso_installer_help_answers_without_building() {
    let out = xtask(&["iso-installer", "--help"]);
    assert!(out.status.success());
    let text = String::from_utf8_lossy(&out.stdout);
    assert!(
        text.contains("cargo xtask iso-installer — build gunnar's INSTALLER ISO"),
        "{text}"
    );
    assert!(text.contains("--unenrolled '<why>'"), "{text}");
}

/// `payload --no-build --out <dir>` writes what the medium would boot: the kernel
/// command line, the payload row, and each staged file at its runtime path.
#[test]
fn payload_writes_the_start_of_a_medium_without_building_it() {
    // a linked worktree cannot stamp what it builds, so the verb refuses there first
    let root = xtask::guard::workspace_root();
    if xtask::isoinstaller::worktree_refusal(&root).is_some() {
        refused(
            &[
                "payload",
                "--variant",
                "gunnar-installer-metered",
                "--no-build",
            ],
            "REFUSED [iso-installer-worktree]",
        );
        return;
    }
    refused(
        &["payload", "--variant", "no-such-cell", "--no-build"],
        "no [[build.installer]] cell named 'no-such-cell'",
    );
    let dir = std::env::temp_dir().join(format!("gunnar-cli-payload-{}", std::process::id()));
    let _ = std::fs::remove_dir_all(&dir);
    std::fs::create_dir_all(&dir).unwrap();
    let seed: PathBuf = dir.join("seed.toml");
    std::fs::write(&seed, "estate = \"cli\"\n").unwrap();
    let out_dir = dir.join("out");
    let param = format!("pairing_seed=@{}", seed.display());
    let out = xtask(&[
        "payload",
        "--variant",
        "gunnar-installer-metered",
        "--param",
        &param,
        "--no-build",
        "--out",
        out_dir.to_str().unwrap(),
    ]);
    assert!(
        out.status.success(),
        "{}",
        String::from_utf8_lossy(&out.stderr)
    );
    let cmdline = std::fs::read_to_string(out_dir.join("cmdline")).unwrap();
    assert!(
        cmdline.contains("korp.env.GUNNAR_DATA_ROOT=/data"),
        "{cmdline}"
    );
    assert_eq!(
        std::fs::read_to_string(out_dir.join("payload-variant")).unwrap(),
        "gunnar-server-metered\n"
    );
    assert_eq!(
        std::fs::read_to_string(out_dir.join("staged/data/pairing/seed.toml")).unwrap(),
        "estate = \"cli\"\n"
    );
    assert!(
        !out_dir.join("binary").exists(),
        "--no-build named a binary"
    );

    let out = xtask(&[
        "payload",
        "--variant",
        "gunnar-front-installer-metered",
        "--no-build",
    ]);
    assert!(
        out.status.success(),
        "{}",
        String::from_utf8_lossy(&out.stderr)
    );
    assert!(String::from_utf8_lossy(&out.stdout).contains("korp.entry=gunnar-front"));
    let _ = std::fs::remove_dir_all(&dir);
}