1try: 2 from builtins import object 3except ImportError: 4 pass 5 6from transitions.core import Enum 7from transitions.extensions.markup import MarkupMachine, rep 8from transitions.extensions import MachineFactory 9from transitions.extensions.factory import HierarchicalMarkupMachine 10from .utils import Stuff 11from functools import partial 12 13 14from unittest import TestCase, skipIf 15 16try: 17 from unittest.mock import MagicMock 18except ImportError: 19 from mock import MagicMock 20 21try: 22 import enum 23except ImportError: 24 enum = None 25 26 27class SimpleModel(object): 28 29 def after_func(self): 30 pass 31 32 33class TestRep(TestCase): 34 35 def test_rep_string(self): 36 self.assertEqual(rep("string"), "string") 37 38 def test_rep_function(self): 39 def check(): 40 return True 41 self.assertTrue(check()) 42 self.assertEqual(rep(check, MarkupMachine.format_references), "check") 43 44 def test_rep_partial_no_args_no_kwargs(self): 45 def check(): 46 return True 47 pcheck = partial(check) 48 self.assertTrue(pcheck()) 49 self.assertEqual(rep(pcheck, MarkupMachine.format_references), "check()") 50 51 def test_rep_partial_with_args(self): 52 def check(result): 53 return result 54 pcheck = partial(check, True) 55 self.assertTrue(pcheck()) 56 self.assertEqual(rep(pcheck, MarkupMachine.format_references), "check(True)") 57 58 def test_rep_partial_with_kwargs(self): 59 def check(result=True): 60 return result 61 pcheck = partial(check, result=True) 62 self.assertTrue(pcheck()) 63 self.assertEqual(rep(pcheck, MarkupMachine.format_references), "check(result=True)") 64 65 def test_rep_partial_with_args_and_kwargs(self): 66 def check(result, doublecheck=True): 67 return result == doublecheck 68 pcheck = partial(check, True, doublecheck=True) 69 self.assertTrue(pcheck()) 70 self.assertEqual(rep(pcheck, MarkupMachine.format_references), "check(True, doublecheck=True)") 71 72 def test_rep_callable_class(self): 73 class Check(object): 74 def __init__(self, result): 75 self.result = result 76 77 def __call__(self): 78 return self.result 79 80 def __repr__(self): 81 return "%s(%r)" % (type(self).__name__, self.result) 82 83 ccheck = Check(True) 84 self.assertTrue(ccheck()) 85 self.assertEqual(rep(ccheck, MarkupMachine.format_references), "Check(True)") 86 87 88class TestMarkupMachine(TestCase): 89 90 def setUp(self): 91 self.machine_cls = MarkupMachine 92 self.states = ['A', 'B', 'C', 'D'] 93 self.transitions = [ 94 {'trigger': 'walk', 'source': 'A', 'dest': 'B'}, 95 {'trigger': 'run', 'source': 'B', 'dest': 'C'}, 96 {'trigger': 'sprint', 'source': 'C', 'dest': 'D'} 97 ] 98 self.num_trans = len(self.transitions) 99 self.num_auto = len(self.states) ** 2 100 101 def test_markup_self(self): 102 m1 = self.machine_cls(states=self.states, transitions=self.transitions, initial='A') 103 m1.walk() 104 m2 = self.machine_cls(markup=m1.markup) 105 self.assertTrue(m1.state == m2.state or m1.state.name == m2.state) 106 self.assertEqual(len(m1.models), len(m2.models)) 107 self.assertEqual(sorted(m1.states.keys()), sorted(m2.states.keys())) 108 self.assertEqual(sorted(m1.events.keys()), sorted(m2.events.keys())) 109 m2.run() 110 m2.sprint() 111 self.assertNotEqual(m1.state, m2.state) 112 113 def test_markup_model(self): 114 model1 = SimpleModel() 115 m1 = self.machine_cls(model1, states=self.states, transitions=self.transitions, initial='A') 116 model1.walk() 117 m2 = self.machine_cls(markup=m1.markup) 118 model2 = m2.models[0] 119 self.assertIsInstance(model2, SimpleModel) 120 self.assertEqual(len(m1.models), len(m2.models)) 121 self.assertTrue(model1.state == model2.state or model1.state.name == model2.state) 122 self.assertEqual(sorted(m1.states.keys()), sorted(m2.states.keys())) 123 self.assertEqual(sorted(m1.events.keys()), sorted(m2.events.keys())) 124 125 def test_conditions_unless(self): 126 s = Stuff(machine_cls=self.machine_cls) 127 s.machine.add_transition('go', 'A', 'B', conditions='this_passes', 128 unless=['this_fails', 'this_fails_by_default']) 129 t = s.machine.markup['transitions'] 130 self.assertEqual(len(t), 1) 131 self.assertEqual(t[0]['trigger'], 'go') 132 self.assertEqual(len(t[0]['conditions']), 1) 133 self.assertEqual(len(t[0]['unless']), 2) 134 135 def test_auto_transitions(self): 136 m1 = self.machine_cls(states=self.states, transitions=self.transitions, initial='A') 137 m2 = self.machine_cls(states=self.states, transitions=self.transitions, initial='A', 138 auto_transitions_markup=True) 139 140 self.assertEqual(len(m1.markup.get('transitions')), self.num_trans) 141 self.assertEqual(len(m2.markup.get('transitions')), self.num_trans + self.num_auto) 142 m1.add_transition('go', 'A', 'B') 143 m2.add_transition('go', 'A', 'B') 144 self.num_trans += 1 145 self.assertEqual(len(m1.markup.get('transitions')), self.num_trans) 146 self.assertEqual(len(m2.markup.get('transitions')), self.num_trans + self.num_auto) 147 m1.auto_transitions_markup = True 148 m2.auto_transitions_markup = False 149 self.assertEqual(len(m1.markup.get('transitions')), self.num_trans + self.num_auto) 150 self.assertEqual(len(m2.markup.get('transitions')), self.num_trans) 151 152 153class TestMarkupHierarchicalMachine(TestMarkupMachine): 154 155 def setUp(self): 156 self.states = ['A', 'B', {'name': 'C', 157 'children': ['1', '2', {'name': '3', 'children': ['a', 'b', 'c']}]}] 158 159 self.transitions = [ 160 {'trigger': 'walk', 'source': 'A', 'dest': 'C_1'}, 161 {'trigger': 'run', 'source': 'C_1', 'dest': 'C_3_a'}, 162 {'trigger': 'sprint', 'source': 'C', 'dest': 'B'} 163 ] 164 165 # MarkupMachine cannot be imported via get_predefined as of now 166 # We want to be able to run these tests without (py)graphviz 167 self.machine_cls = HierarchicalMarkupMachine 168 self.num_trans = len(self.transitions) 169 self.num_auto = len(self.states) * 9 170 171 def test_nested_definitions(self): 172 states = [{'name': 'A'}, 173 {'name': 'B'}, 174 {'name': 'C', 175 'children': [ 176 {'name': '1'}, 177 {'name': '2'}], 178 'transitions': [ 179 {'trigger': 'go', 180 'source': '1', 181 'dest': '2'}], 182 'initial': '2'}] 183 machine = self.machine_cls(states=states, initial='A', auto_transitions=False, name='TestMachine') 184 markup = {k: v for k, v in machine.markup.items() if v and k != 'models'} 185 self.assertEqual(dict(initial='A', states=states, name='TestMachine'), markup) 186 187 188@skipIf(enum is None, "enum is not available") 189class TestMarkupMachineEnum(TestMarkupMachine): 190 191 class States(Enum): 192 A = 1 193 B = 2 194 C = 3 195 D = 4 196 197 def setUp(self): 198 self.machine_cls = MarkupMachine 199 self.states = TestMarkupMachineEnum.States 200 self.transitions = [ 201 {'trigger': 'walk', 'source': self.states.A, 'dest': self.states.B}, 202 {'trigger': 'run', 'source': self.states.B, 'dest': self.states.C}, 203 {'trigger': 'sprint', 'source': self.states.C, 'dest': self.states.D} 204 ] 205 self.num_trans = len(self.transitions) 206 self.num_auto = len(self.states)**2 207