bashrs 6.66.0

Rust-to-Shell transpiler for deterministic bootstrap scripts
//! Simulation Probar Testing - Edge Case Discovery
//!
//! Tests edge cases that must NOT cause panics or crashes.
//! Uses jugar-probar's TUI coverage framework to verify 100 S-code tests.
//!
//! Run: cargo test -p bashrs --test simulation_probar_testing

#![allow(clippy::unwrap_used)]

use bashrs::linter::rules::lint_shell;
use jugar_probar::gui_coverage;
use std::panic::{self, AssertUnwindSafe};

/// Helper: Run lint without panicking
fn lint_safely(code: &str) -> bool {
    let result = panic::catch_unwind(AssertUnwindSafe(|| lint_shell(code)));
    result.is_ok()
}

// ============================================================================
// S1xx: UNICODE AND ENCODING
// ============================================================================

#[test]
fn test_simulation_unicode_encoding() {
    let mut gui = gui_coverage! {
        buttons: ["S101", "S102", "S103", "S104", "S105", "S106", "S107", "S108", "S109", "S110"],
        screens: ["pass", "fail"]
    };

    let tests = [
        ("S101", "echo 'héllo wörld'", "Latin extended chars"),
        ("S102", "echo '日本語テスト'", "Japanese characters"),
        ("S103", "echo '🚀🔥💻'", "Emoji in string"),
        ("S104", "var='مرحبا'; echo $var", "RTL Arabic text"),
        ("S105", "echo 'Ω≈ç√∫'", "Math symbols"),
        ("S106", "echo '\u{0000}'", "Null byte in string"),
        ("S107", "echo $'\\xc0\\xc1'", "Invalid UTF-8 sequence"),
        ("S108", "x='a\u{200B}b'; echo $x", "Zero-width space"),
        ("S109", "echo '\u{200B}'", "Zero-width char only"),
        ("S110", "echo 'A\u{0308}'", "Combining diacritical"),
    ];

    for (id, code, desc) in tests {
        let passed = lint_safely(code);
        gui.click(id);
        gui.visit(if passed { "pass" } else { "fail" });
        assert!(passed, "{}: Must NOT panic on: {} ({})", id, code, desc);
    }

    let report = gui.generate_report();
    println!(
        "\nS1xx Unicode: {:.1}% elements",
        report.element_coverage * 100.0
    );
    assert!(
        report.element_coverage >= 1.0,
        "All unicode tests must pass"
    );
}

// ============================================================================
// S2xx: LARGE INPUT AND BOUNDARIES
// ============================================================================

#[test]
fn test_simulation_boundary_conditions() {
    let mut gui = gui_coverage! {
        buttons: ["S201", "S202", "S203", "S204", "S205", "S206", "S207", "S208", "S209", "S210"],
        screens: ["pass", "fail"]
    };

    // Build test cases - some need dynamic generation
    let s201 = format!("x={}", "a".repeat(10000));
    let s202 = format!("echo {}", "word ".repeat(100));
    let s203 = format!("{}echo test", " ".repeat(100));
    let s204 = format!("echo test{}", " ".repeat(100));
    let s210 = format!("# {}", "x".repeat(500));

    let tests: [(&str, &str, &str); 10] = [
        ("S201", &s201, "10KB variable"),
        ("S202", &s202, "100 word echo"),
        ("S203", &s203, "100 leading spaces"),
        ("S204", &s204, "100 trailing spaces"),
        ("S205", "\n\n\n\n\necho test", "5 leading newlines"),
        (
            "S206",
            "echo test; echo test; echo test; echo test; echo test",
            "5 chained commands",
        ),
        (
            "S207",
            "cat << EOF\nline1\nline2\nline3\nEOF",
            "3 line heredoc",
        ),
        (
            "S208",
            "echo ${x:-${y:-${z:-default}}}",
            "3 nested expansions",
        ),
        ("S209", "arr=(a b c d e f g h i j)", "10 element array"),
        ("S210", &s210, "500 char comment"),
    ];

    for (id, code, desc) in tests {
        let passed = lint_safely(code);
        gui.click(id);
        gui.visit(if passed { "pass" } else { "fail" });
        assert!(passed, "{}: Must NOT panic on: {} ({})", id, desc, desc);
    }

    let report = gui.generate_report();
    println!(
        "\nS2xx Boundary: {:.1}% elements",
        report.element_coverage * 100.0
    );
    assert!(
        report.element_coverage >= 1.0,
        "All boundary tests must pass"
    );
}

