Esempio n. 1
0
    def test_composite_statechart_finished(self):
        statechart = Statechart(name='statechart')
        init = InitialState(statechart)
        final = FinalState(statechart)

        composite = CompositeState(name='composite', context=statechart)
        composite_init = InitialState(composite)
        composite_default = State(name='composite_default', context=composite)
        composite_final = FinalState(composite)

        finish = Event('finish')

        Transition(start=init, end=composite)
        Transition(start=composite_init, end=composite_default)
        Transition(start=composite_default, end=composite_final, event=finish)
        Transition(start=composite, end=final)

        statechart.start()

        assert statechart.is_active('composite')
        assert statechart.is_active('composite_default')
        assert not statechart.is_finished()

        statechart.dispatch(finish)

        assert statechart.is_finished()
Esempio n. 2
0
    def test_default_transition_from_finished_composite_state(self):
        statechart = Statechart(name="statechart")
        statechart_init = InitialState(statechart)

        composite_state = CompositeState(name="composite", context=statechart)
        comp_init = InitialState(composite_state)
        a = State(name="a", context=composite_state)
        comp_final = FinalState(composite_state)

        Transition(start=statechart_init, end=composite_state)
        Transition(start=comp_init, end=a)
        Transition(start=a, end=comp_final, event=Event("e"))

        b = State(name="b", context=statechart)
        c = State(name="c", context=statechart)
        d = State(name="d", context=statechart)

        Transition(start=composite_state, end=c, event=Event("f"))
        Transition(start=composite_state, end=b, event=Event("e"))
        Transition(start=composite_state, end=d)

        statechart.start()

        assert statechart.is_active("a")

        statechart.dispatch(Event("e"))

        assert statechart.is_active("d")
Esempio n. 3
0
    def test_default_transition_from_finished_composite_state(self):
        statechart = Statechart(name='statechart')
        statechart_init = InitialState(statechart)

        composite_state = CompositeState(name='composite', context=statechart)
        comp_init = InitialState(composite_state)
        a = State(name='a', context=composite_state)
        comp_final = FinalState(composite_state)

        Transition(start=statechart_init, end=composite_state)
        Transition(start=comp_init, end=a)
        Transition(start=a, end=comp_final, event=Event('e'))

        b = State(name='b', context=statechart)
        c = State(name='c', context=statechart)
        d = State(name='d', context=statechart)

        Transition(start=composite_state, end=c, event=Event('f'))
        Transition(start=composite_state, end=b, event=Event('e'))
        Transition(start=composite_state, end=d)

        statechart.start()

        assert statechart.is_active('a')

        statechart.dispatch(Event('e'))

        assert statechart.is_active('d')
Esempio n. 4
0
def main() -> None:
    """Code here shows how everything is wired together.

    The following lines are the expected output:

        state 'state-a' got event 'None'
        state 'state-b' got event 'Event(name="to-state-b", data={})'
    """
    # Create the state machine -- the root context of every workflow.
    state_machine = Statechart("state-machine")

    # Create the workflow metadata with all the data accessible to all states and workflows.
    metadata = WorkflowMetadata(a=10, b="foo", c="bar")

    # Create the workflow factory backed by the workflow metadata.
    factory = WorkflowFactory(metadata)

    # Create the main workflow using the workflow factory.
    main_workflow = factory.create_workflow("main-workflow", state_machine, MainWorkflow)

    # Set up the main transitions.
    init = InitialState(state_machine)
    final = FinalState(state_machine)
    Transition(init, main_workflow)
    Transition(main_workflow, final, event=Event("final"))

    # Run the state machine.
    state_machine.start()
    state_machine.dispatch(Event("to-state-b"))
