use std::fs;
use tempfile::tempdir;
use super::{CLEAN, RAGGED, run_in, status_of, stderr_of};
#[derive(Clone, Copy, PartialEq, Eq)]
enum Files {
Clean,
SomeDrift,
AllDrift,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum CliMode {
Print,
InPlace,
Check,
Diff,
}
impl CliMode {
fn args(self) -> &'static [&'static str] {
match self {
Self::Print => &[],
Self::InPlace => &["--in-place"],
Self::Check => &["--check"],
Self::Diff => &["--diff"],
}
}
fn reports(self) -> bool { matches!(self, Self::Check | Self::Diff) }
fn expected_status(self, files: Files, with_error: bool) -> i32 {
if with_error {
2
} else {
i32::from(files != Files::Clean && self.reports())
}
}
}
#[test]
fn exit_status_matrix() {
let shapes = [
("all_clean", Files::Clean),
("some_drift", Files::SomeDrift),
("all_drift", Files::AllDrift),
];
let modes = [
CliMode::Print,
CliMode::InPlace,
CliMode::Check,
CliMode::Diff,
];
for (shape_name, files) in shapes {
for mode in modes {
for with_error in [false, true] {
let dir = tempdir().expect("create temporary directory");
let mut names = Vec::new();
for index in 0..2 {
let ragged = match files {
Files::Clean => false,
Files::SomeDrift => index == 0,
Files::AllDrift => true,
};
let name = format!("file{index}.md");
fs::write(dir.path().join(&name), if ragged { RAGGED } else { CLEAN })
.expect("write fixture");
names.push(name);
}
if with_error {
names.push(String::from("missing.md"));
}
let mut args: Vec<&str> = mode.args().to_vec();
args.extend(names.iter().map(String::as_str));
let output = run_in(dir.path(), &args);
assert_eq!(
status_of(&output),
mode.expected_status(files, with_error),
"{shape_name} under {mode:?} (with_error: {with_error}) exited {}, stderr: {}",
status_of(&output),
stderr_of(&output)
);
}
}
}
}
#[test]
fn mode_flags_require_an_input_source() {
let dir = tempdir().expect("create temporary directory");
fs::write(dir.path().join("clean.md"), CLEAN).expect("write fixture");
fs::write(dir.path().join("also.md"), CLEAN).expect("write fixture");
for mode in [CliMode::InPlace, CliMode::Check, CliMode::Diff] {
let mut with_inputs: Vec<&str> = mode.args().to_vec();
with_inputs.extend(["clean.md", "also.md"]);
assert_eq!(
status_of(&run_in(dir.path(), &with_inputs)),
mode.expected_status(Files::Clean, false),
"{mode:?} over named files must be accepted"
);
let without_input = mode.args().to_vec();
let output = run_in(dir.path(), &without_input);
assert_eq!(
status_of(&output),
2,
"{mode:?} without an input source must be refused, stderr: {}",
stderr_of(&output)
);
}
let conflicting = ["--check", "--diff", "clean.md"];
let output = run_in(dir.path(), &conflicting);
assert_eq!(
status_of(&output),
2,
"two mode flags must conflict, stderr: {}",
stderr_of(&output)
);
assert_eq!(
status_of(&run_in(dir.path(), &["clean.md"])),
0,
"naming a file with no mode flag must still print it"
);
}