// ============================================================================
// S3xx: DEEP NESTING
// ============================================================================

#[test]
fn test_simulation_deep_nesting() {
    let mut gui = gui_coverage! {
        buttons: ["S301", "S302", "S303", "S304", "S305", "S306", "S307", "S308", "S309", "S310"],
        screens: ["pass", "fail"]
    };

    let tests = [
        (
            "S301",
            "if true; then if true; then echo deep; fi; fi",
            "2 nested ifs",
        ),
        ("S302", "{ { { echo test; }; }; }", "3 nested blocks"),
        ("S303", "( ( ( echo test ) ) )", "3 nested subshells"),
        (
            "S304",
            "case x in a) case y in b) echo z ;; esac ;; esac",
            "2 nested case",
        ),
        (
            "S305",
            "while true; do while true; do break 2; done; done",
            "2 nested whiles",
        ),
        (
            "S306",
            "for i in a; do for j in b; do echo $i$j; done; done",
            "2 nested fors",
        ),
        ("S307", "echo $(echo $(echo test))", "2 nested cmd subs"),
        ("S308", "[[ true && true ]]", "Compound conditions"),
        ("S309", "echo $(( 1 + (2 + (3)) ))", "3 nested arithmetic"),
        (
            "S310",
            "f() { g() { echo deep; }; g; }; f",
            "2 nested functions",
        ),
    ];

    for (id, code, desc) in tests {
        let passed = lint_safely(code);
        gui.click(id);
        gui.visit(if passed { "pass" } else { "fail" });
        assert!(passed, "{}: Must NOT panic on: {} ({})", id, code, desc);
    }

    let report = gui.generate_report();
    println!(
        "\nS3xx Nesting: {:.1}% elements",
        report.element_coverage * 100.0
    );
    assert!(
        report.element_coverage >= 1.0,
        "All nesting tests must pass"
    );
}

// ============================================================================
// S4xx: SPECIAL CHARACTERS
// ============================================================================

#[test]
fn test_simulation_special_characters() {
    let mut gui = gui_coverage! {
        buttons: ["S401", "S402", "S403", "S404", "S405", "S406", "S407", "S408", "S409", "S410"],
        screens: ["pass", "fail"]
    };

    let tests = [
        ("S401", "echo 'test\ttest'", "Tab in string"),
        ("S402", "echo 'test\rtest'", "Carriage return"),
        ("S403", "echo 'line1\nline2'", "Newline in string"),
        ("S404", "echo $'\\a\\b\\e\\f'", "ANSI escapes"),
        ("S405", "echo 'test\\\\test'", "Backslash in string"),
        ("S406", "x='`'; echo $x", "Backtick in var"),
        ("S407", "echo '$()'", "Literal cmd sub"),
        ("S408", "echo '$((1+1))'", "Literal arithmetic"),
        ("S409", "echo '!!'", "History expansion chars"),
        ("S410", "echo '#not a comment'", "Hash in quotes"),
    ];

    for (id, code, desc) in tests {
        let passed = lint_safely(code);
        gui.click(id);
        gui.visit(if passed { "pass" } else { "fail" });
        assert!(passed, "{}: Must NOT panic on: {} ({})", id, code, desc);
    }

    let report = gui.generate_report();
    println!(
        "\nS4xx Special Chars: {:.1}% elements",
        report.element_coverage * 100.0
    );
    assert!(
        report.element_coverage >= 1.0,
        "All special char tests must pass"
    );
}

// ============================================================================
// S5xx: MALFORMED SYNTAX (graceful error handling)
// ============================================================================