Esempio n. 5
0
    def test_composite_statechart_finished(self):
        statechart = Statechart(name="statechart")
        init = InitialState(statechart)
        final = FinalState(statechart)

        composite = CompositeState(name="composite", context=statechart)
        composite_init = InitialState(composite)
        composite_default = State(name="composite_default", context=composite)
        composite_final = FinalState(composite)

        finish = Event("finish")

        Transition(start=init, end=composite)
        Transition(start=composite_init, end=composite_default)
        Transition(start=composite_default, end=composite_final, event=finish)
        Transition(start=composite, end=final)

        statechart.start()

        assert statechart.is_active("composite")
        assert statechart.is_active("composite_default")
        assert not statechart.is_finished()

        statechart.dispatch(finish)

        assert statechart.is_finished()
Esempio n. 6
0
    def test_light_switch(self):
        """
                      --Flick-->
        init ---> Off            On
                      <--Flick--   Entry: Light = ON
                                   Exit: Light = OFF
                                   Internal:
                                     Flick: Count++
        """
        class On(State):
            def __init__(self, name, context, data):
                State.__init__(self, name=name, context=context)
                self.data = data

            def entry(self, event):
                self.data['light'] = 'on'

            def exit(self, event):
                self.data['light'] = 'off'

            def handle_internal(self, event):
                if event.name == 'flick':
                    self.data['on_count'] += 1

        sm = Statechart(name='sm')
        data = dict(light='off', on_count=0)
        sm.initial_state = InitialState(context=sm)
        off = State(name='off', context=sm)
        on = On(name='on', context=sm, data=data)

        Transition(start=sm.initial_state, end=off)
        Transition(start=off, end=on, event=Event('flick'))
        Transition(start=on, end=off, event=Event('flick'))

        sm.start()

        assert data['light'] == 'off'

        sm.dispatch(Event('flick'))
        assert data['light'] == 'on'

        assert data['on_count'] == 0

        sm.dispatch(Event('flick'))
        assert data['light'] == 'off'

        assert data['on_count'] == 1
Esempio n. 7
0
    def test_simple_statechart_finished(self):
        statechart = Statechart(name='statechart')
        init = InitialState(statechart)
        default = State(name='default', context=statechart)
        final = FinalState(statechart)

        finish = Event('finish')

        Transition(start=init, end=default)
        Transition(start=default, end=final, event=finish)
        statechart.start()

        assert statechart.is_active('default')
        assert not statechart.is_finished()

        statechart.dispatch(finish)

        assert statechart.is_finished()
Esempio n. 8
0
    def test_simple_statechart_finished(self):
        statechart = Statechart(name="statechart")
        init = InitialState(statechart)
        default = State(name="default", context=statechart)
        final = FinalState(statechart)

        finish = Event("finish")

        Transition(start=init, end=default)
        Transition(start=default, end=final, event=finish)
        statechart.start()

        assert statechart.is_active("default")
        assert not statechart.is_finished()

        statechart.dispatch(finish)

        assert statechart.is_finished()
Esempio n. 9
0
    def test_submachines(self):
        statechart = Statechart(name='statechart')

        init = InitialState(statechart)
        top_a = self.Submachine('top a', statechart)
        top_b = self.Submachine('top b', statechart)

        top_a_to_b = Event('top ab')
        Transition(start=init, end=top_a)
        Transition(start=top_a, end=top_b, event=top_a_to_b)

        statechart.start()

        assert statechart.is_active('top a')
        assert statechart.is_active('sub state a')

        statechart.dispatch(top_a.sub_a_to_b)

        assert statechart.is_active('top a')
        assert statechart.is_active('sub state b')

        statechart.dispatch(top_a_to_b)

        assert statechart.is_active('top b')
        assert statechart.is_active('sub state a')

        statechart.dispatch(top_a.sub_a_to_b)

        assert statechart.is_active('top b')
        assert statechart.is_active('sub state b')
