use super::Error;
use crate::probe::ProbeFailure;
#[test]
fn messages_are_actionable() {
let scope = Error::UnknownScope {
command: "cargo test".to_owned(),
scope: "rust".to_owned(),
};
assert!(scope.to_string().contains("unknown scope `rust`"));
let dup = Error::DuplicateCommand("sh".to_owned());
assert!(dup.to_string().contains("duplicate command name"));
let blank = Error::EmptyCommandName(2);
assert!(blank.to_string().contains("empty `name`"));
let no_match = Error::NoMatch {
command: "cargo build".to_owned(),
};
assert!(
no_match
.to_string()
.contains("no rule matches `cargo build`")
);
let no_inputs = Error::NoInputs {
rule: "cargo test".to_owned(),
};
assert!(no_inputs.to_string().contains("matched no input files"));
let no_manifest = Error::NoManifest {
start: std::path::PathBuf::from("/tmp/x"),
};
assert!(
no_manifest
.to_string()
.contains("no .mmz/config.yaml found")
);
let bad_output = Error::InvalidOutput {
command: "just cover".to_owned(),
path: "target/*.info".to_owned(),
reason: "outputs are literal paths, not patterns".to_owned(),
};
assert!(
bad_output
.to_string()
.contains("declares invalid output `target/*.info`")
);
let missing = Error::MissingOutput {
rule: "just cover".to_owned(),
path: "target/coverage/lcov.info".to_owned(),
};
let text = missing.to_string();
assert!(
text.contains("target/coverage/lcov.info"),
"the missing artifact is named: {text}"
);
assert!(
text.contains("no cache record was written"),
"and the consequence is spelled out: {text}"
);
}
#[test]
fn probe_messages_name_the_probe_and_the_consequence() {
let failed = ProbeFailure::Failed {
run: "just --dump | jq .recipes".to_owned(),
code: 5,
stderr: "jq: error: no such key".to_owned(),
}
.named("fmt-recipe");
let text = failed.to_string();
assert!(
text.contains("probe `fmt-recipe`"),
"names the probe: {text}"
);
assert!(text.contains("exit 5"), "names the exit code: {text}");
assert!(text.contains("jq: error"), "carries stderr: {text}");
assert!(
text.contains("wrote no cache record"),
"a failed probe never reaches the hasher, and says so: {text}"
);
let spawn = ProbeFailure::Spawn {
run: "rustc -vV".to_owned(),
source: std::io::Error::other("no such file"),
}
.named("toolchain");
let text = spawn.to_string();
assert!(
text.contains("probe `toolchain`"),
"names the probe: {text}"
);
assert!(
text.contains("wrote no cache record"),
"an unspawnable probe is the same hard stop: {text}"
);
let empty = ProbeFailure::Empty {
run: "jq -c .missing".to_owned(),
}
.named("selector");
let text = empty.to_string();
assert!(text.contains("probe `selector`"), "names the probe: {text}");
assert!(
text.contains("allow_empty"),
"points at the opt-in rather than leaving it a dead end: {text}"
);
}
#[test]
fn input_namespace_messages_are_actionable() {
let unknown = Error::UnknownInput {
command: "cargo test".to_owned(),
input: "ghost".to_owned(),
};
let text = unknown.to_string();
assert!(
text.contains("unknown input `ghost`"),
"names the entry: {text}"
);
assert!(
text.contains("`scopes:` or `probes:`"),
"names both places it could be declared: {text}"
);
let clash = Error::NameCollision {
name: "rust".to_owned(),
};
assert!(
clash.to_string().contains("one namespace"),
"the collision explains why one name cannot be both"
);
}
#[test]
fn import_refusals_name_the_directory() {
let bare = Error::ImportNotCheckout {
dir: std::path::PathBuf::from("../wt"),
};
let text = bare.to_string();
assert!(text.contains("../wt"), "names the directory: {text}");
assert!(text.contains("no .mmz/"), "says what is missing: {text}");
let own = Error::ImportSelf {
dir: std::path::PathBuf::from("."),
};
assert!(own.to_string().contains("this checkout"));
}