refactor: convert inserter module to package with wayland backend

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vitali Graf
2026-04-08 10:34:07 +02:00
parent f9402c427c
commit b47045ab9b
4 changed files with 41 additions and 33 deletions
+11 -18
View File
@@ -1,15 +1,16 @@
import asyncio
import sys
from unittest.mock import AsyncMock, patch, call
import pytest
from whisper_local.inserter import Inserter
from whisper_local.inserter._wayland import WaylandInserter
class TestInserter:
class TestWaylandInserter:
@pytest.mark.asyncio
@patch("whisper_local.inserter.asyncio.sleep", new_callable=AsyncMock)
@patch("whisper_local.inserter.asyncio.create_subprocess_exec")
@patch("whisper_local.inserter._wayland.asyncio.sleep", new_callable=AsyncMock)
@patch("whisper_local.inserter._wayland.asyncio.create_subprocess_exec")
async def test_insert_text_calls_tools_in_order(self, mock_exec, mock_sleep):
mock_proc = AsyncMock()
mock_proc.communicate.return_value = (b"alter clipboard", b"")
@@ -17,31 +18,24 @@ class TestInserter:
mock_proc.wait = AsyncMock()
mock_exec.return_value = mock_proc
inserter = Inserter()
inserter = WaylandInserter()
await inserter.insert("Hallo Welt")
calls = mock_exec.call_args_list
assert len(calls) == 4
# wl-paste mit PIPE (braucht stdout)
assert calls[0][0] == ("wl-paste", "--no-newline")
# wl-copy mit DEVNULL (forkt Hintergrundprozess)
assert calls[1][0] == ("wl-copy", "--", "Hallo Welt")
# ydotool key
assert calls[2][0][0] == "ydotool"
# wl-copy restore
assert calls[3][0] == ("wl-copy", "--", "alter clipboard")
@pytest.mark.asyncio
@patch("whisper_local.inserter.asyncio.create_subprocess_exec")
async def test_insert_empty_text_does_nothing(self, mock_exec):
inserter = Inserter()
async def test_insert_empty_text_does_nothing(self):
inserter = WaylandInserter()
await inserter.insert("")
mock_exec.assert_not_called()
@pytest.mark.asyncio
@patch("whisper_local.inserter.asyncio.sleep", new_callable=AsyncMock)
@patch("whisper_local.inserter.asyncio.create_subprocess_exec")
@patch("whisper_local.inserter._wayland.asyncio.sleep", new_callable=AsyncMock)
@patch("whisper_local.inserter._wayland.asyncio.create_subprocess_exec")
async def test_clipboard_restore_on_paste_failure(self, mock_exec, mock_sleep):
call_count = 0
@@ -61,9 +55,8 @@ class TestInserter:
mock_exec.side_effect = mock_create_proc
inserter = Inserter()
inserter = WaylandInserter()
with pytest.raises(OSError):
await inserter.insert("Test")
# Clipboard muss trotzdem wiederhergestellt werden (finally-Block)
assert call_count == 4
+8 -4
View File
@@ -7,18 +7,20 @@ from whisper_local.__main__ import App
class TestApp:
@patch("whisper_local.__main__.Inserter")
@patch("whisper_local.__main__.Transcriber")
@patch("whisper_local.__main__.HotkeyListener")
def test_app_init(self, mock_hotkey_class, mock_transcriber_class):
def test_app_init(self, mock_hotkey_class, mock_transcriber_class, mock_inserter_class):
app = App()
assert app.recorder is not None
assert app.inserter is not None
mock_transcriber_class.assert_called_once()
mock_hotkey_class.assert_called_once()
@patch("whisper_local.__main__.Inserter")
@patch("whisper_local.__main__.Transcriber")
@patch("whisper_local.__main__.HotkeyListener")
def test_on_press_starts_recording(self, mock_hotkey_class, mock_transcriber_class):
def test_on_press_starts_recording(self, mock_hotkey_class, mock_transcriber_class, mock_inserter_class):
app = App()
app.recorder = MagicMock()
@@ -27,9 +29,10 @@ class TestApp:
app.recorder.start.assert_called_once()
@patch("whisper_local.__main__.Inserter")
@patch("whisper_local.__main__.Transcriber")
@patch("whisper_local.__main__.HotkeyListener")
def test_on_release_stops_and_transcribes(self, mock_hotkey_class, mock_transcriber_class):
def test_on_release_stops_and_transcribes(self, mock_hotkey_class, mock_transcriber_class, mock_inserter_class):
mock_transcriber = MagicMock()
mock_transcriber.transcribe.return_value = "Hallo"
mock_transcriber_class.return_value = mock_transcriber
@@ -48,9 +51,10 @@ class TestApp:
mock_transcriber.transcribe.assert_called_once_with(audio)
app.inserter.insert.assert_awaited_once_with("Hallo")
@patch("whisper_local.__main__.Inserter")
@patch("whisper_local.__main__.Transcriber")
@patch("whisper_local.__main__.HotkeyListener")
def test_on_release_no_audio_skips(self, mock_hotkey_class, mock_transcriber_class):
def test_on_release_no_audio_skips(self, mock_hotkey_class, mock_transcriber_class, mock_inserter_class):
mock_transcriber = MagicMock()
mock_transcriber_class.return_value = mock_transcriber