From 1bc406d0fb8704a7a71dcdf52f54dc6f5b4e5921 Mon Sep 17 00:00:00 2001 From: Vincent Vinet Date: Tue, 31 Mar 2009 16:59:10 +0000 Subject: Ajout de tests --- (limited to 'src/sugar/tutorius/tests') diff --git a/src/sugar/tutorius/tests/actiontests.py b/src/sugar/tutorius/tests/actiontests.py index 2a60a65..5fb3d0f 100644 --- a/src/sugar/tutorius/tests/actiontests.py +++ b/src/sugar/tutorius/tests/actiontests.py @@ -1,4 +1,6 @@ # 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 @@ -20,7 +22,10 @@ The behavior of the actions must be tested here. """ import unittest -from sugar.tutorius.actions import * +import gtk + +from sugar.tutorius.actions import Action, OnceWrapper +from sugar.tutorius.services import ObjectStore class PropertyAction(Action): def __init__(self, na): @@ -41,5 +46,64 @@ class PropsTest(unittest.TestCase): assert prop.get_properties() == ['a'], "Action does not contain property 'a'" +class CountAction(Action): + """ + This action counts how many times it's do and undo methods get called + """ + def __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 = OnceWrapper(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" + if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() + diff --git a/src/sugar/tutorius/tests/coretests.py b/src/sugar/tutorius/tests/coretests.py index ec730f2..f9125ce 100644 --- a/src/sugar/tutorius/tests/coretests.py +++ b/src/sugar/tutorius/tests/coretests.py @@ -18,18 +18,24 @@ Core Tests This module contains all the tests that pertain to the usage of the Tutorius -Core. This means that the Event Filters, the Finite State Machine and all the +Core. This means that the the Finite State Machine, States and all the related elements and interfaces are tested here. +Usage of actions and event filters is tested, but not the concrete actions +and event filters. Those are in their separate test module + """ import unittest import logging -from sugar.tutorius.actions import Action, OnceWrapper +from sugar.tutorius.actions import Action from sugar.tutorius.core import * from sugar.tutorius.filters import * + +from actiontests import CountAction + # Helper classes to help testing class SimpleTutorial(Tutorial): """ @@ -60,19 +66,6 @@ class TrueWhileActiveAction(Action): self.active = False -class CountAction(Action): - """ - This action counts how many times it's do and undo methods get called - """ - def __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 TriggerEventFilter(EventFilter): """ @@ -110,48 +103,6 @@ class FakeEventFilter(TriggerEventFilter): self.tutorial.set_state(event_filter.get_next_state()) -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 = OnceWrapper(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" # State testing class diff --git a/src/sugar/tutorius/tests/filterstests.py b/src/sugar/tutorius/tests/filterstests.py new file mode 100644 index 0000000..4b7ae61 --- /dev/null +++ b/src/sugar/tutorius/tests/filterstests.py @@ -0,0 +1,200 @@ +# Copyright (C) 2009, Tutorius.org +# 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 +""" +Filters Tests + +This module contains all the tests that pertain to the usage of the Tutorius +Event Filters +""" + +import unittest +import time +import gobject +import gtk + +from sugar.tutorius.filters import EventFilter, TimerEvent, GtkWidgetEventFilter +from gtkutilstests import SignalCatcher + +class BaseEventFilterTests(unittest.TestCase): + """Test the behavior of the Base EventFilter class""" + def test_properties(self): + """Test EventFilter properties""" + e = EventFilter("NEXTSTATE") + + assert e.next_state == "NEXTSTATE", "next_state should have value used in constructor" + + e.next_state = "NEWSTATE" + + assert e.next_state == "NEWSTATE", "next_state should have been changed by setter" + + + def test_callback(self): + """Test the callback mechanism""" + e = EventFilter("Next") + s = SignalCatcher() + + #Trigger the do_callback, shouldn't do anything + e.do_callback() + + #Install the handler + e.install_handlers(s.callback) + + #Trigger the do_callback, s should receive e + e.do_callback() + assert s.data[0] is e + + s.data = None + + e.remove_handlers() + + #Trigger callback, nothing should happen again + e.do_callback() + + assert s.data is None + + + + + +class TestTimerEvent(unittest.TestCase): + """Tests for timer""" + def test_timer(self): + """Make sure timer gets called once, and only once""" + gobject.threads_init() + ctx = gobject.MainContext() + main = gobject.MainLoop(ctx) + + e = TimerEvent("Next",1) #1 second should be enough :s + s = SignalCatcher() + + e.install_handlers(s.callback) + + assert s.data is None, "Callback should not have been called yet" + + #process events + while gtk.events_pending(): + gtk.main_iteration(block=False) + while ctx.pending(): + ctx.iteration(may_block=False) + + #Wait 1.4 sec + time.sleep(1.4) + + #process events + while gtk.events_pending(): + gtk.main_iteration(block=False) + while ctx.pending(): + ctx.iteration(may_block=False) + + assert not s.data is None, "Callback should have been called" + + s.data = None + + #Wait 1.4 sec + time.sleep(1.4) + + #process events + while gtk.events_pending(): + gtk.main_iteration(block=False) + while ctx.pending(): + ctx.iteration(may_block=False) + + assert s.data is None, "Callback should not have been called again" + + def test_timer_stop(self): + """Make sure timer can be stopped""" + gobject.threads_init() + ctx = gobject.MainContext() + main = gobject.MainLoop(ctx) + + e = TimerEvent("Next",1) #1 second should be enough :s + s = SignalCatcher() + + e.install_handlers(s.callback) + + assert s.data is None, "Callback should not have been called yet" + + #process events + while gtk.events_pending(): + gtk.main_iteration(block=False) + while ctx.pending(): + ctx.iteration(may_block=False) + + assert s.data is None, "Callback should not have been called yet" + + #Wait 0.5 sec + time.sleep(0.5) + + e.remove_handlers() + + #Wait 0.5 sec + time.sleep(0.7) + + #process events + while gtk.events_pending(): + gtk.main_iteration(block=False) + while ctx.pending(): + ctx.iteration(may_block=False) + + assert s.data is None, "Callback should not have been called" + + s.data = None + + +class TestGtkWidgetEventFilter(unittest.TestCase): + """Tests for GtkWidgetEventFilter""" + def __init__(self,*args): + unittest.TestCase.__init__(self,*args) + self.top=None + self.btn1=None + + def setUp(self): + self.top = gtk.Window() + self.btn1 = gtk.Button() + self.top.add(self.btn1) + + def test_install(self): + h = GtkWidgetEventFilter("Next","0","whatever") + try: + h.install_handlers(None) + + assert False, "Install handlers should have failed" + except TypeError: + assert True, "Install should have failed" + + def test_button_clicks(self): + h = GtkWidgetEventFilter("Next","0.0","clicked") + s = SignalCatcher() + + h.install_handlers(s.callback, activity=self.top) + + assert s.data is None, "no callback to call yet" + + self.btn1.clicked() + assert not s.data is None, "callback should have been called" + s.data = None + + h.remove_handlers() + + assert s.data is None, "callback must not be called again" + + self.btn1.clicked() + + assert s.data is None, "callback must not be called again" + + + diff --git a/src/sugar/tutorius/tests/gtkutilstests.py b/src/sugar/tutorius/tests/gtkutilstests.py index fb9a20b..5dfd363 100644 --- a/src/sugar/tutorius/tests/gtkutilstests.py +++ b/src/sugar/tutorius/tests/gtkutilstests.py @@ -26,16 +26,22 @@ import unittest import logging import gtk, gobject -from sugar.tutorius.gtkutils import find_widget, register_signals_numbered, register_signals +from sugar.tutorius.gtkutils import find_widget, register_signals_numbered, register_signals, get_children class SignalCatcher(object): + """Test class that store arguments received on it's callback method. + Useful for testing callbacks""" def __init__(self): - self.data = [] + """Constructor""" + self.data = None def callback(self, *args): + """Callback function, stores argument list in self.data""" self.data = args def disconnect_handlers(hlist): + """Disconnect handles in handler list. hlist must be a list of + two-tuples (widget, handler_id)""" for widget, handler in hlist: try: widget.handler_disconnect(handler) @@ -97,6 +103,8 @@ class GtkUtilsTests(unittest.TestCase): def test_named(self): #def register_signals(target, handler, prefix=None, max_depth=None): s=SignalCatcher() + + #Test 0 depth handler_list = register_signals(self.top, s.callback, max_depth=0) #remove duplicates in widget list @@ -104,12 +112,36 @@ class GtkUtilsTests(unittest.TestCase): assert len(widget_list) == 1, "register_signals should not have recursed (%d objects registered)" % len(widget_list) - while gtk.events_pending(): - gtk.main_iteration(block=False) + assert widget_list[0] == self.top, "register_signals should have gotten only the top" + + disconnect_handlers(handler_list) + + #Test 2 depth + handler_list = register_signals(self.top, s.callback, max_depth=2) + + #remove duplicates in widget list + widget_list = dict.fromkeys([w for w, h in handler_list]).keys() + + assert len(widget_list) == 5, "expected %d objects (got %d)" % (len(widget_list), 5) + + disconnect_handlers(handler_list) + + #Test Infinite depth + handler_list = register_signals(self.top, s.callback, max_depth=None) + + #remove duplicates in widget list + widget_list = dict.fromkeys([w for w, h in handler_list]).keys() + + assert len(widget_list) == 7, "expected %d objects (got %d)" % (len(widget_list), 7) + + disconnect_handlers(handler_list) + def test_numbered(self): s=SignalCatcher() #def register_signals_numbered(target, handler, prefix="0", max_depth=None): + + #Test 0 depth handler_list = register_signals_numbered(self.top, s.callback, max_depth=0) #remove duplicates in widget list @@ -117,15 +149,51 @@ class GtkUtilsTests(unittest.TestCase): assert len(widget_list) == 1, "register_signals should not have recursed (%d objects registered)" % len(widget_list) - while gtk.events_pending(): - gtk.main_iteration(block=False) + assert widget_list[0] == self.top, "register_signals should have gotten only the top" + + disconnect_handlers(handler_list) + + #Test 1 depth + handler_list = register_signals_numbered(self.top, s.callback, max_depth=1) + + #remove duplicates in widget list + widget_list = dict.fromkeys([w for w, h in handler_list]).keys() + + assert len(widget_list) == 2, "expected %d objects (got %d)" % (len(widget_list), 2) + + disconnect_handlers(handler_list) + + #Test Infinite depth + handler_list = register_signals_numbered(self.top, s.callback, max_depth=None) + + #remove duplicates in widget list + widget_list = dict.fromkeys([w for w, h in handler_list]).keys() + + assert len(widget_list) == 7, "expected %d objects (got %d)" % (len(widget_list), 7) + + disconnect_handlers(handler_list) + def test_find_widget(self): + #Test individual values in the defined widgets for widget in self.widgets.values(): f = find_widget(self.top, widget["numbered"]) assert f is widget["widget"], "Widget %s found with path %s, expected %s" % (f, widget["numbered"], widget["widget"]) + #Test out of index + f = find_widget(self.top, "0.99.1.2") + assert f is self.top, "Should have returned top widget" + + def test_notwidget(self): + """Test the get_children function""" + o = object() + res = get_children(o) + + assert len(res) == 0, "object has no children" + top_children = get_children(self.top) + expected = [self.widgets["hbox0"]["widget"],] + assert top_children == expected, "expected %s for top's children, got %s" % (str(expected),str(top_children)) if __name__ == "__main__": unittest.main() diff --git a/src/sugar/tutorius/tests/linear_creatortests.py b/src/sugar/tutorius/tests/linear_creatortests.py index 3bc06f9..f9ffbe7 100644 --- a/src/sugar/tutorius/tests/linear_creatortests.py +++ b/src/sugar/tutorius/tests/linear_creatortests.py @@ -19,8 +19,8 @@ from sugar.tutorius.core import * from sugar.tutorius.actions import * from sugar.tutorius.filters import * from sugar.tutorius.linear_creator import * -from coretests import TriggerEventFilter, CountAction - +from coretests import TriggerEventFilter +from actiontests import CountAction import unittest class CreatorTests(unittest.TestCase): @@ -64,6 +64,16 @@ class CreatorTests(unittest.TestCase): assert len(state2.get_action_list()) == 0, "Creator inserted extra actions on wrong state" assert len(state2.get_event_filter_list()) == 0, "Creator assigner events to the final state" + + creator.action(CountAction()) + + fsm = creator.generate_fsm() + + state2 = fsm.get_state_by_name("State2") + + assert len(state2.get_action_list()) == 1, "Creator did not add the action" + + assert len(state2.get_event_filter_list()) == 0, "Creator assigner events to the final state" if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/src/sugar/tutorius/tests/run-tests.py b/src/sugar/tutorius/tests/run-tests.py index 2f89c62..e1dfc00 100755 --- a/src/sugar/tutorius/tests/run-tests.py +++ b/src/sugar/tutorius/tests/run-tests.py @@ -10,10 +10,17 @@ sys.path.insert(0, ) FULL_PATH = os.path.join(INSTALL_PATH,"sugar/tutorius") +SUBDIRS = [] GLOB_PATH = os.path.join(FULL_PATH,"*.py") import unittest from glob import glob +def report_files(): + ret = glob(GLOB_PATH) + for dir in SUBDIRS: + ret += glob(os.path.join(FULL_PATH,dir,"*.py")) + return ret + import sys if __name__=='__main__': if "--coverage" in sys.argv: @@ -29,7 +36,8 @@ if __name__=='__main__': import overlaytests import linear_creatortests import actiontests - + import filterstests + suite = unittest.TestSuite() suite.addTests(unittest.findTestCases(coretests)) suite.addTests(unittest.findTestCases(servicestests)) @@ -37,12 +45,13 @@ if __name__=='__main__': suite.addTests(unittest.findTestCases(overlaytests)) suite.addTests(unittest.findTestCases(linear_creatortests)) suite.addTests(unittest.findTestCases(actiontests)) + suite.addTests(unittest.findTestCases(filterstests)) runner = unittest.TextTestRunner() runner.run(suite) coverage.stop() - coverage.report(glob(GLOB_PATH)) + coverage.report(report_files()) coverage.erase() else: from coretests import * @@ -50,5 +59,7 @@ if __name__=='__main__': from gtkutilstests import * from overlaytests import * from actiontests import * + from linear_creatortests import * + from filterstests import * unittest.main() -- cgit v0.9.1