diff --git a/patterns/behavioral/publish_subscribe.py b/patterns/behavioral/publish_subscribe.py index 0cb3fc52..abd8fac1 100644 --- a/patterns/behavioral/publish_subscribe.py +++ b/patterns/behavioral/publish_subscribe.py @@ -50,41 +50,43 @@ def run(self, msg): def main(): - message_center = Provider() - - fftv = Publisher(message_center) - - jim = Subscriber("jim", message_center) - jim.subscribe("cartoon") - jack = Subscriber("jack", message_center) - jack.subscribe("music") - gee = Subscriber("gee", message_center) - gee.subscribe("movie") - vani = Subscriber("vani", message_center) - vani.subscribe("movie") - vani.unsubscribe("movie") - - fftv.publish("cartoon") - fftv.publish("music") - fftv.publish("ads") - fftv.publish("movie") - fftv.publish("cartoon") - fftv.publish("cartoon") - fftv.publish("movie") - fftv.publish("blank") - - message_center.update() + """ + >>> message_center = Provider() + + >>> fftv = Publisher(message_center) + + >>> jim = Subscriber("jim", message_center) + >>> jim.subscribe("cartoon") + >>> jack = Subscriber("jack", message_center) + >>> jack.subscribe("music") + >>> gee = Subscriber("gee", message_center) + >>> gee.subscribe("movie") + >>> vani = Subscriber("vani", message_center) + >>> vani.subscribe("movie") + >>> vani.unsubscribe("movie") + + # Note that no one subscirbed to `ads` + # and that vani changed their mind + + >>> fftv.publish("cartoon") + >>> fftv.publish("music") + >>> fftv.publish("ads") + >>> fftv.publish("movie") + >>> fftv.publish("cartoon") + >>> fftv.publish("cartoon") + >>> fftv.publish("movie") + >>> fftv.publish("blank") + + >>> message_center.update() + jim got cartoon + jack got music + gee got movie + jim got cartoon + jim got cartoon + gee got movie + """ if __name__ == "__main__": - main() - - -OUTPUT = """ -jim got cartoon -jack got music -gee got movie -jim got cartoon -jim got cartoon -gee got movie -""" + import doctest + doctest.testmod() diff --git a/patterns/behavioral/specification.py b/patterns/behavioral/specification.py index 9cd85d86..f125859a 100644 --- a/patterns/behavioral/specification.py +++ b/patterns/behavioral/specification.py @@ -88,25 +88,23 @@ def is_satisfied_by(self, candidate): def main(): - print('Specification') - andrey = User() - ivan = User(super_user=True) - vasiliy = 'not User instance' + """ + >>> andrey = User() + >>> ivan = User(super_user=True) + >>> vasiliy = 'not User instance' - root_specification = UserSpecification().and_specification(SuperUserSpecification()) + >>> root_specification = UserSpecification().and_specification(SuperUserSpecification()) - print(root_specification.is_satisfied_by(andrey)) - print(root_specification.is_satisfied_by(ivan)) - print(root_specification.is_satisfied_by(vasiliy)) + # Is specification satisfied by + >>> root_specification.is_satisfied_by(andrey), 'andrey' + (False, 'andrey') + >>> root_specification.is_satisfied_by(ivan), 'ivan' + (True, 'ivan') + >>> root_specification.is_satisfied_by(vasiliy), 'vasiliy' + (False, 'vasiliy') + """ if __name__ == '__main__': - main() - - -OUTPUT = """ -Specification -False -True -False -""" + import doctest + doctest.testmod() diff --git a/patterns/behavioral/state.py b/patterns/behavioral/state.py index 32f11d77..971da428 100644 --- a/patterns/behavioral/state.py +++ b/patterns/behavioral/state.py @@ -62,29 +62,27 @@ def scan(self): self.state.scan() -# Test our radio out def main(): - radio = Radio() - actions = [radio.scan] * 2 + [radio.toggle_amfm] + [radio.scan] * 2 - actions *= 2 - - for action in actions: - action() + """ + >>> radio = Radio() + >>> actions = [radio.scan] * 2 + [radio.toggle_amfm] + [radio.scan] * 2 + >>> actions *= 2 + + >>> for action in actions: + ... action() + Scanning... Station is 1380 AM + Scanning... Station is 1510 AM + Switching to FM + Scanning... Station is 89.1 FM + Scanning... Station is 103.9 FM + Scanning... Station is 81.3 FM + Scanning... Station is 89.1 FM + Switching to AM + Scanning... Station is 1250 AM + Scanning... Station is 1380 AM + """ if __name__ == '__main__': - main() - - -OUTPUT = """ -Scanning... Station is 1380 AM -Scanning... Station is 1510 AM -Switching to FM -Scanning... Station is 89.1 FM -Scanning... Station is 103.9 FM -Scanning... Station is 81.3 FM -Scanning... Station is 89.1 FM -Switching to AM -Scanning... Station is 1250 AM -Scanning... Station is 1380 AM -""" + import doctest + doctest.testmod() diff --git a/patterns/creational/borg.py b/patterns/creational/borg.py index dd0df0ba..83b42142 100644 --- a/patterns/creational/borg.py +++ b/patterns/creational/borg.py @@ -19,12 +19,6 @@ added to the instance's attribute dictionary, but, since the attribute dictionary itself is shared (which is __shared_state), all other attributes will also be shared. -For this reason, when the attribute self.state is modified using -instance rm2, the value of self.state in instance rm1 also changes. The -same happens if self.state is modified using rm3, which is an -instance from a subclass. -Notice that even though they share attributes, the instances are not -the same, as seen by their ids. *Where is the pattern used practically? Sharing state is useful in applications like managing database connections: @@ -53,37 +47,44 @@ class YourBorg(Borg): pass -if __name__ == '__main__': - rm1 = Borg() - rm2 = Borg() +def main(): + """ + >>> rm1 = Borg() + >>> rm2 = Borg() - rm1.state = 'Idle' - rm2.state = 'Running' + >>> rm1.state = 'Idle' + >>> rm2.state = 'Running' - print('rm1: {0}'.format(rm1)) - print('rm2: {0}'.format(rm2)) + >>> print('rm1: {0}'.format(rm1)) + rm1: Running + >>> print('rm2: {0}'.format(rm2)) + rm2: Running - rm2.state = 'Zombie' + # When the `state` attribute is modified from instance `rm2`, + # the value of `state` in instance `rm1` also changes + >>> rm2.state = 'Zombie' - print('rm1: {0}'.format(rm1)) - print('rm2: {0}'.format(rm2)) + >>> print('rm1: {0}'.format(rm1)) + rm1: Zombie + >>> print('rm2: {0}'.format(rm2)) + rm2: Zombie - print('rm1 id: {0}'.format(id(rm1))) - print('rm2 id: {0}'.format(id(rm2))) + # Even though `rm1` and `rm2` share attributes, the instances are not the same + >>> rm1 is rm2 + False - rm3 = YourBorg() + # Shared state is also modified from a subclass instance `rm3` + >>> rm3 = YourBorg() - print('rm1: {0}'.format(rm1)) - print('rm2: {0}'.format(rm2)) - print('rm3: {0}'.format(rm3)) + >>> print('rm1: {0}'.format(rm1)) + rm1: Init + >>> print('rm2: {0}'.format(rm2)) + rm2: Init + >>> print('rm3: {0}'.format(rm3)) + rm3: Init + """ -### OUTPUT ### -# rm1: Running -# rm2: Running -# rm1: Zombie -# rm2: Zombie -# rm1 id: 140732837899224 -# rm2 id: 140732837899296 -# rm1: Init -# rm2: Init -# rm3: Init + +if __name__ == "__main__": + import doctest + doctest.testmod() diff --git a/tests/test_outputs.py b/tests/test_outputs.py deleted file mode 100644 index 95d04cf8..00000000 --- a/tests/test_outputs.py +++ /dev/null @@ -1,26 +0,0 @@ -from contextlib import redirect_stdout -import io - -import pytest - -from patterns.behavioral.publish_subscribe import main as publish_subscribe_main -from patterns.behavioral.publish_subscribe import OUTPUT as publish_subscribe_output -from patterns.behavioral.specification import main as specification_main -from patterns.behavioral.specification import OUTPUT as specification_output -from patterns.behavioral.state import main as state_main -from patterns.behavioral.state import OUTPUT as state_output - - -@pytest.mark.parametrize("main,output", [ - (publish_subscribe_main, publish_subscribe_output), - (specification_main, specification_output), - (state_main, state_output), -]) -def test_output(main, output): - f = io.StringIO() - with redirect_stdout(f): - main() - - real_output = f.getvalue().strip() - expected_output = output.strip() - assert real_output == expected_output