class StopwatchTests(unittest.TestCase): def setUp(self): with open("stopwatch.yaml") as f: sc = import_from_yaml(f) self.stopwatch = Interpreter(sc, initial_context=context) self.stopwatch.execute_once() def test_increase_elapsed_time(self): self.stopwatch.queue("start") self.stopwatch.execute() self.stopwatch.clock.time += 1 self.stopwatch.execute() self.assertEqual(self.stopwatch.context["elapsed_time"], 1) def test_reset(self): self.stopwatch.queue("start") self.stopwatch.execute() self.stopwatch.clock.time += 1 self.stopwatch.execute() self.assertEqual(self.stopwatch.context["elapsed_time"], 1) self.stopwatch.clock.time += 1 self.stopwatch.execute() self.assertEqual(self.stopwatch.context["elapsed_time"], 2) self.stopwatch.queue("stop", "reset") self.stopwatch.execute_once() self.assertIn("stopped", self.stopwatch.configuration) self.assertIn("actual time", self.stopwatch.configuration) self.stopwatch.execute_once() self.assertIn("stopped", self.stopwatch.configuration) self.assertIn("actual time", self.stopwatch.configuration) self.assertEqual(self.stopwatch.context["elapsed_time"], 0)
class MicrowaveTests(unittest.TestCase): def setUp(self): with open('microwave.yaml') as f: sc = import_from_yaml(f) self.oven = Interpreter(sc) self.oven.execute_once() def test_no_heating_when_door_is_not_closed(self): self.oven.queue('door_opened', 'item_placed', 'timer_inc') self.oven.execute() self.oven.queue('cooking_start') for step in iter(self.oven.execute_once, None): for event in step.sent_events: self.assertNotEqual(event.name, 'heating_on') self.assertNotIn('cooking_mode', self.oven.configuration) def test_increase_timer(self): self.oven.queue('door_opened', 'item_placed', 'door_closed') events = 10 * ['timer_inc'] self.oven.queue(*events) self.oven.execute() self.assertEqual(self.oven.context['timer'], 10)
class RemoteElevatorTests(unittest.TestCase): def setUp(self): with open('docs/examples/elevator.yaml') as f: elevator = io.import_from_yaml(f) with open('docs/examples/elevator_buttons.yaml') as f: buttons = io.import_from_yaml(f) self.elevator = Interpreter(elevator) self.buttons = Interpreter(buttons) self.buttons.bind(self.elevator) def test_button(self): self.assertEqual(self.elevator.context['current'], 0) self.buttons.queue(Event('button_2_pushed')) self.buttons.execute() event = self.elevator._events.pop() self.assertEqual(event.name, 'floorSelected') self.assertEqual(event.data['floor'], 2) self.buttons.queue(Event('button_2_pushed')) self.buttons.execute() self.elevator.execute() self.assertEqual(self.elevator.context['current'], 2) def test_button_0_on_groundfloor(self): self.assertEqual(self.elevator.context['current'], 0) self.buttons.queue(Event('button_0_pushed')) self.buttons.execute() self.elevator.execute() self.assertEqual(self.elevator.context['current'], 0)
class SimulatorSimpleTests(unittest.TestCase): def setUp(self): with open('tests/yaml/simple.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc, DummyEvaluator) # Stabilization self.interpreter.execute_once() def test_init(self): self.assertEqual(self.interpreter.configuration, ['root', 's1']) self.assertFalse(self.interpreter.final) def test_simple_configuration(self): self.interpreter.execute_once() # Should do nothing! self.assertEqual(self.interpreter.configuration, ['root', 's1']) self.interpreter.queue(Event('goto s2')) self.interpreter.execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's2']) self.interpreter.execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's3']) def test_simple_entered(self): self.interpreter.queue(Event('goto s2')) self.assertEqual(self.interpreter.execute_once().entered_states, ['s2']) self.interpreter.queue(Event('goto final')) self.assertEqual(self.interpreter.execute_once().entered_states, ['s3']) self.assertEqual(self.interpreter.execute_once().entered_states, ['final']) self.assertEqual(self.interpreter.configuration, []) self.assertTrue(self.interpreter.final) def test_simple_final(self): self.interpreter.queue(Event('goto s2')).queue(Event('goto final')) self.interpreter.execute() self.assertTrue(self.interpreter.final)
class InfiniteExecutionTests(unittest.TestCase): def setUp(self): with open('tests/yaml/infinite.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc) # Stabilization self.interpreter.execute_once() def test_three_steps(self): self.assertEqual(self.interpreter.configuration, ['root', 's1']) self.interpreter.execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's2']) self.interpreter.execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's1']) self.interpreter.execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's2']) self.assertEqual(self.interpreter.context['x'], 2) # x is incremented in s1.on_entry def test_auto_three_steps(self): self.interpreter.execute(max_steps=3) self.assertEqual(self.interpreter.configuration, ['root', 's2']) self.assertEqual(self.interpreter.context['x'], 2) # x is incremented in s1.on_entry def test_auto_stop(self): self.interpreter.execute() self.assertTrue(self.interpreter.final) self.assertEqual(self.interpreter.context['x'], 100)
class InternalTests(unittest.TestCase): def setUp(self): with open('tests/yaml/internal.yaml') as f: self.sc = io.import_from_yaml(f) self.interpreter = Interpreter(self.sc) # Stabilization self.interpreter.execute_once() def testInternalSent(self): step = self.interpreter.execute_once() self.assertEqual(step.event.name, 'next') def testInternalBeforeExternal(self): self.interpreter.queue(Event('not_next')) step = self.interpreter.execute_once() self.assertEqual(step.event.name, 'next') step = self.interpreter.execute_once() self.assertEqual(step.event, None) self.assertEqual(step.entered_states, ['s2']) step = self.interpreter.execute_once() self.assertEqual(step.event.name, 'not_next') def testActiveGuard(self): self.interpreter.execute() self.assertTrue(self.interpreter.final)
def generic_test(self, condition: Condition, success_expected: bool, failure_expected: bool, delay: int = 0): statechart = Statechart('test') parallel_state = OrthogonalState('parallel_state') statechart.add_state(parallel_state, parent=None) initial_state = CompoundState('initial_state', initial='Cond') statechart.add_state(initial_state, "parallel_state") statechart.add_state(BasicState('success'), 'initial_state') statechart.add_state(BasicState('failure'), 'initial_state') condition.add_to(statechart=statechart, id='Cond', parent_id='initial_state', status_id=parallel_state, success_id='success', failure_id='failure') interpreter = Interpreter(statechart) self.assertFalse('success' in interpreter.configuration) self.assertFalse('failure' in interpreter.configuration) interpreter.execute() interpreter.time += delay interpreter.queue(Event(Condition.STEP_ENDED_EVENT)) interpreter.queue(Event(Condition.STEP_ENDED_EVENT)) interpreter.execute() self.assertEqual(success_expected, 'success' in interpreter.configuration) self.assertEqual(failure_expected, 'failure' in interpreter.configuration)
class MicrowaveTests(unittest.TestCase): def setUp(self): with open('docs/examples/microwave/microwave.yaml') as f: sc = io.import_from_yaml(f) self.microwave = Interpreter(sc) def test_lamp_on(self): self.microwave.execute_once() self.microwave.queue(Event('door_opened')) step = self.microwave.execute_once() self.microwave.execute_once() self.assertEqual(step.sent_events[0].name, 'lamp_switch_on') def test_heating_on(self): self.microwave.execute_once() self.microwave.queue(Event('door_opened')) self.microwave.queue(Event('item_placed')) self.microwave.queue(Event('door_closed')) self.microwave.queue(Event('input_timer_inc')) self.microwave.execute() self.microwave.queue(Event('input_cooking_start')) step = self.microwave.execute_once() self.assertIn(Event('heating_on'), step.sent_events) self.assertIn(Event('lamp_switch_on'), step.sent_events) self.assertIn(Event('turntable_start'), step.sent_events)
class InternalTests(unittest.TestCase): def setUp(self): with open('tests/yaml/internal.yaml') as f: self.sc = io.import_from_yaml(f) self.interpreter = Interpreter(self.sc) # Stabilization self.interpreter.execute_once() def testInternalSent(self): step = self.interpreter.execute_once() self.assertEqual(step.event.name, 'next') def testInternalBeforeExternal(self): self.interpreter.queue(Event('not_next')) step = self.interpreter.execute_once() self.assertEqual(step.event.name, 'next') step = self.interpreter.execute_once() self.assertEqual(step.event, None) self.assertEqual(step.entered_states, ['s2']) step = self.interpreter.execute_once() self.assertEqual(step.event.name, 'not_next') def testActiveGuard(self): self.interpreter.execute() self.assertTrue(self.interpreter.final)
class SimulatorHistoryTests(unittest.TestCase): def setUp(self): with open('tests/yaml/history.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc, evaluator_klass=DummyEvaluator) # Stabilization self.interpreter.execute_once() def test_memory(self): self.interpreter.queue(Event('next')).execute_once() self.assertEqual(sorted(self.interpreter.configuration), ['loop', 'root', 's2']) step = self.interpreter.queue(Event('pause')).execute_once() self.assertEqual(step.exited_states, ['s2', 'loop']) self.assertEqual(sorted(self.interpreter.configuration), ['pause', 'root']) def test_resume_memory(self): self.interpreter.queue(Event('next')).queue(Event('pause')).queue(Event('continue')) steps = self.interpreter.execute() step = steps[-1] self.assertEqual(step.entered_states, ['loop', 'loop.H', 's2']) self.assertEqual(step.exited_states, ['pause', 'loop.H']) self.assertEqual(sorted(self.interpreter.configuration), ['loop', 'root', 's2']) def test_after_memory(self): self.interpreter.queue(Event('next')).queue(Event('pause')).queue(Event('continue')) self.interpreter.queue(Event('next')).queue(Event('next')) self.interpreter.execute() self.assertEqual(sorted(self.interpreter.configuration), ['loop', 'root', 's1']) self.interpreter.queue(Event('pause')).queue(Event('stop')) self.interpreter.execute() self.assertTrue(self.interpreter.final)
class MicrowaveTests(unittest.TestCase): def setUp(self): with open('docs/examples/microwave/microwave.yaml') as f: sc = io.import_from_yaml(f) self.microwave = Interpreter(sc) def test_lamp_on(self): self.microwave.execute_once() self.microwave.queue(Event('door_opened')) step = self.microwave.execute_once() self.microwave.execute_once() self.assertEqual(step.sent_events[0].name, 'lamp_switch_on') def test_heating_on(self): self.microwave.execute_once() self.microwave.queue(Event('door_opened')) self.microwave.queue(Event('item_placed')) self.microwave.queue(Event('door_closed')) self.microwave.queue(Event('input_timer_inc')) self.microwave.execute() self.microwave.queue(Event('input_cooking_start')) step = self.microwave.execute_once() self.assertIn(Event('heating_on'), step.sent_events) self.assertIn(Event('lamp_switch_on'), step.sent_events) self.assertIn(Event('turntable_start'), step.sent_events)
class InfiniteExecutionTests(unittest.TestCase): def setUp(self): with open('tests/yaml/infinite.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc) # Stabilization self.interpreter.execute_once() def test_three_steps(self): self.assertEqual(self.interpreter.configuration, ['root', 's1']) self.interpreter.execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's2']) self.interpreter.execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's1']) self.interpreter.execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's2']) self.assertEqual(self.interpreter.context['x'], 2) # x is incremented in s1.on_entry def test_auto_three_steps(self): self.interpreter.execute(max_steps=3) self.assertEqual(self.interpreter.configuration, ['root', 's2']) self.assertEqual(self.interpreter.context['x'], 2) # x is incremented in s1.on_entry def test_auto_stop(self): self.interpreter.execute() self.assertTrue(self.interpreter.final) self.assertEqual(self.interpreter.context['x'], 100)
class ElevatorTests(unittest.TestCase): def setUp(self): with open('docs/examples/elevator/elevator.yaml') as f: self.sc = io.import_from_yaml(f) self.interpreter = Interpreter(self.sc) # Stabilization self.interpreter.execute_once() def test_init(self): self.assertEqual(len(self.interpreter.configuration), 5) def test_floor_selection(self): self.interpreter.queue(Event('floorSelected', floor=4)).execute_once() self.assertEqual(self.interpreter.context['destination'], 4) self.interpreter.execute_once() self.assertEqual(sorted(self.interpreter.configuration), [ 'active', 'doorsClosed', 'floorListener', 'floorSelecting', 'movingElevator' ]) def test_doorsOpen(self): self.interpreter.queue(Event('floorSelected', floor=4)) self.interpreter.execute() self.assertEqual(self.interpreter.context['current'], 4) self.interpreter.time += 10 self.interpreter.execute() self.assertTrue('doorsOpen' in self.interpreter.configuration) self.assertEqual(self.interpreter.context['current'], 0)
class RemoteElevatorTests(unittest.TestCase): def setUp(self): with open('docs/examples/elevator/elevator.yaml') as f: elevator = io.import_from_yaml(f) with open('docs/examples/elevator/elevator_buttons.yaml') as f: buttons = io.import_from_yaml(f) self.elevator = Interpreter(elevator) self.buttons = Interpreter(buttons) self.buttons.bind(self.elevator) def test_button(self): self.assertEqual(self.elevator.context['current'], 0) self.buttons.queue(Event('button_2_pushed')) self.buttons.execute() event = self.elevator._external_events.pop() self.assertEqual(event.name, 'floorSelected') self.assertEqual(event.data['floor'], 2) self.buttons.queue(Event('button_2_pushed')) self.buttons.execute() self.elevator.execute() self.assertEqual(self.elevator.context['current'], 2) def test_button_0_on_groundfloor(self): self.assertEqual(self.elevator.context['current'], 0) self.buttons.queue(Event('button_0_pushed')) self.buttons.execute() self.elevator.execute() self.assertEqual(self.elevator.context['current'], 0)
class ElevatorTests(unittest.TestCase): def setUp(self): with open('docs/examples/elevator.yaml') as f: self.sc = io.import_from_yaml(f) self.interpreter = Interpreter(self.sc) # Stabilization self.interpreter.execute_once() def test_init(self): self.assertEqual(len(self.interpreter.configuration), 5) def test_floor_selection(self): self.interpreter.queue(Event('floorSelected', floor=4)).execute_once() self.assertEqual(self.interpreter.context['destination'], 4) self.interpreter.execute_once() self.assertEqual(sorted(self.interpreter.configuration), ['active', 'doorsClosed', 'floorListener', 'floorSelecting', 'movingElevator']) def test_doorsOpen(self): self.interpreter.queue(Event('floorSelected', floor=4)) self.interpreter.execute() self.assertEqual(self.interpreter.context['current'], 4) self.interpreter.time += 10 self.interpreter.execute() self.assertTrue('doorsOpen' in self.interpreter.configuration) self.assertEqual(self.interpreter.context['current'], 0)
class WriterExecutionTests(unittest.TestCase): def setUp(self): with open('docs/examples/writer_options.yaml') as f: self.sc = io.import_from_yaml(f) self.interpreter = Interpreter(self.sc) def test_output(self): scenario = [ Event('keyPress', key='bonjour '), Event('toggle'), Event('keyPress', key='a '), Event('toggle'), Event('toggle_bold'), Event('keyPress', key='tous !'), Event('leave') ] for event in scenario: self.interpreter.queue(event) self.interpreter.execute() self.assertTrue(self.interpreter.final) self.assertEqual(self.interpreter.context['output'], [ 'bonjour ', '[b]', '[i]', 'a ', '[/b]', '[/i]', '[b]', 'tous !', '[/b]' ])
class MicrowaveTests(unittest.TestCase): def setUp(self): with open("microwave_controller.yaml") as f: sc = import_from_yaml(f) self.oven = Interpreter(sc, initial_context=context) self.oven.execute_once() def test_no_heating_when_door_is_not_closed(self): self.oven.queue("door_opened", "item_placed", "timer_inc") self.oven.execute() self.oven.queue("cooking_start") for step in iter(self.oven.execute_once, None): for event in step.sent_events: self.assertNotEqual(event.name, "heating_on") self.assertNotIn("cooking_mode", self.oven.configuration) def test_increase_timer(self): self.oven.queue("door_opened", "item_placed", "door_closed") events = 10 * ["timer_inc"] self.oven.queue(*events) self.oven.execute() self.assertEqual(self.oven.context["timer"], 10)
class SimulatorHistoryTests(unittest.TestCase): def setUp(self): with open('tests/yaml/history.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc, evaluator_klass=DummyEvaluator) # Stabilization self.interpreter.execute_once() def test_memory(self): self.interpreter.queue(Event('next')).execute_once() self.assertEqual(sorted(self.interpreter.configuration), ['loop', 'root', 's2']) step = self.interpreter.queue(Event('pause')).execute_once() self.assertEqual(step.exited_states, ['s2', 'loop']) self.assertEqual(sorted(self.interpreter.configuration), ['pause', 'root']) def test_resume_memory(self): self.interpreter.queue(Event('next')).queue(Event('pause')).queue(Event('continue')) steps = self.interpreter.execute() step = steps[-1] self.assertEqual(step.entered_states, ['loop', 'loop.H', 's2']) self.assertEqual(step.exited_states, ['pause', 'loop.H']) self.assertEqual(sorted(self.interpreter.configuration), ['loop', 'root', 's2']) def test_after_memory(self): self.interpreter.queue(Event('next')).queue(Event('pause')).queue(Event('continue')) self.interpreter.queue(Event('next')).queue(Event('next')) self.interpreter.execute() self.assertEqual(sorted(self.interpreter.configuration), ['loop', 'root', 's1']) self.interpreter.queue(Event('pause')).queue(Event('stop')) self.interpreter.execute() self.assertTrue(self.interpreter.final)
class RacerComponent(Component): def __init__(self, race_distance: int, sensor_distance: str, racer_distance: str, events: str): super().__init__() self._racer_distance_topic = racer_distance self._racer = Racer() with open(SCRIPT_DIR / 'racer.yaml') as f: statechart = sismic.io.import_from_yaml(f) context = {'race_distance': race_distance, 'racer': self._racer} self._interpreter = Interpreter(statechart, initial_context=context) self._interpreter.execute() self._io.subscribe(sensor_distance, self._on_sensor_distance) self._io.subscribe(events, self._on_event) def _on_sensor_distance(self, distance: int): """ :param distance: meters since sensor start """ self._racer.sensor_distance = distance self._io.publish(self._racer_distance_topic, distance=self._racer.distance) steps = self._interpreter.execute() if steps: print(steps) def _on_event(self, name: str, **kwargs): self._interpreter.queue(name, **kwargs)
def test_statechart_postcondition(self): sc = io.import_from_yaml(open('tests/yaml/simple.yaml')) sc.postconditions.append('False') interpreter = Interpreter(sc) interpreter.send(Event('goto s2')).send(Event('goto final')) with self.assertRaises(PostconditionFailed) as cm: interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, StateChart))
class WatchElevatorTests(unittest.TestCase): def setUp(self): with open('docs/examples/elevator.yaml') as f: sc = io.import_from_yaml(f) self.tested = Interpreter(sc) self.watcher = ExecutionWatcher(self.tested) def test_7th_floor_never_reached(self): with open('docs/examples/tester_elevator_7th_floor_never_reached.yaml' ) as f: tester_sc = io.import_from_yaml(f) tester = self.watcher.watch_with(tester_sc) self.watcher.start() # Send elevator to 4th self.tested.queue(Event('floorSelected', floor=4)).execute() self.watcher.stop() self.assertFalse(tester.final) def test_7th_floor_never_reached_fails(self): with open('docs/examples/tester_elevator_7th_floor_never_reached.yaml' ) as f: tester_sc = io.import_from_yaml(f) tester = self.watcher.watch_with(tester_sc) self.watcher.start() # Send elevator to 7th self.tested.queue(Event('floorSelected', floor=7)).execute() self.watcher.stop() self.assertTrue(tester.final) def test_destination_reached(self): with open( 'docs/examples/tester_elevator_destination_reached.yaml') as f: tester_statechart = io.import_from_yaml(f) # Create the interpreter and the watcher watcher = ExecutionWatcher(self.tested) # Add the tester and start watching tester = watcher.watch_with(tester_statechart) watcher.start() # Send the elevator to 4th self.tested.queue(Event('floorSelected', floor=4)).execute(max_steps=2) self.assertEqual(tester.context['destinations'], [4]) self.tested.execute() self.assertEqual(tester.context['destinations'], []) # Stop watching. The tester must be in a final state watcher.stop() self.assertFalse(tester.final)
def generic_temporal_test(self, expression: TemporalExpression, story: list, accept_after: bool): # Todo: convert the story list into a 'real' story that can be told to an interpreter statechart = expression.generate_statechart() interpreter = Interpreter(statechart) for event in story: interpreter.queue(event) interpreter.execute() self.assertEqual(len(interpreter.configuration) == 0, accept_after)
def test_after_memory(self): sc = io.import_from_yaml(open('tests/yaml/history.yaml')) interpreter = Interpreter(sc, DummyEvaluator) interpreter.send(Event('next')).send(Event('pause')).send(Event('continue')) interpreter.send(Event('next')).send(Event('next')) interpreter.execute() self.assertEqual(sorted(interpreter.configuration), ['loop', 's1']) interpreter.send(Event('pause')).send(Event('stop')) interpreter.execute() self.assertTrue(interpreter.final)
def test_doorsOpen(self): sc = io.import_from_yaml(open('docs/examples/elevator.yaml')) interpreter = Interpreter(sc) interpreter.send(Event('floorSelected', floor=4)) interpreter.execute() self.assertEqual(interpreter._evaluator.context['current'], 4) interpreter.time += 10 interpreter.execute() self.assertTrue('doorsOpen' in interpreter.configuration) self.assertEqual(interpreter._evaluator.context['current'], 0)
class WatchElevatorTests(unittest.TestCase): def setUp(self): with open('docs/examples/elevator.yaml') as f: sc = io.import_from_yaml(f) self.tested = Interpreter(sc) self.watcher = ExecutionWatcher(self.tested) def test_7th_floor_never_reached(self): with open('docs/examples/tester_elevator_7th_floor_never_reached.yaml') as f: tester_sc = io.import_from_yaml(f) tester = self.watcher.watch_with(tester_sc) self.watcher.start() # Send elevator to 4th self.tested.queue(Event('floorSelected', floor=4)).execute() self.watcher.stop() self.assertFalse(tester.final) def test_7th_floor_never_reached_fails(self): with open('docs/examples/tester_elevator_7th_floor_never_reached.yaml') as f: tester_sc = io.import_from_yaml(f) tester = self.watcher.watch_with(tester_sc) self.watcher.start() # Send elevator to 7th self.tested.queue(Event('floorSelected', floor=7)).execute() self.watcher.stop() self.assertTrue(tester.final) def test_destination_reached(self): with open('docs/examples/tester_elevator_destination_reached.yaml') as f: tester_statechart = io.import_from_yaml(f) # Create the interpreter and the watcher watcher = ExecutionWatcher(self.tested) # Add the tester and start watching tester = watcher.watch_with(tester_statechart) watcher.start() # Send the elevator to 4th self.tested.queue(Event('floorSelected', floor=4)).execute(max_steps=2) self.assertEqual(tester.context['destinations'], [4]) self.tested.execute() self.assertEqual(tester.context['destinations'], []) # Stop watching. The tester must be in a final state watcher.stop() self.assertFalse(tester.final)
class PythonEvaluatorNestedContextTests(unittest.TestCase): def setUp(self): statechart = """ statechart: name: test preamble: x = y = 1 root state: name: root initial: s1 states: - name: s1 on entry: x, z = 2, 1 transitions: - target: s2 guard: y == 1 action: a, z, y = 2, 2, 2 - name: s2 """ sc = import_from_yaml(statechart) self.intp = Interpreter(sc) def test_initialization(self): self.assertEqual(self.intp.context.get('x'), 1) self.assertEqual(self.intp.context.get('y'), 1) with self.assertRaises(KeyError): _ = self.intp.context['z'] with self.assertRaises(KeyError): _ = self.intp.context['a'] def test_global_context(self): self.intp.execute() self.assertEqual(self.intp.context.get('x'), 2) self.assertEqual(self.intp.context.get('y'), 2) with self.assertRaises(KeyError): _ = self.intp.context['z'] with self.assertRaises(KeyError): _ = self.intp.context['a'] def test_nested_context(self): self.intp.execute() s1 = self.intp._evaluator.context_for('s1') self.assertEqual(s1['x'], 2) self.assertEqual(s1['y'], 2) self.assertEqual(s1['z'], 2) with self.assertRaises(KeyError): _ = s1['a']
class PythonEvaluatorNestedContextTests(unittest.TestCase): def setUp(self): statechart = """ statechart: name: test preamble: x = y = 1 root state: name: root initial: s1 states: - name: s1 on entry: x, z = 2, 1 transitions: - target: s2 guard: y == 1 action: a, z, y = 2, 2, 2 - name: s2 """ sc = import_from_yaml(statechart) self.intp = Interpreter(sc) def test_initialization(self): self.assertEqual(self.intp.context.get('x'), 1) self.assertEqual(self.intp.context.get('y'), 1) with self.assertRaises(KeyError): _ = self.intp.context['z'] with self.assertRaises(KeyError): _ = self.intp.context['a'] def test_global_context(self): self.intp.execute() self.assertEqual(self.intp.context.get('x'), 2) self.assertEqual(self.intp.context.get('y'), 2) with self.assertRaises(KeyError): _ = self.intp.context['z'] with self.assertRaises(KeyError): _ = self.intp.context['a'] def test_nested_context(self): self.intp.execute() s1 = self.intp._evaluator.context_for('s1') self.assertEqual(s1['x'], 2) self.assertEqual(s1['y'], 2) self.assertEqual(s1['z'], 2) with self.assertRaises(KeyError): _ = s1['a']
class SimulatorSimpleTests(unittest.TestCase): def setUp(self): with open('tests/yaml/simple.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc, evaluator_klass=DummyEvaluator) # Stabilization self.interpreter.execute_once() def test_init(self): self.assertEqual(self.interpreter.configuration, ['root', 's1']) self.assertFalse(self.interpreter.final) def test_queue(self): self.interpreter.queue(Event('e1')) self.assertEqual(self.interpreter._select_event(), Event('e1')) self.interpreter.queue(InternalEvent('e1')) self.assertEqual(self.interpreter._select_event(), InternalEvent('e1')) with self.assertRaises(ValueError): self.interpreter.queue('e1') def test_simple_configuration(self): self.interpreter.execute_once() # Should do nothing! self.assertEqual(self.interpreter.configuration, ['root', 's1']) self.interpreter.queue(Event('goto s2')) self.interpreter.execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's2']) self.interpreter.execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's3']) def test_simple_entered(self): self.interpreter.queue(Event('goto s2')) self.assertEqual(self.interpreter.execute_once().entered_states, ['s2']) self.interpreter.queue(Event('goto final')) self.assertEqual(self.interpreter.execute_once().entered_states, ['s3']) self.assertEqual(self.interpreter.execute_once().entered_states, ['final']) self.assertEqual(self.interpreter.configuration, []) self.assertTrue(self.interpreter.final) def test_simple_final(self): self.interpreter.queue(Event('goto s2')).queue(Event('goto final')) self.interpreter.execute() self.assertTrue(self.interpreter.final)
class SimulatorDeepHistoryTests(unittest.TestCase): def setUp(self): with open('tests/yaml/deep_history.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc, evaluator_klass=DummyEvaluator) # Stabilization self.interpreter.execute_once() def test_deep_memory(self): self.interpreter.queue(Event('next1')).queue(Event('next2')) self.interpreter.execute() self.assertEqual(sorted(self.interpreter.configuration), ['active', 'concurrent_processes', 'process_1', 'process_2', 'root', 's12', 's22']) self.interpreter.queue(Event('error1')) self.interpreter.execute() self.assertEqual(self.interpreter.configuration, ['root', 'pause']) self.assertEqual(sorted(self.interpreter._memory['active.H*']), ['concurrent_processes', 'process_1', 'process_2', 's12', 's22']) self.interpreter.queue(Event('continue')) self.interpreter.execute() self.assertEqual(sorted(self.interpreter.configuration), ['active', 'concurrent_processes', 'process_1', 'process_2', 'root', 's12', 's22']) def test_entered_order(self): self.interpreter.queue(Event('next1')).queue(Event('next2')).queue(Event('pause')) step = self.interpreter.execute()[-1] self.assertEqual(step.entered_states, ['pause']) self.assertEqual(sorted(self.interpreter.configuration), ['pause', 'root']) step = self.interpreter.queue(Event('continue')).execute_once() self.assertTrue(step.entered_states.index('active') < step.entered_states.index('active.H*')) self.assertTrue(step.entered_states.index('active.H*') < step.entered_states.index('concurrent_processes')) self.assertTrue(step.entered_states.index('concurrent_processes') < step.entered_states.index('process_1')) self.assertTrue(step.entered_states.index('concurrent_processes') < step.entered_states.index('process_2')) self.assertTrue(step.entered_states.index('process_1') < step.entered_states.index('s12')) self.assertTrue(step.entered_states.index('process_2') < step.entered_states.index('s22')) self.interpreter.queue(Event('next1')).queue(Event('next2')).execute() self.assertTrue(self.interpreter.final) def test_exited_order(self): self.interpreter.queue(Event('next1')).queue(Event('next2')).queue(Event('pause')) step = self.interpreter.execute()[-1] self.assertEqual(step.exited_states, ['s12', 's22', 'process_1', 'process_2', 'concurrent_processes', 'active']) self.assertEqual(sorted(self.interpreter.configuration), ['pause', 'root']) step = self.interpreter.queue(Event('continue')).execute_once() self.assertEqual(step.exited_states, ['pause', 'active.H*']) self.interpreter.queue(Event('next1')).queue(Event('next2')).execute() self.assertTrue(self.interpreter.final)
class SimulatorDeepHistoryTests(unittest.TestCase): def setUp(self): with open('tests/yaml/deep_history.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc, evaluator_klass=DummyEvaluator) # Stabilization self.interpreter.execute_once() def test_deep_memory(self): self.interpreter.queue(Event('next1')).queue(Event('next2')) self.interpreter.execute() self.assertEqual(sorted(self.interpreter.configuration), ['active', 'concurrent_processes', 'process_1', 'process_2', 'root', 's12', 's22']) self.interpreter.queue(Event('error1')) self.interpreter.execute() self.assertEqual(self.interpreter.configuration, ['root', 'pause']) self.assertEqual(sorted(self.interpreter._memory['active.H*']), ['concurrent_processes', 'process_1', 'process_2', 's12', 's22']) self.interpreter.queue(Event('continue')) self.interpreter.execute() self.assertEqual(sorted(self.interpreter.configuration), ['active', 'concurrent_processes', 'process_1', 'process_2', 'root', 's12', 's22']) def test_entered_order(self): self.interpreter.queue(Event('next1')).queue(Event('next2')).queue(Event('pause')) step = self.interpreter.execute()[-1] self.assertEqual(step.entered_states, ['pause']) self.assertEqual(sorted(self.interpreter.configuration), ['pause', 'root']) step = self.interpreter.queue(Event('continue')).execute_once() self.assertTrue(step.entered_states.index('active') < step.entered_states.index('active.H*')) self.assertTrue(step.entered_states.index('active.H*') < step.entered_states.index('concurrent_processes')) self.assertTrue(step.entered_states.index('concurrent_processes') < step.entered_states.index('process_1')) self.assertTrue(step.entered_states.index('concurrent_processes') < step.entered_states.index('process_2')) self.assertTrue(step.entered_states.index('process_1') < step.entered_states.index('s12')) self.assertTrue(step.entered_states.index('process_2') < step.entered_states.index('s22')) self.interpreter.queue(Event('next1')).queue(Event('next2')).execute() self.assertTrue(self.interpreter.final) def test_exited_order(self): self.interpreter.queue(Event('next1')).queue(Event('next2')).queue(Event('pause')) step = self.interpreter.execute()[-1] self.assertEqual(step.exited_states, ['s12', 's22', 'process_1', 'process_2', 'concurrent_processes', 'active']) self.assertEqual(sorted(self.interpreter.configuration), ['pause', 'root']) step = self.interpreter.queue(Event('continue')).execute_once() self.assertEqual(step.exited_states, ['pause', 'active.H*']) self.interpreter.queue(Event('next1')).queue(Event('next2')).execute() self.assertTrue(self.interpreter.final)
def test_resume_memory(self): sc = io.import_from_yaml(open('tests/yaml/history.yaml')) interpreter = Interpreter(sc, DummyEvaluator) interpreter.send(Event('next')).send(Event('pause')).send(Event('continue')) steps = interpreter.execute() step = steps[-1] self.assertEqual(step.entered_states, ['loop', 'loop.H', 's2']) self.assertEqual(step.exited_states, ['pause', 'loop.H']) self.assertEqual(sorted(interpreter.configuration), ['loop', 's2'])
def test_check_guard_failure(self): statechart = Statechart('statechart') statechart.add_state(OrthogonalState('parallel_state'), parent=None) initial_state = CompoundState('initial_state', initial='condition') statechart.add_state(initial_state, parent='parallel_state') statechart.add_state(BasicState('success'), parent='initial_state') statechart.add_state(BasicState('failure'), parent='initial_state') CheckGuard('x == 1').add_to(statechart=statechart, id='condition', parent_id='initial_state', status_id='parallel_state', success_id='success', failure_id='failure') interpreter = Interpreter(statechart) interpreter.context['x'] = 42 interpreter.execute() self.assertFalse('success' in interpreter.configuration) self.assertTrue('failure' in interpreter.configuration)
def generic_test(self, tested_statechart: Statechart, events: list, property: Condition, expected_success: bool, expected_failure: bool): from sismic.interpreter import log_trace tester_statechart = Statechart('tester_statechart') tester_statechart.add_state(OrthogonalState('parallel_state'), None) tester_statechart.add_state(CompoundState('testing_area', initial='property'), parent='parallel_state') tester_statechart.add_state(BasicState('success_state'), parent='testing_area') tester_statechart.add_state(BasicState('failure_state'), parent='testing_area') property.add_to(tester_statechart, id='property', parent_id='testing_area', status_id='parallel_state', success_id='success_state', failure_id='failure_state') tester_interpreter = Interpreter(tester_statechart) self.assertFalse('success_state' in tester_interpreter.configuration) self.assertFalse('failure_state' in tester_interpreter.configuration) tested_interpreter = Interpreter(tested_statechart) trace = log_trace(tested_interpreter) for event in events: tested_interpreter.queue(event) tested_interpreter.execute() story = teststory_from_trace(trace) story.tell(tester_interpreter) self.assertEqual(expected_success, 'success_state' in tester_interpreter.configuration) self.assertEqual(expected_failure, 'failure_state' in tester_interpreter.configuration)
class WriterExecutionTests(unittest.TestCase): def setUp(self): self.sc = io.import_from_yaml(open('docs/examples/writer_options.yaml')) self.interpreter = Interpreter(self.sc) def test_output(self): scenario = [ Event('keyPress', key='bonjour '), Event('toggle'), Event('keyPress', key='a '), Event('toggle'), Event('toggle_bold'), Event('keyPress', key='tous !'), Event('leave') ] for event in scenario: self.interpreter.send(event) self.interpreter.execute() self.assertTrue(self.interpreter.final) self.assertEqual(self.interpreter.context['output'], ['bonjour ', '[b]', '[i]', 'a ', '[/b]', '[/i]', '[b]', 'tous !', '[/b]'])
def test_exited_order(self): sc = io.import_from_yaml(open('tests/yaml/deep_history.yaml')) interpreter = Interpreter(sc, DummyEvaluator) interpreter.send(Event('next1')).send(Event('next2')).send(Event('pause')) step = interpreter.execute()[-1] self.assertEqual(step.exited_states, ['s12', 's22', 'process_1', 'process_2', 'concurrent_processes', 'active']) self.assertEqual(sorted(interpreter.configuration), ['pause']) step = interpreter.send(Event('continue')).execute_once() self.assertEqual(step.exited_states, ['pause', 'active.H*']) interpreter.send(Event('next1')).send(Event('next2')).execute() self.assertTrue(interpreter.final)
class ParallelExecutionTests(unittest.TestCase): def setUp(self): with open('tests/yaml/parallel.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc) # Stabilization self.interpreter.execute_once() def test_concurrent_transitions(self): step = self.interpreter.queue(Event('nextA')).execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's1', 'p1', 'p2', 'a1', 'a2']) self.assertLess(step.exited_states.index('initial1'), step.exited_states.index('initial2')) self.assertLess(step.entered_states.index('a1'), step.entered_states.index('a2')) def test_concurrent_transitions_nested_target(self): self.interpreter.queue(Event('nextA')).queue(Event('reset1')) self.interpreter.execute() self.assertEqual(self.interpreter.configuration, ['root', 's1', 'p1', 'p2', 'a2', 'initial1']) def test_unnested_transitions(self): self.interpreter.queue(Event('nextA')).queue(Event('nextA')) self.interpreter.execute() self.assertEqual(self.interpreter.configuration, ['root', 's1', 'p1', 'p2', 'a2', 'initial1']) def test_unnested_transitions_2(self): self.interpreter.queue(Event('nextA')).queue(Event('nextB')) self.interpreter.execute() self.assertEqual(self.interpreter.configuration, ['root', 's1', 'p1', 'p2', 'b1', 'b2']) def test_conflicting_transitions(self): self.interpreter.queue(Event('nextA')).queue(Event('nextB')).queue( Event('conflict1')) self.interpreter.execute_once() self.interpreter.execute_once() with self.assertRaises(exceptions.ConflictingTransitionsError): self.interpreter.execute_once() def test_conflicting_transitions_2(self): self.interpreter.queue(Event('nextA')).queue(Event('nextB')).queue( Event('conflict2')) self.interpreter.execute_once() self.interpreter.execute_once() with self.assertRaises(exceptions.ConflictingTransitionsError): self.interpreter.execute_once()
class LogTraceTests(unittest.TestCase): def setUp(self): with open('docs/examples/elevator/elevator.yaml') as f: sc = io.import_from_yaml(f) self.tested = Interpreter(sc) self.steps = log_trace(self.tested) def test_empty_trace(self): self.assertEqual(self.steps, []) def test_nonempty_trace(self): self.tested.queue(Event('floorSelected', floor=4)).execute() self.assertTrue(len(self.steps) > 0) def test_log_content(self): self.tested.queue(Event('floorSelected', floor=4)) steps = self.tested.execute() self.assertSequenceEqual(self.steps, steps)
class LogTraceTests(unittest.TestCase): def setUp(self): with open('docs/examples/elevator/elevator.yaml') as f: sc = io.import_from_yaml(f) self.tested = Interpreter(sc) self.steps = log_trace(self.tested) def test_empty_trace(self): self.assertEqual(self.steps, []) def test_nonempty_trace(self): self.tested.queue(Event('floorSelected', floor=4)).execute() self.assertTrue(len(self.steps) > 0) def test_log_content(self): self.tested.queue(Event('floorSelected', floor=4)) steps = self.tested.execute() self.assertSequenceEqual(self.steps, steps)
def tell(self, interpreter: Interpreter, *args, **kwargs) -> List[MacroStep]: """ Tells the whole story to the interpreter. :param interpreter: an interpreter instance :param args: additional positional arguments that are passed to *interpreter.execute*. :param kwargs: additional keywords arguments that are passed to *interpreter.execute*. :return: the resulting trace of execution (a list of *MacroStep*) """ trace = [] # type: List[MacroStep] for item in self: if isinstance(item, Event): interpreter.queue(item) elif isinstance(item, Pause): interpreter.time += item.duration step = interpreter.execute(*args, **kwargs) if step: trace.extend(step) return trace
class ParallelExecutionTests(unittest.TestCase): def setUp(self): with open('tests/yaml/parallel.yaml') as f: sc = io.import_from_yaml(f) self.interpreter = Interpreter(sc) # Stabilization self.interpreter.execute_once() def test_concurrent_transitions(self): step = self.interpreter.queue(Event('nextA')).execute_once() self.assertEqual(self.interpreter.configuration, ['root', 's1', 'p1', 'p2', 'a1', 'a2']) self.assertLess(step.exited_states.index('initial1'), step.exited_states.index('initial2')) self.assertLess(step.entered_states.index('a1'), step.entered_states.index('a2')) def test_concurrent_transitions_nested_target(self): self.interpreter.queue(Event('nextA')).queue(Event('reset1')) self.interpreter.execute() self.assertEqual(self.interpreter.configuration, ['root', 's1', 'p1', 'p2', 'a2', 'initial1']) def test_unnested_transitions(self): self.interpreter.queue(Event('nextA')).queue(Event('nextA')) self.interpreter.execute() self.assertEqual(self.interpreter.configuration, ['root', 's1', 'p1', 'p2', 'a2', 'initial1']) def test_unnested_transitions_2(self): self.interpreter.queue(Event('nextA')).queue(Event('nextB')) self.interpreter.execute() self.assertEqual(self.interpreter.configuration, ['root', 's1', 'p1', 'p2', 'b1', 'b2']) def test_conflicting_transitions(self): self.interpreter.queue(Event('nextA')).queue(Event('nextB')).queue(Event('conflict1')) self.interpreter.execute_once() self.interpreter.execute_once() with self.assertRaises(exceptions.ConflictingTransitionsError): self.interpreter.execute_once() def test_conflicting_transitions_2(self): self.interpreter.queue(Event('nextA')).queue(Event('nextB')).queue(Event('conflict2')) self.interpreter.execute_once() self.interpreter.execute_once() with self.assertRaises(exceptions.ConflictingTransitionsError): self.interpreter.execute_once()
def test_deep_memory(self): sc = io.import_from_yaml(open('tests/yaml/deep_history.yaml')) interpreter = Interpreter(sc, DummyEvaluator) interpreter.send(Event('next1')).send(Event('next2')) interpreter.execute() self.assertEqual(sorted(interpreter.configuration), ['active', 'concurrent_processes', 'process_1', 'process_2', 's12', 's22']) interpreter.send(Event('error1')) interpreter.execute() self.assertEqual(interpreter.configuration, ['pause']) self.assertEqual(sorted(interpreter._memory['active.H*']), ['concurrent_processes', 'process_1', 'process_2', 's12', 's22']) interpreter.send(Event('continue')) interpreter.execute() self.assertEqual(sorted(interpreter.configuration), ['active', 'concurrent_processes', 'process_1', 'process_2', 's12', 's22'])
class ParallelExecutionTests(unittest.TestCase): def setUp(self): self.sc = io.import_from_yaml(open('tests/yaml/parallel.yaml')) self.interpreter = Interpreter(self.sc) def test_concurrent_transitions(self): step = self.interpreter.send(Event('nextA')).execute_once() self.assertEqual(self.interpreter.configuration, ['s1', 'p1', 'p2', 'a1', 'a2']) self.assertLess(step.exited_states.index('initial1'), step.exited_states.index('initial2')) self.assertLess(step.entered_states.index('a1'), step.entered_states.index('a2')) def test_concurrent_transitions_nested_target(self): self.interpreter.send(Event('nextA')).send(Event('reset1')) self.interpreter.execute() self.assertEqual(self.interpreter.configuration, ['s1', 'p1', 'p2', 'a2', 'initial1']) def test_unnested_transitions(self): self.interpreter.send(Event('nextA')).send(Event('nextA')) self.interpreter.execute() self.assertEqual(self.interpreter.configuration, ['s1', 'p1', 'p2', 'a2', 'initial1']) def test_unnested_transitions_2(self): self.interpreter.send(Event('nextA')).send(Event('nextB')) self.interpreter.execute() self.assertEqual(self.interpreter.configuration, ['s1', 'p1', 'p2', 'b1', 'b2']) def test_conflicting_transitions(self): self.interpreter.send(Event('nextA')).send(Event('nextB')).send(Event('conflict1')) self.interpreter.execute_once() self.interpreter.execute_once() with self.assertRaises(Warning): self.interpreter.execute_once() def test_conflicting_transitions_2(self): self.interpreter.send(Event('nextA')).send(Event('nextB')).send(Event('conflict2')) self.interpreter.execute_once() self.interpreter.execute_once() with self.assertRaises(Warning): self.interpreter.execute_once()
class Presenter: def __init__(self, view, model): with open(get_resource_path('statechart/watch.yml')) as f: statechart = yaml.load(f, Loader=IncludeLoader) statechart = import_from_yaml(text=yaml.dump(statechart)) self.it = Interpreter(statechart) self.it.context["pr"] = self self.it.context["model"] = model self.it.clock.start() self._view = view self._view.schedule_once(self._run_interpreter, 0.1) self._view.set_event_callback(self.it.queue) def _run_interpreter(self): self._view.schedule_once(self._run_interpreter, 0.1) self.it.execute() def set_light(self, state): self._view.set_light(state) def _display_time(self, time, hour24): self._view.set_text("min", time.strftime("%M")) self._view.set_text("sec", time.strftime("%S")) if hour24: self._view.set_text("am_pm", time.strftime("%p")) self._view.set_text("hour", time.strftime("%I")) else: self._view.set_text("am_pm", "") self._view.set_text("hour", time.strftime("%H")) def _display_on_off(self, state): if state: self._view.set_text("sec", "ON") else: self._view.set_text("sec", "OFF") def update_disp_select(self, selected): for part in "hour", "min", "sec", "am_pm": if part == selected: self._view.set_text(part + "_sel", "-") else: self._view.set_text(part + "_sel", "") def update_display_time(self, time, hour24): self._display_time(time, hour24) def update_display_date(self, time): self._view.set_text("hour", time.strftime("%m")) self._view.set_text("min", time.strftime("%d")) self._view.set_text("sec", time.strftime("%y")) self._view.set_text("am_pm", time.strftime("%a")) def update_display_alarm(self, time, hour24, enabled): self._display_time(time, hour24) self._display_on_off(enabled) def update_display_chime(self, enabled): self._view.set_text("hour", "") self._view.set_text("min", "00") self._view.set_text("sec", "") self._view.set_text("am_pm", "") self._display_on_off(enabled) def update_display_stopwatch_zero(self): self._view.set_text("hour", "{:02}".format(0)) self._view.set_text("min", "{:02}".format(0)) self._view.set_text("sec", "{:02}".format(0)) self._view.set_text("am_pm", "") def update_display_stopwatch(self, elapsed, stopped, time): if not stopped: elapsed += (datetime.datetime.today() - time) stopwatch_time = elapsed.total_seconds() total_mseconds = int(stopwatch_time * 1000) mseconds = total_mseconds % 1000 total_seconds = total_mseconds // 1000 seconds = total_seconds % 60 total_minutes = total_seconds // 60 minutes = total_minutes % 60 self._view.set_text("hour", "{:02}".format(minutes)) self._view.set_text("min", "{:02}".format(seconds)) self._view.set_text("sec", "{:02}".format(mseconds // 10)) self._view.set_text("am_pm", "") def update_mode_selection(self, mode): for ind in self._view.icons.keys(): if mode.startswith(ind): self._view.set_text(ind, self._view.icons[ind]) else: self._view.set_text(ind, "") def update_indication_state(self, enabled): for ind in self._view.icons.keys(): if enabled[ind]: self._view.set_text(ind, self._view.icons[ind]) else: self._view.set_text(ind, "") def play(self, name, loop=False): self._view.play(name, loop) def stop(self): self._view.stop() def run(self): self._view.run()
class PythonEvaluatorSequenceConditionTests(unittest.TestCase): def setUp(self): self.sc = import_from_yaml(""" statechart: name: test contract root state: name: root on entry: x = 1 initial: s0 states: - name: s0 initial: s1 transitions: - event: end target: root states: - name: s1 transitions: - target: s2 action: x = 2 event: e - name: s2 """) self.root = self.sc.state_for('root') # Will never be exited self.s0 = self.sc.state_for('s0') # Will be exited on "end" self.s1 = self.sc.state_for('s1') # Entered, and then exited on e. self.s2 = self.sc.state_for('s2') # Entered when e self.intp = Interpreter(self.sc) def test_single_condition(self): self.root.sequences.append('"True"') self.intp.execute() def test_access_context(self): self.root.sequences.append('"x == 1"') self.intp.execute() def test_access_nested_context(self): self.s0.sequences.append('"x == 1" -> "x == 2"') self.intp.queue(Event('e')).queue(Event('end')) self.intp.execute() def test_fails_fast(self): self.s0.sequences.append('Failure') with self.assertRaises(SequentialConditionError): self.intp.execute() def test_fails_on_exit(self): self.s0.sequences.append('"x == 1" -> "x == 2" -> "x == 3"') self.intp.queue(Event('e')) self.intp.execute() self.intp.queue(Event('end')) with self.assertRaises(SequentialConditionError): self.intp.execute()
def test_do_not_raise(self): self.sc.invariants.append('False') interpreter = Interpreter(self.sc, ignore_contract=True) interpreter.send(Event('floorSelected', floor=4)) interpreter.execute()
class ElevatorContractTests(unittest.TestCase): def setUp(self): self.sc = io.import_from_yaml(open('docs/examples/elevator.yaml')) self.interpreter = Interpreter(self.sc) def test_no_error(self): self.interpreter.send(Event('floorSelected', floor=4)) self.interpreter.execute() self.assertFalse(self.interpreter.final) def test_state_precondition(self): self.sc.states['movingUp'].preconditions.append('False') self.interpreter.send(Event('floorSelected', floor=4)) with self.assertRaises(PreconditionFailed) as cm: self.interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, StateMixin)) def test_state_postcondition(self): self.sc.states['movingUp'].postconditions.append('False') self.interpreter.send(Event('floorSelected', floor=4)) with self.assertRaises(PostconditionFailed) as cm: self.interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, StateMixin)) def test_state_invariant(self): self.sc.states['movingUp'].invariants.append('False') self.interpreter.send(Event('floorSelected', floor=4)) with self.assertRaises(InvariantFailed) as cm: self.interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, StateMixin)) def test_transition_precondition(self): self.sc.states['floorSelecting'].transitions[0].preconditions.append('False') self.interpreter.send(Event('floorSelected', floor=4)) with self.assertRaises(PreconditionFailed) as cm: self.interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, Transition)) def test_transition_postcondition(self): self.sc.states['floorSelecting'].transitions[0].postconditions.append('False') self.interpreter.send(Event('floorSelected', floor=4)) with self.assertRaises(PostconditionFailed) as cm: self.interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, Transition)) def test_statechart_precondition(self): self.sc.preconditions.append('False') with self.assertRaises(PreconditionFailed) as cm: self.interpreter = Interpreter(self.sc) self.assertTrue(isinstance(cm.exception.obj, StateChart)) def test_statechart_postcondition(self): sc = io.import_from_yaml(open('tests/yaml/simple.yaml')) sc.postconditions.append('False') interpreter = Interpreter(sc) interpreter.send(Event('goto s2')).send(Event('goto final')) with self.assertRaises(PostconditionFailed) as cm: interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, StateChart)) def test_statechart_invariant(self): self.sc.invariants.append('False') self.interpreter.send(Event('floorSelected', floor=4)) with self.assertRaises(InvariantFailed) as cm: self.interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, StateChart)) def test_do_not_raise(self): self.sc.invariants.append('False') interpreter = Interpreter(self.sc, ignore_contract=True) interpreter.send(Event('floorSelected', floor=4)) interpreter.execute()
class StopwatchApplication(tk.Frame): def __init__(self, master=None): super().__init__(master) # Initialize widgets self.create_widgets() # Create a Stopwatch interpreter with open('stopwatch.yaml') as f: statechart = import_from_yaml(f) self.interpreter = Interpreter(statechart, initial_time=time.time()) # Bind interpreter events to the GUI self.interpreter.bind(self.event_handler) # Run the interpreter self.run() def run(self): # This function does essentially the same job than ``sismic.interpreter.run_in_background`` # but uses Tkinter's mainloop instead of a Thread, which is more adequate. # Update internal clock and execute interpreter self.interpreter.time = time.time() self.interpreter.execute() # Queue a call every 100ms on tk's mainloop self.after(100, self.run) # Update the widget that contains the list of active states. self.w_states['text'] = 'active states: ' + ', '.join(self.interpreter.configuration) def create_widgets(self): self.pack() # Add buttons self.w_btn_start = tk.Button(self, text='start', command=self._start) self.w_btn_stop = tk.Button(self, text='stop', command=self._stop) self.w_btn_split = tk.Button(self, text='split', command=self._split) self.w_btn_unsplit = tk.Button(self, text='unsplit', command=self._unsplit) self.w_btn_reset = tk.Button(self, text='reset', command=self._reset) self.w_btn_quit = tk.Button(self, text='quit', command=self._quit) # Initial button states self.w_btn_stop['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.DISABLED # Pack self.w_btn_start.pack(side=tk.LEFT,) self.w_btn_stop.pack(side=tk.LEFT,) self.w_btn_split.pack(side=tk.LEFT,) self.w_btn_unsplit.pack(side=tk.LEFT,) self.w_btn_reset.pack(side=tk.LEFT,) self.w_btn_quit.pack(side=tk.LEFT,) # Active states label self.w_states = tk.Label(root) self.w_states.pack(side=tk.BOTTOM, fill=tk.X) # Timer label self.w_timer = tk.Label(root, font=("Helvetica", 16), pady=5) self.w_timer.pack(side=tk.BOTTOM, fill=tk.X) def event_handler(self, event): # Update text widget when timer value is updated if event.name == 'refresh': self.w_timer['text'] = event.time def _start(self): self.interpreter.queue(Event('start')) self.w_btn_start['state'] = tk.DISABLED self.w_btn_stop['state'] = tk.NORMAL def _stop(self): self.interpreter.queue(Event('stop')) self.w_btn_start['state'] = tk.NORMAL self.w_btn_stop['state'] = tk.DISABLED def _reset(self): self.interpreter.queue(Event('reset')) def _split(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.NORMAL def _unsplit(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.NORMAL self.w_btn_unsplit['state'] = tk.DISABLED def _quit(self): self.master.destroy()
class StopwatchApplication(tk.Frame): def __init__(self, master=None): super().__init__(master) # Initialize widgets self.create_widgets() # Create a Stopwatch interpreter with open('stopwatch_external.yaml') as f: statechart = import_from_yaml(f) # Create a stopwatch object and pass it to the interpreter self.stopwatch = Stopwatch() self.interpreter = Interpreter(statechart, initial_context={'stopwatch': self.stopwatch}, initial_time=time.time()) # Run the interpreter self.run() # Update the stopwatch every 100ms self.after(100, self.update_stopwatch) def update_stopwatch(self): self.stopwatch.update(delta=0.1) self.after(100, self.update_stopwatch) # Update timer label self.w_timer['text'] = self.stopwatch.display() def run(self): # Queue a call every 100ms on tk's mainloop self.interpreter.execute() self.after(100, self.run) self.w_states['text'] = 'active states: ' + ', '.join(self.interpreter.configuration) def create_widgets(self): self.pack() # Add buttons self.w_btn_start = tk.Button(self, text='start', command=self._start) self.w_btn_stop = tk.Button(self, text='stop', command=self._stop) self.w_btn_split = tk.Button(self, text='split', command=self._split) self.w_btn_unsplit = tk.Button(self, text='unsplit', command=self._unsplit) self.w_btn_reset = tk.Button(self, text='reset', command=self._reset) self.w_btn_quit = tk.Button(self, text='quit', command=self._quit) # Initial button states self.w_btn_stop['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.DISABLED # Pack self.w_btn_start.pack(side=tk.LEFT,) self.w_btn_stop.pack(side=tk.LEFT,) self.w_btn_split.pack(side=tk.LEFT,) self.w_btn_unsplit.pack(side=tk.LEFT,) self.w_btn_reset.pack(side=tk.LEFT,) self.w_btn_quit.pack(side=tk.LEFT,) # Active states label self.w_states = tk.Label(root) self.w_states.pack(side=tk.BOTTOM, fill=tk.X) # Timer label self.w_timer = tk.Label(root, font=("Helvetica", 16), pady=5) self.w_timer.pack(side=tk.BOTTOM, fill=tk.X) def _start(self): self.interpreter.queue(Event('start')) self.w_btn_start['state'] = tk.DISABLED self.w_btn_stop['state'] = tk.NORMAL def _stop(self): self.interpreter.queue(Event('stop')) self.w_btn_start['state'] = tk.NORMAL self.w_btn_stop['state'] = tk.DISABLED def _reset(self): self.interpreter.queue(Event('reset')) def _split(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.NORMAL def _unsplit(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.NORMAL self.w_btn_unsplit['state'] = tk.DISABLED def _quit(self): self.master.destroy()
class MicrowaveApplication(tk.Frame): def __init__(self, master=None): super().__init__(master) # Initialize widgets self.create_widgets() # Create a Stopwatch interpreter with open('microwave.yaml') as f: statechart = import_from_yaml(f) self.interpreter = Interpreter(statechart) # Bind interpreter events to the GUI self.interpreter.bind(self.event_handler) self.execute() def execute(self): self.interpreter.execute() # Update the widget that contains the list of active states. self.w_states['text'] = '\n'.join(self.interpreter.configuration) self.w_timer['text'] = 'M.timer: %d' % self.interpreter.context.get( 'controller.timer', 'undefined') self.w_power['text'] = 'M.power: %d' % self.interpreter.context.get( 'controller.power', 'undefined') def create_widgets(self): self.pack(fill=tk.BOTH) # MAIN frame containing all others left_frame = tk.Frame(self) left_frame.pack(side=tk.LEFT, fill=tk.BOTH) # INPUT frame input_frame = tk.LabelFrame(left_frame, text='INPUT BUTTONS') input_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) self.w_power_inc = tk.Button(input_frame, text='power +', command=partial( self.send_event, event_name='input_power_inc')) self.w_power_dec = tk.Button(input_frame, text='power -', command=partial( self.send_event, event_name='input_power_dec')) self.w_power_reset = tk.Button(input_frame, text='power reset', command=partial( self.send_event, event_name='input_power_reset')) self.w_power_inc.pack(side=tk.TOP, fill=tk.X) self.w_power_dec.pack(side=tk.TOP, fill=tk.X) self.w_power_reset.pack(side=tk.TOP, fill=tk.X) self.w_timer_inc = tk.Button(input_frame, text='timer +', command=partial( self.send_event, event_name='input_timer_inc')) self.w_timer_dec = tk.Button(input_frame, text='timer -', command=partial( self.send_event, event_name='input_timer_dec')) self.w_timer_reset = tk.Button(input_frame, text='timer 0', command=partial( self.send_event, event_name='input_timer_reset')) self.w_timer_inc.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) # leave some space before first button self.w_timer_dec.pack(side=tk.TOP, fill=tk.X) self.w_timer_reset.pack(side=tk.TOP, fill=tk.X) self.w_cooking_start = tk.Button(input_frame, text='start', command=partial( self.send_event, event_name='input_cooking_start')) self.w_cooking_stop = tk.Button(input_frame, text='stop', command=partial( self.send_event, event_name='input_cooking_stop')) self.w_cooking_start.pack( side=tk.TOP, fill=tk.X, pady=(8, 0)) # leave some space before first button self.w_cooking_stop.pack(side=tk.TOP, fill=tk.X) # SENSORS frame sensors_frame = tk.LabelFrame(left_frame, text='SENSORS') sensors_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # SENSORS > Clock frame clock_frame = tk.LabelFrame(sensors_frame, text='Clock') clock_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_clock = tk.Label(clock_frame) self.w_tick = tk.Button(clock_frame, text='tick', command=partial(self.send_event, event_name='timer_tick')) self.w_tick.pack(side=tk.TOP, fill=tk.X) # SENSORS > WeightSensor frame weight_frame = tk.LabelFrame(sensors_frame, text='WeightSensor') weight_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=(8, 0)) self.w_weight = tk.Label(weight_frame) self.w_item_placed = tk.Button(weight_frame, text='place item', command=partial( self.send_event, event_name='item_placed')) self.w_item_removed = tk.Button(weight_frame, text='remove item', command=partial( self.send_event, event_name='item_removed')) self.w_item_placed.pack(side=tk.TOP, fill=tk.X) self.w_item_removed.pack(side=tk.TOP, fill=tk.X) # SENSORS > Door frame door_frame = tk.LabelFrame(sensors_frame, text='Door') door_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=(8, 0)) self.w_door = tk.Label(door_frame) self.w_door_opened = tk.Button(door_frame, text='open door', command=partial( self.send_event, event_name='door_opened')) self.w_door_closed = tk.Button(door_frame, text='close door', command=partial( self.send_event, event_name='door_closed')) self.w_door_opened.pack(side=tk.TOP, fill=tk.X) self.w_door_closed.pack(side=tk.TOP, fill=tk.X) # ACTUATORS frame right_frame = tk.LabelFrame(self, text='ACTUATORS') right_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Display component display_frame = tk.LabelFrame(right_frame, text='Display') display_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_display = tk.Label(display_frame) self.w_display.pack(side=tk.TOP) # Lamp component lamp_frame = tk.LabelFrame(right_frame, text='Lamp') lamp_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_lamp = tk.Label(lamp_frame) self.w_lamp.pack(side=tk.TOP) # Heating component heating_frame = tk.LabelFrame(right_frame, text='Heating') heating_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_heating_power = tk.Label(heating_frame) self.w_heating_status = tk.Label(heating_frame) self.w_heating_power.pack(side=tk.TOP) self.w_heating_status.pack(side=tk.TOP) # Beeper component beep_frame = tk.LabelFrame(right_frame, text='Beeper') beep_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_beep = tk.Label(beep_frame) self.w_beep.pack(side=tk.TOP) # Turntable component turntable_frame = tk.LabelFrame(right_frame, text='Turntable') turntable_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_turntable = tk.Label(turntable_frame) self.w_turntable.pack(side=tk.TOP) # Oven controller statechart component controller_frame = tk.LabelFrame(self, text='Oven Controller') controller_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Microwave Controller Statechart status # statechart_frame = tk.LabelFrame(right_frame2, text='Controller') # statechart_frame.pack(side=tk.TOP, fill=tk.BOTH) states_frame = tk.LabelFrame(controller_frame, text='States') states_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_states = tk.Label(states_frame) self.w_states.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) variables_frame = tk.LabelFrame(controller_frame, text='Variables') variables_frame.pack(side=tk.TOP, fill=tk.BOTH, pady=(8, 0)) self.w_timer = tk.Label(variables_frame) self.w_timer.pack(side=tk.BOTTOM, fill=tk.X) self.w_power = tk.Label(variables_frame) self.w_power.pack(side=tk.BOTTOM, fill=tk.X) def event_handler(self, event): name = event.name if name == 'lamp_switch_on': self.w_lamp['text'] = 'on' elif name == 'lamp_switch_off': self.w_lamp['text'] = 'off' elif name == 'display_set': self.w_display['text'] = event.text elif name == 'display_clear': self.w_display['text'] = '' elif name == 'heating_set_power': self.w_heating_power['text'] = event.power elif name == 'heating_on': self.w_heating_status['text'] = 'on' elif name == 'heating_off': self.w_heating_status['text'] = 'off' elif name == 'beep': self.w_beep['text'] = event.number elif name == 'turntable_start': self.w_turntable['text'] = 'on' elif name == 'turntable_stop': self.w_turntable['text'] = 'off' else: raise ValueError('Unknown event %s' % event) def send_event(self, event_name): self.interpreter.queue(Event(event_name)) self.execute() def _quit(self): self.master.destroy()
class StopwatchApplication(tk.Frame): def __init__(self, master=None): super().__init__(master) # Initialize widgets self.create_widgets() # Create a Stopwatch interpreter with open('stopwatch.yaml') as f: statechart = import_from_yaml(f) self.interpreter = Interpreter(statechart) self.interpreter.time = time.time() # Bind interpreter events to the GUI self.interpreter.bind(self.event_handler) # Run the interpreter self.run() def run(self): # This function does essentially the same job than ``sismic.interpreter.run_in_background`` # but uses Tkinter's mainloop instead of a Thread, which is more adequate. # Update internal clock and execute interpreter self.interpreter.time = time.time() self.interpreter.execute() # Queue a call every 100ms on tk's mainloop self.after(100, self.run) # Update the widget that contains the list of active states. self.w_states['text'] = 'active states: ' + ', '.join( self.interpreter.configuration) def create_widgets(self): self.pack() # Add buttons self.w_btn_start = tk.Button(self, text='start', command=self._start) self.w_btn_stop = tk.Button(self, text='stop', command=self._stop) self.w_btn_split = tk.Button(self, text='split', command=self._split) self.w_btn_unsplit = tk.Button(self, text='unsplit', command=self._unsplit) self.w_btn_reset = tk.Button(self, text='reset', command=self._reset) self.w_btn_quit = tk.Button(self, text='quit', command=self._quit) # Initial button states self.w_btn_stop['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.DISABLED # Pack self.w_btn_start.pack(side=tk.LEFT, ) self.w_btn_stop.pack(side=tk.LEFT, ) self.w_btn_split.pack(side=tk.LEFT, ) self.w_btn_unsplit.pack(side=tk.LEFT, ) self.w_btn_reset.pack(side=tk.LEFT, ) self.w_btn_quit.pack(side=tk.LEFT, ) # Active states label self.w_states = tk.Label(root) self.w_states.pack(side=tk.BOTTOM, fill=tk.X) # Timer label self.w_timer = tk.Label(root, font=("Helvetica", 16), pady=5) self.w_timer.pack(side=tk.BOTTOM, fill=tk.X) def event_handler(self, event): # Update text widget when timer value is updated if event.name == 'refresh': self.w_timer['text'] = event.time def _start(self): self.interpreter.queue(Event('start')) self.w_btn_start['state'] = tk.DISABLED self.w_btn_stop['state'] = tk.NORMAL def _stop(self): self.interpreter.queue(Event('stop')) self.w_btn_start['state'] = tk.NORMAL self.w_btn_stop['state'] = tk.DISABLED def _reset(self): self.interpreter.queue(Event('reset')) def _split(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.NORMAL def _unsplit(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.NORMAL self.w_btn_unsplit['state'] = tk.DISABLED def _quit(self): self.master.destroy()
class ElevatorContractTests(unittest.TestCase): def setUp(self): with open('docs/examples/elevator/elevator.yaml') as f: self.sc = io.import_from_yaml(f) self.interpreter = Interpreter(self.sc) def test_no_error(self): self.interpreter.queue(Event('floorSelected', floor=4)) self.interpreter.execute() self.assertFalse(self.interpreter.final) def test_state_precondition(self): self.sc.state_for('movingUp').preconditions.append('False') self.interpreter.queue(Event('floorSelected', floor=4)) with self.assertRaises(PreconditionError) as cm: self.interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, StateMixin)) def test_state_postcondition(self): self.sc.state_for('movingUp').postconditions.append('False') self.interpreter.queue(Event('floorSelected', floor=4)) with self.assertRaises(PostconditionError) as cm: self.interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, StateMixin)) def test_state_invariant(self): self.sc.state_for('movingUp').invariants.append('False') self.interpreter.queue(Event('floorSelected', floor=4)) with self.assertRaises(InvariantError) as cm: self.interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, StateMixin)) def test_transition_precondition(self): transitions = self.sc.transitions_from('floorSelecting') transitions[0].preconditions.append('False') self.interpreter.queue(Event('floorSelected', floor=4)) with self.assertRaises(PreconditionError) as cm: self.interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, Transition)) def test_transition_postcondition(self): transitions = self.sc.transitions_from('floorSelecting') transitions[0].postconditions.append('False') self.interpreter.queue(Event('floorSelected', floor=4)) with self.assertRaises(PostconditionError) as cm: self.interpreter.execute() self.assertTrue(isinstance(cm.exception.obj, Transition)) def test_do_not_raise(self): self.interpreter = Interpreter(self.sc, ignore_contract=True) transitions = self.sc.transitions_from('floorSelecting') transitions[0].postconditions.append('False') self.interpreter.queue(Event('floorSelected', floor=4)) self.interpreter.execute()
class StopwatchApplication(tk.Frame): def __init__(self, master=None): super().__init__(master) # Initialize widgets self.create_widgets() # Create a Stopwatch interpreter with open('stopwatch_external.yaml') as f: statechart = import_from_yaml(f) # Create a stopwatch object and pass it to the interpreter self.stopwatch = Stopwatch() self.interpreter = Interpreter( statechart, initial_context={'stopwatch': self.stopwatch}) self.interpreter.time = time.time() # Run the interpreter self.run() # Update the stopwatch every 100ms self.after(100, self.update_stopwatch) def update_stopwatch(self): self.stopwatch.update(delta=0.1) self.after(100, self.update_stopwatch) # Update timer label self.w_timer['text'] = self.stopwatch.display() def run(self): # Queue a call every 100ms on tk's mainloop self.interpreter.execute() self.after(100, self.run) self.w_states['text'] = 'active states: ' + ', '.join( self.interpreter.configuration) def create_widgets(self): self.pack() # Add buttons self.w_btn_start = tk.Button(self, text='start', command=self._start) self.w_btn_stop = tk.Button(self, text='stop', command=self._stop) self.w_btn_split = tk.Button(self, text='split', command=self._split) self.w_btn_unsplit = tk.Button(self, text='unsplit', command=self._unsplit) self.w_btn_reset = tk.Button(self, text='reset', command=self._reset) self.w_btn_quit = tk.Button(self, text='quit', command=self._quit) # Initial button states self.w_btn_stop['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.DISABLED # Pack self.w_btn_start.pack(side=tk.LEFT, ) self.w_btn_stop.pack(side=tk.LEFT, ) self.w_btn_split.pack(side=tk.LEFT, ) self.w_btn_unsplit.pack(side=tk.LEFT, ) self.w_btn_reset.pack(side=tk.LEFT, ) self.w_btn_quit.pack(side=tk.LEFT, ) # Active states label self.w_states = tk.Label(root) self.w_states.pack(side=tk.BOTTOM, fill=tk.X) # Timer label self.w_timer = tk.Label(root, font=("Helvetica", 16), pady=5) self.w_timer.pack(side=tk.BOTTOM, fill=tk.X) def _start(self): self.interpreter.queue(Event('start')) self.w_btn_start['state'] = tk.DISABLED self.w_btn_stop['state'] = tk.NORMAL def _stop(self): self.interpreter.queue(Event('stop')) self.w_btn_start['state'] = tk.NORMAL self.w_btn_stop['state'] = tk.DISABLED def _reset(self): self.interpreter.queue(Event('reset')) def _split(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.DISABLED self.w_btn_unsplit['state'] = tk.NORMAL def _unsplit(self): self.interpreter.queue(Event('split')) self.w_btn_split['state'] = tk.NORMAL self.w_btn_unsplit['state'] = tk.DISABLED def _quit(self): self.master.destroy()
class MicrowaveApplication(tk.Frame): def __init__(self, master, statechart, contracts, properties): super().__init__(master) # Initialize widgets self.create_widgets() # Create a Stopwatch interpreter statechart = import_from_yaml(statechart) self.interpreter = Interpreter(statechart, ignore_contract=not contracts) # Bind interpreter events to the GUI self.interpreter.bind(self.event_handler) # Bind execution watchers self.watcher = ExecutionWatcher(self.interpreter) for prop in properties if properties else []: self.watcher.watch_with(import_from_yaml(prop), fails_fast=True) self.watcher.start() # Hide disabled widgets for widget_name in DISABLED_WIDGETS: widget = getattr(self, widget_name) widget.pack_forget() self.on_autotick() self.execute() def execute(self): try: print(self.interpreter.execute()) except ContractError as e: messagebox.showerror( 'Contract error!', e.__class__.__name__ + '\n\n' + 'The following assertion does not hold in ' + str(e.obj) + ':\n' + e.condition + '\n\n' + 'Step: \n' + str(e.step)) self.master.destroy() raise except AssertionError as e: messagebox.showerror('Unsatisfied property', e.args[0]) self.master.destroy() raise except Exception as e: messagebox.showerror( 'Fatal error', e.__class__.__name__ + ' was raised during the execution.\n' + 'See console for the traceback.') self.master.destroy() raise # Update the widget that contains the list of active states. self.w_states['text'] = '\n'.join(self.interpreter.configuration) self.w_context['text'] = '\n'.join([ '%s: %s' % (key, self.interpreter.context[key]) for key in sorted(self.interpreter.context) ]) def create_widgets(self): self.pack(fill=tk.BOTH) # Statechart status controller_frame = tk.LabelFrame(self, text='CONTROLLER') controller_frame.pack(side=tk.BOTTOM, fill=tk.X, padx=(8, 8)) state_frame = tk.LabelFrame(controller_frame, text='Active configuration') state_frame.pack(side=tk.BOTTOM, fill=tk.X) self.w_states = tk.Label(state_frame) self.w_states.pack(side=tk.BOTTOM, fill=tk.X) context_frame = tk.LabelFrame(controller_frame, text='Context') context_frame.pack(side=tk.BOTTOM, fill=tk.X) self.w_context = tk.Label(context_frame) self.w_context.pack(side=tk.BOTTOM, fill=tk.X) # left_frame = tk.Frame(self) left_frame.pack(side=tk.LEFT, fill=tk.BOTH) # Input frame input_frame = tk.LabelFrame(left_frame, text='INPUT BUTTONS') input_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Sensor frame sensors_frame = tk.LabelFrame(left_frame, text='ACTUATORS') sensors_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Add buttons self.w_input_power_inc = tk.Button(input_frame, text='power +', command=partial( self.send_event, event_name='input_power_inc')) self.w_input_power_dec = tk.Button(input_frame, text='power -', command=partial( self.send_event, event_name='input_power_dec')) self.w_input_power_reset = tk.Button( input_frame, text='power 0', command=partial(self.send_event, event_name='input_power_reset')) self.w_input_timer_inc = tk.Button(input_frame, text='timer +', command=partial( self.send_event, event_name='input_timer_inc')) self.w_input_timer_dec = tk.Button(input_frame, text='timer -', command=partial( self.send_event, event_name='input_timer_dec')) self.w_input_timer_reset = tk.Button( input_frame, text='timer 0', command=partial(self.send_event, event_name='input_timer_reset')) self.w_input_cooking_start = tk.Button( input_frame, text='start', command=partial(self.send_event, event_name='input_cooking_start')) self.w_input_cooking_stop = tk.Button( input_frame, text='stop', command=partial(self.send_event, event_name='input_cooking_stop')) self.w_tick = tk.Button(sensors_frame, text='tick', command=partial(self.send_event, event_name='timer_tick')) self.v_autotick = tk.BooleanVar() self.v_autotick.set(True) self.w_autotick = tk.Checkbutton(sensors_frame, text='Auto-tick', var=self.v_autotick, command=self.on_autotick) self.w_item_placed = tk.Button(sensors_frame, text='place item', command=partial( self.send_event, event_name='item_placed')) self.w_item_removed = tk.Button(sensors_frame, text='remove item', command=partial( self.send_event, event_name='item_removed')) self.w_door_opened = tk.Button(sensors_frame, text='open door', command=partial( self.send_event, event_name='door_opened')) self.w_door_closed = tk.Button(sensors_frame, text='close door', command=partial( self.send_event, event_name='door_closed')) # Pack self.w_input_power_inc.pack(side=tk.TOP, fill=tk.X) self.w_input_power_dec.pack(side=tk.TOP, fill=tk.X) self.w_input_power_reset.pack(side=tk.TOP, fill=tk.X) self.w_input_timer_inc.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) self.w_input_timer_dec.pack(side=tk.TOP, fill=tk.X) self.w_input_timer_reset.pack(side=tk.TOP, fill=tk.X) self.w_input_cooking_start.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) self.w_input_cooking_stop.pack(side=tk.TOP, fill=tk.X) self.w_autotick.pack(side=tk.TOP, fill=tk.X) self.w_tick.pack(side=tk.TOP, fill=tk.X) self.w_item_placed.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) self.w_item_removed.pack(side=tk.TOP, fill=tk.X) self.w_door_opened.pack(side=tk.TOP, fill=tk.X, pady=(8, 0)) self.w_door_closed.pack(side=tk.TOP, fill=tk.X) right_frame = tk.LabelFrame(self, text='COMPONENTS') right_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(8, 8)) # Door component self.w_doorsensor_frame = tk.LabelFrame(right_frame, text='Door') self.w_doorsensor_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_doorsensor = tk.Label(self.w_doorsensor_frame) self.w_doorsensor.config(text='closed') self.w_doorsensor.pack(side=tk.TOP) # Weightsensor component self.w_weightsensor_frame = tk.LabelFrame(right_frame, text='Weight sensor') self.w_weightsensor_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_weightsensor = tk.Label(self.w_weightsensor_frame) self.w_weightsensor.config(text='no item') self.w_weightsensor.pack(side=tk.TOP) # Display component self.w_display_frame = tk.LabelFrame(right_frame, text='Display') self.w_display_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_display = tk.Label(self.w_display_frame) self.w_display.pack(side=tk.TOP) # Lamp component self.w_lamp_frame = tk.LabelFrame(right_frame, text='Lamp') self.w_lamp_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_lamp = tk.Label(self.w_lamp_frame) self.w_lamp.pack(side=tk.TOP) # Heating component self.w_heating_frame = tk.LabelFrame(right_frame, text='Heating') self.w_heating_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_heating_power = tk.Label(self.w_heating_frame) self.w_heating_status = tk.Label(self.w_heating_frame) self.w_heating_power.pack(side=tk.TOP) self.w_heating_status.pack(side=tk.TOP) # Beeper component self.w_beep_frame = tk.LabelFrame(right_frame, text='Beeper') self.w_beep_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_beep = tk.Label(self.w_beep_frame) self.w_beep.pack(side=tk.TOP) # Turntable component self.w_turntable_frame = tk.LabelFrame(right_frame, text='Turntable') self.w_turntable_frame.pack(side=tk.TOP, fill=tk.BOTH) self.w_turntable = tk.Label(self.w_turntable_frame) self.w_turntable.pack(side=tk.TOP) def event_handler(self, event): name = event.name if name == 'lamp_switch_on': self.w_lamp['text'] = 'on' elif name == 'lamp_switch_off': self.w_lamp['text'] = 'off' elif name == 'display_set': self.w_display['text'] = event.text elif name == 'display_clear': self.w_display['text'] = '' elif name == 'heating_set_power': self.w_heating_power['text'] = event.power elif name == 'heating_on': self.w_heating_status['text'] = 'on' elif name == 'heating_off': self.w_heating_status['text'] = 'off' elif name == 'beep': self.w_beep['text'] = event.number elif name == 'turntable_start': self.w_turntable['text'] = 'on' elif name == 'turntable_stop': self.w_turntable['text'] = 'off' else: raise ValueError('Unknown event %s' % event) def on_autotick(self): if self.v_autotick.get(): self.send_event('timer_tick') self.after(1000, self.on_autotick) def send_event(self, event_name): if event_name == 'item_placed': self.w_weightsensor.config(text='item detected') elif event_name == 'item_removed': self.w_weightsensor.config(text='no item') elif event_name == 'door_opened': self.w_doorsensor.config(text='open') elif event_name == 'door_closed': self.w_doorsensor.config(text='closed') self.interpreter.queue(Event(event_name)) self.execute() def _quit(self): self.master.destroy()