From 99cd980b034ec3fd725e20e5a1168380eb869ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niko=20F=C3=B6hr?= Date: Sun, 21 Apr 2024 16:02:18 +0300 Subject: [PATCH 1/6] rename test class: TestActivateOneOfMethods --- tests/unit/test_core/test_mode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_core/test_mode.py b/tests/unit/test_core/test_mode.py index 80b4ef94..ede25fd9 100644 --- a/tests/unit/test_core/test_mode.py +++ b/tests/unit/test_core/test_mode.py @@ -328,7 +328,7 @@ def test_truthy_values(self, val): assert should_fake_success(val) is True -class TestActivateMode: +class TestActivateOneOfMethods: """tests for Mode._activate_one_of_methods""" def test_activate_without_methods(self): From ed6eda38e7a9cb2ba69c39db8a7d72390de26893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niko=20F=C3=B6hr?= Date: Sun, 21 Apr 2024 16:05:35 +0300 Subject: [PATCH 2/6] remove test of tests --- tests/unit/test_core/testmethods.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/tests/unit/test_core/testmethods.py b/tests/unit/test_core/testmethods.py index 54d05749..12483264 100644 --- a/tests/unit/test_core/testmethods.py +++ b/tests/unit/test_core/testmethods.py @@ -116,20 +116,3 @@ def iterate_test_methods( yield get_test_method_class( enter_mode=enter_mode_, heartbeat=heartbeat_, exit_mode=exit_mode_ )() - - -# Just test that iterating the test methods works as expected -_methods = list( - iterate_test_methods( - enter_mode=[METHOD_MISSING], - heartbeat=[ - METHOD_MISSING, - False, - "Failure reason", - ], - exit_mode=METHOD_OPTIONS, - ) -) -assert len(_methods) == 1 * 3 * 5 -assert all(isinstance(m, Method) for m in _methods) -del _methods From 7375bd0517cdf1af4392564ff0715c7531742b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niko=20F=C3=B6hr?= Date: Sun, 21 Apr 2024 16:06:53 +0300 Subject: [PATCH 3/6] rename: combinations_of_test_methods was: iterate_test_methods --- .../test_core/test_method/test_activation.py | 22 +++++++++---------- tests/unit/test_core/testmethods.py | 4 +++- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/unit/test_core/test_method/test_activation.py b/tests/unit/test_core/test_method/test_activation.py index 1385934b..d5371ea4 100644 --- a/tests/unit/test_core/test_method/test_activation.py +++ b/tests/unit/test_core/test_method/test_activation.py @@ -14,8 +14,8 @@ METHOD_MISSING, METHOD_OPTIONS, WakepyMethodTestError, + combinations_of_test_methods, get_test_method_class, - iterate_test_methods, ) from wakepy.core import Method, MethodActivationResult, PlatformName, get_methods from wakepy.core.constants import StageName, StageNameValue @@ -145,7 +145,7 @@ def test_enter_mode_failing(self): """Tests 1) F* from TABLE 1; enter_mode failing""" # Case: enter_mode raises exception - for method in iterate_test_methods( + for method in combinations_of_test_methods( enter_mode=[RuntimeError(FAILURE_REASON)], heartbeat=METHOD_OPTIONS, exit_mode=METHOD_OPTIONS, @@ -161,7 +161,7 @@ def test_enter_mode_failing(self): def test_enter_mode_missing_and_heartbeat(self): """Tests 2) MM from TABLE 1; missing both enter_mode and heartbeat""" - for method in iterate_test_methods( + for method in combinations_of_test_methods( enter_mode=[METHOD_MISSING], heartbeat=[METHOD_MISSING], exit_mode=METHOD_OPTIONS, @@ -182,7 +182,7 @@ def test_enter_mode_missing_and_heartbeat(self): def test_enter_mode_missing_heartbeat_failing(self): """Tests 3) MF from TABLE 1; enter_mode missing and heartbeat failing""" - for method in iterate_test_methods( + for method in combinations_of_test_methods( enter_mode=[METHOD_MISSING], heartbeat=[False], exit_mode=METHOD_OPTIONS, @@ -197,7 +197,7 @@ def test_enter_mode_missing_heartbeat_failing(self): assert "The only accepted return value is None" in err_message assert heartbeat_call_time is None - for method in iterate_test_methods( + for method in combinations_of_test_methods( enter_mode=[METHOD_MISSING], heartbeat=[FAILURE_REASON], exit_mode=METHOD_OPTIONS, @@ -218,7 +218,7 @@ def test_enter_mode_missing_heartbeat_success(self): expected_time = dt.datetime.strptime( "2023-12-21 16:17:00", "%Y-%m-%d %H:%M:%S" ).replace(tzinfo=dt.timezone.utc) - for method in iterate_test_methods( + for method in combinations_of_test_methods( enter_mode=[METHOD_MISSING], heartbeat=[None], exit_mode=METHOD_OPTIONS, @@ -230,7 +230,7 @@ def test_enter_mode_missing_heartbeat_success(self): def test_enter_mode_success_hearbeat_missing(self): """Tests 5) SM from TABLE 1; enter_mode success, heartbeat missing""" - for method in iterate_test_methods( + for method in combinations_of_test_methods( enter_mode=[None], heartbeat=[METHOD_MISSING], exit_mode=METHOD_OPTIONS, @@ -248,7 +248,7 @@ def test_enter_mode_success_heartbeat_failing(self): """ # Case: Heartbeate fails by raising RuntimeError - for method in iterate_test_methods( + for method in combinations_of_test_methods( enter_mode=[None], heartbeat=[RuntimeError(FAILURE_REASON)], exit_mode=[None, METHOD_MISSING], @@ -261,7 +261,7 @@ def test_enter_mode_success_heartbeat_failing(self): # Case: The heartbeat fails, and because enter_mode() has succeed, # wakepy tries to call exit_mode(). If that fails, the program must # crash, as we are in an unknown state and this is clearly an error. - for method in iterate_test_methods( + for method in combinations_of_test_methods( enter_mode=[None], heartbeat=[False, FAILURE_REASON], exit_mode=[False, FAILURE_REASON], @@ -278,7 +278,7 @@ def test_enter_mode_success_heartbeat_failing(self): # Case: Same as the one above, but this time exit_mode() raises a # WakepyMethodTestError. That is re-raised as RuntimeError, instead. # If this happens, the Method.exit_mode() has a bug. - for method in iterate_test_methods( + for method in combinations_of_test_methods( enter_mode=[None], heartbeat=[False, FAILURE_REASON], exit_mode=[WakepyMethodTestError("foo")], @@ -298,7 +298,7 @@ def test_enter_mode_success_heartbeat_success(self): "2023-12-21 16:17:00", "%Y-%m-%d %H:%M:%S" ).replace(tzinfo=dt.timezone.utc) - for method in iterate_test_methods( + for method in combinations_of_test_methods( enter_mode=[None], heartbeat=[None], exit_mode=METHOD_OPTIONS, diff --git a/tests/unit/test_core/testmethods.py b/tests/unit/test_core/testmethods.py index 12483264..1671ced6 100644 --- a/tests/unit/test_core/testmethods.py +++ b/tests/unit/test_core/testmethods.py @@ -105,11 +105,13 @@ def _create_class() -> Type[Method]: return _test_method_classes[key] -def iterate_test_methods( +def combinations_of_test_methods( enter_mode=Iterable, heartbeat=Iterable, exit_mode=Iterable, ) -> Iterable[Method]: + """Create an iterator of Methods over the combinations of the given + enter_mode, heartbeat and exit_mode""" for enter_mode_, heartbeat_, exit_mode_ in itertools.product( enter_mode, heartbeat, exit_mode ): From 1dc68c985da00e2f7a2dd1bd4ba66b87468f0770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niko=20F=C3=B6hr?= Date: Sun, 21 Apr 2024 16:18:30 +0300 Subject: [PATCH 4/6] add docstring for testmethods.py --- tests/unit/test_core/testmethods.py | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/unit/test_core/testmethods.py b/tests/unit/test_core/testmethods.py index 1671ced6..352ee055 100644 --- a/tests/unit/test_core/testmethods.py +++ b/tests/unit/test_core/testmethods.py @@ -1,3 +1,37 @@ +"""This module defines two important helpers for the tests + +1) get_test_method_class +A function which may used to create wakepy.Method classes using arguments. + +Example +------- +Create Method which return True from Method.caniuse() and raises a +RuntimeError in Method.enter_mode() + +>>> method_cls = get_test_method_class( + caniuse=True, enter_mode=RuntimeError("failed") +) + +2) combinations_of_test_methods +A function which returns an iterator for testing a cross product of different +Methods. This uses get_test_method_class underneath. + +Example +------- +>>> METHOD_OPTIONS = [ + METHOD_MISSING, + True, + False, + RunTimeError('foo'), +] +>>> for method in combinations_of_test_methods( + enter_mode=[METHOD_MISSING], + heartbeat=[METHOD_MISSING], + exit_mode=METHOD_OPTIONS, + ): + # test +""" + from __future__ import annotations import itertools From 63335e4de03df7f59d93addafb43304b0c165c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niko=20F=C3=B6hr?= Date: Sun, 21 Apr 2024 16:22:29 +0300 Subject: [PATCH 5/6] simplify test --- tests/unit/test_core/test_method/test_activation.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unit/test_core/test_method/test_activation.py b/tests/unit/test_core/test_method/test_activation.py index d5371ea4..ca7dd2f0 100644 --- a/tests/unit/test_core/test_method/test_activation.py +++ b/tests/unit/test_core/test_method/test_activation.py @@ -67,7 +67,7 @@ def test_activate_method_method_without_platform_support(self): def test_activate_method_method_caniuse_fails(self): # Case 1: Fail by returning False from caniuse - method = get_test_method_class(caniuse=False, enter_mode=True, exit_mode=True)() + method = get_test_method_class(caniuse=False)() res, heartbeat = activate_method(method) assert res.success is False assert res.failure_stage == StageName.REQUIREMENTS @@ -77,8 +77,6 @@ def test_activate_method_method_caniuse_fails(self): # Case 2: Fail by returning some error reason from caniuse method = get_test_method_class( caniuse="SomeSW version <2.1.5 not supported", - enter_mode=True, - exit_mode=True, )() res, heartbeat = activate_method(method) assert res.success is False From 6d9c867722350c833e54e11e9c1517df4eafd232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niko=20F=C3=B6hr?= Date: Sun, 21 Apr 2024 16:27:44 +0300 Subject: [PATCH 6/6] use single definition of TestMethod --- tests/conftest.py | 7 +------ tests/unit/test_core/conftest.py | 15 +++++---------- tests/unit/test_core/test_method/test_method.py | 6 +----- tests/unit/test_core/test_registry.py | 6 +----- tests/unit/test_core/testmethods.py | 5 +++++ 5 files changed, 13 insertions(+), 26 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 6ef29a03..08c9b32b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ import pytest -from wakepy import Method +from tests.unit.test_core.testmethods import TestMethod from wakepy.core.strenum import StrEnum if sys.version_info < (3, 8): # pragma: no-cover-if-py-gte-38 @@ -12,11 +12,6 @@ import typing -class TestMethod(Method): - __test__ = False # for pytest - mode = "_test" - - @pytest.fixture def method1(): return TestMethod() diff --git a/tests/unit/test_core/conftest.py b/tests/unit/test_core/conftest.py index 826cb504..110e9fc8 100644 --- a/tests/unit/test_core/conftest.py +++ b/tests/unit/test_core/conftest.py @@ -1,18 +1,9 @@ import pytest +from tests.unit.test_core.testmethods import TestMethod from wakepy.core import DBusAddress, DBusMethod, Method, PlatformName from wakepy.core.heartbeat import Heartbeat -# B, D, E -FIRST_MODE = "first_mode" -# A, F -SECOND_MODE = "second_mode" - - -class TestMethod(Method): - __test__ = False # for pytest - mode = "_test" - @pytest.fixture def heartbeat1(method1: Method): @@ -71,6 +62,10 @@ class MultiPlatformA(TestMethod): @pytest.fixture(scope="function") def provide_methods_a_f(monkeypatch, testutils): testutils.empty_method_registry(monkeypatch) + # B, D, E + FIRST_MODE = "first_mode" + # A, F + SECOND_MODE = "second_mode" class MethodA(TestMethod): name = "A" diff --git a/tests/unit/test_core/test_method/test_method.py b/tests/unit/test_core/test_method/test_method.py index 3406dbba..a974972d 100644 --- a/tests/unit/test_core/test_method/test_method.py +++ b/tests/unit/test_core/test_method/test_method.py @@ -5,6 +5,7 @@ import pytest +from tests.unit.test_core.testmethods import TestMethod from wakepy.core import DBusMethodCall from wakepy.core.method import ( Method, @@ -25,11 +26,6 @@ from wakepy.core import DBusMethod -class TestMethod(Method): - __test__ = False # for pytest - mode = "_test" - - def test_overridden_methods_autodiscovery(): """The enter_mode, heartbeat and exit_mode methods by default do nothing (on the Method base class). In subclasses, these are usually overriden. diff --git a/tests/unit/test_core/test_registry.py b/tests/unit/test_core/test_registry.py index 6f378f2c..94219690 100644 --- a/tests/unit/test_core/test_registry.py +++ b/tests/unit/test_core/test_registry.py @@ -2,15 +2,11 @@ import pytest +from tests.unit.test_core.testmethods import TestMethod from wakepy.core import Method, get_method, get_methods, get_methods_for_mode from wakepy.core.registry import register_method -class TestMethod(Method): - __test__ = False # for pytest - mode = "_test" - - @pytest.mark.usefixtures("empty_method_registry") def test_get_method_which_is_not_yet_defined(): # The method registry is empty so there is no Methods with the name diff --git a/tests/unit/test_core/testmethods.py b/tests/unit/test_core/testmethods.py index 352ee055..479ed0d8 100644 --- a/tests/unit/test_core/testmethods.py +++ b/tests/unit/test_core/testmethods.py @@ -42,6 +42,11 @@ from wakepy.core.method import Method +class TestMethod(Method): + __test__ = False # for pytest; this won't be interpreted as test class. + mode = "_test" + + class WakepyMethodTestError(Exception): ...