Merge lp:~pitti/autopilot-gtk/add-tests into lp:autopilot-gtk

Proposed by Martin Pitt
Status: Merged
Approved by: Francis Ginther
Approved revision: 70
Merged at revision: 46
Proposed branch: lp:~pitti/autopilot-gtk/add-tests
Merge into: lp:autopilot-gtk
Diff against target: 1081 lines (+946/-61)
12 files modified
CMakeLists.txt (+1/-1)
debian/control (+6/-1)
debian/rules (+3/-2)
tests/autopilot/tests/test_actions.py (+184/-0)
tests/autopilot/tests/test_gnome_system_log.py (+61/-0)
tests/autopilot/tests/test_matching_properties.py (+0/-32)
tests/autopilot/tests/test_properties.py (+99/-0)
tests/autopilot/tests/test_widget_tree.py (+186/-0)
tests/autopilot/tests/test_xpath_query.py (+110/-0)
tests/hello_color.py (+53/-0)
tests/hello_color.ui (+243/-0)
tests/test-matching.sh (+0/-25)
To merge this branch: bzr merge lp:~pitti/autopilot-gtk/add-tests
Reviewer Review Type Date Requested Status
Francis Ginther Approve
PS Jenkins bot continuous-integration Approve
Martin Pitt (community) Needs Resubmitting
Thomi Richards (community) Needs Fixing
Autopilot Hackers fixed license and test robustness Pending
Review via email: mp+171036@code.launchpad.net

Commit message

Add integration test suite (LP: #1083612)

Description of the change

Add some integration tests, using a tiny tests/hello_color.py application.
There is also a test case that exercises gnome-system-log, which is a lot
lighter than gedit. All these supersede the old test_matching_properties.py.
Please see the individual commits for details.

To post a comment you must log in.
Revision history for this message
Martin Pitt (pitti) wrote :

This MP depends on (and contains) the bits for running the tests during package build: https://code.launchpad.net/~pitti/autopilot-gtk/testsuite/+merge/170607 . So please review that one first.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

Hi,

It looks to me like your copyright header is malformed - you should have two paragraphs.

Other than that, looks good to me.

review: Needs Fixing
lp:~pitti/autopilot-gtk/add-tests updated
56. By Martin Pitt

add complete GPL copyright headers

Revision history for this message
Martin Pitt (pitti) wrote :

Indeed, I added complete ones now.

review: Needs Resubmitting
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~pitti/autopilot-gtk/add-tests updated
57. By Martin Pitt

Add test case for GtkMenuItem globalRect

This verifies https://bugs.launchpad.net/autopilot-gtk/+bug/1133893

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~pitti/autopilot-gtk/add-tests updated
58. By Martin Pitt

tests/hello_color.py: Implement about dialog

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~pitti/autopilot-gtk/add-tests updated
59. By Martin Pitt

adjust tests after previous commit

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~pitti/autopilot-gtk/add-tests updated
60. By Martin Pitt

Add test case for XPath queries

This also reproduces https://launchpad.net/bugs/1179806

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~pitti/autopilot-gtk/add-tests updated
61. By Martin Pitt

refine test to work with the autopilot runner, too

62. By Martin Pitt

drop tests/test-matching.sh; broken, and superseded by test_xpath_query.py

63. By Martin Pitt

debian/control: Add trailing comma to build dependencies to avoid future patch noise

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Francis Ginther (fginther) wrote :

I've started another CI build to get another sample to see if the same error reproduces. The failure could be caused by a timing difference.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Francis Ginther (fginther) wrote :

More failures this time. I'm concerned that this is a product of running with xvfb. We may have to stop running the tests during package build.

I am working on a solution to running these types of tests during CI, but outside of the build itself. No ETA yet as I've only started.

Revision history for this message
Martin Pitt (pitti) wrote :

I can reproduce this failure on my machine when I load it heavily (I have a VM with an autopkgtest running in the background). Looks like I need an Eventually matcher there, the test currently assumes that the GtkEntry has the typed text right after self.app.type(...).

BTW, I ran the tests with verbosity, and it seems it's that achingly slow not because of xvfb, but because of some timeouts due to the local D-BUS:

1: 06:44:22.605 INFO globals:49 - Starting test tests.test_actions.ActionsTest.test_greeting_keyboard
1: 06:44:23.077 INFO __init__:136 - Launching process: ['/home/martin/upstream/ap-gtk-tests/tests/hello_color.py']
1: 06:44:23.082 INFO __init__:169 - Looking for autopilot interface for PID 11949 (and children)
1: 06:44:23.103 WARNING __init__:186 - Caught exception while searching for autopilot interface: 'DBusException("Could not get PID of name 'org.freedesktop.DBus': no such name",)'
1: 06:44:24.131 WARNING __init__:186 - Caught exception while searching for autopilot interface: 'DBusException("Could not get PID of name 'org.freedesktop.DBus': no such name",)'
1: 06:44:49.157 ERROR proxies:410 - Introspect error on :1.7:/com/canonical/Autopilot/Introspection: dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
1: 06:44:49.157 DEBUG proxies:413 - Executing introspect queue due to error
1: 06:45:14.180 WARNING __init__:186 - Caught exception while searching for autopilot interface: 'DBusException('Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.',)'
1: 06:45:14.192 DEBUG dbus:354 - Selecting objects of type GtkEntry with attributes: {}

So it spends almost a minute(!) on each test case on these. I'll try to track that down, too.

lp:~pitti/autopilot-gtk/add-tests updated
64. By Martin Pitt

merge with trunk

65. By Martin Pitt

Run tests with verbosity, to see more detailled output in build logs on failures

66. By Martin Pitt

Fix d-bus startup during package build

Drop our own dbus-launch invocation in debian/rules; that instance fights with
at-spi's own D-BUS launcher, causing long timeouts in autopilot. Also, that
instance never got cleaned up.

This drops the time to run the tests from 10.5 minutes to 47 seconds due to
avoiding the D-BUS timeouts.

67. By Martin Pitt

Fix test_actions.test_menu

In xvfb, the menu might actually start at (0,0), cover this (literal) corner
case.

68. By Martin Pitt

Work around default focus problem in Xvfb

When running under Xvfb, there is sometimes no default focus. If the entry_name
doesn't have focus, click it to work around this.

69. By Martin Pitt

Use Eventually matchers for robustness

Revision history for this message
Martin Pitt (pitti) wrote :

I made some progress:

 * r66 fixes the abysmally long test run time due to the aforementioned D-BUS timeouts. It now runs in ~ 45 seconds instead of 10.5 minutes.

 * r68 works around the test program in xvfb sometimes not having the default focus. That's what caused the above "Joe" != "" failures. Debugging this properly is a bit tricky, I wanted to find out which widget has the default focus (if at all), but I found that select_many() doesn't work for int/bool properties. I'm investigating this now, will file a bug, and add a test case. I marked these as "FIXME" for now, but the workaround is IMHO not too bad. Also, it will become more general and easier to spot after the fix for bug 1082391 lands.

 * The other are various smaller improvements, see their changelogs.

Now, let's see how the CI run likes these :-) I ran this in sbuild about six times and it always passed.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Martin Pitt (pitti) wrote :

OK, two passes in a row, and armhf tests only take 77.51 sec. Feel free to trigger a third build, but from my POV this is robust enough now (I ran this through sbuild another three times).

lp:~pitti/autopilot-gtk/add-tests updated
70. By Martin Pitt

Add (failing) test cases for selecting int/bool properties

This reproduces https://launchpad.net/bugs/1194763

Revision history for this message
Francis Ginther (fginther) wrote :

So I had some trouble running the tests on raring outside of the package build (i.e. "cmake .; make; make test"). But it all ran fine under saucy. The failures are in:

tests.test_actions.ActionsTest.test_menu
 - The test attempts to open the menu where it would appear if it were embedded in the app window, but my menu is in the unity panel.

tests.test_gnome_system_log.GnomeAppTest.test_search
 - This test fails because it can't find the 'GdRevealer'. Possibly this doesn't exist in the saucy version of gnome-system-log?

Given that the failures are not seen on saucy (where development is targeted). I don't see a reason not to approve.

review: Approve
Revision history for this message
Martin Pitt (pitti) wrote :

Indeed in saucy some programs fell back to having integrated menus even under Unity, such as gtimelog or the hello_color.py test application. I'm not sure whether that's deliberate or a bug, I'll ask Didier later. But it should be possible to force a builtin menu with setting UBUNTU_MENUPROXY.

The test_search test should then just be skipped if gnome-system-log is too old.

I'll try this stuff in a raring VM (I don't currently have a raring installation), and do another MP to fix the package build on raring.

