import sys import os import json import subprocess from unittest.mock import patch, MagicMock from src import ai_client def test_gemini_cli_full_integration() -> None: """Integration test for the Gemini CLI provider and tool bridge.""" from src import ai_client # 1. Setup mock response with a tool call tool_call_json = { "kind": "tool_use", "payload": { "id": "call_123", "name": "read_file", "input": {"path": "test.txt"} } } # 2. Setup mock final response final_resp_json = { "kind": "message", "payload": "Final integrated answer" } # 3. Mock subprocess.Popen mock_process = MagicMock() mock_process.stdout = [ (json.dumps(tool_call_json) + "\n").encode('utf-8'), (json.dumps(final_resp_json) + "\n").encode('utf-8') ] mock_process.stderr = [] mock_process.returncode = 0 with patch('subprocess.Popen', return_value=mock_process), \ patch('src.mcp_client.dispatch', return_value="file content") as mock_dispatch: ai_client.set_provider("gemini_cli", "gemini-2.0-flash") result = ai_client.send("context", "integrated test") assert result == "Final integrated answer" assert mock_dispatch.called mock_dispatch.assert_called_with("read_file", {"path": "test.txt"}) def test_gemini_cli_rejection_and_history() -> None: """Integration test for the Gemini CLI provider: Rejection flow and history.""" from src import ai_client # Tool call tool_call_json = { "kind": "tool_use", "payload": {"id": "c1", "name": "run_powershell", "input": {"script": "dir"}} } mock_process = MagicMock() mock_process.stdout = [(json.dumps(tool_call_json) + "\n").encode('utf-8')] mock_process.stderr = [] mock_process.returncode = 0 with patch('subprocess.Popen', return_value=mock_process): ai_client.set_provider("gemini_cli", "gemini-2.0-flash") # Simulate rejection def pre_tool_cb(*args, **kwargs): return None # Reject result = ai_client.send("ctx", "msg", pre_tool_callback=pre_tool_cb) # In current impl, if rejected, it returns the accumulated text so far # or a message about rejection. assert "REJECTED" in result or result == ""