Merge lp:~jtatum/mago/gcalctool into lp:~mago-contributors/mago/mago-1.0

Proposed by James Tatum
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
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.

To post a comment you must log in.
Revision history for this message
James Tatum (jtatum) wrote : Posted in a previous version of this proposal

Adding tests for gcalctool

Revision history for this message
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.

Revision history for this message
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_calculations.py you seemed to haved copypasted the skeleton from gedit_chains.py, and added an import (time, sfrtime...) not needed in these cases (minor issue, really).

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.

review: Needs Fixing
Revision history for this message
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/application/gnome.py is setup makes it very sensitive to the title bar, so it was not necessary to explicitly test for the correct title bar.

Revision history for this message
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.

review: Approve
Revision history for this message
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?

review: Needs Information
Revision history for this message
Javier Collado (javier.collado) wrote : Posted in a previous version of this proposal

Looking at gcalctools_views.xml, I saw that test cases are expected to be executed in the same order that they were written and that they are interrelated.

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?

review: Needs Information
Revision history for this message
James Tatum (jtatum) wrote :

Resubmitting. Javier correctly noted that the test cases did not need to depend on each other in gcalctool views. Updated.

Revision history for this message
Javier Collado (javier.collado) wrote :

Nice job.

review: Approve
Revision history for this message
Ara Pulido (ara) wrote :

Thanks James. Nice job.
I will merge your changes today.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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

Subscribers

People subscribed via source and target branches

to status/vote changes: