use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use tempfile::TempDir;
#[allow(deprecated)]
fn decy_cmd() -> Command {
Command::cargo_bin("decy").expect("Failed to find decy binary")
}
fn create_c_file(dir: &TempDir, name: &str, content: &str) -> std::path::PathBuf {
let path = dir.path().join(name);
fs::write(&path, content).expect("Failed to write C file");
path
}
#[test]
fn cli_transpile_project_valid_dir_exits_zero() {
let temp = TempDir::new().unwrap();
create_c_file(&temp, "main.c", "int main() { return 0; }");
let output_dir = temp.path().join("output");
decy_cmd()
.arg("transpile-project")
.arg(temp.path())
.arg("-o")
.arg(&output_dir)
.assert()
.success(); }
#[test]
fn cli_transpile_project_missing_dir_exits_nonzero() {
let temp = TempDir::new().unwrap();
let nonexistent = temp.path().join("does_not_exist");
let output_dir = temp.path().join("output");
decy_cmd()
.arg("transpile-project")
.arg(&nonexistent)
.arg("-o")
.arg(&output_dir)
.assert()
.failure() .stderr(
predicate::str::contains("not found")
.or(predicate::str::contains("No such"))
.or(predicate::str::contains("does not exist")),
);
}
#[test]
fn cli_transpile_project_no_output_dir_exits_nonzero() {
let temp = TempDir::new().unwrap();
create_c_file(&temp, "main.c", "int main() { return 0; }");
decy_cmd()
.arg("transpile-project")
.arg(temp.path())
.assert()
.failure();
}
#[test]
fn cli_transpile_project_creates_output_dir() {
let temp = TempDir::new().unwrap();
create_c_file(&temp, "test.c", "int add(int a, int b) { return a + b; }");
let output_dir = temp.path().join("rust_output");
decy_cmd()
.arg("transpile-project")
.arg(temp.path())
.arg("-o")
.arg(&output_dir)
.assert()
.success();
assert!(output_dir.exists(), "Output directory should be created");
}
#[test]
fn cli_transpile_project_preserves_directory_structure() {
let temp = TempDir::new().unwrap();
let src_dir = temp.path().join("src");
fs::create_dir(&src_dir).unwrap();
fs::write(src_dir.join("main.c"), "int main() { return 0; }").unwrap();
let lib_dir = temp.path().join("lib");
fs::create_dir(&lib_dir).unwrap();
fs::write(lib_dir.join("utils.c"), "int util() { return 1; }").unwrap();
let output_dir = temp.path().join("output");
decy_cmd()
.arg("transpile-project")
.arg(temp.path())
.arg("-o")
.arg(&output_dir)
.assert()
.success();
assert!(output_dir.join("src").exists(), "src/ should exist in output");
assert!(output_dir.join("lib").exists(), "lib/ should exist in output");
}
#[test]
fn cli_transpile_project_generates_rust_files() {
let temp = TempDir::new().unwrap();
create_c_file(&temp, "test.c", "int value() { return 42; }");
let output_dir = temp.path().join("output");
decy_cmd()
.arg("transpile-project")
.arg(temp.path())
.arg("-o")
.arg(&output_dir)
.assert()
.success();
let rust_file = output_dir.join("test.rs");
assert!(rust_file.exists(), "Should generate test.rs");
let rust_content = fs::read_to_string(&rust_file).unwrap();
assert!(rust_content.contains("fn value"), "Should contain Rust function");
}
#[test]
fn cli_transpile_project_with_multiple_files() {
let temp = TempDir::new().unwrap();
create_c_file(&temp, "file1.c", "int a() { return 1; }");
create_c_file(&temp, "file2.c", "int b() { return 2; }");
create_c_file(&temp, "file3.c", "int c() { return 3; }");
let output_dir = temp.path().join("output");
decy_cmd()
.arg("transpile-project")
.arg(temp.path())
.arg("-o")
.arg(&output_dir)
.assert()
.success();
assert!(output_dir.join("file1.rs").exists());
assert!(output_dir.join("file2.rs").exists());
assert!(output_dir.join("file3.rs").exists());
}
#[test]
fn cli_transpile_project_with_cache_flag() {
let temp = TempDir::new().unwrap();
create_c_file(&temp, "main.c", "int main() { return 0; }");
let output_dir = temp.path().join("output");
decy_cmd()
.arg("transpile-project")
.arg(temp.path())
.arg("-o")
.arg(&output_dir)
.assert()
.success();
}
#[test]
fn cli_transpile_project_without_cache_flag() {
let temp = TempDir::new().unwrap();
create_c_file(&temp, "main.c", "int main() { return 0; }");
let output_dir = temp.path().join("output");
decy_cmd()
.arg("transpile-project")
.arg(temp.path())
.arg("-o")
.arg(&output_dir)
.arg("--no-cache")
.assert()
.success();
}
#[test]
fn cli_transpile_project_empty_directory() {
let temp = TempDir::new().unwrap();
let output_dir = temp.path().join("output");
decy_cmd()
.arg("transpile-project")
.arg(temp.path())
.arg("-o")
.arg(&output_dir)
.assert()
.success() .stdout(predicate::str::contains("0 files").or(predicate::str::contains("No C files")));
}
#[test]
fn cli_transpile_project_ignores_non_c_files() {
let temp = TempDir::new().unwrap();
create_c_file(&temp, "test.c", "int test() { return 1; }");
create_c_file(&temp, "readme.txt", "This is not C code");
create_c_file(&temp, "data.json", "{}");
let output_dir = temp.path().join("output");
decy_cmd()
.arg("transpile-project")
.arg(temp.path())
.arg("-o")
.arg(&output_dir)
.assert()
.success();
assert!(output_dir.join("test.rs").exists());
assert!(!output_dir.join("readme.rs").exists());
assert!(!output_dir.join("data.rs").exists());
}
#[test]
fn cli_transpile_project_with_syntax_errors() {
let temp = TempDir::new().unwrap();
create_c_file(&temp, "bad.c", "int main( { }");
let output_dir = temp.path().join("output");
decy_cmd()
.arg("transpile-project")
.arg(temp.path())
.arg("-o")
.arg(&output_dir)
.assert()
.failure() .stderr(
predicate::str::contains("bad.c")
.and(predicate::str::contains("error").or(predicate::str::contains("failed"))),
);
}