Skip to content

Commit

Permalink
add coverage for legacy hsm
Browse files Browse the repository at this point in the history
  • Loading branch information
aleneum committed Mar 18, 2020
1 parent 6104cad commit 70f42eb
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 27 deletions.
61 changes: 38 additions & 23 deletions tests/test_nesting.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from os.path import getsize
from os import unlink

from transitions.extensions.nesting import NestedState as State
from transitions.extensions.nesting import NestedState
from transitions.extensions import MachineFactory

from unittest import skipIf
Expand All @@ -28,7 +28,8 @@
except ImportError: # pragma: no cover
pgv = None

state_separator = State.separator

default_separator = NestedState.separator


class Dummy(object):
Expand All @@ -38,14 +39,14 @@ class Dummy(object):
class TestTransitions(TestsCore):

def setUp(self):
states = ['A', 'B', {'name': 'C', 'children': ['1', '2', {'name': '3', 'children': ['a', 'b', 'c']}]},
'D', 'E', 'F']
machine_cls = MachineFactory.get_predefined(nested=True)
self.stuff = Stuff(states, machine_cls)
self.states = ['A', 'B', {'name': 'C', 'children': ['1', '2', {'name': '3', 'children': ['a', 'b', 'c']}]},
'D', 'E', 'F']
self.machine_cls = MachineFactory.get_predefined(nested=True)
self.state_cls = NestedState
self.stuff = Stuff(self.states, self.machine_cls)

def tearDown(self):
State.separator = state_separator
pass
self.state_cls.separator = default_separator

def test_add_model(self):
model = Dummy()
Expand All @@ -62,7 +63,7 @@ def test_function_wrapper(self):

