"""Tests for Windows-specific functionality.""" import os import sys import subprocess import pytest from unittest.mock import patch, MagicMock from ra_aid.proc.interactive import get_terminal_size, create_process, run_interactive_command @pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific tests") class TestWindowsCompatibility: """Test suite for Windows-specific functionality.""" def test_get_terminal_size(self): """Test terminal size detection on Windows.""" with patch('shutil.get_terminal_size') as mock_get_size: mock_get_size.return_value = MagicMock(columns=120, lines=30) cols, rows = get_terminal_size() assert cols == 120 assert rows == 30 mock_get_size.assert_called_once() def test_create_process(self): """Test process creation on Windows.""" with patch('subprocess.Popen') as mock_popen: mock_process = MagicMock() mock_process.returncode = 0 mock_popen.return_value = mock_process proc, _ = create_process(['echo', 'test']) assert mock_popen.called args, kwargs = mock_popen.call_args assert kwargs['stdin'] == subprocess.PIPE assert kwargs['stdout'] == subprocess.PIPE assert kwargs['stderr'] == subprocess.STDOUT assert 'startupinfo' in kwargs assert kwargs['startupinfo'].dwFlags & subprocess.STARTF_USESHOWWINDOW def test_run_interactive_command(self): """Test running an interactive command on Windows.""" test_output = "Test output\n" with patch('subprocess.Popen') as mock_popen, \ patch('pyte.Stream') as mock_stream, \ patch('pyte.HistoryScreen') as mock_screen, \ patch('threading.Thread') as mock_thread: # Setup mock process mock_process = MagicMock() mock_process.stdout = MagicMock() mock_process.stdout.read.return_value = test_output.encode() mock_process.poll.side_effect = [None, 0] # First None, then return 0 mock_process.returncode = 0 mock_popen.return_value = mock_process # Setup mock screen with history mock_screen_instance = MagicMock() mock_screen_instance.history.top = [] mock_screen_instance.history.bottom = [] mock_screen_instance.display = ["Test output"] mock_screen.return_value = mock_screen_instance # Setup mock thread mock_thread_instance = MagicMock() mock_thread.return_value = mock_thread_instance # Run the command output, return_code = run_interactive_command(['echo', 'test']) # Verify results assert return_code == 0 assert "Test output" in output.decode() # Verify the thread was started and joined mock_thread_instance.start.assert_called() mock_thread_instance.join.assert_called() def test_windows_dependencies(self): """Test that required Windows dependencies are available.""" if sys.platform == "win32": import msvcrt # If we get here without ImportError, the test passes assert True def test_windows_output_handling(self): """Test handling of multi-chunk output on Windows.""" if sys.platform != "win32": pytest.skip("Windows-specific test") # Test with multiple chunks of output to verify proper handling with patch('subprocess.Popen') as mock_popen, \ patch('msvcrt.kbhit', return_value=False), \ patch('threading.Thread') as mock_thread, \ patch('time.sleep'): # Mock sleep to speed up test # Setup mock process mock_process = MagicMock() mock_process.stdout = MagicMock() mock_process.poll.return_value = 0 mock_process.returncode = 0 mock_popen.return_value = mock_process # Setup mock thread to simulate output collection def side_effect(*args, **kwargs): # Simulate thread collecting output mock_process.stdout.read.side_effect = [ b"First chunk\n", b"Second chunk\n", b"Third chunk with unicode \xe2\x9c\x93\n", # UTF-8 checkmark None # End of output ] return MagicMock() mock_thread.side_effect = side_effect # Run the command output, return_code = run_interactive_command(['test', 'command']) # Verify results assert return_code == 0 # We can't verify exact output content in this test since we're mocking the thread # that would collect the output, but we can verify the process was created correctly assert mock_popen.called