Files
punktfunk/clients/cli/tests/cli_smoke.rs
T
enricobuehlerandClaude Fable 5 8e396b8391 feat(cli): every command explains itself
`punktfunk help` was one usage blob, and `punktfunk pair --help` was worse than
nothing: the flag fell through to the verb, which read "--help" as its subject,
printed a terse usage line to stderr and exited 5. For the command that is about to
be the documented door for scripts and plugins (Playnite shells to `library --json`),
"self-documenting" has to actually hold.

Now `punktfunk help <command>` — and `--help`/`-h` after any verb, caught BEFORE
dispatch so no verb can mistake the flag for its subject — prints that command's own
page: flags, what lands on stdout vs stderr, and which exit code means what, which is
the part a script author actually needs. Help goes to stdout and exits 0; an unknown
topic refuses with 5. A unit test walks USAGE and asserts every advertised verb has a
help page that leads with its own invocation, so the overview and the pages cannot
drift apart, and an integration test runs the REAL binary over both spellings.

`reachable` also stops scolding: probing an unsaved address is that verb's documented
use, but it resolved through the saved-host path first, whose "pair it first" advice
printed before the probe ran. It resolves quietly now — same lookup, no lecture.

Verified on the Windows CI runner (clippy -D warnings, fmt, 8/8 tests, and the built
punktfunk.exe by hand: overview, per-verb pages, quiet `reachable` exit 2) and in the
Linux CI image (same gates, 8/8). One field note from the hand run: the exe needs the
FFmpeg DLLs beside it or on PATH — true of the session binary already, and the MSIX
ships them next to both, so packaging is unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 10:58:44 +02:00

70 lines
2.4 KiB
Rust

//! Runs the REAL `punktfunk` binary and pins its self-documentation contract: help goes
//! to stdout and exits 0, an unknown verb refuses on stderr with the not-found code.
//!
//! This exists so CI *executes* the shipped binary at least once per platform. A binary
//! that compiles but is the wrong program passes every build/clippy/fmt gate — that is
//! exactly how 0.22.0 shipped a stub as `punktfunk-session` — and only a gate that runs
//! the thing catches the class. The help paths are the right probe: they touch no config
//! stores and no network, so they are safe on any runner.
#![cfg(any(target_os = "linux", windows))]
use std::process::Command;
fn punktfunk(args: &[&str]) -> std::process::Output {
Command::new(env!("CARGO_BIN_EXE_punktfunk"))
.args(args)
.output()
.expect("run punktfunk")
}
#[test]
fn bare_and_help_print_the_overview_on_stdout() {
for args in [&[][..], &["help"][..], &["--help"][..], &["-h"][..]] {
let out = punktfunk(args);
assert!(out.status.success(), "{args:?} must exit 0");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(
stdout.contains("punktfunk pair"),
"{args:?} overview lists the verbs"
);
assert!(
stdout.contains("help <command>"),
"{args:?} overview points at per-verb help"
);
}
}
#[test]
fn per_verb_help_answers_both_spellings() {
for args in [
&["help", "launch"][..],
&["launch", "--help"][..],
&["launch", "-h"][..],
] {
let out = punktfunk(args);
assert!(out.status.success(), "{args:?} must exit 0");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(
stdout.contains("--exec"),
"{args:?} documents launch's flags"
);
}
}
#[test]
fn version_prints_the_crate_version() {
let out = punktfunk(&["--version"]);
assert!(out.status.success());
assert!(String::from_utf8_lossy(&out.stdout).contains(env!("CARGO_PKG_VERSION")));
}
#[test]
fn unknown_verbs_refuse_with_the_not_found_code() {
let out = punktfunk(&["frobnicate"]);
assert_eq!(out.status.code(), Some(5), "unknown verb exits 5");
assert!(String::from_utf8_lossy(&out.stderr).contains("unknown command"));
let out = punktfunk(&["help", "frobnicate"]);
assert_eq!(out.status.code(), Some(5), "unknown help topic exits 5");
}