def test_init_machine_with_hella_arguments(self):
states = [
State('State1'),
self.state_cls('State1'),
'State2',
{
'name': 'State3',
Expand All @@ -82,15 +83,16 @@ def test_init_machine_with_hella_arguments(self):
self.assertEqual(s.message, 'Hello World!')

def test_init_machine_with_nested_states(self):
State = self.state_cls
a = State('A')
b = State('B')
b_1 = State('1')
b_2 = State('2')
b.add_substates([b_1, b_2])
m = self.stuff.machine_cls(states=[a, b])
self.assertEqual(m.states['B'].states['1'], b_1)
m.to("B{0}1".format(state_separator))
self.assertEqual(m.state, "B{0}1".format(state_separator))
m.to("B{0}1".format(State.separator))
self.assertEqual(m.state, "B{0}1".format(State.separator))

def test_property_initial(self):
# Define with list of dictionaries
Expand All @@ -109,6 +111,7 @@ def test_property_initial(self):
self.assertEqual(m.initial, 'initial')

def test_transition_definitions(self):
State = self.state_cls
states = ['A', 'B', {'name': 'C', 'children': ['1', '2', '3']}, 'D']
# Define with list of dictionaries
transitions = [
Expand Down Expand Up @@ -180,6 +183,7 @@ def test_conditions(self):
self.assertEqual(s.state, 'C')

def test_multiple_add_transitions_from_state(self):
State = self.state_cls
s = self.stuff
s.machine.add_transition(
'advance', 'A', 'B', conditions=['this_fails'])
Expand All @@ -201,6 +205,7 @@ def test_use_machine_as_model(self):
self.assertEqual(m.state, 'B')

def test_add_custom_state(self):
State = self.state_cls
s = self.stuff
s.machine.add_states([{'name': 'E', 'children': ['1', '2']}])
s.machine.add_state('E%s3' % State.separator)
Expand All @@ -215,6 +220,7 @@ def test_add_custom_state(self):
self.assertEqual('C{0}3{0}a'.format(State.separator), s.state)

def test_enter_exit_nested_state(self):
State = self.state_cls
mock = MagicMock()

def callback():
Expand All @@ -232,6 +238,7 @@ def callback():
self.assertEqual(mock.call_count, 3)

def test_state_change_listeners(self):
State = self.state_cls
s = self.stuff
s.machine.add_transition('advance', 'A', 'C%s1' % State.separator)
s.machine.add_transition('reverse', 'C', 'A')
Expand Down Expand Up @@ -262,6 +269,7 @@ def test_state_change_listeners(self):
self.assertTrue(s.message.startswith('So long'))

def test_enter_exit_nested(self):
State = self.state_cls
s = self.stuff
s.machine.add_transition('advance', 'A', 'C{0}3'.format(State.separator))
s.machine.add_transition('reverse', 'C', 'A')
Expand Down Expand Up @@ -312,6 +320,7 @@ def test_enter_exit_nested(self):
self.assertEqual(s.transitions, 24) # exit A; enter C, 3, a

def test_ordered_transitions(self):
State = self.state_cls
states = [{'name': 'first', 'children': ['second', 'third', {'name': 'fourth', 'children': ['fifth', 'sixth']},
'seventh']}, 'eighth', 'ninth']
m = self.stuff.machine_cls(states=states)
Expand Down Expand Up @@ -397,21 +406,21 @@ def test_callbacks_duplicate(self):
self.assertEqual(m.after_change.call_count, 2)

def test_with_custom_separator(self):
State.separator = '.'
self.state_cls.separator = '.'
self.setUp()
self.test_enter_exit_nested()
self.setUp()
self.test_state_change_listeners()
self.test_nested_auto_transitions()
State.separator = '.' if sys.version_info[0] < 3 else u'↦'
self.state_cls.separator = '.' if sys.version_info[0] < 3 else u'↦'
self.setUp()
self.test_enter_exit_nested()
self.setUp()
self.test_state_change_listeners()
self.test_nested_auto_transitions()

def test_with_slash_separator(self):
State.separator = '/'
self.state_cls.separator = '/'
self.setUp()
self.test_enter_exit_nested()
self.setUp()
Expand All @@ -421,6 +430,7 @@ def test_with_slash_separator(self):
self.test_ordered_transitions()

def test_nested_auto_transitions(self):
State = self.state_cls
s = self.stuff
s.to_C()
self.assertEqual(s.state, 'C')
Expand All @@ -436,6 +446,7 @@ def test_nested_auto_transitions(self):
self.assertEqual(len(s.machine.events[event_name].transitions), num_base_states)

def test_example_one(self):
State = self.state_cls
State.separator = '_'
states = ['standing', 'walking', {'name': 'caffeinated', 'children': ['dithering', 'running']}]
transitions = [['walk', 'standing', 'walking'],
Expand Down Expand Up @@ -463,6 +474,7 @@ def test_example_one(self):
machine.on_enter_caffeinated_running('callback_method')

def test_example_two(self):
State = self.state_cls
State.separator = '.' if sys.version_info[0] < 3 else u'↦'
states = ['A', 'B',
{'name': 'C', 'children': ['1', '2',
Expand Down Expand Up @@ -509,35 +521,37 @@ def test_excessive_nesting(self):
m = self.stuff.machine_cls(states=states, initial='A')

def test_intial_state(self):
separator = self.state_cls.separator
states = [{'name': 'A', 'children': ['1', '2'], 'initial': '2'},
{'name': 'B', 'initial': '2',
'children': ['1', {'name': '2', 'initial': 'a',
'children': ['a', 'b']}]}]
transitions = [['do', 'A', 'B'],
['do', 'B{0}2'.format(state_separator),
'B{0}1'.format(state_separator)]]
['do', 'B{0}2'.format(separator),
'B{0}1'.format(separator)]]
m = self.stuff.machine_cls(states=states, transitions=transitions, initial='A')
self.assertEqual(m.state, 'A{0}2'.format(state_separator))
self.assertEqual(m.state, 'A{0}2'.format(separator))
m.do()
self.assertEqual(m.state, 'B{0}2{0}a'.format(state_separator))
self.assertEqual(m.state, 'B{0}2{0}a'.format(separator))
self.assertTrue(m.is_B(allow_substates=True))
m.do()
self.assertEqual(m.state, 'B{0}1'.format(state_separator))
self.assertEqual(m.state, 'B{0}1'.format(separator))

def test_get_triggers(self):
seperator = self.state_cls.separator
states = ['standing', 'walking', {'name': 'caffeinated', 'children': ['dithering', 'running']}]
transitions = [
['walk', 'standing', 'walking'],
['go', 'standing', 'walking'],
['stop', 'walking', 'standing'],
{'trigger': 'drink', 'source': '*', 'dest': 'caffeinated_dithering',
{'trigger': 'drink', 'source': '*', 'dest': 'caffeinated{0}dithering'.format(seperator),
'conditions': 'is_hot', 'unless': 'is_too_hot'},
['walk', 'caffeinated_dithering', 'caffeinated_running'],
['walk', 'caffeinated{0}dithering'.format(seperator), 'caffeinated{0}running'.format(seperator)],
['relax', 'caffeinated', 'standing']
]

machine = self.stuff.machine_cls(states=states, transitions=transitions, auto_transitions=False)
trans = machine.get_triggers('caffeinated{0}dithering'.format(state_separator))
trans = machine.get_triggers('caffeinated{0}dithering'.format(seperator))
self.assertEqual(len(trans), 3)
self.assertTrue('relax' in trans)

Expand All @@ -553,14 +567,15 @@ def test_internal_transitions(self):
class TestWithGraphTransitions(TestTransitions):

def setUp(self):
State.separator = state_separator
states = ['A', 'B', {'name': 'C', 'children': ['1', '2', {'name': '3', 'children': ['a', 'b', 'c']}]},
'D', 'E', 'F']

machine_cls = MachineFactory.get_predefined(graph=True, nested=True)
self.state_cls = machine_cls.state_cls
self.stuff = Stuff(states, machine_cls)

def test_ordered_with_graph(self):
State = self.state_cls
GraphMachine = MachineFactory.get_predefined(graph=True, nested=True)

states = ['A', 'B', {'name': 'C', 'children': ['1', '2',
Expand Down
53 changes: 53 additions & 0 deletions tests/test_nesting_legacy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from .test_nesting import TestTransitions, Stuff
from transitions.extensions.nesting_legacy import HierarchicalMachine, NestedState


class TestNestedLegacy(TestTransitions):

def setUp(self):
super(TestNestedLegacy, self).setUp()
self.machine_cls = HierarchicalMachine
self.stuff = Stuff(self.states, self.machine_cls)
self.state_cls = NestedState

def test_add_custom_state(self):
s = self.stuff
s.machine.add_states([{'name': 'E', 'children': ['1', '2']}])
s.machine.add_state('3', parent='E')
s.machine.add_transition('go', '*', 'E%s1' % self.state_cls.separator)
s.machine.add_transition('walk', '*', 'E%s3' % self.state_cls.separator)
s.machine.add_transition('run', 'E', 'C{0}3{0}a'.format(self.state_cls.separator))
s.go()
self.assertEqual('E{0}1'.format(self.state_cls.separator), s.state)
s.walk()
self.assertEqual('E{0}3'.format(self.state_cls.separator), s.state)
s.run()
self.assertEqual('C{0}3{0}a'.format(self.state_cls.separator), s.state)

def test_init_machine_with_nested_states(self):
State = self.state_cls
a = State('A')
b = State('B')
b_1 = State('1', parent=b)
b_2 = State('2', parent=b)
m = self.stuff.machine_cls(states=[a, b])
self.assertEqual(b_1.name, 'B{0}1'.format(State.separator))
m.to("B{0}1".format(State.separator))

def test_transitioning(self):
State = self.state_cls
s = self.stuff
s.machine.add_transition('advance', 'A', 'B')
s.machine.add_transition('advance', 'B', 'C')
s.machine.add_transition('advance', 'C', 'D')
s.machine.add_transition('reset', '*', 'A')
self.assertEqual(len(s.machine.events['reset'].transitions['C%s1' % State.separator]), 1)
s.advance()
self.assertEqual(s.state, 'B')
self.assertFalse(s.is_A())
self.assertTrue(s.is_B())
s.advance()
self.assertEqual(s.state, 'C')

def test_nested_definitions(self):
pass
6 changes: 4 additions & 2 deletions tests/test_threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,12 @@ def test_model_context(self):
class TestLockedHierarchicalTransitions(TestsNested, TestLockedTransitions):

def setUp(self):
NestedState.separator = '_'
states = ['A', 'B', {'name': 'C', 'children': ['1', '2', {'name': '3', 'children': ['a', 'b', 'c']}]},
'D', 'E', 'F']
self.stuff = Stuff(states, machine_cls=MachineFactory.get_predefined(locked=True, nested=True))
self.machine_cls = MachineFactory.get_predefined(locked=True, nested=True)
self.state_cls = self.machine_cls.state_cls
self.state_cls.separator = '_'
self.stuff = Stuff(states, machine_cls=self.machine_cls)
self.stuff.heavy_processing = heavy_processing
self.stuff.machine.add_transition('forward', '*', 'B', before='heavy_processing')

Expand Down
7 changes: 5 additions & 2 deletions transitions/extensions/nesting_legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
from copy import copy, deepcopy
from functools import partial
import logging

from six import string_types

from ..core import Machine, Transition, State, Event, listify, MachineError, EventData, Enum
from ..extensions.nesting import FunctionWrapper
from .nesting import FunctionWrapper

_LOGGER = logging.getLogger(__name__)
_LOGGER.addHandler(logging.NullHandler())
Expand Down Expand Up @@ -431,6 +430,10 @@ def add_states(self, states, on_enter=None, on_exit=None,
args = self._buffered_transitions.pop(0)
self.add_transition(**args)

def get_nested_state_names(self):
""" Returns all states of the state machine. """
return self.states

def get_triggers(self, *args):
""" Extends transitions.core.Machine.get_triggers to also include parent state triggers. """
# add parents to state set
Expand Down

0 comments on commit 70f42eb

Please sign in to comment.