A4

Merge lp:~andrea.corbellini/a4/test-suite into lp:a4

Proposed by Andrea Corbellini
Status: Merged
Approved by: Andrea Corbellini
Approved revision: 32
Merged at revision: 52
Proposed branch: lp:~andrea.corbellini/a4/test-suite
Merge into: lp:a4
Diff against target: 777 lines (+443/-288)
8 files modified
Makefile (+4/-0)
test.py (+45/-0)
test_images/drawing.svg (+0/-118)
test_images/roi.svg (+0/-170)
tests/images/drawing.svg (+118/-0)
tests/images/roi.svg (+170/-0)
tests/opening_files.py (+39/-0)
tests/testhelpers.py (+67/-0)
To merge this branch: bzr merge lp:~andrea.corbellini/a4/test-suite
Reviewer Review Type Date Requested Status
Andrea Gualano Approve
Andrea Colangelo Needs Fixing
Review via email: mp+27716@code.launchpad.net

Description of the change

This branch adds the code for a test suite. I've used LDTP as testing framework. It allows us to start and handle windows in a simple manner (however, when a test fails it behaves badly).

To post a comment you must log in.
Revision history for this message
Andrea Gualano (andrea-gualano) wrote :

I couldn't make the tests work:

$ bzr branch lp:~andrea.corbellini/a4/test-suite
Branched 25 revision(s).
$ cd test-suite/
$ make check
python test.py

** (-c:2332): WARNING **: Trying to register gtype 'WnckWindowState' as enum when in fact it is of type 'GFlags'

** (-c:2332): WARNING **: Trying to register gtype 'WnckWindowActions' as enum when in fact it is of type 'GFlags'

** (-c:2332): WARNING **: Trying to register gtype 'WnckWindowMoveResizeMask' as enum when in fact it is of type 'GFlags'
GTK Accessibility Module initialized
GTK Accessibility Module initialized
GTK Accessibility Module initialized
Failed test case: opening_files.TestOpeningFiles.test_open_existent_file
  Traceback (most recent call last):
    File "tests/opening_files.py", line 20, in test_open_existent_file
      dialog.settextvalue('txtLocation', TEST_IMAGE_FILE)
    File "tests/testhelpers.py", line 32, in wrapper
      retval = ldtp_method(self.window_id, *args, **kwargs)
    File "/usr/lib/pymodules/python2.6/ldtp/client.py", line 50, in __call__
      return self.__send(self.__name, args)
    File "/usr/lib/python2.6/xmlrpclib.py", line 1489, in __request
      verbose=self.__verbose
    File "/usr/lib/pymodules/python2.6/ldtp/client.py", line 99, in request
      raise LdtpExecutionError(e.faultString)
  LdtpExecutionError: Unable to find object name "txtLocation" in application map
Failed test case: opening_files.TestOpeningFiles.test_open_incorrect_file
  Traceback (most recent call last):
    File "tests/opening_files.py", line 57, in test_open_incorrect_file
      dialog.settextvalue('txtLocation', os.path.abspath(__file__))
    File "tests/testhelpers.py", line 32, in wrapper
      retval = ldtp_method(self.window_id, *args, **kwargs)
    File "/usr/lib/pymodules/python2.6/ldtp/client.py", line 50, in __call__
      return self.__send(self.__name, args)
    File "/usr/lib/python2.6/xmlrpclib.py", line 1489, in __request
      verbose=self.__verbose
    File "/usr/lib/pymodules/python2.6/ldtp/client.py", line 99, in request
      raise LdtpExecutionError(e.faultString)
  LdtpExecutionError: Unable to find object name "txtLocation" in application map
Failed test case: opening_files.TestOpeningFiles.test_open_inexistent_file
  Traceback (most recent call last):
    File "tests/opening_files.py", line 38, in test_open_inexistent_file
      dialog.settextvalue('txtLocation', 'this-file-does-not-exist')
    File "tests/testhelpers.py", line 32, in wrapper
      retval = ldtp_method(self.window_id, *args, **kwargs)
    File "/usr/lib/pymodules/python2.6/ldtp/client.py", line 50, in __call__
      return self.__send(self.__name, args)
    File "/usr/lib/python2.6/xmlrpclib.py", line 1489, in __request
      verbose=self.__verbose
    File "/usr/lib/pymodules/python2.6/ldtp/client.py", line 99, in request
      raise LdtpExecutionError(e.faultString)
  LdtpExecutionError: Unable to find object name "txtLocation" in application map
Ran 3 tests (3 failed)

review: Needs Fixing
Revision history for this message
Andrea Gualano (andrea-gualano) wrote :

Hi,
the roi.svg test image is something I use to develop A4; all the objects are positioned to allow me to see the trajectories during transitions and so on. Probably it's only useful to me, but I'd prefer to have it in the mainline repository so that I can open it any time I run a test version.

Also, you made several changes to the properties of the objects in A4_nested_transforms.svg; maybe they were useful that way (or maybe not, we should ask Gaspa).

Anyway, the handling of test files is a complex matter, I would split the deletion of test_images/ into a separate branch so that we can finalize this one before taking a definitive position on the test images directory.

Revision history for this message
Andrea Gualano (andrea-gualano) wrote :

One more (possibly unrelated) thing: LDTP is a GUI automation framework, which is cool for testing that the GUI remains functional.
I think we should also have traditional unit tests for things like SVG parsing, maths, rendering.
Perhaps we should make separate make targets for unit and GUI tests.

