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

nordisk/holger

server/cli/tests/open_cli_speaks_no_money.rs

//! **The open command line offers no money** (A28 M13): the half of Gunnar's guard that walks
//! the `clap` tree (`the_open_command_line_offers_no_money`), here over the built `holger`
//! binary's own `--help` (the CLI is a bin, so its `Cli` is not reachable from a test).
//! Every subcommand's help is asked for and judged by the one judge,
//! `server/lib/tests/money/judge.rs` (Gunnar's, verbatim). A `metered` build may speak of
//! money: it is the one paired with monetize, so this is scoped to the open build.

#[path = "../../lib/tests/money/judge.rs"]
mod judge;

use std::process::Command;

/// The subcommand names a `clap` help lists under `Commands:`.
fn subcommands(help: &str) -> Vec<String> {
    let mut out = Vec::new();
    let mut inside = false;
    for line in help.lines() {
        if line.trim_end() == "Commands:" {
            inside = true;
            continue;
        }
        if inside {
            if line.trim().is_empty() || !line.starts_with("  ") {
                if !line.trim().is_empty() {
                    inside = false;
                }
                continue;
            }
            if let Some(name) = line.split_whitespace().next() {
                if name != "help" && !line.starts_with("   ") {
                    out.push(name.trim_end_matches(',').to_owned());
                }
            }
        }
    }
    out
}

#[test]
fn the_help_reader_finds_the_subcommands() {
    let help = "holger\n\nUsage: holger <COMMAND>\n\nCommands:\n  start   Start the server\n  token   Mint a token\n          (continued)\n  help    Print this message\n\nOptions:\n  -h, --help\n";
    assert_eq!(subcommands(help), vec!["start", "token"]);
}

fn help_of(path: &[String]) -> String {
    let out = Command::new(env!("CARGO_BIN_EXE_holger"))
        .args(path)
        .arg("--help")
        .output()
        .expect("the holger binary runs");
    let mut text = String::from_utf8_lossy(&out.stdout).into_owned();
    text.push_str(&String::from_utf8_lossy(&out.stderr));
    text
}

#[cfg(not(feature = "metered"))]
#[test]
fn the_open_command_line_offers_no_money() {
    let mut stack: Vec<Vec<String>> = vec![Vec::new()];
    let mut walked = 0usize;
    let mut leaks = Vec::new();
    while let Some(path) = stack.pop() {
        let help = help_of(&path);
        walked += 1;
        for (n, para) in help.split("\n\n").enumerate() {
            let hits = judge::leaks_in(para);
            if !hits.is_empty() {
                leaks.push(format!(
                    "holger {} --help ¶{}: {hits:?} in {:?}",
                    path.join(" "),
                    n + 1,
                    para.trim()
                ));
            }
        }
        if path.len() < 3 {
            for sub in subcommands(&help) {
                let mut next = path.clone();
                next.push(sub);
                stack.push(next);
            }
        }
    }
    assert!(
        walked > 5,
        "only {walked} help pages were read; the help layout moved"
    );
    assert!(
        leaks.is_empty(),
        "the OPEN holger command line offers money vocabulary to its operator ({} hits). holger \
         takes no money; every word below belongs to the private monetize half, behind \
         `metered`.\n  {}",
        leaks.len(),
        leaks.join("\n  ")
    );
}