"""Tests for configuration loading.""" import tempfile from pathlib import Path from stt_daemon.config import load_config def test_load_config_defaults(): """Test that load_config returns defaults when no file exists.""" with tempfile.TemporaryDirectory() as tmpdir: # Change to temp dir and load (no config.toml exists) import os old_cwd = os.getcwd() try: os.chdir(tmpdir) cfg = load_config() assert cfg.audio.backend == "parec" assert cfg.audio.device == "VirtualMicSink.monitor" assert cfg.audio.sample_rate == 16000 assert cfg.vad.aggressiveness == 2 assert cfg.whisper.model == "small" assert cfg.whisper.language is None assert cfg.output.stdout is True finally: os.chdir(old_cwd) def test_load_config_from_file(): """Test loading config from a TOML file.""" config_toml = """ [audio] backend = "sounddevice" device = "hw:0" sample_rate = 44100 [vad] aggressiveness = 3 pre_roll_ms = 500 [whisper] model = "base" device = "cuda" language = "es" [output] stdout = false jsonl_dir = "logs" """ with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "config.toml" config_path.write_text(config_toml) cfg = load_config(str(config_path)) assert cfg.audio.backend == "sounddevice" assert cfg.audio.device == "hw:0" assert cfg.audio.sample_rate == 44100 assert cfg.vad.aggressiveness == 3 assert cfg.vad.pre_roll_ms == 500 assert cfg.whisper.model == "base" assert cfg.whisper.device == "cuda" assert cfg.whisper.language == "es" assert cfg.output.stdout is False assert cfg.output.jsonl_dir == "logs" def test_language_normalization_auto(): """Test that language 'auto' is normalized to None.""" config_toml = """ [whisper] language = "auto" """ with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "config.toml" config_path.write_text(config_toml) cfg = load_config(str(config_path)) assert cfg.whisper.language is None def test_language_normalization_empty_string(): """Test that language '' is normalized to None.""" config_toml = """ [whisper] language = "" """ with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "config.toml" config_path.write_text(config_toml) cfg = load_config(str(config_path)) assert cfg.whisper.language is None def test_language_normalization_none(): """Test that language 'none' is normalized to None.""" config_toml = """ [whisper] language = "none" """ with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "config.toml" config_path.write_text(config_toml) cfg = load_config(str(config_path)) assert cfg.whisper.language is None def test_language_explicit_en(): """Test that explicit language codes are preserved.""" config_toml = """ [whisper] language = "en" """ with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "config.toml" config_path.write_text(config_toml) cfg = load_config(str(config_path)) assert cfg.whisper.language == "en" def test_partial_config(): """Test that partial configs merge with defaults.""" config_toml = """ [audio] device = "custom_device" """ with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "config.toml" config_path.write_text(config_toml) cfg = load_config(str(config_path)) # Overridden assert cfg.audio.device == "custom_device" # Defaults assert cfg.audio.backend == "parec" assert cfg.audio.sample_rate == 16000 assert cfg.vad.aggressiveness == 2 def test_chunking_and_confidence_fields(): """New chunking/gate fields load from TOML.""" config_toml = """ [vad] chunk_pause_ms = 500 soft_max_s = 8.0 rms_floor = 0.01 trailing_trim_ms = 150 [whisper] no_speech_prob_max = 0.7 avg_logprob_min = -0.8 """ with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "config.toml" config_path.write_text(config_toml) cfg = load_config(str(config_path)) assert cfg.vad.chunk_pause_ms == 500 assert cfg.vad.soft_max_s == 8.0 assert cfg.vad.rms_floor == 0.01 assert cfg.vad.trailing_trim_ms == 150 assert cfg.whisper.no_speech_prob_max == 0.7 assert cfg.whisper.avg_logprob_min == -0.8 def test_chunking_defaults(): """New fields have sane defaults.""" with tempfile.TemporaryDirectory() as tmpdir: import os old_cwd = os.getcwd() try: os.chdir(tmpdir) cfg = load_config() finally: os.chdir(old_cwd) assert cfg.vad.chunk_pause_ms == 350 assert cfg.vad.soft_max_s == 10.0 assert cfg.vad.rms_floor == 0.008 assert cfg.vad.trailing_trim_ms == 200 assert cfg.whisper.no_speech_prob_max == 0.6 assert cfg.whisper.avg_logprob_min == -1.0 def test_output_defaults_disable_audio_saving(): with tempfile.TemporaryDirectory() as tmpdir: import os old_cwd = os.getcwd() try: os.chdir(tmpdir) cfg = load_config() finally: os.chdir(old_cwd) assert cfg.output.save_audio is False assert cfg.output.audio_dir == "audio" def test_output_save_audio_fields(): config_toml = """ [output] save_audio = true audio_dir = "clips" """ with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "config.toml" config_path.write_text(config_toml) cfg = load_config(str(config_path)) assert cfg.output.save_audio is True assert cfg.output.audio_dir == "clips" def test_daemon_defaults(): with tempfile.TemporaryDirectory() as tmpdir: import os old_cwd = os.getcwd() try: os.chdir(tmpdir) cfg = load_config() finally: os.chdir(old_cwd) assert cfg.daemon.queue_size == 50 assert cfg.daemon.backlog_warn_at == 5 def test_daemon_config_fields(): config_toml = """ [daemon] queue_size = 20 backlog_warn_at = 3 """ with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "config.toml" config_path.write_text(config_toml) cfg = load_config(str(config_path)) assert cfg.daemon.queue_size == 20 assert cfg.daemon.backlog_warn_at == 3