Esempio n. 10
0
    def test_submachines(self):
        statechart = Statechart(name="statechart")

        init = InitialState(statechart)
        top_a = self.Submachine("top a", statechart)
        top_b = self.Submachine("top b", statechart)

        top_a_to_b = Event("top ab")
        Transition(start=init, end=top_a)
        Transition(start=top_a, end=top_b, event=top_a_to_b)

        statechart.start()

        assert statechart.is_active("top a")
        assert statechart.is_active("sub state a")

        statechart.dispatch(top_a.sub_a_to_b)

        assert statechart.is_active("top a")
        assert statechart.is_active("sub state b")

        statechart.dispatch(top_a_to_b)

        assert statechart.is_active("top b")
        assert statechart.is_active("sub state a")

        statechart.dispatch(top_a.sub_a_to_b)

        assert statechart.is_active("top b")
        assert statechart.is_active("sub state b")
Esempio n. 11
0
    def test_default_transition_isnt_executed_from_unfinished_composite_state(self):
        statechart = Statechart(name="statechart")
        statechart_init = InitialState(statechart)

        composite_state = CompositeState(name="composite", context=statechart)
        comp_init = InitialState(composite_state)
        a = State(name="a", context=composite_state)

        Transition(start=statechart_init, end=composite_state)
        Transition(start=comp_init, end=a)

        b = State(name="b", context=statechart)

        Transition(start=composite_state, end=b)

        statechart.start()

        assert statechart.is_active("a")

        statechart.dispatch(Event("e"))

        assert statechart.is_active("a")
Esempio n. 12
0
    def test_default_transition_isnt_executed_from_unfinished_composite_state(
            self):
        statechart = Statechart(name='statechart')
        statechart_init = InitialState(statechart)

        composite_state = CompositeState(name='composite', context=statechart)
        comp_init = InitialState(composite_state)
        a = State(name='a', context=composite_state)

        Transition(start=statechart_init, end=composite_state)
        Transition(start=comp_init, end=a)

        b = State(name='b', context=statechart)

        Transition(start=composite_state, end=b)

        statechart.start()

        assert statechart.is_active('a')

        statechart.dispatch(Event('e'))

        assert statechart.is_active('a')
