Merge lp:~mzanetti/autopilot-qt/add-tests into lp:autopilot-qt
- add-tests
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Mathieu Trudel-Lapierre | ||||
Approved revision: | 55 | ||||
Merged at revision: | 52 | ||||
Proposed branch: | lp:~mzanetti/autopilot-qt/add-tests | ||||
Merge into: | lp:autopilot-qt | ||||
Diff against target: |
1062 lines (+773/-129) 23 files modified
autopilot-qt.pro (+1/-1) debian/control (+12/-0) debian/libautopilot-qt-autopilot.install (+3/-0) debian/rules (+2/-2) driver/introspection.cpp (+21/-4) test/main.cpp (+0/-17) test/test.pro (+0/-11) test/test_dbus_introspection.cpp (+0/-50) test/test_dbus_introspection.h (+0/-44) tests/autopilot/autopilot.pro (+2/-0) tests/autopilot/libautopilot_qt/__init__.py (+8/-0) tests/autopilot/libautopilot_qt/emulators/__init__.py (+6/-0) tests/autopilot/libautopilot_qt/emulators/main_window_qt4.py (+57/-0) tests/autopilot/libautopilot_qt/emulators/main_window_qt5.py (+57/-0) tests/autopilot/libautopilot_qt/tests/__init__.py (+66/-0) tests/autopilot/libautopilot_qt/tests/test_main.py (+103/-0) tests/autopilot/testapp/qt4.qml (+55/-0) tests/autopilot/testapp/qt5.qml (+55/-0) tests/autopilot/testapp/testapp.cpp (+52/-0) tests/autopilot/testapp/testapp.pro (+22/-0) tests/tests.pro (+2/-0) tests/unittests/tst_introspection.cpp (+223/-0) tests/unittests/unittests.pro (+26/-0) |
||||
To merge this branch: | bzr merge lp:~mzanetti/autopilot-qt/add-tests | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mathieu Trudel-Lapierre (community) | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Martin Mrazik (community) | Approve | ||
Review via email: mp+153695@code.launchpad.net |
Commit message
- added unittests
- added integration tests
- added support for reading QtObjects dynamic properties
- fixed a bug with Qt5 QWidget introspection
- added libuatopilot-
Description of the change
All the tests run with Qt4 and Qt5.
export QT_SELECT to either "qt4" or "qt5" and run
qmake autopilot.pro && make && make check && cd tests/autopilot && autopilot run libautopilot_qt
run "make distclean" when switching between qt versions.
Some tests fail because of the latest breakages with the libxpathselect update which mostly need to be fixed in python-autopilot.
PS Jenkins bot (ps-jenkins) wrote : | # |
- 50. By Michael Zanetti
-
fix typo in test function name
- 51. By Michael Zanetti
-
remove double empty lines
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:50
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Martin Mrazik (mrazik) wrote : | # |
Just for the reference here are some of the test failures:
1. libautopilot_
- this fails because it expect autopilot-phablet (rather the python-autopilot). This should pass once the phablet stuff is completely merged with lp:autopilot
2. libautopilot_
Should be fixed by:
https:/
3. libautopilot_
Should be workarounded/fixed by:
https:/
I'm a bit unsure about the packaging stuff (and the install file). Would be good, if Mathieu reviews those.
As far as I can see the unit tests are not executed during the build. How should they be executed? Right now it looks like they will never be in jenkins (no dh_auto_test). We should figure out how to run these.
I'm also getting a failure:
-------
Fontconfig warning: "/etc/fonts/
********* Start testing of tst_Introspection *********
Config: Using QTest library 4.8.4, Qt 4.8.4
PASS : tst_Introspecti
FAIL! : tst_Introspecti
Actual (resultList.
Expected (resultCount): 1
Loc: [tst_introspect
PASS : tst_Introspecti
PASS : tst_Introspecti
PASS : tst_Introspecti
Totals: 4 passed, 1 failed, 0 skipped
-------
Martin Mrazik (mrazik) wrote : | # |
The unit tests seem to work fine for qt5.
Günter Schwann (schwann) wrote : | # |
There are some empty line that I would remove (but might fit to the style in autopilot).
72 +
295 +
298 +
358 +
360 +
430 +
495 +
520 +
552 +
561 +
570 +
579 +
771 +
777 +
779 +
783 +
787 +
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:51
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 52. By Michael Zanetti
-
fix Qt4 unit tests
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:52
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Günter Schwann (schwann) wrote : | # |
Qt4 still fails after the update:
********* Start testing of tst_Introspection *********
Config: Using QTest library 4.8.4, Qt 4.8.4
PASS : tst_Introspecti
FAIL! : tst_Introspecti
Actual (resultList.
Expected (resultCount): 1
Loc: [tst_introspect
PASS : tst_Introspecti
PASS : tst_Introspecti
PASS : tst_Introspecti
Totals: 4 passed, 1 failed, 0 skipped
********* Finished testing of tst_Introspection *********
Michael Zanetti (mzanetti) wrote : | # |
> Qt4 still fails after the update:
Yeah... the problem is that they fail for you after the update (just like here) but for Martin its the other way round... Need to figure which Object is sitting _sometimes_ in between and using up the id.
- 53. By Michael Zanetti
-
make test a bit more flexible
- 54. By Michael Zanetti
-
get rid of some newlines
Michael Zanetti (mzanetti) wrote : | # |
> There are some empty line that I would remove (but might fit to the style in
> autopilot).
Removed the Qt ones. The Python ones are pep8 compiant.
Michael Zanetti (mzanetti) wrote : | # |
Tests should now pass with Qt4 and Qt5 on all systems. I couldn't reproduce Martins failure but discovered a empty QWidget in my object tree that eats one id. Could imagine this is related to theming (I'm using the oxygen style for QtWidget). I check now for such widgets in the hierarchy and increase the id number on the next check if present.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:53
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:54
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Martin Mrazik (mrazik) wrote : | # |
The unit tests are passing for me.
The only unanswered question is on when/how are these supposed to be executed.
Michael Zanetti (mzanetti) wrote : | # |
> The only unanswered question is on when/how are these supposed to be executed.
https:/
- 55. By Michael Zanetti
-
merge and fix trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:55
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Mathieu Trudel-Lapierre (cyphermox) wrote : | # |
Rockin'. Now the problem is that although you're adding tests, this constitutes a new package, and thus should need a freeze exception. Could you please file a bug about adding tests if there isn't one already, and I'll take care of the rest of the process?
Michael Zanetti (mzanetti) wrote : | # |
> Rockin'. Now the problem is that although you're adding tests, this
> constitutes a new package, and thus should need a freeze exception. Could you
> please file a bug about adding tests if there isn't one already, and I'll take
> care of the rest of the process?
Done. Bug number 1157697
Mathieu Trudel-Lapierre (cyphermox) wrote : | # |
Approve. You'll want to file this against lp:autopilot-qt/0.8 too if this is to land in Raring.
Preview Diff
1 | === modified file 'autopilot-qt.pro' |
2 | --- autopilot-qt.pro 2013-01-14 13:09:51 +0000 |
3 | +++ autopilot-qt.pro 2013-03-19 12:15:26 +0000 |
4 | @@ -5,4 +5,4 @@ |
5 | SUBDIRS += lib |
6 | } |
7 | |
8 | -SUBDIRS += driver |
9 | +SUBDIRS += driver tests |
10 | |
11 | === modified file 'debian/control' |
12 | --- debian/control 2013-03-18 22:44:43 +0000 |
13 | +++ debian/control 2013-03-19 12:15:26 +0000 |
14 | @@ -36,3 +36,15 @@ |
15 | Description: This project makes Qt applications introspectable by autopilot. |
16 | This allows autopilot to test any existing Qt4 or Qt5 application, |
17 | without having to rebuild the application under test. |
18 | + |
19 | +Package: libautopilot-qt-autopilot |
20 | +Section: libs |
21 | +Architecture: any |
22 | +Depends: ${shlibs:Depends}, |
23 | + ${misc:Depends}, |
24 | + python-support (>= 0.90), |
25 | + libautopilot-qt (= ${source:Version}), |
26 | + python-autopilot, |
27 | +Description: Autopilot tests for libautopilot-qt |
28 | + This contains sample Qt4 and Qt5 apps and autopilot tests |
29 | + to test libautopilot-qt. |
30 | |
31 | === added file 'debian/libautopilot-qt-autopilot.install' |
32 | --- debian/libautopilot-qt-autopilot.install 1970-01-01 00:00:00 +0000 |
33 | +++ debian/libautopilot-qt-autopilot.install 2013-03-19 12:15:26 +0000 |
34 | @@ -0,0 +1,3 @@ |
35 | +tests/autopilot/libautopilot_qt/* usr/lib/python2.7/dist-packages/libautopilot_qt/ |
36 | +tests/autopilot/testapp/qt*.qml usr/share/libautopilot-qt/ |
37 | +qt*/tests/autopilot/testapp/qt*testapp usr/share/libautopilot-qt/ |
38 | |
39 | === modified file 'debian/rules' |
40 | --- debian/rules 2013-03-18 22:44:43 +0000 |
41 | +++ debian/rules 2013-03-19 12:15:26 +0000 |
42 | @@ -24,6 +24,6 @@ |
43 | dh_install --fail-missing |
44 | |
45 | override_dh_auto_test: |
46 | - cd qt4 && xvfb-run make check |
47 | - cd qt5 && xvfb-run make check |
48 | + cd qt4 && xvfb-run -a make check |
49 | + cd qt5 && xvfb-run -a make check |
50 | |
51 | |
52 | === modified file 'driver/introspection.cpp' |
53 | --- driver/introspection.cpp 2012-12-19 13:05:22 +0000 |
54 | +++ driver/introspection.cpp 2013-03-19 12:15:26 +0000 |
55 | @@ -13,7 +13,7 @@ |
56 | #include <QDebug> |
57 | |
58 | #ifdef QT5_SUPPORT |
59 | - #include <QtGui/QGuiApplication> |
60 | + #include <QtWidgets/QApplication> |
61 | #include <QtWidgets/QGraphicsItem> |
62 | #include <QtWidgets/QGraphicsScene> |
63 | #include <QtWidgets/QGraphicsView> |
64 | @@ -63,8 +63,15 @@ |
65 | QList<QtNode::Ptr> GetNodesThatMatchQuery(QString const& query_string) |
66 | { |
67 | #ifdef QT5_SUPPORT |
68 | - std::shared_ptr<RootNode> root = std::make_shared<RootNode>(QGuiApplication::instance()); |
69 | - foreach (QWindow *widget, QGuiApplication::topLevelWindows()) |
70 | + std::shared_ptr<RootNode> root = std::make_shared<RootNode>(QApplication::instance()); |
71 | + |
72 | + // Add all QWidget top level widgets |
73 | + foreach (const QWidget *widget, QApplication::topLevelWidgets()) |
74 | + { |
75 | + root->AddChild((QObject*) widget); |
76 | + } |
77 | + // Add all QML top level Windows |
78 | + foreach (const QWindow *widget, QGuiApplication::topLevelWindows()) |
79 | { |
80 | root->AddChild((QObject*) widget); |
81 | } |
82 | @@ -127,6 +134,15 @@ |
83 | continue; |
84 | object_properties[prop.name()] = object_property; |
85 | } |
86 | + foreach(const QByteArray &dynamicPropertyName, obj->dynamicPropertyNames()) { |
87 | + QVariant dynamicPropertyValue = obj->property(dynamicPropertyName); |
88 | + |
89 | + QVariant object_property = PackProperty(dynamicPropertyValue); |
90 | + if (! object_property.isValid()) |
91 | + continue; |
92 | + object_properties[dynamicPropertyName] = object_property; |
93 | + } |
94 | + |
95 | meta = meta->superClass(); |
96 | } while(meta); |
97 | |
98 | @@ -260,8 +276,9 @@ |
99 | QStringList child_names; |
100 | foreach (QObject *child, obj->children()) |
101 | { |
102 | - if (child->parent() == obj) |
103 | + if (child->parent() == obj) { |
104 | child_names.append(GetNodeName(child)); |
105 | + } |
106 | } |
107 | return child_names; |
108 | } |
109 | |
110 | === removed directory 'test' |
111 | === removed file 'test/main.cpp' |
112 | --- test/main.cpp 2012-07-10 21:03:34 +0000 |
113 | +++ test/main.cpp 1970-01-01 00:00:00 +0000 |
114 | @@ -1,17 +0,0 @@ |
115 | -/* |
116 | -Copyright 2012 Canonical |
117 | - |
118 | -This program is free software: you can redistribute it and/or modify it |
119 | -under the terms of the GNU General Public License version 3, as published |
120 | -by the Free Software Foundation. |
121 | -*/ |
122 | - |
123 | -#include <QTest> |
124 | - |
125 | -#include "test_dbus_introspection.h" |
126 | - |
127 | -int main(int argc, char **argv) |
128 | -{ |
129 | - TestDBusIntrospection tests; |
130 | - return QTest::qExec(&tests, argc, argv); |
131 | -} |
132 | |
133 | === removed file 'test/test.pro' |
134 | --- test/test.pro 2012-07-10 21:03:34 +0000 |
135 | +++ test/test.pro 1970-01-01 00:00:00 +0000 |
136 | @@ -1,11 +0,0 @@ |
137 | -TEMPLATE=app |
138 | -TARGET=test_runner |
139 | -DESTDIR=.. |
140 | -QT=core testlib dbus |
141 | -QMAKE_CXXFLAGS += -std=c++0x |
142 | -INCLUDEPATH += ../lib |
143 | -LIBS += -L.. -lqttestability |
144 | -SOURCES=main.cpp \ |
145 | - test_dbus_introspection.cpp |
146 | - |
147 | -HEADERS = test_dbus_introspection.h |
148 | |
149 | === removed file 'test/test_dbus_introspection.cpp' |
150 | --- test/test_dbus_introspection.cpp 2012-07-10 21:03:34 +0000 |
151 | +++ test/test_dbus_introspection.cpp 1970-01-01 00:00:00 +0000 |
152 | @@ -1,50 +0,0 @@ |
153 | -/* |
154 | -Copyright 2012 Canonical |
155 | - |
156 | -This program is free software: you can redistribute it and/or modify it |
157 | -under the terms of the GNU General Public License version 3, as published |
158 | -by the Free Software Foundation. |
159 | -*/ |
160 | - |
161 | -#include "test_dbus_introspection.h" |
162 | -#include "introspection.h" |
163 | - |
164 | -#include <QTest> |
165 | -#include <QDebug> |
166 | -#include <QDBusArgument> |
167 | - |
168 | - |
169 | -/// A simple QObject with no properties must return an empty map. |
170 | -void TestDBusIntrospection::test_simple_object() |
171 | -{ |
172 | - TestEmptyObject obj; |
173 | - QVariantMap state = Introspect(&obj); |
174 | - QVERIFY(state.count() == 0); |
175 | -} |
176 | - |
177 | -void TestDBusIntrospection::test_string_props() |
178 | -{ |
179 | - TestObject obj; |
180 | - QVariantMap state = Introspect(&obj); |
181 | - QVERIFY(state.count() >= 1); |
182 | - QVERIFY(state.count("stringProp") == 1); |
183 | - QVERIFY(state.value("stringProp") == ""); |
184 | - obj.setStringProp("FooBar"); |
185 | - state = Introspect(&obj); |
186 | - QVERIFY(state.count("stringProp") == 1); |
187 | - QVERIFY(state.value("stringProp") == "FooBar"); |
188 | -} |
189 | - |
190 | -void TestDBusIntrospection::test_children() |
191 | -{ |
192 | - QVariantMap state; |
193 | - TestObject obj; |
194 | - { |
195 | - TestEmptyObject obj2(&obj); |
196 | - state = Introspect(&obj); |
197 | - } |
198 | - qDebug() << state; |
199 | - QVERIFY(state.count("Children") == 1); |
200 | - |
201 | - |
202 | -} |
203 | |
204 | === removed file 'test/test_dbus_introspection.h' |
205 | --- test/test_dbus_introspection.h 2012-07-10 21:03:34 +0000 |
206 | +++ test/test_dbus_introspection.h 1970-01-01 00:00:00 +0000 |
207 | @@ -1,44 +0,0 @@ |
208 | -/* |
209 | -Copyright 2012 Canonical |
210 | - |
211 | -This program is free software: you can redistribute it and/or modify it |
212 | -under the terms of the GNU General Public License version 3, as published |
213 | -by the Free Software Foundation. |
214 | -*/ |
215 | - |
216 | -#ifndef TEST_DBUS_INTROSPECTION_H |
217 | -#define TEST_DBUS_INTROSPECTION_H |
218 | - |
219 | -#include <QObject> |
220 | - |
221 | -class TestDBusIntrospection: public QObject |
222 | -{ |
223 | - Q_OBJECT |
224 | -private slots: |
225 | - void test_simple_object(); |
226 | - void test_string_props(); |
227 | - void test_children(); |
228 | -}; |
229 | - |
230 | -class TestEmptyObject: public QObject |
231 | -{ |
232 | - Q_OBJECT |
233 | -public: |
234 | - TestEmptyObject(QObject *p=nullptr) |
235 | - : QObject(p) {} |
236 | -}; |
237 | - |
238 | -class TestObject: public QObject |
239 | -{ |
240 | - Q_OBJECT |
241 | - Q_PROPERTY(QString stringProp READ stringProp WRITE setStringProp) |
242 | -public: |
243 | - |
244 | - QString stringProp() const { return string_prop_;} |
245 | - void setStringProp(const QString& p) { string_prop_ = p;} |
246 | - |
247 | -private: |
248 | - QString string_prop_; |
249 | -}; |
250 | - |
251 | -#endif |
252 | |
253 | === added directory 'tests' |
254 | === added directory 'tests/autopilot' |
255 | === added file 'tests/autopilot/autopilot.pro' |
256 | --- tests/autopilot/autopilot.pro 1970-01-01 00:00:00 +0000 |
257 | +++ tests/autopilot/autopilot.pro 2013-03-19 12:15:26 +0000 |
258 | @@ -0,0 +1,2 @@ |
259 | +TEMPLATE = subdirs |
260 | +SUBDIRS += testapp |
261 | |
262 | === added directory 'tests/autopilot/libautopilot_qt' |
263 | === added file 'tests/autopilot/libautopilot_qt/__init__.py' |
264 | --- tests/autopilot/libautopilot_qt/__init__.py 1970-01-01 00:00:00 +0000 |
265 | +++ tests/autopilot/libautopilot_qt/__init__.py 2013-03-19 12:15:26 +0000 |
266 | @@ -0,0 +1,8 @@ |
267 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
268 | +# Copyright 2013 Canonical |
269 | +# |
270 | +# This program is free software: you can redistribute it and/or modify it |
271 | +# under the terms of the GNU General Public License version 3, as published |
272 | +# by the Free Software Foundation. |
273 | + |
274 | +"""libautopilot-qt autopilot tests - top level package.""" |
275 | |
276 | === added directory 'tests/autopilot/libautopilot_qt/emulators' |
277 | === added file 'tests/autopilot/libautopilot_qt/emulators/__init__.py' |
278 | --- tests/autopilot/libautopilot_qt/emulators/__init__.py 1970-01-01 00:00:00 +0000 |
279 | +++ tests/autopilot/libautopilot_qt/emulators/__init__.py 2013-03-19 12:15:26 +0000 |
280 | @@ -0,0 +1,6 @@ |
281 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
282 | +# Copyright 2013 Canonical |
283 | +# |
284 | +# This program is free software: you can redistribute it and/or modify it |
285 | +# under the terms of the GNU General Public License version 3, as published |
286 | +# by the Free Software Foundation. |
287 | |
288 | === added file 'tests/autopilot/libautopilot_qt/emulators/main_window_qt4.py' |
289 | --- tests/autopilot/libautopilot_qt/emulators/main_window_qt4.py 1970-01-01 00:00:00 +0000 |
290 | +++ tests/autopilot/libautopilot_qt/emulators/main_window_qt4.py 2013-03-19 12:15:26 +0000 |
291 | @@ -0,0 +1,57 @@ |
292 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
293 | +# Copyright 2013 Canonical |
294 | +# |
295 | +# This program is free software: you can redistribute it and/or modify it |
296 | +# under the terms of the GNU General Public License version 3, as published |
297 | +# by the Free Software Foundation. |
298 | + |
299 | +import logging |
300 | +logger = logging.getLogger(__name__) |
301 | + |
302 | + |
303 | +class MainWindowQt4(object): |
304 | + |
305 | + def __init__(self, app): |
306 | + self.app = app |
307 | + |
308 | + def get_qml_view(self): |
309 | + qml_view = self.app.select_single("QDeclarativeView") |
310 | + if qml_view is None: |
311 | + logger.error("*** select_single(\"QDeclarativeView\") failed ***") |
312 | + return qml_view |
313 | + |
314 | + def get_root_item(self): |
315 | + root_item = self.app.select_single("QDeclarativeItem", objectName="rootItem") |
316 | + if root_item is None: |
317 | + logger.error("*** select_single(\"QDeclarativeItem\", objectName=\rootItem\") failed ***") |
318 | + return root_item |
319 | + |
320 | + def get_test_item(self): |
321 | + test_item = self.app.select_single("QDeclarativeItem", objectName="testItem") |
322 | + if test_item is None: |
323 | + logger.error("*** select_single(\"QDeclarativeItem\", objectName=\"testItem\") failed ***") |
324 | + return test_item |
325 | + |
326 | + def get_test_item_by_objectname(self): |
327 | + test_item = self.app.select_single(objectName="testItem") |
328 | + if test_item is None: |
329 | + logger.error("*** select_single(objectName=\"testItem\") failed ***") |
330 | + return test_item |
331 | + |
332 | + def get_test_rectangle(self): |
333 | + rectangle = self.app.select_single("QDeclarativeRectangle") |
334 | + if rectangle is None: |
335 | + logger.error("*** select_single(\"QDeclarativeRectangle\") failed ***") |
336 | + return rectangle |
337 | + |
338 | + def get_test_rectangle_by_child_search(self): |
339 | + rectangle = self.get_root_item().get_children_by_type("QDeclarativeRectangle")[0] |
340 | + if rectangle is None: |
341 | + logger.error("*** get_children_by_type(\"QDeclarativeRectangle\")[0] failed ***") |
342 | + return rectangle |
343 | + |
344 | + def get_test_mousearea(self): |
345 | + mousearea = self.app.select_single("QDeclarativeMouseArea") |
346 | + if mousearea is None: |
347 | + logger.error("*** select_single(\"QDeclarativeMouseArea\") failed ***") |
348 | + return mousearea |
349 | |
350 | === added file 'tests/autopilot/libautopilot_qt/emulators/main_window_qt5.py' |
351 | --- tests/autopilot/libautopilot_qt/emulators/main_window_qt5.py 1970-01-01 00:00:00 +0000 |
352 | +++ tests/autopilot/libautopilot_qt/emulators/main_window_qt5.py 2013-03-19 12:15:26 +0000 |
353 | @@ -0,0 +1,57 @@ |
354 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
355 | +# Copyright 2013 Canonical |
356 | +# |
357 | +# This program is free software: you can redistribute it and/or modify it |
358 | +# under the terms of the GNU General Public License version 3, as published |
359 | +# by the Free Software Foundation. |
360 | + |
361 | +import logging |
362 | +logger = logging.getLogger(__name__) |
363 | + |
364 | + |
365 | +class MainWindowQt5(object): |
366 | + |
367 | + def __init__(self, app): |
368 | + self.app = app |
369 | + |
370 | + def get_qml_view(self): |
371 | + qml_view = self.app.select_single("QQuickView") |
372 | + if qml_view is None: |
373 | + logger.error("*** select_single(\"QQuickView\") failed ***") |
374 | + return qml_view |
375 | + |
376 | + def get_root_item(self): |
377 | + root_item = self.app.select_single("QQuickItem", objectName="rootItem") |
378 | + if root_item is None: |
379 | + logger.error("*** select_single(\"QQuickItem\", objectName=\rootItem\") failed ***") |
380 | + return root_item |
381 | + |
382 | + def get_test_item(self): |
383 | + test_item = self.app.select_single("QQuickItem", objectName="testItem") |
384 | + if test_item is None: |
385 | + logger.error("*** select_single(\"QQuickItem\", objectName=\"testItem\") failed ***") |
386 | + return test_item |
387 | + |
388 | + def get_test_item_by_objectname(self): |
389 | + test_item = self.app.select_single(objectName="testItem") |
390 | + if test_item is None: |
391 | + logger.error("*** select_single(objectName=\"testItem\") failed ***") |
392 | + return test_item |
393 | + |
394 | + def get_test_rectangle(self): |
395 | + rectangle = self.app.select_single("QQuickRectangle") |
396 | + if rectangle is None: |
397 | + logger.error("*** select_single(\"QQuickRectangle\") failed ***") |
398 | + return rectangle |
399 | + |
400 | + def get_test_rectangle_by_child_search(self): |
401 | + rectangle = self.get_root_item().get_children_by_type("QQuickRectangle")[0] |
402 | + if rectangle is None: |
403 | + logger.error("*** get_children_by_type(\"QQuickRectangle\")[0] failed ***") |
404 | + return rectangle |
405 | + |
406 | + def get_test_mousearea(self): |
407 | + mousearea = self.app.select_single("QQuickMouseArea") |
408 | + if mousearea is None: |
409 | + logger.error("*** select_single(\"QQuickMouseArea\") failed ***") |
410 | + return mousearea |
411 | |
412 | === added directory 'tests/autopilot/libautopilot_qt/tests' |
413 | === added file 'tests/autopilot/libautopilot_qt/tests/__init__.py' |
414 | --- tests/autopilot/libautopilot_qt/tests/__init__.py 1970-01-01 00:00:00 +0000 |
415 | +++ tests/autopilot/libautopilot_qt/tests/__init__.py 2013-03-19 12:15:26 +0000 |
416 | @@ -0,0 +1,66 @@ |
417 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
418 | +# Copyright 2013 Canonical |
419 | +# |
420 | +# This program is free software: you can redistribute it and/or modify it |
421 | +# under the terms of the GNU General Public License version 3, as published |
422 | +# by the Free Software Foundation. |
423 | + |
424 | +"""libautopilot-qt autopilot tests.""" |
425 | + |
426 | +import os |
427 | + |
428 | +from autopilot.introspection.qt import QtIntrospectionTestMixin |
429 | +from autopilot.testcase import AutopilotTestCase |
430 | + |
431 | +from libautopilot_qt.emulators.main_window_qt4 import MainWindowQt4 |
432 | +from libautopilot_qt.emulators.main_window_qt5 import MainWindowQt5 |
433 | + |
434 | +import logging |
435 | +logger = logging.getLogger(__name__) |
436 | + |
437 | + |
438 | +class AutopilotQtTestCase(AutopilotTestCase, QtIntrospectionTestMixin): |
439 | + qt_version = 0 |
440 | + |
441 | + def setUp(self, *app_args): |
442 | + super(AutopilotQtTestCase, self).setUp() |
443 | + self.launch_test_app(app_args) |
444 | + |
445 | + def launch_test_app(self, *app_args): |
446 | + # Lets assume we are installed system wide if this file is somewhere in /usr |
447 | + if os.path.realpath(__file__).startswith("/usr/"): |
448 | + path = "/usr/share/libautopilot-qt/" |
449 | + else: |
450 | + # Load library from local build dir |
451 | + os.environ['LD_LIBRARY_PATH'] = "../../" |
452 | + path = "testapp/" |
453 | + |
454 | + app_name_qt4 = path + "qt4testapp" |
455 | + app_name_qt5 = path + "qt5testapp" |
456 | + |
457 | + qt_select = os.environ.get('QT_SELECT') |
458 | + |
459 | + if os.path.isfile(app_name_qt5) and not qt_select == "qt4": |
460 | + logger.info("Found Qt5 test app") |
461 | + app_name = app_name_qt5 |
462 | + qml_file = path + "qt5.qml" |
463 | + self.qt_version = 5 |
464 | + elif os.path.isfile(app_name_qt4) and not qt_select == "qt5": |
465 | + logger.info("Found Qt4 test app") |
466 | + app_name = app_name_qt4 |
467 | + qml_file = path + "qt4.qml" |
468 | + self.qt_version = 4 |
469 | + else: |
470 | + logger.error("Could not find test app.") |
471 | + |
472 | + args = [app_name] |
473 | + args.extend(*app_args) |
474 | + args.append(qml_file) |
475 | + self.app = self.launch_test_application(*args) |
476 | + |
477 | + @property |
478 | + def main_window(self): |
479 | + if self.qt_version == 4: |
480 | + return MainWindowQt4(self.app) |
481 | + if self.qt_version == 5: |
482 | + return MainWindowQt5(self.app) |
483 | |
484 | === added file 'tests/autopilot/libautopilot_qt/tests/test_main.py' |
485 | --- tests/autopilot/libautopilot_qt/tests/test_main.py 1970-01-01 00:00:00 +0000 |
486 | +++ tests/autopilot/libautopilot_qt/tests/test_main.py 2013-03-19 12:15:26 +0000 |
487 | @@ -0,0 +1,103 @@ |
488 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
489 | +# Copyright 2013 Canonical |
490 | +# |
491 | +# This program is free software: you can redistribute it and/or modify it |
492 | +# under the terms of the GNU General Public License version 3, as published |
493 | +# by the Free Software Foundation. |
494 | + |
495 | +from __future__ import absolute_import |
496 | + |
497 | +from testtools.matchers import Equals, NotEquals |
498 | +from autopilot.matchers import Eventually |
499 | + |
500 | +from libautopilot_qt.tests import AutopilotQtTestCase |
501 | + |
502 | + |
503 | +class TestQueries(AutopilotQtTestCase): |
504 | + |
505 | + def setUp(self): |
506 | + super(TestQueries, self).setUp() |
507 | + self.assertThat(self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
508 | + |
509 | + def tearDown(self): |
510 | + super(TestQueries, self).tearDown() |
511 | + |
512 | + def test_find_select_single(self): |
513 | + root_item = self.main_window.get_root_item() |
514 | + self.assertThat(root_item, NotEquals(None)) |
515 | + |
516 | + def test_find_by_objectname(self): |
517 | + test_item = self.main_window.get_test_item_by_objectname() |
518 | + self.assertThat(test_item, NotEquals(None)) |
519 | + |
520 | + def test_find_by_child_search(self): |
521 | + rectangle = self.main_window.get_test_rectangle_by_child_search() |
522 | + self.assertThat(rectangle, NotEquals(None)) |
523 | + |
524 | + |
525 | +class TestProperties(AutopilotQtTestCase): |
526 | + |
527 | + def setUp(self): |
528 | + super(TestProperties, self).setUp() |
529 | + self.assertThat(self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
530 | + |
531 | + def tearDown(self): |
532 | + super(TestProperties, self).tearDown() |
533 | + |
534 | + def test_basic_properties(self): |
535 | + test_item = self.main_window.get_test_item() |
536 | + |
537 | + self.assertThat(test_item.stringProperty, Equals("Testing rocks, debugging sucks!")) |
538 | + self.assertThat(test_item.intProperty, Equals(42)) |
539 | + self.assertThat(test_item.boolProperty, Equals(False)) |
540 | + self.assertThat(test_item.realProperty, Equals(0.42)) |
541 | + self.assertThat(test_item.doubleProperty, Equals(0.42)) |
542 | + |
543 | + rectangle = self.main_window.get_test_rectangle() |
544 | + self.assertThat(rectangle.color, Equals([0, 0, 255, 255])) |
545 | + |
546 | + def test_mouse_interaction(self): |
547 | + rectangle = self.main_window.get_test_rectangle() |
548 | + self.assertThat(rectangle.color, Equals([0, 0, 255, 255])) |
549 | + |
550 | + mousearea = self.main_window.get_test_mousearea() |
551 | + self.pointing_device.move_to_object(mousearea) |
552 | + self.pointing_device.click() |
553 | + |
554 | + self.assertThat(rectangle.color, Eventually(Equals([255, 0, 0, 255]))) |
555 | + |
556 | + |
557 | +class TestAppNameQtDefault(AutopilotQtTestCase): |
558 | + |
559 | + def setUp(self): |
560 | + super(TestAppNameQtDefault, self).setUp("--appname", "untitled1") |
561 | + |
562 | + def test_connection(self): |
563 | + self.assertThat(self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
564 | + |
565 | + |
566 | +class TestAppNameTech(AutopilotQtTestCase): |
567 | + |
568 | + def setUp(self): |
569 | + super(TestAppNameTech, self).setUp("--appname", "qt-test-app") |
570 | + |
571 | + def test_connection(self): |
572 | + self.assertThat(self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
573 | + |
574 | + |
575 | +class TestAppNameUserfriendly(AutopilotQtTestCase): |
576 | + |
577 | + def setUp(self): |
578 | + super(TestAppNameUserfriendly, self).setUp("--appname", "Qt Test App") |
579 | + |
580 | + def test_connection(self): |
581 | + self.assertThat(self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
582 | + |
583 | + |
584 | +class TestAppNameFqdn(AutopilotQtTestCase): |
585 | + |
586 | + def setUp(self): |
587 | + super(TestAppNameFqdn, self).setUp("--appname", "com.ubuntu.qttestapp") |
588 | + |
589 | + def test_connection(self): |
590 | + self.assertThat(self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
591 | |
592 | === added directory 'tests/autopilot/testapp' |
593 | === added file 'tests/autopilot/testapp/qt4.qml' |
594 | --- tests/autopilot/testapp/qt4.qml 1970-01-01 00:00:00 +0000 |
595 | +++ tests/autopilot/testapp/qt4.qml 2013-03-19 12:15:26 +0000 |
596 | @@ -0,0 +1,55 @@ |
597 | +/* |
598 | + * Copyright (C) 2013 Canonical, Ltd. |
599 | + * |
600 | + * Authors: |
601 | + * Michael Zanetti <michael.zanetti@canonical.com> |
602 | + * |
603 | + * This program is free software; you can redistribute it and/or modify |
604 | + * it under the terms of the GNU General Public License as published by |
605 | + * the Free Software Foundation; version 3. |
606 | + * |
607 | + * This program is distributed in the hope that it will be useful, |
608 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
609 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
610 | + * GNU General Public License for more details. |
611 | + * |
612 | + * You should have received a copy of the GNU General Public License |
613 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
614 | + * |
615 | + */ |
616 | + |
617 | +import QtQuick 1.0 |
618 | + |
619 | +Item { |
620 | + id: root |
621 | + objectName: "rootItem" |
622 | + width: 500 |
623 | + height: 500 |
624 | + |
625 | + Item { |
626 | + id: testItem |
627 | + objectName: "testItem" |
628 | + |
629 | + property string stringProperty: "Testing rocks, debugging sucks!" |
630 | + property int intProperty: 42 |
631 | + property bool boolProperty: false |
632 | + property real realProperty: 0.42 |
633 | + property double doubleProperty: 0.42 |
634 | + } |
635 | + |
636 | + Rectangle { |
637 | + id: rect |
638 | + objectName: "testRectangle" |
639 | + anchors.fill: parent |
640 | + color: "blue" |
641 | + } |
642 | + |
643 | + MouseArea { |
644 | + objectName: "testMouseArea" |
645 | + width: root.width / 2 |
646 | + height: root.height / 2 |
647 | + anchors.centerIn: root |
648 | + |
649 | + onClicked: rect.color = "red" |
650 | + } |
651 | +} |
652 | |
653 | === added file 'tests/autopilot/testapp/qt5.qml' |
654 | --- tests/autopilot/testapp/qt5.qml 1970-01-01 00:00:00 +0000 |
655 | +++ tests/autopilot/testapp/qt5.qml 2013-03-19 12:15:26 +0000 |
656 | @@ -0,0 +1,55 @@ |
657 | +/* |
658 | + * Copyright (C) 2013 Canonical, Ltd. |
659 | + * |
660 | + * Authors: |
661 | + * Michael Zanetti <michael.zanetti@canonical.com> |
662 | + * |
663 | + * This program is free software; you can redistribute it and/or modify |
664 | + * it under the terms of the GNU General Public License as published by |
665 | + * the Free Software Foundation; version 3. |
666 | + * |
667 | + * This program is distributed in the hope that it will be useful, |
668 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
669 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
670 | + * GNU General Public License for more details. |
671 | + * |
672 | + * You should have received a copy of the GNU General Public License |
673 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
674 | + * |
675 | + */ |
676 | + |
677 | +import QtQuick 2.0 |
678 | + |
679 | +Item { |
680 | + id: root |
681 | + objectName: "rootItem" |
682 | + width: 500 |
683 | + height: 500 |
684 | + |
685 | + Item { |
686 | + id: testItem |
687 | + objectName: "testItem" |
688 | + |
689 | + property string stringProperty: "Testing rocks, debugging sucks!" |
690 | + property int intProperty: 42 |
691 | + property bool boolProperty: false |
692 | + property real realProperty: 0.42 |
693 | + property double doubleProperty: 0.42 |
694 | + } |
695 | + |
696 | + Rectangle { |
697 | + id: rect |
698 | + objectName: "testRectangle" |
699 | + anchors.fill: parent |
700 | + color: "blue" |
701 | + } |
702 | + |
703 | + MouseArea { |
704 | + objectName: "testMouseArea" |
705 | + width: root.width / 2 |
706 | + height: root.height / 2 |
707 | + anchors.centerIn: root |
708 | + |
709 | + onClicked: rect.color = "red" |
710 | + } |
711 | +} |
712 | |
713 | === added file 'tests/autopilot/testapp/testapp.cpp' |
714 | --- tests/autopilot/testapp/testapp.cpp 1970-01-01 00:00:00 +0000 |
715 | +++ tests/autopilot/testapp/testapp.cpp 2013-03-19 12:15:26 +0000 |
716 | @@ -0,0 +1,52 @@ |
717 | +/* |
718 | + * Copyright (C) 2013 Canonical, Ltd. |
719 | + * |
720 | + * Authors: |
721 | + * Michael Zanetti <michael.zanetti@canonical.com> |
722 | + * |
723 | + * This program is free software; you can redistribute it and/or modify |
724 | + * it under the terms of the GNU General Public License as published by |
725 | + * the Free Software Foundation; version 3. |
726 | + * |
727 | + * This program is distributed in the hope that it will be useful, |
728 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
729 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
730 | + * GNU General Public License for more details. |
731 | + * |
732 | + * You should have received a copy of the GNU General Public License |
733 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
734 | + * |
735 | + */ |
736 | + |
737 | +#include <QApplication> |
738 | +#include <QStringList> |
739 | + |
740 | +#ifdef QT5_SUPPORT |
741 | +#include <QQuickView> |
742 | +#else |
743 | +#include <QDeclarativeView> |
744 | +#endif |
745 | + |
746 | +int main(int argc, char *argv[]) |
747 | +{ |
748 | + QApplication app(argc, argv); |
749 | + |
750 | + QStringList args = QApplication::arguments(); |
751 | + QString sourceFile = args.last(); |
752 | + |
753 | + int appNameIndex = args.indexOf("--appname"); |
754 | + if(appNameIndex > 0 && args.count() >= appNameIndex) { |
755 | + app.setApplicationName(args.at(appNameIndex+1)); |
756 | + } |
757 | + |
758 | +#ifdef QT5_SUPPORT |
759 | + QQuickView view; |
760 | +#else |
761 | + QDeclarativeView view; |
762 | +#endif |
763 | + |
764 | + view.setSource(QUrl(sourceFile)); |
765 | + |
766 | + view.show(); |
767 | + app.exec(); |
768 | +} |
769 | |
770 | === added file 'tests/autopilot/testapp/testapp.pro' |
771 | --- tests/autopilot/testapp/testapp.pro 1970-01-01 00:00:00 +0000 |
772 | +++ tests/autopilot/testapp/testapp.pro 2013-03-19 12:15:26 +0000 |
773 | @@ -0,0 +1,22 @@ |
774 | +TEMPLATE = app |
775 | + |
776 | +contains(QT_VERSION, ^5\\..\\..*) { |
777 | + TARGET = qt5testapp |
778 | + QT += widgets quick |
779 | + qmlfile.file = qt5.qml |
780 | + |
781 | + DEFINES += QT5_SUPPORT |
782 | +} else { |
783 | + TARGET = qt4testapp |
784 | + QT += declarative |
785 | + qmlfile.file = qt4.qml |
786 | +} |
787 | + |
788 | +SOURCES += testapp.cpp |
789 | + |
790 | +qmlfile.path=/usr/share/libautopilot-qt/ |
791 | + |
792 | +target.path=/usr/share/libautopilot-qt/ |
793 | +target.file = $TARGET |
794 | + |
795 | +INSTALLS += target qmlfile |
796 | |
797 | === added file 'tests/tests.pro' |
798 | --- tests/tests.pro 1970-01-01 00:00:00 +0000 |
799 | +++ tests/tests.pro 2013-03-19 12:15:26 +0000 |
800 | @@ -0,0 +1,2 @@ |
801 | +TEMPLATE = subdirs |
802 | +SUBDIRS += autopilot unittests |
803 | |
804 | === added directory 'tests/unittests' |
805 | === added file 'tests/unittests/tst_introspection.cpp' |
806 | --- tests/unittests/tst_introspection.cpp 1970-01-01 00:00:00 +0000 |
807 | +++ tests/unittests/tst_introspection.cpp 2013-03-19 12:15:26 +0000 |
808 | @@ -0,0 +1,223 @@ |
809 | +/* |
810 | + * Copyright (C) 2013 Canonical, Ltd. |
811 | + * |
812 | + * Authors: |
813 | + * Michael Zanetti <michael.zanetti@canonical.com> |
814 | + * |
815 | + * This program is free software; you can redistribute it and/or modify |
816 | + * it under the terms of the GNU General Public License as published by |
817 | + * the Free Software Foundation; version 3. |
818 | + * |
819 | + * This program is distributed in the hope that it will be useful, |
820 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
821 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
822 | + * GNU General Public License for more details. |
823 | + * |
824 | + * You should have received a copy of the GNU General Public License |
825 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
826 | + * |
827 | + */ |
828 | + |
829 | +#include <QStringList> |
830 | +#include <QtTest> |
831 | +#include <QMainWindow> |
832 | +#include <QDebug> |
833 | +#include <QGridLayout> |
834 | +#include <QPushButton> |
835 | + |
836 | +#include "introspection.h" |
837 | + |
838 | +QVariant IntrospectNode(QObject* obj); |
839 | + |
840 | +class tst_Introspection : public QObject |
841 | +{ |
842 | + Q_OBJECT |
843 | + |
844 | +private slots: |
845 | + void initTestCase(); |
846 | + void cleanupTestCase(); |
847 | + |
848 | + void test_introspect_data(); |
849 | + void test_introspect(); |
850 | + |
851 | + void test_application_names_data(); |
852 | + void test_application_names(); |
853 | + |
854 | + void test_properties_data(); |
855 | + void test_properties(); |
856 | + |
857 | +private: |
858 | + QMainWindow *m_object; |
859 | +}; |
860 | + |
861 | + |
862 | +void tst_Introspection::initTestCase() |
863 | +{ |
864 | + QApplication::setApplicationName("tst_introspection"); |
865 | + |
866 | + m_object = new QMainWindow(); |
867 | + QWidget *centralWidget = new QWidget(); |
868 | + centralWidget->setObjectName("centralTestWidget"); |
869 | + m_object->setCentralWidget(centralWidget); |
870 | + |
871 | + QGridLayout *layout = new QGridLayout(); |
872 | + layout->setObjectName("myTestLayout"); |
873 | + centralWidget->setLayout(layout); |
874 | + |
875 | + QPushButton *button = new QPushButton("MyButton1"); |
876 | + button->setObjectName("myButton1"); |
877 | + layout->addWidget(button); |
878 | + |
879 | + button = new QPushButton("MyButton2"); |
880 | + button->setObjectName("myButton2"); |
881 | + layout->addWidget(button); |
882 | + |
883 | + m_object->setObjectName("testWindow"); |
884 | + m_object->setProperty("dynamicTestProperty", "testValue"); |
885 | + m_object->setProperty("myUInt", QVariant(quint8(5))); |
886 | + m_object->setProperty("myStringList", QVariant(QStringList() << "string1" << "string2" << "string3")); |
887 | + m_object->setProperty("myColor", QColor("red")); |
888 | + m_object->setProperty("myByteArray", QByteArray("0xDEADBEEF")); |
889 | + m_object->setProperty("myUrl", QUrl("http://www.ubuntu.com")); |
890 | + m_object->setMaximumSize(1234, 4321); |
891 | + m_object->resize(123, 321); |
892 | + m_object->move(333, 444); |
893 | + m_object->setVisible(false); |
894 | + m_object->setWindowOpacity(0.12345); |
895 | + |
896 | + m_object->show(); |
897 | +} |
898 | + |
899 | +void tst_Introspection::cleanupTestCase() |
900 | +{ |
901 | + m_object->close(); |
902 | + delete m_object; |
903 | +} |
904 | + |
905 | +void tst_Introspection::test_introspect_data() |
906 | +{ |
907 | + // some query |
908 | + QTest::addColumn<QString>("xpath"); |
909 | + |
910 | + // number of expected results |
911 | + QTest::addColumn<int>("resultCount"); |
912 | + |
913 | + // first result object type. Empty string if 0 results expected |
914 | + QTest::addColumn<QString>("firstResultType"); |
915 | + |
916 | + // Choose a property from the first result object to be compared, empty QString/QVariant if 0 results expected |
917 | + QTest::addColumn<QString>("firstResultPropertyName"); |
918 | + QTest::addColumn<QVariant>("firstResultPropertyValue"); |
919 | + |
920 | +#ifdef QT5_SUPPORT |
921 | + QTest::newRow("/") << "/" << 1 << "tst_introspection" << "Children" << QVariant(QStringList() << "QMainWindow" << "QWidgetWindow"); |
922 | + QTest::newRow("//QWidget[id=6]") << "//QWidget[id=6]" << 1 << "QWidget" << "objectName" << QVariant("centralTestWidget"); |
923 | + QTest::newRow("//QPushButton[id=9]") << "//QPushButton[id=9]" << 1 << "QPushButton" << "objectName" << QVariant("myButton2"); |
924 | +#else |
925 | + QTest::newRow("/") << "/" << 1 << "tst_introspection" << "Children" << QVariant(QStringList() << "QMainWindow"); |
926 | + QTest::newRow("//QWidget[id=5]") << "//QWidget[id=5]" << 1 << "QWidget" << "objectName" << QVariant("centralTestWidget"); |
927 | + |
928 | + // Depending on the environment, Qt4 could add a second QWidget at position 6. That moves other items down by one. |
929 | + if (Introspect("//QWidget[id=6]").count() > 0) { |
930 | + QTest::newRow("//QPushButton[id=9]") << "//QPushButton[id=9]" << 1 << "QPushButton" << "objectName" << QVariant("myButton2"); |
931 | + } else { |
932 | + QTest::newRow("//QPushButton[id=8]") << "//QPushButton[id=8]" << 1 << "QPushButton" << "objectName" << QVariant("myButton2"); |
933 | + } |
934 | +#endif |
935 | + |
936 | + QTest::newRow("//GridLayout") << "//QGridLayout" << 1 << "QGridLayout" << "objectName" << QVariant("myTestLayout"); |
937 | + QTest::newRow("//QPushButton") << "//QPushButton" << 2 << "QPushButton" << "objectName" << QVariant("myButton1"); |
938 | + QTest::newRow("//QWidget/*") << "//QWidget/*" << 5 << "QGridLayout" << "objectName" << QVariant("myTestLayout"); |
939 | + QTest::newRow("broken query") << "broken query" << 0 << QString() << QString() << QVariant(); |
940 | +} |
941 | + |
942 | +void tst_Introspection::test_introspect() |
943 | +{ |
944 | + QFETCH(QString, xpath); |
945 | + QFETCH(int, resultCount); |
946 | + QFETCH(QString, firstResultType); |
947 | + QFETCH(QString, firstResultPropertyName); |
948 | + QFETCH(QVariant, firstResultPropertyValue); |
949 | + |
950 | + QList<QVariant> resultList = Introspect(xpath); |
951 | + |
952 | + QCOMPARE(resultList.count(), resultCount); |
953 | + |
954 | + if (resultCount > 0) { |
955 | + QVariant firstResult = resultList.first(); |
956 | + QVariantMap firstResultProperties = firstResult.toList().last().toMap(); |
957 | + |
958 | + QCOMPARE(firstResult.toList().first().toString(), firstResultType); |
959 | + QCOMPARE(firstResultProperties.value(firstResultPropertyName), firstResultPropertyValue); |
960 | + } |
961 | +} |
962 | + |
963 | +void tst_Introspection::test_application_names_data() |
964 | +{ |
965 | + QTest::addColumn<QString>("app_name"); |
966 | + |
967 | + QTest::newRow("Unset") << "untitled1"; |
968 | + QTest::newRow("Tech") << "autopilot-qt"; |
969 | + QTest::newRow("Userfriendly") << "Autopilot Qt Driver"; |
970 | + QTest::newRow("Fqdn name") << "com.canonical.Autopilot.Qt"; |
971 | +} |
972 | + |
973 | +void tst_Introspection::test_application_names() |
974 | +{ |
975 | + QFETCH(QString, app_name); |
976 | + qApp->setApplicationName(app_name); |
977 | + |
978 | +#ifdef QT5_SUPPORT |
979 | + QList<QVariant> result = Introspect("//QWidgetWindow"); |
980 | +#else |
981 | + QList<QVariant> result = Introspect("//QMainWindow"); |
982 | +#endif |
983 | + |
984 | + QVERIFY(!result.isEmpty()); |
985 | +} |
986 | + |
987 | +void tst_Introspection::test_properties_data() |
988 | +{ |
989 | + QTest::addColumn<QString>("propertyName"); |
990 | + QTest::addColumn<QVariant>("propertyValue"); |
991 | + QTest::addColumn<bool>("fuzzyCompare"); |
992 | + |
993 | + QTest::newRow("static property") << "objectName" << QVariant(m_object->objectName()) << false; |
994 | + QTest::newRow("dynamic property") << "dynamicTestProperty" << m_object->property("dynamicTestProperty") << false; |
995 | + |
996 | + QTest::newRow("int") << "width" << QVariant(m_object->width()) << false; |
997 | + QTest::newRow("uint") << "myUInt" << m_object->property("myUInt") << false; |
998 | + QTest::newRow("bool") << "visible" << QVariant(m_object->isVisible()) << false; |
999 | + QTest::newRow("double") << "windowOpacity" << QVariant(m_object->windowOpacity()) << true; |
1000 | + |
1001 | + QTest::newRow("QString") << "objectName" << QVariant(m_object->objectName()) << false; |
1002 | + QTest::newRow("QStringList") << "myStringList" << m_object->property("myStringList") << false; |
1003 | + QTest::newRow("QSize") << "maximumSize" << QVariant(QList<QVariant>() << m_object->maximumWidth() << m_object->maximumHeight()) << false; |
1004 | + QTest::newRow("QPoint") << "pos" << QVariant(QList<QVariant>() << m_object->x() << m_object->y()) << false; |
1005 | + QTest::newRow("QRect") << "geometry" << QVariant(QList<QVariant>() << m_object->geometry().x() << m_object->geometry().y() << m_object->geometry().width() << m_object->geometry().height()) << false; |
1006 | + QTest::newRow("QColor") << "myColor" << QVariant(QList<QVariant>() << 255 << 0 << 0 << 255) << false; |
1007 | + QTest::newRow("QByteArray") << "myByteArray" << m_object->property("myByteArray") << false; |
1008 | + QTest::newRow("QUrl") << "myUrl" << m_object->property("myUrl") << false; |
1009 | +} |
1010 | + |
1011 | +void tst_Introspection::test_properties() |
1012 | +{ |
1013 | + QFETCH(QString, propertyName); |
1014 | + QFETCH(QVariant, propertyValue); |
1015 | + QFETCH(bool, fuzzyCompare); |
1016 | + |
1017 | + QVariant result = IntrospectNode(m_object); |
1018 | + |
1019 | + QCOMPARE(result.toList().count(), 2); |
1020 | + QVariantMap properties = result.toList().at(1).toMap(); |
1021 | + |
1022 | + if (fuzzyCompare) { |
1023 | + qFuzzyCompare(properties.value(propertyName).toDouble(), propertyValue.toDouble()); |
1024 | + } else { |
1025 | + QCOMPARE(properties.value(propertyName), propertyValue); |
1026 | + } |
1027 | +} |
1028 | + |
1029 | +QTEST_MAIN(tst_Introspection) |
1030 | + |
1031 | +#include "tst_introspection.moc" |
1032 | |
1033 | === added file 'tests/unittests/unittests.pro' |
1034 | --- tests/unittests/unittests.pro 1970-01-01 00:00:00 +0000 |
1035 | +++ tests/unittests/unittests.pro 2013-03-19 12:15:26 +0000 |
1036 | @@ -0,0 +1,26 @@ |
1037 | +#include(../../coverage.pri) |
1038 | + |
1039 | +CONFIG += testcase |
1040 | +TARGET = tst_introspection |
1041 | + |
1042 | +QT += testlib dbus widgets quick |
1043 | + |
1044 | +CONFIG += link_pkgconfig |
1045 | +PKGCONFIG += xpathselect |
1046 | +QMAKE_CXXFLAGS += -std=c++0x -Wl,--no-undefined |
1047 | + |
1048 | +contains(QT_VERSION, ^5\\..\\..*) { |
1049 | + DEFINES += QT5_SUPPORT |
1050 | +} |
1051 | + |
1052 | +INCLUDEPATH += ../../driver |
1053 | + |
1054 | +SOURCES += tst_introspection.cpp \ |
1055 | + ../../driver/introspection.cpp \ |
1056 | + ../../driver/rootnode.cpp \ |
1057 | + ../../driver/qtnode.cpp |
1058 | + |
1059 | +HEADERS += \ |
1060 | + ../../driver/introspection.h \ |
1061 | + ../../driver/rootnode.h \ |
1062 | + ../../driver/qtnode.h |
PASSED: Continuous integration, rev:49 jenkins. qa.ubuntu. com/job/ autopilot- qt-ci/5/ jenkins. qa.ubuntu. com/job/ autopilot- qt-raring- amd64-ci/ 5/console jenkins. qa.ubuntu. com/job/ autopilot- qt-raring- armhf-ci/ 5/console
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: jenkins. qa.ubuntu. com/job/ autopilot- qt-ci/5/ rebuild
http://