windjammer 0.48.0

A simple language inspired by Go, Ruby, and Elixir that transpiles to Rust - 80% of Rust's power with 20% of the complexity
Documentation
#![cfg(any(
    not(any(
        feature = "parser_tests",
        feature = "analyzer_tests",
        feature = "codegen_tests",
        feature = "interpreter_tests",
        feature = "conformance_tests",
        feature = "integration_tests",
    )),
    feature = "codegen_tests",
))]

/// TDD Test: String literal to String auto-conversion in @test_cases
///
/// The Windjammer Way: "Compiler Does the Hard Work, Not the Developer"
///
/// Developers should NOT have to write:
///     ["node1".to_string(), "Hello".to_string()]
///
/// They should be able to write:
///     ["node1", "Hello"]
///
/// The compiler should automatically infer and convert string literals to String
/// when the parameter type expects String.
#[path = "common/test_utils.rs"]
mod test_utils;

use std::fs;
use std::process::Command;
use tempfile::TempDir;

#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_test_cases_with_string_literals_auto_converts_to_string() {
    let source = r#"
@test_cases([
    ["alice", "Alice", 25],
    ["bob", "Bob", 30]
])
fn test_user(id: string, name: string, age: i32) {
    // string methods should work (not &string)
    assert_eq(id.len() as i32, 5)
    assert_eq(name.len() as i32 > 0, true)
}
"#;

    let temp_dir = TempDir::new().unwrap();
    let input_path = temp_dir.path().join("test_cases_string_inference.wj");
    let output_path = temp_dir
        .path()
        .join("build")
        .join("test_cases_string_inference.rs");

    fs::write(&input_path, source).unwrap();

    // Compile with wj
    let output = Command::new(test_utils::wj_binary())
        .args(["build", input_path.to_str().unwrap(), "--no-cargo"])
        .current_dir(temp_dir.path())
        .output()
        .expect("Failed to run wj compiler");

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        let stdout = String::from_utf8_lossy(&output.stdout);
        panic!(
            "Windjammer compilation failed:\nSTDOUT:\n{}\nSTDERR:\n{}",
            stdout, stderr
        );
    }

    // Read generated Rust code
    let rust_code = fs::read_to_string(&output_path).unwrap();
    println!("Generated Rust:\n{}", rust_code);

    // The impl function should take &str parameters (read-only usage infers Borrowed)
    // Windjammer philosophy: compiler infers the cheapest ownership mode
    // DESIGN: String → &str for borrowed (idiomatic Rust, not &String anti-pattern)
    assert!(
        rust_code.contains("fn test_user_impl(id: &str, name: &str, _age: i32)"),
        "Should generate impl function with &str parameters (idiomatic Rust).\nGenerated:\n{}",
        rust_code
    );

    // The test case calls pass string literals directly (already &str, no .to_string() needed)
    assert!(
        rust_code.contains(r#"test_user_impl("alice", "Alice""#),
        "string literals pass directly as &str (no .to_string() needed).\nGenerated:\n{}",
        rust_code
    );

    // Strip windjammer_runtime import for standalone rustc test
    let rust_code_stripped = rust_code
        .lines()
        .filter(|line| !line.trim().starts_with("use windjammer_runtime::test::"))
        .collect::<Vec<_>>()
        .join("\n");

    let rustc_test_path = temp_dir.path().join("test_rustc.rs");
    fs::write(&rustc_test_path, rust_code_stripped).unwrap();

    // Verify it compiles with rustc
    let rustc_result = Command::new("rustc")
        .args([
            "--crate-type",
            "lib",
            "--edition",
            "2021",
            rustc_test_path.to_str().unwrap(),
        ])
        .output()
        .expect("Failed to run rustc");

    if !rustc_result.status.success() {
        panic!(
            "Rustc compilation failed:\n{}",
            String::from_utf8_lossy(&rustc_result.stderr)
        );
    }
}

#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_function_call_with_string_literal_auto_converts() {
    let source = r#"
fn greet(name: string) -> string {
    format!("Hello, {}", name)
}

fn test_greet() {
    let result = greet("World")
    assert_eq(result, "Hello, World".to_string())
}
"#;

    let temp_dir = TempDir::new().unwrap();
    let input_path = temp_dir.path().join("string_literal_param.wj");
    let output_path = temp_dir
        .path()
        .join("build")
        .join("string_literal_param.rs");

    fs::write(&input_path, source).unwrap();

    // Compile with wj
    let output = Command::new(test_utils::wj_binary())
        .args(["build", input_path.to_str().unwrap(), "--no-cargo"])
        .current_dir(temp_dir.path())
        .output()
        .expect("Failed to run wj compiler");

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        let stdout = String::from_utf8_lossy(&output.stdout);
        panic!(
            "Windjammer compilation failed:\nSTDOUT:\n{}\nSTDERR:\n{}",
            stdout, stderr
        );
    }

    // Read generated Rust code
    let rust_code = fs::read_to_string(&output_path).unwrap();
    println!("Generated Rust:\n{}", rust_code);

    // NEW DESIGN: Read-only string parameter infers to &str
    // String literal (already &str) can be passed directly - no conversion needed!
    assert!(
        rust_code.contains(r#"greet("World")"#),
        "String literal should be passed directly to &str parameter.\nGenerated:\n{}",
        rust_code
    );

    // Strip windjammer_runtime import for standalone rustc test
    let rust_code_stripped = rust_code
        .lines()
        .filter(|line| !line.trim().starts_with("use windjammer_runtime::test::"))
        .collect::<Vec<_>>()
        .join("\n");

    let rustc_test_path = temp_dir.path().join("test_rustc_2.rs");
    fs::write(&rustc_test_path, rust_code_stripped).unwrap();

    // Verify it compiles with rustc
    let rustc_result = Command::new("rustc")
        .args([
            "--crate-type",
            "lib",
            "--edition",
            "2021",
            rustc_test_path.to_str().unwrap(),
        ])
        .output()
        .expect("Failed to run rustc");

    if !rustc_result.status.success() {
        panic!(
            "Rustc compilation failed:\n{}",
            String::from_utf8_lossy(&rustc_result.stderr)
        );
    }
}