Esempio n. 13
0
    def test_keyboard_example(self):
        """
        Test classic concurrent state keyboard example with concurrent states
        for caps, num and scroll lock.

        init - -
               |
               v
        -- keyboard --------------------------------------
        |                                                |
        |  init ---> --caps lock off --                  |
        |        --- |                | <--              |
        |        |   -----------------|   |              |
        |  caps lock pressed       caps lock pressed     |
        |        |   -- caps lock on --   |              |
        |        --> |                | ---              |
        |            ------------------                  |
        |                                                |
        --------------------------------------------------
        |                                                |
        |  init ---> --num lock off ---                  |
        |        --- |                | <--              |
        |        |   -----------------|   |              |
        |  num lock pressed      num lock pressed        |
        |        |   -- num lock on ---   |              |
        |        --> |                | ---              |
        |            ------------------                  |
        |                                                |
        --------------------------------------------------
        |                                                |
        |  init ---> -- scroll lock off --               |
        |        --- |                    | <--          |
        |        |   ---------------------|   |          |
        |  scroll lock pressed      scroll lock pressed  |
        |        |   -- scroll lock on ---|   |          |
        |        --> |                    | ---          |
        |            ----------------------              |
        |                                                |
        --------------------------------------------------
        """
        statechart = Statechart(name='statechart')

        start_state = InitialState(statechart)
        keyboard = ConcurrentState(name='keyboard', context=statechart)
        Transition(start=start_state, end=keyboard)

        caps_lock = CompositeState(name='caps_lock', context=keyboard)
        caps_lock_initial = InitialState(caps_lock)
        caps_lock_on = State(name='caps_lock_on', context=caps_lock)
        caps_lock_off = State(name='caps_lock_off', context=caps_lock)
        caps_lock_pressed = Event(name='caps_lock_pressed')
        Transition(start=caps_lock_initial, end=caps_lock_off)
        Transition(start=caps_lock_on,
                   end=caps_lock_off,
                   event=caps_lock_pressed)
        Transition(start=caps_lock_off,
                   end=caps_lock_on,
                   event=caps_lock_pressed)

        num_lock = CompositeState(name='num_lock', context=keyboard)
        num_lock_initial = InitialState(num_lock)
        num_lock_on = State(name='num_lock_on', context=num_lock)
        num_lock_off = State(name='num_lock_off', context=num_lock)
        num_lock_pressed = Event(name='num_lock_pressed')
        Transition(start=num_lock_initial, end=num_lock_off)
        Transition(start=num_lock_on, end=num_lock_off, event=num_lock_pressed)
        Transition(start=num_lock_off, end=num_lock_on, event=num_lock_pressed)

        scroll_lock = CompositeState(name='scroll_lock', context=keyboard)
        scroll_lock_initial = InitialState(scroll_lock)
        scroll_lock_on = State(name='scroll_lock_on', context=scroll_lock)
        scroll_lock_off = State(name='scroll_lock_off', context=scroll_lock)
        scroll_lock_pressed = Event(name='scroll_lock_pressed')
        Transition(start=scroll_lock_initial, end=scroll_lock_off)
        Transition(start=scroll_lock_on,
                   end=scroll_lock_off,
                   event=scroll_lock_pressed)
        Transition(start=scroll_lock_off,
                   end=scroll_lock_on,
                   event=scroll_lock_pressed)

        statechart.start()

        assert statechart.is_active('keyboard')
        assert statechart.is_active('caps_lock_off')
        assert statechart.is_active('num_lock_off')
        assert statechart.is_active('scroll_lock_off')

        statechart.dispatch(event=caps_lock_pressed)
        assert statechart.is_active('caps_lock_on')

        statechart.dispatch(event=num_lock_pressed)
        assert statechart.is_active('num_lock_on')

        statechart.dispatch(event=scroll_lock_pressed)
        assert statechart.is_active('scroll_lock_on')

        statechart.dispatch(event=caps_lock_pressed)
        assert statechart.is_active('caps_lock_off')

        statechart.dispatch(event=num_lock_pressed)
        assert statechart.is_active('num_lock_off')

        statechart.dispatch(event=scroll_lock_pressed)
        assert statechart.is_active('scroll_lock_off')
Esempio n. 14
0
    def test_activate_shallow_history_state(self):
        """
        statechart:

        statechart_init
                  |
        *** csa **********************          *** csb *************
        *                            *          *                   *
        *  csa_init-csa_hist         *          *  csb_init         *
        *              |             *  --J-->  *     |             *
        *              A  --I-->  B  *  <--K--  *     C  --L-->  D  *
        *                            *          *                   *
        ******************************          *********************
        """

        # Top level states
        statechart = Statechart(name='statechart')
        csa = CompositeState(name='csa', context=statechart)
        csb = CompositeState(name='csb', context=statechart)

        # Child states
        # statechart
        statechart_init = InitialState(statechart)
        # csa
        csa_init = InitialState(csa)
        csa_hist = ShallowHistoryState(context=csa)
        A = State(name='A', context=csa)
        B = State(name='B', context=csa)
        # csb
        csb_init = InitialState(csb)
        C = State(name='C', context=csb)
        D = State(name='D', context=csb)

        # Events
        I = Event(name='I')
        J = Event(name='J')
        K = Event(name='K')
        L = Event(name='L')

        # Transitions between states & event triggers
        Transition(start=statechart_init, end=csa)
        Transition(start=csa_init, end=csa_hist)
        Transition(start=csa_hist, end=A)
        Transition(start=A, end=B, event=I)
        Transition(start=csa, end=csb, event=J)
        Transition(start=csb, end=csa, event=K)
        Transition(start=csb_init, end=C)
        Transition(start=C, end=D, event=L)

        # Execute statechart
        statechart.start()
        statechart.dispatch(I)

        # Assert we have reached state B, history should restore this state
        assert statechart.is_active('B')

        statechart.dispatch(J)

        # Assert we have reached state C
        assert statechart.is_active('C')

        statechart.dispatch(K)

        # Assert the history state has restored state B
        assert statechart.is_active('B')
