From c9a917aefb3c99fe980a64963debeca25143b6f7 Mon Sep 17 00:00:00 2001 From: Drachenfels Date: Wed, 8 May 2024 00:08:41 +0100 Subject: [PATCH 1/2] Add first test suite and make sure renpy is not needed to run it. --- tests/__init__.py | 0 tests/conftest.py | 21 ++++++++++++ tests/test_nqtr_button.py | 67 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_nqtr_button.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..09e23c4 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,21 @@ +import builtins +from unittest.mock import MagicMock, patch + +import pytest + + +@pytest.fixture(autouse=True) +def mock_renpy(monkeypatch): + """This trick overrides for time of testing need to have renpy in the sys.path. + + Rationale is that we want to test NQTR library and and renpy usually is installed + globally somewhere else in the OS. + """ + import_orig = builtins.__import__ + + def mocked_import(name, *args, **kwargs): + if name in ("renpy.exports", "renpy.character", "renpy"): + return MagicMock() + return import_orig(name, *args, **kwargs) + + monkeypatch.setattr(builtins, "__import__", mocked_import) diff --git a/tests/test_nqtr_button.py b/tests/test_nqtr_button.py new file mode 100644 index 0000000..3553325 --- /dev/null +++ b/tests/test_nqtr_button.py @@ -0,0 +1,67 @@ +import pytest + + +def test_button(): + """Base tests, to prove that default button state is one we expect""" + from pythonpackages.nqtr.button import Button + + some_button = Button() + + assert some_button.align == (0, 0) + assert some_button.name == "" + assert some_button.label_name is None + assert some_button.button_icon is None + assert some_button.button_icon_selected is None + assert some_button.picture_in_background is None + assert some_button.picture_in_background_selected is None + assert some_button.xalign == 0 + assert some_button.yalign == 0 + assert some_button.hidden is False + assert some_button.default_label_name is None + + +def test_align_not_working_as_expected(): + """Previously this test was showcasing problem with align""" + from pythonpackages.nqtr.button import Button + + some_button = Button() + + assert type(some_button.align) is tuple + assert some_button.align == (0, 0) + + some_button.xalign = 0 + + assert type(some_button.align) is tuple + assert some_button.align == (0, 0) + + +@pytest.mark.parametrize( + "xalign,yalign,xexpected,yexpected", + [ + (0, 0, 0, 0), + (1, 1, 1, 1), + (-1, -1, -1, -1), + (1.1, 1.2, 1.1, 1.2), + (-1.1, -1.2, -1.1, -1.2), + ("", "", 0, 0), + (False, False, 0, 0), + (None, None, 0, 0), + ({}, {}, 0, 0), + ("0", "0", "0", "0"), + ], +) +def test_button_aligns_accept_any_param_except_none( + xalign, yalign, xexpected, yexpected +): + """Check if various xalign, yalign attributes are properly saved to the class, all + Falsey values should be converted to 0 (special caveat for "0", it's not False-y, + but some may thing it is) + """ + from pythonpackages.nqtr.button import Button + + some_button = Button(xalign=xalign, yalign=yalign) + + assert some_button.xalign == xexpected + assert some_button.yalign == yexpected + assert type(some_button.xalign) is type(xexpected) + assert type(some_button.yalign) is type(yexpected) From d40f8aaef3f32a6a3e86bb9a826e67fc87cf2bc3 Mon Sep 17 00:00:00 2001 From: Drachenfels Date: Wed, 8 May 2024 00:12:39 +0100 Subject: [PATCH 2/2] Fix errors detected by tests and make code somewhat more 'pythonic' --- pythonpackages/nqtr/button.py | 126 ++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 61 deletions(-) diff --git a/pythonpackages/nqtr/button.py b/pythonpackages/nqtr/button.py index 9bb6eba..12145f7 100644 --- a/pythonpackages/nqtr/button.py +++ b/pythonpackages/nqtr/button.py @@ -1,6 +1,6 @@ from typing import Optional, Union -from pythonpackages.nqtr.disabled_solution import DisabledClass +from pythonpackages.nqtr.disabled_solution import DisabledClass from pythonpackages.renpy_utility.flags import * from pythonpackages.renpy_utility.renpy_custom_log import * from pythonpackages.renpy_utility.utility import * @@ -9,6 +9,9 @@ class Button(DisabledClass): """Wiki: https://github.com/DRincs-Productions/NQTR-toolkit/wiki/Button""" + _align = (0, 0) + _name = "" + def __init__( self, name: Optional[str] = None, @@ -25,8 +28,6 @@ def __init__( ): # DisabledClass init super().__init__(disabled=disabled) - # Button init - self.align = None self.name = name self.label_name = label_name @@ -34,10 +35,8 @@ def __init__( self.button_icon_selected = button_icon_selected self.picture_in_background = picture_in_background self.picture_in_background_selected = picture_in_background_selected - if not xalign == None: - self.xalign = xalign - if not yalign == None: - self.yalign = yalign + self.xalign = 0 if xalign is None else xalign + self.yalign = 0 if yalign is None else yalign self.hidden = hidden self.default_label_name = default_label_name @@ -48,23 +47,28 @@ def name(self) -> str: @name.setter def name(self, value: Optional[str]): - self._name = value or "" - if isNullOrEmpty(self._name): + if not value: log_warn("You have set name to None or empty", "nqtr.button.Button.name") + return + + self._name = value + @property def label_name(self) -> Optional[str]: """onClick label name""" - if not isNullOrEmpty(self._label_name): + if self._label_name: return self._label_name - elif not isNullOrEmpty(self.default_label_name): + + if self.default_label_name: return self.default_label_name - else: - log_warn( - "In the button " + self.name + ", label_name is null or empty", - "nqtr.button.Button.label_name", - ) - return + + log_warn( + f"In the button {self.name}, label_name is null or empty", + "nqtr.button.Button.label_name", + ) + + return None @label_name.setter def label_name(self, value: Optional[str]): @@ -73,16 +77,16 @@ def label_name(self, value: Optional[str]): @property def button_icon(self) -> Optional[str]: """Button icon""" - if not isNullOrEmpty(self._button_icon): + if self._button_icon: return self._button_icon - else: - log_warn( - "In the button " - + self.name - + ", button_icon is null or empty, use is_button_icon to check if it is a button icon button", - "nqtr.button.Button.button_icon", - ) - return None + + log_warn( + f"In the button {self.name}, " + "button_icon is null or empty, " + "use is_button_icon to check if it is a button icon button", + "nqtr.button.Button.button_icon", + ) + return None @button_icon.setter def button_icon(self, value: Optional[str]): @@ -91,10 +95,10 @@ def button_icon(self, value: Optional[str]): @property def button_icon_selected(self) -> Optional[str]: """Selected button icon""" - if not isNullOrEmpty(self._button_icon_selected): + if self._button_icon_selected: return self._button_icon_selected - else: - return self.button_icon + + return self.button_icon @button_icon_selected.setter def button_icon_selected(self, value: Optional[str]): @@ -102,11 +106,12 @@ def button_icon_selected(self, value: Optional[str]): @property def picture_in_background(self) -> Optional[str]: - """Picture in background: Is an button that is started by clicking on an image in the room.""" - if not isNullOrEmpty(self._picture_in_background): + """Picture in background: Is an button that is started by clicking on an image + in the room.""" + if self._picture_in_background: return self._picture_in_background - else: - return None + + return None @picture_in_background.setter def picture_in_background(self, value: Optional[str]): @@ -115,10 +120,10 @@ def picture_in_background(self, value: Optional[str]): @property def picture_in_background_selected(self) -> Optional[str]: """Selected picture in background""" - if not isNullOrEmpty(self._picture_in_background_selected): + if self._picture_in_background_selected: return self._picture_in_background_selected - else: - return self.picture_in_background + + return self.picture_in_background @picture_in_background_selected.setter def picture_in_background_selected(self, value: Optional[str]): @@ -136,48 +141,46 @@ def align(self, value: Optional[tuple[Union[int, float], Union[int, float]]]): @property def xalign(self) -> Union[int, float]: """X align""" - if self._align != None: - return self._align[0] - else: + if self._align is None: return 0 + return self._align[0] + @xalign.setter def xalign(self, value: Optional[Union[int, float]]): - if value == None: + if not value and str(value) != "0": log_warn( - "In the button " - + self.name - + ", you have set xalign to None, use 0 instead", + f"In the button {self.name}, " + "you have set xalign to None or other booleani false, use 0 instead", "nqtr.button.Button.xalign", ) value = 0 - if self._align == None: - self._align = (value, 0) - else: - self._align = (value, self._align[1]) + + yval = 0 if self._align is None else self._align[1] + + self._align = (value, yval) @property def yalign(self) -> Union[int, float]: """Y align""" - if self._align != None: - return self._align[1] - else: + if self._align is None: return 0 + return self._align[1] + @yalign.setter def yalign(self, value: Optional[Union[int, float]]): - if value == None: + if not value and str(value) != "0": log_warn( - "In the button " - + self.name - + ", you have set yalign to None, use 0 instead", + f"In the button {self.name}, " + "you have set yalign to None or other booleani false, use 0 instead", "nqtr.button.Button.yalign", ) value = 0 - if self._align == None: - self._align = (0, value) - else: - self._align = (self._align[0], value) + + xval = 0 if self._align is None else self._align[0] + + self._align = (xval, value) @property def hidden(self) -> Union[bool, str]: @@ -213,11 +216,12 @@ def is_hidden( """ "If hidden is a string: get the value of the flags system""" if isinstance(self.hidden, str): return get_flags(self.hidden, flags) - elif ( + + if ( check_if_has_icon and not self.is_button and not self.is_picture_in_background ): return True - else: - return self.hidden + + return self.hidden