use std::path::Path;
use std::process::Command;
fn bin() -> &'static str {
env!("CARGO_BIN_EXE_unity-solution-generator")
}
fn write(root: &Path, rel: &str, content: &str) {
let path = root.join(rel);
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(&path, content).unwrap();
}
fn fixture() -> tempfile::TempDir {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
write(root, "ProjectSettings/ProjectVersion.txt", "m_EditorVersion: 6000.2.7f2\n");
write(root, "Assets/A/Lib.asmdef", r#"{"name":"Lib"}"#);
write(root, "Assets/A/Code.cs", "class Code {}\n");
let lf = unity_solution_generator::Lockfile::empty("6000.2.7f2", "/test/unity");
let lf_dir = root.join("Library/UnitySolutionGenerator");
std::fs::create_dir_all(&lf_dir).unwrap();
unity_solution_generator::LockfileIO::write(&lf, lf_dir.join("csproj.lock").to_str().unwrap()).unwrap();
tmp
}
#[test]
fn help_exits_zero_and_lists_subcommands() {
let out = Command::new(bin()).arg("--help").output().expect("spawn");
assert!(out.status.success(), "--help should exit 0");
let stdout = String::from_utf8_lossy(&out.stdout);
assert!(stdout.contains("lock"), "help missing 'lock'");
assert!(stdout.contains("generate"), "help missing 'generate'");
}
#[test]
fn no_args_exits_zero_and_prints_usage() {
let out = Command::new(bin()).output().expect("spawn");
assert!(out.status.success(), "no-args should match --help (exit 0)");
}
#[test]
fn unknown_subcommand_exits_nonzero() {
let out = Command::new(bin()).arg("nope").output().expect("spawn");
assert!(!out.status.success(), "unknown subcommand should fail");
}
#[test]
fn generate_emits_sln_path_to_stdout() {
let tmp = fixture();
let root = tmp.path();
let out = Command::new(bin())
.args(["generate", root.to_str().unwrap(), "ios", "editor"])
.output()
.expect("spawn");
assert!(
out.status.success(),
"generate failed:\nstdout={}\nstderr={}",
String::from_utf8_lossy(&out.stdout),
String::from_utf8_lossy(&out.stderr)
);
let sln_line = String::from_utf8_lossy(&out.stdout)
.lines()
.next()
.expect("stdout empty")
.to_string();
assert!(
sln_line.ends_with(".sln"),
"expected .sln path on stdout, got {:?}",
sln_line
);
}
#[test]
fn generate_invalid_platform_exits_nonzero() {
let tmp = fixture();
let out = Command::new(bin())
.args(["generate", tmp.path().to_str().unwrap(), "windows", "editor"])
.output()
.expect("spawn");
assert!(!out.status.success(), "invalid platform should fail");
}
#[test]
fn generate_invalid_config_exits_nonzero() {
let tmp = fixture();
let out = Command::new(bin())
.args(["generate", tmp.path().to_str().unwrap(), "ios", "release"])
.output()
.expect("spawn");
assert!(!out.status.success(), "invalid config should fail");
}
#[test]
fn generate_auto_runs_lock_when_lockfile_missing() {
let tmp = tempfile::tempdir().unwrap();
let root = tmp.path();
write(root, "ProjectSettings/ProjectVersion.txt", "m_EditorVersion: 6000.2.7f2\n");
write(root, "Assets/A/Lib.asmdef", r#"{"name":"Lib"}"#);
write(root, "Assets/A/Code.cs", "class Code {}\n");
let out = Command::new(bin())
.args(["generate", root.to_str().unwrap(), "ios", "editor"])
.output()
.expect("spawn");
if !out.status.success() {
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(
stderr.contains("Unity") || stderr.contains("lockfile") || stderr.contains("error"),
"implicit lock failed without a diagnosable stderr message: {}",
stderr
);
}
}