Esempio n. 15
0
    def test_keyboard_example(self):
        """
        Test classic concurrent state keyboard example with concurrent states
        for caps, num and scroll lock.

        init - -
               |
               v
        -- keyboard --------------------------------------
        |                                                |
        |  init ---> --caps lock off --                  |
        |        --- |                | <--              |
        |        |   -----------------|   |              |
        |  caps lock pressed       caps lock pressed     |
        |        |   -- caps lock on --   |              |
        |        --> |                | ---              |
        |            ------------------                  |
        |                                                |
        --------------------------------------------------
        |                                                |
        |  init ---> --num lock off ---                  |
        |        --- |                | <--              |
        |        |   -----------------|   |              |
        |  num lock pressed      num lock pressed        |
        |        |   -- num lock on ---   |              |
        |        --> |                | ---              |
        |            ------------------                  |
        |                                                |
        --------------------------------------------------
        |                                                |
        |  init ---> -- scroll lock off --               |
        |        --- |                    | <--          |
        |        |   ---------------------|   |          |
        |  scroll lock pressed      scroll lock pressed  |
        |        |   -- scroll lock on ---|   |          |
        |        --> |                    | ---          |
        |            ----------------------              |
        |                                                |
        --------------------------------------------------
        """
        statechart = Statechart(name="statechart")

        start_state = InitialState(statechart)
        keyboard = ConcurrentState(name="keyboard", context=statechart)
        Transition(start=start_state, end=keyboard)

        caps_lock = CompositeState(name="caps_lock", context=keyboard)
        caps_lock_initial = InitialState(caps_lock)
        caps_lock_on = State(name="caps_lock_on", context=caps_lock)
        caps_lock_off = State(name="caps_lock_off", context=caps_lock)
        caps_lock_pressed = Event(name="caps_lock_pressed")
        Transition(start=caps_lock_initial, end=caps_lock_off)
        Transition(start=caps_lock_on, end=caps_lock_off, event=caps_lock_pressed)
        Transition(start=caps_lock_off, end=caps_lock_on, event=caps_lock_pressed)

        num_lock = CompositeState(name="num_lock", context=keyboard)
        num_lock_initial = InitialState(num_lock)
        num_lock_on = State(name="num_lock_on", context=num_lock)
        num_lock_off = State(name="num_lock_off", context=num_lock)
        num_lock_pressed = Event(name="num_lock_pressed")
        Transition(start=num_lock_initial, end=num_lock_off)
        Transition(start=num_lock_on, end=num_lock_off, event=num_lock_pressed)
        Transition(start=num_lock_off, end=num_lock_on, event=num_lock_pressed)

        scroll_lock = CompositeState(name="scroll_lock", context=keyboard)
        scroll_lock_initial = InitialState(scroll_lock)
        scroll_lock_on = State(name="scroll_lock_on", context=scroll_lock)
        scroll_lock_off = State(name="scroll_lock_off", context=scroll_lock)
        scroll_lock_pressed = Event(name="scroll_lock_pressed")
        Transition(start=scroll_lock_initial, end=scroll_lock_off)
        Transition(start=scroll_lock_on, end=scroll_lock_off, event=scroll_lock_pressed)
        Transition(start=scroll_lock_off, end=scroll_lock_on, event=scroll_lock_pressed)

        statechart.start()

        assert statechart.is_active("keyboard")
        assert statechart.is_active("caps_lock_off")
        assert statechart.is_active("num_lock_off")
        assert statechart.is_active("scroll_lock_off")

        statechart.dispatch(event=caps_lock_pressed)
        assert statechart.is_active("caps_lock_on")

        statechart.dispatch(event=num_lock_pressed)
        assert statechart.is_active("num_lock_on")

        statechart.dispatch(event=scroll_lock_pressed)
        assert statechart.is_active("scroll_lock_on")

        statechart.dispatch(event=caps_lock_pressed)
        assert statechart.is_active("caps_lock_off")

        statechart.dispatch(event=num_lock_pressed)
        assert statechart.is_active("num_lock_off")

        statechart.dispatch(event=scroll_lock_pressed)
        assert statechart.is_active("scroll_lock_off")
