test_notification.test_scenario()   A
last analyzed

Complexity

Conditions 3

Size

Total Lines 48
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 30
dl 0
loc 48
rs 9.16
c 0
b 0
f 0
cc 3
nop 0
1
import pytest
2
3
from software_patterns import Observer, Subject
4
5
6
def test_observers_sanity_test():
7
    subject1: Subject = Subject([])
8
    subject2: Subject = Subject([])
9
    assert hasattr(subject1, '_observers')
10
    assert hasattr(subject2, '_observers')
11
    assert id(subject1._observers) != id(subject2._observers)
12
13
14
# def test_observer_as_constructor(observer: t.Type[Observer]):
15
def test_observer_as_constructor():
16
17
    import sys
18
    observer = Observer
19
20
    with pytest.raises(TypeError) as instantiation_from_interface_error:
21
        _observer_instance = observer()  # type: ignore[abstract]
22
23
    error_msg = str(instantiation_from_interface_error.value)
24
    if sys.version_info >= (3, 12):
25
        expected = "Can't instantiate abstract class Observer without an implementation for abstract method 'update'"
26
        assert error_msg == expected
27
    else:
28
        import re
29
        runtime_exception_message_reg = r"Can't instantiate abstract class Observer with abstract methods? update"
30
        assert re.match(runtime_exception_message_reg, error_msg)
31
32
33
# def test_scenario(subject: t.Type[Subject], observer: t.Type[Observer]):
34
def test_scenario():
35
    # Scenario 1
36
    # The client code.
37
    class ObserverA(Observer):
38
        def update(self, *args, **kwargs) -> None:
39
            print("ObserverA: Reacted to the event")
40
41
    s1: Subject = Subject([])
42
    o1 = ObserverA()
43
    s1.attach(o1)
44
45
    # business logic
46
    s1.state = 0
47
    s1.notify()
48
49
    # Scenario 2
50
    class Businessubject(Subject):
51
        def some_business_logic(self) -> None:
52
            """
53
            Usually, the subscription logic is only a fraction of what a Subject can
54
            really do. Subjects commonly hold some important business logic, that
55
            triggers a notification method whenever something important is about to
56
            happen (or after it).
57
            """
58
            print("\nSubject: I'm doing something important.")
59
            self._state = 2
60
            print(f"Subject: My state has just changed to: {self._state}")
61
            self.notify()
62
63
    class ObserverB(Observer):
64
        def update(self, *args, **kwargs) -> None:
65
            subject = args[0]
66
            if subject.state == 0 or subject.state >= 2:
67
                print("ObserverB: Reacted to the event")
68
69
    s2 = Businessubject([])
70
    assert id(s1) != id(s2)
71
    assert id(s1._observers) != id(s2._observers)
72
    o1, o2 = ObserverA(), ObserverB()
73
74
    s2.add(o1, o2)
75
    # business logic
76
    print(s2._observers)
77
    s2.some_business_logic()
78
    s2.some_business_logic()
79
80
    s2.detach(o1)
81
    s2.some_business_logic()
82