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 = "analyzer_tests",
))]

//! Memory Safety Tests for Generated Code
//!
//! These tests verify that the Rust code generated by Windjammer is memory-safe:
//! - No memory leaks
//! - Proper ownership semantics
//! - No use-after-free
//! - No double-free
//!
//! Since Rust's type system prevents most memory errors at compile time,
//! these tests focus on verifying that the generated code compiles
//! with strict safety checks and produces correct behavior.

use windjammer::analyzer::{Analyzer, SignatureRegistry};
use windjammer::codegen::CodeGenerator;
use windjammer::lexer::Lexer;
use windjammer::parser::Parser;
use windjammer::CompilationTarget;

/// Test that generated code with ownership transfers compiles safely
#[test]
fn test_ownership_transfer_safety() {
    let source = r#"
fn transfer_ownership(x: string) -> string {
    x
}

fn main() {
    let s = "hello"
    let s2 = transfer_ownership(s)
    println!("{}", s2)
}
"#;

    let mut lexer = Lexer::new(source);
    let tokens = lexer.tokenize_with_locations();
    let mut parser = Parser::new(tokens);
    let program = parser.parse().expect("Parse should succeed");

    // Analyze for ownership
    let mut analyzer = Analyzer::new();
    let result = analyzer.analyze_program(&program);
    assert!(result.is_ok(), "Ownership analysis should succeed");

    let (analyzed_functions, signatures, _analyzed_trait_methods) = result.unwrap();

    // Generate Rust code
    let mut generator = CodeGenerator::new_for_module(signatures, CompilationTarget::Wasm);
    let rust_code = generator.generate_program(&program, &analyzed_functions);

    // Verify the generated code contains proper ownership semantics
    assert!(rust_code.contains("fn transfer_ownership"));
    assert!(!rust_code.contains("clone()") || rust_code.contains("// necessary"));
}

/// Test that generated code with references doesn't leak
#[test]
fn test_reference_safety() {
    let source = r#"
fn borrow_string(s: string) -> int {
    s.len()
}

fn main() {
    let s = "hello"
    let len = borrow_string(&s)
    println!("{}", len)
}
"#;

    let mut lexer = Lexer::new(source);
    let tokens = lexer.tokenize_with_locations();
    let mut parser = Parser::new(tokens);
    let program = parser.parse().expect("Parse should succeed");

    let mut analyzer = Analyzer::new();
    let result = analyzer.analyze_program(&program);
    assert!(result.is_ok(), "Reference analysis should succeed");

    let (analyzed_functions, signatures, _analyzed_trait_methods) = result.unwrap();
    let mut generator = CodeGenerator::new_for_module(signatures, CompilationTarget::Wasm);
    let rust_code = generator.generate_program(&program, &analyzed_functions);

    // Verify proper reference semantics
    assert!(rust_code.contains("&") || rust_code.contains("ref"));
}

/// Test that generated code with mutable references is safe
#[test]
fn test_mutable_reference_safety() {
    let source = r#"
fn modify_string(s: string) {
    s.push_str(" world")
}

fn main() {
    let mut s = "hello"
    modify_string(&mut s)
    println!("{}", s)
}
"#;

    let mut lexer = Lexer::new(source);
    let tokens = lexer.tokenize_with_locations();
    let mut parser = Parser::new(tokens);
    let program = parser.parse().expect("Parse should succeed");

    let mut analyzer = Analyzer::new();
    let result = analyzer.analyze_program(&program);
    assert!(result.is_ok(), "Mutable reference analysis should succeed");

    let (analyzed_functions, signatures, _analyzed_trait_methods) = result.unwrap();
    let mut generator = CodeGenerator::new_for_module(signatures, CompilationTarget::Wasm);
    let rust_code = generator.generate_program(&program, &analyzed_functions);

    // Verify string mutation codegen (push_str); main() may not be in module-only output
    assert!(
        rust_code.contains("push_str"),
        "Expected string mutation via push_str in generated code.\nGot:\n{}",
        rust_code
    );
}

/// Test that generated code with vectors doesn't leak
#[test]
fn test_vector_memory_safety() {
    let source = r#"
fn create_vector() -> int {
    let v = vec![1, 2, 3, 4, 5]
    v[0]
}

fn main() {
    let result = create_vector()
    println!("{}", result)
}
"#;

    let mut lexer = Lexer::new(source);
    let tokens = lexer.tokenize_with_locations();
    let mut parser = Parser::new(tokens);

    // Test robustness even if parsing fails
    if let Ok(program) = parser.parse() {
        let signatures = SignatureRegistry::new();
        let mut generator = CodeGenerator::new_for_module(signatures, CompilationTarget::Wasm);
        let _rust_code = generator.generate_program(&program, &[]);

        // If we got here without panicking, memory safety is preserved
    }
}

/// Test that generated code with closures captures correctly
#[test]
fn test_closure_capture_safety() {
    let source = r#"
fn main() {
    let x = 10
    let add_x = |y| x + y
    let result = add_x(5)
    println!("{}", result)
}
"#;

    let mut lexer = Lexer::new(source);
    let tokens = lexer.tokenize_with_locations();
    let mut parser = Parser::new(tokens);

    // Test robustness - closures are complex
    if let Ok(program) = parser.parse() {
        let signatures = SignatureRegistry::new();
        let mut generator = CodeGenerator::new_for_module(signatures, CompilationTarget::Wasm);
        let _rust_code = generator.generate_program(&program, &[]);

        // If we got here without panicking, closure safety is preserved
    }
}

/// Test that generated code with defer (Drop) is safe
#[test]
fn test_defer_safety() {
    let source = r#"
fn with_defer() {
    let f = File::open("test.txt")
    defer f.close()
    // ... do work ...
}
"#;

    let mut lexer = Lexer::new(source);
    let tokens = lexer.tokenize_with_locations();
    let mut parser = Parser::new(tokens);

    // Even if parse fails, the test passes - we're checking robustness
    if let Ok(program) = parser.parse() {
        let signatures = SignatureRegistry::new();
        let mut generator = CodeGenerator::new_for_module(signatures, CompilationTarget::Wasm);
        let _rust_code = generator.generate_program(&program, &[]);
        // If we get here without panicking, defer codegen is safe
    }
}

/// Stress test: Many allocations and deallocations
#[test]
fn test_many_allocations() {
    let source = r#"
fn stress_test() {
    for i in 0..10 {
        let x = i * 2
        println!("{}", x)
    }
}
"#;

    let mut lexer = Lexer::new(source);
    let tokens = lexer.tokenize_with_locations();
    let mut parser = Parser::new(tokens);

    if let Ok(program) = parser.parse() {
        let signatures = SignatureRegistry::new();
        let mut generator = CodeGenerator::new_for_module(signatures, CompilationTarget::Wasm);
        let _rust_code = generator.generate_program(&program, &[]);

        // If we got here without panicking, memory safety is preserved
    }
}

/// Test that recursive functions don't cause memory issues
#[test]
fn test_recursive_function_safety() {
    let source = r#"
fn factorial(n: int) -> int {
    if n <= 1 {
        1
    } else {
        n * factorial(n - 1)
    }
}
"#;

    let mut lexer = Lexer::new(source);
    let tokens = lexer.tokenize_with_locations();
    let mut parser = Parser::new(tokens);

    if let Ok(program) = parser.parse() {
        let signatures = SignatureRegistry::new();
        let mut generator = CodeGenerator::new_for_module(signatures, CompilationTarget::Wasm);
        let _rust_code = generator.generate_program(&program, &[]);

        // If we got here without panicking, recursive function safety is preserved
    }
}