Beispiel #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()
Beispiel #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')
Beispiel #3
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()
Beispiel #4
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")
Beispiel #5
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')
Beispiel #6
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")
Beispiel #7
0
    def test_choice_state_transitions(self, choice, expected_state_name):
        class MyMetadata(Metadata):
            def __init__(self):
                super().__init__()
                self.value = None

        class IsA(Guard):
            def check(self, metadata, event):
                return metadata.value == 'a'

        myMetadata = MyMetadata()
        myMetadata.value = choice
        statechart = Statechart(name='statechart', metadata=myMetadata)
        init = InitialState(statechart)

        state_a = State(name='a', context=statechart)
        state_b = State(name='b', context=statechart)

        choice = ChoiceState(context=statechart)

        Transition(start=init, end=choice)

        Transition(start=choice, end=state_a, event=None, guard=IsA())
        Transition(start=choice, end=state_b, event=None, guard=ElseGuard())

        statechart.start()

        assert statechart.is_active(expected_state_name)
Beispiel #8
0
    def test_activate_initial_state(self):
        startchart = Statechart(name='statechart')
        initial_state = InitialState(startchart)
        default_state = State(name='default', context=startchart)
        Transition(start=initial_state, end=default_state)
        startchart.start()

        initial_state.activate(metadata=startchart.metadata, event=None)
        assert startchart.is_active('default')
    def test_activate_initial_state(self):
        startchart = Statechart(name='statechart')
        initial_state = InitialState(startchart)
        default_state = State(name='default', context=startchart)
        Transition(start=initial_state, end=default_state)
        startchart.start()

        initial_state.activate(metadata=startchart._metadata, event=None)
        assert startchart.is_active('default')
Beispiel #10
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")
Beispiel #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')
Beispiel #12
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()
Beispiel #13
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()
Beispiel #14
0
    def test_choice_state_transitions(self, state_name, expected_state_name):
        def is_a(**kwargs):
            return state_name == 'a'

        statechart = Statechart(name='statechart')
        init = InitialState(statechart)

        state_a = State(name='a', context=statechart)
        state_b = State(name='b', context=statechart)

        choice = ChoiceState(context=statechart)

        Transition(start=init, end=choice)

        Transition(start=choice, end=state_a, event=None, guard=is_a)
        Transition(start=choice, end=state_b, event=None, guard=None)  # else

        statechart.start()

        assert statechart.is_active(expected_state_name)
Beispiel #15
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')
Beispiel #16
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')
Beispiel #17
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")
Beispiel #18
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')
Beispiel #19
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')
Beispiel #20
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')