2026-04-06 20:28:18 +02:00
|
|
|
import asyncio
|
2026-04-06 21:26:51 +02:00
|
|
|
from unittest.mock import AsyncMock, patch, call
|
2026-04-06 20:28:18 +02:00
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
from whisper_local.inserter import Inserter
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestInserter:
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
|
@patch("whisper_local.inserter.asyncio.sleep", new_callable=AsyncMock)
|
|
|
|
|
@patch("whisper_local.inserter.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"")
|
|
|
|
|
mock_proc.returncode = 0
|
2026-04-06 21:26:51 +02:00
|
|
|
mock_proc.wait = AsyncMock()
|
2026-04-06 20:28:18 +02:00
|
|
|
mock_exec.return_value = mock_proc
|
|
|
|
|
|
|
|
|
|
inserter = Inserter()
|
|
|
|
|
await inserter.insert("Hallo Welt")
|
|
|
|
|
|
|
|
|
|
calls = mock_exec.call_args_list
|
|
|
|
|
assert len(calls) == 4
|
2026-04-06 21:26:51 +02:00
|
|
|
# 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")
|
2026-04-06 20:28:18 +02:00
|
|
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
|
@patch("whisper_local.inserter.asyncio.create_subprocess_exec")
|
|
|
|
|
async def test_insert_empty_text_does_nothing(self, mock_exec):
|
|
|
|
|
inserter = Inserter()
|
|
|
|
|
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")
|
|
|
|
|
async def test_clipboard_restore_on_paste_failure(self, mock_exec, mock_sleep):
|
|
|
|
|
call_count = 0
|
|
|
|
|
|
|
|
|
|
async def mock_create_proc(*args, **kwargs):
|
|
|
|
|
nonlocal call_count
|
|
|
|
|
call_count += 1
|
|
|
|
|
mock_proc = AsyncMock()
|
2026-04-06 21:26:51 +02:00
|
|
|
mock_proc.wait = AsyncMock()
|
2026-04-06 20:28:18 +02:00
|
|
|
if call_count == 1: # wl-paste
|
|
|
|
|
mock_proc.communicate.return_value = (b"original", b"")
|
|
|
|
|
mock_proc.returncode = 0
|
2026-04-06 21:26:51 +02:00
|
|
|
elif call_count == 3: # ydotool — fails
|
|
|
|
|
mock_proc.wait.side_effect = OSError("ydotool not found")
|
|
|
|
|
else: # wl-copy calls
|
2026-04-06 20:28:18 +02:00
|
|
|
mock_proc.returncode = 0
|
|
|
|
|
return mock_proc
|
|
|
|
|
|
|
|
|
|
mock_exec.side_effect = mock_create_proc
|
|
|
|
|
|
|
|
|
|
inserter = Inserter()
|
2026-04-06 21:26:51 +02:00
|
|
|
with pytest.raises(OSError):
|
|
|
|
|
await inserter.insert("Test")
|
2026-04-06 20:28:18 +02:00
|
|
|
|
2026-04-06 21:26:51 +02:00
|
|
|
# Clipboard muss trotzdem wiederhergestellt werden (finally-Block)
|
2026-04-06 20:28:18 +02:00
|
|
|
assert call_count == 4
|