From 6584510d390a37153c20974da6704a907058fea0 Mon Sep 17 00:00:00 2001 From: mike Date: Mon, 19 Oct 2009 04:38:32 +0000 Subject: Merge gitorious@git.sugarlabs.org:tutorius/michaeljm-dev into merge_michaeljm-dev --- (limited to 'tutorius/core.py') diff --git a/tutorius/core.py b/tutorius/core.py index dd2435e..4376315 100644 --- a/tutorius/core.py +++ b/tutorius/core.py @@ -89,18 +89,6 @@ class Tutorial (object): self.state_machine.set_state(name) - - # Currently unused -- equivalent function is in each state - def _eventfilter_state_done(self, eventfilter): - """ - Callback handler for eventfilter to notify - when we must go to the next state. - """ - #XXX Tests should be run here normally - - #Swith to the next state pointed by the eventfilter - self.set_state(eventfilter.get_next_state()) - def _prepare_activity(self): """ Prepare the activity for the tutorial by loading the saved state and @@ -141,9 +129,6 @@ class State(object): self._actions = action_list or [] - # Unused for now - #self.tests = [] - self._event_filters = event_filter_list or [] self.tutorial = tutorial @@ -205,15 +190,13 @@ class State(object): # These functions are used to simplify the creation of states def add_action(self, new_action): """ - Adds an action to the state (only if it wasn't added before) + Adds an action to the state @param new_action The new action to execute when in this state @return True if added, False otherwise """ - if new_action not in self._actions: - self._actions.append(new_action) - return True - return False + self._actions.append(new_action) + return True # remove_action - We did not define names for the action, hence they're # pretty hard to remove on a precise basis @@ -258,6 +241,60 @@ class State(object): tutorial. """ self._event_filters = [] + + def __eq__(self, otherState): + """ + Compares two states and tells whether they contain the same states with the + same actions and event filters. + + @param otherState The other State that we wish to match + @returns True if every action in this state has a matching action in the + other state with the same properties and values AND if every + event filters in this state has a matching filter in the + other state having the same properties and values AND if both + states have the same name. +` """ + if not isinstance(otherState, State): + return False + if self.name != otherState.name: + return False + + # Do they have the same actions? + if len(self._actions) != len(otherState._actions): + return False + + if len(self._event_filters) != len(otherState._event_filters): + return False + + for act in self._actions: + found = False + # For each action in the other state, try to match it with this one. + for otherAct in otherState._actions: + if act == otherAct: + found = True + break + if found == False: + # If we arrive here, then we could not find an action with the + # same values in the other state. We know they're not identical + return False + + # Do they have the same event filters? + for event in self._event_filters: + found = False + # For every event filter in the other state, try to match it with + # the current filter. We just need to find one with the right + # properties and values. + for otherEvent in otherState._event_filters: + if event == otherEvent: + found = True + break + if found == False: + # We could not find the given event filter in the other state. + return False + + # If nothing failed up to now, then every actions and every filters can + # be found in the other state + return True class FiniteStateMachine(State): """ @@ -348,7 +385,7 @@ class FiniteStateMachine(State): # Flag the FSM level setup as done self._fsm_setup_done = True # Execute all the FSM level actions - for action in self.actions: + for action in self._actions: action.do() # Then, we need to run the setup of the current state @@ -413,7 +450,7 @@ class FiniteStateMachine(State): # Flag the FSM teardown as not needed anymore self._fsm_teardown_done = True # Undo all the FSM level actions here - for action in self.actions: + for action in self._actions: action.undo() # TODO : It might be nice to have a start() and stop() method for the @@ -526,3 +563,58 @@ class FiniteStateMachine(State): for st in self._states.itervalues(): out_string += st.name + ", " return out_string + + def __eq__(self, otherFSM): + """ + Compares the elements of two FSM to ensure and returns true if they have the + same set of states, containing the same actions and the same event filters. + + @returns True if the two FSMs have the same content, False otherwise + """ + if not isinstance(otherFSM, FiniteStateMachine): + return False + + # Make sure they share the same name + if not (self.name == otherFSM.name) or \ + not (self.start_state_name == otherFSM.start_state_name): + return False + + # Ensure they have the same number of FSM-level actions + if len(self._actions) != len(otherFSM._actions): + return False + + # Test that we have all the same FSM level actions + for act in self._actions: + found = False + # For every action in the other FSM, try to match it with the + # current one. + for otherAct in otherFSM._actions: + if act == otherAct: + found = True + break + if found == False: + return False + + # Make sure we have the same number of states in both FSMs + if len(self._states) != len(otherFSM._states): + return False + + # For each state, try to find a corresponding state in the other FSM + for state_name in self._states.keys(): + state = self._states[state_name] + other_state = None + try: + # Attempt to use this key in the other FSM. If it's not present + # the dictionary will throw an exception and we'll know we have + # at least one different state in the other FSM + other_state = otherFSM._states[state_name] + except: + return False + # If two states with the same name exist, then we want to make sure + # they are also identical + if not state == other_state: + return False + + # If we made it here, then all the states in this FSM could be matched to an + # identical state in the other FSM. + return True -- cgit v0.9.1