Merge lp:~jtatum/mago/gcalctool into lp:~mago-contributors/mago/mago-1.0
- gcalctool
- Merge into mago-1.0
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~jtatum/mago/gcalctool |
Merge into: | lp:~mago-contributors/mago/mago-1.0 |
Diff against target: | None lines |
To merge this branch: | bzr merge lp:~jtatum/mago/gcalctool |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ara Pulido | Approve | ||
Javier Collado (community) | Approve | ||
Review via email: mp+12236@code.launchpad.net |
This proposal supersedes a proposal from 2009-09-11.
Commit message
Description of the change
James Tatum (jtatum) wrote : Posted in a previous version of this proposal | # |
James Tatum (jtatum) wrote : Posted in a previous version of this proposal | # |
Apologies to anyone who tried r115. There was a small typo in the suite code which broke most of the tests. Oops! r116 works properly.
Ara Pulido (ara) wrote : Posted in a previous version of this proposal | # |
Hello James,
Excellent addition. I specially liked the way you solved the question of menus and buttons using lists.
Only a couple of comments:
In gcalctool_views.py and gcalctool_
Also, in gcalctool_views suite, you just check that the value has not changed. I don't think this is the correct thing to check. Indeed, it is also good to check that, it can be kept, but I would have also had checked things like:
* Buttons that only exist for that view, are now visible
* Window name has changed
Just some possible improvements to an overall very good job.
James Tatum (jtatum) wrote : Posted in a previous version of this proposal | # |
Ara indicated there were superfluous imports in the tests which were removed. Also added tests for specific buttons on specific views. The way the Calculator class in mago/applicatio
Ara Pulido (ara) wrote : Posted in a previous version of this proposal | # |
It looks fine for me. Thanks for your changes!
I will wait for another person to approve, before merging.
Javier Collado (javier.collado) wrote : Posted in a previous version of this proposal | # |
This is a good job, thanks James.
The tests worked perfectly in Karmic, but they didn't in Jaunty probably because LDTP version in repositories is a little old. However, I think this was useful to see that just setting the view to the expected value maybe isn't enough setup for a calculation test case.
For example, let's suppose that in a test case the '=' button wasn't correctly pressed, then the following test case needs to clear the display before continuing. Otherwise, the calculation doesn't start from scratch and the expected value won't be obtained. What do you think about this small change?
Javier Collado (javier.collado) wrote : Posted in a previous version of this proposal | # |
Looking at gcalctools_
While this isn't necessarily bad, I'd say that it's a good practice to write test cases to be independently executed and that prerequisites should be part of test itself and not of a different test cases.
Do you agree on this?
James Tatum (jtatum) wrote : | # |
Resubmitting. Javier correctly noted that the test cases did not need to depend on each other in gcalctool views. Updated.
Javier Collado (javier.collado) wrote : | # |
Nice job.
Ara Pulido (ara) wrote : | # |
Thanks James. Nice job.
I will merge your changes today.
Preview Diff
1 | === added directory 'gcalctool' |
2 | === added file 'gcalctool/README' |
3 | --- gcalctool/README 1970-01-01 00:00:00 +0000 |
4 | +++ gcalctool/README 2009-09-11 02:51:23 +0000 |
5 | @@ -0,0 +1,46 @@ |
6 | +GCALCTOOL TESTS |
7 | +----------- |
8 | +Tests that verify calculator functionality. |
9 | + |
10 | +Safety |
11 | +------ |
12 | +These tests will change the calculator's view, which is loaded at startup. |
13 | +Otherwise, they are safe to run. |
14 | + |
15 | +Configuration |
16 | +------------- |
17 | +No configuration is needed |
18 | + |
19 | +Version |
20 | +------- |
21 | +Tests were updated for Ubuntu Karmic |
22 | + |
23 | +Available Testsuites |
24 | +-------------------- |
25 | + |
26 | +* gcalctool views (testcases wiki: cal-001) |
27 | + Tools that exercise the views in gcalctool |
28 | + These tests will also fail if the title bar text is incorrect |
29 | + - Advanced |
30 | + - Advanced button |
31 | + Verify that the Square button exists in the current view |
32 | + - Financial |
33 | + - Financial button |
34 | + Verify that the Future value button exists in the current view |
35 | + - Scientific |
36 | + - Scientific button |
37 | + Verify that the ln button exists in the current view |
38 | + - Programming |
39 | + - Programming button |
40 | + Verify that the 1's button exists in the current view |
41 | + - Basic |
42 | + - Basic button |
43 | + Verify that the Reciprocal button is hidden in the current view |
44 | +* gcalctool calculations (testcases wiki: cal-002) |
45 | + Tools that perform calculations in gcalctool and verify the results |
46 | + - 3*4=12 |
47 | + - Square root 9=3 |
48 | + - 1+1=2 |
49 | + - 10-2=8 |
50 | + - 14/2=7 |
51 | + - 5*6=30 |
52 | |
53 | === added file 'gcalctool/gcalctool_calculations.py' |
54 | --- gcalctool/gcalctool_calculations.py 1970-01-01 00:00:00 +0000 |
55 | +++ gcalctool/gcalctool_calculations.py 2009-09-10 14:53:24 +0000 |
56 | @@ -0,0 +1,17 @@ |
57 | +# -*- coding: utf-8 -*- |
58 | +from mago.test_suite.gnome import GCalctoolTestSuite |
59 | + |
60 | +class GCalctoolCalculations(GCalctoolTestSuite): |
61 | + def calculate(self, input, oracle, view='BASIC'): |
62 | + if self.application.get_view() != view: |
63 | + self.application.set_view(view) |
64 | + self.application.push(input) |
65 | + value = self.application.get_value() |
66 | + if unicode(value) == unicode(oracle): |
67 | + pass |
68 | + else: |
69 | + raise AssertionError, "Expected %s, calculator returned %s" % (oracle, value) |
70 | + |
71 | +if __name__ == "__main__": |
72 | + gcalctool_calculations_test = GCalctoolCalculations() |
73 | + gcalctool_calculations_test.run() |
74 | |
75 | === added file 'gcalctool/gcalctool_calculations.xml' |
76 | --- gcalctool/gcalctool_calculations.xml 1970-01-01 00:00:00 +0000 |
77 | +++ gcalctool/gcalctool_calculations.xml 2009-09-03 12:20:23 +0000 |
78 | @@ -0,0 +1,61 @@ |
79 | +<?xml version="1.0"?> |
80 | +<suite name="gcalctool calculations"> |
81 | + <class>gcalctool_calculations.GCalctoolCalculations</class> |
82 | + <description> |
83 | + Tests that perform calculations and check the answer (cal-002) |
84 | + </description> |
85 | + <case name="1"> |
86 | + <method>calculate</method> |
87 | + <description>3*4=12</description> |
88 | + <args> |
89 | + <input>3*4=</input> |
90 | + <oracle>12</oracle> |
91 | + <view>BASIC</view> |
92 | + </args> |
93 | + </case> |
94 | + <case name="2"> |
95 | + <method>calculate</method> |
96 | + <description>s9=3</description> |
97 | + <args> |
98 | + <input>Cs9=</input> |
99 | + <oracle>3</oracle> |
100 | + <view>ADVANCED</view> |
101 | + </args> |
102 | + </case> |
103 | + <case name="3"> |
104 | + <method>calculate</method> |
105 | + <description>1+1=2</description> |
106 | + <args> |
107 | + <input>1+1=</input> |
108 | + <oracle>2</oracle> |
109 | + <view>ADVANCED</view> |
110 | + </args> |
111 | + </case> |
112 | + <case name="4"> |
113 | + <method>calculate</method> |
114 | + <description>10-2=8</description> |
115 | + <args> |
116 | + <input>10-2=</input> |
117 | + <oracle>8</oracle> |
118 | + <view>PROGRAMMING</view> |
119 | + </args> |
120 | + </case> |
121 | + <case name="5"> |
122 | + <method>calculate</method> |
123 | + <description>14/2=7</description> |
124 | + <args> |
125 | + <input>14/2=</input> |
126 | + <oracle>7</oracle> |
127 | + <view>FINANCIAL</view> |
128 | + </args> |
129 | + </case> |
130 | + <case name="6"> |
131 | + <method>calculate</method> |
132 | + <description>5*6=30</description> |
133 | + <args> |
134 | + <input>5*6=</input> |
135 | + <oracle>30</oracle> |
136 | + <view>SCIENTIFIC</view> |
137 | + </args> |
138 | + </case> |
139 | +</suite> |
140 | |
141 | === added file 'gcalctool/gcalctool_views.py' |
142 | --- gcalctool/gcalctool_views.py 1970-01-01 00:00:00 +0000 |
143 | +++ gcalctool/gcalctool_views.py 2009-09-19 03:28:17 +0000 |
144 | @@ -0,0 +1,19 @@ |
145 | +# -*- coding: utf-8 -*- |
146 | +from mago.test_suite.gnome import GCalctoolViewTestSuite |
147 | + |
148 | +class GCalctoolViews(GCalctoolViewTestSuite): |
149 | + def changeViews(self, view, state, button): |
150 | + value = self.application.get_value() |
151 | + self.application.set_view(view) |
152 | + if value != self.application.get_value(): |
153 | + raise AssertionError, "Displayed value changed upon changing views" |
154 | + if state == "showing": |
155 | + if self.application.showing(button) == False: |
156 | + raise AssertionError, "Expected button is not showing" |
157 | + elif state == "hidden": |
158 | + if self.application.showing(button) == True: |
159 | + raise AssertionError, "Button is not hidden as expected" |
160 | + |
161 | +if __name__ == "__main__": |
162 | + gcalctool_views_test = GCalctoolViews() |
163 | + gcalctool_views_test.run() |
164 | |
165 | === added file 'gcalctool/gcalctool_views.xml' |
166 | --- gcalctool/gcalctool_views.xml 1970-01-01 00:00:00 +0000 |
167 | +++ gcalctool/gcalctool_views.xml 2009-09-19 03:28:17 +0000 |
168 | @@ -0,0 +1,57 @@ |
169 | +<?xml version="1.0"?> |
170 | +<suite name="gcalctool views"> |
171 | + <class>gcalctool_views.GCalctoolViews</class> |
172 | + <description> |
173 | + Tests that iterate through each calculator view (cal-001) |
174 | + </description> |
175 | + <case name="Advanced"> |
176 | + <method>changeViews</method> |
177 | + <description>Change to the 'advanced' view and verify the square button |
178 | + is showing</description> |
179 | + <args> |
180 | + <view>ADVANCED</view> |
181 | + <state>showing</state> |
182 | + <button>Square</button> |
183 | + </args> |
184 | + </case> |
185 | + <case name="Financial"> |
186 | + <method>changeViews</method> |
187 | + <description>Change to the 'financial' view and verify the future value |
188 | + button is showing</description> |
189 | + <args> |
190 | + <view>FINANCIAL</view> |
191 | + <state>showing</state> |
192 | + <button>Future value</button> |
193 | + </args> |
194 | + </case> |
195 | + <case name="Scientific"> |
196 | + <method>changeViews</method> |
197 | + <description>Change to the 'scientific' view and verify the ln button |
198 | + is showing</description> |
199 | + <args> |
200 | + <view>SCIENTIFIC</view> |
201 | + <state>showing</state> |
202 | + <button>ln</button> |
203 | + </args> |
204 | + </case> |
205 | + <case name="Programming"> |
206 | + <method>changeViews</method> |
207 | + <description>Change to the 'programming' view and verify the 1's button |
208 | + is showing</description> |
209 | + <args> |
210 | + <view>PROGRAMMING</view> |
211 | + <state>showing</state> |
212 | + <button>1's</button> |
213 | + </args> |
214 | + </case> |
215 | + <case name="Basic"> |
216 | + <method>changeViews</method> |
217 | + <description>Change to the 'basic' view and verify the reciprocal button |
218 | + is hidden</description> |
219 | + <args> |
220 | + <view>BASIC</view> |
221 | + <state>hidden</state> |
222 | + <button>Reciprocal</button> |
223 | + </args> |
224 | + </case> |
225 | +</suite> |
226 | |
227 | === modified file 'mago/application/gnome.py' |
228 | --- mago/application/gnome.py 2009-09-02 19:35:05 +0000 |
229 | +++ mago/application/gnome.py 2009-09-11 04:58:37 +0000 |
230 | @@ -6,6 +6,194 @@ |
231 | import ooldtp |
232 | import ldtp |
233 | from .main import Application |
234 | +from ..gconfwrapper import GConf |
235 | +import time |
236 | + |
237 | +class Calculator(Application): |
238 | + """ |
239 | + The Calculator class contains methods for exercising the gcalctool application |
240 | + """ |
241 | + LAUNCHER = "gcalctool" |
242 | + WINDOW = "frmCalculator" |
243 | + WINDOW_ADVANCED = "frmCalculator-Advanced" |
244 | + WINDOW_FINANCIAL = "frmCalculator-Financial" |
245 | + WINDOW_SCIENTIFIC = "frmCalculator-Scientific" |
246 | + WINDOW_PROGRAMMING = "frmCalculator-Programming" |
247 | + MNU_BASIC = "mnuBasic" |
248 | + MNU_ADVANCED = "mnuAdvanced" |
249 | + MNU_FINANCIAL = "mnuFinancial" |
250 | + MNU_SCIENTIFIC = "mnuScientific" |
251 | + MNU_PROGRAMMING = "mnuProgramming" |
252 | + VIEWS = {"BASIC" : {"WINDOW" : WINDOW, |
253 | + "MENU" : MNU_BASIC}, |
254 | + "ADVANCED" : {"WINDOW" : WINDOW_ADVANCED, |
255 | + "MENU" : MNU_ADVANCED}, |
256 | + "FINANCIAL" : {"WINDOW" : WINDOW_FINANCIAL, |
257 | + "MENU" : MNU_FINANCIAL}, |
258 | + "SCIENTIFIC" : {"WINDOW" : WINDOW_SCIENTIFIC, |
259 | + "MENU" : MNU_SCIENTIFIC}, |
260 | + "PROGRAMMING" : {"WINDOW" : WINDOW_PROGRAMMING, |
261 | + "MENU" : MNU_PROGRAMMING}} |
262 | + BUTTONS = {"0" : "Numeric 0", |
263 | + "1" : "Numeric 1", |
264 | + "2" : "Numeric 2", |
265 | + "3" : "Numeric 3", |
266 | + "4" : "Numeric 4", |
267 | + "5" : "Numeric 5", |
268 | + "6" : "Numeric 6", |
269 | + "7" : "Numeric 7", |
270 | + "8" : "Numeric 8", |
271 | + "9" : "Numeric 9", |
272 | + "=" : "Calculate result", |
273 | + "+" : "Add", |
274 | + "-" : "Subtract", |
275 | + "*" : "Multiply", |
276 | + "/" : "Divide", |
277 | + "c" : "Clear entry", |
278 | + "C" : "Clear", |
279 | + "." : "Numeric point", |
280 | + "@" : "Square", |
281 | + "s" : "Square root"} |
282 | + EDITBAR_ROLE = "edit bar" |
283 | + EDITBAR_INDEX = 0 |
284 | + SLEEP_DELAY = 2 |
285 | + GCONF_MODE_KEY = "/apps/gcalctool/mode" |
286 | + GCONF_MODE_VAL = "BASIC" |
287 | + |
288 | + def __init__(self): |
289 | + Application.__init__(self) |
290 | + |
291 | + def open(self): |
292 | + """ |
293 | + Opens the application |
294 | + """ |
295 | + try: |
296 | + GConf.set_item(self.GCONF_MODE_KEY, self.GCONF_MODE_VAL) |
297 | + except GConf.GConfError: |
298 | + raise ldtp.LdtpExecutionError, "Could not set default view in gconf" |
299 | + Application.open(self) |
300 | + |
301 | + def showing(self, button): |
302 | + """ |
303 | + Test whether the specified button is showing |
304 | + |
305 | + @param button: Specify the button to test |
306 | + @type button: string |
307 | + @return: Value indicating whether the button is showing in the view |
308 | + @rtype: boolean |
309 | + |
310 | + >>> c = Calculator() |
311 | + >>> c.open() # Calculator opens in BASIC view |
312 | + >>> c.showing("Reciprocal") |
313 | + False |
314 | + >>> c.set_view("ADVANCED") |
315 | + >>> c.showing("Reciprocal") |
316 | + True |
317 | + """ |
318 | + calculator = ooldtp.context(self.name) |
319 | + try: |
320 | + children = calculator.getchild(button,'push button') |
321 | + for child in children: |
322 | + childName=child.getName() |
323 | + if calculator.hasstate(childName, ldtp.state.SHOWING): |
324 | + return True |
325 | + except ldtp.LdtpExecutionError: |
326 | + raise ldtp.LdtpExecutionError, "Error locating button %s" % button |
327 | + return False |
328 | + |
329 | + def push(self, buttons): |
330 | + """ |
331 | + Push the specified buttons in the calculator window. |
332 | + |
333 | + >>> c = Calculator() |
334 | + >>> c.open() |
335 | + >>> c.push('2+2=') |
336 | + |
337 | + @param buttons: Specify the buttons to push. |
338 | + @type buttons: string |
339 | + """ |
340 | + calculator = ooldtp.context(self.name) |
341 | + for button in buttons: |
342 | + try: |
343 | + # The calculator has some buttons with the same names that are |
344 | + # hidden depending on the view. |
345 | + children = calculator.getchild(self.BUTTONS[button],'push button') |
346 | + for child in children: |
347 | + childName=child.getName() |
348 | + if calculator.hasstate(childName, ldtp.state.SHOWING): |
349 | + calculator.click(childName) |
350 | + break |
351 | + else: |
352 | + raise LookupError, "Could not find button %s in current view" % button |
353 | + except ldtp.LdtpExecutionError: |
354 | + raise ldtp.LdtpExecutionError, "Error clicking button %s" % button |
355 | + |
356 | + def get_view(self): |
357 | + """ |
358 | + Get the current view of the calculator. |
359 | + |
360 | + >>> c = Calculator() |
361 | + >>> c.open() |
362 | + >>> c.get_view() |
363 | + 'BASIC' |
364 | + |
365 | + @return: The current view: BASIC, ADVANCED, FINANCIAL, SCIENTIFIC, |
366 | + or PROGRAMMING |
367 | + @rtype: string |
368 | + """ |
369 | + windowname = self.name |
370 | + for view in self.VIEWS: |
371 | + if self.VIEWS[view]['WINDOW'] == windowname: |
372 | + return view |
373 | + raise LookupError, "Could not identify the current calculator view" |
374 | + |
375 | + def set_view(self, new_view): |
376 | + """ |
377 | + Change to the specified view in the calculator |
378 | + |
379 | + >>> c = Calculator() |
380 | + >>> c.open() |
381 | + >>> c.set_view('ADVANCED') |
382 | + |
383 | + @param new_view: Specify the new view. Valid values are: |
384 | + BASIC, ADVANCED, FINANCIAL, SCIENTIFIC, PROGRAMMING |
385 | + @type new_view: string |
386 | + """ |
387 | + new_window_name = self.VIEWS[new_view]["WINDOW"] |
388 | + new_view_menu_name = self.VIEWS[new_view]["MENU"] |
389 | + calculator = ooldtp.context(self.name) |
390 | + try: |
391 | + mnu_new_view = calculator.getchild(new_view_menu_name) |
392 | + except ldtp.LdtpExecutionError: |
393 | + raise ldtp.LdtpExecutionError, "The menu item for the requested view was not found." |
394 | + |
395 | + try: |
396 | + mnu_new_view.selectmenuitem() |
397 | + except ldtp.LdtpExecutionError: |
398 | + raise ldtp.LdtpExecutionError, "There was a problem changing views." |
399 | + self.set_name(new_window_name) |
400 | + time.sleep(self.SLEEP_DELAY) # need to give mago some time to catch up to calc ui |
401 | + |
402 | + def get_value(self): |
403 | + """ |
404 | + Read the value from the calculator screen |
405 | + |
406 | + >>> c = Calculator() |
407 | + >>> c.open() |
408 | + >>> c.push('2+2=') |
409 | + >>> c.get_value() |
410 | + u'4' |
411 | + |
412 | + @return: The contents of the calculator's screen |
413 | + @rtype: string |
414 | + """ |
415 | + calculator = ooldtp.context(self.name) |
416 | + try: |
417 | + editBar = calculator.getchild('txtResultRegion') # txtResultRegion |
418 | + value = editBar.gettextvalue() |
419 | + except ldtp.LdtpExecutionError: |
420 | + raise ldtp.LdtpExecutionError, "There was a problem reading the value." |
421 | + return value |
422 | |
423 | class GnomeScreenshot(Application): |
424 | """ |
425 | @@ -252,7 +440,6 @@ |
426 | except ldtp.LdtpExecutionError: |
427 | raise ldtp.LdtpExecutionError, "Window " + self.SAVE_FILE_WINDOW + " did not go away" |
428 | |
429 | - |
430 | class Seahorse(Application): |
431 | """ |
432 | Seahorse manages the Seahorse application. |
433 | |
434 | === modified file 'mago/test_suite/gnome.py' |
435 | --- mago/test_suite/gnome.py 2009-08-25 18:33:48 +0000 |
436 | +++ mago/test_suite/gnome.py 2009-09-09 19:03:31 +0000 |
437 | @@ -4,7 +4,30 @@ |
438 | """ |
439 | import ldtp, ooldtp |
440 | from .main import SingleApplicationTestSuite |
441 | -from ..application.gnome import Application, GnomeScreenshot, Seahorse, GEdit |
442 | +from ..application.gnome import Application, Seahorse, GEdit, GnomeScreenshot, Calculator |
443 | + |
444 | +class GCalctoolTestSuite(SingleApplicationTestSuite): |
445 | + """ |
446 | + Default test suite for Calculator |
447 | + """ |
448 | + APPLICATION_FACTORY = Calculator |
449 | + def setup(self): |
450 | + self.application.open() |
451 | + self.application.push("C") |
452 | + |
453 | + def teardown(self): |
454 | + self.application.close() |
455 | + |
456 | + def cleanup(self): |
457 | + pass |
458 | + |
459 | +class GCalctoolViewTestSuite(GCalctoolTestSuite): |
460 | + """ |
461 | + Test suite for views populates the screen with some data in setup |
462 | + """ |
463 | + def setup(self): |
464 | + GCalctoolTestSuite.setup(self) |
465 | + self.application.push("13.37") |
466 | |
467 | class GnomeScreenshotTestSuite(SingleApplicationTestSuite): |
468 | APPLICATION_FACTORY = GnomeScreenshot |
Adding tests for gcalctool