toga/gtk/tests_backend/app.py
2024-04-24 15:04:14 +08:00

205 lines
6.9 KiB
Python

from pathlib import Path
import PIL.Image
import pytest
import toga
from toga_gtk.keys import gtk_accel, toga_key
from toga_gtk.libs import Gdk, Gtk
from .probe import BaseProbe
class AppProbe(BaseProbe):
supports_key = True
supports_key_mod3 = True
def __init__(self, app):
super().__init__()
self.app = app
assert isinstance(self.app._impl.native, Gtk.Application)
@property
def config_path(self):
return Path.home() / ".config/testbed"
@property
def data_path(self):
return Path.home() / ".local/share/testbed"
@property
def cache_path(self):
return Path.home() / ".cache/testbed"
@property
def logs_path(self):
return Path.home() / ".local/state/testbed/log"
@property
def is_cursor_visible(self):
pytest.skip("Cursor visibility not implemented on GTK")
def is_full_screen(self, window):
return bool(
window._impl.native.get_window().get_state() & Gdk.WindowState.FULLSCREEN
)
def content_size(self, window):
content_allocation = window._impl.container.get_allocation()
return (content_allocation.width, content_allocation.height)
def assert_app_icon(self, icon):
for window in self.app.windows:
# We have no real way to check we've got the right icon; use pixel peeping as a
# guess. Construct a PIL image from the current icon.
img = toga.Image(window._impl.native.get_icon()).as_format(PIL.Image.Image)
if icon:
# The explicit alt icon has blue background, with green at a point 1/3 into
# the image
assert img.getpixel((5, 5)) == (211, 230, 245)
mid_color = img.getpixel((img.size[0] // 3, img.size[1] // 3))
assert mid_color == (0, 204, 9)
else:
# The default icon is transparent background, and brown in the center.
assert img.getpixel((5, 5))[3] == 0
mid_color = img.getpixel((img.size[0] // 2, img.size[1] // 2))
assert mid_color == (149, 119, 73, 255)
def _menu_item(self, path):
main_menu = self.app._impl.native.get_menubar()
menu = main_menu
orig_path = path.copy()
try:
while True:
label, path = path[0], path[1:]
items = {}
for index in range(menu.get_n_items()):
section = menu.get_item_link(index, "section")
if section:
for section_index in range(section.get_n_items()):
items[
section.get_item_attribute_value(
section_index, "label"
).get_string()
] = (section, section_index)
else:
items[
menu.get_item_attribute_value(index, "label").get_string()
] = (menu, index)
if label == "*":
item = items[self.app.formal_name]
else:
item = items[label]
menu = item[0].get_item_link(item[1], "submenu")
except IndexError:
pass
except AttributeError:
raise AssertionError(f"Menu {' > '.join(orig_path)} not found")
action = item[0].get_item_attribute_value(item[1], "action")
if action:
action_name = (
item[0].get_item_attribute_value(item[1], "action").get_string()
)
cmd_id = action_name.split(".")[1]
action = self.app._impl.native.lookup_action(cmd_id)
return item, action
def _activate_menu_item(self, path):
_, action = self._menu_item(path)
action.emit("activate", None)
def activate_menu_exit(self):
self._activate_menu_item(["*", "Quit Toga Testbed"])
def activate_menu_about(self):
self._activate_menu_item(["Help", "About Toga Testbed"])
async def close_about_dialog(self):
self.app._impl._close_about(self.app._impl.native_about_dialog)
def activate_menu_visit_homepage(self):
# Homepage is a link on the GTK about page.
pytest.xfail("GTK doesn't have a visit homepage menu item")
def assert_system_menus(self):
self.assert_menu_item(["*", "Preferences"], enabled=False)
self.assert_menu_item(["*", "Quit Toga Testbed"], enabled=True)
self.assert_menu_item(["Help", "About Toga Testbed"], enabled=True)
def activate_menu_close_window(self):
pytest.xfail("GTK doesn't have a window management menu items")
def activate_menu_close_all_windows(self):
pytest.xfail("GTK doesn't have a window management menu items")
def activate_menu_minimize(self):
pytest.xfail("GTK doesn't have a window management menu items")
def assert_menu_item(self, path, enabled):
_, action = self._menu_item(path)
assert action.get_enabled() == enabled
def assert_menu_order(self, path, expected):
item, action = self._menu_item(path)
menu = item[0].get_item_link(item[1], "submenu")
# Loop over the sections
actual = []
for index in range(menu.get_n_items()):
section = menu.get_item_link(index, "section")
if section:
if actual:
actual.append("---")
for section_index in range(section.get_n_items()):
actual.append(
section.get_item_attribute_value(
section_index, "label"
).get_string()
)
else:
actual.append(
section.get_item_attribute_value(index, "label").get_string()
)
assert actual == expected
def keystroke(self, combination):
accel = gtk_accel(combination)
state = 0
if "<Primary>" in accel:
state |= Gdk.ModifierType.CONTROL_MASK
accel = accel.replace("<Primary>", "")
if "<Alt>" in accel:
state |= Gdk.ModifierType.META_MASK
accel = accel.replace("<Alt>", "")
if "<Hyper>" in accel:
state |= Gdk.ModifierType.HYPER_MASK
accel = accel.replace("<Hyper>", "")
if "<Shift>" in accel:
state |= Gdk.ModifierType.SHIFT_MASK
accel = accel.replace("<Shift>", "")
keyval = getattr(
Gdk,
f"KEY_{accel}",
{
"!": Gdk.KEY_exclam,
"<home>": Gdk.KEY_Home,
"F5": Gdk.KEY_F5,
}.get(accel, None),
)
event = Gdk.Event.new(Gdk.EventType.KEY_PRESS)
event.keyval = keyval
event.length = 1
event.is_modifier = state != 0
event.state = state
return toga_key(event)