"""Tests for the interactive subprocess module.""" import os import sys import pytest import tempfile from ra_aid.proc.interactive import run_interactive_command def test_basic_command(): """Test running a basic command.""" output, retcode = run_interactive_command(["echo", "hello world"]) assert b"hello world" in output assert retcode == 0 def test_shell_pipeline(): """Test running a shell pipeline command.""" output, retcode = run_interactive_command(["/bin/bash", "-c", "echo 'hello world' | grep 'world'"]) assert b"world" in output assert retcode == 0 def test_stderr_capture(): """Test that stderr is properly captured in combined output.""" # Use a command that definitely writes to stderr output, retcode = run_interactive_command(["/bin/bash", "-c", "ls /nonexistent/path"]) assert b"No such file or directory" in output assert retcode == 2 # ls returns 2 for file not found def test_command_not_found(): """Test handling of non-existent commands.""" with pytest.raises(FileNotFoundError): run_interactive_command(["nonexistentcommand"]) def test_empty_command(): """Test handling of empty commands.""" with pytest.raises(ValueError): run_interactive_command([]) def test_interactive_command(): """Test running an interactive command. This test verifies that output appears in real-time using process substitution. We use a command that prints to both stdout and stderr to verify capture.""" output, retcode = run_interactive_command(["/bin/bash", "-c", "echo stdout; echo stderr >&2"]) assert b"stdout" in output assert b"stderr" in output assert retcode == 0 def test_large_output(): """Test handling of commands that produce large output.""" # Generate a large output with predictable content cmd = "for i in {1..10000}; do echo \"Line $i of test output\"; done" output, retcode = run_interactive_command(["/bin/bash", "-c", cmd]) # Filter out script header/footer lines = [line for line in output.splitlines() if b"Script" not in line and line.strip()] # Verify we got all 10000 lines assert len(lines) == 10000 # Verify content of some lines assert lines[0] == b"Line 1 of test output" assert lines[999] == b"Line 1000 of test output" assert lines[-1] == b"Line 10000 of test output" assert retcode == 0 def test_unicode_handling(): """Test handling of unicode characters.""" test_string = "Hello " output, retcode = run_interactive_command(["/bin/bash", "-c", f"echo '{test_string}'"]) assert test_string.encode() in output assert retcode == 0 def test_multiple_commands(): """Test running multiple commands in sequence.""" output, retcode = run_interactive_command(["/bin/bash", "-c", "echo 'first'; echo 'second'"]) assert b"first" in output assert b"second" in output assert retcode == 0 def test_cat_medium_file(): """Test that cat command properly captures output for medium-length files.""" # Create a temporary file with known content with tempfile.NamedTemporaryFile(mode='w', delete=False) as f: for i in range(500): f.write(f"This is test line {i}\n") temp_path = f.name try: output, retcode = run_interactive_command(["/bin/bash", "-c", f"cat {temp_path}"]) # Split by newlines and filter out script header/footer lines lines = [line for line in output.splitlines() if b"Script" not in line and line.strip()] assert len(lines) == 500 assert retcode == 0 # Verify content integrity by checking first and last lines assert b"This is test line 0" in lines[0] assert b"This is test line 499" in lines[-1] finally: os.unlink(temp_path) def test_realtime_output(): """Test that output appears in real-time and is captured correctly.""" # Create a command that sleeps briefly between outputs cmd = "echo 'first'; sleep 0.1; echo 'second'; sleep 0.1; echo 'third'" output, retcode = run_interactive_command(["/bin/bash", "-c", cmd]) # Filter out script header/footer lines lines = [line for line in output.splitlines() if b"Script" not in line and line.strip()] assert b"first" in lines[0] assert b"second" in lines[1] assert b"third" in lines[2] assert retcode == 0 def test_tty_available(): """Test that commands have access to a TTY.""" output, retcode = run_interactive_command(["/bin/bash", "-c", "tty"]) assert b"/dev/pts/" in output # Should show a PTY device assert retcode == 0