Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/tests/actiontests.py
blob: 7b8d1cb5af23cf667915169ff56b9c3d03d52dba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# Copyright (C) 2009, Tutorius.org
# Copyright (C) 2009, Michael Janelle-Montcalm <michael.jmontcalm@gmail.com>
# Copyright (C) 2009, Vincent Vinet <vince.vinet@gmail.com>
#
# 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 *
from sugar.tutorius.services import ObjectStore

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 act.get_properties() == test_props.keys(), "Action does not contain property 'a'"
        
        for prop_name in act.get_properties():
            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 text", [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', 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', [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()
        ObjectStore().activity = btn
        btn.set_sensitive(True)
        
        assert btn.props.sensitive is True, "Callback should have been called"

        act = addon.create('DisableWidgetAction', "0")
        assert btn.props.sensitive is True, "Callback should have been called again"
        act.do()
        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)
        ObjectStore().activity = activity

        test_text = "This is text"
       
        
        action = addon.create('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 = addon.create('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

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 = addon.create('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 = addon.create('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
if __name__ == "__main__":
    unittest.main()