Esempio n. 16
0
    def test_activate_multiple_shallow_history_states(self):
        """
        statechart:

        statechart_init
               |
        *** csa *****************************************************          *** csc *************
        *                                                           *          *                   *
        *  csa_init--csa_hist                                       *          *  csc_init         *
        *               |                                           *  --K-->  *     |             *
        *               A  --I-->  *** csb ***********************  *  <--L--  *     D  --M-->  E  *
        *                          *                             *  *          *                   *
        *                          *  csb_init--csb_hist         *  *          *********************
        *                          *               |             *  *
        *                          *               B  --J-->  C  *  *
        *                          *                             *  *
        *                          *******************************  *
        *                                                           *
        *************************************************************
        """
        # Top level states
        statechart = Statechart(name='statechart')
        csa = CompositeState(name='csa', context=statechart)
        csb = CompositeState(name='csb', context=csa)
        csc = CompositeState(name='csc', context=statechart)

        # Child states
        # statechart
        statechart_init = InitialState(statechart)

        # csa
        csa_init = InitialState(csa)
        csa_hist = ShallowHistoryState(context=csa)
        A = State(name='A', context=csa)
        # csb
        csb_init = InitialState(csb)
        csb_hist = ShallowHistoryState(context=csb)
        B = State(name='B', context=csb)
        C = State(name='C', context=csb)
        # csc
        csc_init = InitialState(csc)
        D = State(name='D', context=csc)
        E = State(name='E', context=csc)

        # Events
        I = Event(name='I')
        J = Event(name='J')
        K = Event(name='K')
        L = Event(name='L')
        M = Event(name='M')

        # Transitions between states & event triggers
        Transition(start=statechart_init, end=csa)
        Transition(start=csa_init, end=csa_hist)
        Transition(start=csa_hist, end=A)
        Transition(start=A, end=csb, event=I)
        Transition(start=csb_init, end=csb_hist)
        Transition(start=csb_hist, end=B)
        Transition(start=B, end=C, event=J)
        Transition(start=csa, end=csc, event=K)
        Transition(start=csc, end=csa, event=L)
        Transition(start=csc_init, end=D)
        Transition(start=D, end=E, event=M)

        # Execute statechart
        statechart.start()
        statechart.dispatch(I)

        assert statechart.is_active('B')

        statechart.dispatch(J)

        # Assert we have reached state C, csb's history state should restore
        # this state
        assert statechart.is_active('C')

        statechart.dispatch(K)

        # Assert we have reached state D
        assert statechart.is_active('D')

        statechart.dispatch(L)

        # Assert the history state has restored state C
        assert statechart.is_active('C')