Revision history for this message
Martin Pitt (pitti) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2013-06-25 14:42:17 +0000
+++ CMakeLists.txt 2013-06-26 09:35:33 +0000
@@ -11,4 +11,4 @@
11add_subdirectory(lib)11add_subdirectory(lib)
1212
13enable_testing()13enable_testing()
14add_test(nose sh -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/tests/autopilot; GTK_PATH=${CMAKE_CURRENT_BINARY_DIR}/lib autopilot run tests")14add_test(nose sh -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/tests/autopilot; GTK_PATH=${CMAKE_CURRENT_BINARY_DIR}/lib autopilot run -v tests")
1515
=== modified file 'debian/control'
--- debian/control 2013-06-20 13:50:10 +0000
+++ debian/control 2013-06-26 09:35:33 +0000
@@ -11,7 +11,12 @@
11 xvfb,11 xvfb,
12 dbus-x11,12 dbus-x11,
13 python-autopilot,13 python-autopilot,
14 gedit14 python-xlib,
15 python-evdev,
16 python-gi,
17 gir1.2-gtk-3.0,
18 gsettings-desktop-schemas,
19 gnome-system-log,
15Standards-Version: 3.9.420Standards-Version: 3.9.4
16Section: libs21Section: libs
17Homepage: https://launchpad.net/autopilot-gtk22Homepage: https://launchpad.net/autopilot-gtk
1823
=== modified file 'debian/rules'
--- debian/rules 2013-06-20 13:50:10 +0000
+++ debian/rules 2013-06-26 09:35:33 +0000
@@ -7,8 +7,9 @@
7 dh $@ 7 dh $@
88
9override_dh_auto_test:9override_dh_auto_test:
10 mkdir -p debian/tmp/home10 mkdir -p debian/tmp/home/run
11 env HOME=debian/tmp/home xvfb-run dbus-launch dh_auto_test11 env HOME=$(CURDIR)/debian/tmp/home XDG_RUNTIME_DIR=$(CURDIR)/debian/tmp/home/run \
12 xvfb-run dh_auto_test
1213
13override_dh_install:14override_dh_install:
14 dh_install --fail-missing15 dh_install --fail-missing
1516
=== added file 'tests/autopilot/tests/test_actions.py'
--- tests/autopilot/tests/test_actions.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/tests/test_actions.py 2013-06-26 09:35:33 +0000
@@ -0,0 +1,184 @@
1# blackbox testing of autopilot API against our hello_color.py test GTK program
2# Author: Martin Pitt <martin.pitt@ubuntu.com>
3# Copyright (C) 2013 Canonical Ltd
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3 as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import os.path
18
19from autopilot.testcase import AutopilotTestCase
20from autopilot.matchers import Eventually
21from testtools.matchers import Equals, NotEquals
22
23tests_dir = os.path.dirname(os.path.dirname(os.path.dirname(
24 os.path.realpath(__file__))))
25test_app = os.path.join(tests_dir, 'hello_color.py')
26
27
28class ActionsTest(AutopilotTestCase):
29 """Test performing actions in the UI and verify results"""
30
31 def setUp(self):
32 super(ActionsTest, self).setUp()
33 self.app = self.launch_test_application(test_app, app_type='gtk')
34
35 def test_greeting_keyboard(self):
36 """Greeting with keyboard navigation"""
37
38 entries = self.app.select_many('GtkEntry')
39 self.assertEqual(len(entries), 2)
40 # the upper entry is for the name, the lower for the color
41 # FIXME: once we have proper names (LP# 1082391), replace this with an
42 # assertion
43 if entries[0].globalRect[1] < entries[1].globalRect[1]:
44 (entry_name, entry_color) = entries
45 else:
46 (entry_color, entry_name) = entries
47
48 # FIXME: This isn't necessary for real X, but under Xvfb there is no
49 # default focus sometimes
50 if not entry_name.has_focus:
51 self.mouse.click_object(entry_name)
52
53 # type in name and color
54 self.keyboard.type('Joe')
55 self.keyboard.press_and_release('Tab')
56 self.keyboard.type('red')
57
58 # entries should now have the typed text
59 self.assertThat(entry_name.text, Eventually(Equals('Joe')))
60 self.assertThat(entry_color.text, Eventually(Equals('red')))
61
62 # should not have any dialogs
63 self.assertEqual(self.app.select_single('GtkMessageDialog'), None)
64
65 # focus and activate the "Greet" button
66 self.keyboard.press_and_release('Tab')
67 self.keyboard.press_and_release('Enter')
68
69 # should get the greeting dialog
70 self.assertThat(lambda: self.app.select_single('GtkMessageDialog', visible=True),
71 Eventually(NotEquals(None)))
72 md = self.app.select_single('GtkMessageDialog')
73
74 # we expect the message dialog to show the corresponding greeting
75 self.assertNotEqual(md.select_single('GtkLabel',
76 label=u'Hello Joe, you like red.'),
77 None)
78
79 # close the dialog
80 self.keyboard.press_and_release('Enter')
81 self.assertThat(lambda: self.app.select_single('GtkMessageDialog', visible=True),
82 Eventually(Equals(None)))
83
84 def test_greeting_mouse(self):
85 """Greeting with mouse navigation"""
86
87 entries = self.app.select_many('GtkEntry')
88 self.assertEqual(len(entries), 2)
89 # the upper entry is for the name, the lower for the color
90 # FIXME: once we have proper names (LP# 1082391), replace this with an
91 # assertion
92 if entries[0].globalRect[1] < entries[1].globalRect[1]:
93 (entry_name, entry_color) = entries
94 else:
95 (entry_color, entry_name) = entries
96
97 # FIXME: This isn't necessary for real X, but under Xvfb there is no
98 # default focus sometimes
99 if not entry_name.has_focus:
100 self.mouse.click_object(entry_name)
101
102 # type in name and color
103 self.keyboard.type('Joe')
104 self.mouse.click_object(entry_color)
105 self.keyboard.type('blue')
106
107 # entries should now have the typed text
108 self.assertThat(entry_name.text, Eventually(Equals('Joe')))
109 self.assertThat(entry_color.text, Eventually(Equals('blue')))
110
111 # should not have any dialogs
112 self.assertEqual(self.app.select_single('GtkMessageDialog'), None)
113
114 # focus and activate the "Greet" button
115 btn = self.app.select_single('GtkButton', label='Greet')
116 self.assertNotEqual(btn, None)
117 self.mouse.click_object(btn)
118
119 # should get the greeting dialog
120 self.assertThat(lambda: self.app.select_single('GtkMessageDialog', visible=True),
121 Eventually(NotEquals(None)))
122 md = self.app.select_single('GtkMessageDialog')
123
124 # we expect the message dialog to show the corresponding greeting
125 self.assertNotEqual(md.select_single('GtkLabel',
126 label=u'Hello Joe, you like blue.'),
127 None)
128
129 # close the dialog
130 btn = md.select_single('GtkButton', label='gtk-close')
131 self.mouse.click_object(btn)
132 self.assertThat(lambda: self.app.select_single('GtkMessageDialog', visible=True),
133 Eventually(Equals(None)))
134
135 def test_clear(self):
136 """Using Clear button with mouse"""
137
138 # type in name and color
139 self.keyboard.type('Joe')
140 self.keyboard.press_and_release('Tab')
141 self.keyboard.type('blue')
142
143 # clear
144 btn = self.app.select_single('GtkButton', label='gtk-delete')
145 self.mouse.click_object(btn)
146
147 # entries should be clear now
148 entries = self.app.select_many('GtkEntry')
149 self.assertEqual(len(entries), 2)
150 for e in entries:
151 self.assertThat(e.text, Eventually(Equals('')))
152
153 def test_menu(self):
154 """Browse the menu"""
155
156 file_menu = self.app.select_single('GtkMenuItem', label='_File')
157 help_menu = self.app.select_single('GtkMenuItem', label='_Help')
158 self.assertNotEqual(file_menu, None)
159 self.assertNotEqual(help_menu, None)
160
161 # the top-level menus should be visible and thus have a rect
162 for m in (file_menu, help_menu):
163 self.assertGreaterEqual(m.globalRect[0], 0)
164 self.assertGreaterEqual(m.globalRect[1], 0)
165 self.assertGreater(m.globalRect[2], 0)
166 self.assertGreater(m.globalRect[3], 0)
167
168 # the submenus are not visible by default
169 m = self.app.select_single('GtkImageMenuItem', label='gtk-open')
170 self.assertFalse(hasattr(m, 'globalRect'))
171
172 # after opening, submenus should become visible
173 self.mouse.click_object(file_menu)
174 # FIXME: getting a reference to this object once and then just querying
175 # it doesn't work
176 self.assertThat(lambda: hasattr(self.app.select_single('GtkImageMenuItem',
177 label='gtk-open'),
178 'globalRect'),
179 Eventually(Equals(True)))
180 m = self.app.select_single('GtkImageMenuItem', label='gtk-open')
181 self.assertGreaterEqual(m.globalRect[0], 0)
182 self.assertGreaterEqual(m.globalRect[1], 0)
183 self.assertGreater(m.globalRect[2], 0)
184 self.assertGreater(m.globalRect[3], 0)
0185
=== added file 'tests/autopilot/tests/test_gnome_system_log.py'
--- tests/autopilot/tests/test_gnome_system_log.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/tests/test_gnome_system_log.py 2013-06-26 09:35:33 +0000
@@ -0,0 +1,61 @@
1# blackbox testing of autopilot API against gnome-system-log
2# Author: Martin Pitt <martin.pitt@ubuntu.com>
3# Copyright (C) 2013 Canonical Ltd
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3 as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
18from autopilot.testcase import AutopilotTestCase
19from autopilot.matchers import Eventually
20from testtools.matchers import Equals, NotEquals
21
22
23class GnomeAppTest(AutopilotTestCase):
24 """Test autopilot against an actual GNOME application"""
25
26 def setUp(self):
27 super(GnomeAppTest, self).setUp()
28 self.patch_environment('LANGUAGE', '')
29 self.patch_environment('LANG', '')
30 self.patch_environment('LC_MESSAGES', 'C')
31 self.app = self.launch_test_application('gnome-system-log', '/etc/issue')
32
33 def test_filename_label(self):
34 """Find file name label"""
35
36 l = self.app.select_single('GtkLabel', label=u'<b>issue</b>')
37 self.assertNotEqual(l, None)
38 self.assertEqual(l.visible, True)
39
40 def test_search(self):
41 """Run a search"""
42
43 revealer = self.app.select_single('GdRevealer')
44 self.assertNotEqual(revealer, None)
45
46 # search bar not visible by default
47 self.assertEqual(revealer.child_revealed, False)
48
49 search_btn = self.app.select_single('GtkToggleButton')
50 self.assertNotEqual(search_btn, None)
51 self.mouse.click_object(search_btn)
52
53 # should trigger search bar
54 self.assertThat(lambda: revealer.child_revealed, Eventually(Equals(True)))
55 search = self.app.select_single('GtkSearchEntry', visible=True)
56 self.assertTrue(search.has_focus)
57
58 # something that will not be in /etc/issue
59 self.keyboard.type('Bogus12!')
60 self.assertThat(lambda: self.app.select_single('GtkLabel', label=u'No matches found'),
61 Eventually(NotEquals(None)))
062
=== removed file 'tests/autopilot/tests/test_matching_properties.py'
--- tests/autopilot/tests/test_matching_properties.py 2013-05-22 23:29:06 +0000
+++ tests/autopilot/tests/test_matching_properties.py 1970-01-01 00:00:00 +0000
@@ -1,32 +0,0 @@
1
2
3from autopilot.testcase import AutopilotTestCase
4from testtools.matchers import NotEquals
5
6
7
8class PropertyMatchingTest(AutopilotTestCase):
9
10 def setUp(self):
11 super(PropertyMatchingTest, self).setUp()
12 self.app = self.launch_test_application('gedit')
13
14 def test_integer_matches(self):
15 """Test property matching for integers.
16
17 Find an opaque GtkWindow in Gedit.
18 """
19
20 opaque_window = self.app.select_many('GtkWindow', opacity=1)
21 self.assertThat(opaque_window, NotEquals(None))
22
23
24 def test_string_matches(self):
25 """Match a string property.
26
27 Find an GtkImageMenuItem named 'BookmarkOpen' in Gedit.
28 """
29
30 bookmark_open_item = self.app.select_single('GtkImageMenuItem',
31 name='BookmarkOpen')
32 self.assertThat(bookmark_open_item, NotEquals(None))
330
=== added file 'tests/autopilot/tests/test_properties.py'
--- tests/autopilot/tests/test_properties.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/tests/test_properties.py 2013-06-26 09:35:33 +0000
@@ -0,0 +1,99 @@
1# blackbox testing of autopilot API against our hello_color.py test GTK program
2# Author: Martin Pitt <martin.pitt@ubuntu.com>
3# Copyright (C) 2013 Canonical Ltd
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3 as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import os.path
18import unittest
19
20from autopilot.testcase import AutopilotTestCase
21
22tests_dir = os.path.dirname(os.path.dirname(os.path.dirname(
23 os.path.realpath(__file__))))
24test_app = os.path.join(tests_dir, 'hello_color.py')
25
26
27class PropertyTest(AutopilotTestCase):
28 """Widget properties"""
29
30 def setUp(self):
31 super(PropertyTest, self).setUp()
32 self.app = self.launch_test_application(test_app, app_type='gtk')
33
34 def test_button(self):
35 """GtkButton properties"""
36
37 btn_greet = self.app.select_single('GtkButton', label='Greet')
38 self.assertNotEqual(btn_greet, None)
39 btn_quit = self.app.select_single('GtkButton', label='gtk-quit')
40 self.assertNotEqual(btn_quit, None)
41
42 self.assertEqual(btn_greet.use_stock, False)
43 self.assertEqual(btn_quit.use_stock, True)
44
45 # only GtkButton, GtkFileChooserButton, and GtkComboBox have
46 # focus-on-click, and we don't use the latter two
47 self.assertEqual(btn_greet.focus_on_click, True)
48 self.assertEqual(btn_quit.focus_on_click, True)
49
50 # all buttons are visible and thus should have a rect
51 self.assertTrue(btn_greet.visible)
52 self.assertTrue(btn_quit.visible)
53 self.assertEqual(len(btn_greet.globalRect), 4)
54 self.assertEqual(len(btn_quit.globalRect), 4)
55
56 def test_entry(self):
57 """GtkEntry properties"""
58
59 entries = self.app.select_many('GtkEntry')
60 self.assertEqual(len(entries), 2)
61 # the upper entry is for the name, the lower for the color
62 # FIXME: once we have proper names (LP# 1082391), replace this with an
63 # assertion
64 if entries[0].globalRect[1] < entries[1].globalRect[1]:
65 (entry_name, entry_color) = entries
66 else:
67 (entry_color, entry_name) = entries
68
69 self.assertTrue(entry_name.visible)
70 self.assertTrue(entry_color.visible)
71
72 # the entries should have the same size and x alignment
73 self.assertEqual(entry_name.globalRect[0], entry_color.globalRect[0])
74 self.assertEqual(entry_name.globalRect[2:], entry_color.globalRect[2:])
75
76 # FIXME: This isn't necessary for real X, but under Xvfb there is no
77 # default focus sometimes
78 if not entry_name.has_focus:
79 self.mouse.click_object(entry_name)
80
81 # first entry has default focus
82 self.assertEqual(entry_name.has_focus, True)
83 self.assertEqual(entry_color.has_focus, False)
84
85 # both entries are empty by default
86 self.assertEqual(entry_name.text, '')
87 self.assertEqual(entry_color.text, '')
88
89 # text-length is an unique property for GtkEntry
90 self.assertEqual(entry_name.text_length, 0)
91 self.assertEqual(entry_color.text_length, 0)
92
93 #https://launchpad.net/bugs/1193342
94 @unittest.expectedFailure
95 def test_enum_properties(self):
96 '''enum properties'''
97
98 btn_greet = self.app.select_single('GtkButton', label='Greet')
99 self.assertTrue(hasattr(btn_greet, 'relief'))
0100
=== added file 'tests/autopilot/tests/test_widget_tree.py'
--- tests/autopilot/tests/test_widget_tree.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/tests/test_widget_tree.py 2013-06-26 09:35:33 +0000
@@ -0,0 +1,186 @@
1# blackbox testing of autopilot API against our hello_color.py test GTK program
2# Author: Martin Pitt <martin.pitt@ubuntu.com>
3# Copyright (C) 2013 Canonical Ltd
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3 as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import os.path
18import unittest
19
20from autopilot.testcase import AutopilotTestCase
21
22tests_dir = os.path.dirname(os.path.dirname(os.path.dirname(
23 os.path.realpath(__file__))))
24test_app = os.path.join(tests_dir, 'hello_color.py')
25
26
27class WidgetTreeTest(AutopilotTestCase):
28 """Widget tree iteration and search"""
29
30 def setUp(self):
31 super(WidgetTreeTest, self).setUp()
32 self.app = self.launch_test_application(test_app, app_type='gtk')
33
34 def test_get_children_recursive(self):
35 """Recursive get_children()
36
37 This should not crash, and deliver valid widgets.
38 """
39 widgets = set()
40 self._get_widgets(self.app, widgets)
41 for c in widgets:
42 self.assertIn('.Gtk', str(type(c)))
43 self.assertGreaterEqual(c.id, 0)
44 # uncomment this to get a dump of all widgets and properties
45 #print(type(c))
46 #for p in c.get_properties():
47 # print ' ', p, repr(getattr(c, p))
48
49 def test_get_children_by_type(self):
50 # multiple instances
51 res = self.app.get_children_by_type('GtkWindow')
52 self.assertGreaterEqual(len(res), 3)
53 self.assertIn('.GtkWindow', str(type(res[0])))
54
55 # one qualified instance
56 res = self.app.get_children_by_type('GtkWindow', Children=['GtkBox'])
57 self.assertGreaterEqual(len(res), 1)
58
59 # no instances
60 self.assertEqual(self.app.get_children_by_type('GtkTable'), [])
61
62 def test_select_single_unique(self):
63 """select_single() on widget types with only one instance"""
64
65 for wtype in ('GtkMenuBar', 'GtkAboutDialog', 'GtkGrid'):
66 w = self.app.select_single(wtype)
67 self.assertIn('.' + wtype, str(type(w)))
68
69 def test_select_single_nonunique(self):
70 """select_single() on widget types with multiple instances"""
71
72 # we have more than one instance of these
73 for wtype in ('GtkButton', 'GtkEntry'):
74 self.assertRaises(ValueError, self.app.select_single, wtype)
75
76 # we have no instances of these
77 for wtype in ('GtkTable', 'GtkRadioButton'):
78 self.assertIs(self.app.select_single(wtype), None)
79
80 # qualified: visible property is not unique
81 self.assertRaises(ValueError,
82 self.app.select_single, 'GtkButton', visible=1)
83
84 # qualified: label property is unique within GtkButton
85 w = self.app.select_single('GtkButton', label='gtk-quit')
86 self.assertIn('.GtkButton', str(type(w)))
87 self.assertEqual(w.label, 'gtk-quit')
88
89 def test_select_single_noclass(self):
90 """select_single() without specifying a class"""
91
92 # gtk-delete label is unique to our Button
93 w = self.app.select_single(label='gtk-delete')
94 self.assertIn('.GtkButton', str(type(w)))
95 self.assertEqual(w.label, 'gtk-delete')
96
97 # gtk-quit label is not unique globally, it's also a menu item
98 self.assertRaises(ValueError, self.app.select_single, label='gtk-quit')
99
100 # ... but it is unique for focussable widgets (menus don't allow that)
101 w = self.app.select_single(label='gtk-quit', can_focus=1)
102 self.assertIn('.GtkButton', str(type(w)))
103 self.assertEqual(w.label, 'gtk-quit')
104
105 def test_select_many_string(self):
106 """select_many() with string properties"""
107
108 # by class, unqualified, multiple instances
109 res = self.app.select_many('GtkButton')
110 # we have three in our main window, plus some in the about dialog
111 self.assertGreaterEqual(len(res), 3)
112 self.assertIn('.GtkButton', str(type(res[0])))
113
114 # .. but exactly three in the main window
115 main_window = self.app.select_single('GtkWindow', Children=['GtkBox'], visible=True)
116 res = main_window.select_many('GtkButton')
117 self.assertEqual(len(res), 3)
118
119 # by class, unqualified, single instance
120 res = self.app.select_many('GtkMenuBar')
121 self.assertEqual(len(res), 1)
122 self.assertIn('.GtkMenuBar', str(type(res[0])))
123
124 # by class, unqualified, no instance
125 res = self.app.select_many('GtkTable')
126 self.assertEqual(res, [])
127
128 # by class, qualified
129 res = self.app.select_many('GtkButton', label='Greet')
130 self.assertEqual(len(res), 1)
131 self.assertIn('.GtkButton', str(type(res[0])))
132 self.assertEqual(res[0].label, 'Greet')
133
134 # untyped
135 res = self.app.select_many(label='gtk-delete')
136 self.assertEqual(len(res), 1)
137 self.assertIn('.GtkButton', str(type(res[0])))
138 self.assertEqual(res[0].label, 'gtk-delete')
139
140 res = self.app.select_many(label='gtk-quit')
141 # button and menu item
142 self.assertEqual(len(res), 2)
143
144 # https://launchpad.net/bugs/1194763
145 @unittest.expectedFailure
146 def test_select_int(self):
147 """select_*() with int properties"""
148
149 # with class
150 res = self.app.select_many('GtkButtonBox', border_width=5)
151 self.assertEqual(len(res), 1)
152
153 self.assertNotEqual(self.app.select_single('GtkButtonBox', border_width=5), None)
154
155 # without class
156 res = self.app.select_many(border_width=5)
157 self.assertGreater(len(res), 2)
158
159 self.assertNotEqual(self.app.select_single(border_width=2), None)
160
161 # https://launchpad.net/bugs/1194763
162 @unittest.expectedFailure
163 def test_select_bool(self):
164 """select_*() with boolean properties"""
165
166 # with class
167 res = self.app.select_many('GtkButton', visible=True)
168 self.assertGreater(len(res), 2)
169
170 res = self.app.select_many('GtkAboutDialog', visible=False)
171 self.assertGreater(len(res), 0)
172
173 # without class
174 res = self.app.select_many(visible=True)
175 self.assertGreater(len(res), 5)
176
177 res = self.app.select_many(visible=False)
178 self.assertGreater(len(res), 4)
179
180 @classmethod
181 def _get_widgets(klass, obj, widget_set):
182 """Recursively add all children of obj to widget_set"""
183
184 for c in obj.get_children():
185 widget_set.add(c)
186 klass._get_widgets(c, widget_set)
0187
=== added file 'tests/autopilot/tests/test_xpath_query.py'
--- tests/autopilot/tests/test_xpath_query.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/tests/test_xpath_query.py 2013-06-26 09:35:33 +0000
@@ -0,0 +1,110 @@
1# blackbox testing of autopilot API against our hello_color.py test GTK program
2# Author: Martin Pitt <martin.pitt@ubuntu.com>
3# Copyright (C) 2013 Canonical Ltd
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3 as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import os.path
18import unittest
19
20from autopilot.testcase import AutopilotTestCase
21
22tests_dir = os.path.dirname(os.path.dirname(os.path.dirname(
23 os.path.realpath(__file__))))
24test_app = os.path.join(tests_dir, 'hello_color.py')
25
26
27class XPathQueryTest(AutopilotTestCase):
28 """XPath queries"""
29
30 def setUp(self):
31 super(XPathQueryTest, self).setUp()
32 self.app = self.launch_test_application(test_app, app_type='gtk')
33
34 def xtest_have_path(self):
35 """All children have a unique path"""
36
37 widgets = set()
38 self._get_widgets(self.app, widgets)
39
40 seen_paths = set()
41 for widget in widgets:
42 path = widget.get_class_query_string()
43 self.assertNotIn(path, seen_paths)
44 seen_paths.add(path)
45
46 # we can resolve the path back to the widget
47 state = self.app.get_state_by_path(path)
48 # state is an array with one (path, props) element
49 props = state[0][1]
50 self.assertEqual(props['id'], widget.id)
51 self.assertEqual(props['visible'], widget.visible)
52
53 def xtest_select_full_path(self):
54 """Select widgets with full XPath"""
55
56 # three buttons in main dialog's ButtonBox
57 state = self.app.get_state_by_path('/Root/GtkWindow/GtkBox/GtkButtonBox/GtkButton')
58 self.assertEqual(len(state), 3)
59 labels = [str(props[1]['label']) for props in state]
60 labels.sort()
61 self.assertEqual(labels, ['Greet', 'gtk-delete', 'gtk-quit'])
62
63 # select button with particular label
64 for l in ['Greet', 'gtk-delete', 'gtk-quit']:
65 state = self.app.get_state_by_path('/Root/GtkWindow/GtkBox/GtkButtonBox/GtkButton[label=%s]' % l)
66 self.assertEqual(len(state), 1)
67 self.assertEqual(state[0][1]['label'], l)
68
69 def xtest_select_path_pattern(self):
70 """Select widgets with XPath path pattern"""
71
72 # three buttons in main dialog's ButtonBox
73 state = self.app.get_state_by_path('//GtkWindow//GtkButton')
74 self.assertEqual(len(state), 3)
75 labels = [str(props[1]['label']) for props in state]
76 labels.sort()
77 self.assertEqual(labels, ['Greet', 'gtk-delete', 'gtk-quit'])
78
79 # at least four buttons in the whole tree
80 state = self.app.get_state_by_path('/Root//GtkButton')
81 self.assertGreaterEqual(len(state), 4)
82
83 def test_select_by_attribute(self):
84 """Select widgets with attribute pattern"""
85
86 state = self.app.get_state_by_path('//*[label=gtk-delete]')
87 self.assertEqual(len(state), 1, state)
88 self.assertEqual(state[0][1]['label'], 'gtk-delete')
89 self.assertTrue(state[0][0].endswith('/GtkButton'), state[0][0])
90
91 # https://launchpad.net/bugs/1179806
92 @unittest.expectedFailure
93 def test_select_by_attribute_spaces(self):
94 """Select widgets with attribute pattern containing spaces"""
95
96 # none of these work ATM, but are supposed to:
97 #state = self.app.get_state_by_path('//*[label=Hello&#x20;Color!]')
98 #state = self.app.get_state_by_path('//*[label=Hello&#x0020;Color!]')
99 state = self.app.get_state_by_path('//*[label="Hello Color!"]')
100 self.assertEqual(len(state), 1, str(state))
101 self.assertEqual(state[0][1]['label'], 'Hello Color!')
102 self.assertTrue(state[0][0].endswith('/GtkLabel'), state[0][0])
103
104 @classmethod
105 def _get_widgets(klass, obj, widget_set):
106 """Recursively add all children of obj to widget_set"""
107
108 for c in obj.get_children():
109 widget_set.add(c)
110 klass._get_widgets(c, widget_set)
0111
=== added file 'tests/hello_color.py'
--- tests/hello_color.py 1970-01-01 00:00:00 +0000
+++ tests/hello_color.py 2013-06-26 09:35:33 +0000
@@ -0,0 +1,53 @@
1#!/usr/bin/python
2
3import sys
4import os.path
5
6from gi.repository import Gtk
7
8
9class HelloColorApp(Gtk.Application):
10 def __init__(self):
11 self.widgets = Gtk.Builder.new()
12 self.widgets.add_from_file((os.path.join(os.path.dirname(sys.argv[0]), 'hello_color.ui')))
13 assert self.widgets.connect_signals(self) is None
14
15 def run(self):
16 self.widgets.get_object('window_app').show()
17 Gtk.main()
18
19 def on_quit(self, *args):
20 Gtk.main_quit()
21
22 def on_file_open(self, *args):
23 md = Gtk.FileChooserDialog('Select a file..',
24 parent=self.widgets.get_object('window_app'),
25 buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
26 Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
27 result = md.run()
28 md.hide()
29 if result == Gtk.ResponseType.OK:
30 self.widgets.get_object('label_status').set_text('Loaded %s' % md.get_filenames()[0])
31
32 def on_button_greet(self, *args):
33 name = self.widgets.get_object('entry_name').get_text()
34 color = self.widgets.get_object('entry_color').get_text()
35
36 md = Gtk.MessageDialog(message_type=Gtk.MessageType.INFO,
37 buttons=Gtk.ButtonsType.CLOSE,
38 text='Hello %s, you like %s.' % (name, color))
39 md.run()
40 md.hide()
41
42 def on_button_clear(self, *args):
43 self.widgets.get_object('entry_name').set_text('')
44 self.widgets.get_object('entry_color').set_text('')
45 self.widgets.get_object('label_status').set_text('')
46
47 def on_about(self, *args):
48 d = self.widgets.get_object('dialog_about')
49 d.run()
50 d.hide()
51
52if __name__ == '__main__':
53 HelloColorApp().run()
054
=== added file 'tests/hello_color.ui'
--- tests/hello_color.ui 1970-01-01 00:00:00 +0000
+++ tests/hello_color.ui 2013-06-26 09:35:33 +0000
@@ -0,0 +1,243 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<interface>
3 <!-- interface-requires gtk+ 3.0 -->
4 <object class="GtkAboutDialog" id="dialog_about">
5 <property name="can_focus">False</property>
6 <property name="border_width">5</property>
7 <property name="type_hint">dialog</property>
8 <property name="program_name">Hello Color!</property>
9 <property name="copyright" translatable="yes">(C) 2013 Canonical Ltd.</property>
10 <property name="authors">Martin Pitt</property>
11 <property name="license_type">gpl-3-0</property>
12 </object>
13 <object class="GtkWindow" id="window_app">
14 <property name="can_focus">False</property>
15 <signal name="destroy" handler="on_quit" swapped="no"/>
16 <child>
17 <object class="GtkBox" id="box1">
18 <property name="visible">True</property>
19 <property name="can_focus">False</property>
20 <property name="orientation">vertical</property>
21 <child>
22 <object class="GtkMenuBar" id="menubar">
23 <property name="visible">True</property>
24 <property name="can_focus">False</property>
25 <child>
26 <object class="GtkMenuItem" id="menuitem_file">
27 <property name="visible">True</property>
28 <property name="can_focus">False</property>
29 <property name="label" translatable="yes">_File</property>
30 <property name="use_underline">True</property>
31 <child type="submenu">
32 <object class="GtkMenu" id="menu1">
33 <property name="visible">True</property>
34 <property name="can_focus">False</property>
35 <child>
36 <object class="GtkImageMenuItem" id="menu_file_open">
37 <property name="label">gtk-open</property>
38 <property name="visible">True</property>
39 <property name="can_focus">False</property>
40 <property name="use_underline">True</property>
41 <property name="use_stock">True</property>
42 <signal name="activate" handler="on_file_open" swapped="no"/>
43 </object>
44 </child>
45 <child>
46 <object class="GtkSeparatorMenuItem" id="separatormenuitem1">
47 <property name="visible">True</property>
48 <property name="can_focus">False</property>
49 </object>
50 </child>
51 <child>
52 <object class="GtkImageMenuItem" id="menu_item_quit">
53 <property name="label">gtk-quit</property>
54 <property name="visible">True</property>
55 <property name="can_focus">False</property>
56 <property name="use_underline">True</property>
57 <property name="use_stock">True</property>
58 <signal name="activate" handler="on_quit" swapped="no"/>
59 </object>
60 </child>
61 </object>
62 </child>
63 </object>
64 </child>
65 <child>
66 <object class="GtkMenuItem" id="menuitem_help">
67 <property name="visible">True</property>
68 <property name="can_focus">False</property>
69 <property name="label" translatable="yes">_Help</property>
70 <property name="use_underline">True</property>
71 <child type="submenu">
72 <object class="GtkMenu" id="menu2">
73 <property name="visible">True</property>
74 <property name="can_focus">False</property>
75 <child>
76 <object class="GtkImageMenuItem" id="menu_help_about">
77 <property name="label">gtk-about</property>
78 <property name="visible">True</property>
79 <property name="can_focus">False</property>
80 <property name="use_underline">True</property>
81 <property name="use_stock">True</property>
82 <signal name="activate" handler="on_about" swapped="no"/>
83 </object>
84 </child>
85 </object>
86 </child>
87 </object>
88 </child>
89 </object>
90 <packing>
91 <property name="expand">False</property>
92 <property name="fill">True</property>
93 <property name="position">0</property>
94 </packing>
95 </child>
96 <child>
97 <object class="GtkGrid" id="grid1">
98 <property name="visible">True</property>
99 <property name="can_focus">False</property>
100 <property name="halign">start</property>
101 <property name="margin_left">5</property>
102 <property name="margin_right">5</property>
103 <property name="margin_top">5</property>
104 <property name="margin_bottom">5</property>
105 <property name="row_spacing">5</property>
106 <property name="column_spacing">5</property>
107 <child>
108 <object class="GtkLabel" id="label1">
109 <property name="visible">True</property>
110 <property name="can_focus">False</property>
111 <property name="label" translatable="yes">Name</property>
112 </object>
113 <packing>
114 <property name="left_attach">0</property>
115 <property name="top_attach">0</property>
116 <property name="width">1</property>
117 <property name="height">1</property>
118 </packing>
119 </child>
120 <child>
121 <object class="GtkLabel" id="label2">
122 <property name="visible">True</property>
123 <property name="can_focus">False</property>
124 <property name="label" translatable="yes">Color</property>
125 </object>
126 <packing>
127 <property name="left_attach">0</property>
128 <property name="top_attach">1</property>
129 <property name="width">1</property>
130 <property name="height">1</property>
131 </packing>
132 </child>
133 <child>
134 <object class="GtkEntry" id="entry_name">
135 <property name="visible">True</property>
136 <property name="can_focus">True</property>
137 <property name="has_focus">True</property>
138 <property name="invisible_char">•</property>
139 </object>
140 <packing>
141 <property name="left_attach">1</property>
142 <property name="top_attach">0</property>
143 <property name="width">1</property>
144 <property name="height">1</property>
145 </packing>
146 </child>
147 <child>
148 <object class="GtkEntry" id="entry_color">
149 <property name="visible">True</property>
150 <property name="can_focus">True</property>
151 <property name="invisible_char">•</property>
152 </object>
153 <packing>
154 <property name="left_attach">1</property>
155 <property name="top_attach">1</property>
156 <property name="width">1</property>
157 <property name="height">1</property>
158 </packing>
159 </child>
160 </object>
161 <packing>
162 <property name="expand">True</property>
163 <property name="fill">True</property>
164 <property name="position">1</property>
165 </packing>
166 </child>
167 <child>
168 <object class="GtkLabel" id="label_status">
169 <property name="visible">True</property>
170 <property name="can_focus">False</property>
171 <property name="xalign">0</property>
172 <property name="xpad">5</property>
173 <property name="ypad">10</property>
174 </object>
175 <packing>
176 <property name="expand">False</property>
177 <property name="fill">True</property>
178 <property name="position">2</property>
179 </packing>
180 </child>
181 <child>
182 <object class="GtkButtonBox" id="buttonbox2">
183 <property name="visible">True</property>
184 <property name="can_focus">False</property>
185 <property name="spacing">10</property>
186 <property name="homogeneous">True</property>
187 <property name="layout_style">end</property>
188 <child>
189 <object class="GtkButton" id="button_greet">
190 <property name="label" translatable="yes">Greet</property>
191 <property name="visible">True</property>
192 <property name="can_focus">True</property>
193 <property name="receives_default">True</property>
194 <signal name="clicked" handler="on_button_greet" swapped="no"/>
195 </object>
196 <packing>
197 <property name="expand">False</property>
198 <property name="fill">True</property>
199 <property name="position">0</property>
200 </packing>
201 </child>
202 <child>
203 <object class="GtkButton" id="button_clear">
204 <property name="label">gtk-delete</property>
205 <property name="visible">True</property>
206 <property name="can_focus">True</property>
207 <property name="receives_default">True</property>
208 <property name="use_stock">True</property>
209 <signal name="clicked" handler="on_button_clear" swapped="no"/>
210 </object>
211 <packing>
212 <property name="expand">False</property>
213 <property name="fill">True</property>
214 <property name="position">1</property>
215 </packing>
216 </child>
217 <child>
218 <object class="GtkButton" id="button_quit">
219 <property name="label">gtk-quit</property>
220 <property name="visible">True</property>
221 <property name="can_focus">True</property>
222 <property name="receives_default">True</property>
223 <property name="use_stock">True</property>
224 <property name="image_position">right</property>
225 <signal name="clicked" handler="on_quit" swapped="no"/>
226 </object>
227 <packing>
228 <property name="expand">False</property>
229 <property name="fill">True</property>
230 <property name="position">2</property>
231 </packing>
232 </child>
233 </object>
234 <packing>
235 <property name="expand">False</property>
236 <property name="fill">True</property>
237 <property name="position">3</property>
238 </packing>
239 </child>
240 </object>
241 </child>
242 </object>
243</interface>
0244
=== removed file 'tests/test-matching.sh'
--- tests/test-matching.sh 2013-05-22 09:11:04 +0000
+++ tests/test-matching.sh 1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
1#!/bin/bash
2#
3
4# gedit --gtk-module `pwd`/lib/libautopilot.so &
5# GEDIT_PID=$!
6# sleep 2
7
8EMPTY_SET='[Argument: a(sv) {}]'
9RES=1
10
11RET=`qdbus --literal org.gnome.gedit /com/canonical/Autopilot/Introspection com.canonical.Autopilot.Introspection.GetState '/Root//GtkWindow[opacity=1]'`
12if [ "$RET" == "$EMPTY_SET" ]; then
13 echo "FAIL"
14 RES=0
15fi
16
17RET=`qdbus --literal org.gnome.gedit /com/canonical/Autopilot/Introspection com.canonical.Autopilot.Introspection.GetState '/Root//GtkWindow/GtkMenu/GtkImageMenuItem[name=BookmarkOpen]'`
18if [ "$RET" == "$EMPTY_SET" ]; then
19 echo "FAIL"
20 RES=0
21fi
22
23
24# kill $GEDIT_PID
25exit $RES

Subscribers

People subscribed via source and target branches

to all changes: