Source code for enable.testing

# (C) Copyright 2005-2022 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
from unittest.mock import Mock

from traits.api import Undefined

from enable.abstract_window import AbstractWindow
from enable.events import DragEvent, KeyEvent, MouseEvent
from kiva.testing import KivaTestAssistant


class _MockWindow(AbstractWindow):

    # FIXME: for some reason I cannot replace these functions with a Mock
    def _get_control_size(self):
        return 0, 0

    def _redraw(self, coordinates=None):
        pass

    _drag_result = None

    def set_drag_result(self, result):
        self._drag_result = result


[docs]class EnableTestAssistant(KivaTestAssistant): """ Mixin helper for enable/chaco components. """
[docs] def press_move_release(self, interactor, points, window=None, alt_down=False, control_down=False, shift_down=False): """ Simulate the action of left click pressing, dragging and releasing the mouse. Parameters ---------- interactor : enable interactor object This is object where the mouse events will be dispatched to. points : A list of x,y tuple The x,y positions of the three event sections. The first tuple will be sent with a left-down event and the last will be sent with a left-up. All the other events in the list will be sent using a mouse-move event. window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. If the window has a mouse owner then that interactor is used. If a non-Mocked window is used, then either the test should not require the use of get_pointer_position() or should use a mock for the method. alt_down : boolean, optional The button is pressed while `alt` is down. Default value is False. control_down : boolean, optional The button is pressed while `control` is down. Default value is False. shift_down : boolean, optional The button is pressed while `shift` is down. Default value is False. """ x, y = points[0] window = self.create_mock_window() if window is None else window self.mouse_down( interactor, x, y, "left", window=window, alt_down=alt_down, control_down=control_down, shift_down=shift_down, ) for x, y in points[1:-1]: self.mouse_move( interactor, x, y, window=window, alt_down=alt_down, control_down=control_down, shift_down=shift_down, left_down=True, ) x, y = points[-1] self.mouse_up( interactor, x, y, "left", window=window, alt_down=alt_down, control_down=control_down, shift_down=shift_down, )
[docs] def create_mock_window(self): """ Creates a Mock class that behaves as an enable Abstract Window. Returns ------- window : Mock A mock class instance of an abstract window. """ window = _MockWindow() window._capture_mouse = Mock() window.set_pointer = Mock() window._release_mouse = Mock() window._redraw = Mock() window.control = Mock() window.control.set_pointer = Mock() window.get_pointer_position = Mock() return window
[docs] def create_key_press(self, key, window=None, alt_down=False, control_down=False, shift_down=False): """ Creates a KeyEvent for the given Key. Parameters ---------- key : string The key of the event window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. alt_down : boolean, optional The key is pressed while `alt` is down. Default value is False. control_down : boolean, optional The key is pressed while `control` is down. Default value is False. shift_down : boolean, optional The key is pressed while `shift` is down. Default value is False. Returns ------- key_event : KeyEvent The enable KEyEvent instance of the desired event ready to be passed to an enable Interactor. """ key_event = KeyEvent( character=key, event_type="key_pressed", alt_down=alt_down, control_down=control_down, shift_down=shift_down, ) if window is None: key_event.window = self.create_mock_window() else: key_event.window = window return key_event
[docs] def create_mouse_event(self, **kwargs): """ Creates a MouseEvent() with the specified attributes. """ # provide defaults for all key shift states event_attributes = { # key shift states "alt_down": False, "control_down": False, "shift_down": False, "mouse_wheel": 0, "mouse_wheel_axis": "vertical", } event_attributes.update(**kwargs) event = MouseEvent(**event_attributes) return event
[docs] def create_drag_event(self, **kwargs): """ Creates a DragEvent() with the specified attributes. """ event = DragEvent(**kwargs) return event
[docs] def mouse_down(self, interactor, x, y, button="left", window=None, alt_down=False, control_down=False, shift_down=False): """ Send a mouse button down event to the interactor. Parameters ---------- interactor : Interactor The interactor (or subclass) where to dispatch the event. x : float The x coordinates of the mouse position y : float The y coordinates of the mouse position button : {'left', 'right'}, optional The mouse button for which to simulate a press (down) action. window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. If the window has a mouse owner then that interactor is used. alt_down : boolean, optional The button is pressed while `alt` is down. Default value is False. control_down : boolean, optional The button is pressed while `control` is down. Default value is False. shift_down : boolean, optional The button is pressed while `shift` is down. Default value is False. Returns ------- event : MouseEvent The event instance after it has be processed by the `interactor`. """ window = self.create_mock_window() if window is None else window event_attributes = { "x": x, "y": y, "alt_down": alt_down, "control_down": control_down, "shift_down": shift_down, "{0}_down".format(button): True, "window": window, } event = self.create_mouse_event(**event_attributes) self._mouse_event_dispatch( interactor, event, "{0}_down".format(button) ) return event
[docs] def mouse_dclick(self, interactor, x, y, button="left", window=None, alt_down=False, control_down=False, shift_down=False): """ Send a mouse double-click event to the interactor. Parameters ---------- interactor : Interactor The interactor (or subclass) where to dispatch the event. x : float The x coordinates of the mouse position y : float The y coordinates of the mouse position button : {'left', 'right'}, optional The mouse button for which to simulate a press (down) action. window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. If the window has a mouse owner then that interactor is used. alt_down : boolean, optional The button is pressed while `alt` is down. Default value is False. control_down : boolean, optional The button is pressed while `control` is down. Default value is False. shift_down : boolean, optional The button is pressed while `shift` is down. Default value is False. Returns ------- event : MouseEvent The event instance after it has be processed by the `interactor`. """ window = self.create_mock_window() if window is None else window event_attributes = { "x": x, "y": y, "alt_down": alt_down, "control_down": control_down, "shift_down": shift_down, "{0}_down".format(button): True, "window": window, } event = self.create_mouse_event(**event_attributes) self._mouse_event_dispatch( interactor, event, "{0}_dclick".format(button) ) return event
[docs] def mouse_move(self, interactor, x, y, window=None, alt_down=False, control_down=False, shift_down=False, left_down=Undefined, middle_down=Undefined, right_down=Undefined): """ Send a mouse move event to the interactor. Parameters ---------- interactor : Interactor The interactor (or subclass) where to dispatch the event. x : float The x coordinates of the mouse position y : float The y coordinates of the mouse position window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. If the window has a mouse owner then that interactor is used. If a non-Mocked window is used, then either the test should not require the use of get_pointer_position() or should use a mock for the method. alt_down : boolean, optional The mouse is moved while `alt` is down. Default value is False. control_down : boolean, optional The mouse is moved while `control` is down. Default value is False. shift_down : boolean, optional The mouse is moved while `shift` is down. Default value is False. left_down : boolean, optional The mouse is moved while `left` is down. Default value is Undefined. middle_down : boolean, optional The mouse is moved while `middle` is down. Default value is Undefined. right_down : boolean, optional The mouse is moved while `right` is down. Default value is Undefined. Returns ------- event : MouseEvent The event instance after it has be processed by the `interactor`. """ window = self.create_mock_window() if window is None else window event = self.create_mouse_event( x=x, y=y, window=window, alt_down=alt_down, control_down=control_down, shift_down=shift_down, left_down=left_down, middle_down=middle_down, right_down=right_down, ) if hasattr(window.get_pointer_position, "return_value"): # Note: Non-mock windows shouldn't try to get pointer position window.get_pointer_position.return_value = (x, y) self._mouse_event_dispatch(interactor, event, "mouse_move") return event
[docs] def mouse_up(self, interactor, x, y, button="left", window=None, alt_down=False, control_down=False, shift_down=False): """ Send a mouse button up event to the interactor. Parameters ---------- interactor : Interactor The interactor (or subclass) where to dispatch the event. x : float The x coordinates of the mouse position y : float The y coordinates of the mouse position button : {'left', 'right'}, optional The mouse button for which to simulate a release (up) action. window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. If the window has a mouse owner then that interactor is used. alt_down : boolean, optional The button is pressed while `alt` is down. Default value is False. control_down : boolean, optional The button is pressed while `control` is down. Default value is False. shift_down : boolean, optional The button is pressed while `shift` is down. Default value is False. Returns ------- event : MouseEvent The event instance after it has be processed by the `interactor`. """ window = self.create_mock_window() if window is None else window event = self.create_mouse_event( x=x, y=y, window=window, alt_down=alt_down, control_down=control_down, shift_down=shift_down, ) self._mouse_event_dispatch(interactor, event, "{0}_up".format(button)) return event
[docs] def mouse_leave(self, interactor, x, y, window=None, alt_down=False, control_down=False, shift_down=False): """ Send a mouse leave event to the interactor. Parameters ---------- interactor : Interactor The interactor (or subclass) where to dispatch the event. x : float The x coordinates of the mouse position y : float The y coordinates of the mouse position window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. If the window has a mouse owner then that interactor is used. alt_down : boolean, optional The button is pressed while `alt` is down. Default value is False. control_down : boolean, optional The button is pressed while `control` is down. Default value is False. shift_down : boolean, optional The button is pressed while `shift` is down. Default value is False. Returns ------- event : MouseEvent The event instance after it has be processed by the `interactor`. """ window = self.create_mock_window() if window is None else window event = self.create_mouse_event( x=x, y=y, window=window, alt_down=alt_down, control_down=control_down, shift_down=shift_down, ) self._mouse_event_dispatch(interactor, event, "mouse_leave") return event
[docs] def mouse_enter(self, interactor, x, y, window=None, alt_down=False, control_down=False, shift_down=False): """ Send a mouse enter event to the interactor. Parameters ---------- interactor : Interactor The interactor (or subclass) where to dispatch the event. x : float The x coordinates of the mouse position y : float The y coordinates of the mouse position window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. If the window has a mouse owner then that interactor is used. alt_down : boolean, optional The button is pressed while `alt` is down. Default value is False. control_down : boolean, optional The button is pressed while `control` is down. Default value is False. shift_down : boolean, optional The button is pressed while `shift` is down. Default value is False. Returns ------- event : MouseEvent The event instance after it has be processed by the `interactor`. """ window = self.create_mock_window() if window is None else window event = self.create_mouse_event( x=x, y=y, window=window, alt_down=alt_down, control_down=control_down, shift_down=shift_down, ) self._mouse_event_dispatch(interactor, event, "mouse_enter") return event
[docs] def send_key(self, interactor, key, window=None): """ Sent a key press event to the interactor. Parameters ---------- interactor : Interactor The interactor (or subclass) where to dispatch the event. key : string The key press to simulate. window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. If the window has a focus owner then that interactor is used. Returns ------- event : KeyEvent The event instance after it has be processed by the `interactor`. """ window = self.create_mock_window() if window is None else window event = self.create_key_press(key, window=window) self._key_event_dispatch(interactor, event) return event
[docs] def send_drag_over(self, interactor, x, y, obj, window=None): """ Sent a drag_over event to the interactor. Parameters ---------- interactor : Interactor The interactor (or subclass) where to dispatch the event. x : float The x coordinates of the mouse position y : float The y coordinates of the mouse position obj : object The object(s) being dragged or dropped window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. If the window has a mouse owner then that interactor is used. Returns ------- event : KeyEvent The event instance after it has be processed by the `interactor`. """ window = self.create_mock_window() if window is None else window event = self.create_drag_event(x=x, y=y, obj=obj, window=window) self._drag_event_dispatch(interactor, event, "drag_over") return event
[docs] def send_dropped_on(self, interactor, x, y, obj, window=None): """ Sent a dropped_on event to the interactor. Parameters ---------- interactor : Interactor The interactor (or subclass) where to dispatch the event. x : float The x coordinates of the mouse position y : float The y coordinates of the mouse position obj : object The object(s) being dragged or dropped window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. If the window has a mouse owner then that interactor is used. Returns ------- event : KeyEvent The event instance after it has be processed by the `interactor`. """ window = self.create_mock_window() if window is None else window event = self.create_drag_event(x=x, y=y, obj=obj, window=window) self._drag_event_dispatch(interactor, event, "dropped_on") return event
[docs] def send_drag_leave(self, interactor, x, y, window=None): """ Sent a drag_leave event to the interactor. Parameters ---------- interactor : Interactor The interactor (or subclass) where to dispatch the event. x : float The x coordinates of the mouse position y : float The y coordinates of the mouse position window : AbstractWindow, optional The enable AbstractWindow to associate with the event. Default is to create a mock class instance. If the window has a mouse owner then that interactor is used. Returns ------- event : KeyEvent The event instance after it has be processed by the `interactor`. """ window = self.create_mock_window() if window is None else window event = self.create_drag_event(x=x, y=y, window=window) self._drag_event_dispatch(interactor, event, "drag_leave") return event
def _mouse_event_dispatch(self, interactor, event, suffix): mouse_owner = event.window.mouse_owner if mouse_owner is None: interactor.dispatch(event, suffix) else: mouse_owner.dispatch(event, suffix) def _key_event_dispatch(self, interactor, event): focus_owner = event.window.focus_owner if focus_owner is None: interactor.dispatch(event, "key_pressed") else: focus_owner.dispatch(event, "key_pressed") def _drag_event_dispatch(self, interactor, event, suffix): interactor.dispatch(event, suffix)