use std::path::PathBuf;
use std::process::Command;
fn runner_binary() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_runner"))
}
fn run_binary() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_run"))
}
fn fixture(name: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures")
.join(name)
}
fn just_available() -> bool {
Command::new("just")
.arg("--version")
.output()
.is_ok_and(|o| o.status.success())
}
#[test]
fn runner_list_is_always_builtin_even_with_a_list_task() {
if !just_available() {
eprintln!("skipping: `just` not found on PATH");
return;
}
let output = Command::new(runner_binary())
.args(["--dir", fixture("list-shadowed").to_str().unwrap(), "list"])
.output()
.expect("runner binary spawns");
assert!(output.status.success(), "`runner list` should exit 0");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
!stdout.contains("project-list-recipe-ran"),
"the project `list` recipe must NOT run for the explicit subcommand. stdout: {stdout}",
);
assert!(
stdout.contains("list") && stdout.contains("build"),
"expected the justfile recipes in the builtin list output. stdout: {stdout}",
);
}
#[test]
fn run_list_runs_a_same_named_task() {
if !just_available() {
eprintln!("skipping: `just` not found on PATH");
return;
}
let dir = fixture("list-shadowed");
let dir = dir.to_str().unwrap();
let invocations: [(&str, PathBuf, Vec<&str>); 2] = [
("run list", run_binary(), vec!["--dir", dir, "list"]),
(
"runner run list",
runner_binary(),
vec!["--dir", dir, "run", "list"],
),
];
for (label, binary, args) in invocations {
let output = Command::new(binary)
.args(&args)
.output()
.expect("binary spawns");
assert!(output.status.success(), "`{label}` should exit 0");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("project-list-recipe-ran"),
"`{label}` should run the project `list` recipe. stdout: {stdout}",
);
}
}
#[test]
fn run_list_falls_back_to_builtin_when_no_task() {
if !just_available() {
eprintln!("skipping: `just` not found on PATH");
return;
}
let dir = fixture("info-deprecated");
let dir = dir.to_str().unwrap();
for (label, binary, args) in [
("run list", run_binary(), vec!["--dir", dir, "list"]),
(
"runner run list",
runner_binary(),
vec!["--dir", dir, "run", "list"],
),
] {
let output = Command::new(binary)
.args(&args)
.output()
.expect("binary spawns");
assert!(
output.status.success(),
"`{label}` should fall back to the builtin list and exit 0. stderr: {}",
String::from_utf8_lossy(&output.stderr),
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("build") && stdout.contains("test"),
"`{label}` builtin-list fallback should render the justfile tasks. stdout: {stdout}",
);
}
}