Files
voculinux/tests/test_resource_manager.py
T
Jatin K MalikandGitHub 9e5b632710 test: Improve test coverage to 80%+ (#122)
* test: Improve test coverage to 80%

Increased test coverage from ~33% to 80.15% statement coverage.

New test files added:
- test_action_handler.py (100% coverage)
- test_version.py (100% coverage)
- test_logging_manager.py (100% coverage)
- test_common_types.py
- test_speech_recognition_init.py (100% coverage)
- test_resource_manager.py (93% coverage)

Significantly expanded existing tests:
- test_tray_indicator.py: 76% -> 98%
- test_main.py: 50% -> 92%
- test_text_injector.py: 60% -> 94%
- test_recognition_manager.py: 30% -> 48%
- test_command_processor.py: 85% -> 98%
- test_keyboard_shortcuts.py: 88% -> 95%
- test_config_manager.py: improved to 98%
- test_audio_feedback.py: improved to 92%

Configuration changes:
- Updated pyproject.toml to exclude untestable GTK dialog files
  (settings_dialog.py, logging_dialog.py) from coverage metrics

Key testing improvements:
- Added comprehensive GTK mocking for UI components
- Added edge case tests for text injection on X11/Wayland
- Added keyboard shortcut injection tests
- Added error handling and callback tests
- Added configuration management tests

* fix: Use runtime CI mode detection to fix Python 3.8/3.10 tests

Change CI_MODE from module-level constant to _is_ci_mode() function
that is evaluated at runtime. This ensures pytest detection works
correctly on all Python versions, since pytest modules may not be
loaded at import time.

* fix: Add PYTEST_RUNNING env var for reliable pytest detection in CI

The previous approach to detect pytest at runtime wasn't working
reliably on Python 3.8/3.10 in CI environments. This adds a
PYTEST_RUNNING=1 environment variable set early in conftest.py
that _is_ci_mode() can check to reliably determine if tests are
running.

* fix: Use patch.object for reliable mocking in audio_feedback tests

The previous approach using patch() with module paths didn't work
reliably because the module reimport caused the patched objects
to not be the same as the ones the functions referenced.

Using patch.object() on the imported module's attributes ensures
the patches are applied to the actual objects the functions use.

* fix: Use patch.object for reliable mocking in test_settings_callback

The test was failing on Python 3.8/3.10 because the module-level patch
for SettingsDialog wasn't being applied reliably across all Python
versions due to import timing differences.

Using patch.object() on the imported module ensures the mock is applied
to the actual reference that _on_settings_clicked() uses, regardless of
Python version or module caching behavior.
2026-02-04 21:01:34 -08:00

106 lines
3.6 KiB
Python

"""
Tests for the resource_manager module.
"""
import os
import sys
import unittest
from pathlib import Path
from unittest.mock import MagicMock, patch
from vocalinux.utils.resource_manager import ResourceManager
class TestResourceManager(unittest.TestCase):
"""Tests for ResourceManager class."""
def test_initialization(self):
"""Test ResourceManager initializes properly."""
manager = ResourceManager()
self.assertIsNotNone(manager.resources_dir)
self.assertIsNotNone(manager.icons_dir)
self.assertIsNotNone(manager.sounds_dir)
def test_icons_dir_property(self):
"""Test icons_dir returns correct path."""
manager = ResourceManager()
self.assertIn("icons", manager.icons_dir)
self.assertIn("scalable", manager.icons_dir)
def test_sounds_dir_property(self):
"""Test sounds_dir returns correct path."""
manager = ResourceManager()
self.assertIn("sounds", manager.sounds_dir)
def test_get_icon_path(self):
"""Test get_icon_path returns correct path."""
manager = ResourceManager()
path = manager.get_icon_path("test-icon")
self.assertTrue(path.endswith("test-icon.svg"))
def test_get_sound_path(self):
"""Test get_sound_path returns correct path."""
manager = ResourceManager()
path = manager.get_sound_path("test-sound")
self.assertTrue(path.endswith("test-sound.wav"))
def test_ensure_directories_exist(self):
"""Test ensure_directories_exist creates directories."""
manager = ResourceManager()
with patch("os.makedirs") as mock_makedirs:
manager.ensure_directories_exist()
self.assertEqual(mock_makedirs.call_count, 2)
def test_validate_resources(self):
"""Test validate_resources returns proper structure."""
manager = ResourceManager()
with patch("os.path.exists", return_value=True):
results = manager.validate_resources()
self.assertIn("resources_dir_exists", results)
self.assertIn("icons_dir_exists", results)
self.assertIn("sounds_dir_exists", results)
self.assertIn("missing_icons", results)
self.assertIn("missing_sounds", results)
def test_validate_resources_missing_icons(self):
"""Test validate_resources detects missing icons."""
manager = ResourceManager()
with patch("os.path.exists", return_value=False):
results = manager.validate_resources()
self.assertFalse(results["resources_dir_exists"])
self.assertTrue(len(results["missing_icons"]) > 0)
def test_validate_resources_missing_sounds(self):
"""Test validate_resources detects missing sounds."""
manager = ResourceManager()
with patch("os.path.exists", return_value=False):
results = manager.validate_resources()
self.assertTrue(len(results["missing_sounds"]) > 0)
def test_find_resources_dir_no_candidates_exist(self):
"""Test _find_resources_dir when no candidates exist."""
# Need to patch at the module level before instantiation
original_exists = Path.exists
def mock_exists(self):
# Return False for all resources paths
path_str = str(self)
if "resources" in path_str:
return False
return original_exists(self)
with patch.object(Path, "exists", mock_exists):
manager = ResourceManager()
# Should default to first candidate with warning
self.assertIsNotNone(manager.resources_dir)
if __name__ == "__main__":
unittest.main()