ruchy 4.2.0

A systems scripting language that transpiles to idiomatic Rust with extreme quality engineering
Documentation
//! String Method Transpilation Tests
//! Toyota Way: Automated tests institutionalize correct behavior permanently
//!
//! These tests ensure string methods are correctly mapped from Ruchy names
//! to Rust names during transpilation, preventing regressions.

#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
#![allow(clippy::needless_raw_string_hashes)]
#![allow(clippy::uninlined_format_args)]
#![allow(clippy::manual_assert)]
#![allow(clippy::panic)]
#![allow(clippy::expect_fun_call)]

use ruchy::{Parser, Transpiler};
use std::fs;
use std::process::Command;
use tempfile::TempDir;

/// Test string method name mapping in transpilation
#[test]
fn test_string_method_name_mapping() {
    let transpiler = Transpiler::new();

    // Check cases: (ruchy_method, expected_rust_method)
    let test_cases = [
        ("to_upper", "to_uppercase"),
        ("to_lower", "to_lowercase"),
        ("length", "len"),
    ];

    for (ruchy_method, rust_method) in test_cases {
        let code = format!(r#""hello".{}()"#, ruchy_method);
        let mut parser = Parser::new(&code);
        let ast = parser.parse().expect("Failed to parse");

        let result = transpiler.transpile(&ast).expect("Failed to transpile");
        let transpiled_code = result.to_string();

        // The transpiled code should contain the correct Rust method name
        assert!(
            transpiled_code.contains(rust_method),
            "Expected '{}' to be transpiled to '{}', but got: {}",
            ruchy_method,
            rust_method,
            transpiled_code
        );

        // The transpiled code should NOT contain the original Ruchy method name
        assert!(
            !transpiled_code.contains(&format!(".{}", ruchy_method)),
            "Transpiled code still contains original method '{}': {}",
            ruchy_method,
            transpiled_code
        );
    }
}

/// Test string method compilation (end-to-end)
#[test]
fn test_string_method_compilation() {
    let test_cases = [
        (r#""hello".to_upper()"#, "HELLO"),
        (r#""WORLD".to_lower()"#, "world"),
        (r#""test".len()"#, "4"),
    ];

    for (code, expected_output) in test_cases {
        let temp_dir = TempDir::new().expect("Failed to create temp dir");
        let test_file = temp_dir.path().join("test.ruchy");

        fs::write(&test_file, code).expect("Failed to write test file");

        let output = Command::new("./target/debug/ruchy")
            .arg("run")
            .arg(&test_file)
            .output()
            .expect("Failed to execute ruchy");

        if !output.status.success() {
            panic!(
                "Compilation failed for '{}': {}",
                code,
                String::from_utf8_lossy(&output.stderr)
            );
        }

        let stdout = String::from_utf8_lossy(&output.stdout);
        assert!(
            stdout.contains(expected_output),
            "Expected output '{}' for '{}', got: '{}'",
            expected_output,
            code,
            stdout
        );
    }
}

/// Property test: All string methods should transpile to valid Rust
#[test]
fn test_string_method_transpilation_validity() {
    let transpiler = Transpiler::new();

    let string_methods = [
        "to_upper",
        "to_lower",
        "len",
        "trim",
        "chars",
        "reverse",
        "contains",
        "starts_with",
        "ends_with",
        "replace",
        "split",
    ];

    for method in string_methods {
        let code = match method {
            "replace" => format!(r#""hello".{}("l", "x")"#, method),
            "contains" | "starts_with" | "ends_with" => format!(r#""hello".{}("he")"#, method),
            "split" => format!(r#""hello".{}(" ")"#, method),
            _ => format!(r#""hello".{}()"#, method),
        };

        let mut parser = Parser::new(&code);
        let ast = parser.parse().expect(&format!("Failed to parse: {}", code));

        let result = transpiler
            .transpile(&ast)
            .expect(&format!("Failed to transpile: {}", code));
        let transpiled_code = result.to_string();

        // The transpiled code should be valid Rust syntax (basic check)
        assert!(
            transpiled_code.contains("fn main"),
            "Transpiled code should contain main function: {}",
            transpiled_code
        );

        // Should not contain obvious syntax errors
        assert!(
            !transpiled_code.contains(".."),
            "Transpiled code contains double dots (syntax error): {}",
            transpiled_code
        );
    }
}

/// Integration test: String methods in complex expressions
#[test]
fn test_string_methods_in_expressions() {
    let test_cases = [
        (r#"let x = "hello".to_upper(); println("{}", x)"#, "HELLO"),
        (r#"println("{}", "WORLD".to_lower().len())"#, "5"),
        (
            r#"if "test".len() > 3 { println("long") } else { println("short") }"#,
            "long",
        ),
    ];

    for (code, expected_output) in test_cases {
        let temp_dir = TempDir::new().expect("Failed to create temp dir");
        let test_file = temp_dir.path().join("test.ruchy");

        fs::write(&test_file, code).expect("Failed to write test file");

        let output = Command::new("./target/debug/ruchy")
            .arg("run")
            .arg(&test_file)
            .output()
            .expect("Failed to execute ruchy");

        if !output.status.success() {
            panic!(
                "Compilation failed for complex expression '{}': {}",
                code,
                String::from_utf8_lossy(&output.stderr)
            );
        }

        let stdout = String::from_utf8_lossy(&output.stdout);
        assert!(
            stdout.contains(expected_output),
            "Expected output '{}' for complex expression '{}', got: '{}'",
            expected_output,
            code,
            stdout
        );
    }
}

/// Regression test: Ensure one-liner compatibility
#[test]
fn test_string_method_one_liners() {
    let one_liners = [
        r#""hello".to_upper()"#,
        r#""WORLD".to_lower()"#,
        r#""test".len()"#,
        r#""  spaced  ".trim()"#,
    ];

    for code in one_liners {
        let temp_dir = TempDir::new().expect("Failed to create temp dir");
        let test_file = temp_dir.path().join("test.ruchy");

        fs::write(&test_file, code).expect("Failed to write test file");

        let output = Command::new("./target/debug/ruchy")
            .arg("run")
            .arg(&test_file)
            .output()
            .expect("Failed to execute ruchy");

        assert!(
            output.status.success(),
            "One-liner '{}' failed to compile: {}",
            code,
            String::from_utf8_lossy(&output.stderr)
        );

        // Should produce some output (not empty)
        let stdout = String::from_utf8_lossy(&output.stdout);
        assert!(
            !stdout.trim().is_empty(),
            "One-liner '{}' produced no output",
            code
        );
    }
}