/
sapertlt
/
layout_switcher
Обзор
Документация
Войти
/
sapertlt
/
layout_switcher
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop
tests/test_clipboard.py
198 строк
8 KB
Andrey Nikolaev
release: v0.1.6 — Безусловная коррекция выделения и управление буфером обмена
20 июн 2026, 02:02
20 июн 2026, 02:02
0ffe2a1
Код
Авторство
О чём код?
""" Тесты сохранения, восстановления и очистки буфера обмена (X11 и Wayland). """ import pytest from unittest.mock import MagicMock, patch from subprocess import DEVNULL, PIPE from layout_switcher.output.x11_output import X11OutputProvider from layout_switcher.output.wayland_output import WaylandOutputProvider class TestClipboardHandling: """Тестирование работы с буфером обмена для X11 и Wayland.""" # ========================================================================= # X11 Тесты # ========================================================================= @patch("subprocess.run") @patch("subprocess.Popen") def test_x11_set_clipboard_normal(self, mock_popen, mock_run): """Проверка обычной записи текста в буфер обмена X11.""" provider = X11OutputProvider() mock_proc = MagicMock() mock_proc.returncode = 0 mock_popen.return_value = mock_proc result = provider._set_clipboard("hello") assert result is True mock_popen.assert_called_once_with( ["xclip", "-selection", "clipboard"], stdin=PIPE, ) mock_proc.communicate.assert_called_once_with( input=b"hello", timeout=2.0, ) @patch("subprocess.run") @patch("subprocess.Popen") def test_x11_set_clipboard_empty(self, mock_popen, mock_run): """Проверка очистки буфера обмена X11 при пустой строке.""" provider = X11OutputProvider() mock_proc = MagicMock() mock_proc.returncode = 0 mock_popen.return_value = mock_proc result = provider._set_clipboard("") assert result is True mock_popen.assert_called_once_with( ["xclip", "-selection", "clipboard"], stdin=DEVNULL, ) mock_proc.communicate.assert_called_once_with( timeout=2.0, ) @patch("time.sleep") @patch("subprocess.run") @patch("subprocess.Popen") def test_x11_replace_selected_text_restores_clipboard(self, mock_popen, mock_run, mock_sleep): """Проверка, что replace_selected_text сохраняет и восстанавливает буфер обмена X11.""" provider = X11OutputProvider() # Настраиваем мок для чтения буфера обмена (сначала возвращает "old_content") mock_run.return_value = MagicMock(returncode=0, stdout="old_content") # Настраиваем мок для Popen (для записи в буфер) mock_proc = MagicMock(returncode=0) mock_popen.return_value = mock_proc provider.replace_selected_text("new_content") # Должно быть два вызова _set_clipboard (снаружи): # 1. Запись "new_content" перед вставкой # 2. Восстановление "old_content" после вставки assert mock_popen.call_count == 2 # Проверяем аргументы вызовов popen calls = mock_popen.call_args_list assert calls[0][1].get("stdin") == PIPE # Для записи "new_content" assert calls[1][1].get("stdin") == PIPE # Для записи "old_content" @patch("time.sleep") @patch("subprocess.run") @patch("subprocess.Popen") def test_x11_replace_selected_text_clears_if_empty(self, mock_popen, mock_run, mock_sleep): """Проверка, что replace_selected_text очищает буфер обмена X11, если он был пуст.""" provider = X11OutputProvider() # Настраиваем мок для чтения буфера обмена (возвращает None/ошибку, т.е. буфер был пуст) mock_run.return_value = MagicMock(returncode=1, stdout="") # Настраиваем мок для Popen mock_proc = MagicMock(returncode=0) mock_popen.return_value = mock_proc provider.replace_selected_text("new_content") # Должно быть два вызова _set_clipboard (Popen): # 1. Запись "new_content" перед вставкой # 2. Очистка буфера обмена (запись "") assert mock_popen.call_count == 2 calls = mock_popen.call_args_list assert calls[0][1].get("stdin") == PIPE # Запись "new_content" assert calls[1][1].get("stdin") == DEVNULL # Очистка (stdin=DEVNULL) # ========================================================================= # Wayland Тесты # ========================================================================= @patch("subprocess.run") def test_wayland_set_clipboard_normal(self, mock_run): """Проверка обычной записи текста в буфер обмена Wayland.""" provider = WaylandOutputProvider() mock_run.return_value = MagicMock(returncode=0) provider._set_clipboard("hello") mock_run.assert_called_once_with( ["wl-copy"], input="hello", capture_output=True, text=True, timeout=5, ) @patch("subprocess.run") def test_wayland_set_clipboard_empty(self, mock_run): """Проверка очистки буфера обмена Wayland при пустой строке.""" provider = WaylandOutputProvider() mock_run.return_value = MagicMock(returncode=0) provider._set_clipboard("") mock_run.assert_called_once_with( ["wl-copy", "-c"], capture_output=True, timeout=5, ) @patch("time.sleep") @patch("subprocess.run") def test_wayland_replace_selected_text_restores_clipboard(self, mock_run, mock_sleep): """Проверка, что replace_selected_text сохраняет и восстанавливает буфер обмена Wayland.""" provider = WaylandOutputProvider() # Первым делом wl-paste для сохранения исходного буфера # Настраиваем последовательные возвраты для subprocess.run: # 1. wl-paste (возвращает "old_content") # 2. wl-copy (запись "new_content") # 3. ydotool key (вставка) # 4. wl-copy (восстановление "old_content") mock_run.side_effect = [ MagicMock(returncode=0, stdout="old_content"), # get_clipboard MagicMock(returncode=0), # set_clipboard (new) MagicMock(returncode=0), # paste MagicMock(returncode=0), # set_clipboard (old) ] provider.replace_selected_text("new_content") # Проверим вызовы wl-copy copy_calls = [ args[0][0] for args in mock_run.call_args_list if args[0][0][0] == "wl-copy" ] assert len(copy_calls) == 2 # Первая запись: wl-copy с input="new_content" # Второй запись: wl-copy с input="old_content" assert mock_run.call_args_list[1][1].get("input") == "new_content" assert mock_run.call_args_list[3][1].get("input") == "old_content" @patch("time.sleep") @patch("subprocess.run") def test_wayland_replace_selected_text_clears_if_empty(self, mock_run, mock_sleep): """Проверка, что replace_selected_text очищает буфер обмена Wayland, если он был пуст.""" provider = WaylandOutputProvider() # 1. wl-paste (возвращает ошибку, т.е. буфер пуст) # 2. wl-copy (запись "new_content") # 3. ydotool key (вставка) # 4. wl-copy -c (очистка) mock_run.side_effect = [ MagicMock(returncode=1, stdout=""), # get_clipboard (None) MagicMock(returncode=0), # set_clipboard (new) MagicMock(returncode=0), # paste MagicMock(returncode=0), # set_clipboard (empty -> wl-copy -c) ] provider.replace_selected_text("new_content") # Проверяем последний вызов wl-copy assert mock_run.call_args_list[3][0][0] == ["wl-copy", "-c"]