From 329e0acd8110f7dbae6a20137686f6e8e534eeb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mose=20M=C3=BCller?= Date: Tue, 5 Dec 2023 12:48:58 +0100 Subject: [PATCH] adds observer_pattern tests --- .../observable/test_observable.py | 159 ++++++++++ .../observable/test_observable_object.py | 282 ++++++++++++++++++ .../observer/test_observer.py | 25 ++ 3 files changed, 466 insertions(+) create mode 100644 tests/observer_pattern/observable/test_observable.py create mode 100644 tests/observer_pattern/observable/test_observable_object.py create mode 100644 tests/observer_pattern/observer/test_observer.py diff --git a/tests/observer_pattern/observable/test_observable.py b/tests/observer_pattern/observable/test_observable.py new file mode 100644 index 0000000..dc09d81 --- /dev/null +++ b/tests/observer_pattern/observable/test_observable.py @@ -0,0 +1,159 @@ +import logging +from typing import Any + +import pytest +from pydase.observer_pattern.observable import Observable +from pydase.observer_pattern.observer import Observer + +logger = logging.getLogger(__name__) + + +class MyObserver(Observer): + def on_change(self, full_access_path: str, value: Any) -> None: + logger.info("'%s' changed to '%s'", full_access_path, value) + + +def test_simple_class_attribute(caplog: pytest.LogCaptureFixture) -> None: + class MyObservable(Observable): + int_attribute = 10 + + instance = MyObservable() + observer = MyObserver(instance) + instance.int_attribute = 12 + + assert "'int_attribute' changed to '12'" in caplog.text + + +def test_simple_instance_attribute(caplog: pytest.LogCaptureFixture) -> None: + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.int_attribute = 10 + + instance = MyObservable() + observer = MyObserver(instance) + instance.int_attribute = 12 + + assert "'int_attribute' changed to '12'" in caplog.text + + +def test_nested_class_attribute(caplog: pytest.LogCaptureFixture) -> None: + class MySubclass(Observable): + name = "My Subclass" + + class MyObservable(Observable): + subclass = MySubclass() + + instance = MyObservable() + observer = MyObserver(instance) + instance.subclass.name = "Other name" + + assert "'subclass.name' changed to 'Other name'" in caplog.text + + +def test_nested_instance_attribute(caplog: pytest.LogCaptureFixture) -> None: + class MySubclass(Observable): + def __init__(self) -> None: + super().__init__() + self.name = "Subclass name" + + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.subclass = MySubclass() + + instance = MyObservable() + observer = MyObserver(instance) + instance.subclass.name = "Other name" + + assert "'subclass.name' changed to 'Other name'" in caplog.text + + +def test_removed_observer_on_class_attr(caplog: pytest.LogCaptureFixture) -> None: + class NestedObservable(Observable): + name = "Hello" + + nested_instance = NestedObservable() + + class MyObservable(Observable): + nested_attr = nested_instance + changed_attr = nested_instance + + instance = MyObservable() + observer = MyObserver(instance) + instance.changed_attr = "Ciao" + + assert "'changed_attr' changed to 'Ciao'" in caplog.text + caplog.clear() + + instance.nested_attr.name = "Hi" + + assert "'nested_attr.name' changed to 'Hi'" in caplog.text + assert "'changed_attr.name' changed to 'Hi'" not in caplog.text + + +def test_removed_observer_on_instance_attr(caplog: pytest.LogCaptureFixture) -> None: + class NestedObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.name = "Hello" + + nested_instance = NestedObservable() + + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.nested_attr = nested_instance + self.changed_attr = nested_instance + + instance = MyObservable() + observer = MyObserver(instance) + instance.changed_attr = "Ciao" + + assert "'changed_attr' changed to 'Ciao'" in caplog.text + caplog.clear() + + instance.nested_attr.name = "Hi" + + assert "'nested_attr.name' changed to 'Hi'" in caplog.text + assert "'changed_attr.name' changed to 'Hi'" not in caplog.text + + +def test_property_getter(caplog: pytest.LogCaptureFixture) -> None: + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self._name = "Hello" + + @property + def name(self) -> str: + """The name property.""" + return self._name + + instance = MyObservable() + observer = MyObserver(instance) + _ = instance.name + + assert "'name' changed to 'Hello'" in caplog.text + + +def test_property_setter(caplog: pytest.LogCaptureFixture) -> None: + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self._name = "Hello" + + @property + def name(self) -> str: + return self._name + + @name.setter + def name(self, value: str) -> None: + self._name = value + + instance = MyObservable() + observer = MyObserver(instance) + instance.name = "Ciao" + + assert "'name' changed to 'Hello'" not in caplog.text + assert "'name' changed to 'Ciao'" in caplog.text diff --git a/tests/observer_pattern/observable/test_observable_object.py b/tests/observer_pattern/observable/test_observable_object.py new file mode 100644 index 0000000..d12f927 --- /dev/null +++ b/tests/observer_pattern/observable/test_observable_object.py @@ -0,0 +1,282 @@ +import logging +from typing import Any + +import pytest +from pydase.observer_pattern.observable import Observable +from pydase.observer_pattern.observer import Observer + +logger = logging.getLogger(__name__) + + +class MyObserver(Observer): + def on_change(self, full_access_path: str, value: Any) -> None: + logger.info("'%s' changed to '%s'", full_access_path, value) + + +def test_simple_instance_list_attribute(caplog: pytest.LogCaptureFixture) -> None: + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.list_attr = [1, 2] + + instance = MyObservable() + observer = MyObserver(instance) + instance.list_attr[0] = 12 + + assert "'list_attr[0]' changed to '12'" in caplog.text + + +def test_instance_object_list_attribute(caplog: pytest.LogCaptureFixture) -> None: + class NestedObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.name = "Hello" + + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.list_attr = [NestedObservable()] + + instance = MyObservable() + observer = MyObserver(instance) + instance.list_attr[0].name = "Ciao" + + assert "'list_attr[0].name' changed to 'Ciao'" in caplog.text + + +def test_simple_class_list_attribute(caplog: pytest.LogCaptureFixture) -> None: + class MyObservable(Observable): + list_attr = [1, 2] + + instance = MyObservable() + observer = MyObserver(instance) + instance.list_attr[0] = 12 + + assert "'list_attr[0]' changed to '12'" in caplog.text + + +def test_class_object_list_attribute(caplog: pytest.LogCaptureFixture) -> None: + class NestedObservable(Observable): + name = "Hello" + + class MyObservable(Observable): + list_attr = [NestedObservable()] + + instance = MyObservable() + observer = MyObserver(instance) + instance.list_attr[0].name = "Ciao" + + assert "'list_attr[0].name' changed to 'Ciao'" in caplog.text + + +def test_simple_instance_dict_attribute(caplog: pytest.LogCaptureFixture) -> None: + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.dict_attr = {"first": "Hello"} + + instance = MyObservable() + observer = MyObserver(instance) + instance.dict_attr["first"] = "Ciao" + instance.dict_attr["second"] = "World" + + assert "'dict_attr['first']' changed to 'Ciao'" in caplog.text + assert "'dict_attr['second']' changed to 'World'" in caplog.text + + +def test_simple_class_dict_attribute(caplog: pytest.LogCaptureFixture) -> None: + class MyObservable(Observable): + dict_attr = {"first": "Hello"} + + instance = MyObservable() + observer = MyObserver(instance) + instance.dict_attr["first"] = "Ciao" + instance.dict_attr["second"] = "World" + + assert "'dict_attr['first']' changed to 'Ciao'" in caplog.text + assert "'dict_attr['second']' changed to 'World'" in caplog.text + + +def test_instance_dict_attribute(caplog: pytest.LogCaptureFixture) -> None: + class NestedObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.name = "Hello" + + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.dict_attr = {"first": NestedObservable()} + + instance = MyObservable() + observer = MyObserver(instance) + instance.dict_attr["first"].name = "Ciao" + + assert "'dict_attr['first'].name' changed to 'Ciao'" in caplog.text + + +def test_class_dict_attribute(caplog: pytest.LogCaptureFixture) -> None: + class NestedObservable(Observable): + name = "Hello" + + class MyObservable(Observable): + dict_attr = {"first": NestedObservable()} + + instance = MyObservable() + observer = MyObserver(instance) + instance.dict_attr["first"].name = "Ciao" + + assert "'dict_attr['first'].name' changed to 'Ciao'" in caplog.text + + +def test_removed_observer_on_class_list_attr(caplog: pytest.LogCaptureFixture) -> None: + class NestedObservable(Observable): + name = "Hello" + + nested_instance = NestedObservable() + + class MyObservable(Observable): + nested_attr = nested_instance + changed_list_attr = [nested_instance] + + instance = MyObservable() + observer = MyObserver(instance) + instance.changed_list_attr[0] = "Ciao" + + assert "'changed_list_attr[0]' changed to 'Ciao'" in caplog.text + caplog.clear() + + instance.nested_attr.name = "Hi" + + assert "'nested_attr.name' changed to 'Hi'" in caplog.text + assert "'changed_list_attr[0].name' changed to 'Hi'" not in caplog.text + + +def test_removed_observer_on_instance_dict_attr( + caplog: pytest.LogCaptureFixture, +) -> None: + class NestedObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.name = "Hello" + + nested_instance = NestedObservable() + + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.nested_attr = nested_instance + self.changed_dict_attr = {"nested": nested_instance} + + instance = MyObservable() + observer = MyObserver(instance) + instance.changed_dict_attr["nested"] = "Ciao" + + assert "'changed_dict_attr['nested']' changed to 'Ciao'" in caplog.text + caplog.clear() + + instance.nested_attr.name = "Hi" + + assert "'nested_attr.name' changed to 'Hi'" in caplog.text + assert "'changed_dict_attr['nested'].name' changed to 'Hi'" not in caplog.text + + +def test_removed_observer_on_instance_list_attr( + caplog: pytest.LogCaptureFixture, +) -> None: + class NestedObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.name = "Hello" + + nested_instance = NestedObservable() + + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.nested_attr = nested_instance + self.changed_list_attr = [nested_instance] + + instance = MyObservable() + observer = MyObserver(instance) + instance.changed_list_attr[0] = "Ciao" + + assert "'changed_list_attr[0]' changed to 'Ciao'" in caplog.text + caplog.clear() + + instance.nested_attr.name = "Hi" + + assert "'nested_attr.name' changed to 'Hi'" in caplog.text + assert "'changed_list_attr[0].name' changed to 'Hi'" not in caplog.text + + +def test_removed_observer_on_class_dict_attr(caplog: pytest.LogCaptureFixture) -> None: + class NestedObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.name = "Hello" + + nested_instance = NestedObservable() + + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.nested_attr = nested_instance + self.changed_dict_attr = {"nested": nested_instance} + + instance = MyObservable() + observer = MyObserver(instance) + instance.changed_dict_attr["nested"] = "Ciao" + + assert "'changed_dict_attr['nested']' changed to 'Ciao'" in caplog.text + caplog.clear() + + instance.nested_attr.name = "Hi" + + assert "'nested_attr.name' changed to 'Hi'" in caplog.text + assert "'changed_dict_attr['nested'].name' changed to 'Hi'" not in caplog.text + + +def test_nested_dict_instances(caplog: pytest.LogCaptureFixture) -> None: + dict_instance = {"first": "Hello", "second": "World"} + + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.nested_dict_attr = {"nested": dict_instance} + + instance = MyObservable() + observer = MyObserver(instance) + instance.nested_dict_attr["nested"]["first"] = "Ciao" + + assert "'nested_dict_attr['nested']['first']' changed to 'Ciao'" in caplog.text + + +def test_dict_in_list_instance(caplog: pytest.LogCaptureFixture) -> None: + dict_instance = {"first": "Hello", "second": "World"} + + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.dict_in_list = [dict_instance] + + instance = MyObservable() + observer = MyObserver(instance) + instance.dict_in_list[0]["first"] = "Ciao" + + assert "'dict_in_list[0]['first']' changed to 'Ciao'" in caplog.text + + +def test_list_in_dict_instance(caplog: pytest.LogCaptureFixture) -> None: + list_instance = [1, 2, 3] + + class MyObservable(Observable): + def __init__(self) -> None: + super().__init__() + self.list_in_dict = {"some_list": list_instance} + + instance = MyObservable() + observer = MyObserver(instance) + instance.list_in_dict["some_list"][0] = "Ciao" + + assert "'list_in_dict['some_list'][0]' changed to 'Ciao'" in caplog.text diff --git a/tests/observer_pattern/observer/test_observer.py b/tests/observer_pattern/observer/test_observer.py new file mode 100644 index 0000000..80d5702 --- /dev/null +++ b/tests/observer_pattern/observer/test_observer.py @@ -0,0 +1,25 @@ +from typing import Any + +import pytest +from pydase.observer_pattern.observable import Observable +from pydase.observer_pattern.observer import Observer + + +def test_abstract_method_error() -> None: + class MyObserver(Observer): + pass + + class MyObservable(Observable): + pass + + with pytest.raises(TypeError): + MyObserver(MyObservable()) + + +def test_constructor_error() -> None: + class MyObserver(Observer): + def on_change(self, full_access_path: str, value: Any) -> None: + pass + + with pytest.raises(TypeError): + MyObserver()