# -*- coding: utf-8 -*- """ Unit-Tests für trixy_core.config. """ import json import pytest from dataclasses import dataclass from pathlib import Path from trixy_core.config.config_manager import ConfigManager from trixy_core.config.datasets.server import ( ServerConfig, NetworkConfig, SecurityConfig, AudioConfig, WakewordConfig, PluginConfig ) from trixy_core.config.datasets.client import ( ClientConfig, ServerConnectionConfig, ClientAudioConfig, SatelliteIdentityConfig ) from trixy_core.config.datasets.standalone import StandaloneConfig from trixy_core.config.datasets.trainer import ( TrainerConfig, WakewordTrainerConfig, VoiceRecognitionTrainerConfig, DataConfig ) class TestServerConfig: """Tests für Server-Konfiguration.""" def test_default_network_config(self): """Testet die Standard-Netzwerk-Konfiguration.""" config = NetworkConfig() assert config.command_port == 2101 assert config.audio_input_port == 2102 assert config.audio_output_port == 2103 assert config.music_port == 2104 assert config.bind_address == "0.0.0.0" assert config.max_connections == 100 def test_default_security_config(self): """Testet die Standard-Sicherheits-Konfiguration.""" config = SecurityConfig() assert config.encryption_enabled is True assert config.ssl_enabled is False assert config.allowed_mac_addresses == [] def test_default_audio_config(self): """Testet die Standard-Audio-Konfiguration.""" config = AudioConfig() assert config.sample_rate == 16000 assert config.channels == 1 assert config.bit_depth == 16 assert config.music_sample_rate == 44100 # Standard für die meisten Geräte assert config.music_channels == 2 def test_default_wakeword_config(self): """Testet die Standard-Wakeword-Konfiguration.""" config = WakewordConfig() assert config.models == ["custom", "system_command"] assert config.threshold == 0.5 assert config.debounce_seconds == 1.0 def test_default_server_config(self): """Testet die Standard-Server-Konfiguration.""" config = ServerConfig() assert isinstance(config.network, NetworkConfig) assert isinstance(config.security, SecurityConfig) assert config.profile == "default" class TestClientConfig: """Tests für Client-Konfiguration.""" def test_default_server_connection(self): """Testet die Standard-Server-Verbindung.""" config = ServerConnectionConfig() assert config.host == "localhost" assert config.port == 2101 assert config.reconnect_interval_seconds == 5.0 def test_default_client_audio(self): """Testet die Standard-Client-Audio-Konfiguration.""" config = ClientAudioConfig() assert config.sample_rate == 16000 assert config.input_device is None assert config.output_device is None def test_default_identity(self): """Testet die Standard-Identität.""" config = SatelliteIdentityConfig() assert config.room == "" assert config.alias == "" assert config.mac_address == "" def test_default_client_config(self): """Testet die Standard-Client-Konfiguration.""" config = ClientConfig() assert isinstance(config.server, ServerConnectionConfig) assert isinstance(config.identity, SatelliteIdentityConfig) class TestStandaloneConfig: """Tests für Standalone-Konfiguration.""" def test_default_standalone_config(self): """Testet die Standard-Standalone-Konfiguration.""" config = StandaloneConfig() assert config.room == "standalone" assert config.alias == "Trixy" assert config.profile == "default" class TestTrainerConfig: """Tests für Trainer-Konfiguration.""" def test_default_wakeword_trainer(self): """Testet die Standard-Wakeword-Trainer-Konfiguration.""" config = WakewordTrainerConfig() assert config.model_name == "custom" assert config.epochs == 100 assert config.batch_size == 32 assert config.learning_rate == 0.001 def test_default_voice_recognition_trainer(self): """Testet die Standard-Sprechererkennung-Trainer-Konfiguration.""" config = VoiceRecognitionTrainerConfig() assert config.embedding_size == 256 assert config.epochs == 100 def test_default_data_config(self): """Testet die Standard-Daten-Konfiguration.""" config = DataConfig() assert config.min_samples_per_class == 10 def test_default_trainer_config(self): """Testet die Standard-Trainer-Konfiguration.""" config = TrainerConfig() assert config.device == "auto" assert config.seed == 42 assert config.verbose is True class TestConfigManager: """Tests für ConfigManager.""" @pytest.fixture def manager(self): """Erstellt einen ConfigManager.""" return ConfigManager() @pytest.fixture def config_file(self, temp_dir): """Erstellt eine Test-Konfigurationsdatei.""" config = { "network": { "command_port": 3000, "audio_input_port": 3001 }, "profile": "test" } path = temp_dir / "test_config.json" path.write_text(json.dumps(config)) return path def test_load_config(self, manager, config_file): """Testet das Laden einer Konfiguration.""" config = manager.load(config_file, ServerConfig, name="test") assert config.network.command_port == 3000 assert config.network.audio_input_port == 3001 assert config.profile == "test" def test_load_nonexistent_uses_defaults(self, manager, temp_dir): """Testet, dass fehlende Dateien Standardwerte verwenden.""" path = temp_dir / "nonexistent.json" config = manager.load(path, ServerConfig, name="default") assert config.network.command_port == 2101 # Standard def test_get_config(self, manager, config_file): """Testet das Abrufen einer Konfiguration.""" manager.load(config_file, ServerConfig, name="test") config = manager.get("test") assert config is not None assert isinstance(config, ServerConfig) def test_get_nonexistent_config(self, manager): """Testet get für nicht existierende Konfiguration.""" assert manager.get("nonexistent") is None def test_get_typed(self, manager, config_file): """Testet get_typed.""" manager.load(config_file, ServerConfig, name="test") config = manager.get_typed("test", ServerConfig) assert isinstance(config, ServerConfig) def test_save_config(self, manager, temp_dir): """Testet das Speichern einer Konfiguration.""" path = temp_dir / "save_test.json" config = ServerConfig() config.profile = "saved" manager.load(path, ServerConfig, name="save") manager.save("save", config) # Datei lesen und prüfen data = json.loads(path.read_text()) assert data["profile"] == "saved" def test_reload_config(self, manager, config_file): """Testet das Neuladen einer Konfiguration.""" manager.load(config_file, ServerConfig, name="test") # Datei ändern config_file.write_text(json.dumps({ "profile": "reloaded" })) config = manager.reload("test") assert config.profile == "reloaded" def test_on_reload_callback(self, manager, config_file): """Testet Reload-Callbacks.""" called = [] def callback(config): called.append(config) manager.load(config_file, ServerConfig, name="test") manager.on_reload("test", callback) # Datei ändern config_file.write_text(json.dumps({"profile": "callback_test"})) manager.reload("test") assert len(called) == 1 assert called[0].profile == "callback_test" def test_create_default(self, manager, temp_dir): """Testet das Erstellen einer Standard-Konfiguration.""" path = temp_dir / "default_config.json" config = manager.create_default(ServerConfig, path) assert path.exists() assert isinstance(config, ServerConfig) # Datei lesen und prüfen data = json.loads(path.read_text()) assert "network" in data def test_nested_dataclass_loading(self, manager, temp_dir): """Testet das Laden verschachtelter Dataclasses.""" config = { "network": { "command_port": 5000, "bind_address": "127.0.0.1" }, "security": { "encryption_enabled": False } } path = temp_dir / "nested.json" path.write_text(json.dumps(config)) loaded = manager.load(path, ServerConfig, name="nested") assert loaded.network.command_port == 5000 assert loaded.network.bind_address == "127.0.0.1" assert loaded.security.encryption_enabled is False def test_stop_watching(self, manager): """Testet das Stoppen der Dateiüberwachung.""" # Sollte ohne Fehler durchlaufen manager.stop_watching()