bashrs 6.66.0

Rust-to-Shell transpiler for deterministic bootstrap scripts
#![allow(clippy::unwrap_used)]
#![allow(unused_imports)]

use super::super::ast::Redirect;
use super::super::lexer::Lexer;
use super::super::parser::BashParser;
use super::super::semantic::SemanticAnalyzer;
use super::super::*;

/// Helper: parse a script and return whether parsing succeeded.
/// Used by documentation tests that only need to verify parsability.
#[test]
fn test_JOB_002_jobs_command_output_format() {
    // DOCUMENTATION: jobs command output format
    //
    // Output format: [job_number]status command
    //
    // Example:
    // [1]-  Running                 sleep 10 &
    // [2]+  Stopped                 vim file.txt
    // [3]   Running                 ./long_process &
    //
    // Fields:
    // - [1]: Job number (sequential)
    // - -/+: Current (-) or previous (+) job
    // - Running/Stopped: Job status
    // - command: Original command with arguments
    //
    // Status values:
    // - Running: Job executing in background
    // - Stopped: Job suspended (Ctrl-Z)
    // - Done: Job completed
    // - Terminated: Job killed
    //
    // All of this is interactive-only, NOT SUPPORTED in bashrs.

    let jobs_with_options = r#"
sleep 10 &
sleep 20 &
jobs -l  # List with PIDs
jobs -r  # Running jobs only
jobs -s  # Stopped jobs only
"#;

    let result = BashParser::new(jobs_with_options);
    if let Ok(mut parser) = result {
        let parse_result = parser.parse();
        assert!(
            parse_result.is_ok() || parse_result.is_err(),
            "jobs command with options is interactive only"
        );
    }

    // Job status tracking is interactive-only:
    // - Requires terminal control
    // - Needs signal handling (SIGTSTP, SIGCONT)
    // - Not available in non-interactive scripts
    // - bashrs scripts run foreground only
}

#[test]
fn test_JOB_002_purification_removes_jobs() {
    // DOCUMENTATION: Purification removes jobs command
    //
    // Before (with job control):
    // #!/bin/bash
    // sleep 10 &
    // sleep 20 &
    // jobs
    // echo "Waiting..."
    // wait
    //
    // After (purified, jobs removed):
    // #!/bin/sh
    // sleep 10  # Foreground
    // sleep 20  # Foreground
    // # jobs removed (not needed)
    // printf '%s\n' "Waiting..."
    // # wait removed (no background jobs)
    //
    // Removed because:
    // - Scripts run foreground only (no &)
    // - No job tracking needed
    // - Simplified execution model

    let purified_no_jobs = r#"
#!/bin/sh
sleep 10
sleep 20
printf '%s\n' "Waiting..."
"#;

    let result = BashParser::new(purified_no_jobs);
    if let Ok(mut parser) = result {
        let parse_result = parser.parse();
        assert!(
            parse_result.is_ok() || parse_result.is_err(),
            "Purified scripts have no jobs command"
        );
    }

    // Purification strategy:
    // 1. Remove & from commands (run foreground)
    // 2. Remove jobs command (no job tracking)
    // 3. Remove wait command (no background jobs)
    // 4. Sequential execution only
}

#[test]
fn test_JOB_002_job_control_requirements() {
    // DOCUMENTATION: Job control requirements
    //
    // Job control requires:
    // 1. Interactive shell (set -m, monitor mode)
    // 2. Terminal control (TTY)
    // 3. Signal handling (SIGTSTP, SIGCONT, SIGCHLD)
    // 4. Process groups
    //
    // Example (interactive shell only):
    // $ set -m           # Enable job control
    // $ sleep 10 &       # Start background job
    // [1] 12345
    // $ jobs             # List jobs
    // [1]+  Running      sleep 10 &
    // $ fg %1            # Bring to foreground
    // sleep 10
    //
    // Scripts don't have these:
    // - No TTY (run non-interactively)
    // - No job control (-m not set)
    // - Signal handling different
    // - No foreground/background management

    let job_control_script = r#"
set -m          # Enable job control
sleep 10 &      # Background job
jobs            # List jobs
fg %1           # Foreground job
"#;

    let result = BashParser::new(job_control_script);
    if let Ok(mut parser) = result {
        let parse_result = parser.parse();
        assert!(
            parse_result.is_ok() || parse_result.is_err(),
            "Job control requires interactive shell"
        );
    }

    // bashrs philosophy:
    // - No job control (set -m never enabled)
    // - No background jobs (& removed)
    // - No jobs/fg/bg commands
    // - Foreground sequential execution only
}

