From 8a6aa42d98f3615a89db224e1f24f3c7fb5d868a Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 27 Jan 2023 09:50:39 +0800 Subject: [PATCH 1/3] Add GTK probe. --- gtk/src/toga_gtk/libs/styles.py | 22 ++++++++---- gtk/tests_backend/__init__.py | 0 gtk/tests_backend/widgets/__init__.py | 0 gtk/tests_backend/widgets/base.py | 47 +++++++++++++++++++++++++ gtk/tests_backend/widgets/button.py | 25 +++++++++++++ gtk/tests_backend/widgets/label.py | 29 +++++++++++++++ gtk/tests_backend/widgets/properties.py | 34 ++++++++++++++++++ gtk/tests_backend/widgets/slider.py | 22 ++++++++++++ testbed/pyproject.toml | 3 ++ testbed/tests/widgets/test_button.py | 10 ++++++ testbed/tests/widgets/test_label.py | 7 ++++ testbed/tests/widgets/test_slider.py | 8 +++-- 12 files changed, 199 insertions(+), 8 deletions(-) create mode 100644 gtk/tests_backend/__init__.py create mode 100644 gtk/tests_backend/widgets/__init__.py create mode 100644 gtk/tests_backend/widgets/base.py create mode 100644 gtk/tests_backend/widgets/button.py create mode 100644 gtk/tests_backend/widgets/label.py create mode 100644 gtk/tests_backend/widgets/properties.py create mode 100644 gtk/tests_backend/widgets/slider.py diff --git a/gtk/src/toga_gtk/libs/styles.py b/gtk/src/toga_gtk/libs/styles.py index 996d18a5c6..73aa38be47 100644 --- a/gtk/src/toga_gtk/libs/styles.py +++ b/gtk/src/toga_gtk/libs/styles.py @@ -1,3 +1,5 @@ +from toga.colors import TRANSPARENT + from . import Gtk TOGA_DEFAULT_STYLES = b""" @@ -37,12 +39,20 @@ def get_color_css(value): def get_bg_color_css(value): - return ( - ".toga-bg-color {" - f"background-color: rgba({value.r}, {value.g}, {value.b}, {value.a});" - "background-image: none;" - "}" - ) + if value == TRANSPARENT: + return ( + ".toga-bg-color {" + "background-color: rgba(0, 0, 0, 0);" + "background-image: none;" + "}" + ) + else: + return ( + ".toga-bg-color {" + f"background-color: rgba({value.r}, {value.g}, {value.b}, {value.a});" + "background-image: none;" + "}" + ) def get_font_css(value): diff --git a/gtk/tests_backend/__init__.py b/gtk/tests_backend/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/gtk/tests_backend/widgets/__init__.py b/gtk/tests_backend/widgets/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/gtk/tests_backend/widgets/base.py b/gtk/tests_backend/widgets/base.py new file mode 100644 index 0000000000..0538037f8d --- /dev/null +++ b/gtk/tests_backend/widgets/base.py @@ -0,0 +1,47 @@ +from pytest import skip + +from toga_gtk.libs import Gtk + + +class SimpleProbe: + def __init__(self, widget): + self.widget = widget + self.impl = widget._impl + self.native = widget._impl.native + assert isinstance(self.native, self.native_class) + + def assert_container(self, container): + container_native = container._impl.native + for control in container_native.get_children(): + if control == self.native: + break + else: + raise ValueError(f"cannot find {self.native} in {container_native}") + + async def redraw(self): + """Request a redraw of the app, waiting until that redraw has completed.""" + # Refresh the layout + self.widget.window.content.refresh() + + # Force a repaint + while Gtk.events_pending(): + Gtk.main_iteration_do(blocking=False) + + @property + def enabled(self): + skip("enabled probe not implemented") + + @property + def hidden(self): + skip("hidden probe not implemented") + + @property + def width(self): + return self.native.get_allocation().width + + @property + def height(self): + return self.native.get_allocation().height + + def press(self): + skip("Press probe not implemented") diff --git a/gtk/tests_backend/widgets/button.py b/gtk/tests_backend/widgets/button.py new file mode 100644 index 0000000000..422ae75d3b --- /dev/null +++ b/gtk/tests_backend/widgets/button.py @@ -0,0 +1,25 @@ +from pytest import skip + +from toga_gtk.libs import Gtk + +from .base import SimpleProbe + + +class ButtonProbe(SimpleProbe): + native_class = Gtk.Button + + @property + def text(self): + return self.native.get_label() + + @property + def color(self): + skip("color probe not implemented") + + @property + def font(self): + skip("font probe not implemented") + + @property + def background_color(self): + skip("background color probe not implemented") diff --git a/gtk/tests_backend/widgets/label.py b/gtk/tests_backend/widgets/label.py new file mode 100644 index 0000000000..ac94895af6 --- /dev/null +++ b/gtk/tests_backend/widgets/label.py @@ -0,0 +1,29 @@ +from pytest import skip + +from toga_gtk.libs import Gtk + +from .base import SimpleProbe + + +class LabelProbe(SimpleProbe): + native_class = Gtk.Label + + @property + def text(self): + return self.native.get_label() + + @property + def color(self): + skip("color probe not implemented") + + @property + def background_color(self): + skip("background color probe not implemented") + + @property + def font(self): + skip("font probe not implemented") + + @property + def alignment(self): + skip("alignment probe not implemented") diff --git a/gtk/tests_backend/widgets/properties.py b/gtk/tests_backend/widgets/properties.py new file mode 100644 index 0000000000..c62b123307 --- /dev/null +++ b/gtk/tests_backend/widgets/properties.py @@ -0,0 +1,34 @@ +from dataclasses import dataclass + +from toga.fonts import NORMAL +from toga.style.pack import CENTER, JUSTIFY, LEFT, RIGHT +from toga_gtk.libs import Gtk, Pango + + +def toga_color(color): + return color + + +@dataclass +class Font: + family: str + size: int + style: str = NORMAL + variant: str = NORMAL + weight: str = NORMAL + + +def toga_font(font): + return Font( + family=font.get_family(), + size=font.get_size() / Pango.SCALE, + ) + + +def toga_alignment(alignment): + return { + (0.0, Gtk.Justification.LEFT): LEFT, + (1.0, Gtk.Justification.RIGHT): RIGHT, + (0.5, Gtk.Justification.CENTER): CENTER, + (0.0, Gtk.Justification.FILL): JUSTIFY, + }[alignment] diff --git a/gtk/tests_backend/widgets/slider.py b/gtk/tests_backend/widgets/slider.py new file mode 100644 index 0000000000..3a882d550b --- /dev/null +++ b/gtk/tests_backend/widgets/slider.py @@ -0,0 +1,22 @@ +from toga_gtk.libs import Gtk + +from .base import SimpleProbe + + +class SliderProbe(SimpleProbe): + native_class = Gtk.Scale + + @property + def position(self): + return (self.native.get_value() - self._min) / (self._max - self._min) + + def change(self, position): + self.native.set_value(self._min + round(position * (self._max - self._min))) + + @property + def _min(self): + return self.impl.adj.get_lower() + + @property + def _max(self): + return self.impl.adj.get_upper() diff --git a/testbed/pyproject.toml b/testbed/pyproject.toml index ccd8d5d0b0..01a3d7e4b5 100644 --- a/testbed/pyproject.toml +++ b/testbed/pyproject.toml @@ -37,6 +37,9 @@ test_sources = [ ] [tool.briefcase.app.testbed.linux] +test_sources = [ + "../gtk/tests_backend", +] requires = [ "../gtk", ] diff --git a/testbed/tests/widgets/test_button.py b/testbed/tests/widgets/test_button.py index 0b96aaaf5c..bdd458ece9 100644 --- a/testbed/tests/widgets/test_button.py +++ b/testbed/tests/widgets/test_button.py @@ -24,6 +24,12 @@ async def widget(): return toga.Button("Hello") +test_text_width_change = mark.skipif( + current_platform in {"linux"}, + reason="resizes not applying correctly", +)(test_text_width_change) + + async def test_press(widget, probe): # Press the button before installing a handler probe.press() @@ -52,6 +58,10 @@ async def test_background_color_transparent(widget, probe): current_platform in {"android"}, reason="await redraw() not implemented", ) +@mark.skipif( + current_platform in {"linux"}, + reason="resizes not applying correctly", +) async def test_button_size(widget, probe): "Check that the button resizes" # Container is initially a non-flex row box. diff --git a/testbed/tests/widgets/test_label.py b/testbed/tests/widgets/test_label.py index b02a29a7f8..c034af1320 100644 --- a/testbed/tests/widgets/test_label.py +++ b/testbed/tests/widgets/test_label.py @@ -1,6 +1,7 @@ from pytest import approx, fixture, mark import toga +from toga.platform import current_platform from toga.style.pack import CENTER, COLUMN, JUSTIFY, LEFT, LTR, RIGHT, RTL from .properties import ( # noqa: F401 @@ -20,6 +21,12 @@ async def widget(): return toga.Label("hello") +test_text_width_change = mark.skipif( + current_platform in {"linux"}, + reason="resizes not applying correctly", +)(test_text_width_change) + + # TODO: a `width` test, for any widget whose width depends on its text. @mark.skip("changing text does not trigger a refresh (#1289)") async def test_multiline(widget, probe): diff --git a/testbed/tests/widgets/test_slider.py b/testbed/tests/widgets/test_slider.py index 3a7bee19cd..e43ac0daa3 100644 --- a/testbed/tests/widgets/test_slider.py +++ b/testbed/tests/widgets/test_slider.py @@ -31,7 +31,7 @@ async def test_init(widget, probe, on_change): @mark.skipif( - current_platform in ["windows", "macOS"], + current_platform in {"windows", "macOS", "linux"}, reason="on_change called 2 times", ) @mark.skipif(current_platform == "android", reason="position is 0.0") @@ -46,9 +46,13 @@ async def test_value(widget, probe, on_change): @mark.skipif( - current_platform in ["android", "windows", "macOS"], + current_platform in {"android", "windows", "macOS"}, reason="on_change called 0 times", ) +@mark.skipif( + current_platform in {"linux"}, + reason="min/max value not correct", +) async def test_change(widget, probe, on_change): for scale in SCALES: widget.range = (0, scale) From 7b17c8aa261b5061562446525d4fc7aefe7eab82 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 27 Jan 2023 09:53:58 +0800 Subject: [PATCH 2/3] Add changenote. --- changes/1755.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/1755.misc.rst diff --git a/changes/1755.misc.rst b/changes/1755.misc.rst new file mode 100644 index 0000000000..4be0a85b1e --- /dev/null +++ b/changes/1755.misc.rst @@ -0,0 +1 @@ +A GTK GUI test probe was added. From cc5e96089c96e4d37603c078efb8f1c794a24193 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 27 Jan 2023 09:55:33 +0800 Subject: [PATCH 3/3] Add tests_backend to manifest. --- gtk/MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/gtk/MANIFEST.in b/gtk/MANIFEST.in index ecd14299d5..6fb7b6c41f 100644 --- a/gtk/MANIFEST.in +++ b/gtk/MANIFEST.in @@ -2,3 +2,4 @@ include CONTRIBUTING.md include LICENSE include README.rst recursive-include tests *.py +recursive-include tests_backend *.py