Add tests for drop move events

This commit is contained in:
Kovid Goyal
2026-04-20 11:23:49 +05:30
parent 4c484ca1e8
commit 54eab02709
3 changed files with 104 additions and 17 deletions

View File

@@ -1,12 +1,15 @@
#!/usr/bin/env python
# License: GPLv3 Copyright: 2026, Kovid Goyal <kovid at kovidgoyal.net>
import os
import tempfile
from base64 import standard_b64encode
from kitty.constants import kitten_exe
from kitty.fast_data_types import (
DND_CODE,
GLFW_DRAG_OPERATION_COPY,
GLFW_DRAG_OPERATION_MOVE,
dnd_set_test_write_func,
dnd_test_cleanup_fake_window,
dnd_test_create_fake_window,
@@ -33,11 +36,16 @@ class TestDnDKitten(BaseTest):
capture.os_window_id = os_window_id
self.capture = capture
self.test_dir = self.enterContext(tempfile.TemporaryDirectory())
self.kitten_wd = os.path.join(self.test_dir, 'kitten')
os.mkdir(self.kitten_wd)
self.src_data_dir = os.path.join(self.test_dir, 'src')
os.mkdir(self.src_data_dir)
self.messages_from_kitten = ''
self.set_options({'tab_bar_style': 'hidden'})
def send_dnd_command_to_kitten(self, payload=b'', as_base64=False, flush=False, **metadata):
def send_dnd_command_to_kitten(self, payload=b'', as_base64=False, flush=False, t='T', **metadata):
header = f'\x1b]{DND_CODE};'
metadata['t'] = t
for k, v in metadata.items():
header = header + f'{k}={v}:'
self.pty.write_to_child(header.encode())
@@ -62,7 +70,7 @@ class TestDnDKitten(BaseTest):
cmd = [kitten_exe(), 'dnd']
if remote_client:
cmd.append('--machine-id=remote-client-for-test')
self.pty = self.enterContext(PTY(argv=cmd, rows=25, columns=80, window_id=self.capture.window_id))
self.pty = self.enterContext(PTY(argv=cmd, cwd=self.kitten_wd, rows=25, columns=80, window_id=self.capture.window_id))
self.pty.callbacks.printbuf = self
self.screen = self.pty.screen
self.pty.wait_till(lambda: bool(self.pty.callbacks.titlebuf))
@@ -70,7 +78,23 @@ class TestDnDKitten(BaseTest):
self.assertEqual(remote_client, self.probe_state('drop_is_remote_client'))
if self.probe_state('drag_can_offer'):
self.assertEqual(remote_client, self.probe_state('drag_is_remote_client'))
self.send_dnd_command_to_kitten('SETUP', t='T')
self.send_dnd_command_to_kitten('SETUP')
def get_button_geometry(self, are_present: bool = True):
self.send_dnd_command_to_kitten('GEOMETRY')
self.pty.wait_till(lambda: bool(self.messages_from_kitten))
self.assertTrue(self.messages_from_kitten.startswith('GEOMETRY') and self.messages_from_kitten.endswith('\n'),
f'Unexpected messages from kitten: {self.messages_from_kitten!r}')
q, self.messages_from_kitten = self.messages_from_kitten.rstrip(), ''
parts = tuple(map(int, q.split(':')[1:]))
copy, move = parts[:4], parts[4:]
if are_present:
self.assertGreater(copy[2], 4)
self.assertGreater(move[2], 4)
else:
self.assertEqual(copy, (0,0,0,0))
self.assertEqual(move, (0,0,0,0))
return copy, move
def append(self, text):
self.messages_from_kitten += text
@@ -79,12 +103,21 @@ class TestDnDKitten(BaseTest):
q = '\n'.join(responses)
def wait_till():
return q == self.messages_from_kitten.strip()
self.pty.wait_till(wait_till, timeout, lambda: f'Responses so far: {self.messages_from_kitten!r}')
self.messages_from_kitten = ''
try:
self.pty.wait_till(wait_till, timeout, lambda: f'Responses so far: {self.messages_from_kitten!r}')
finally:
self.messages_from_kitten = ''
def wait_for_state(self, q, expected, timeout=10):
self.pty.wait_till(lambda: self.probe_state(q) == expected, timeout, lambda: f'{q}: {self.probe_state(q)!r}')
def probe_state(self, which: str):
return dnd_test_probe_state(self.capture.window_id, which)
def roundtrip(self):
self.send_dnd_command_to_kitten('PING')
self.wait_for_responses('PONG')
def tearDown(self):
dnd_set_test_write_func(None)
dnd_test_cleanup_fake_window(self.capture.os_window_id)
@@ -93,6 +126,31 @@ class TestDnDKitten(BaseTest):
self.pty = None
def test_dnd_kitten_drop(self):
for remote_client in (False, True):
with self.subTest(remote_client=remote_client):
self.finish_setup(remote_client=remote_client)
self.finish_setup(remote_client=False)
self.dnd_kitten_drop(False)
def test_dnd_kitten_drop_remote(self):
self.finish_setup(remote_client=True)
self.dnd_kitten_drop(True)
def dnd_kitten_drop(self, remote_client):
copy, move = self.get_button_geometry()
all_mimes = 'text/uri-list a/b c/d'
for b, expected in ((copy, GLFW_DRAG_OPERATION_COPY), (move, GLFW_DRAG_OPERATION_MOVE)):
self.send_dnd_command_to_kitten(all_mimes, t='m', x=str(b[0] + 1), y=str(b[1] + 1))
self.wait_for_state('drop_action', expected)
self.assertEqual('text/uri-list', self.probe_state('drop_mimes').rstrip('\x00'))
self.send_dnd_command_to_kitten('DROP_MIMES')
self.wait_for_responses(all_mimes)
self.send_dnd_command_to_kitten(t='m', x='-1', y='-1')
self.send_dnd_command_to_kitten('DROP_MIMES')
self.wait_for_responses('')
large_mimes = (all_mimes + ' ') * 300
self.assertGreater(len(large_mimes), 4096)
self.send_dnd_command_to_kitten(all_mimes, t='m', x=str(copy[0] + 1), y=str(copy[1] + 1))
self.wait_for_state('drop_action', GLFW_DRAG_OPERATION_COPY)
self.send_dnd_command_to_kitten('DROP_MIMES')
self.wait_for_responses(all_mimes)
self.send_dnd_command_to_kitten(t='m', x='-1', y='-1')
self.send_dnd_command_to_kitten('DROP_MIMES')
self.wait_for_responses('')