# Copyright (C) 2009, Tutorius.org # Copyright (C) 2009, Michael Janelle-Montcalm # Copyright (C) 2009, Vincent Vinet # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ Action tests The behavior of the actions must be tested here. """ import unittest import gtk from sugar.tutorius import addon from sugar.tutorius.addons.triggereventfilter import * from sugar.tutorius.actions import * test_props = {"prop_a":8, "prop_b":3, "prop_c":"Hi"} class PropertyAction(Action): prop_a = TIntProperty(test_props["prop_a"]) prop_b = TIntProperty(test_props["prop_b"]) prop_c = TStringProperty(test_props["prop_c"]) def __init__(self, na): Action.__init__(self) def has_function(obj, function_name): """ Checks whether the object has a function by that name. """ if hasattr(obj, function_name) and hasattr(obj.__getattribute__(function_name), "__call__"): return True return False class PropsTest(unittest.TestCase): def test_get_properties(self): act = PropertyAction(8) assert set(act.get_properties()).issuperset(test_props.keys()), "Action properties should contain at least those we specified" for prop_name in test_props.keys(): assert getattr(act, prop_name) == test_props[prop_name], "Wrong initial value for property %s : %s"%(prop_name,str(getattr(act, prop_name))) class DialogMessageTest(unittest.TestCase): def setUp(self): self.dial = addon.create('DialogMessage', message="Message text", position=[200, 300]) def test_properties(self): assert self.dial.message == "Message text", "Wrong start value for the message" assert self.dial.position == [200, 300], "Wrong start value for the position" class BubbleMessageTest(unittest.TestCase): def setUp(self): self.bubble = addon.create('BubbleMessage', message="Message text", position=[200, 300], tail_pos=[-15, -25]) def test_properties(self): props = self.bubble.get_properties() assert "message" in props, 'No message property of BubbleMessage' assert "position" in props, 'No position property in BubbleMessage' assert "tail_pos" in props, 'No tail position property in BubbleMessage' class CountAction(Action): """ This action counts how many times it's do and undo methods get called """ def __init__(self): Action.__init__(self) self.do_count = 0 self.undo_count = 0 def do(self): self.do_count += 1 def undo(self): self.undo_count += 1 class BaseActionTests(unittest.TestCase): def test_do_unimplemented(self): act = Action() try: act.do() assert False, "do() should trigger a NotImplemented" except NotImplementedError: assert True, "do() should trigger a NotImplemented" def test_undo(self): act = Action() act.undo() assert True, "undo() should never fail on the base action" class OnceWrapperTests(unittest.TestCase): def test_onceaction_toggle(self): """ Validate that the OnceWrapper wrapper works properly using the CountAction """ act = CountAction() wrap = addon.create('OnceWrapper', action=act) assert act.do_count == 0, "do() should not have been called in __init__()" assert act.undo_count == 0, "undo() should not have been called in __init__()" wrap.undo() assert act.undo_count == 0, "undo() should not be called if do() has not been called" wrap.do() assert act.do_count == 1, "do() should have been called once" wrap.do() assert act.do_count == 1, "do() should have been called only once" wrap.undo() assert act.undo_count == 1, "undo() should have been called once" wrap.undo() assert act.undo_count == 1, "undo() should have been called only once" class ChainTester(Action): def __init__(self, witness): Action.__init__(self) self._witness = witness def do(self, **kwargs): self._witness.append([self,"do"]) def undo(self): self._witness.append([self,"undo"]) class ChainActionTest(unittest.TestCase): """Tester for ChainAction""" def test_empty(self): """If the expected empty behavior (do nothing) changes and starts throwing exceptions, this will flag it""" a = addon.create('ChainAction') a.do() a.undo() def test_order(self): witness = [] first = ChainTester(witness) second = ChainTester(witness) c = addon.create('ChainAction', actions=[first, second]) assert witness == [], "Actions should not be triggered on init""" c.do() assert witness[0][0] is first, "First triggered action must be 'first'" assert witness[0][1] is "do", "Action do() should be triggered" assert witness[1][0] is second, "second triggered action must be 'second'" assert witness[1][1] is "do", "Action do() should be triggered" assert len(witness) is 2, "Two actions should give 2 do's" #empty the witness list while len(witness): rm = witness.pop() c.undo() assert witness[1][0] is first, "second triggered action must be 'first'" assert witness[1][1] is "undo", "Action undo() should be triggered" assert witness[0][0] is second, "first triggered action must be 'second'" assert witness[0][1] is "undo", "Action undo() should be triggered" assert len(witness) is 2, "Two actions should give 2 undo's" class DisableWidgetActionTests(unittest.TestCase): def test_disable(self): btn = gtk.Button() btn.set_sensitive(True) assert btn.props.sensitive is True, "Callback should have been called" act = addon.create('DisableWidgetAction', target="0") assert btn.props.sensitive is True, "Callback should have been called again" act.do(activity=btn) assert btn.props.sensitive is False, "Callback should not have been called again" act.undo() assert btn.props.sensitive is True, "Callback should have been called again" class TrueWhileActiveAction(Action): """ This action's active member is set to True after a do and to False after an undo. Used to verify that a State correctly triggers the do and undo actions. """ def __init__(self): Action.__init__(self) self.active = False def do(self): self.active = True 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 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 TypeTextActionTests(unittest.TestCase): """ Test class for type text action """ def test_do_action(self): activity = FakeParentWidget() widget = FakeTextEntry() activity.add_child(widget) test_text = "This is text" action = addon.create('TypeTextAction', widgetUAM="0.0", text=test_text) assert widget == activity.get_children()[0],\ "The clickable widget isn't reachable from the object store \ the test cannot pass" action.do(activity=activity) assert widget.last_entered_line == test_text, "insert_text() should have been called by do()" action.do(activity=activity) 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) test_text = "This is text" action = addon.create('TypeTextAction', widgetUAM="0.0", text=test_text) assert widget == 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 ClickActionTests(unittest.TestCase): """ Test class for click action """ def test_do_action(self): activity = FakeParentWidget() widget = ClickableWidget() activity.add_child(widget) action = addon.create('ClickAction', widget="0.0") assert widget == activity.get_children()[0],\ "The clickable widget isn't reachable from the object store \ the test cannot pass" action.do(activity=activity) assert widget.click_count == 1, "clicked() should have been called by do()" action.do(activity=activity) assert widget.click_count == 2, "clicked() should have been called by do()" def test_undo(self): activity = FakeParentWidget() widget = ClickableWidget() activity.add_child(widget) action = addon.create('ClickAction', widget="0.0") assert widget == 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 if __name__ == "__main__": unittest.main()