use std::fs;
use std::process::Command;
fn write_marker_step(marker: &str) -> String {
if cfg!(windows) {
format!(r#"type = "shell"
script = "cmd /C echo ok > {marker}""#)
} else {
format!(r#"type = "shell"
script = "echo ok > {marker}""#)
}
}
#[test]
fn input_confirm_match_passes_via_env() {
let bin = env!("CARGO_BIN_EXE_insmaller");
let dir = tempfile::tempdir().unwrap();
let marker = dir.path().join("ran").display().to_string().replace('\\', "/");
let marker_step = write_marker_step(&marker);
fs::write(
dir.path().join("installer.toml"),
format!(
r#"[task.reset]
[[task.reset.steps]]
type = "input"
name = "CONFIRM"
required = true
confirm = "RESET"
[[task.reset.steps]]
{marker_step}
"#
),
)
.unwrap();
let out = Command::new(bin)
.args(["task", "reset"])
.env("CONFIRM", "RESET")
.current_dir(dir.path())
.output()
.expect("run");
assert!(
out.status.success(),
"env-provided CONFIRM=RESET should pass\nstderr: {}",
String::from_utf8_lossy(&out.stderr),
);
assert!(
std::path::Path::new(&marker).exists(),
"follow-up step did not run after passing confirm",
);
}
#[test]
fn input_confirm_mismatch_aborts() {
let bin = env!("CARGO_BIN_EXE_insmaller");
let dir = tempfile::tempdir().unwrap();
let marker = dir.path().join("ran").display().to_string().replace('\\', "/");
let marker_step = write_marker_step(&marker);
fs::write(
dir.path().join("installer.toml"),
format!(
r#"[task.reset]
[[task.reset.steps]]
type = "input"
name = "CONFIRM"
required = true
confirm = "RESET"
[[task.reset.steps]]
{marker_step}
"#
),
)
.unwrap();
let out = Command::new(bin)
.args(["task", "reset"])
.env("CONFIRM", "NOPE")
.current_dir(dir.path())
.output()
.expect("run");
assert!(
!out.status.success(),
"confirm mismatch must abort\nstderr: {}",
String::from_utf8_lossy(&out.stderr),
);
assert!(
!std::path::Path::new(&marker).exists(),
"follow-up step must not run after confirm mismatch",
);
assert!(
String::from_utf8_lossy(&out.stderr).contains("confirm"),
"expected a 'confirm' error message; got: {}",
String::from_utf8_lossy(&out.stderr),
);
}
#[test]
fn input_required_unset_and_no_tty_fails_fast() {
let bin = env!("CARGO_BIN_EXE_insmaller");
let dir = tempfile::tempdir().unwrap();
fs::write(
dir.path().join("installer.toml"),
r#"[task.need]
[[task.need.steps]]
type = "input"
name = "MUST_BE_SET"
required = true
"#,
)
.unwrap();
let out = Command::new(bin)
.args(["task", "need"])
.env_remove("MUST_BE_SET")
.current_dir(dir.path())
.output()
.expect("run");
assert!(!out.status.success(), "required+unset must fail");
assert!(
String::from_utf8_lossy(&out.stderr).to_lowercase().contains("required"),
"expected 'required' in stderr; got: {}",
String::from_utf8_lossy(&out.stderr),
);
}
#[test]
fn interactive_tasks_false_keeps_env_only_contract() {
let bin = env!("CARGO_BIN_EXE_insmaller");
let dir = tempfile::tempdir().unwrap();
let marker = dir.path().join("ran").display().to_string().replace('\\', "/");
let marker_step = write_marker_step(&marker);
fs::write(
dir.path().join("installer.toml"),
format!(
r#"[settings]
interactive_tasks = false
[task.t]
[[task.t.steps]]
type = "prompt"
name = "TOK"
required = true
[[task.t.steps]]
{marker_step}
"#
),
)
.unwrap();
let out = Command::new(bin)
.args(["task", "t"])
.env("TOK", "ok")
.current_dir(dir.path())
.output()
.expect("run");
assert!(
out.status.success(),
"interactive_tasks=false + env-set value must pass\nstderr: {}",
String::from_utf8_lossy(&out.stderr),
);
assert!(std::path::Path::new(&marker).exists());
}