"""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 assert cfg.output.jsonl is False 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 = true 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 is True 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 def test_unknown_sections_warn_and_are_ignored(caplog): """A typo'd section like [assitant] must warn, not silently use defaults.""" config_toml = """ [assitant] require_viewer = false """ with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "config.toml" config_path.write_text(config_toml) with caplog.at_level("WARNING", logger="stt_daemon.config"): cfg = load_config(str(config_path)) assert "assitant" in caplog.text assert cfg.assistant.require_viewer is True def test_cpu_threads_default_is_auto(): """cpu_threads defaults to 0 (CTranslate2's automatic choice).""" 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.whisper.cpu_threads == 0 def test_cpu_threads_config_field(): config_toml = """ [whisper] cpu_threads = 16 """ 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.cpu_threads == 16 def test_language_strategy_defaults_to_static(): """language_strategy defaults to 'static'.""" 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.whisper.language_strategy == "static" def test_language_strategy_sticky_is_parsed(): """language_strategy 'sticky' is parsed correctly.""" config_toml = """ [whisper] language_strategy = "sticky" """ 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_strategy == "sticky" def test_unknown_language_strategy_falls_back_to_static(caplog): """An unknown language_strategy value falls back to 'static' with a warning.""" config_toml = """ [whisper] language_strategy = "bogus" """ with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "config.toml" config_path.write_text(config_toml) with caplog.at_level("WARNING", logger="stt_daemon.config"): cfg = load_config(str(config_path)) assert cfg.whisper.language_strategy == "static" assert "Unknown language_strategy" in caplog.text assert "bogus" in caplog.text def test_sticky_redetect_logprob_defaults_to_minus_0_8(): """sticky_redetect_logprob defaults to -0.8.""" 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.whisper.sticky_redetect_logprob == -0.8 def test_sticky_redetect_logprob_is_parsed(): """sticky_redetect_logprob is parsed from TOML.""" config_toml = """ [whisper] sticky_redetect_logprob = -0.5 """ 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.sticky_redetect_logprob == -0.5