#![allow(clippy::ignore_without_reason)] #![allow(missing_docs)]
use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use std::path::PathBuf;
use tempfile::TempDir;
fn ruchy_cmd() -> Command {
assert_cmd::cargo::cargo_bin_cmd!("ruchy")
}
fn example_path(relative_path: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("examples")
.join(relative_path)
}
fn temp_dir() -> TempDir {
TempDir::new().expect("Failed to create temp directory")
}
fn write_ruchy_file(dir: &TempDir, name: &str, content: &str) -> PathBuf {
let path = dir.path().join(name);
fs::write(&path, content).expect("Failed to write file");
path
}
#[test]
fn tool_01_check_smoke_test_valid_syntax() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "valid.ruchy", "let x = 42");
ruchy_cmd().arg("check").arg(&file).assert().success();
}
#[test]
fn tool_01_check_rejects_invalid_syntax() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "invalid.ruchy", "let x = ");
ruchy_cmd().arg("check").arg(&file).assert().failure();
}
#[test]
fn tool_01_check_validates_example_programs() {
let examples = vec!["debug_ast.rs", "parser_demo.rs", "transpiler_demo.rs"];
for example in examples {
let path = example_path(example);
if path.exists() {
assert!(path.exists(), "Example file should exist: {path:?}");
}
}
}
#[test]
fn tool_02_transpile_smoke_test() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "simple.ruchy", "let x = 42\nprintln(x)");
let output = ruchy_cmd()
.arg("transpile")
.arg(&file)
.output()
.expect("Failed to transpile");
assert!(output.status.success());
let rust_code = String::from_utf8_lossy(&output.stdout);
assert!(rust_code.contains("fn main"));
assert!(rust_code.contains("42"));
}
#[test]
fn tool_02_transpile_generates_valid_rust() {
let temp = temp_dir();
let file = write_ruchy_file(
&temp,
"functions.ruchy",
"fun add(a, b) { a + b }\nlet result = add(2, 3)",
);
let output = ruchy_cmd()
.arg("transpile")
.arg(&file)
.output()
.expect("Failed to transpile");
assert!(output.status.success());
let rust_code = String::from_utf8_lossy(&output.stdout);
assert!(rust_code.contains("fn add"));
}
#[test]
fn tool_02_transpile_example_validation() {
let result = std::process::Command::new("cargo")
.args(["run", "--example", "transpiler_demo"])
.output();
if let Ok(output) = result {
assert!(
output.status.success() || output.status.code() == Some(0),
"transpiler_demo should execute"
);
}
}
#[test]
fn tool_03_run_smoke_test() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "hello.ruchy", "println(\"Hello, World!\")");
ruchy_cmd()
.arg("run")
.arg(&file)
.assert()
.success()
.stdout(predicate::str::contains("Hello, World!"));
}
#[test]
fn tool_03_run_executes_arithmetic() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "math.ruchy", "let x = 2 + 2\nprintln(x)");
ruchy_cmd()
.arg("run")
.arg(&file)
.assert()
.success()
.stdout(predicate::str::contains("4"));
}
#[test]
fn tool_03_run_example_validation() {
let result = std::process::Command::new("cargo")
.args(["run", "--example", "repl_basic_arithmetic"])
.output();
if let Ok(output) = result {
assert!(
output.status.success() || output.status.code() == Some(0),
"repl_basic_arithmetic should execute"
);
}
}
#[test]
fn tool_04_eval_smoke_test() {
ruchy_cmd()
.arg("-e")
.arg("2 + 2")
.assert()
.success()
.stdout(predicate::str::contains("4"));
}
#[test]
fn tool_04_eval_executes_expressions() {
ruchy_cmd()
.arg("-e")
.arg("println(\"test\")")
.assert()
.success()
.stdout(predicate::str::contains("test"));
}
#[test]
fn tool_04_eval_handles_errors() {
ruchy_cmd()
.arg("-e")
.arg("undefined_variable")
.assert()
.failure();
}
#[test]
fn tool_05_test_smoke_test_passing() {
let temp = temp_dir();
let file = write_ruchy_file(
&temp,
"test_pass.ruchy",
r#"
@test("simple passing test")
fun test_pass() {
assert_eq(2, 2, "Two equals two")
}
"#,
);
ruchy_cmd()
.arg("test")
.arg(&file)
.assert()
.success()
.stdout(predicate::str::contains("1").and(predicate::str::contains("Passed")));
}
#[test]
fn tool_05_test_smoke_test_failing() {
let temp = temp_dir();
let file = write_ruchy_file(
&temp,
"test_fail.ruchy",
r#"
@test("simple failing test")
fun test_fail() {
assert_eq(2, 3, "Two does not equal three")
}
"#,
);
ruchy_cmd()
.arg("test")
.arg(&file)
.assert()
.failure()
.stdout(predicate::str::contains("FAILED").or(predicate::str::contains("failed")));
}
#[test]
#[ignore = "KNOWN LIMITATION: Test runner only detects first @test function (parser issue)"]
fn tool_05_test_runs_multiple_tests() {
let temp = temp_dir();
let file = write_ruchy_file(
&temp,
"test_multi.ruchy",
r#"
@test("first test")
fun test_one() {
assert_eq(1, 1, "one")
}
@test("second test")
fun test_two() {
assert_eq(2, 2, "two")
}
"#,
);
ruchy_cmd()
.arg("test")
.arg(&file)
.assert()
.success()
.stdout(predicate::str::contains("2").and(predicate::str::contains("Passed")));
}
#[test]
fn tool_06_lint_smoke_test_clean_code() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "clean.ruchy", "let x = 42\nprintln(x)");
ruchy_cmd().arg("lint").arg(&file).assert().success();
}
#[test]
fn tool_06_lint_detects_unused_variables() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "unused.ruchy", "let unused_var = 42");
let output = ruchy_cmd()
.arg("lint")
.arg(&file)
.output()
.expect("Failed to lint");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
output.status.success() || stdout.contains("unused"),
"Linter should handle unused variables"
);
}
#[test]
fn tool_07_compile_smoke_test() {
let temp = temp_dir();
let source = write_ruchy_file(
&temp,
"hello.ruchy",
"println(\"Hello from compiled binary\")",
);
let output_binary = temp.path().join("hello");
ruchy_cmd()
.arg("compile")
.arg(&source)
.arg("-o")
.arg(&output_binary)
.assert()
.success();
assert!(output_binary.exists(), "Compiled binary should exist");
}
#[test]
fn tool_07_compile_creates_executable() {
let temp = temp_dir();
let source = write_ruchy_file(&temp, "app.ruchy", "let x = 42\nprintln(x)");
let output_binary = temp.path().join("app");
ruchy_cmd()
.arg("compile")
.arg(&source)
.arg("-o")
.arg(&output_binary)
.assert()
.success();
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let metadata = fs::metadata(&output_binary).expect("Binary should exist");
let permissions = metadata.permissions();
assert!(
permissions.mode() & 0o111 != 0,
"Binary should be executable"
);
}
}
#[test]
fn tool_08_ast_smoke_test() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "simple.ruchy", "let x = 42");
let output = ruchy_cmd()
.arg("ast")
.arg(&file)
.output()
.expect("Failed to generate AST");
assert!(output.status.success());
let ast_output = String::from_utf8_lossy(&output.stdout);
assert!(ast_output.contains("Expr") || ast_output.contains("Let"));
}
#[test]
fn tool_08_ast_example_validation() {
let result = std::process::Command::new("cargo")
.args(["run", "--example", "debug_ast"])
.output();
if let Ok(output) = result {
assert!(
output.status.success() || output.status.code() == Some(0),
"debug_ast example should execute"
);
}
}
#[test]
fn tool_09_wasm_smoke_test() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "wasm.ruchy", "let x = 42");
let result = ruchy_cmd().arg("wasm").arg(&file).output();
assert!(result.is_ok(), "WASM tool should not crash");
}
#[test]
fn tool_09_wasm_example_validation() {
let result = std::process::Command::new("cargo")
.args(["run", "--example", "wasm_minimal"])
.output();
if let Ok(output) = result {
assert!(
output.status.success() || output.status.code() == Some(0),
"wasm_minimal example should execute"
);
}
}
#[test]
#[ignore = "Notebook requires server setup"]
fn tool_10_notebook_smoke_test() {
}
#[test]
#[ignore = "Notebook acceptance tests require server setup and are long-running"]
fn tool_10_notebook_example_validation() {
let result = std::process::Command::new("cargo")
.args(["run", "--example", "notebook_acceptance_tests"])
.output();
if let Ok(output) = result {
assert!(
output.status.success() || output.status.code().is_some(),
"notebook_acceptance_tests should at least start"
);
}
}
#[test]
fn tool_11_coverage_smoke_test() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "cov.ruchy", "let x = 42\nif x > 0 { println(x) }");
let result = ruchy_cmd().arg("coverage").arg(&file).output();
assert!(result.is_ok(), "Coverage tool should not crash");
}
#[test]
fn tool_12_runtime_analysis_smoke_test() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "runtime.ruchy", "let x = 42");
let result = ruchy_cmd().arg("runtime").arg(&file).output();
assert!(result.is_ok(), "Runtime tool should not crash");
}
#[test]
fn tool_13_provability_smoke_test() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "prove.ruchy", "let x = 42");
let result = ruchy_cmd().arg("provability").arg(&file).output();
assert!(result.is_ok(), "Provability tool should not crash");
}
#[test]
fn tool_14_property_tests_smoke_test() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "prop.ruchy", "fun add(a, b) { a + b }");
let result = ruchy_cmd().arg("property-tests").arg(&file).output();
assert!(result.is_ok(), "Property-tests tool should not crash");
}
#[test]
fn tool_15_mutations_smoke_test() {
let temp = temp_dir();
let file = write_ruchy_file(&temp, "mut.ruchy", "let x = 42");
let result = ruchy_cmd().arg("mutations").arg(&file).output();
assert!(result.is_ok(), "Mutations tool should not crash");
}
#[test]
fn validate_all_examples_compile() {
let examples_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
if !examples_dir.exists() {
return; }
let example_files: Vec<_> = fs::read_dir(examples_dir)
.expect("Failed to read examples directory")
.filter_map(|entry| {
let entry = entry.ok()?;
let path = entry.path();
if path.extension()? == "rs" {
Some(path.file_stem()?.to_string_lossy().to_string())
} else {
None
}
})
.collect();
println!("Found {} example files", example_files.len());
assert!(
example_files.len() >= 5,
"Should have at least 5 example files"
);
}
#[test]
fn integration_all_tools_on_single_program() {
let temp = temp_dir();
let file = write_ruchy_file(
&temp,
"comprehensive.ruchy",
r#"
// Comprehensive test program
fun factorial(n) {
if n <= 1 {
1
} else {
n * factorial(n - 1)
}
}
let result = factorial(5)
println(result)
@test("factorial works")
fun test_factorial() {
assert_eq(factorial(5), 120, "5! = 120")
}
"#,
);
ruchy_cmd().arg("check").arg(&file).assert().success();
ruchy_cmd().arg("transpile").arg(&file).assert().success();
ruchy_cmd()
.arg("run")
.arg(&file)
.assert()
.success()
.stdout(predicate::str::contains("120"));
ruchy_cmd().arg("test").arg(&file).assert().success();
ruchy_cmd().arg("lint").arg(&file).assert().success();
ruchy_cmd().arg("ast").arg(&file).assert().success();
}