diff options
Diffstat (limited to 'src/sugar/tutorius')
-rw-r--r-- | src/sugar/tutorius/Makefile.am | 6 | ||||
-rw-r--r-- | src/sugar/tutorius/actions.py | 63 | ||||
-rw-r--r-- | src/sugar/tutorius/bundler.py | 247 | ||||
-rwxr-xr-x | src/sugar/tutorius/tests/run-tests.py | 3 | ||||
-rw-r--r-- | src/sugar/tutorius/tests/serializertests.py | 105 |
5 files changed, 321 insertions, 103 deletions
diff --git a/src/sugar/tutorius/Makefile.am b/src/sugar/tutorius/Makefile.am index 8805314..7223c60 100644 --- a/src/sugar/tutorius/Makefile.am +++ b/src/sugar/tutorius/Makefile.am @@ -1,3 +1,5 @@ +SUBDIRS = uam + sugardir = $(pythondir)/sugar/tutorius sugar_PYTHON = \ __init__.py \ @@ -9,5 +11,7 @@ sugar_PYTHON = \ services.py \ overlayer.py \ editor.py \ - linear_creator.py\ + linear_creator.py \ + constraints.py \ + properties.py \ bundler.py diff --git a/src/sugar/tutorius/actions.py b/src/sugar/tutorius/actions.py index d81e3c2..d2516f7 100644 --- a/src/sugar/tutorius/actions.py +++ b/src/sugar/tutorius/actions.py @@ -29,7 +29,7 @@ class Action(object): """Base class for Actions""" def __init__(self): object.__init__(self) - self.properties = {} + self.properties = None def do(self, **kwargs): """ @@ -44,7 +44,12 @@ class Action(object): pass #Should raise NotImplemented? def get_properties(self): - if self.properties is None or len(self.properties) == 0: + """ + Fills self.property with a dict of TutoriusProperty and return the list + of property names. get_properties has to be called before accessing + self.property + """ + if self.properties is None: self.properties = {} for i in dir(self): if isinstance(getattr(self,i), TutoriusProperty): @@ -130,9 +135,9 @@ class BubbleMessage(Action): Action.__init__(self) self.message = TStringProperty(message) # Create the position as an array of fixed-size 2 - self.position = TArrayProperty(pos, 2, 2) + self.position = TArrayProperty(pos or [0,0], 2, 2) # Do the same for the tail position - self.tail_pos = TArrayProperty(tailpos, 2, 2) + self.tail_pos = TArrayProperty(tailpos or [0,0], 2, 2) self.overlay = None self._bubble = None @@ -217,53 +222,54 @@ class DisableWidgetAction(Action): self._widget = gtkutils.find_widget(os.activity, self._target) if self._widget: self._widget.set_sensitive(False) - - def undo(self): + + def undo(self): """Action undo""" if self._widget: self._widget.set_sensitive(True) - + + class TypeTextAction(Action): - """ + """ Simulate a user typing text in a widget Work on any widget that implements a insert_text method - + @param widget The treehish representation of the widget @param text the text that is typed - """ + """ def __init__(self, widget, text): Action.__init__(self) - + self._widget = widget self._text = text - + def do(self, **kwargs): - """ - Type the text - """ + """ + Type the text + """ widget = gtkutils.find_widget(ObjectStore().activity, self._widget) if hasattr(widget, "insert_text"): widget.insert_text(self._text, -1) - - def undo(self): - """ - no undo - """ - pass - + + def undo(self): + """ + no undo + """ + pass + class ClickAction(Action): - """ + """ Action that simulate a click on a widget Work on any widget that implements a clicked() method - + @param widget The threehish representation of the widget - """ + """ def __init__(self, widget): Action.__init__(self) self._widget = widget - - def do(self): - """ + + def do(self): + """ click the widget """ widget = gtkutils.find_widget(ObjectStore().activity, self._widget) @@ -275,3 +281,4 @@ class ClickAction(Action): No undo """ pass + diff --git a/src/sugar/tutorius/bundler.py b/src/sugar/tutorius/bundler.py index a28d6ef..34b3a12 100644 --- a/src/sugar/tutorius/bundler.py +++ b/src/sugar/tutorius/bundler.py @@ -24,17 +24,17 @@ import logging import os import uuid import xml.dom.minidom -import xml.dom.ext from sugar.tutorius import gtkutils, overlayer from sugar.tutorius.core import Tutorial, State, FiniteStateMachine -import sugar.tutorius.actions +from sugar.tutorius.actions import * import sugar.tutorius.filters +#from sugar.tutorius.filters import EventFilter, TimerEvent, GtkWidgetEventFilter, GtkWidgetTypeFilter from ConfigParser import SafeConfigParser -def __get_store_root(): +def _get_store_root(): return os.path.join(os.getenv("SUGAR_PREFIX"),"share","tutorius","data") -def __get_bundle_root(): +def _get_bundle_root(): return os.path.join(os.getenv("SUGAR_BUNDLE_PATH"),"data","tutorius","data") INI_ACTIVITY_SECTION = "RELATED_ACTIVITIES" @@ -51,8 +51,8 @@ class TutorialStore: given activity. """ - store_root = __get_store_root() - bundle_root = __get_bundle_root() + store_root = _get_store_root() + bundle_root = _get_bundle_root() logging.debug("*********** Path of store_root : " + store_root) @@ -119,70 +119,90 @@ class XMLSerializer(Serializer): used in the tutorials to/from a .xml file. Inherit from Serializer """ - def create_state_dict_node(self, state_dict, doc): + def _create_state_dict_node(self, state_dict, doc): """ Create and return a xml Node from a State dictionnary. """ statesList = doc.createElement("States") for state_name, state in state_dict.items(): - stateNode = statesList.appendChild("State") - stateNode.setAttribute("State:Name", state_name) - stateNode = stateNode.appendChild(create_action_list_node(state.action_list, doc)) - stateNode = stateNode.appendChild(create_event_filters_node(state.event_filters, doc)) + stateNode = doc.createElement("State") + statesList.appendChild(stateNode) + stateNode.setAttribute("Name", state_name) + actionsList = stateNode.appendChild(self._create_action_list_node(state.get_action_list(), doc)) + eventfiltersList = stateNode.appendChild(self._create_event_filters_node(state.get_event_filter_list(), doc)) return statesList - def create_action_list_node(self, action_list, doc): + def _create_action_list_node(self, action_list, doc): """ Create and return a xml Node from a Action list. """ actionsList = doc.createElement("Actions") for action in action_list: - actionNode = actionsList.appendChild("Action") + actionNode = doc.createElement("Action") + actionsList.appendChild(actionNode) + # Using .__class__ since type() doesn't have the same behavior + # with class derivating from object and class that don't + actionNode.setAttribute("Class", str(action.__class__)) + if type(action) is DialogMessage: - actionNode.setAttribute("Action:Class", type(action)) - actionNode.setAttribute("Action:Message", action.message) - actionNode.setAttribute("Action:Position", action.position) + actionNode.setAttribute("Message", action.message.value) + actionNode.setAttribute("PositionX", action.position.value[0]) + actionNode.setAttribute("PositionY", str(action.position.value[1])) elif type(action) is BubbleMessage: - actionNode.setAttribute("Action:Class", str(type(action))) - actionNode.setAttribute("Action:Message", action.message) - actionNode.setAttribute("Action:Position", action.position) - actionNode.setAttribute("Action:Tail_pos", action.tail_pos) + actionNode.setAttribute("Message", action.message.value) + actionNode.setAttribute("PositionX", str(action.position.value[0])) + actionNode.setAttribute("PositionY", str(action.position.value[1])) + actionNode.setAttribute("Tail_posX", str(action.tail_pos.value[0])) + actionNode.setAttribute("Tail_posY", str(action.tail_pos.value[1])) # TODO : elif for each type of action elif type(action) is WidgetIdentifyAction: - actionNode.setAttribute("Action:Class", str(type(action))) - # TODO + # Nothing else to save + pass elif type(action) is ChainAction: - # TODO - actionNode.setAttribute("Action:Class", str(type(action))) + # Recusively write the contained actions - in the correct order + subActionsNode = self._create_actions_node(action._actions, doc) + actionNode.appendChild(subActionsNode) elif type(action) is DisableWidgetAction: - # TODO - actionNode.setAttribute("Action:Class", str(type(action))) + # Remember the target + actionNode.setAttribute("Target", action._target) elif type(action) is TypeTextAction: - # TODO - actionNode.setAttribute("Action:Class", str(type(action))) + # Save the text and the widget + actionNode.setAttribute("Widget", action._widget) + actionNode.setAttribute("Text", action._text) elif type(action) is ClickAction: - # TODO - actionNode.setAttribute("Action:Class", str(type(action))) + # Save the widget to click + actionNode.setAttribute("Widget", action._widget) return actionsList - def create_event_filters_node(self, event_filters, doc): + def _create_event_filters_node(self, event_filters, doc): """ Create and return a xml Node from a event filters. """ eventFiltersList = doc.createElement("EventFiltersList") for event_f in event_filters: eventFilterNode = eventFiltersList.appendChild("EventFilter") - # TODO : elif for each type of event filters - if type(event_f) is TimerEvent: - # TODO - eventFilterNode.setAttribute("EventFilter:Class", str(type(event_f))) - elif type(event_f) is GtkWidgetEventFilter: - # TODO - eventFilterNode.setAttribute("EventFilter:Class", str(type(event_f))) - elif type(event_f) is GtkWidgetTypeFilter: - # TODO - eventFilterNode.setAttribute("EventFilter:Class", str(type(event_f))) + + # Using .__class__ since type() doesn't have the same behavior + # with class derivating from object and class that don't + eventFilterNode.setAttribute("Class", str(event_f.__class__)) + + # Write the name of the next state + eventFilterNode.setAttribute("NextState", event_f.next_state) + + if type(event_f) is sugar.tutorius.filters.TimerEvent: + eventFilterNode.setAttribute("Timeout_s", str(event_f._timeout)) + + elif type(event_f) is sugar.tutorius.filters.GtkWidgetEventFilter: + eventFilterNode.setAttribute("EventName", event_f._event_name) + eventFilterNode.setAttribute("ObjectId", event_f._object_id) + + elif type(event_f) is sugar.tutorius.filters.GtkWidgetTypeFilter: + eventFilterNode.setAttribute("ObjectId", event_f._object_id) + if event_f._strokes is not None: + eventFilterNode.setAttribute("Strokes", event_f._strokes) + if event_f._text is not None: + eventFilterNode.setAttribute("Text", event_f._text) return eventFiltersList @@ -194,15 +214,18 @@ class XMLSerializer(Serializer): doc = xml.dom.minidom.Document() fsm_element = doc.createElement("FSM") doc.appendChild(fsm_element) - fsm_element.setAttribute("fsm:Name", fsm.name) - fsm_element.setAttribute("fsm:StartStateName", fsm.start_state_name) - fsm_element = fsm_element.appendChild(create_state_dict_node(fsm.state_dict, doc)) - fsm_element = fsm_element.appendChild(create_action_list_node(fsm.action_list, doc)) + fsm_element.setAttribute("Name", fsm.name) + fsm_element.setAttribute("StartStateName", fsm.start_state_name) + statesDict = fsm_element.appendChild(self._create_state_dict_node(fsm._states, doc)) + + fsm_actions_node = self._create_action_list_node(fsm.actions, doc) + fsm_actions_node.tagName = "FSMActions" + actionsList = fsm_element.appendChild(fsm_actions_node) - file_object = open(path + "/" + xml_filename, "w") - xml.dom.ext.PrettyPrint(doc, file_object) + file_object = open(os.path.join(path, xml_filename), "w") + file_object.write(doc.toprettyxml()) file_object.close() - + def _find_tutorial_dir_with_guid(self, guid): """ @@ -218,12 +241,12 @@ class XMLSerializer(Serializer): @param guid The GUID of the tutorial that is to be loaded. """ # Attempt to find the tutorial's directory in the global directory - global_dir = os.path.join(__get_store_root(), guid) + global_dir = os.path.join(_get_store_root(), guid) # Then in the activty's bundle path - activity_dir = os.path.join(__get_bundle_root(), guid) + activity_dir = os.path.join(_get_bundle_root(), guid) # If they both exist - if os.path.isdir(global_filename) and os.path.isdir(activity_dir): + if os.path.isdir(global_dir) and os.path.isdir(activity_dir): # Inspect both metadata files global_meta = os.path.join(global_dir, "meta.ini") activity_meta = os.path.join(activity_dir, "meta.ini") @@ -254,7 +277,7 @@ class XMLSerializer(Serializer): return activity_dir # Error : none of these directories contain the tutorial - raise IOError(2, "Neither the global nor the bundle directory contained the tutorial with GUID"%guid) + raise IOError(2, "Neither the global nor the bundle directory contained the tutorial with GUID %s"%guid) def _load_xml_properties(self, properties_elem): """ @@ -271,7 +294,40 @@ class XMLSerializer(Serializer): @param filters_elem An XML Element representing a list of event filters """ - return [] + reformed_event_filters_list = [] + # item(0) because there is always only one <EventFilterList> tag in the xml file + # so states_elem should always contain only one element + event_filter_element_list = filters_elem.item(0).getElementsByTagName("EventFilter") + new_event_filter = None + + for event_filter in event_filter_element_list: + # Load the name of the next state for this filter + next_state = event_filter.getAttribute("NextState") + + if event_filter.getAttribute("Class") == str(sugar.tutorius.filters.TimerEvent): + timeout = int(event_filter.getAttribute("Timeout_s")) + new_event_filter = TimerEvent(next_state, timeout) + + elif event_filter.getAttribute("Class") == str(sugar.tutorius.filters.GtkWidgetEventFilter): + # Get the event name and the object's ID + event_name = event_filter.getAttribute("EventName") + object_id = event_filter.getAttribute("ObjectId") + + new_event_filter = GtkWidgetEventFilter(next_state, object_id, event_name) + elif event_filter.getAttribute("Class") == str(sugar.tutorius.filters.GtkWidgetTypeFilter): + # Get the widget to write in and the text + object_id = event_filter.getAttribute("ObjectId") + if event_filter.hasAttribute("Text"): + text = event_filter.getAttribute("Text") + new_event_filter = GtkWidgetTypeFilter(next_state, object_id, text=text) + elif event_filter.hasAttribute("Strokes"): + strokes = event_filter.getAttribute("Strokes") + new_event_filter = GtkWidgetTypeFilter(next_state, object_id, strokes=strokes) + + if new_event_filter is not None: + reformed_event_filter.append(new_event_filter) + + return reformed_event_filters_list def _load_xml_actions(self, actions_elem): """ @@ -279,7 +335,51 @@ class XMLSerializer(Serializer): @param actions_elem An XML Element representing a list of Actions """ - return [] + reformed_actions_list = [] + # item(0) because there is always only one <Actions> tag in the xml file + # so states_elem should always contain only one element + actions_element_list = actions_elem.item(0).getElementsByTagName("Action") + + for action in actions_element_list: + # TODO : elif for each type of action + if action.getAttribute("Class") == str(DialogMessage): + message = action.getAttribute("Message") + positionX = int(action.getAttribute("PositionX")) + positionY = int(action.getAttribute("PositionY")) + position = [positionX, positionY] + reformed_actions_list.append(DialogMessage(message,position)) + elif action.getAttribute("Class") == str(BubbleMessage): + message = action.getAttribute("Message") + positionX = int(action.getAttribute("PositionX")) + positionY = int(action.getAttribute("PositionY")) + position = [positionX, positionY] + tail_posX = action.getAttribute("Tail_posX") + tail_posY = action.getAttribute("Tail_posY") + tail_pos = [tail_posX, tail_posY] + reformed_actions_list.append(BubbleMessage(message,position,None,tail_pos)) + elif action.getAttribute("Class") == str(WidgetIdentifyAction): + reformed_actions_list.append(WidgetIdentifyAction()) + elif action.getAttribute("Class") == str(ChainAction): + # Load the subactions + subActionsList = _load_xml_actions(action.getElementsByTagName("Actions")) + reformed_actions_list.append(ChainAction(subActionsList)) + elif action.getAttribute("Class") == str(DisableWidgetAction): + # Get the target + targetName = action.getAttribute("Target") + reformed_actions_list.append(DisableWidgetAction(targetName)) + elif action.getAttribute("Class") == str(TypeTextAction): + # Get the widget and the text to type + widget = action.getAttribute("Widget") + text = action.getAttribute("Text") + + reformed_actions_list.append(TypeTextAction(widget, text)) + elif action.getAttribute("Class") == str(ClickAction): + # Load the widget to click + widget = action.getAttribute("Widget") + + reformed_actions_list.append(ClickAction(widget)) + + return reformed_actions_list def _load_xml_states(self, states_elem): """ @@ -288,7 +388,18 @@ class XMLSerializer(Serializer): @param states_elem An XML Element that represents a list of States """ - return [] + reformed_state_list = [] + # item(0) because there is always only one <States> tag in the xml file + # so states_elem should always contain only one element + states_element_list = states_elem.item(0).getElementsByTagName("State") + + for state in states_element_list: + stateName = state.getAttribute("Name") + actions_list = self._load_xml_actions(state.getElementsByTagName("Actions")) + event_filters_list = self._load_xml_event_filters(state.getElementsByTagName("EventFiltersList")) + reformed_state_list.append(State(stateName, actions_list, event_filters_list)) + + return reformed_state_list def _load_xml_fsm(self, fsm_elem): """ @@ -298,28 +409,28 @@ class XMLSerializer(Serializer): @param fsm_elem The XML element that describes a FSM """ # Load the FSM's name and start state's name - fsm_name = fsm_elem.getAttribute("fsm:Name") + fsm_name = fsm_elem.getAttribute("Name") fsm_start_state_name = None try: - fsm_start_state_name = fsm_elem.getAttribute("fsm:StartStateName") + fsm_start_state_name = fsm_elem.getAttribute("StartStateName") except: pass fsm = FiniteStateMachine(fsm_name, start_state_name=fsm_start_state_name) # Load the states - states = self._load_xml_states(fsm_elem.getElementsByName("States")) + states = self._load_xml_states(fsm_elem.getElementsByTagName("States")) for state in states: fsm.add_state(state) # Load the actions on this FSM - actions = self._load_xml_actions(fsm_elem.getElementsByName("Actions")) + actions = self._load_xml_actions(fsm_elem.getElementsByTagName("FSMActions")) for action in actions: fsm.add_action(action) # Load the event filters - events = self._load_xml_event_filters(fsm_elem.getElementsByName("EventFiltersList")) + events = self._load_xml_event_filters(fsm_elem.getElementsByTagName("EventFiltersList")) for event in events: fsm.add_event_filter(event) @@ -338,7 +449,7 @@ class XMLSerializer(Serializer): xml_dom = xml.dom.minidom.parse(tutorial_file) - fsm_elem = xml_dom.getElementsByTagName("fsm")[0] + fsm_elem = xml_dom.getElementsByTagName("FSM")[0] return self._load_xml_fsm(fsm_elem) @@ -351,7 +462,6 @@ class TutorialBundler: def __init__(self,generated_guid = None): """ - TODO. Tutorial_bundler constructor. If a GUID is given in the parameter, the Tutorial_bundler object will be associated with it. If no GUID is given, a new GUID will be generated, @@ -362,12 +472,12 @@ class TutorialBundler: #Look for the file in the path if a uid is supplied if generated_guid: #General store - store_path = os.path.join(__get_store_root(), generated_guid, INI_FILENAME) + store_path = os.path.join(_get_store_root(), generated_guid, INI_FILENAME) if os.path.isfile(store_path): self.Path = os.path.dirname(store_path) else: #Bundle store - bundle_path = os.path.join(__get_bundle_root(), generated_guid, INI_FILENAME) + bundle_path = os.path.join(_get_bundle_root(), generated_guid, INI_FILENAME) if os.path.isfile(bundle_path): self.Path = os.path.dirname(bundle_path) else: @@ -375,7 +485,7 @@ class TutorialBundler: else: #Create the folder, any failure will go through to the caller for now - store_path = os.path.join(__get_store_root(), generated_guid) + store_path = os.path.join(_get_store_root(), generated_guid) os.mkdir(store_path) self.Path = store_path @@ -424,8 +534,8 @@ class TutorialBundler: more than one path, the store_root is given priority. """ - store_root = __get_store_root() - bundle_root = __get_bundle_root() + store_root = _get_store_root() + bundle_root = _get_bundle_root() config = SafeConfigParser() path = None @@ -483,10 +593,11 @@ class TutorialBundler: config = SafeConfigParser() if guid is not None: + serializer = XMLSerializer() path = get_tutorial_path() + "/meta.ini" config.read(path) xml_filename = config.get(INI_METADATA_SECTION, INI_XML_FSM_PROPERTY) - save_fsm(fsm, xml_filename, store_root) + serializer.save_fsm(fsm, xml_filename, store_root) def add_resources(self, typename, file): diff --git a/src/sugar/tutorius/tests/run-tests.py b/src/sugar/tutorius/tests/run-tests.py index 1fc534e..042b10e 100755 --- a/src/sugar/tutorius/tests/run-tests.py +++ b/src/sugar/tutorius/tests/run-tests.py @@ -51,8 +51,7 @@ if __name__=='__main__': suite.addTests(unittest.findTestCases(filterstests)) suite.addTests(unittest.findTestCases(constraintstests)) suite.addTests(unittest.findTestCases(propertiestests)) - suite.addTests(unittest.findTestCases(serializertests)) - + suite.addTests(unittest.findTestCases(serializertests)) runner = unittest.TextTestRunner() runner.run(suite) coverage.stop() diff --git a/src/sugar/tutorius/tests/serializertests.py b/src/sugar/tutorius/tests/serializertests.py index a53e196..2a743e1 100644 --- a/src/sugar/tutorius/tests/serializertests.py +++ b/src/sugar/tutorius/tests/serializertests.py @@ -28,21 +28,118 @@ import unittest import logging import linecache import os -import cPickle as pickle +import shutil from sugar.tutorius import gtkutils, overlayer from sugar.tutorius.core import Tutorial, State, FiniteStateMachine from sugar.tutorius.actions import DialogMessage, OnceWrapper, BubbleMessage from sugar.tutorius.filters import GtkWidgetEventFilter, TimerEvent +from sugar.tutorius.bundler import * +from uuid import * +import rpdb2 -# Helper classes to help testing - +class SerializerInterfaceTest(unittest.TestCase): + """ + For completeness' sake. + """ + def test_save(self): + ser = Serializer() + + try: + ser.save_fsm(None) + assert False, "save_fsm() should throw an unimplemented error" + except: + pass + + def test_load(self): + ser = Serializer() + + try: + ser.load_fsm(str(uuid.uuid1)) + assert False, "load_fsm() should throw an unimplemented error" + except: + pass +class XMLSerializerTest(unittest.TestCase): + """ + Tests the transformation of XML to FSM, then back. + """ + def setUp(self): + # Create the sample FSM + self.fsm = FiniteStateMachine("testingMachine") + + # Add a few states + act1 = BubbleMessage(message="Hi", pos=[300, 450]) + ev1 = GtkWidgetEventFilter("0.12.31.2.2", "clicked", "Second") + act2 = BubbleMessage(message="Second message", pos=[250, 150], tailpos=[1,2]) + + st1 = State("INIT") + st1.add_action(act1) + + st2 = State("Second") + + st2.add_action(act2) + + self.fsm.add_state(st1) + self.fsm.add_state(st2) + + self.uuid = uuid1() + + + def test_save(self, remove=True): + """ + Writes an FSM to disk, then compares the file to the expected results. + "Remove" boolean argument specify if the test data must be removed or not + """ + # Make the serializer believe the test is in a activity path + testpath = "/tmp/testdata/" + os.environ["SUGAR_BUNDLE_PATH"] = testpath + os.environ["SUGAR_PREFIX"] = testpath +## os.mkdir(sugar.tutorius.bundler._get_store_root()) + xml_ser = XMLSerializer() + os.makedirs(os.path.join(sugar.tutorius.bundler._get_store_root(), str(self.uuid))) + #rpdb2.start_embedded_debugger('flakyPass') + xml_ser.save_fsm(self.fsm, "fsm.xml", os.path.join(sugar.tutorius.bundler._get_store_root(), str(self.uuid))) + + #Remove test file and path + if remove == True: + os.remove(os.path.join(sugar.tutorius.bundler._get_store_root(), str(self.uuid)) + "/fsm.xml") + if os.path.isdir(testpath): + shutil.rmtree(testpath) + + def test_save_and_load(self): + """ + Load up the written FSM and compare it with the object representation. + """ + self.test_save(False) + testpath = "/tmp/testdata/" + #rpdb2.start_embedded_debugger('flakyPass') + xml_ser = XMLSerializer() + + # This interface needs to be redone... It's not clean because there is + # a responsibility mixup between the XML reader and the bundler. + loaded_fsm = xml_ser.load_fsm(str(self.uuid)) + + # Compare the two FSMs + assert loaded_fsm._states.get("INIT").name == self.fsm._states.get("INIT").name, \ + 'FSM underlying dictionary differ from original to pickled/reformed one' + assert loaded_fsm._states.get("Second").name == self.fsm._states.get("Second").name, \ + 'FSM underlying dictionary differ from original to pickled/reformed one' + assert loaded_fsm._states.get("INIT").get_action_list()[0].message.value == \ + self.fsm._states.get("INIT").get_action_list()[0].message.value, \ + 'FSM underlying State underlying Action differ from original to reformed one' + assert len(loaded_fsm.get_action_list()) == 0, "FSM should not have any actions on itself" + + os.remove(os.path.join(sugar.tutorius.bundler._get_store_root(), str(self.uuid)) + "/fsm.xml") + if os.path.isdir(testpath): + shutil.rmtree(testpath) +# Helper classes to help testing class SerializerTest(unittest.TestCase): """ + This class has to test the Serializer methods as well as the expected functionality. """ @@ -119,4 +216,4 @@ class SerializerTest(unittest.TestCase): if __name__ == "__main__": - unittest.main()
\ No newline at end of file + unittest.main() |