Every patch verb outside the series work is real. check reads the working tree through checkpatch's stdin, which is the only way it can read one, since --git with no revision dies; format puts --fix-inplace's output back into the tree after setting the uncommitted change aside, and restores it if the fix does not apply; commit and create sit on git; create writes a mail-formatted patch, because git send-email refuses a bare diff with "No subject line"; submit splits get_maintainer.pl's roles into To and Cc, prints the command line it is about to run, and only sends when --dry-run is off; update re-rolls a patch by renaming it and does nothing at the revision it is already at. git.rs grows the plumbing those verbs stand on: diff_unstaged, format_patch, apply, commit, rev_parse. apply feeds the patch in on stdin, so a fixed patch stays in memory until it is known to apply. tests/ holds a fixture kernel tree, so the suite needs no kernel tree, no network, and no configured git send-email. The two tests that do want the host's own checkpatch and get_maintainer are ignored unless asked for, and one of them earned its place immediately: checkpatch's --file means "this argument is source code", so checking a patch with it reported a dirty patch as clean, 8004 lines and no errors. Patchfile mode is checkpatch's default and the path now stands alone. patch check also takes --rev, which is how a committed range gets checked. Checked with cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test, and cargo doc --no-deps.
83 lines
2.3 KiB
Rust
83 lines
2.3 KiB
Rust
//! The command surface parses, and a bad invocation is a usage error rather
|
|
//! than a panic.
|
|
|
|
mod common;
|
|
|
|
use common::Fixture;
|
|
|
|
#[test]
|
|
fn the_top_level_help_names_both_command_groups() {
|
|
let fixture = Fixture::bare();
|
|
let output = fixture.cli(&["--help"]);
|
|
|
|
assert!(output.status.success());
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
assert!(stdout.contains("kernel"), "{stdout}");
|
|
assert!(stdout.contains("patch"), "{stdout}");
|
|
}
|
|
|
|
#[test]
|
|
fn every_verb_has_help_of_its_own() {
|
|
let fixture = Fixture::bare();
|
|
|
|
for verb in [
|
|
&["kernel", "quest"][..],
|
|
&["kernel", "test"],
|
|
&["patch", "check"],
|
|
&["patch", "format"],
|
|
&["patch", "commit"],
|
|
&["patch", "create"],
|
|
&["patch", "submit"],
|
|
&["patch", "update"],
|
|
] {
|
|
let mut args = verb.to_vec();
|
|
args.push("--help");
|
|
|
|
let output = fixture.cli(&args);
|
|
assert!(
|
|
output.status.success(),
|
|
"{} --help failed: {}",
|
|
verb.join(" "),
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
assert!(
|
|
!String::from_utf8_lossy(&output.stdout).is_empty(),
|
|
"{} --help printed nothing",
|
|
verb.join(" ")
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn an_unknown_subcommand_exits_two() {
|
|
let fixture = Fixture::bare();
|
|
let output = fixture.cli(&["frobnicate"]);
|
|
|
|
assert_eq!(output.status.code(), Some(2));
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(stderr.contains("Usage"), "{stderr}");
|
|
}
|
|
|
|
#[test]
|
|
fn a_leaf_missing_its_argument_exits_two() {
|
|
let fixture = Fixture::bare();
|
|
let output = fixture.cli(&["patch", "commit"]);
|
|
|
|
assert_eq!(output.status.code(), Some(2));
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(stderr.contains("MESSAGE"), "{stderr}");
|
|
}
|
|
|
|
#[test]
|
|
fn a_verb_that_is_still_a_stub_panics_where_it_says_it_does() {
|
|
// `kernel quest` is P5 and `kernel test` is P6. Until they land, this is
|
|
// the proof that the dispatch is wired end to end: exit 101 with the
|
|
// panic's own location in it.
|
|
let fixture = Fixture::kernel_tree();
|
|
let output = fixture.cli(&["kernel", "quest"]);
|
|
|
|
assert_eq!(output.status.code(), Some(101));
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(stderr.contains("kernel/quest.rs"), "{stderr}");
|
|
}
|