Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions Lib/test/test_tkinter/test_dnd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import unittest
import tkinter
from tkinter import dnd
from test.support import requires
from test.test_tkinter.support import setUpModule # noqa: F401
from test.test_tkinter.support import AbstractTkTest

requires('gui')


class Target:
def __init__(self, widget, log):
self.widget = widget
self.log = log
widget.dnd_accept = self.dnd_accept

def dnd_accept(self, source, event):
self.log.append('accept')
return self

def dnd_enter(self, source, event):
self.log.append('enter')

def dnd_motion(self, source, event):
self.log.append('motion')

def dnd_leave(self, source, event):
self.log.append('leave')

def dnd_commit(self, source, event):
self.log.append('commit')


class Source:
def __init__(self, log):
self.log = log

def dnd_end(self, target, event):
self.log.append('end')


class FakeEvent:
def __init__(self, widget, num=1):
self.num = num
self.widget = widget
self.x = self.y = self.x_root = self.y_root = 0


class DndTest(AbstractTkTest, unittest.TestCase):

def setUp(self):
super().setUp()
self.canvas = tkinter.Canvas(self.root)
self.canvas.pack()
# on_motion() locates the target with winfo_containing(). Bypass that
# real screen lookup, which depends on the window being visible and
# unobscured, so the test does not hinge on the window manager.
self.canvas.winfo_containing = lambda x, y: self.canvas
self.log = []
self.source = Source(self.log)
self.target = Target(self.canvas, self.log)

def test_drag_and_drop(self):
handler = dnd.dnd_start(self.source, FakeEvent(self.canvas))
self.assertIsNotNone(handler)
handler.on_motion(FakeEvent(self.canvas)) # Enter the target.
handler.on_motion(FakeEvent(self.canvas)) # Move within the target.
handler.on_release(FakeEvent(self.canvas)) # Drop on the target.
self.assertEqual(self.log,
['accept', 'enter', 'accept', 'motion', 'commit', 'end'])

def test_cancel(self):
handler = dnd.dnd_start(self.source, FakeEvent(self.canvas))
handler.on_motion(FakeEvent(self.canvas)) # Enter the target.
handler.cancel() # Leaves the target without committing.
self.assertEqual(self.log, ['accept', 'enter', 'leave', 'end'])

def test_no_target(self):
# Nothing under the pointer accepts the drag.
self.canvas.winfo_containing = lambda x, y: None
handler = dnd.dnd_start(self.source, FakeEvent(self.canvas))
handler.on_motion(FakeEvent(self.canvas))
handler.on_release(FakeEvent(self.canvas))
self.assertEqual(self.log, ['end'])

def test_no_recursive_start(self):
handler = dnd.dnd_start(self.source, FakeEvent(self.canvas))
self.assertIsNotNone(handler)
# A drag is already in progress, so a second start is ignored.
self.assertIsNone(dnd.dnd_start(self.source, FakeEvent(self.canvas)))
handler.cancel()

def test_high_button_number_ignored(self):
self.assertIsNone(dnd.dnd_start(self.source, FakeEvent(self.canvas, num=6)))


if __name__ == "__main__":
unittest.main()
Loading