Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/tests/coretests.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/coretests.py')
-rw-r--r--tests/coretests.py412
1 files changed, 223 insertions, 189 deletions
diff --git a/tests/coretests.py b/tests/coretests.py
index eadea01..4f564c8 100644
--- a/tests/coretests.py
+++ b/tests/coretests.py
@@ -28,13 +28,14 @@ and event filters. Those are in their separate test module
import unittest
+import copy
import logging
-from sugar.tutorius.actions import Action, OnceWrapper, ClickAction, TypeTextAction
+from sugar.tutorius.actions import *
+from sugar.tutorius.addon import *
from sugar.tutorius.core import *
from sugar.tutorius.filters import *
-
-from actiontests import CountAction
+from actiontests import CountAction, FakeEventFilter
# Helper classes to help testing
class SimpleTutorial(Tutorial):
@@ -49,6 +50,28 @@ class SimpleTutorial(Tutorial):
def set_state(self, name):
self.current_state_name = name
+class TutorialTest(unittest.TestCase):
+ """Tests the tutorial functions that are not covered elsewhere."""
+ def test_detach(self):
+ class Activity(object):
+ name = "this"
+
+ activity1 = Activity()
+ activity2 = Activity()
+
+ fsm = FiniteStateMachine("Sample example")
+
+ tutorial = Tutorial("Test tutorial", fsm)
+
+ assert tutorial.activity == None, "There is a default activity in the tutorial"
+
+ tutorial.attach(activity1)
+
+ assert tutorial.activity == activity1, "Activity should have been associated to this tutorial"
+
+ tutorial.attach(activity2)
+ assert tutorial.activity == activity2, "Activity should have been changed to activity2"
+
class TutorialWithFSM(Tutorial):
"""
Fake tutorial, but associated with a FSM.
@@ -73,173 +96,6 @@ class TrueWhileActiveAction(Action):
def undo(self):
self.active = False
-
-class ClickableWidget():
- """
- This class fakes a widget with a clicked() method
- """
- def __init__(self):
- self.click_count = 0
-
- def clicked(self):
- self.click_count += 1
-
-class FakeTextEntry():
- """
- This class fakes a widget with an insert_text() method
- """
- def __init__(self):
- self.text_lines = []
- self.last_entered_line = ""
- self.displayed_text = ""
-
- def insert_text(self, text, index):
- self.last_entered_line = text
- self.text_lines.append(text)
- self.displayed_text = self.displayed_text[0:index] + text + self.displayed_text[index+1:]
-
-class FakeParentWidget():
- """
- This class fakes a widet container, it implements the get_children() method
- """
- def __init__(self):
- self._children = []
-
- def add_child(self, child):
- self._children.append(child)
-
- def get_children(self):
- return self._children
-
-
-
-
-class TriggerEventFilter(EventFilter):
- """
- This event filter can be triggered by simply calling its do_callback function.
-
- Used to fake events and see the effect on the FSM.
- """
- def __init__(self, next_state):
- EventFilter.__init__(self, next_state)
- self.toggle_on_callback = False
-
- def install_handlers(self, callback, **kwargs):
- """
- Forsakes the incoming callback function and just set the inner one.
- """
- self._callback = self._inner_cb
-
- 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 ClickActionTests(unittest.TestCase):
- """
- Test class for click action
- """
- def test_do_action(self):
- activity = FakeParentWidget()
- widget = ClickableWidget()
- activity.add_child(widget)
- ObjectStore().activity = activity
-
- action = ClickAction("0.0")
-
- assert widget == ObjectStore().activity.get_children()[0],\
- "The clickable widget isn't reachable from the object store \
- the test cannot pass"
-
- action.do()
-
- assert widget.click_count == 1, "clicked() should have been called by do()"
-
- action.do()
-
- assert widget.click_count == 2, "clicked() should have been called by do()"
-
- def test_undo(self):
- activity = FakeParentWidget()
- widget = ClickableWidget()
- activity.add_child(widget)
- ObjectStore().activity = activity
-
- action = ClickAction("0.0")
-
- assert widget == ObjectStore().activity.get_children()[0],\
- "The clickable widget isn't reachable from the object store \
- the test cannot pass"
-
- action.undo()
-
- #There is no undo for this action so the test should not fail
- assert True
-
-
-
-class TypeTextActionTests(unittest.TestCase):
- """
- Test class for type text action
- """
- def test_do_action(self):
- activity = FakeParentWidget()
- widget = FakeTextEntry()
- activity.add_child(widget)
- ObjectStore().activity = activity
-
- test_text = "This is text"
-
-
- action = TypeTextAction("0.0", test_text)
-
- assert widget == ObjectStore().activity.get_children()[0],\
- "The clickable widget isn't reachable from the object store \
- the test cannot pass"
-
- action.do()
-
- assert widget.last_entered_line == test_text, "insert_text() should have been called by do()"
-
- action.do()
-
- assert widget.last_entered_line == test_text, "insert_text() should have been called by do()"
- assert len(widget.text_lines) == 2, "insert_text() should have been called twice"
-
- def test_undo(self):
- activity = FakeParentWidget()
- widget = FakeTextEntry()
- activity.add_child(widget)
- ObjectStore().activity = activity
-
- test_text = "This is text"
-
-
- action = TypeTextAction("0.0", test_text)
-
- assert widget == ObjectStore().activity.get_children()[0],\
- "The clickable widget isn't reachable from the object store \
- the test cannot pass"
-
- action.undo()
-
- #There is no undo for this action so the test should not fail
- assert True
# State testing class
class StateTest(unittest.TestCase):
@@ -274,7 +130,7 @@ class StateTest(unittest.TestCase):
Tests the fact that the event filters are correctly installed on setup
and uninstalled on teardown.
"""
- event_filter = TriggerEventFilter("second_state")
+ event_filter = addon.create('TriggerEventFilter', "second_state")
state = State("event_test", event_filter_list=[event_filter])
state.set_tutorial(SimpleTutorial())
@@ -326,14 +182,11 @@ class StateTest(unittest.TestCase):
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,\
+ assert act1 in actions and act2 in actions and act3 in actions, \
"The actions were not properly inserted in the state"
# Clear the list
@@ -345,9 +198,9 @@ class StateTest(unittest.TestCase):
def test_add_event_filter(self):
state = State("INIT")
- event1 = TriggerEventFilter("s")
- event2 = TriggerEventFilter("t")
- event3 = TriggerEventFilter("r")
+ event1 = addon.create('TriggerEventFilter', "s")
+ event2 = addon.create('TriggerEventFilter', "t")
+ event3 = addon.create('TriggerEventFilter', "r")
# Insert the event filters
assert state.add_event_filter(event1), "Could not add event filter 1"
@@ -368,7 +221,80 @@ class StateTest(unittest.TestCase):
assert len(state.get_event_filter_list()) == 0, \
"Could not clear the event filter list properly"
+
+ def test_eq_simple(self):
+ """
+ Two empty states with the same name must be identical
+ """
+ st1 = State("Identical")
+ st2 = State("Identical")
+
+ assert st1 == st2, "Empty states with the same name should be identical"
+
+ def test_eq(self):
+ """
+ Test whether two states share the same set of actions and event filters.
+ """
+ st1 = State("Identical")
+ st2 = State("Identical")
+
+ non_state = object()
+
+ act1 = addon.create("BubbleMessage", message="Hi", position=[132,450])
+ act2 = addon.create("BubbleMessage", message="Hi", position=[132,450])
+
+ event1 = addon.create("GtkWidgetEventFilter", "nextState", "0.0.0.1.1.2.3.1", "clicked")
+
+ act3 = addon.create("DialogMessage", message="Hello again.", position=[200, 400])
+
+ # Build the first state
+ st1.add_action(act1)
+ st1.add_action(act3)
+ st1.add_event_filter(event1)
+
+ # Build the second state
+ st2.add_action(act2)
+ st2.add_action(act3)
+ st2.add_event_filter(event1)
+
+ # Make sure that they are identical for now
+ assert st1 == st2, "States should be considered as identical"
+ assert st2 == st1, "States should be considered as identical"
+ # Modify the second bubble message action
+ act2.message = "New message"
+
+ # Since one action changed in the second state, this should indicate that the states
+ # are not identical anymore
+ assert not (st1 == st2), "Action was changed and states should be different"
+ assert not (st2 == st1), "Action was changed and states should be different"
+
+ # Make sure that trying to find identity with something else than a State object fails properly
+ assert not (st1 == non_state), "Passing a non-State object should fail for identity"
+
+ st2.name = "Not identical anymore"
+ assert not(st1 == st2), "Different state names should give different states"
+ st2.name = "Identical"
+
+ st3 = copy.deepcopy(st1)
+ st3.add_action(addon.create("BubbleMessage", "Hi!", [128,264]))
+
+ assert not (st1 == st3), "States having a different number of actions should be different"
+
+ st4 = copy.deepcopy(st1)
+ st4.add_event_filter(addon.create("GtkWidgetEventFilter", "next_state", "0.0.1.1.2.2.3", "clicked"))
+
+ assert not (st1 == st4), "States having a different number of events should be different"
+
+ st5 = copy.deepcopy(st1)
+ st5._event_filters = []
+
+ st5.add_event_filter(addon.create("GtkWidgetEventFilter", "other_state", "0.1.2.3.4.1.2", "pressed"))
+
+ #import rpdb2; rpdb2.start_embedded_debugger('pass')
+ assert not (st1 == st5), "States having the same number of event filters" \
+ + " but those being different should be different"
+
class FSMTest(unittest.TestCase):
"""
This class needs to text the interface and functionality of the Finite
@@ -413,6 +339,7 @@ class FSMTest(unittest.TestCase):
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.
@@ -472,9 +399,9 @@ class FSMTest(unittest.TestCase):
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")])
+ st1 = State("INIT", event_filter_list=[addon.create('TriggerEventFilter', "second")])
+ st2 = State("second", event_filter_list=[addon.create('TriggerEventFilter', "third")])
+ st3 = State("third", event_filter_list=[addon.create('TriggerEventFilter', "second")])
fsm = FiniteStateMachine("StateRemovalTest")
@@ -504,10 +431,10 @@ class FSMTest(unittest.TestCase):
# 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"),\
+ 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"),\
+ assert "second" not in fsm.get_following_states("third"), \
"The link to second from third still exists after removal"
def test_set_same_state(self):
@@ -534,8 +461,116 @@ class FSMTest(unittest.TestCase):
"The action was triggered a second time, do_count = %d"%do_count
undo_count = fsm.get_state_by_name("INIT").get_action_list()[0].undo_count
- assert fsm.get_state_by_name("INIT").get_action_list()[0].undo_count == 0,\
+ assert fsm.get_state_by_name("INIT").get_action_list()[0].undo_count == 0, \
"The action has been undone unappropriately, undo_count = %d"%undo_count
+
+ def test_setup(self):
+ fsm = FiniteStateMachine("New state machine")
+
+ try:
+ fsm.setup()
+ assert False, "fsm should throw an exception when trying to setup and not bound to a tutorial"
+ except UnboundLocalError:
+ pass
+
+ def test_setup_actions(self):
+ tut = SimpleTutorial()
+
+ states_dict = {"INIT": State("INIT")}
+ fsm = FiniteStateMachine("New FSM", state_dict=states_dict)
+
+ act = CountAction()
+ fsm.add_action(act)
+
+ fsm.set_tutorial(tut)
+
+ fsm.setup()
+
+ # Let's also test the current state name
+ assert fsm.get_current_state_name() == "INIT", "Initial state should be INIT"
+
+ assert act.do_count == 1, "Action should have been called during setup"
+
+ fsm._fsm_has_finished = True
+
+ fsm.teardown()
+
+ assert act.undo_count == 1, "Action should have been undone"
+
+ def test_string_rep(self):
+ fsm = FiniteStateMachine("Testing machine")
+
+ st1 = State("INIT")
+ st2 = State("Other State")
+ st3 = State("Final State")
+
+ st1.add_action(addon.create("BubbleMessage", "Hi!", [132,312]))
+
+ fsm.add_state(st1)
+ fsm.add_state(st2)
+ fsm.add_state(st3)
+
+ assert str(fsm) == "INIT, Final State, Other State, "
+
+ def test_eq_(self):
+ fsm = FiniteStateMachine("Identity test")
+
+ non_fsm_object = object()
+
+ assert not (fsm == non_fsm_object), "Testing with non FSM object should not give identity"
+
+ # Compare FSMs
+ act1 = CountAction()
+
+ fsm.add_action(act1)
+
+ fsm2 = copy.deepcopy(fsm)
+
+ assert fsm == fsm2
+
+ act2 = CountAction()
+ fsm2.add_action(act2)
+
+ assert not(fsm == fsm2), \
+ "FSMs having a different number of actions should be different"
+
+ fsm3 = FiniteStateMachine("Identity test")
+
+ act3 = addon.create("BubbleMessage", "Hi!", [123,312])
+ fsm3.add_action(act3)
+
+ assert not(fsm3 == fsm), \
+ "Actions having the same number of actions but different ones should be different"
+
+ st1 = State("INIT")
+
+ st2 = State("OtherState")
+
+ fsm.add_state(st1)
+ fsm.add_state(st2)
+
+ fsm4 = copy.deepcopy(fsm)
+
+ assert fsm == fsm4
+
+ st3 = State("Last State")
+
+ fsm4.add_state(st3)
+
+ assert not (fsm == fsm4), "FSMs having a different number of states should not be identical"
+
+ fsm4.remove_state("OtherState")
+
+ assert not (fsm == fsm4), "FSMs having different states should be different"
+
+ fsm4.remove_state("Last State")
+
+ st5 = State("OtherState")
+ st5.add_action(CountAction())
+
+ fsm4.add_state(st5)
+
+ assert not(fsm == fsm4), "FSMs having states with same name but different content should be different"
class FSMExplorationTests(unittest.TestCase):
def setUp(self):
@@ -547,13 +582,13 @@ class FSMExplorationTests(unittest.TestCase):
"""
st1 = State("INIT")
st1.add_action(CountAction())
- st1.add_event_filter(TriggerEventFilter("Second"))
- st1.add_event_filter(TriggerEventFilter("Third"))
+ st1.add_event_filter(addon.create('TriggerEventFilter', "Second"))
+ st1.add_event_filter(addon.create('TriggerEventFilter', "Third"))
st2 = State("Second")
st2.add_action(TrueWhileActiveAction())
- st2.add_event_filter(TriggerEventFilter("Third"))
- st2.add_event_filter(TriggerEventFilter("Fourth"))
+ st2.add_event_filter(addon.create('TriggerEventFilter', "Third"))
+ st2.add_event_filter(addon.create('TriggerEventFilter', "Fourth"))
st3 = State("Third")
st3.add_action(CountAction())
@@ -592,6 +627,5 @@ class FSMExplorationTests(unittest.TestCase):
self.validate_previous_states("Fourth", ("Second"))
-
if __name__ == "__main__":
unittest.main()