#![allow(missing_docs)]
use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use tempfile::TempDir;
fn ruchy_cmd() -> Command {
assert_cmd::cargo::cargo_bin_cmd!("ruchy")
}
fn create_temp_file(dir: &TempDir, name: &str, content: &str) -> std::path::PathBuf {
let path = dir.path().join(name);
fs::write(&path, content).expect("Failed to write temp file");
path
}
#[test]
fn cli_compile_valid_program_exits_zero() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "hello.ruchy", "println(\"Hello, World!\")\n");
let output = temp.path().join("hello");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.assert()
.success(); }
#[test]
fn cli_compile_syntax_error_exits_nonzero() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "invalid.ruchy", "let x = \n");
let output = temp.path().join("invalid");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.assert()
.failure(); }
#[test]
fn cli_compile_missing_file_exits_nonzero() {
let temp = TempDir::new().unwrap();
let output = temp.path().join("output");
ruchy_cmd()
.arg("compile")
.arg("nonexistent_xyz.ruchy")
.arg("--output")
.arg(&output)
.assert()
.failure(); }
#[test]
fn cli_compile_success_writes_stdout() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "simple.ruchy", "let x = 42\n");
let output = temp.path().join("simple");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.assert()
.success()
.stdout(predicate::str::contains("Successfully compiled"));
}
#[test]
fn cli_compile_output_path_in_stdout() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "program.ruchy", "println(\"test\")\n");
let output = temp.path().join("my_program");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.assert()
.success()
.stdout(predicate::str::contains("my_program"));
}
#[test]
fn cli_compile_syntax_error_writes_stderr() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "bad_syntax.ruchy", "fun f( { }\n");
let output = temp.path().join("bad");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.assert()
.failure()
.stderr(predicate::str::is_empty().not()); }
#[test]
fn cli_compile_missing_file_writes_stderr() {
let temp = TempDir::new().unwrap();
let output = temp.path().join("output");
ruchy_cmd()
.arg("compile")
.arg("missing.ruchy")
.arg("--output")
.arg(&output)
.assert()
.failure()
.stderr(
predicate::str::contains("not found")
.or(predicate::str::contains("No such file"))
.or(predicate::str::contains("does not exist")),
);
}
#[test]
fn cli_compile_creates_output_binary() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "create_bin.ruchy", "println(\"binary test\")\n");
let output = temp.path().join("test_binary");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.assert()
.success();
assert!(output.exists(), "Binary should be created at output path");
}
#[test]
fn cli_compile_binary_is_executable() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "exec_test.ruchy", "println(\"executable\")\n");
let output = temp.path().join("exec_binary");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.assert()
.success();
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let metadata = fs::metadata(&output).expect("Binary should exist");
let permissions = metadata.permissions();
assert!(
permissions.mode() & 0o111 != 0,
"Binary should be executable"
);
}
}
#[test]
fn cli_compile_default_output_name() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "default.ruchy", "println(\"default name\")\n");
let current_dir = std::env::current_dir().unwrap();
std::env::set_current_dir(temp.path()).unwrap();
ruchy_cmd().arg("compile").arg(&file).assert().success();
let default_output = temp.path().join("a.out");
assert!(
default_output.exists(),
"Default output 'a.out' should be created"
);
std::env::set_current_dir(current_dir).unwrap();
}
#[test]
fn cli_compile_with_optimization_level() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "optimized.ruchy", "println(\"optimized\")\n");
let output = temp.path().join("optimized");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.arg("-O")
.arg("3") .assert()
.success();
assert!(output.exists(), "Optimized binary should be created");
}
#[test]
fn cli_compile_with_strip_flag() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "stripped.ruchy", "println(\"stripped\")\n");
let output = temp.path().join("stripped");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.arg("--strip") .assert()
.success();
assert!(output.exists(), "Stripped binary should be created");
}
#[test]
fn cli_compile_empty_file_fails() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "empty.ruchy", "");
let output = temp.path().join("empty");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.assert()
.failure(); }
#[test]
fn cli_compile_comment_only_fails() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(&temp, "comments.ruchy", "// Just a comment\n");
let output = temp.path().join("comments");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.assert()
.failure(); }
#[test]
fn cli_compile_complex_program() {
let temp = TempDir::new().unwrap();
let file = create_temp_file(
&temp,
"complex.ruchy",
r"
fun fibonacci(n) {
if n <= 1 {
n
} else {
fibonacci(n - 1) + fibonacci(n - 2)
}
}
println(fibonacci(10))
",
);
let output = temp.path().join("complex");
ruchy_cmd()
.arg("compile")
.arg(&file)
.arg("--output")
.arg(&output)
.assert()
.success();
assert!(
output.exists(),
"Complex program should compile successfully"
);
}