Esempio n. 17
0
    def test_activate_shallow_history_state(self):
        """
        statechart:

        statechart_init
                  |
        *** csa **********************          *** csb *************
        *                            *          *                   *
        *  csa_init-csa_hist         *          *  csb_init         *
        *              |             *  --J-->  *     |             *
        *              A  --I-->  B  *  <--K--  *     C  --L-->  D  *
        *                            *          *                   *
        ******************************          *********************
        """

        # Top level states
        statechart = Statechart(name='statechart')
        csa = CompositeState(name='csa', context=statechart)
        csb = CompositeState(name='csb', context=statechart)

        # Child states
        # statechart
        statechart_init = InitialState(statechart)
        # csa
        csa_init = InitialState(csa)
        csa_hist = ShallowHistoryState(context=csa)
        A = State(name='A', context=csa)
        B = State(name='B', context=csa)
        # csb
        csb_init = InitialState(csb)
        C = State(name='C', context=csb)
        D = State(name='D', context=csb)

        # Events
        I = Event(name='I')
        J = Event(name='J')
        K = Event(name='K')
        L = Event(name='L')

        # Transitions between states & event triggers
        Transition(start=statechart_init, end=csa)
        Transition(start=csa_init, end=csa_hist)
        Transition(start=csa_hist, end=A)
        Transition(start=A, end=B, event=I)
        Transition(start=csa, end=csb, event=J)
        Transition(start=csb, end=csa, event=K)
        Transition(start=csb_init, end=C)
        Transition(start=C, end=D, event=L)

        # Execute statechart
        statechart.start()
        statechart.dispatch(I)

        # Assert we have reached state B, history should restore this state
        assert statechart.is_active('B')

        statechart.dispatch(J)

        # Assert we have reached state C
        assert statechart.is_active('C')

        statechart.dispatch(K)

        # Assert the history state has restored state B
        assert statechart.is_active('B')
Esempio n. 18
0
    def test_activate_multiple_shallow_history_states(self):
        """
        statechart:

        statechart_init
               |
        *** csa *****************************************************          *** csc *************
        *                                                           *          *                   *
        *  csa_init--csa_hist                                       *          *  csc_init         *
        *               |                                           *  --K-->  *     |             *
        *               A  --I-->  *** csb ***********************  *  <--L--  *     D  --M-->  E  *
        *                          *                             *  *          *                   *
        *                          *  csb_init--csb_hist         *  *          *********************
        *                          *               |             *  *
        *                          *               B  --J-->  C  *  *
        *                          *                             *  *
        *                          *******************************  *
        *                                                           *
        *************************************************************
        """
        # Top level states
        statechart = Statechart(name='statechart')
        csa = CompositeState(name='csa', context=statechart)
        csb = CompositeState(name='csb', context=csa)
        csc = CompositeState(name='csc', context=statechart)

        # Child states
        # statechart
        statechart_init = InitialState(statechart)

        # csa
        csa_init = InitialState(csa)
        csa_hist = ShallowHistoryState(context=csa)
        A = State(name='A', context=csa)
        # csb
        csb_init = InitialState(csb)
        csb_hist = ShallowHistoryState(context=csb)
        B = State(name='B', context=csb)
        C = State(name='C', context=csb)
        # csc
        csc_init = InitialState(csc)
        D = State(name='D', context=csc)
        E = State(name='E', context=csc)

        # Events
        I = Event(name='I')
        J = Event(name='J')
        K = Event(name='K')
        L = Event(name='L')
        M = Event(name='M')

        # Transitions between states & event triggers
        Transition(start=statechart_init, end=csa)
        Transition(start=csa_init, end=csa_hist)
        Transition(start=csa_hist, end=A)
        Transition(start=A, end=csb, event=I)
        Transition(start=csb_init, end=csb_hist)
        Transition(start=csb_hist, end=B)
        Transition(start=B, end=C, event=J)
        Transition(start=csa, end=csc, event=K)
        Transition(start=csc, end=csa, event=L)
        Transition(start=csc_init, end=D)
        Transition(start=D, end=E, event=M)

        # Execute statechart
        statechart.start()
        statechart.dispatch(I)

        assert statechart.is_active('B')

        statechart.dispatch(J)

        # Assert we have reached state C, csb's history state should restore
        # this state
        assert statechart.is_active('C')

        statechart.dispatch(K)

        # Assert we have reached state D
        assert statechart.is_active('D')

        statechart.dispatch(L)

        # Assert the history state has restored state C
        assert statechart.is_active('C')