marver 0.0.9

A TUI workspace for AI agent sessions: tmux orchestration, git worktree management, and repo control in one place.
Documentation
//! What the binary says about itself.

use std::process::Command;

fn run(args: &[&str]) -> std::process::Output {
    Command::new(env!("CARGO_BIN_EXE_marver"))
        .args(args)
        .output()
        .expect("run marver")
}

#[test]
fn the_version_flag_reports_the_crate_version() {
    // Both spellings, because `-V` is what clap-shaped tools train people to
    // type and `--version` is what everything else does.
    for flag in ["-V", "--version"] {
        let out = run(&[flag]);
        let text = String::from_utf8_lossy(&out.stdout).trim().to_string();

        assert!(out.status.success(), "{flag} should exit 0");
        assert_eq!(text, format!("marver {}", env!("CARGO_PKG_VERSION")));
    }
}

#[test]
fn the_version_flag_does_not_open_the_interface() {
    // A leading flag otherwise falls through to the interface, which would try
    // to take over the terminal — and, since 0.0.6, start a daemon on the way.
    // The version arm has to come first.
    let out = run(&["--version"]);
    let text = String::from_utf8_lossy(&out.stdout);
    assert!(!text.contains("Tasks"), "{text:?}");
    assert!(text.lines().count() == 1, "one line and no more: {text:?}");
}

#[test]
fn an_unknown_subcommand_is_refused_rather_than_assumed() {
    let out = run(&["wat"]);
    let stderr = String::from_utf8_lossy(&out.stderr);
    assert!(!out.status.success());
    assert!(stderr.contains("unknown command"), "{stderr:?}");
}

#[test]
fn help_asked_for_goes_to_stdout_and_succeeds() {
    // `marver --help | less` is someone reading. A shell that treats it as a
    // failure is wrong about what happened, and the text belongs on stdout
    // where a pipe can reach it.
    let out = run(&["--help"]);
    let text = String::from_utf8_lossy(&out.stdout);

    assert!(out.status.success(), "help was asked for, not misused");
    assert!(
        String::from_utf8_lossy(&out.stderr).is_empty(),
        "nothing went wrong, so stderr stays quiet"
    );
    for command in ["status", "daemon", "scan", "hook", "--version"] {
        assert!(
            text.contains(command),
            "{command} missing from help: {text:?}"
        );
    }
}

#[test]
fn help_as_a_correction_goes_to_stderr_and_fails() {
    // The same text, the opposite event. Sharing one exit code between them is
    // what made `--help` report failure in the first place.
    let out = run(&["wat"]);
    let stderr = String::from_utf8_lossy(&out.stderr);

    assert!(!out.status.success());
    assert!(stderr.contains("usage:"), "{stderr:?}");
    assert!(
        String::from_utf8_lossy(&out.stdout).is_empty(),
        "a correction does not belong on stdout"
    );
}