Revision history for this message
Andrea Corbellini (andrea.corbellini) wrote :

> I couldn't make the tests work...
I suppose that's because you have set Italian as your language. Using English should work, could you confirm, please?

> the roi.svg test image is something I use to develop A4...
Then I will re-add it to the branch. I deleted it because I found it very similar to the other image, sorry.

> Also, you made several changes to the properties of the objects in A4_nested_transforms.svg...
I've just run the 'Delete unused defs' function of Inkscape, so it should be fine.

> Anyway, the handling of test files is a complex matter...
I will put them in tests/images. However I would like to give them more descriptive names, but this can be done in the future.

> One more (possibly unrelated) thing: LDTP is a GUI automation framework...
I generally prefer to write short merge proposals focused on a single feature to make them easier to review. That's why you see just the behaviour-driven tests, but writing tests for the code itself is on my roadmap too (in fact, many things are difficult to test with LDTP).

Revision history for this message
Andrea Gualano (andrea-gualano) wrote :

> I suppose that's because you have set Italian as your language. Using English
> should work, could you confirm, please?

No, my system is set up in English.
I am using Lucid on amd64.

Also, if I have other applications open when I run the tests, they will be closed as if I had clicked on the X button. Don't know if this is useful.

> A4_nested_transforms.svg...
> I've just run the 'Delete unused defs' function of Inkscape, so it should be
> fine.

Yes. After a closer look, I see that the only properties that have changed are in the inkscape namespace, so I don't think we are using them.

> > Anyway, the handling of test files is a complex matter...
> I will put them in tests/images. However I would like to give them more
> descriptive names, but this can be done in the future.

This is okay for now.
In the future we may have to handle three different kinds of test presentations:
- images that will actually be installed on the user's system (in /usr/share/a4/...); ideally these should be beautiful presentations about A4's amazing features, but for now we will have to use the images we have; these are also useful for samples and documentations, see here for example: http://wiki.ubuntu-it.org/GruppoTest/Casi/A4
- images used for development, with a special selection of items, transformations and so on;
- images used by the automated tests.

Revision history for this message
Andrea Gualano (andrea-gualano) wrote :

