use assert_cmd::Command;
const A: &str = "99999999";
const B: &str = "99999998";
const C: &str = "99999997";
fn run(args: &[&str]) -> (String, String) {
let output = Command::cargo_bin("proc")
.unwrap()
.env("NO_COLOR", "1")
.args(args)
.output()
.unwrap();
(
String::from_utf8(output.stdout).unwrap(),
String::from_utf8(output.stderr).unwrap(),
)
}
fn notes(stderr: &str) -> Vec<&str> {
stderr
.lines()
.filter(|line| line.starts_with("note:"))
.collect()
}
fn notice_for(command: &str, example: &str) -> String {
format!(
"note: comma-separated targets are deprecated and will be removed in a future \
major release; pass them as separate arguments: proc {command} {example}"
)
}
#[test]
fn a_comma_list_prints_the_notice_with_the_users_own_targets() {
let list = format!("{A},{B}");
let (stdout, stderr) = run(&["kill", &list, "--dry-run"]);
assert_eq!(
notes(&stderr),
vec![notice_for("kill", &format!("{A} {B}"))]
);
assert!(!stdout.contains("deprecated"), "stdout: {stdout}");
assert!(
!stderr.contains('\x1b'),
"no colour off a terminal: {stderr:?}"
);
}
#[test]
fn the_example_keeps_the_other_targets_and_the_real_command_name() {
let list = format!("{B},{C}");
let (_, stderr) = run(&["k", A, &list, "--dry-run"]);
assert_eq!(
notes(&stderr),
vec![notice_for("kill", &format!("{A} {B} {C}"))]
);
}
#[test]
fn it_prints_once_however_many_values_have_commas() {
let first = format!("{A},{B}");
let second = format!("{C},{A},{B}");
let (_, stderr) = run(&["kill", &first, &second, "--dry-run"]);
assert_eq!(notes(&stderr).len(), 1, "{stderr}");
assert_eq!(stderr.matches("deprecated").count(), 1, "{stderr}");
}
#[test]
fn separate_arguments_print_no_notice() {
let (_, stderr) = run(&["kill", A, B, "--dry-run"]);
assert!(!stderr.contains("deprecated"), "{stderr}");
assert!(notes(&stderr).is_empty(), "{stderr}");
}
#[test]
fn json_output_is_identical_with_commas_on_stdout_and_stderr() {
let with_commas = run(&["list", "nosuch1,nosuch2", "--json"]);
let separate = run(&["list", "nosuch1", "nosuch2", "--json"]);
assert_eq!(with_commas, separate);
assert!(with_commas.1.is_empty(), "stderr: {}", with_commas.1);
assert_eq!(run(&["list", "nosuch1,nosuch2", "-j"]), separate);
let list = format!("{A},{B}");
let (stdout, stderr) = run(&["kill", &list, "--dry-run", "--json"]);
assert!(stderr.is_empty(), "stderr: {stderr}");
assert!(
stdout.contains(&format!("No process found matching '{A},{B}'")),
"{stdout}"
);
}
#[test]
fn a_trailing_or_empty_piece_is_dropped_as_before_and_still_noticed() {
let (_, stderr) = run(&["kill", &format!("{A},"), "--dry-run"]);
assert_eq!(notes(&stderr), vec![notice_for("kill", A)]);
let (_, stderr) = run(&["list", ",", "--json"]);
assert!(stderr.is_empty(), "{stderr}");
}
#[test]
fn a_name_that_needs_quoting_is_quoted_in_the_example() {
let (_, stderr) = run(&["kill", "my app,it's", "--dry-run"]);
assert_eq!(
notes(&stderr),
vec![notice_for("kill", r"'my app' 'it'\''s'")]
);
}
#[test]
fn commas_in_flag_values_and_single_value_commands_do_not_count() {
for args in [
vec!["kill", A, "--by", "x,y", "--dry-run"],
vec!["kill", A, "--in=/no/such,dir", "--dry-run"],
vec!["list", "--by", "x,y"],
vec!["by", "x,y"],
vec!["in", "/no/such,dir"],
vec!["for", "/no/such,file"],
vec!["tree", "x,y"],
vec!["ports", "--by", "x,y"],
] {
let (_, stderr) = run(&args);
assert!(!stderr.contains("deprecated"), "{args:?}: {stderr}");
}
}
#[test]
fn every_command_that_splits_targets_gives_the_notice() {
for command in [
"on", "info", "list", "kill", "stop", "unstick", "freeze", "thaw", "why", "free", "wait",
] {
let (first, second) = if command == "free" {
(":65530", ":65531")
} else {
(A, B)
};
let list = format!("{first},{second}");
let mut args = vec![command, &list];
match command {
"kill" | "stop" | "unstick" | "freeze" | "thaw" | "free" => args.push("--dry-run"),
"wait" => args.extend(["--timeout", "1"]),
_ => {}
}
let (_, stderr) = run(&args);
assert_eq!(
notes(&stderr),
vec![notice_for(command, &format!("{first} {second}"))],
"{command}"
);
}
}