Merge lp:~mzanetti/autopilot-qt/add-tests into lp:autopilot-qt

Proposed by Michael Zanetti
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
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-qt-autopilot package

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.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~mzanetti/autopilot-qt/add-tests updated
50. By Michael Zanetti

fix typo in test function name

51. By Michael Zanetti

remove double empty lines

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

Just for the reference here are some of the test failures:

1. libautopilot_qt.tests.test_main.TestProperties.test_mouse_interaction
 - 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_qt.tests.test_main.TestQueries.test_find_by_objectname
Should be fixed by:
https://code.launchpad.net/~thomir/autopilot/fix-select_single_bug/+merge/152052

3. libautopilot_qt.tests.test_main.TestAppNameFqdn.test_connection
Should be workarounded/fixed by:
https://code.launchpad.net/~mzanetti/autopilot-qt/workaround-xpathselect/+merge/153544

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:
-----------snip-------------
Fontconfig warning: "/etc/fonts/conf.d/50-user.conf", line 9: reading configurations from ~/.fonts.conf is deprecated.
********* Start testing of tst_Introspection *********
Config: Using QTest library 4.8.4, Qt 4.8.4
PASS : tst_Introspection::initTestCase()
FAIL! : tst_Introspection::test_introspect(//QPushButton[id=7]) Compared values are not the same
   Actual (resultList.count()): 0
   Expected (resultCount): 1
   Loc: [tst_introspection.cpp(141)]
PASS : tst_Introspection::test_application_names()
PASS : tst_Introspection::test_properties()
PASS : tst_Introspection::cleanupTestCase()
Totals: 4 passed, 1 failed, 0 skipped
-----------snip-------------

review: Needs Fixing
Revision history for this message
Martin Mrazik (mrazik) wrote :

The unit tests seem to work fine for qt5.

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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~mzanetti/autopilot-qt/add-tests updated
52. By Michael Zanetti

fix Qt4 unit tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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_Introspection::initTestCase()
FAIL! : tst_Introspection::test_introspect(//QPushButton[id=9]) Compared values are not the same
   Actual (resultList.count()): 0
   Expected (resultCount): 1
   Loc: [tst_introspection.cpp(137)]
PASS : tst_Introspection::test_application_names()
PASS : tst_Introspection::test_properties()
PASS : tst_Introspection::cleanupTestCase()
Totals: 4 passed, 1 failed, 0 skipped
********* Finished testing of tst_Introspection *********

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

lp:~mzanetti/autopilot-qt/add-tests updated
53. By Michael Zanetti

make test a bit more flexible

54. By Michael Zanetti

get rid of some newlines

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

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

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 Mrazik (mrazik) wrote :

The unit tests are passing for me.
The only unanswered question is on when/how are these supposed to be executed.

Revision history for this message
Michael Zanetti (mzanetti) wrote :

> The only unanswered question is on when/how are these supposed to be executed.

https://code.launchpad.net/~mathieu-tl/autopilot-qt/unittests/+merge/153950

lp:~mzanetti/autopilot-qt/add-tests updated
55. By Michael Zanetti

merge and fix trunk

Revision history for this message
Martin Mrazik (mrazik) wrote :

Thanks

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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?

review: Needs Fixing
Revision history for this message
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

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

review: Approve

Preview Diff

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

Subscribers

People subscribed via source and target branches