Files
voculinux/tests/test_config_manager_ext.py
T
Jatin K MalikandGitHub fd23ef0d9d feat(audio): add a family dictation tone picker (#707)
Settings → Audio can pick start/stop cues from the shared catalog
(lift, flick, ember, step, voca, soft, chirp, scale, drop, glass, off).
New installs and any missing or unknown sound_effects.tone value use
voca. A saved id, including off, is left alone.

The old start_recording/stop_recording files stay on disk. They are
no longer the implicit default. Error cues still follow the existing
enable switch.
2026-08-18 17:46:55 -07:00

308 lines
13 KiB
Python

"""
Additional coverage tests for config_manager.py module.
Tests for uncovered config manager methods.
"""
import json
import os
import sys
import tempfile
from pathlib import Path
from unittest.mock import MagicMock, patch
import pytest
# Autouse fixture to prevent sys.modules pollution
@pytest.fixture(autouse=True)
def _restore_sys_modules():
saved = dict(sys.modules)
yield
added = set(sys.modules.keys()) - set(saved.keys())
for k in added:
del sys.modules[k]
for k, v in saved.items():
if k not in sys.modules or sys.modules[k] is not v:
sys.modules[k] = v
class TestConfigManagerVoiceCommands:
"""Tests for voice commands enabled configuration."""
def test_is_voice_commands_enabled_explicit_true(self):
"""Test is_voice_commands_enabled when explicitly set to True."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(
json.dumps({"speech_recognition": {"voice_commands_enabled": True}})
)
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = json.loads(config_file.read_text())
assert manager.is_voice_commands_enabled() is True
def test_is_voice_commands_enabled_explicit_false(self):
"""Test is_voice_commands_enabled when explicitly set to False."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(
json.dumps({"speech_recognition": {"voice_commands_enabled": False}})
)
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = json.loads(config_file.read_text())
assert manager.is_voice_commands_enabled() is False
def test_is_voice_commands_enabled_auto_vosk(self):
"""Test is_voice_commands_enabled auto mode with VOSK engine."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(
json.dumps(
{"speech_recognition": {"engine": "vosk", "voice_commands_enabled": None}}
)
)
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = json.loads(config_file.read_text())
# VOSK should have voice commands enabled
assert manager.is_voice_commands_enabled() is True
def test_is_voice_commands_enabled_auto_whisper(self):
"""Test is_voice_commands_enabled auto mode with Whisper engine."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(
json.dumps(
{"speech_recognition": {"engine": "whisper", "voice_commands_enabled": None}}
)
)
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = json.loads(config_file.read_text())
# Whisper should have voice commands disabled
assert manager.is_voice_commands_enabled() is False
def test_is_voice_commands_enabled_auto_whisper_cpp(self):
"""Test is_voice_commands_enabled auto mode with whisper_cpp engine."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(
json.dumps(
{
"speech_recognition": {
"engine": "whisper_cpp",
"voice_commands_enabled": None,
}
}
)
)
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = json.loads(config_file.read_text())
# whisper_cpp should have voice commands disabled
assert manager.is_voice_commands_enabled() is False
class TestConfigManagerUpdateSettings:
"""Tests for update_speech_recognition_settings method."""
def test_update_speech_recognition_settings(self):
"""Test updating speech recognition settings."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(
json.dumps({"speech_recognition": {"engine": "vosk", "model_size": "small"}})
)
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = json.loads(config_file.read_text())
# Update settings
manager.update_speech_recognition_settings(
{"engine": "whisper_cpp", "model_size": "medium", "language": "es"}
)
assert manager.config["speech_recognition"]["engine"] == "whisper_cpp"
assert manager.config["speech_recognition"]["language"] == "es"
def test_update_speech_recognition_settings_creates_section(self):
"""Test that update creates speech_recognition section if missing."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(json.dumps({}))
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = json.loads(config_file.read_text())
manager.update_speech_recognition_settings(
{"engine": "whisper_cpp", "model_size": "small"}
)
assert "speech_recognition" in manager.config
assert manager.config["speech_recognition"]["engine"] == "whisper_cpp"
class TestConfigManagerSoundEffects:
"""Tests for sound effects configuration."""
def test_is_sound_effects_enabled_default(self):
"""Test sound effects enabled by default."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(json.dumps({}))
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = json.loads(config_file.read_text())
assert manager.is_sound_effects_enabled() is True
def test_is_sound_effects_enabled_explicit_false(self):
"""Test sound effects when explicitly disabled."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(json.dumps({"sound_effects": {"enabled": False}}))
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = json.loads(config_file.read_text())
assert manager.is_sound_effects_enabled() is False
def test_set_sound_effects_enabled(self):
"""Test setting sound effects enabled."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(json.dumps({}))
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = json.loads(config_file.read_text())
# Initially should be enabled (default)
assert manager.is_sound_effects_enabled() is True
# Disable
manager.set_sound_effects_enabled(False)
assert manager.is_sound_effects_enabled() is False
# Enable again
manager.set_sound_effects_enabled(True)
assert manager.is_sound_effects_enabled() is True
def test_set_sound_effects_creates_section(self):
"""Test that set_sound_effects_enabled creates section if missing."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(json.dumps({}))
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = json.loads(config_file.read_text())
manager.set_sound_effects_enabled(False)
assert "sound_effects" in manager.config
assert manager.config["sound_effects"]["enabled"] is False
def test_missing_tone_key_lands_on_voca(self):
from vocalinux.ui.config_manager import ConfigManager
manager = ConfigManager.__new__(ConfigManager)
manager.config = {"sound_effects": {"enabled": True}}
assert manager.get_sound_effects_tone() == "voca"
def test_unknown_tone_lands_on_voca(self):
from vocalinux.ui.config_manager import ConfigManager
manager = ConfigManager.__new__(ConfigManager)
manager.config = {"sound_effects": {"enabled": True, "tone": "fifth"}}
assert manager.get_sound_effects_tone() == "voca"
assert manager.config["sound_effects"]["tone"] == "fifth"
def test_explicit_saved_tone_is_left_alone(self):
from vocalinux.ui.config_manager import SOUND_EFFECT_TONE_IDS, ConfigManager
manager = ConfigManager.__new__(ConfigManager)
for tone_id in SOUND_EFFECT_TONE_IDS:
manager.config = {"sound_effects": {"enabled": True, "tone": tone_id}}
assert manager.get_sound_effects_tone() == tone_id
def test_set_sound_effects_tone_persists(self):
from vocalinux.ui.config_manager import ConfigManager
manager = ConfigManager.__new__(ConfigManager)
manager.config = {}
manager.set_sound_effects_tone("off")
assert manager.get_sound_effects_tone() == "off"
manager.set_sound_effects_tone("lift")
assert manager.get_sound_effects_tone() == "lift"
class TestConfigManagerUpdateDictRecursive:
"""Tests for _update_dict_recursive method."""
def test_update_dict_recursive_simple(self):
"""Test recursive dict update with simple values."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(json.dumps({}))
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = {"a": {"b": 1, "c": 2}, "d": 3}
manager._update_dict_recursive(manager.config, {"a": {"b": 10}, "d": 30})
assert manager.config["a"]["b"] == 10
assert manager.config["a"]["c"] == 2 # unchanged
assert manager.config["d"] == 30
def test_update_dict_recursive_nested(self):
"""Test recursive dict update with deeply nested dicts."""
from vocalinux.ui.config_manager import ConfigManager
with tempfile.TemporaryDirectory() as tmp_dir:
config_file = Path(tmp_dir) / "config.json"
config_file.write_text(json.dumps({}))
with patch.dict(os.environ, {"XDG_CONFIG_HOME": tmp_dir}, clear=False):
manager = ConfigManager()
manager.config = {"level1": {"level2": {"level3": "original"}}}
manager._update_dict_recursive(
manager.config, {"level1": {"level2": {"level3": "updated"}}}
)
assert manager.config["level1"]["level2"]["level3"] == "updated"