105 lines
3.3 KiB
Python
105 lines
3.3 KiB
Python
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()
|