"""Unit tests for VoiceMode state machine."""
import pytest
from src.localvoicemode.state.voice_mode import VoiceMode, ModeStateMachine
class TestVoiceMode:
"""Tests for VoiceMode enum."""
def test_enum_values(self):
"""Verify all four modes exist with correct values."""
assert VoiceMode.FULL_VOICE.value == "full_voice"
assert VoiceMode.TTS_ONLY.value == "tts_only"
assert VoiceMode.STT_ONLY.value == "stt_only"
assert VoiceMode.SILENT.value == "silent"
def test_enum_from_string(self):
"""Can create enum from string value."""
assert VoiceMode("full_voice") == VoiceMode.FULL_VOICE
assert VoiceMode("tts_only") == VoiceMode.TTS_ONLY
def test_enum_count(self):
"""Exactly four modes exist."""
assert len(VoiceMode) == 4
class TestModeStateMachine:
"""Tests for ModeStateMachine."""
@pytest.fixture
def machine(self):
"""Fresh state machine for each test."""
return ModeStateMachine()
def test_initial_state_is_full_voice(self, machine):
"""Default mode is FULL_VOICE."""
assert machine.current_state.id == "full_voice"
assert machine.mode == VoiceMode.FULL_VOICE
assert machine.mode_name == "full_voice"
def test_initial_component_flags(self, machine):
"""FULL_VOICE enables both STT and TTS."""
assert machine.stt_enabled is True
assert machine.tts_enabled is True
# Transition tests
def test_transition_to_tts_only(self, machine):
"""Can transition to TTS_ONLY mode."""
machine.set_tts_only()
assert machine.mode == VoiceMode.TTS_ONLY
assert machine.stt_enabled is False
assert machine.tts_enabled is True
def test_transition_to_stt_only(self, machine):
"""Can transition to STT_ONLY mode."""
machine.set_stt_only()
assert machine.mode == VoiceMode.STT_ONLY
assert machine.stt_enabled is True
assert machine.tts_enabled is False
def test_transition_to_silent(self, machine):
"""Can transition to SILENT mode."""
machine.set_silent()
assert machine.mode == VoiceMode.SILENT
assert machine.stt_enabled is False
assert machine.tts_enabled is False
def test_transition_back_to_full_voice(self, machine):
"""Can return to FULL_VOICE from any mode."""
machine.set_silent()
machine.set_full_voice()
assert machine.mode == VoiceMode.FULL_VOICE
assert machine.stt_enabled is True
assert machine.tts_enabled is True
# Idempotent transitions
def test_idempotent_full_voice(self, machine):
"""set_full_voice when already in full_voice succeeds."""
machine.set_full_voice() # Should not raise
assert machine.mode == VoiceMode.FULL_VOICE
def test_idempotent_tts_only(self, machine):
"""set_tts_only when already in tts_only succeeds."""
machine.set_tts_only()
machine.set_tts_only() # Should not raise
assert machine.mode == VoiceMode.TTS_ONLY
def test_idempotent_stt_only(self, machine):
"""set_stt_only when already in stt_only succeeds."""
machine.set_stt_only()
machine.set_stt_only() # Should not raise
assert machine.mode == VoiceMode.STT_ONLY
def test_idempotent_silent(self, machine):
"""set_silent when already in silent succeeds."""
machine.set_silent()
machine.set_silent() # Should not raise
assert machine.mode == VoiceMode.SILENT
# All-to-all transitions
def test_tts_only_to_stt_only(self, machine):
"""Can transition directly from TTS_ONLY to STT_ONLY."""
machine.set_tts_only()
machine.set_stt_only()
assert machine.mode == VoiceMode.STT_ONLY
def test_stt_only_to_tts_only(self, machine):
"""Can transition directly from STT_ONLY to TTS_ONLY."""
machine.set_stt_only()
machine.set_tts_only()
assert machine.mode == VoiceMode.TTS_ONLY
def test_silent_to_tts_only(self, machine):
"""Can transition from SILENT to TTS_ONLY."""
machine.set_silent()
machine.set_tts_only()
assert machine.mode == VoiceMode.TTS_ONLY
def test_silent_to_stt_only(self, machine):
"""Can transition from SILENT to STT_ONLY."""
machine.set_silent()
machine.set_stt_only()
assert machine.mode == VoiceMode.STT_ONLY
# Component flag matrix
@pytest.mark.parametrize("mode,stt,tts", [
("full_voice", True, True),
("tts_only", False, True),
("stt_only", True, False),
("silent", False, False),
])
def test_component_flags_matrix(self, mode, stt, tts):
"""Verify component flags for each mode."""
machine = ModeStateMachine()
getattr(machine, f"set_{mode}")()
assert machine.stt_enabled == stt
assert machine.tts_enabled == tts
# Mode property returns correct enum
@pytest.mark.parametrize("event,expected_mode", [
("set_full_voice", VoiceMode.FULL_VOICE),
("set_tts_only", VoiceMode.TTS_ONLY),
("set_stt_only", VoiceMode.STT_ONLY),
("set_silent", VoiceMode.SILENT),
])
def test_mode_property_returns_enum(self, event, expected_mode):
"""Mode property returns correct VoiceMode enum."""
machine = ModeStateMachine()
getattr(machine, event)()
assert machine.mode == expected_mode
assert isinstance(machine.mode, VoiceMode)