import os import sys import tempfile import unittest from pathlib import Path from unittest.mock import patch ROOT = Path(__file__).resolve().parents[1] SRC = ROOT / "src" if str(SRC) not in sys.path: sys.path.insert(0, str(SRC)) import leld from config import Config class FakeDesktop: def __init__(self): self.inject_calls = [] self.quit_calls = 0 def inject_text(self, text: str, backend: str) -> None: self.inject_calls.append((text, backend)) def request_quit(self) -> None: self.quit_calls += 1 class FakeSegment: def __init__(self, text: str): self.text = text class FakeModel: def transcribe(self, _audio, language=None, vad_filter=None): return [FakeSegment("hello world")], {"language": language, "vad_filter": vad_filter} class FakeAudio: def __init__(self, size: int): self.size = size class DaemonTests(unittest.TestCase): def _config(self) -> Config: cfg = Config() cfg.ai.enabled = False cfg.logging.log_transcript = False return cfg @patch("leld._build_whisper_model", return_value=FakeModel()) @patch("leld.stop_audio_recording", return_value=FakeAudio(8)) @patch("leld.start_audio_recording", return_value=(object(), object())) def test_toggle_start_stop_injects_text(self, _start_mock, _stop_mock, _model_mock): desktop = FakeDesktop() daemon = leld.Daemon(self._config(), desktop, verbose=False) daemon._start_stop_worker = ( lambda stream, record, trigger, process_audio: daemon._stop_and_process( stream, record, trigger, process_audio ) ) daemon.toggle() self.assertEqual(daemon.get_state(), leld.State.RECORDING) daemon.toggle() self.assertEqual(daemon.get_state(), leld.State.IDLE) self.assertEqual(desktop.inject_calls, [("hello world", "clipboard")]) @patch("leld._build_whisper_model", return_value=FakeModel()) @patch("leld.stop_audio_recording", return_value=FakeAudio(8)) @patch("leld.start_audio_recording", return_value=(object(), object())) def test_shutdown_stops_recording_without_injection(self, _start_mock, _stop_mock, _model_mock): desktop = FakeDesktop() daemon = leld.Daemon(self._config(), desktop, verbose=False) daemon._start_stop_worker = ( lambda stream, record, trigger, process_audio: daemon._stop_and_process( stream, record, trigger, process_audio ) ) daemon.toggle() self.assertEqual(daemon.get_state(), leld.State.RECORDING) self.assertTrue(daemon.shutdown(timeout=0.2)) self.assertEqual(daemon.get_state(), leld.State.IDLE) self.assertEqual(desktop.inject_calls, []) class LockTests(unittest.TestCase): def test_lock_rejects_second_instance(self): with tempfile.TemporaryDirectory() as td: with patch.dict(os.environ, {"XDG_RUNTIME_DIR": td}, clear=False): first = leld._lock_single_instance() try: with self.assertRaises(SystemExit) as ctx: leld._lock_single_instance() self.assertIn("already running", str(ctx.exception)) finally: first.close() if __name__ == "__main__": unittest.main()