From ee2d6f4234cf40da3954a3993e93e8b225ccbcfc Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 28 Feb 2026 19:20:41 -0500 Subject: [PATCH] refactor(tests): Add strict type hints to fourth batch of test files --- tests/test_cli_tool_bridge_mapping.py | 2 +- tests/test_deepseek_infra.py | 5 +++-- tests/test_gemini_cli_integration.py | 5 +++-- tests/test_gui2_layout.py | 7 ++++--- tests/test_live_gui_integration.py | 7 ++++--- tests/test_log_pruner.py | 5 +++-- tests/test_mma_ticket_actions.py | 7 ++++--- tests/test_process_pending_gui_tasks.py | 9 ++++----- tests/test_session_logging.py | 14 ++++++++------ 9 files changed, 34 insertions(+), 27 deletions(-) diff --git a/tests/test_cli_tool_bridge_mapping.py b/tests/test_cli_tool_bridge_mapping.py index 75bb7e9..a79eb18 100644 --- a/tests/test_cli_tool_bridge_mapping.py +++ b/tests/test_cli_tool_bridge_mapping.py @@ -18,7 +18,7 @@ class TestCliToolBridgeMapping(unittest.TestCase): @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): + def test_mapping_from_api_format(self, mock_request: MagicMock, mock_stdout: MagicMock, mock_stdin: MagicMock) -> None: """ Verify that bridge correctly maps 'id', 'name', 'input' (Gemini API format) into tool_name and tool_input for the hook client. diff --git a/tests/test_deepseek_infra.py b/tests/test_deepseek_infra.py index 3ad3742..089f4f2 100644 --- a/tests/test_deepseek_infra.py +++ b/tests/test_deepseek_infra.py @@ -1,3 +1,4 @@ +from typing import Any import pytest import os import tomllib @@ -11,7 +12,7 @@ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) import ai_client import project_manager -def test_credentials_error_mentions_deepseek(monkeypatch): +def test_credentials_error_mentions_deepseek(monkeypatch: pytest.MonkeyPatch) -> None: """ Verify that the error message shown when credentials.toml is missing includes deepseek instructions. @@ -48,7 +49,7 @@ def test_deepseek_model_listing() -> None: assert "deepseek-chat" in models assert "deepseek-reasoner" in models -def test_gui_provider_list_via_hooks(live_gui): +def test_gui_provider_list_via_hooks(live_gui: Any) -> None: """ Verify 'deepseek' is present in the GUI provider list using API hooks. """ diff --git a/tests/test_gemini_cli_integration.py b/tests/test_gemini_cli_integration.py index d7b2a7b..9c829ce 100644 --- a/tests/test_gemini_cli_integration.py +++ b/tests/test_gemini_cli_integration.py @@ -1,3 +1,4 @@ +from typing import Any import pytest import time import os @@ -5,7 +6,7 @@ import sys import requests from api_hook_client import ApiHookClient -def test_gemini_cli_full_integration(live_gui): +def test_gemini_cli_full_integration(live_gui: Any) -> None: """ Integration test for the Gemini CLI provider and tool bridge. Handles 'ask_received' events from the bridge and any other approval requests. @@ -70,7 +71,7 @@ def test_gemini_cli_full_integration(live_gui): assert approved_count > 0, "No approval events were processed" assert found_final, "Final message from mock CLI was not found in the GUI history" -def test_gemini_cli_rejection_and_history(live_gui): +def test_gemini_cli_rejection_and_history(live_gui: Any) -> None: """ Integration test for the Gemini CLI provider: Rejection flow and history. """ diff --git a/tests/test_gui2_layout.py b/tests/test_gui2_layout.py index 4408c48..6fd220e 100644 --- a/tests/test_gui2_layout.py +++ b/tests/test_gui2_layout.py @@ -1,9 +1,10 @@ +from typing import Generator import pytest from unittest.mock import patch from gui_2 import App @pytest.fixture -def app_instance() -> None: +def app_instance() -> Generator[App, None, None]: with ( patch('gui_2.load_config', return_value={'gui': {'show_windows': {}}}), patch('gui_2.save_config'), @@ -17,7 +18,7 @@ def app_instance() -> None: ): yield App() -def test_gui2_hubs_exist_in_show_windows(app_instance): +def test_gui2_hubs_exist_in_show_windows(app_instance: App) -> None: """ Verifies that the new consolidated Hub windows are defined in the App's show_windows. This ensures they will be available in the 'Windows' menu. @@ -33,7 +34,7 @@ def test_gui2_hubs_exist_in_show_windows(app_instance): for hub in expected_hubs: assert hub in app_instance.show_windows, f"Expected hub window '{hub}' not found in show_windows" -def test_gui2_old_windows_removed_from_show_windows(app_instance): +def test_gui2_old_windows_removed_from_show_windows(app_instance: App) -> None: """ Verifies that the old fragmented windows are removed from show_windows. """ diff --git a/tests/test_live_gui_integration.py b/tests/test_live_gui_integration.py index fc903b3..c750376 100644 --- a/tests/test_live_gui_integration.py +++ b/tests/test_live_gui_integration.py @@ -1,3 +1,4 @@ +from typing import Generator import pytest from unittest.mock import MagicMock, patch, AsyncMock import asyncio @@ -7,7 +8,7 @@ from events import UserRequestEvent import ai_client @pytest.fixture -def mock_app() -> None: +def mock_app() -> Generator[App, None, None]: with ( patch('gui_2.load_config', return_value={ "ai": {"provider": "gemini", "model": "model-1", "temperature": 0.0, "max_tokens": 100, "history_trunc_limit": 1000}, @@ -33,7 +34,7 @@ def mock_app() -> None: # so we just let it daemon-exit. @pytest.mark.timeout(10) -def test_user_request_integration_flow(mock_app): +def test_user_request_integration_flow(mock_app: App) -> None: """ Verifies that pushing a UserRequestEvent to the event_queue: 1. Triggers ai_client.send @@ -83,7 +84,7 @@ def test_user_request_integration_flow(mock_app): assert app.ai_status == "done" @pytest.mark.timeout(10) -def test_user_request_error_handling(mock_app): +def test_user_request_error_handling(mock_app: App) -> None: """ Verifies that if ai_client.send raises an exception, the UI is updated with the error state. """ diff --git a/tests/test_log_pruner.py b/tests/test_log_pruner.py index 7d7bcf5..b36fda2 100644 --- a/tests/test_log_pruner.py +++ b/tests/test_log_pruner.py @@ -1,3 +1,4 @@ +from typing import Tuple import os import shutil import pytest @@ -7,7 +8,7 @@ from log_registry import LogRegistry from log_pruner import LogPruner @pytest.fixture -def pruner_setup(tmp_path): +def pruner_setup(tmp_path: Path) -> Tuple[LogPruner, LogRegistry, Path]: logs_dir = tmp_path / "logs" logs_dir.mkdir() registry_path = logs_dir / "log_registry.toml" @@ -15,7 +16,7 @@ def pruner_setup(tmp_path): pruner = LogPruner(registry, str(logs_dir)) return pruner, registry, logs_dir -def test_prune_old_insignificant_logs(pruner_setup): +def test_prune_old_insignificant_logs(pruner_setup: Tuple[LogPruner, LogRegistry, Path]) -> None: pruner, registry, logs_dir = pruner_setup # 1. Old and small (insignificant) -> should be pruned session_id_old_small = "old_small" diff --git a/tests/test_mma_ticket_actions.py b/tests/test_mma_ticket_actions.py index 61fdac4..2886acf 100644 --- a/tests/test_mma_ticket_actions.py +++ b/tests/test_mma_ticket_actions.py @@ -1,10 +1,11 @@ +from typing import Generator import pytest from unittest.mock import patch, MagicMock import asyncio from gui_2 import App @pytest.fixture -def app_instance() -> None: +def app_instance() -> Generator[App, None, None]: with ( patch('gui_2.load_config', return_value={'ai': {}, 'projects': {}}), patch('gui_2.save_config'), @@ -21,7 +22,7 @@ def app_instance() -> None: app._loop = MagicMock() yield app -def test_cb_ticket_retry(app_instance): +def test_cb_ticket_retry(app_instance: App) -> None: ticket_id = "test_ticket_1" app_instance.active_tickets = [{"id": ticket_id, "status": "failed"}] with patch('asyncio.run_coroutine_threadsafe') as mock_run_safe: @@ -34,7 +35,7 @@ def test_cb_ticket_retry(app_instance): args, _ = mock_run_safe.call_args assert args[1] == app_instance._loop -def test_cb_ticket_skip(app_instance): +def test_cb_ticket_skip(app_instance: App) -> None: ticket_id = "test_ticket_1" app_instance.active_tickets = [{"id": ticket_id, "status": "todo"}] with patch('asyncio.run_coroutine_threadsafe') as mock_run_safe: diff --git a/tests/test_process_pending_gui_tasks.py b/tests/test_process_pending_gui_tasks.py index f0021fb..ed6c159 100644 --- a/tests/test_process_pending_gui_tasks.py +++ b/tests/test_process_pending_gui_tasks.py @@ -1,10 +1,11 @@ +from typing import Generator import pytest from unittest.mock import MagicMock, patch import ai_client from gui_2 import App @pytest.fixture -def app_instance() -> None: +def app_instance() -> Generator[App, None, None]: with ( patch('gui_2.load_config', return_value={'ai': {'provider': 'gemini', 'model': 'gemini-2.5-flash-lite'}, 'projects': {}}), patch('gui_2.save_config'), @@ -21,8 +22,7 @@ def app_instance() -> None: app = App() yield app -def test_redundant_calls_in_process_pending_gui_tasks(app_instance): -# Setup +def test_redundant_calls_in_process_pending_gui_tasks(app_instance: App) -> None: app_instance._pending_gui_tasks = [ {'action': 'set_value', 'item': 'current_provider', 'value': 'anthropic'} ] @@ -40,8 +40,7 @@ def test_redundant_calls_in_process_pending_gui_tasks(app_instance): assert mock_set_provider.call_count == 1 assert mock_reset_session.call_count == 1 -def test_gcli_path_updates_adapter(app_instance): -# Setup +def test_gcli_path_updates_adapter(app_instance: App) -> None: app_instance.current_provider = 'gemini_cli' app_instance._pending_gui_tasks = [ {'action': 'set_value', 'item': 'gcli_path', 'value': '/new/path/to/gemini'} diff --git a/tests/test_session_logging.py b/tests/test_session_logging.py index 626cfca..f23bff9 100644 --- a/tests/test_session_logging.py +++ b/tests/test_session_logging.py @@ -1,15 +1,16 @@ -import os -import shutil import pytest +import shutil +import os +import tomllib from pathlib import Path from datetime import datetime from unittest.mock import patch +from typing import Generator import session_logger -import tomllib @pytest.fixture -def temp_logs(tmp_path, monkeypatch): -# Ensure closed before starting +def temp_logs(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Generator[Path, None, None]: + # Ensure closed before starting session_logger.close_session() monkeypatch.setattr(session_logger, "_comms_fh", None) # Mock _LOG_DIR in session_logger @@ -28,7 +29,8 @@ def temp_logs(tmp_path, monkeypatch): session_logger._LOG_DIR = original_log_dir session_logger._SCRIPTS_DIR = original_scripts_dir -def test_open_session_creates_subdir_and_registry(temp_logs): +def test_open_session_creates_subdir_and_registry(temp_logs: Path) -> None: + label = "test-label" # We can't easily mock datetime.datetime.now() because it's a built-in # but we can check the resulting directory name pattern