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 test_issue_106_simple_mod_declaration() {
let temp = TempDir::new().unwrap();
create_temp_file(
&temp,
"scanner.ruchy",
r#"
pub fun scan() {
println!("Scanning...")
}
"#,
);
let main_file = create_temp_file(
&temp,
"main.ruchy",
r"
mod scanner;
fun main() {
scanner::scan()
}
main()
",
);
ruchy_cmd()
.arg(main_file)
.assert()
.success()
.stdout(predicate::str::contains("Scanning..."));
}
#[test]
fn test_issue_106_multiple_mod_declarations() {
let temp = TempDir::new().unwrap();
create_temp_file(
&temp,
"utils.ruchy",
r#"
pub fun helper() {
"Helper function"
}
"#,
);
create_temp_file(
&temp,
"logger.ruchy",
r#"
pub fun log(msg) {
println!("LOG: {}", msg)
}
"#,
);
let main_file = create_temp_file(
&temp,
"main.ruchy",
r"
mod utils;
mod logger;
fun main() {
let msg = utils::helper()
logger::log(msg)
}
main()
",
);
ruchy_cmd()
.arg(main_file)
.assert()
.success()
.stdout(predicate::str::contains("LOG: Helper function"));
}
#[test]
fn test_issue_106_nested_module_calls() {
let temp = TempDir::new().unwrap();
create_temp_file(
&temp,
"math.ruchy",
r"
pub fun add(x, y) {
x + y
}
pub fun multiply(x, y) {
x * y
}
",
);
let main_file = create_temp_file(
&temp,
"main.ruchy",
r#"
mod math;
fun main() {
let a = math::add(5, 3)
let b = math::multiply(a, 2)
println!("Result: {}", b)
}
main()
"#,
);
ruchy_cmd()
.arg(main_file)
.assert()
.success()
.stdout(predicate::str::contains("Result: 16"));
}
#[test]
fn test_issue_106_compile_with_mod_declaration() {
let temp = TempDir::new().unwrap();
create_temp_file(
&temp,
"calculator.ruchy",
r"
pub fun compute(x, y) {
x + y
}
",
);
let main_file = create_temp_file(
&temp,
"main.ruchy",
r#"
mod calculator;
fun main() {
let result = calculator::compute(10, 20)
println!("Result: {}", result)
}
main()
"#,
);
let output = temp.path().join("compiled_test");
ruchy_cmd()
.arg("compile")
.arg(&main_file)
.arg("--output")
.arg(&output)
.assert()
.success()
.stdout(predicate::str::contains("Successfully compiled"));
assert!(output.exists(), "Binary should be created");
}
#[test]
fn test_issue_106_compiled_binary_executes() {
let temp = TempDir::new().unwrap();
create_temp_file(
&temp,
"processor.ruchy",
r"
pub fun process(value) {
value * 2
}
",
);
let main_file = create_temp_file(
&temp,
"main.ruchy",
r#"
mod processor;
fun main() {
let result = processor::process(42)
println!("Processed: {}", result)
}
main()
"#,
);
let output = temp.path().join("binary_test");
ruchy_cmd()
.arg("compile")
.arg(&main_file)
.arg("--output")
.arg(&output)
.assert()
.success();
Command::new(&output)
.assert()
.success()
.stdout(predicate::str::contains("Processed: 84"));
}
#[test]
fn test_issue_106_missing_module_file() {
let temp = TempDir::new().unwrap();
let main_file = create_temp_file(
&temp,
"main.ruchy",
r"
mod nonexistent;
fun main() {
nonexistent::function()
}
",
);
ruchy_cmd().arg(main_file).assert().failure().stderr(
predicate::str::contains("Failed to find module")
.or(predicate::str::contains("Module 'nonexistent' not found"))
.or(predicate::str::contains(
"Failed to resolve module declaration",
)),
);
}
#[test]
fn test_issue_106_invalid_module_syntax() {
let temp = TempDir::new().unwrap();
create_temp_file(
&temp,
"broken.ruchy",
r"
pub fun missing_body()
",
);
let main_file = create_temp_file(
&temp,
"main.ruchy",
r"
mod broken;
fun main() {
broken::missing_body()
}
",
);
ruchy_cmd().arg(main_file).assert().failure().stderr(
predicate::str::contains("Syntax error")
.or(predicate::str::contains("Expected"))
.or(predicate::str::contains("Failed to parse module"))
.or(predicate::str::contains(
"Failed to resolve module declaration",
)),
);
}
#[test]
fn test_issue_106_inline_modules_still_work() {
let temp = TempDir::new().unwrap();
let main_file = create_temp_file(
&temp,
"main.ruchy",
r#"
mod utils {
pub fun greet() {
println!("Hello from inline module")
}
}
fun main() {
utils::greet()
}
main()
"#,
);
ruchy_cmd()
.arg(main_file)
.assert()
.success()
.stdout(predicate::str::contains("Hello from inline module"));
}
#[test]
fn test_issue_106_mixed_inline_and_declaration() {
let temp = TempDir::new().unwrap();
create_temp_file(
&temp,
"external.ruchy",
r#"
pub fun external_func() {
"From external"
}
"#,
);
let main_file = create_temp_file(
&temp,
"main.ruchy",
r#"
mod external;
mod inline {
pub fun inline_func() {
"From inline"
}
}
fun main() {
println!("{}", external::external_func())
println!("{}", inline::inline_func())
}
main()
"#,
);
ruchy_cmd()
.arg(main_file)
.assert()
.success()
.stdout(predicate::str::contains("From external"))
.stdout(predicate::str::contains("From inline"));
}