Same failure on a different machine: Lucid x86, English :-(

Revision history for this message
Andrea Corbellini (andrea.corbellini) wrote :

I've fixed the test. The problem was that by default the 'Location' textbox of the 'Open file' dialog is hidden on GNOME.

Revision history for this message
Andrea Gualano (andrea-gualano) wrote :

GREAT!
I'm going to to test it ASAP.

Revision history for this message
Andrea Colangelo (warp10) wrote :

Looks like we still need some work aroun it. I tried to run test.py and I got this:

andrea@starfleet:~/A4/a4$ python ./test.py

** (-c:18310): WARNING **: Trying to register gtype 'WnckWindowState' as enum when in fact it is of type 'GFlags'

** (-c:18310): WARNING **: Trying to register gtype 'WnckWindowActions' as enum when in fact it is of type 'GFlags'

** (-c:18310): WARNING **: Trying to register gtype 'WnckWindowMoveResizeMask' as enum when in fact it is of type 'GFlags'
GTK Accessibility Module initialized
GTK Accessibility Module initialized
Traceback (most recent call last):
  File "/home/andrea/A4/a4/a4lib/app.py", line 198, in on_drawing_area_expose
    self.player.render(context)
  File "/home/andrea/A4/a4/a4lib/player.py", line 139, in render
    if not self.presentation:
AttributeError: 'CairoPlayer' object has no attribute 'presentation'
Traceback (most recent call last):
  File "/home/andrea/A4/a4/a4lib/app.py", line 198, in on_drawing_area_expose
    self.player.render(context)
  File "/home/andrea/A4/a4/a4lib/player.py", line 139, in render
    if not self.presentation:
AttributeError: 'CairoPlayer' object has no attribute 'presentation'
GTK Accessibility Module initialized
Traceback (most recent call last):
  File "/home/andrea/A4/a4/a4lib/app.py", line 198, in on_drawing_area_expose
    self.player.render(context)
  File "/home/andrea/A4/a4/a4lib/player.py", line 139, in render
    if not self.presentation:
AttributeError: 'CairoPlayer' object has no attribute 'presentation'
Traceback (most recent call last):
  File "/home/andrea/A4/a4/a4lib/app.py", line 198, in on_drawing_area_expose
    self.player.render(context)
  File "/home/andrea/A4/a4/a4lib/player.py", line 139, in render
    if not self.presentation:
AttributeError: 'CairoPlayer' object has no attribute 'presentation'
Traceback (most recent call last):
  File "/home/andrea/A4/a4/a4lib/app.py", line 198, in on_drawing_area_expose
    self.player.render(context)
  File "/home/andrea/A4/a4/a4lib/player.py", line 139, in render
    if not self.presentation:
AttributeError: 'CairoPlayer' object has no attribute 'presentation'
Ran 3 tests without failures
andrea@starfleet:~/A4/a4$ Traceback (most recent call last):
  File "/home/andrea/A4/a4/a4lib/app.py", line 198, in on_drawing_area_expose
    self.player.render(context)
  File "/home/andrea/A4/a4/a4lib/player.py", line 139, in render
    if not self.presentation:
AttributeError: 'CairoPlayer' object has no attribute 'presentation'

Immediately before showing the Traceback, it tried to close the terminal (terminator prevented it).

review: Needs Fixing
Revision history for this message
Andrea Corbellini (andrea.corbellini) wrote :

The tracebacks you are seeing are bugs in the trunk branch (and that's why I like unit testing). The test suite should be fine.

Revision history for this message
Andrea Gualano (andrea-gualano) wrote :
Download full text (3.4 KiB)

Sadly, it's still not working. This time it can't find the control called "tbtnTypeafilename". Also, even in the previous version the Location text field was visible, so the problem seems to be that it can't find the controls by name.

This is what happens: an A4 main window opens, then an Open File dialog titled "a4" opens and gets focus, then nothing happens for a few seconds; then it happens again twice (a main window and a dialog for each test). None of these windows gets closed automatically.
It doesn't close random windows anymore.

Is there any way to see which window the "dialog" variable actually captures? or to get the names of the window controls?

Output:

$ make check
python test.py

** (-c:23319): WARNING **: Trying to register gtype 'WnckWindowState' as enum when in fact it is of type 'GFlags'

** (-c:23319): WARNING **: Trying to register gtype 'WnckWindowActions' as enum when in fact it is of type 'GFlags'

** (-c:23319): WARNING **: Trying to register gtype 'WnckWindowMoveResizeMask' as enum when in fact it is of type 'GFlags'
GTK Accessibility Module initialized
GTK Accessibility Module initialized
GTK Accessibility Module initialized
Failed test case: opening_files.TestOpeningFiles.test_open_existent_file
  Traceback (most recent call last):
    File "tests/opening_files.py", line 24, in test_open_existent_file
      dialog.click('tbtnTypeafilename')
    File "tests/testhelpers.py", line 32, in wrapper
      retval = ldtp_method(self.window_id, *args, **kwargs)
    File "/usr/lib/pymodules/python2.6/ldtp/client.py", line 50, in __call__
      return self.__send(self.__name, args)
    File "/usr/lib/python2.6/xmlrpclib.py", line 1489, in __request
      verbose=self.__verbose
    File "/usr/lib/pymodules/python2.6/ldtp/client.py", line 99, in request
      raise LdtpExecutionError(e.faultString)
  LdtpExecutionError: Unable to find object name "tbtnTypeafilename" in application map
Failed test case: opening_files.TestOpeningFiles.test_open_incorrect_file
  Traceback (most recent call last):
    File "tests/opening_files.py", line 69, in test_open_incorrect_file
      dialog.click('tbtnTypeafilename')
    File "tests/testhelpers.py", line 32, in wrapper
      retval = ldtp_method(self.window_id, *args, **kwargs)
    File "/usr/lib/pymodules/python2.6/ldtp/client.py", line 50, in __call__
      return self.__send(self.__name, args)
    File "/usr/lib/python2.6/xmlrpclib.py", line 1489, in __request
      verbose=self.__verbose
    File "/usr/lib/pymodules/python2.6/ldtp/client.py", line 99, in request
      raise LdtpExecutionError(e.faultString)
  LdtpExecutionError: Unable to find object name "tbtnTypeafilename" in application map
Failed test case: opening_files.TestOpeningFiles.test_open_inexistent_file
  Traceback (most recent call last):
    File "tests/opening_files.py", line 46, in test_open_inexistent_file
      dialog.click('tbtnTypeafilename')
    File "tests/testhelpers.py", line 32, in wrapper
      retval = ldtp_method(self.window_id, *args, **kwargs)
    File "/usr/lib/pymodules/python2.6/ldtp/client.py", line 50, in __call__
      return self.__send(self.__name, args)
    File "/usr/lib/python2.6/xmlrpclib.py"...

Read more...

review: Needs Fixing
Revision history for this message
Andrea Corbellini (andrea.corbellini) wrote :

With the latest revision (32) now everything should work. Instead of opening files using the dialog (that is the cause of the problems), I've given the file name as an argument to A4.

The only exceptions that you should see when running `make check` should be two `AttributeError`s, but these are bugs in the software (that I'd happy to fix with my next branch), not something in the test suite itself.

As usual, feel free to ask if you have questions, doubts or problems.

Revision history for this message
Andrea Gualano (andrea-gualano) wrote :

> Ran 3 tests without failures

It finally works for me too :-)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2010-07-03 00:05:02 +0000
3+++ Makefile 2010-07-14 09:01:45 +0000
4@@ -7,5 +7,9 @@
5 install: build
6 python setup.py install
7
8+check:
9+ python test.py
10+
11 clean:
12+ rm -rf build
13 find . -name "*.pyc" -o -name "*.pyo" -o -name "*~" | xargs rm -f
14
15=== added file 'test.py'
16--- test.py 1970-01-01 00:00:00 +0000
17+++ test.py 2010-07-14 09:01:45 +0000
18@@ -0,0 +1,45 @@
19+# Copyright 2010 A4 Developers. This software is licensed under the
20+# GNU General Public License version 3 (see the file COPYING).
21+
22+"""Test suite runner for A4."""
23+
24+import os
25+import sys
26+import unittest
27+
28+
29+def main():
30+ """Run the test suite."""
31+ total_tests_run = 0
32+ total_failures = 0
33+ sys.path.insert(0, 'tests')
34+ loader = unittest.TestLoader()
35+
36+ for file_name in os.listdir('tests'):
37+ if not file_name.endswith('.py'):
38+ continue
39+
40+ # Get all the test cases from the module.
41+ module = __import__(file_name[:-3])
42+ test = loader.loadTestsFromModule(module)
43+ result = test.run(unittest.TestResult())
44+
45+ # Report the failures (if any).
46+ failures = result.errors + result.failures
47+ for parser, traceback in failures:
48+ print 'Failed test case:', parser.id()
49+ print '\n'.join(' ' + line for line in traceback.splitlines())
50+
51+ total_tests_run += result.testsRun
52+ total_failures += len(failures)
53+
54+ # Give a summary of the tests run.
55+ if total_failures:
56+ print 'Ran {0} tests ({1} failed)'.format(
57+ total_tests_run, total_failures)
58+ else:
59+ print 'Ran {0} tests without failures'.format(total_tests_run)
60+
61+
62+if __name__ == '__main__':
63+ main()
64
65=== removed file 'test_images/drawing.svg'
66--- test_images/drawing.svg 2010-07-03 00:05:02 +0000
67+++ test_images/drawing.svg 1970-01-01 00:00:00 +0000
68@@ -1,118 +0,0 @@
69-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
70-<!-- Created with Inkscape (http://www.inkscape.org/) -->
71-
72-<svg
73- xmlns:dc="http://purl.org/dc/elements/1.1/"
74- xmlns:cc="http://creativecommons.org/ns#"
75- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
76- xmlns:svg="http://www.w3.org/2000/svg"
77- xmlns="http://www.w3.org/2000/svg"
78- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
79- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
80- width="744.09448819"
81- height="1052.3622047"
82- id="svg2"
83- version="1.1"
84- inkscape:version="0.47 r22583"
85- sodipodi:docname="New document 1">
86- <defs
87- id="defs4">
88- <marker
89- inkscape:stockid="Arrow1Lend"
90- orient="auto"
91- refY="0.0"
92- refX="0.0"
93- id="Arrow1Lend"
94- style="overflow:visible;">
95- <path
96- id="path3596"
97- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
98- style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
99- transform="scale(0.8) rotate(180) translate(12.5,0)" />
100- </marker>
101- <marker
102- inkscape:stockid="Arrow1Lstart"
103- orient="auto"
104- refY="0.0"
105- refX="0.0"
106- id="Arrow1Lstart"
107- style="overflow:visible">
108- <path
109- id="path3593"
110- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
111- style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
112- transform="scale(0.8) translate(12.5,0)" />
113- </marker>
114- <inkscape:perspective
115- sodipodi:type="inkscape:persp3d"
116- inkscape:vp_x="0 : 526.18109 : 1"
117- inkscape:vp_y="0 : 1000 : 0"
118- inkscape:vp_z="744.09448 : 526.18109 : 1"
119- inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
120- id="perspective10" />
121- </defs>
122- <sodipodi:namedview
123- id="base"
124- pagecolor="#ffffff"
125- bordercolor="#666666"
126- borderopacity="1.0"
127- inkscape:pageopacity="0.0"
128- inkscape:pageshadow="2"
129- inkscape:zoom="0.7"
130- inkscape:cx="257.79836"
131- inkscape:cy="623.94763"
132- inkscape:document-units="px"
133- inkscape:current-layer="layer1"
134- showgrid="false"
135- inkscape:window-width="1152"
136- inkscape:window-height="789"
137- inkscape:window-x="0"
138- inkscape:window-y="24"
139- inkscape:window-maximized="1" />
140- <metadata
141- id="metadata7">
142- <rdf:RDF>
143- <cc:Work
144- rdf:about="">
145- <dc:format>image/svg+xml</dc:format>
146- <dc:type
147- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
148- <dc:title></dc:title>
149- </cc:Work>
150- </rdf:RDF>
151- </metadata>
152- <g
153- inkscape:label="Layer 1"
154- inkscape:groupmode="layer"
155- id="layer1">
156- <path
157- style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-mid:none;marker-end:url(#Arrow1Lend)"
158- d="m 105.71429,146.6479 0,274.28571 246.42856,-0.71428"
159- id="path2816"
160- sodipodi:nodetypes="ccc" />
161- <path
162- style="fill:none;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
163- d="m 112.14286,263.07647 30,-32.85715 134.28571,170"
164- id="path4410" />
165- <text
166- xml:space="preserve"
167- style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
168- x="316.39716"
169- y="17.035498"
170- id="text4412"
171- transform="matrix(0.60856319,0.79350541,-0.79350541,0.60856319,0,0)"><tspan
172- sodipodi:role="line"
173- id="tspan4414"
174- x="316.39716"
175- y="17.035498"
176- style="font-size:11px">Calo delle vendite</tspan></text>
177- <path
178- style="fill:none;stroke:#000000;stroke-width:20;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
179- d="M 225.71429,592.36218 158.57143,756.6479 344.28571,713.79075"
180- id="path4416" />
181- <path
182- style="fill:none;stroke:#000000;stroke-width:20;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
183- d="m 198.57143,670.93361 54.28571,60"
184- id="path4418" />
185- </g>
186-</svg>
187
188=== removed file 'test_images/roi.svg'
189--- test_images/roi.svg 2010-07-03 00:05:02 +0000
190+++ test_images/roi.svg 1970-01-01 00:00:00 +0000
191@@ -1,170 +0,0 @@
192-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
193-<!-- Created with Inkscape (http://www.inkscape.org/) -->
194-
195-<svg
196- xmlns:dc="http://purl.org/dc/elements/1.1/"
197- xmlns:cc="http://creativecommons.org/ns#"
198- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
199- xmlns:svg="http://www.w3.org/2000/svg"
200- xmlns="http://www.w3.org/2000/svg"
201- xmlns:xlink="http://www.w3.org/1999/xlink"
202- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
203- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
204- width="600"
205- height="300"
206- id="svg2"
207- version="1.1"
208- inkscape:version="0.47 r22583"
209- sodipodi:docname="roi.svg">
210- <defs
211- id="defs4">
212- <linearGradient
213- inkscape:collect="always"
214- id="linearGradient5711">
215- <stop
216- style="stop-color:#0000ff;stop-opacity:1;"
217- offset="0"
218- id="stop5713" />
219- <stop
220- style="stop-color:#0000ff;stop-opacity:0;"
221- offset="1"
222- id="stop5715" />
223- </linearGradient>
224- <inkscape:perspective
225- sodipodi:type="inkscape:persp3d"
226- inkscape:vp_x="0 : 526.18109 : 1"
227- inkscape:vp_y="0 : 1000 : 0"
228- inkscape:vp_z="744.09448 : 526.18109 : 1"
229- inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
230- id="perspective10" />
231- <linearGradient
232- inkscape:collect="always"
233- xlink:href="#linearGradient5711"
234- id="linearGradient5717"
235- x1="-0.5"
236- y1="902.36218"
237- x2="600.5"
238- y2="902.36218"
239- gradientUnits="userSpaceOnUse"
240- gradientTransform="matrix(0.99833752,0,0,0.99667503,0.49875296,-749.36182)" />
241- <inkscape:perspective
242- id="perspective3676"
243- inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
244- inkscape:vp_z="1 : 0.5 : 1"
245- inkscape:vp_y="0 : 1000 : 0"
246- inkscape:vp_x="0 : 0.5 : 1"
247- sodipodi:type="inkscape:persp3d" />
248- <inkscape:perspective
249- id="perspective3704"
250- inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
251- inkscape:vp_z="1 : 0.5 : 1"
252- inkscape:vp_y="0 : 1000 : 0"
253- inkscape:vp_x="0 : 0.5 : 1"
254- sodipodi:type="inkscape:persp3d" />
255- </defs>
256- <sodipodi:namedview
257- id="base"
258- pagecolor="#ffffff"
259- bordercolor="#666666"
260- borderopacity="1.0"
261- inkscape:pageopacity="0.0"
262- inkscape:pageshadow="2"
263- inkscape:zoom="1.3616667"
264- inkscape:cx="225.18656"
265- inkscape:cy="133.68434"
266- inkscape:document-units="px"
267- inkscape:current-layer="layer1"
268- showgrid="false"
269- inkscape:window-width="1280"
270- inkscape:window-height="949"
271- inkscape:window-x="0"
272- inkscape:window-y="24"
273- inkscape:window-maximized="1" />
274- <metadata
275- id="metadata7">
276- <rdf:RDF>
277- <cc:Work
278- rdf:about="">
279- <dc:format>image/svg+xml</dc:format>
280- <dc:type
281- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
282- <dc:title />
283- </cc:Work>
284- </rdf:RDF>
285- </metadata>
286- <metadata
287- id="a4-presentation-information">
288- {&quot;path&quot;:[&quot;one&quot;,&quot;two&quot;,&quot;three&quot;]}</metadata>
289- <g
290- inkscape:label="Layer 1"
291- inkscape:groupmode="layer"
292- id="layer1">
293- <rect
294- style="fill:url(#linearGradient5717);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.9975059;stroke-opacity:1"
295- id="all"
296- width="599.0025"
297- height="299.0025"
298- x="0.49875295"
299- y="0.49874461"
300- inkscape:label="#rect2816" />
301- <rect
302- style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1.013;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
303- id="one"
304- width="198.9865"
305- height="98.986504"
306- x="50.506744"
307- y="50.506802"
308- inkscape:label="#rect5062" />
309- <rect
310- style="fill:#008000;fill-rule:evenodd;stroke:#000000;stroke-width:0.89774972px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
311- id="two"
312- width="149.10225"
313- height="99.102249"
314- x="171.85901"
315- y="323.65402"
316- transform="matrix(0.8660254,-0.5,0.5,0.8660254,0,0)"
317- inkscape:label="#rect2884" />
318- <text
319- xml:space="preserve"
320- style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans;font-stretch:normal;font-variant:normal"
321- x="116.66015"
322- y="110.56646"
323- id="text3658"><tspan
324- sodipodi:role="line"
325- x="116.66015"
326- y="110.56646"
327- id="tspan3662"
328- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">one</tspan></text>
329- <text
330- xml:space="preserve"
331- style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
332- x="216.74605"
333- y="384.34283"
334- id="text3666"
335- transform="matrix(0.8660254,-0.5,0.5,0.8660254,0,0)"><tspan
336- sodipodi:role="line"
337- id="tspan3668"
338- x="216.74605"
339- y="384.34283">two</tspan></text>
340- <rect
341- style="fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.20260075999999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
342- id="three"
343- width="39.797398"
344- height="19.7974"
345- x="380.10132"
346- y="30.101299"
347- inkscape:label="#rect5062" />
348- <text
349- xml:space="preserve"
350- style="font-size:8.00003052px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
351- x="390.99463"
352- y="42.113239"
353- id="text3658-9"
354- transform="scale(0.99999871,1.0000013)"><tspan
355- sodipodi:role="line"
356- x="390.99463"
357- y="42.113239"
358- style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
359- id="tspan3724">three</tspan></text>
360- </g>
361-</svg>
362
363=== added directory 'tests'
364=== renamed directory 'test_images' => 'tests/images'
365=== added file 'tests/images/drawing.svg'
366--- tests/images/drawing.svg 1970-01-01 00:00:00 +0000
367+++ tests/images/drawing.svg 2010-07-14 09:01:45 +0000
368@@ -0,0 +1,118 @@
369+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
370+<!-- Created with Inkscape (http://www.inkscape.org/) -->
371+
372+<svg
373+ xmlns:dc="http://purl.org/dc/elements/1.1/"
374+ xmlns:cc="http://creativecommons.org/ns#"
375+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
376+ xmlns:svg="http://www.w3.org/2000/svg"
377+ xmlns="http://www.w3.org/2000/svg"
378+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
379+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
380+ width="744.09448819"
381+ height="1052.3622047"
382+ id="svg2"
383+ version="1.1"
384+ inkscape:version="0.47 r22583"
385+ sodipodi:docname="New document 1">
386+ <defs
387+ id="defs4">
388+ <marker
389+ inkscape:stockid="Arrow1Lend"
390+ orient="auto"
391+ refY="0.0"
392+ refX="0.0"
393+ id="Arrow1Lend"
394+ style="overflow:visible;">
395+ <path
396+ id="path3596"
397+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
398+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
399+ transform="scale(0.8) rotate(180) translate(12.5,0)" />
400+ </marker>
401+ <marker
402+ inkscape:stockid="Arrow1Lstart"
403+ orient="auto"
404+ refY="0.0"
405+ refX="0.0"
406+ id="Arrow1Lstart"
407+ style="overflow:visible">
408+ <path
409+ id="path3593"
410+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
411+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
412+ transform="scale(0.8) translate(12.5,0)" />
413+ </marker>
414+ <inkscape:perspective
415+ sodipodi:type="inkscape:persp3d"
416+ inkscape:vp_x="0 : 526.18109 : 1"
417+ inkscape:vp_y="0 : 1000 : 0"
418+ inkscape:vp_z="744.09448 : 526.18109 : 1"
419+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
420+ id="perspective10" />
421+ </defs>
422+ <sodipodi:namedview
423+ id="base"
424+ pagecolor="#ffffff"
425+ bordercolor="#666666"
426+ borderopacity="1.0"
427+ inkscape:pageopacity="0.0"
428+ inkscape:pageshadow="2"
429+ inkscape:zoom="0.7"
430+ inkscape:cx="257.79836"
431+ inkscape:cy="623.94763"
432+ inkscape:document-units="px"
433+ inkscape:current-layer="layer1"
434+ showgrid="false"
435+ inkscape:window-width="1152"
436+ inkscape:window-height="789"
437+ inkscape:window-x="0"
438+ inkscape:window-y="24"
439+ inkscape:window-maximized="1" />
440+ <metadata
441+ id="metadata7">
442+ <rdf:RDF>
443+ <cc:Work
444+ rdf:about="">
445+ <dc:format>image/svg+xml</dc:format>
446+ <dc:type
447+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
448+ <dc:title></dc:title>
449+ </cc:Work>
450+ </rdf:RDF>
451+ </metadata>
452+ <g
453+ inkscape:label="Layer 1"
454+ inkscape:groupmode="layer"
455+ id="layer1">
456+ <path
457+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-mid:none;marker-end:url(#Arrow1Lend)"
458+ d="m 105.71429,146.6479 0,274.28571 246.42856,-0.71428"
459+ id="path2816"
460+ sodipodi:nodetypes="ccc" />
461+ <path
462+ style="fill:none;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
463+ d="m 112.14286,263.07647 30,-32.85715 134.28571,170"
464+ id="path4410" />
465+ <text
466+ xml:space="preserve"
467+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
468+ x="316.39716"
469+ y="17.035498"
470+ id="text4412"
471+ transform="matrix(0.60856319,0.79350541,-0.79350541,0.60856319,0,0)"><tspan
472+ sodipodi:role="line"
473+ id="tspan4414"
474+ x="316.39716"
475+ y="17.035498"
476+ style="font-size:11px">Calo delle vendite</tspan></text>
477+ <path
478+ style="fill:none;stroke:#000000;stroke-width:20;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
479+ d="M 225.71429,592.36218 158.57143,756.6479 344.28571,713.79075"
480+ id="path4416" />
481+ <path
482+ style="fill:none;stroke:#000000;stroke-width:20;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
483+ d="m 198.57143,670.93361 54.28571,60"
484+ id="path4418" />
485+ </g>
486+</svg>
487
488=== added file 'tests/images/roi.svg'
489--- tests/images/roi.svg 1970-01-01 00:00:00 +0000
490+++ tests/images/roi.svg 2010-07-14 09:01:45 +0000
491@@ -0,0 +1,170 @@
492+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
493+<!-- Created with Inkscape (http://www.inkscape.org/) -->
494+
495+<svg
496+ xmlns:dc="http://purl.org/dc/elements/1.1/"
497+ xmlns:cc="http://creativecommons.org/ns#"
498+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
499+ xmlns:svg="http://www.w3.org/2000/svg"
500+ xmlns="http://www.w3.org/2000/svg"
501+ xmlns:xlink="http://www.w3.org/1999/xlink"
502+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
503+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
504+ width="600"
505+ height="300"
506+ id="svg2"
507+ version="1.1"
508+ inkscape:version="0.47 r22583"
509+ sodipodi:docname="roi.svg">
510+ <defs
511+ id="defs4">
512+ <linearGradient
513+ inkscape:collect="always"
514+ id="linearGradient5711">
515+ <stop
516+ style="stop-color:#0000ff;stop-opacity:1;"
517+ offset="0"
518+ id="stop5713" />
519+ <stop
520+ style="stop-color:#0000ff;stop-opacity:0;"
521+ offset="1"
522+ id="stop5715" />
523+ </linearGradient>
524+ <inkscape:perspective
525+ sodipodi:type="inkscape:persp3d"
526+ inkscape:vp_x="0 : 526.18109 : 1"
527+ inkscape:vp_y="0 : 1000 : 0"
528+ inkscape:vp_z="744.09448 : 526.18109 : 1"
529+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
530+ id="perspective10" />
531+ <linearGradient
532+ inkscape:collect="always"
533+ xlink:href="#linearGradient5711"
534+ id="linearGradient5717"
535+ x1="-0.5"
536+ y1="902.36218"
537+ x2="600.5"
538+ y2="902.36218"
539+ gradientUnits="userSpaceOnUse"
540+ gradientTransform="matrix(0.99833752,0,0,0.99667503,0.49875296,-749.36182)" />
541+ <inkscape:perspective
542+ id="perspective3676"
543+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
544+ inkscape:vp_z="1 : 0.5 : 1"
545+ inkscape:vp_y="0 : 1000 : 0"
546+ inkscape:vp_x="0 : 0.5 : 1"
547+ sodipodi:type="inkscape:persp3d" />
548+ <inkscape:perspective
549+ id="perspective3704"
550+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
551+ inkscape:vp_z="1 : 0.5 : 1"
552+ inkscape:vp_y="0 : 1000 : 0"
553+ inkscape:vp_x="0 : 0.5 : 1"
554+ sodipodi:type="inkscape:persp3d" />
555+ </defs>
556+ <sodipodi:namedview
557+ id="base"
558+ pagecolor="#ffffff"
559+ bordercolor="#666666"
560+ borderopacity="1.0"
561+ inkscape:pageopacity="0.0"
562+ inkscape:pageshadow="2"
563+ inkscape:zoom="1.3616667"
564+ inkscape:cx="225.18656"
565+ inkscape:cy="133.68434"
566+ inkscape:document-units="px"
567+ inkscape:current-layer="layer1"
568+ showgrid="false"
569+ inkscape:window-width="1280"
570+ inkscape:window-height="949"
571+ inkscape:window-x="0"
572+ inkscape:window-y="24"
573+ inkscape:window-maximized="1" />
574+ <metadata
575+ id="metadata7">
576+ <rdf:RDF>
577+ <cc:Work
578+ rdf:about="">
579+ <dc:format>image/svg+xml</dc:format>
580+ <dc:type
581+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
582+ <dc:title />
583+ </cc:Work>
584+ </rdf:RDF>
585+ </metadata>
586+ <metadata
587+ id="a4-presentation-information">
588+ {&quot;path&quot;:[&quot;one&quot;,&quot;two&quot;,&quot;three&quot;]}</metadata>
589+ <g
590+ inkscape:label="Layer 1"
591+ inkscape:groupmode="layer"
592+ id="layer1">
593+ <rect
594+ style="fill:url(#linearGradient5717);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.9975059;stroke-opacity:1"
595+ id="all"
596+ width="599.0025"
597+ height="299.0025"
598+ x="0.49875295"
599+ y="0.49874461"
600+ inkscape:label="#rect2816" />
601+ <rect
602+ style="fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:1.013;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
603+ id="one"
604+ width="198.9865"
605+ height="98.986504"
606+ x="50.506744"
607+ y="50.506802"
608+ inkscape:label="#rect5062" />
609+ <rect
610+ style="fill:#008000;fill-rule:evenodd;stroke:#000000;stroke-width:0.89774972px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
611+ id="two"
612+ width="149.10225"
613+ height="99.102249"
614+ x="171.85901"
615+ y="323.65402"
616+ transform="matrix(0.8660254,-0.5,0.5,0.8660254,0,0)"
617+ inkscape:label="#rect2884" />
618+ <text
619+ xml:space="preserve"
620+ style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans;font-stretch:normal;font-variant:normal"
621+ x="116.66015"
622+ y="110.56646"
623+ id="text3658"><tspan
624+ sodipodi:role="line"
625+ x="116.66015"
626+ y="110.56646"
627+ id="tspan3662"
628+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans">one</tspan></text>
629+ <text
630+ xml:space="preserve"
631+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
632+ x="216.74605"
633+ y="384.34283"
634+ id="text3666"
635+ transform="matrix(0.8660254,-0.5,0.5,0.8660254,0,0)"><tspan
636+ sodipodi:role="line"
637+ id="tspan3668"
638+ x="216.74605"
639+ y="384.34283">two</tspan></text>
640+ <rect
641+ style="fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-width:0.20260075999999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
642+ id="three"
643+ width="39.797398"
644+ height="19.7974"
645+ x="380.10132"
646+ y="30.101299"
647+ inkscape:label="#rect5062" />
648+ <text
649+ xml:space="preserve"
650+ style="font-size:8.00003052px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
651+ x="390.99463"
652+ y="42.113239"
653+ id="text3658-9"
654+ transform="scale(0.99999871,1.0000013)"><tspan
655+ sodipodi:role="line"
656+ x="390.99463"
657+ y="42.113239"
658+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
659+ id="tspan3724">three</tspan></text>
660+ </g>
661+</svg>
662
663=== added file 'tests/opening_files.py'
664--- tests/opening_files.py 1970-01-01 00:00:00 +0000
665+++ tests/opening_files.py 2010-07-14 09:01:45 +0000
666@@ -0,0 +1,39 @@
667+# Copyright 2010 A4 Developers. This software is licensed under the
668+# GNU General Public License version 3 (see the file COPYING).
669+
670+import os
671+from unittest import TestCase
672+from testhelpers import Application, TEST_IMAGE_FILE
673+
674+"""Try to open some files and see if A4 reports errors when it should."""
675+
676+
677+class TestOpeningFiles(TestCase):
678+ """Check that the procedure of opening a file works as expected."""
679+
680+ def test_open_existent_file(self):
681+ """Try to open an existent file."""
682+ app = Application(TEST_IMAGE_FILE)
683+ self.assertRaises(AssertionError, app.wait_for, 'dlgError')
684+
685+ def test_open_inexistent_file(self):
686+ """Try to open a file that doesn't exist."""
687+ app = Application('this-file-does-not-exist')
688+ # An error dialog should be shown saying that the file doesn't exist.
689+ dialog = app.wait_for('dlgError')
690+ message = dialog.gettextvalue('lblCannotopen*')
691+ self.assertTrue(message.endswith('No such file or directory'))
692+ dialog.click('btnClose')
693+ del dialog
694+
695+ def test_open_incorrect_file(self):
696+ """Try to open an existent file that is not a SVG image."""
697+ # Open a Python script.
698+ app = Application(os.path.abspath(__file__))
699+ # An error dialog should be shown saying that the file format is
700+ # incorrect.
701+ dialog = app.wait_for('dlgError')
702+ message = dialog.gettextvalue('lblCannotopen*')
703+ self.assertTrue(message.endswith('Unknown file type'))
704+ dialog.click('btnClose')
705+ del dialog
706
707=== added file 'tests/testhelpers.py'
708--- tests/testhelpers.py 1970-01-01 00:00:00 +0000
709+++ tests/testhelpers.py 2010-07-14 09:01:45 +0000
710@@ -0,0 +1,67 @@
711+# Copyright 2010 A4 Developers. This software is licensed under the
712+# GNU General Public License version 3 (see the file COPYING).
713+
714+"""Helpers containing code common to almost every the test."""
715+
716+import os
717+import ldtp
718+
719+# An image to be used for tests.
720+TEST_IMAGE_FILE = os.path.abspath(
721+ os.path.join(os.path.dirname(__file__), 'images', 'roi.svg'))
722+
723+# The default timeout for `waittillguiexist` and `waittillguinotexist`.
724+_DEFAULT_TIMEOUT = 1
725+
726+
727+class Window(object):
728+ """An object representing a window or a message dialog."""
729+
730+ def __init__(self, window_id):
731+ self.window_id = window_id
732+ assert ldtp.waittillguiexist(window_id, guiTimeOut=_DEFAULT_TIMEOUT)
733+
734+ def __getattr__(self, attr_name):
735+ """Return a wrapper around the LDTP method with the given name.
736+
737+ The returned wrapper is a function that automatically send the window
738+ ID to the `ldtp` module.
739+ """
740+ ldtp_method = getattr(ldtp, attr_name)
741+
742+ def wrapper(*args, **kwargs):
743+ retval = ldtp_method(self.window_id, *args, **kwargs)
744+ if isinstance(retval, int):
745+ assert retval
746+ else:
747+ return retval
748+
749+ return wrapper
750+
751+ def __del__(self):
752+ """Wait for the closure of the window."""
753+ # `window_id` may be unset if __init__ did not complete successfully.
754+ if hasattr(self, 'window_id'):
755+ ldtp.closewindow(self.window_id)
756+ ldtp.waittillguinotexist(
757+ self.window_id, guiTimeOut=_DEFAULT_TIMEOUT)
758+
759+ def __repr__(self):
760+ return '<{0} {1!r}>'.format(self.__class__.__name__, self.window_id)
761+
762+
763+class Application(Window):
764+ """The main window of A4."""
765+
766+ def __init__(self, *args):
767+ assert ldtp.launchapp('./a4', args)
768+ super(Application, self).__init__('frmA4')
769+
770+ @property
771+ def window_list(self):
772+ """Return a list of IDs of the open windows, including this one."""
773+ return ldtp.getwindowlist()
774+
775+ def wait_for(self, window_id):
776+ """Wait for a window to be opened and return it's object."""
777+ return Window(window_id)

Subscribers

People subscribed via source and target branches