use std::fs;
use std::path::Path;
use std::process::Command;
#[test]
fn test_transpile_minimal_c_program() {
let example_path = "../../examples/simple/minimal.c";
assert!(Path::new(example_path).exists(), "Example file {} should exist", example_path);
let c_code = fs::read_to_string(example_path).expect("Failed to read example file");
assert!(c_code.contains("int main()"), "Should contain main function");
let result = decy_core::transpile(&c_code);
assert!(result.is_ok(), "Transpilation should succeed, got error: {:?}", result.err());
let rust_code = result.unwrap();
assert!(rust_code.contains("fn main"), "Should contain main function, got: {}", rust_code);
let temp_dir = std::env::temp_dir();
let temp_file = temp_dir.join("test_minimal.rs");
fs::write(&temp_file, &rust_code).expect("Failed to write temp file");
let compile_output = Command::new("rustc")
.arg(&temp_file)
.arg("--crate-type")
.arg("bin")
.arg("-o")
.arg(temp_dir.join("test_minimal"))
.output()
.expect("Failed to run rustc");
let _ = fs::remove_file(&temp_file);
let _ = fs::remove_file(temp_dir.join("test_minimal"));
assert!(
compile_output.status.success(),
"Generated Rust code should compile successfully. Compilation errors:\n{}",
String::from_utf8_lossy(&compile_output.stderr)
);
}
#[test]
fn test_transpile_arithmetic_functions() {
let example_path = "../../examples/simple/arithmetic.c";
assert!(Path::new(example_path).exists(), "Example file {} should exist", example_path);
let c_code = fs::read_to_string(example_path).expect("Failed to read example file");
assert!(c_code.contains("int add"), "Should contain add function");
assert!(c_code.contains("int multiply"), "Should contain multiply function");
let result = decy_core::transpile(&c_code);
assert!(result.is_ok(), "Transpilation should succeed, got error: {:?}", result.err());
let rust_code = result.unwrap();
assert!(rust_code.contains("fn add"), "Should contain add function, got: {}", rust_code);
assert!(
rust_code.contains("fn multiply"),
"Should contain multiply function, got: {}",
rust_code
);
assert!(rust_code.contains("i32"), "Should use i32 type, got: {}", rust_code);
let temp_dir = std::env::temp_dir();
let temp_file = temp_dir.join("test_arithmetic.rs");
fs::write(&temp_file, &rust_code).expect("Failed to write temp file");
let compile_output = Command::new("rustc")
.arg(&temp_file)
.arg("--crate-type")
.arg("lib")
.arg("-o")
.arg(temp_dir.join("libtest_arithmetic.rlib"))
.output()
.expect("Failed to run rustc");
let _ = fs::remove_file(&temp_file);
let _ = fs::remove_file(temp_dir.join("libtest_arithmetic.rlib"));
assert!(
compile_output.status.success(),
"Generated Rust code should compile as library. Compilation errors:\n{}",
String::from_utf8_lossy(&compile_output.stderr)
);
}
#[test]
fn test_cli_help() {
let output = Command::new("cargo")
.args(["run", "-p", "decy", "--", "--help"])
.output()
.expect("Failed to run CLI");
assert!(output.status.success(), "CLI should run successfully");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("decy") || stdout.contains("Usage"),
"Should show help text, got: {}",
stdout
);
}
#[test]
fn test_cli_transpile_file() {
let example_path = "../../examples/simple/minimal.c";
let output = Command::new("cargo")
.args(["run", "-p", "decy", "--", "transpile", example_path])
.output()
.expect("Failed to run CLI");
assert!(
output.status.success(),
"CLI should transpile successfully, stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("fn main"), "Should contain Rust main function, got: {}", stdout);
}
#[test]
fn test_transpile_control_flow() {
let example_path = "../../examples/moderate/control_flow.c";
assert!(Path::new(example_path).exists(), "Example file {} should exist", example_path);
let c_code = fs::read_to_string(example_path).expect("Failed to read example file");
assert!(c_code.contains("if"), "Should contain if statement");
assert!(c_code.contains("for"), "Should contain for loop");
let result = decy_core::transpile(&c_code);
assert!(result.is_ok(), "Should transpile control flow, got error: {:?}", result.err());
let rust_code = result.unwrap();
assert!(rust_code.contains("fn max"), "Should contain max function, got: {}", rust_code);
assert!(
rust_code.contains("fn factorial"),
"Should contain factorial function, got: {}",
rust_code
);
assert!(rust_code.contains("if"), "Should contain if statement, got: {}", rust_code);
assert!(
rust_code.contains("while"),
"Should contain while loop (for converted to while), got: {}",
rust_code
);
let temp_dir = std::env::temp_dir();
let temp_file = temp_dir.join("test_control_flow.rs");
fs::write(&temp_file, &rust_code).expect("Failed to write temp file");
let compile_output = Command::new("rustc")
.arg(&temp_file)
.arg("--crate-type")
.arg("lib")
.arg("-o")
.arg(temp_dir.join("libtest_control_flow.rlib"))
.output()
.expect("Failed to run rustc");
let _ = fs::remove_file(&temp_file);
let _ = fs::remove_file(temp_dir.join("libtest_control_flow.rlib"));
assert!(
compile_output.status.success(),
"Generated Rust code with control flow should compile. Compilation errors:\n{}",
String::from_utf8_lossy(&compile_output.stderr)
);
}