diff options
Diffstat (limited to 'tutorius/core.py')
-rw-r--r-- | tutorius/core.py | 147 |
1 files changed, 131 insertions, 16 deletions
diff --git a/tutorius/core.py b/tutorius/core.py index c583a1f..80e1b4f 100644 --- a/tutorius/core.py +++ b/tutorius/core.py @@ -24,9 +24,9 @@ This module contains the core classes for tutorius import logging import os -from sugar.tutorius.TProbe import ProbeManager -from sugar.tutorius.dbustools import save_args -from sugar.tutorius import addon +from .TProbe import ProbeManager +from .dbustools import save_args +from . import addon logger = logging.getLogger("tutorius") @@ -91,7 +91,6 @@ class Tutorial (object): self.state_machine.set_state(name) - def _prepare_activity(self): """ Prepare the activity for the tutorial by loading the saved state and @@ -134,9 +133,6 @@ class State(object): self._actions = action_list or [] - # Unused for now - #self.tests = [] - self._transitions= dict(event_filter_list or []) self._installedEvents = set() @@ -200,15 +196,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 @@ -255,6 +249,50 @@ class State(object): tutorial. """ self._transitions = {} + + 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._transitions) != len(otherState._transitions): + 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? + if self._transitions != otherState._transitions: + 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): """ @@ -467,8 +505,8 @@ class FiniteStateMachine(State): #TODO : Move this code inside the State itself - we're breaking # encap :P - for event, state in st._transitions: - if state == state_name: + for event in st._transitions: + if st._transitions[event] == state_name: del st._transitions[event] # Remove the state from the dictionary @@ -487,7 +525,7 @@ class FiniteStateMachine(State): next_states = set() - for event, state in state._transitions: + for event, state in state._transitions.items(): next_states.add(state) return tuple(next_states) @@ -510,7 +548,7 @@ class FiniteStateMachine(State): states = [] # Walk through the list of states for st in self._states.itervalues(): - for event, state in st._transitions: + for event, state in st._transitions.items(): if state == state_name: states.append(state) continue @@ -523,3 +561,80 @@ 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 + 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 |