mod cli_testing_tools;
use cli_testing_tools::*;
use predicates::prelude::*;
use std::fs;
use tempfile::TempDir;
#[test]
fn cli_transpile_valid_file_exits_zero() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "valid.c", VALID_C_CODE);
decy_cmd().arg("transpile").arg(&file).assert().success(); }
#[test]
fn cli_transpile_invalid_syntax_exits_nonzero() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "invalid.c", INVALID_C_CODE);
decy_cmd().arg("transpile").arg(&file).assert().failure(); }
#[test]
fn cli_transpile_missing_file_exits_nonzero() {
decy_cmd().arg("transpile").arg("nonexistent_file.c").assert().failure(); }
#[test]
fn cli_transpile_outputs_rust_to_stdout() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "hello.c", VALID_C_CODE);
decy_cmd()
.arg("transpile")
.arg(&file)
.assert()
.success()
.stdout(predicate::str::contains("fn main")) .stdout(predicate::str::is_empty().not()); }
#[test]
fn cli_transpile_rust_contains_function() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "function.c", C_WITH_FUNCTION);
decy_cmd()
.arg("transpile")
.arg(&file)
.assert()
.success()
.stdout(predicate::str::contains("fn add")) .stdout(predicate::str::contains("fn main"));
}
#[test]
fn cli_transpile_to_file_creates_output() {
let temp = TempDir::new().unwrap();
let input = create_temp_file(&temp, "input.c", VALID_C_CODE);
let output = temp.path().join("output.rs");
decy_cmd().arg("transpile").arg(&input).arg("-o").arg(&output).assert().success();
assert!(output.exists(), "Output file should exist");
let content = fs::read_to_string(&output).unwrap();
assert!(content.contains("fn main"), "Should contain Rust fn main, got: {}", content);
}
#[test]
fn cli_transpile_to_file_no_stdout() {
let temp = TempDir::new().unwrap();
let input = create_temp_file(&temp, "input.c", VALID_C_CODE);
let output = temp.path().join("output.rs");
decy_cmd()
.arg("transpile")
.arg(&input)
.arg("-o")
.arg(&output)
.assert()
.success()
.stdout(predicate::str::is_empty()); }
#[test]
fn cli_transpile_output_flag_long_form() {
let temp = TempDir::new().unwrap();
let input = create_temp_file(&temp, "input.c", VALID_C_CODE);
let output = temp.path().join("long_form.rs");
decy_cmd().arg("transpile").arg(&input).arg("--output").arg(&output).assert().success();
assert!(output.exists());
}
#[test]
fn cli_transpile_invalid_syntax_writes_stderr() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "bad.c", INVALID_C_CODE);
decy_cmd()
.arg("transpile")
.arg(&file)
.assert()
.failure()
.stderr(predicate::str::is_empty().not()); }
#[test]
fn cli_transpile_missing_file_writes_stderr() {
decy_cmd().arg("transpile").arg("missing.c").assert().failure().stderr(
predicate::str::contains("not found")
.or(predicate::str::contains("No such file"))
.or(predicate::str::contains("does not exist"))
.or(predicate::str::contains("Failed to read")),
);
}
#[test]
fn cli_transpile_error_includes_filename() {
decy_cmd()
.arg("transpile")
.arg("missing_specific_file.c")
.assert()
.failure()
.stderr(predicate::str::contains("missing_specific_file.c"));
}
#[test]
fn cli_transpile_empty_file_handles_gracefully() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "empty.c", "");
let result = decy_cmd().arg("transpile").arg(&file).assert();
result.code(predicate::function(|code: &i32| *code == 0 || *code == 1));
}
#[test]
fn cli_transpile_comment_only_succeeds() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "comments.c", "// Just a comment\n/* Block comment */\n");
decy_cmd().arg("transpile").arg(&file).assert().success();
}
#[test]
fn cli_transpile_whitespace_only_succeeds() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "whitespace.c", " \n\n \t \n");
decy_cmd().arg("transpile").arg(&file).assert().success();
}
#[test]
fn cli_transpile_function_with_parameters() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "func.c", C_WITH_FUNCTION);
decy_cmd()
.arg("transpile")
.arg(&file)
.assert()
.success()
.stdout(predicate::str::contains("fn add"));
}
#[test]
fn cli_transpile_pointer_code() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "pointers.c", C_WITH_POINTERS);
decy_cmd()
.arg("transpile")
.arg(&file)
.assert()
.success()
.stdout(predicate::str::contains("fn increment"));
}
#[test]
fn cli_transpile_malloc_code() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "malloc.c", C_WITH_MALLOC);
let result = decy_cmd().arg("transpile").arg(&file).assert();
result.code(predicate::function(|code: &i32| *code == 0 || *code == 1));
}
#[test]
fn cli_transpile_help_flag() {
decy_cmd()
.arg("transpile")
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("Transpile a C source file"));
}
#[test]
fn cli_transpile_requires_input_file() {
decy_cmd().arg("transpile").assert().failure().stderr(predicate::str::contains("required"));
}
#[test]
fn cli_transpile_relative_path() {
let temp = TempDir::new().unwrap();
let _file = create_temp_file(&temp, "relative.c", VALID_C_CODE);
std::env::set_current_dir(temp.path()).unwrap();
decy_cmd().arg("transpile").arg("relative.c").assert().success();
}
#[test]
fn cli_transpile_absolute_path() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "absolute.c", VALID_C_CODE);
decy_cmd().arg("transpile").arg(file.canonicalize().unwrap()).assert().success();
}
#[test]
fn cli_transpile_output_is_valid_rust_syntax() {
let temp = TempDir::new().unwrap();
let input = create_temp_file(&temp, "input.c", VALID_C_CODE);
let output = temp.path().join("output.rs");
decy_cmd().arg("transpile").arg(&input).arg("-o").arg(&output).assert().success();
let content = fs::read_to_string(&output).unwrap();
assert!(
content.contains("fn ") || content.is_empty(),
"Output should contain Rust functions or be empty"
);
}
#[test]
fn cli_transpile_generates_consistent_output() {
let temp = TempDir::new().unwrap();
let input = create_temp_file(&temp, "input.c", VALID_C_CODE);
let output1 =
decy_cmd().arg("transpile").arg(&input).assert().success().get_output().stdout.clone();
let output2 =
decy_cmd().arg("transpile").arg(&input).assert().success().get_output().stdout.clone();
assert_eq!(output1, output2, "Transpiler should produce consistent output");
}