test(cli): RED — aura graph with a bad blueprint arg must be a usage fault (#28)
The #28 cycle-close audit found the just-shipped `aura graph <file>` silently renders the embedded sample at exit 0 when the positional names an unreadable blueprint (typo, nonexistent path, wrong extension): is_blueprint_file returns None both for "no positional" (the legit sample default) and for a bad arg, and dispatch_graph's None arm conflates them — re-introducing the exact #28 "I asked for my graph, got the sample" surprise in the error path. This pins the fix: a named-but-unreadable arg exits 2 like its siblings, while bare `aura graph` still renders the sample. refs #28
This commit is contained in:
@@ -709,6 +709,65 @@ fn graph_renders_a_consumer_blueprint_file_not_the_embedded_sample() {
|
||||
);
|
||||
}
|
||||
|
||||
/// Property (#28 close-audit): a NAMED-but-unreadable blueprint arg to
|
||||
/// `aura graph` is a usage fault, not a silent fallback to the embedded sample.
|
||||
/// `dispatch_graph`'s no-subcommand arm branches on `is_blueprint_file`, which
|
||||
/// returns `None` for BOTH "no positional given" (→ legitimate sample default)
|
||||
/// and "a positional was given but it is not a readable `.json` file" (→ a bad
|
||||
/// arg). The two must not be conflated: a bad arg (typo, nonexistent path, wrong
|
||||
/// extension) must `eprintln!` a usage error and exit 2, mirroring `dispatch_run`
|
||||
/// — NOT render the r_sma sample and exit 0, which re-introduces the exact #28
|
||||
/// friction ("I asked for my graph, got the sample") in the error path. The
|
||||
/// bare-`aura graph` default (no positional → sample, exit 0) is guarded in the
|
||||
/// same test so the fix cannot regress it.
|
||||
#[test]
|
||||
fn graph_with_bad_blueprint_arg_is_a_usage_fault_not_a_silent_sample() {
|
||||
let cwd = temp_cwd("graph-bad-arg");
|
||||
// A named .json path that does not exist: `is_blueprint_file` returns None,
|
||||
// and the buggy arm falls through to the embedded sample instead of refusing.
|
||||
let out = Command::new(BIN)
|
||||
.arg("graph")
|
||||
.arg("does-not-exist.json")
|
||||
.current_dir(&cwd)
|
||||
.output()
|
||||
.expect("spawn aura graph <bad-arg>");
|
||||
// Headline pin: a named-but-unreadable blueprint arg exits 2 (usage fault),
|
||||
// mirroring `dispatch_run`'s bad-blueprint branch — not 0.
|
||||
assert_eq!(
|
||||
out.status.code(),
|
||||
Some(2),
|
||||
"`aura graph <nonexistent.json>` must be a usage fault (exit 2), not a silent sample fallback; got {:?}\nstderr: {}",
|
||||
out.status,
|
||||
String::from_utf8_lossy(&out.stderr),
|
||||
);
|
||||
// ...and it must NOT emit the embedded r_sma sample: the sample's inlined
|
||||
// model + its Bias node must be absent from stdout.
|
||||
let stdout = String::from_utf8(out.stdout).expect("utf-8 stdout");
|
||||
assert!(
|
||||
!stdout.contains("\"type\":\"Bias\""),
|
||||
"a bad blueprint arg silently rendered the embedded r_sma sample (its Bias node is present) instead of refusing"
|
||||
);
|
||||
|
||||
// Guard the legitimate default: bare `aura graph` (no positional) still
|
||||
// renders the embedded sample and exits 0.
|
||||
let default = Command::new(BIN)
|
||||
.arg("graph")
|
||||
.current_dir(&cwd)
|
||||
.output()
|
||||
.expect("spawn aura graph");
|
||||
assert_eq!(
|
||||
default.status.code(),
|
||||
Some(0),
|
||||
"bare `aura graph` must still render the sample (exit 0); got {:?}",
|
||||
default.status,
|
||||
);
|
||||
let default_out = String::from_utf8(default.stdout).expect("utf-8 stdout");
|
||||
assert!(
|
||||
default_out.contains("\"type\":\"Bias\""),
|
||||
"bare `aura graph` must render the embedded r_sma sample (its Bias node), the no-positional default"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sweep_with_trailing_token_is_strict_and_exits_two() {
|
||||
// strict-arg reading (#16): an unexpected trailing token is a usage error.
|
||||
|
||||
Reference in New Issue
Block a user