"""Integration tests for the voice pipeline."""
import pytest
class TestVoicePipeline:
"""Integration tests for voice client components working together."""
def test_import_voice_client(self):
"""voice_client.py can be imported without errors."""
import voice_client
assert hasattr(voice_client, "VoiceModeController")
assert hasattr(voice_client, "Theme")
assert hasattr(voice_client, "console")
def test_controller_init_with_mocked_deps(self, mock_tts_model, mock_onnx_model):
"""VoiceModeController initializes with mocked dependencies."""
import voice_client
from unittest.mock import patch, MagicMock
mock_provider = MagicMock()
mock_provider.type.value = "lm_studio"
mock_provider.api_url = "http://localhost:1234/v1"
mock_provider.api_key = None
mock_provider.model = "test-model"
with patch.object(
voice_client.ProviderManager, "get_best_provider", return_value=mock_provider
):
controller = voice_client.VoiceModeController(provider_config=mock_provider)
assert controller.conversation is not None
assert len(controller.conversation.history) == 0
def test_controller_conversation_manager_integration(
self, mock_tts_model, mock_onnx_model
):
"""VoiceModeController conversation property uses ConversationManager."""
import voice_client
from src.localvoicemode.state import ConversationManager
from unittest.mock import patch, MagicMock
mock_provider = MagicMock()
mock_provider.type.value = "lm_studio"
mock_provider.api_url = "http://localhost:1234/v1"
mock_provider.api_key = None
mock_provider.model = "test-model"
with patch.object(
voice_client.ProviderManager, "get_best_provider", return_value=mock_provider
):
controller = voice_client.VoiceModeController(provider_config=mock_provider)
# Verify conversation is a ConversationManager instance
assert isinstance(controller.conversation, ConversationManager)
# Add turns through ConversationManager
controller.conversation.add_turn("user", "Hello")
controller.conversation.add_turn("assistant", "Hi there!")
# Verify properties work (backward compatibility)
assert controller.last_user_text == "Hello"
assert controller.last_response == "Hi there!"
assert len(controller.conversation_history) == 2
assert controller.tokens_in > 0
assert controller.tokens_out > 0
def test_controller_conversation_clear(self, mock_tts_model, mock_onnx_model):
"""VoiceModeController conversation can be cleared."""
import voice_client
from unittest.mock import patch, MagicMock
mock_provider = MagicMock()
mock_provider.type.value = "lm_studio"
mock_provider.api_url = "http://localhost:1234/v1"
mock_provider.api_key = None
mock_provider.model = "test-model"
with patch.object(
voice_client.ProviderManager, "get_best_provider", return_value=mock_provider
):
controller = voice_client.VoiceModeController(provider_config=mock_provider)
# Add turns
controller.conversation.add_turn("user", "Hello")
controller.conversation.add_turn("assistant", "Hi!")
# Clear
controller.conversation.clear()
# Verify cleared
assert len(controller.conversation_history) == 0
assert controller.tokens_in == 0
assert controller.tokens_out == 0
assert controller.last_user_text == ""
assert controller.last_response == ""
def test_modules_are_accessible(self):
"""All extracted modules are importable."""
from src.localvoicemode.audio import AudioRecorder
from src.localvoicemode.speech import ASREngine, TTSEngine, SmartTurnVAD
from src.localvoicemode.llm import LLMClient, ProviderManager
from src.localvoicemode.skills import SkillLoader
from src.localvoicemode.state import Config, ConversationManager
# Basic sanity check
assert AudioRecorder is not None
assert ASREngine is not None
assert TTSEngine is not None
assert ConversationManager is not None
assert ProviderManager is not None
assert SkillLoader is not None
assert Config is not None
def test_modules_accessible_from_voice_client(self):
"""Modules are accessible through voice_client imports."""
import voice_client
# Check key classes are available
assert hasattr(voice_client, "AudioRecorder")
assert hasattr(voice_client, "ASREngine")
assert hasattr(voice_client, "TTSEngine")
assert hasattr(voice_client, "LLMClient")
assert hasattr(voice_client, "ProviderManager")
assert hasattr(voice_client, "ProviderConfig")
assert hasattr(voice_client, "ProviderType")
assert hasattr(voice_client, "SkillLoader")
assert hasattr(voice_client, "Skill")
assert hasattr(voice_client, "Config")
assert hasattr(voice_client, "ConversationManager")
def test_skill_loader_from_voice_client(self, temp_skill_dir, sample_skill_yaml):
"""SkillLoader loaded via voice_client can load skills."""
import voice_client
# Create test skill
skill_file = temp_skill_dir / "SKILL.md"
skill_file.write_text(sample_skill_yaml, encoding="utf-8")
# Create loader
loader = voice_client.SkillLoader(
skills_dir=temp_skill_dir.parent, voice_refs_dir=temp_skill_dir.parent
)
# List skills
skills = loader.list_skills()
assert len(skills) == 1
assert skills[0]["id"] == "test-assistant"
def test_conversation_manager_from_voice_client(self):
"""ConversationManager from voice_client works correctly."""
import voice_client
conv = voice_client.ConversationManager()
# Add turns
conv.add_turn("user", "Test message")
conv.add_turn("assistant", "Test response")
# Verify
assert conv.last_user_text == "Test message"
assert conv.last_response == "Test response"
assert len(conv.history) == 2
# Clear
conv.clear()
assert conv.is_empty
def test_config_from_voice_client(self, tmp_path):
"""Config from voice_client can be created with explicit base_dir."""
import voice_client
# Create config with explicit base dir
config = voice_client.Config.from_base_dir(tmp_path)
assert config.base_dir == tmp_path
assert config.skills_dir == tmp_path / "skills"
assert config.voice_refs_dir == tmp_path / "voice_references"