#[test]
fn test_JOB_002_script_alternatives_to_jobs() {
    // DOCUMENTATION: Script alternatives to job monitoring
    //
    // Interactive job control → Script alternative
    //
    // 1. Monitor background jobs → Run foreground sequentially
    //    Interactive: sleep 10 & sleep 20 & jobs
    //    Script:      sleep 10; sleep 20
    //
    // 2. Check job status → Use wait + $?
    //    Interactive: jobs -r  # Running jobs
    //    Script:      wait $pid && echo "success"
    //
    // 3. List running processes → Use ps command
    //    Interactive: jobs
    //    Script:      ps aux | grep my_process
    //
    // 4. Parallel execution → Use make -j or xargs -P
    //    Interactive: cmd1 & cmd2 & cmd3 & jobs
    //    Script:      printf '%s\n' cmd1 cmd2 cmd3 | xargs -P 3 -I {} sh -c {}

    let sequential_alternative = r#"
#!/bin/sh
# Sequential execution (no job control)

printf '%s\n' "Task 1..."
sleep 10

printf '%s\n' "Task 2..."
sleep 20

printf '%s\n' "All tasks complete"
"#;

    let result = BashParser::new(sequential_alternative);
    if let Ok(mut parser) = result {
        let parse_result = parser.parse();
        assert!(
            parse_result.is_ok() || parse_result.is_err(),
            "Scripts use sequential execution instead of job control"
        );
    }

    // Key principle:
    // Interactive: Implicit job tracking with jobs command
    // Scripts: Explicit process management (ps, wait, sequential)
}

#[test]
fn test_JOB_002_interactive_vs_script_job_control() {
    // DOCUMENTATION: Interactive vs script job control
    //
    // Interactive shells (have job control):
    // - jobs: List background jobs
    // - fg: Bring job to foreground
    // - bg: Resume job in background
    // - Ctrl-Z: Suspend current job
    // - disown: Remove job from table
    // - Job numbers: %1, %2, %+, %-
    //
    // Scripts (no job control):
    // - wait: Wait for process completion (POSIX)
    // - ps: List processes (external command)
    // - kill: Send signals to processes
    // - Sequential execution (default)
    // - Process IDs only (no job numbers)

    let script_process_management = r#"
#!/bin/sh
# Script-style process management (no job control)

# Start process, save PID
sleep 60 &
pid=$!

# Monitor with ps (not jobs)
ps -p "$pid" > /dev/null 2>&1 && printf '%s\n' "Process running"

# Wait for completion
wait "$pid"
exit_status=$?

printf 'Process exited with status: %d\n' "$exit_status"
"#;

    let result = BashParser::new(script_process_management);
    if let Ok(mut parser) = result {
        let parse_result = parser.parse();
        assert!(
            parse_result.is_ok() || parse_result.is_err(),
            "Scripts use PIDs and wait, not job control"
        );
    }

    // Summary:
    // Interactive: jobs, fg, bg, job numbers (%1, %2)
    // Script: wait, ps, kill, process IDs ($pid, $!)
    //
    // bashrs: Remove jobs command, keep wait (POSIX)
}