#[test]
fn test_simulation_malformed_syntax() {
    let mut gui = gui_coverage! {
        buttons: ["S501", "S502", "S503", "S504", "S505", "S506", "S507", "S508", "S509", "S510"],
        screens: ["pass", "fail"]
    };

    let tests = [
        ("S501", "echo ${", "Unclosed brace"),
        ("S502", "echo $((1+)", "Unclosed arithmetic"),
        ("S503", "if true; then", "Missing fi"),
        ("S504", "case x in", "Missing esac"),
        ("S505", "while true; do", "Missing done"),
        ("S506", "echo \"unterminated", "Unclosed quote"),
        ("S507", "echo 'unterminated", "Unclosed single quote"),
        ("S508", "((", "Empty arithmetic"),
        ("S509", "[[", "Empty condition"),
        ("S510", "}", "Unmatched brace"),
    ];

    for (id, code, desc) in tests {
        // Malformed syntax should NOT cause panics - may return errors
        let passed = lint_safely(code);
        gui.click(id);
        gui.visit(if passed { "pass" } else { "fail" });
        assert!(
            passed,
            "{}: Must NOT panic on malformed: {} ({})",
            id, code, desc
        );
    }

    let report = gui.generate_report();
    println!(
        "\nS5xx Malformed: {:.1}% elements",
        report.element_coverage * 100.0
    );
    assert!(
        report.element_coverage >= 1.0,
        "All malformed tests must not panic"
    );
}

// ============================================================================
// S6xx: TIMING/ORDER EDGE CASES
// ============================================================================

#[test]
fn test_simulation_timing_order() {
    let mut gui = gui_coverage! {
        buttons: ["S601", "S602", "S603", "S604", "S605", "S606", "S607", "S608", "S609", "S610"],
        screens: ["pass", "fail"]
    };

    let tests = [
        ("S601", "echo $$ $!", "PID variables"),
        ("S602", "echo ${RANDOM} ${RANDOM}", "Multiple RANDOM"),
        ("S603", "trap 'echo exit' EXIT; exit", "Trap on exit"),
        ("S604", "eval 'echo test'", "Eval command"),
        ("S605", "exec 3>&1", "FD manipulation"),
        ("S606", "wait", "Wait builtin"),
        ("S607", "jobs", "Jobs builtin"),
        ("S608", "bg 2>/dev/null", "Background builtin"),
        ("S609", "fg 2>/dev/null", "Foreground builtin"),
        ("S610", "disown 2>/dev/null", "Disown builtin"),
    ];

    for (id, code, desc) in tests {
        let passed = lint_safely(code);
        gui.click(id);
        gui.visit(if passed { "pass" } else { "fail" });
        assert!(passed, "{}: Must NOT panic on: {} ({})", id, code, desc);
    }

    let report = gui.generate_report();
    println!(
        "\nS6xx Timing: {:.1}% elements",
        report.element_coverage * 100.0
    );
    assert!(report.element_coverage >= 1.0, "All timing tests must pass");
}

// ============================================================================
// S7xx: RESOURCE LIMITS
// ============================================================================

#[test]
fn test_simulation_resource_limits() {
    let mut gui = gui_coverage! {
        buttons: ["S701", "S702", "S703", "S704", "S705", "S706", "S707", "S708", "S709", "S710"],
        screens: ["pass", "fail"]
    };

    let tests = [
        ("S701", "echo ${xxxxxxxxxx}", "Long variable name"),
        ("S702", "fxxxxxxxx() { :; }", "Long function name"),
        ("S703", "alias aaaaaaaaaa='echo'", "Long alias name"),
        ("S704", "export VVVVVVVVVV=value", "Long export name"),
        ("S705", "read vvvvv wwwww", "Multiple read vars"),
        ("S706", "f() { local vvvvvvvvvv=x; }", "Long local var"),
        ("S707", "declare -a arrarrarr", "Long array name"),
        ("S708", "printf '%s' 'x' 'y' 'z'", "Many printf args"),
        ("S709", "echo $1 $2 $3 $4 $5", "Many positional refs"),
        ("S710", "set -- arg1 arg2 arg3 arg4 arg5", "Many set args"),
    ];

    for (id, code, desc) in tests {
        let passed = lint_safely(code);
        gui.click(id);
        gui.visit(if passed { "pass" } else { "fail" });
        assert!(passed, "{}: Must NOT panic on: {} ({})", id, code, desc);
    }

    let report = gui.generate_report();
    println!(
        "\nS7xx Resource: {:.1}% elements",
        report.element_coverage * 100.0
    );
    assert!(
        report.element_coverage >= 1.0,
        "All resource tests must pass"
    );
}

// ============================================================================
// S8xx: ESCAPE SEQUENCES
// ============================================================================

#[test]

include!("simulation_probar_testing_simulation_e.rs");