1 parent
4a0695ab57
commit
9b2a8b4b30
24 files changed
+3002
-24
No files matched your search
@@ -0,0 +1,273 @@
|
||||
"""Unit tests for shared models."""
|
||||
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.unit.conftest import make_state as make_server_state
|
||||
|
||||
|
||||
def make_preferences(**kwargs):
|
||||
from linux_voice_assistant.models import Preferences
|
||||
|
||||
return Preferences(**kwargs)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# WakeWordType
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestWakeWordType:
|
||||
def test_micro_value(self):
|
||||
from linux_voice_assistant.models import WakeWordType
|
||||
|
||||
assert WakeWordType.MICRO_WAKE_WORD == "micro"
|
||||
|
||||
def test_open_wake_word_value(self):
|
||||
from linux_voice_assistant.models import WakeWordType
|
||||
|
||||
assert WakeWordType.OPEN_WAKE_WORD == "openWakeWord"
|
||||
|
||||
def test_is_string_enum(self):
|
||||
from linux_voice_assistant.models import WakeWordType
|
||||
|
||||
assert isinstance(WakeWordType.MICRO_WAKE_WORD, str)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Preferences
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestPreferences:
|
||||
def test_default_active_wake_words_is_empty_list(self):
|
||||
p = make_preferences()
|
||||
assert p.active_wake_words == []
|
||||
|
||||
def test_default_volume_is_none(self):
|
||||
p = make_preferences()
|
||||
assert p.volume is None
|
||||
|
||||
def test_default_thinking_sound_is_zero(self):
|
||||
p = make_preferences()
|
||||
assert p.thinking_sound == 0
|
||||
|
||||
def test_default_mic_auto_gain_is_zero(self):
|
||||
p = make_preferences()
|
||||
assert p.mic_auto_gain == 0
|
||||
|
||||
def test_default_mic_noise_suppression_is_zero(self):
|
||||
p = make_preferences()
|
||||
assert p.mic_noise_suppression == 0
|
||||
|
||||
def test_custom_values_stored(self):
|
||||
p = make_preferences(
|
||||
volume=0.8,
|
||||
mic_auto_gain=5,
|
||||
mic_noise_suppression=2,
|
||||
thinking_sound=1,
|
||||
)
|
||||
assert p.volume == 0.8
|
||||
assert p.mic_auto_gain == 5
|
||||
assert p.mic_noise_suppression == 2
|
||||
assert p.thinking_sound == 1
|
||||
|
||||
def test_active_wake_words_are_independent_per_instance(self):
|
||||
"""Mutable default must not be shared between instances."""
|
||||
p1 = make_preferences()
|
||||
p2 = make_preferences()
|
||||
p1.active_wake_words.append("okay_nabu")
|
||||
assert p2.active_wake_words == []
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ServerState.save_preferences()
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestSavePreferences:
|
||||
def test_creates_preferences_file(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.save_preferences()
|
||||
assert state.preferences_path.exists()
|
||||
|
||||
def test_saved_json_is_valid(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.save_preferences()
|
||||
with open(state.preferences_path) as f:
|
||||
data = json.load(f)
|
||||
assert isinstance(data, dict)
|
||||
|
||||
def test_saved_json_contains_expected_keys(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.save_preferences()
|
||||
with open(state.preferences_path) as f:
|
||||
data = json.load(f)
|
||||
assert "mic_auto_gain" in data
|
||||
assert "mic_noise_suppression" in data
|
||||
assert "volume" in data
|
||||
assert "thinking_sound" in data
|
||||
|
||||
def test_saved_values_match_preferences(self, tmp_path):
|
||||
from linux_voice_assistant.models import Preferences
|
||||
|
||||
prefs = Preferences(volume=0.75, mic_auto_gain=3, mic_noise_suppression=1)
|
||||
state = make_server_state(tmp_path, preferences=prefs)
|
||||
state.save_preferences()
|
||||
with open(state.preferences_path) as f:
|
||||
data = json.load(f)
|
||||
assert data["volume"] == 0.75
|
||||
assert data["mic_auto_gain"] == 3
|
||||
assert data["mic_noise_suppression"] == 1
|
||||
|
||||
def test_creates_parent_directory_if_missing(self, tmp_path):
|
||||
nested_path = tmp_path / "nested" / "dir" / "preferences.json"
|
||||
state = make_server_state(tmp_path, preferences_path=nested_path)
|
||||
state.save_preferences()
|
||||
assert nested_path.exists()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ServerState.persist_volume()
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestPersistVolume:
|
||||
def test_updates_volume_on_state(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_volume(0.5)
|
||||
assert state.volume == 0.5
|
||||
|
||||
def test_updates_volume_on_preferences(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_volume(0.5)
|
||||
assert state.preferences.volume == 0.5
|
||||
|
||||
def test_clamps_above_one(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_volume(1.5)
|
||||
assert state.volume == 1.0
|
||||
|
||||
def test_clamps_below_zero(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_volume(-0.5)
|
||||
assert state.volume == 0.0
|
||||
|
||||
def test_saves_to_file(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_volume(0.6)
|
||||
with open(state.preferences_path) as f:
|
||||
data = json.load(f)
|
||||
assert data["volume"] == pytest.approx(0.6)
|
||||
|
||||
def test_skips_save_when_volume_unchanged(self, tmp_path):
|
||||
from linux_voice_assistant.models import Preferences
|
||||
|
||||
prefs = Preferences(volume=0.5)
|
||||
state = make_server_state(tmp_path, preferences=prefs, volume=0.5)
|
||||
|
||||
with patch.object(state, "save_preferences") as mock_save:
|
||||
state.persist_volume(0.5)
|
||||
mock_save.assert_not_called()
|
||||
|
||||
def test_saves_when_volume_changed(self, tmp_path):
|
||||
from linux_voice_assistant.models import Preferences
|
||||
|
||||
prefs = Preferences(volume=0.5)
|
||||
state = make_server_state(tmp_path, preferences=prefs, volume=0.5)
|
||||
|
||||
with patch.object(state, "save_preferences") as mock_save:
|
||||
state.persist_volume(0.8)
|
||||
mock_save.assert_called_once()
|
||||
|
||||
def test_boundary_value_zero(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_volume(0.0)
|
||||
assert state.volume == 0.0
|
||||
|
||||
def test_boundary_value_one(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_volume(1.0)
|
||||
assert state.volume == 1.0
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ServerState.persist_mic_gain()
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestPersistMicGain:
|
||||
def test_updates_mic_auto_gain_on_state(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_mic_gain(5.0)
|
||||
assert state.mic_auto_gain == 5
|
||||
|
||||
def test_updates_mic_auto_gain_on_preferences(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_mic_gain(5.0)
|
||||
assert state.preferences.mic_auto_gain == 5
|
||||
|
||||
def test_converts_float_to_int(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_mic_gain(7.9)
|
||||
assert state.mic_auto_gain == 7
|
||||
|
||||
def test_skips_save_when_gain_unchanged(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.mic_auto_gain = 3
|
||||
state.preferences.mic_auto_gain = 3
|
||||
|
||||
with patch.object(state, "save_preferences") as mock_save:
|
||||
state.persist_mic_gain(3.0)
|
||||
mock_save.assert_not_called()
|
||||
|
||||
def test_saves_when_gain_changed(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.mic_auto_gain = 3
|
||||
state.preferences.mic_auto_gain = 3
|
||||
|
||||
with patch.object(state, "save_preferences") as mock_save:
|
||||
state.persist_mic_gain(10.0)
|
||||
mock_save.assert_called_once()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ServerState.persist_mic_noise()
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestPersistMicNoise:
|
||||
def test_updates_mic_noise_suppression_on_state(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_mic_noise(2.0)
|
||||
assert state.mic_noise_suppression == 2
|
||||
|
||||
def test_updates_mic_noise_suppression_on_preferences(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_mic_noise(2.0)
|
||||
assert state.preferences.mic_noise_suppression == 2
|
||||
|
||||
def test_converts_float_to_int(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.persist_mic_noise(3.9)
|
||||
assert state.mic_noise_suppression == 3
|
||||
|
||||
def test_skips_save_when_noise_unchanged(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.mic_noise_suppression = 2
|
||||
state.preferences.mic_noise_suppression = 2
|
||||
|
||||
with patch.object(state, "save_preferences") as mock_save:
|
||||
state.persist_mic_noise(2.0)
|
||||
mock_save.assert_not_called()
|
||||
|
||||
def test_saves_when_noise_changed(self, tmp_path):
|
||||
state = make_server_state(tmp_path)
|
||||
state.mic_noise_suppression = 2
|
||||
state.preferences.mic_noise_suppression = 2
|
||||
|
||||
with patch.object(state, "save_preferences") as mock_save:
|
||||
state.persist_mic_noise(4.0)
|
||||
mock_save.assert_called_once()
|
||||
Reference in new issue
Block a user