// ============================================================================
// JOB-003: fg/bg Commands (Interactive Job Control, NOT SUPPORTED)
// ============================================================================
//
// Task: JOB-003 - Document fg/bg commands
// Status: DOCUMENTED (NOT SUPPORTED - interactive job control)
// Priority: LOW (job control not needed in scripts)
//
// The fg (foreground) and bg (background) commands manage job execution state.
// They're interactive job control features.
//
// Bash behavior:
// - fg: Brings background/stopped job to foreground
// - bg: Resumes stopped job in background
// - Job specification: %n, %string, %%, %+, %-
// - Interactive shells only (requires job control)
//
// bashrs policy:
// - NOT SUPPORTED (interactive job control)
// - Purification removes fg/bg commands
// - Scripts run foreground only (no job state management)
// - POSIX sh supports fg/bg, but bashrs doesn't use them
//
// Transformation:
// Bash input:
//   sleep 10 &
//   fg %1
//
// Purified POSIX sh:
//   sleep 10  # Run in foreground (no &)
//   (fg removed - not needed)
//
// Related features:
// - jobs command - JOB-002 (not supported)
// - Background jobs (&) - JOB-001 (partial support)
// - disown command - Job control (not supported)
// - Ctrl-Z (suspend) - Interactive signal handling

#[test]
fn test_JOB_003_fg_command_not_supported() {
    // DOCUMENTATION: 'fg' command is NOT SUPPORTED (interactive job control)
    //
    // fg command brings job to foreground:
    // $ sleep 10 &
    // [1] 12345
    // $ fg %1
    // sleep 10
    // (now running in foreground)
    //
    // NOT SUPPORTED because:
    // - Interactive job control feature
    // - Scripts run foreground only (no job state changes)
    // - No TTY control in non-interactive mode
    // - Not needed in automated execution

    let fg_script = r#"
sleep 10 &
fg %1
"#;

    let result = BashParser::new(fg_script);
    match result {
        Ok(mut parser) => {
            let parse_result = parser.parse();
            assert!(
                parse_result.is_ok() || parse_result.is_err(),
                "fg command is interactive only, NOT SUPPORTED in scripts"
            );
        }
        Err(_) => {
            // Parse error acceptable - interactive feature
        }
    }

    // fg command syntax (all interactive):
    // fg          # Foreground current job (%)
    // fg %1       # Foreground job 1
    // fg %sleep   # Foreground job with 'sleep' in command
    // fg %%       # Foreground current job
    // fg %+       # Foreground current job
    // fg %-       # Foreground previous job
    //
    // All forms are interactive-only and NOT SUPPORTED in bashrs.
}

#[test]
fn test_JOB_003_bg_command_not_supported() {
    // DOCUMENTATION: 'bg' command is NOT SUPPORTED (interactive job control)
    //
    // bg command resumes stopped job in background:
    // $ sleep 10
    // ^Z                    # Ctrl-Z suspends job
    // [1]+  Stopped         sleep 10
    // $ bg %1               # Resume in background
    // [1]+ sleep 10 &
    //
    // NOT SUPPORTED because:
    // - Interactive job control feature
    // - Requires Ctrl-Z (SIGTSTP) suspension
    // - No job state management in scripts
    // - Scripts don't suspend/resume jobs

    let bg_script = r#"
sleep 10
# User presses Ctrl-Z (interactive only)
bg %1
"#;

    let result = BashParser::new(bg_script);
    if let Ok(mut parser) = result {
        let parse_result = parser.parse();
        assert!(
            parse_result.is_ok() || parse_result.is_err(),
            "bg command is interactive only, NOT SUPPORTED in scripts"
        );
    }

    // bg command syntax (all interactive):
    // bg          # Background current stopped job
    // bg %1       # Background stopped job 1
    // bg %sleep   # Background stopped job with 'sleep'
    // bg %%       # Background current stopped job
    // bg %+       # Background current stopped job
    // bg %-       # Background previous stopped job
    //
    // All forms require interactive job suspension, NOT SUPPORTED.
}

#[test]

include!("part2_5_job_003.rs");