import unittest from unittest.mock import patch, MagicMock import io import json import sys import os # Add project root to sys.path sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) # Import after path fix from scripts.cli_tool_bridge import main class TestCliToolBridgeMapping(unittest.TestCase): def setUp(self): os.environ['GEMINI_CLI_HOOK_CONTEXT'] = 'manual_slop' @patch('sys.stdin', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) @patch('api_hook_client.ApiHookClient.request_confirmation') def test_mapping_from_api_format(self, mock_request, mock_stdout, mock_stdin): """ Verify that bridge correctly maps 'id', 'name', 'input' (Gemini API format) into tool_name and tool_input for the hook client. """ api_tool_call = { 'id': 'call123', 'name': 'read_file', 'input': {'path': 'test.txt'} } # 1. Mock stdin with the API format JSON mock_stdin.write(json.dumps(api_tool_call)) mock_stdin.seek(0) # 2. Mock ApiHookClient to return approved mock_request.return_value = {'approved': True} # Run main main() # 3. Verify that request_confirmation was called with mapped values # If it's not mapped, it will likely be called with None or fail mock_request.assert_called_once_with('read_file', {'path': 'test.txt'}) # 4. Capture stdout and assert allow output_str = mock_stdout.getvalue().strip() self.assertTrue(output_str, "Stdout should not be empty") output = json.loads(output_str) self.assertEqual(output.get('decision'), 'allow') if __name__ == '__main__': unittest.main()