bashrs 6.66.0

Rust-to-Shell transpiler for deterministic bootstrap scripts
#![allow(deprecated)]
#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
// Tests can use unwrap() for simplicity
// Integration tests for REPL Explain Mode (REPL-005-002)
//
// Tests the explain mode functionality end-to-end using assert_cmd.
// This verifies the user-facing REPL behavior for bash construct explanations.
#![allow(non_snake_case)] // Test naming convention: test_<TASK_ID>_<feature>_<scenario>

use assert_cmd::Command;

#[allow(dead_code)] // Reserved for future REPL integration tests
fn bashrs_repl() -> Command {
    assert_cmd::cargo_bin_cmd!("bashrs")
}

// ===== INTEGRATION TESTS =====

/// Test: Switch to explain mode and explain parameter expansion
#[test]
fn test_REPL_005_002_explain_mode_parameter_expansion() {
    // Note: This test would work if we had a way to send stdin to the REPL
    // For now, we'll document the expected behavior:
    //
    // Input:
    // :mode explain
    // ${var:-default}
    //
    // Expected output:
    // Switched to explain mode
    // 📖 Parameter Expansion: ${parameter:-word}
    //    Use Default Value
    //
    // Actual implementation: Would require interactive input handling
    // which assert_cmd doesn't support well. Consider implementing
    // --explain flag for non-interactive use.
}

/// Test: Explain mode shows helpful message for unknown constructs
#[test]
fn test_REPL_005_002_explain_mode_unknown_construct() {
    // Expected behavior documented for manual testing:
    //
    // Input:
    // :mode explain
    // unknown_construct_xyz
    //
    // Expected output:
    // No explanation available for: unknown_construct_xyz
    // Try parameter expansions (${var:-default}), control flow (for, if, while), or redirections (>, <, |)
}

/// Test: Documentation - explain mode is listed in help
#[test]
fn test_REPL_005_002_explain_mode_in_help() {
    // Verify the REPL help text mentions explain mode
    // This would be tested by checking bashrs repl --help
    // or the help command within the REPL
}

// ===== DOCUMENTATION TESTS =====

/// Verify explain module is public and properly exported
#[test]
fn test_REPL_005_002_explain_module_exported() {
    // This test verifies the API is properly exported
    use bashrs::repl::explain_bash;

    let result = explain_bash("${var:-default}");
    assert!(result.is_some(), "Should recognize parameter expansion");

    let explanation = result.unwrap();
    assert!(explanation.title.contains(":-"));
}

/// Verify Explanation struct is public and usable
#[test]
fn test_REPL_005_002_explanation_struct_public() {
    use bashrs::repl::Explanation;

    let exp = Explanation::new("Test", "Description", "Details").with_example("$ example");

    let formatted = exp.format();
    assert!(formatted.contains("📖 Test"));
    assert!(formatted.contains("Example:"));
}

/// Test parameter expansion variations
#[test]
fn test_REPL_005_002_parameter_expansions_comprehensive() {
    use bashrs::repl::explain_bash;

    // Use default value
    assert!(explain_bash("${var:-default}").is_some());

    // Assign default value
    assert!(explain_bash("${var:=default}").is_some());

    // Display error
    assert!(explain_bash("${var:?error}").is_some());

    // Use alternate value
    assert!(explain_bash("${var:+alternate}").is_some());

    // String length
    assert!(explain_bash("${#var}").is_some());
}

/// Test control flow constructs
#[test]
fn test_REPL_005_002_control_flow_comprehensive() {
    use bashrs::repl::explain_bash;

    // For loop
    assert!(explain_bash("for i in *.txt").is_some());

    // If statement
    assert!(explain_bash("if [ -f file ]").is_some());

    // While loop
    assert!(explain_bash("while true").is_some());

    // Case statement
    assert!(explain_bash("case $var in").is_some());
}

/// Test redirection constructs
#[test]
fn test_REPL_005_002_redirections_comprehensive() {
    use bashrs::repl::explain_bash;

    // Output redirection
    assert!(explain_bash("echo test > file").is_some());

    // Input redirection
    assert!(explain_bash("cat < file").is_some());

    // Pipe
    assert!(explain_bash("cat file | grep pattern").is_some());

    // Here document
    assert!(explain_bash("cat << EOF").is_some());
}

/// Property test: All recognized constructs return Some(Explanation)
#[test]
fn test_REPL_005_002_property_recognized_constructs() {
    use bashrs::repl::explain_bash;

    let constructs = vec![
        "${var:-default}",
        "${var:=default}",
        "${var:?error}",
        "${var:+alternate}",
        "${#var}",
        "for i in list",
        "if [ test ]",
        "while true",
        "case $var in",
        "echo > file",
        "cat < file",
        "cmd | grep",
        "cat << EOF",
    ];

    for construct in constructs {
        let result = explain_bash(construct);
        assert!(
            result.is_some(),
            "Should recognize construct: {}",
            construct
        );

        let explanation = result.unwrap();
        assert!(!explanation.title.is_empty(), "Title should not be empty");
        assert!(
            !explanation.description.is_empty(),
            "Description should not be empty"
        );
        assert!(
            !explanation.details.is_empty(),
            "Details should not be empty"
        );
    }
}

/// Property test: Unknown constructs return None
#[test]
fn test_REPL_005_002_property_unknown_constructs() {
    use bashrs::repl::explain_bash;

    let unknown_constructs = vec![
        "unknown_command_xyz",
        "random text",
        "123456",
        "",
        "no special characters here",
    ];

    for construct in unknown_constructs {
        let result = explain_bash(construct);
        assert!(
            result.is_none(),
            "Should not recognize unknown construct: {}",
            construct
        );
    }
}

/// Property test: Explanation format is consistent
#[test]
fn test_REPL_005_002_property_format_consistency() {
    use bashrs::repl::explain_bash;

    let constructs = vec!["${var:-default}", "for i in list", "echo > file"];

    for construct in constructs {
        let result = explain_bash(construct);
        assert!(result.is_some());

        let explanation = result.unwrap();
        let formatted = explanation.format();

        // All formatted explanations should start with 📖
        assert!(
            formatted.starts_with("📖"),
            "Should start with 📖: {}",
            construct
        );

        // Should contain the title
        assert!(
            formatted.contains(&explanation.title),
            "Should contain title"
        );

        // Should contain the description
        assert!(
            formatted.contains(&explanation.description),
            "Should contain description"
        );
    }
}