import json import sys import tempfile import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[1] SRC = ROOT / "src" if str(SRC) not in sys.path: sys.path.insert(0, str(SRC)) from config import load class ConfigTests(unittest.TestCase): def test_defaults_when_file_missing(self): missing = Path(tempfile.gettempdir()) / "lel_missing_config_test.json" if missing.exists(): missing.unlink() cfg = load(str(missing)) self.assertEqual(cfg.daemon.hotkey, "Cmd+m") self.assertEqual(cfg.recording.input, "") self.assertEqual(cfg.stt.model, "base") self.assertEqual(cfg.stt.device, "cpu") self.assertEqual(cfg.injection.backend, "clipboard") self.assertTrue(cfg.ai.enabled) self.assertEqual(cfg.vocabulary.replacements, []) self.assertEqual(cfg.vocabulary.terms, []) self.assertEqual(cfg.vocabulary.max_rules, 500) self.assertEqual(cfg.vocabulary.max_terms, 500) self.assertTrue(cfg.domain_inference.enabled) self.assertEqual(cfg.domain_inference.mode, "auto") def test_loads_nested_config(self): payload = { "daemon": {"hotkey": "Ctrl+space"}, "recording": {"input": 3}, "stt": {"model": "small", "device": "cuda"}, "injection": {"backend": "injection"}, "ai": {"enabled": False}, "vocabulary": { "replacements": [ {"from": "Martha", "to": "Marta"}, {"from": "docker", "to": "Docker"}, ], "terms": ["Systemd", "Kubernetes"], "max_rules": 100, "max_terms": 200, }, "domain_inference": {"enabled": True, "mode": "auto"}, } with tempfile.TemporaryDirectory() as td: path = Path(td) / "config.json" path.write_text(json.dumps(payload), encoding="utf-8") cfg = load(str(path)) self.assertEqual(cfg.daemon.hotkey, "Ctrl+space") self.assertEqual(cfg.recording.input, 3) self.assertEqual(cfg.stt.model, "small") self.assertEqual(cfg.stt.device, "cuda") self.assertEqual(cfg.injection.backend, "injection") self.assertFalse(cfg.ai.enabled) self.assertEqual(cfg.vocabulary.max_rules, 100) self.assertEqual(cfg.vocabulary.max_terms, 200) self.assertEqual(len(cfg.vocabulary.replacements), 2) self.assertEqual(cfg.vocabulary.replacements[0].source, "Martha") self.assertEqual(cfg.vocabulary.replacements[0].target, "Marta") self.assertEqual(cfg.vocabulary.terms, ["Systemd", "Kubernetes"]) self.assertTrue(cfg.domain_inference.enabled) self.assertEqual(cfg.domain_inference.mode, "auto") def test_loads_legacy_keys(self): payload = { "hotkey": "Alt+m", "input": "Mic", "whisper_model": "tiny", "whisper_device": "cpu", "injection_backend": "clipboard", "ai_enabled": False, } with tempfile.TemporaryDirectory() as td: path = Path(td) / "config.json" path.write_text(json.dumps(payload), encoding="utf-8") cfg = load(str(path)) self.assertEqual(cfg.daemon.hotkey, "Alt+m") self.assertEqual(cfg.recording.input, "Mic") self.assertEqual(cfg.stt.model, "tiny") self.assertEqual(cfg.stt.device, "cpu") self.assertEqual(cfg.injection.backend, "clipboard") self.assertFalse(cfg.ai.enabled) self.assertEqual(cfg.vocabulary.replacements, []) def test_invalid_injection_backend_raises(self): payload = {"injection": {"backend": "invalid"}} with tempfile.TemporaryDirectory() as td: path = Path(td) / "config.json" path.write_text(json.dumps(payload), encoding="utf-8") with self.assertRaisesRegex(ValueError, "injection.backend"): load(str(path)) def test_removed_logging_section_raises(self): payload = {"logging": {"log_transcript": True}} with tempfile.TemporaryDirectory() as td: path = Path(td) / "config.json" path.write_text(json.dumps(payload), encoding="utf-8") with self.assertRaisesRegex(ValueError, "no longer supported"): load(str(path)) def test_removed_legacy_log_transcript_raises(self): payload = {"log_transcript": True} with tempfile.TemporaryDirectory() as td: path = Path(td) / "config.json" path.write_text(json.dumps(payload), encoding="utf-8") with self.assertRaisesRegex(ValueError, "no longer supported"): load(str(path)) def test_conflicting_replacements_raise(self): payload = { "vocabulary": { "replacements": [ {"from": "Martha", "to": "Marta"}, {"from": "martha", "to": "Martha"}, ] } } with tempfile.TemporaryDirectory() as td: path = Path(td) / "config.json" path.write_text(json.dumps(payload), encoding="utf-8") with self.assertRaisesRegex(ValueError, "conflicting"): load(str(path)) def test_duplicate_rules_and_terms_are_deduplicated(self): payload = { "vocabulary": { "replacements": [ {"from": "docker", "to": "Docker"}, {"from": "DOCKER", "to": "Docker"}, ], "terms": ["Systemd", "systemd"], } } with tempfile.TemporaryDirectory() as td: path = Path(td) / "config.json" path.write_text(json.dumps(payload), encoding="utf-8") cfg = load(str(path)) self.assertEqual(len(cfg.vocabulary.replacements), 1) self.assertEqual(cfg.vocabulary.replacements[0].source, "docker") self.assertEqual(cfg.vocabulary.replacements[0].target, "Docker") self.assertEqual(cfg.vocabulary.terms, ["Systemd"]) def test_wildcard_term_raises(self): payload = { "vocabulary": { "terms": ["Dock*"], } } with tempfile.TemporaryDirectory() as td: path = Path(td) / "config.json" path.write_text(json.dumps(payload), encoding="utf-8") with self.assertRaisesRegex(ValueError, "wildcard"): load(str(path)) def test_invalid_domain_mode_raises(self): payload = {"domain_inference": {"mode": "heuristic"}} with tempfile.TemporaryDirectory() as td: path = Path(td) / "config.json" path.write_text(json.dumps(payload), encoding="utf-8") with self.assertRaisesRegex(ValueError, "domain_inference.mode"): load(str(path)) if __name__ == "__main__": unittest.main()