diff options
Diffstat (limited to 'src/sugar/tutorius/tests')
-rw-r--r-- | src/sugar/tutorius/tests/coretests.py | 245 |
1 files changed, 244 insertions, 1 deletions
diff --git a/src/sugar/tutorius/tests/coretests.py b/src/sugar/tutorius/tests/coretests.py index 7792930..a28880f 100644 --- a/src/sugar/tutorius/tests/coretests.py +++ b/src/sugar/tutorius/tests/coretests.py @@ -76,7 +76,7 @@ class CountAction(Action): class TriggerEventFilter(EventFilter): """ - This event filter can be triggered by simply calling its execute function. + This event filter can be triggered by simply calling its do_callback function. Used to fake events and see the effect on the FSM. """ @@ -93,6 +93,21 @@ class TriggerEventFilter(EventFilter): def _inner_cb(self, event_filter): self.toggle_on_callback = not self.toggle_on_callback +class FakeEventFilter(TriggerEventFilter): + """ + This is a fake event that is connected to the tutorial. + + The difference between this one and the TriggerEventFilter is that the + tutorial's set_state will be called on the callback. + + Do not forget to add the do_callback() after creating the object. + """ + def set_tutorial(self, tutorial): + self.tutorial = tutorial + + def _inner_cb(self, event_filter): + self.toggle_on_callback = not self.toggle_on_callback + self.tutorial.set_state(event_filter.get_next_state()) class BaseActionTests(unittest.TestCase): def test_do_unimplemented(self): act = Action() @@ -206,7 +221,235 @@ class StateTest(unittest.TestCase): assert False, "No RuntimeWarning was raised on second set_tutorial" except : pass + + def test_add_action(self): + """ + Tests on manipulating the actions inside a state. + """ + state = State("INIT") + + act1 = CountAction() + act2 = CountAction() + act3 = CountAction() + + # Try to add the actions + assert state.add_action(act1), "Could not add the first action" + assert state.add_action(act2), "Could not add the second action" + assert state.add_action(act3), "Could not add the third action" + + # Try to add a second time an action that was already inserted + assert state.add_action(act1) == False, "Not supposed to insert an action twice" + + # Fetch the associated actions + actions = state.get_action_list() + + # Make sure all the actions are present in the state + assert act1 in actions and act2 in actions and act3 in actions,\ + "The actions were not properly inserted in the state" + + # Clear the list + state.clear_actions() + + # Make sure the list of actions is empty now + assert len(state.get_action_list()) == 0, "Clearing of actions failed" + + +class FSMTest(unittest.TestCase): + """ + This class needs to text the interface and functionality of the Finite + State Machine. + """ + + def test_sample_usage(self): + act_init = TrueWhileActiveAction() + act_second = TrueWhileActiveAction() + + event_init = FakeEventFilter("SECOND") + + content = { + "INIT": State("INIT", action_list=[act_init],event_filter_list=[event_init]), + "SECOND": State("SECOND", action_list=[act_second]) + } + + fsm = FiniteStateMachine("SampleUsage", state_dict=content) + + assert fsm is not None, "Unable to create FSM" + + tut = Tutorial("SampleUsageTutorial", fsm) + + tut.attach(None) + event_init.set_tutorial(tut) + + assert fsm.current_state.name == "INIT", "Unable to set state to initial state" + + assert act_init.active, "FSM did not call the state's action DO properly" + + # Trigger the event of the INIT state + event_init.do_callback() + + assert act_init.active == False, "FSM did not teardown INIT properly" + + assert fsm.current_state.name == "SECOND", "FSM did not switch to SECOND state" + + assert act_second.active == True, "FSM did not setup SECOND properly" + + tut.detach() + + assert act_second.active == False, "FSM did not teardown SECOND properly" + + + def test_state_insert(self): + """ + This is a simple test to insert, then find a state. + """ + st1 = State("FakeState") + + fsm = FiniteStateMachine("StateInsertTest") + + fsm.add_state(st1) + + inserted_state = fsm.get_state_by_name(st1.name) + + assert inserted_state is st1, "Inserting, then fetching a state did not work" + + # Make sure we cannot insert it twice + try : + fsm.add_state(st1) + assert False, "No error raised on addition of an already present state" + except KeyError: + pass + + def test_state_find_by_name(self): + """ + Tests the interface for fetching a state by name. + - Basic functionnality + - Non-existent state + """ + + st1 = State("INIT") + + st2 = State("second") + + fsm = FiniteStateMachine("StateFindTest") + + fsm.add_state(st1) + fsm.add_state(st2) + + # Test the fetch by name + fetched_st1 = fsm.get_state_by_name(st1.name) + + assert fetched_st1 is st1, "Fetched state is not the same as the inserted one" + + fetched_st2 = fsm.get_state_by_name(st2.name) + + assert fetched_st2 is st2, "Fetched state is not the same as the inserted one" + + try: + fsm.get_state_by_name("no such state") + assert False, "Did not get a KeyError on non-existing key search" + except KeyError: + pass + except Exception: + assert False, "Did not get the right error on non-existing key search" + + def test_state_removal(self): + """ + This test removes a state from the FSM. It also verifies that the links + from other states going into the removed state are gone. + """ + st1 = State("INIT", event_filter_list=[TriggerEventFilter("second")]) + st2 = State("second", event_filter_list=[TriggerEventFilter("third")]) + st3 = State("third", event_filter_list=[TriggerEventFilter("second")]) + + fsm = FiniteStateMachine("StateRemovalTest") + + fsm.add_state(st1) + fsm.add_state(st2) + fsm.add_state(st3) + + # First tests - Removing a non-existing state and make sure we get a + # KeyError + try: + fsm.remove_state("Non-existing") + assert False, "Removing a non-existing state did not throw a KeyError" + except KeyError: + pass + except Exception: + assert False, "Removing a non-existing state dit not throw the right kind of exception" + + + # Now try removing the second state + fsm.remove_state("second") + + # Make sure it cannot be fetched + try : + fetched_state = fsm.get_state_by_name("second") + assert False, "The supposedly removed state is still present in the FSM" + except KeyError: + pass + + # Make sure that there is no link to the removed state in the rest + # of the FSM + assert "second" not in fsm.get_following_states("INIT"),\ + "The link to second from INIT still exists after removal" + + assert "second" not in fsm.get_following_states("third"),\ + "The link to second from third still exists after removal" + +class FSMExplorationTests(unittest.TestCase): + def setUp(self): + self.buildFSM() + + def buildFSM(self): + """ + Create a sample FSM to play with in the rest of the tests. + """ + st1 = State("INIT") + st1.add_action(CountAction()) + st1.add_event_filter(TriggerEventFilter("Second")) + st1.add_event_filter(TriggerEventFilter("Third")) + + st2 = State("Second") + st2.add_action(TrueWhileActiveAction()) + st2.add_event_filter(TriggerEventFilter("Third")) + st2.add_event_filter(TriggerEventFilter("Fourth")) + + st3 = State("Third") + st3.add_action(CountAction()) + st3.add_action(TrueWhileActiveAction()) + + self.fsm = FiniteStateMachine("ExplorationTestingMachine") + self.fsm.add_state(st1) + self.fsm.add_state(st2) + self.fsm.add_state(st3) + def validate_following_states(self, in_name, out_name_list): + nextStates = self.fsm.get_following_states(in_name) + assert list(nextStates).sort() == list(out_name_list).sort(), \ + "The following states for %s are wrong : got %s"%\ + (in_name, str(nextStates)) + + def validate_previous_states(self, in_name, out_name_list): + prevStates = self.fsm.get_previous_states(in_name) + assert list(prevStates).sort() == list(out_name_list).sort(), \ + "The following states for %s are wrong : got %s"%\ + (in_name, str(prevStates)) + def test_get_following_states(self): + self.validate_following_states("INIT", ('Second', 'Third')) + + self.validate_following_states("Second", ("Third", "Fourth")) + + self.validate_following_states("Third", ()) + + def test_get_previous_states(self): + self.validate_previous_states("INIT", ()) + + self.validate_previous_states("Second", ("INIT")) + + self.validate_previous_states("Third", ("INIT", "Second")) + + self.validate_previous_states("Fourth", ("Second")) + if __name__ == "__main__": unittest.main() |