refactor(tests): Add strict type hints to fourth batch of test files

This commit is contained in:
2026-02-28 19:20:41 -05:00
parent e8513d563b
commit ee2d6f4234
9 changed files with 34 additions and 27 deletions

View File

@@ -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.

View File

@@ -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.
"""

View File

@@ -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.
"""

View File

@@ -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.
"""

View File

@@ -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.
"""

View File

@@ -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"

View File

@@ -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:

View File

@@ -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'}

View File

@@ -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