Merge lp:~autopilot/autopilot-qt/experimental into lp:autopilot-qt

Proposed by Thomi Richards
Status: Merged
Approved by: Thomi Richards
Approved revision: 85
Merged at revision: 71
Proposed branch: lp:~autopilot/autopilot-qt/experimental
Merge into: lp:autopilot-qt
Diff against target: 1194 lines (+610/-161)
15 files modified
debian/changelog (+7/-0)
debian/control (+4/-2)
driver/autopilot_types.h (+26/-0)
driver/dbus_adaptor.cpp (+1/-1)
driver/dbus_object.cpp (+4/-2)
driver/driver.pro (+2/-1)
driver/introspection.cpp (+62/-25)
driver/introspection.h (+1/-1)
driver/qtnode.cpp (+125/-50)
driver/qtnode.h (+29/-8)
driver/qttestability.cpp (+3/-0)
driver/rootnode.cpp (+15/-26)
driver/rootnode.h (+2/-4)
tests/unittests/tst_introspection.cpp (+326/-39)
tests/unittests/unittests.pro (+3/-2)
To merge this branch: bzr merge lp:~autopilot/autopilot-qt/experimental
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Autopilot Hackers Pending
Review via email: mp+185843@code.launchpad.net

Commit message

1.4 wire protocol changes.

Description of the change

Merge 1.4 changes.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
85. By Thomi Richards

Add Breaks clause on binary package.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2013-08-14 02:04:35 +0000
3+++ debian/changelog 2013-09-16 18:00:39 +0000
4@@ -1,3 +1,10 @@
5+autopilot-qt (1.4-0ubuntu1) saucy; urgency=low
6+
7+ [ Thomi Richards ]
8+ * Update to new xpathselect 1.4 API. Version bump to 1.4.
9+
10+ -- Thomi Richards <thomi.richards@canonical.com> Thu, 15 Aug 2013 11:23:33 +1200
11+
12 autopilot-qt (1.3+13.10.20130814-0ubuntu1) saucy; urgency=low
13
14 [ Robert Bruce Park ]
15
16=== modified file 'debian/control'
17--- debian/control 2013-08-13 22:39:44 +0000
18+++ debian/control 2013-09-16 18:00:39 +0000
19@@ -6,7 +6,7 @@
20 libgl1-mesa-dev,
21 libgles2-mesa-dev,
22 libqt4-dev,
23- libxpathselect-dev (>= 1.3),
24+ libxpathselect-dev (>= 1.4),
25 mesa-common-dev,
26 pkg-config,
27 qt4-qmake,
28@@ -27,9 +27,11 @@
29 Package: libautopilot-qt
30 Section: libs
31 Architecture: any
32-Depends: libxpathselect1.3,
33+Depends: libxpathselect1.4,
34 ${misc:Depends},
35 ${shlibs:Depends},
36+Breaks: python-autopilot (<< 1.4),
37+ python3-autopilot (<< 1.4)
38 Replaces: autopilot-qt,
39 autopilot-qt5,
40 Conflicts: autopilot-qt,
41
42=== added file 'driver/autopilot_types.h'
43--- driver/autopilot_types.h 1970-01-01 00:00:00 +0000
44+++ driver/autopilot_types.h 2013-09-16 18:00:39 +0000
45@@ -0,0 +1,26 @@
46+/*
47+Copyright 2012 Canonical
48+
49+This program is free software: you can redistribute it and/or modify it
50+under the terms of the GNU General Public License version 3, as published
51+by the Free Software Foundation.
52+*/
53+
54+
55+#ifndef AUTOPILOT_TYPES_H
56+#define AUTOPILOT_TYPES_H
57+
58+/// IMPORTANT: THese constants are taken from the autopilot XPathSelect protocol document.
59+/// Only add options here if the support has been added for them in autopilot itself.
60+enum autopilot_type_id
61+{
62+ TYPE_PLAIN = 0,
63+ TYPE_RECT = 1,
64+ TYPE_POINT = 2,
65+ TYPE_SIZE = 3,
66+ TYPE_COLOR = 4,
67+ TYPE_DATETIME = 5,
68+ TYPE_TIME = 6,
69+};
70+
71+#endif
72
73=== modified file 'driver/dbus_adaptor.cpp'
74--- driver/dbus_adaptor.cpp 2013-05-07 23:46:49 +0000
75+++ driver/dbus_adaptor.cpp 2013-09-16 18:00:39 +0000
76@@ -51,7 +51,7 @@
77 void AutopilotAdaptor::GetVersion(const QDBusMessage &message)
78 {
79 QDBusMessage reply = message.createReply();
80- reply << QVariant(QString("1.3"));
81+ reply << QVariant(QString("1.4"));
82 QDBusConnection::sessionBus().send(reply);
83 }
84
85
86=== modified file 'driver/dbus_object.cpp'
87--- driver/dbus_object.cpp 2013-06-27 16:27:11 +0000
88+++ driver/dbus_object.cpp 2013-09-16 18:00:39 +0000
89@@ -294,10 +294,12 @@
90 void DBusObject::ProcessQuery()
91 {
92 Query query = _queries.takeFirst();
93- QList<QVariant> state = Introspect(query.first);
94+ QList<NodeIntrospectionData> state = Introspect(query.first);
95
96 QDBusMessage msg = query.second;
97- msg << QVariant(state);
98+ QVariant var;
99+ var.setValue(state);
100+ msg << var;
101
102 QDBusConnection::sessionBus().send(msg);
103 }
104
105=== modified file 'driver/driver.pro'
106--- driver/driver.pro 2013-01-17 20:20:44 +0000
107+++ driver/driver.pro 2013-09-16 18:00:39 +0000
108@@ -29,7 +29,8 @@
109 rootnode.h \
110 qtnode.h \
111 introspection.h \
112- dbus_adaptor_qt.h
113+ dbus_adaptor_qt.h \
114+ autopilot_types.h
115
116 target.file = libtestability*
117
118
119=== modified file 'driver/introspection.cpp'
120--- driver/introspection.cpp 2013-06-26 09:00:13 +0000
121+++ driver/introspection.cpp 2013-09-16 18:00:39 +0000
122@@ -37,6 +37,7 @@
123 #include <QUrl>
124 #include <QDateTime>
125
126+#include "autopilot_types.h"
127 #include "introspection.h"
128 #include "qtnode.h"
129 #include "rootnode.h"
130@@ -47,13 +48,13 @@
131 QStringList GetNodeChildNames(QObject* obj);
132 void AddCustomProperties(QObject* obj, QVariantMap& properties);
133
134-QList<QVariant> Introspect(QString const& query_string)
135+QList<NodeIntrospectionData> Introspect(QString const& query_string)
136 {
137- QList<QVariant> state;
138+ QList<NodeIntrospectionData> state;
139 QList<QtNode::Ptr> node_list = GetNodesThatMatchQuery(query_string);
140 foreach (QtNode::Ptr obj, node_list)
141 {
142- state.append(obj->IntrospectNode());
143+ state.append(obj->GetIntrospectionData());
144 }
145
146 return state;
147@@ -85,11 +86,11 @@
148 #endif
149 QList<QtNode::Ptr> node_list;
150
151- xpathselect::NodeList list = xpathselect::SelectNodes(root, query_string.toStdString());
152+ xpathselect::NodeVector list = xpathselect::SelectNodes(root, query_string.toStdString());
153 for (auto node : list)
154 {
155 // node may be our root node wrapper *or* an ordinary qobject wrapper
156- auto object_ptr = std::static_pointer_cast<QtNode>(node);
157+ auto object_ptr = std::static_pointer_cast<const QtNode>(node);
158 if (object_ptr)
159 {
160 node_list.append(object_ptr);
161@@ -154,7 +155,7 @@
162 // add the 'Children' pseudo-property:
163 QStringList children = GetNodeChildNames(obj);
164 if (!children.empty())
165- object_properties["Children"] = children;
166+ object_properties["Children"] = PackProperty(children);
167
168 return object_properties;
169 }
170@@ -211,69 +212,105 @@
171 case QVariant::StringList:
172 case QVariant::Double:
173 {
174- return prop;
175+ return QList<QVariant> {
176+ QVariant(TYPE_PLAIN),
177+ prop
178+ };
179 }
180
181 case QVariant::ByteArray:
182 {
183- return QVariant(QString(qvariant_cast<QByteArray>(prop)));
184+ return QList<QVariant> {
185+ QVariant(TYPE_PLAIN),
186+ QVariant(QString(qvariant_cast<QByteArray>(prop)))
187+ };
188 }
189
190 case QVariant::Point:
191 {
192 QPoint p = qvariant_cast<QPoint>(prop);
193- QList<QVariant> l = {QVariant(p.x()), QVariant(p.y())};
194- return QVariant(l);
195+ return QList<QVariant> {
196+ QVariant(TYPE_POINT),
197+ QVariant(p.x()),
198+ QVariant(p.y())
199+ };
200 }
201
202 case QVariant::Rect:
203 {
204 QRect r = qvariant_cast<QRect>(prop);
205- QList<QVariant> l = {
206+ return QList<QVariant> {
207+ QVariant(TYPE_RECT),
208 QVariant(r.x()),
209 QVariant(r.y()),
210 QVariant(r.width()),
211 QVariant(r.height()) };
212- return QVariant(l);
213 }
214
215 case QVariant::Size:
216 {
217 QSize s = qvariant_cast<QSize>(prop);
218- QList<QVariant> l = { QVariant(s.width()), QVariant(s.height()) };
219- return QVariant(l);
220+ return QList<QVariant> {
221+ QVariant(TYPE_SIZE),
222+ QVariant(s.width()),
223+ QVariant(s.height())
224+ };
225 }
226
227 case QVariant::Color:
228 {
229 QColor color = qvariant_cast<QColor>(prop).toRgb();
230- QList<QVariant> l = { QVariant(color.red()),
231- QVariant(color.green()),
232- QVariant(color.blue()),
233- QVariant(color.alpha())
234- };
235- return QVariant(l);
236+ return QList<QVariant> {
237+ QVariant(TYPE_COLOR),
238+ QVariant(color.red()),
239+ QVariant(color.green()),
240+ QVariant(color.blue()),
241+ QVariant(color.alpha())
242+ };
243 }
244
245 case QVariant::Url:
246 {
247- return QVariant(prop.toUrl().toString());
248+ return QList<QVariant> {
249+ QVariant(TYPE_PLAIN),
250+ QVariant(prop.toUrl().toString())
251+ };
252 }
253
254 // Depending on the architecture, floating points might be of type QMetaType::Float instead of QVariant::Double
255 // QDBus however, can only carry QVariant types, so lets convert it to QVariant::Double
256 case QMetaType::Float:
257 {
258- return QVariant(prop.toDouble());
259+ return QList<QVariant> {
260+ QVariant(TYPE_PLAIN),
261+ QVariant(prop.toDouble())
262+ };
263 }
264+
265 case QVariant::Date:
266 case QVariant::DateTime:
267- return QVariant(prop.toDateTime().toTime_t());
268+ {
269+ return QList<QVariant> {
270+ QVariant(TYPE_DATETIME),
271+ QVariant(prop.toDateTime().toTime_t())
272+ };
273+ }
274+
275 case QVariant::Time:
276- return QVariant(prop.toTime().toString("hh:mm:ss"));
277+ {
278+ QTime t = qvariant_cast<QTime>(prop);
279+ return QList<QVariant> {
280+ QVariant(TYPE_TIME),
281+ QVariant(t.hour()),
282+ QVariant(t.minute()),
283+ QVariant(t.second()),
284+ QVariant(t.msec())
285+ };
286+ }
287+
288 default:
289 {
290- return QVariant();
291+ return QVariant(); // unsupported type, will not be sent to the client.
292 }
293 }
294 }
295
296=== modified file 'driver/introspection.h'
297--- driver/introspection.h 2012-08-23 22:01:03 +0000
298+++ driver/introspection.h 2013-09-16 18:00:39 +0000
299@@ -14,7 +14,7 @@
300 #include <QVariantMap>
301
302 /// Introspect 'obj' and return it's properties in a QVariantMap.
303-QList<QVariant> Introspect(const QString& query_string);
304+QList<NodeIntrospectionData> Introspect(const QString& query_string);
305
306 /// Get a list of QtNode pointers that match the given query.
307 QList<QtNode::Ptr> GetNodesThatMatchQuery(QString const& query_string);
308
309=== modified file 'driver/qtnode.cpp'
310--- driver/qtnode.cpp 2013-06-19 10:56:21 +0000
311+++ driver/qtnode.cpp 2013-09-16 18:00:39 +0000
312@@ -15,41 +15,54 @@
313 #include <QGraphicsScene>
314 #include <QGraphicsObject>
315 #endif
316+#include <QDBusArgument>
317+
318+// Marshall the NodeIntrospectionData data into a D-Bus argument
319+ QDBusArgument &operator<<(QDBusArgument &argument, const NodeIntrospectionData &node_data)
320+ {
321+ argument.beginStructure();
322+ argument << node_data.object_path << node_data.state;
323+ argument.endStructure();
324+ return argument;
325+ }
326+
327+ // Retrieve the NodeIntrospectionData data from the D-Bus argument
328+ const QDBusArgument &operator>>(const QDBusArgument &argument, NodeIntrospectionData &node_data)
329+ {
330+ argument.beginStructure();
331+ argument >> node_data.object_path >> node_data.state;
332+ argument.endStructure();
333+ return argument;
334+ }
335
336 const QByteArray AP_ID_NAME("_autopilot_id");
337
338-QtNode::QtNode(QObject *obj, std::string const& parent_path)
339- : object_(obj)
340+QtNode::QtNode(QObject *obj, QtNode::Ptr parent)
341+: object_(obj)
342+, parent_(parent)
343 {
344+ std::string parent_path = parent ? parent->GetPath() : "";
345 full_path_ = parent_path + "/" + GetName();
346 }
347
348+QtNode::QtNode(QObject* obj)
349+: object_(obj)
350+{
351+ full_path_ = "/" + GetName();
352+}
353+
354 QObject* QtNode::getWrappedObject() const
355 {
356 return object_;
357 }
358
359-QVariant QtNode::IntrospectNode() const
360-{
361- // return must be (name, state_map)
362- QString object_name = QString::fromStdString(GetPath());
363- QVariantMap object_properties = GetNodeProperties(object_);
364- object_properties["id"] = GetObjectId();
365- QList<QVariant> object_tuple = { QVariant(object_name), QVariant(object_properties) };
366- return QVariant(object_tuple);
367-}
368-
369-qint64 QtNode::GetObjectId() const
370-{
371- // Note: This starts at 1 for a reason - 1 is reserved for the pseudo root node, and
372- // so must never be allocated to a regular object.
373- static qint64 next_id=1;
374-
375- QList<QByteArray> property_names = object_->dynamicPropertyNames();
376- if (!property_names.contains(AP_ID_NAME))
377- object_->setProperty(AP_ID_NAME, QVariant(++next_id));
378- return object_->property(AP_ID_NAME).toLongLong();
379-
380+NodeIntrospectionData QtNode::GetIntrospectionData() const
381+{
382+ NodeIntrospectionData data;
383+ data.object_path = QString::fromStdString(GetPath());
384+ data.state = GetNodeProperties(object_);
385+ data.state["id"] = PackProperty(GetId());
386+ return data;
387 }
388
389 std::string QtNode::GetName() const
390@@ -68,30 +81,86 @@
391 return full_path_;
392 }
393
394-bool QtNode::MatchProperty(const std::string& name, const std::string& value) const
395+int32_t QtNode::GetId() const
396+{
397+ // Note: This method is used to assign ids to both the root node (with a QApplication object) and
398+ // child nodes. This used to be separate code, but now that we export QApplication properties,
399+ // we can use this one method everywhere.
400+ static int32_t next_id=0;
401+
402+ QList<QByteArray> property_names = object_->dynamicPropertyNames();
403+ if (!property_names.contains(AP_ID_NAME))
404+ {
405+ int32_t new_id = ++next_id;
406+ object_->setProperty(AP_ID_NAME, QVariant(new_id));
407+ }
408+ return qvariant_cast<int32_t>(object_->property(AP_ID_NAME));
409+}
410+
411+bool QtNode::MatchStringProperty(const std::string& name, const std::string& value) const
412+{
413+ QVariantMap properties = GetNodeProperties(object_);
414+
415+ QString qname = QString::fromStdString(name);
416+ if (! properties.contains(qname))
417+ return false;
418+
419+ QVariant object_value = qvariant_cast<QVariantList>(properties[qname]).at(1);
420+ QVariant check_value(QString::fromStdString(value));
421+ if (check_value.canConvert(object_value.type()))
422+ {
423+ check_value.convert(object_value.type());
424+ return check_value == object_value;
425+ }
426+
427+ return false;
428+}
429+
430+bool QtNode::MatchIntegerProperty(const std::string& name, int32_t value) const
431 {
432 if (name == "id")
433- return QString::fromStdString(value).toLongLong() == GetObjectId();
434- QVariantMap properties = GetNodeProperties(object_);
435-
436- QString qname = QString::fromStdString(name);
437- if (! properties.contains(qname))
438- return false;
439-
440- QVariant object_value = properties[qname];
441- QVariant check_value(QString::fromStdString(value));
442- if (check_value.canConvert(object_value.type()))
443- {
444- check_value.convert(object_value.type());
445- return check_value == object_value;
446- }
447-
448- return false;
449-}
450-
451-xpathselect::NodeList QtNode::Children() const
452-{
453- xpathselect::NodeList children;
454+ return value == GetId();
455+
456+ QVariantMap properties = GetNodeProperties(object_);
457+
458+ QString qname = QString::fromStdString(name);
459+ if (! properties.contains(qname))
460+ return false;
461+
462+ QVariant object_value = qvariant_cast<QVariantList>(properties[qname]).at(1);
463+ QVariant check_value(value);
464+ if (check_value.canConvert(object_value.type()))
465+ {
466+ check_value.convert(object_value.type());
467+ return check_value == object_value;
468+ }
469+
470+ return false;
471+}
472+
473+bool QtNode::MatchBooleanProperty(const std::string& name, bool value) const
474+{
475+ QVariantMap properties = GetNodeProperties(object_);
476+
477+ QString qname = QString::fromStdString(name);
478+ if (! properties.contains(qname))
479+ return false;
480+
481+ QVariant object_value = qvariant_cast<QVariantList>(properties[qname]).at(1);
482+ QVariant check_value(value);
483+
484+ if (check_value.canConvert(object_value.type()))
485+ {
486+ check_value.convert(object_value.type());
487+ return check_value == object_value;
488+ }
489+
490+ return false;
491+}
492+
493+xpathselect::NodeVector QtNode::Children() const
494+{
495+ xpathselect::NodeVector children;
496
497 #ifdef QT5_SUPPORT
498 // Qt5's hierarchy for QML has changed a bit:
499@@ -101,21 +170,21 @@
500
501 QQuickView *view = qobject_cast<QQuickView*>(object_);
502 if (view && view->rootObject() != 0) {
503- children.push_back(std::make_shared<QtNode>(view->rootObject(), GetPath()));
504+ children.push_back(std::make_shared<QtNode>(view->rootObject(), shared_from_this()));
505 }
506
507 QQuickItem* item = qobject_cast<QQuickItem*>(object_);
508 if (item) {
509 foreach (QQuickItem *childItem, item->childItems()) {
510 if (childItem->parentItem() == item) {
511- children.push_back(std::make_shared<QtNode>(childItem, GetPath()));
512+ children.push_back(std::make_shared<QtNode>(childItem, shared_from_this()));
513 }
514 }
515 } else {
516 foreach (QObject *child, object_->children())
517 {
518 if (child->parent() == object_)
519- children.push_back(std::make_shared<QtNode>(child, GetPath()));
520+ children.push_back(std::make_shared<QtNode>(child, shared_from_this()));
521 }
522 }
523
524@@ -123,7 +192,7 @@
525 foreach (QObject *child, object_->children())
526 {
527 if (child->parent() == object_)
528- children.push_back(std::make_shared<QtNode>(child, GetPath()));
529+ children.push_back(std::make_shared<QtNode>(child, shared_from_this()));
530 }
531
532 // If our wrapped object is a QGraphicsScene, we need to explicitly grab any child graphics
533@@ -137,10 +206,16 @@
534 {
535 QGraphicsObject *obj = item->toGraphicsObject();
536 if (obj && ! obj->parent())
537- children.push_back(std::make_shared<QtNode>(obj, GetPath()));
538+ children.push_back(std::make_shared<QtNode>(obj, shared_from_this()));
539 }
540 }
541 #endif
542
543 return children;
544 }
545+
546+
547+xpathselect::Node::Ptr QtNode::GetParent() const
548+{
549+ return parent_;
550+}
551
552=== modified file 'driver/qtnode.h'
553--- driver/qtnode.h 2013-04-18 03:44:31 +0000
554+++ driver/qtnode.h 2013-09-16 18:00:39 +0000
555@@ -1,33 +1,54 @@
556 #ifndef QTNODE_H
557 #define QTNODE_H
558
559+#include <cstdint>
560 #include <QVariant>
561+#include <QDBusArgument>
562 #include <xpathselect/node.h>
563
564+/// A simple data structure representing the state of a single node:
565+struct NodeIntrospectionData
566+{
567+ QString object_path;
568+ QVariantMap state;
569+};
570+
571+Q_DECLARE_METATYPE(NodeIntrospectionData);
572+Q_DECLARE_METATYPE(QList<NodeIntrospectionData>);
573+
574+QDBusArgument &operator<<(QDBusArgument &argument, const NodeIntrospectionData &node_data);
575+const QDBusArgument &operator>>(const QDBusArgument &argument, NodeIntrospectionData &node_data);
576+
577 /// Base class for all Qt-based object nodes.
578 ///
579 /// QtNode wraps a single QObject pointer. It derives from xpathselect::Node and,
580 /// like that class, is designed to be allocated on the heap and stored in a
581 /// std::shared_ptr.
582-class QtNode: public xpathselect::Node
583+class QtNode: public xpathselect::Node, public std::enable_shared_from_this<QtNode>
584 {
585 public:
586- typedef std::shared_ptr<QtNode> Ptr;
587+ typedef std::shared_ptr<const QtNode> Ptr;
588
589- QtNode(QObject* object, std::string const& parent_path);
590+ QtNode(QObject* object, Ptr parent);
591+ explicit QtNode(QObject* object);
592
593 QObject* getWrappedObject() const;
594-
595- virtual QVariant IntrospectNode() const;
596- virtual qint64 GetObjectId() const;
597+ xpathselect::Node::Ptr GetParent() const;
598+
599+ virtual NodeIntrospectionData GetIntrospectionData() const;
600+
601
602 virtual std::string GetName() const;
603 virtual std::string GetPath() const;
604- virtual bool MatchProperty(const std::string& name, const std::string& value) const;
605- virtual xpathselect::NodeList Children() const;
606+ virtual int32_t GetId() const;
607+ virtual bool MatchStringProperty(const std::string& name, const std::string& value) const;
608+ virtual bool MatchIntegerProperty(const std::string& name, int32_t value) const;
609+ virtual bool MatchBooleanProperty(const std::string& name, bool value) const;
610+ virtual xpathselect::NodeVector Children() const;
611 private:
612 QObject *object_;
613 std::string full_path_;
614+ Ptr parent_;
615 };
616
617 #endif // QTNODE_H
618
619=== modified file 'driver/qttestability.cpp'
620--- driver/qttestability.cpp 2012-12-19 12:27:25 +0000
621+++ driver/qttestability.cpp 2013-09-16 18:00:39 +0000
622@@ -10,6 +10,7 @@
623 #include "dbus_adaptor.h"
624 #include "dbus_adaptor_qt.h"
625 #include "dbus_object.h"
626+#include "qtnode.h"
627
628 #include <QCoreApplication>
629 #include <QDebug>
630@@ -20,6 +21,8 @@
631 void qt_testability_init(void)
632 {
633 qDebug() << "Loading testability driver.";
634+ qDBusRegisterMetaType<NodeIntrospectionData>();
635+ qDBusRegisterMetaType<QList<NodeIntrospectionData> >();
636
637 DBusObject* obj = new DBusObject;
638 new AutopilotAdaptor(obj);
639
640=== modified file 'driver/rootnode.cpp'
641--- driver/rootnode.cpp 2013-04-18 04:46:44 +0000
642+++ driver/rootnode.cpp 2013-09-16 18:00:39 +0000
643@@ -1,35 +1,32 @@
644 #include "rootnode.h"
645+#include "introspection.h"
646
647 #include <QObject>
648 #include <QCoreApplication>
649 #include <QStringList>
650+#include <QDebug>
651
652 RootNode::RootNode(QCoreApplication* application)
653- : QtNode(application, std::string())
654+ : QtNode(application)
655 , application_(application)
656 {
657 }
658
659-QVariant RootNode::IntrospectNode() const
660+
661+NodeIntrospectionData RootNode::GetIntrospectionData() const
662 {
663- // return must be (name, state_map)
664- QString object_name = QString::fromStdString(GetPath());
665+ NodeIntrospectionData data;
666+ data.object_path = QString::fromStdString(GetPath());
667+ data.state = GetNodeProperties(application_);
668 QStringList child_names;
669 foreach(QObject* child, children_)
670 {
671 child_names.append(child->metaObject()->className());
672 }
673
674- QVariantMap object_properties;
675- object_properties["Children"] = child_names;
676- object_properties["id"] = GetObjectId();
677- QList<QVariant> object_tuple = { QVariant(object_name), QVariant(object_properties) };
678- return QVariant(object_tuple);
679-}
680-
681-qint64 RootNode::GetObjectId() const
682-{
683- return 1;
684+ data.state["Children"] = PackProperty(child_names);
685+ data.state["id"] = PackProperty(GetId());
686+ return data;
687 }
688
689 void RootNode::AddChild(QObject* child)
690@@ -48,18 +45,10 @@
691 return "/" + GetName();
692 }
693
694-bool RootNode::MatchProperty(const std::string& name, const std::string& value) const
695-{
696- if (name == "id")
697- return QString::fromStdString(value).toLongLong() == GetObjectId();
698-
699- return false;
700-}
701-
702-xpathselect::NodeList RootNode::Children() const
703-{
704- xpathselect::NodeList children;
705+xpathselect::NodeVector RootNode::Children() const
706+{
707+ xpathselect::NodeVector children;
708 foreach(QObject* child, children_)
709- children.push_back(std::make_shared<QtNode>(child, GetPath()));
710+ children.push_back(std::make_shared<QtNode>(child, shared_from_this()));
711 return children;
712 }
713
714=== modified file 'driver/rootnode.h'
715--- driver/rootnode.h 2013-04-18 04:46:44 +0000
716+++ driver/rootnode.h 2013-09-16 18:00:39 +0000
717@@ -13,15 +13,13 @@
718 public:
719 RootNode(QCoreApplication* application);
720
721- virtual QVariant IntrospectNode() const;
722- virtual qint64 GetObjectId() const;
723+ virtual NodeIntrospectionData GetIntrospectionData() const;
724
725 void AddChild(QObject* child);
726
727 virtual std::string GetName() const;
728 virtual std::string GetPath() const;
729- virtual bool MatchProperty(const std::string& name, const std::string& value) const;
730- virtual xpathselect::NodeList Children() const;
731+ virtual xpathselect::NodeVector Children() const;
732 private:
733 QCoreApplication* application_;
734 QList<QObject*> children_;
735
736=== modified file 'tests/unittests/tst_introspection.cpp'
737--- tests/unittests/tst_introspection.cpp 2013-06-26 09:00:13 +0000
738+++ tests/unittests/tst_introspection.cpp 2013-09-16 18:00:39 +0000
739@@ -26,6 +26,7 @@
740 #include <QPushButton>
741
742 #include "introspection.h"
743+#include "qtnode.h"
744
745 QVariant IntrospectNode(QObject* obj);
746
747@@ -46,6 +47,8 @@
748 void test_properties_data();
749 void test_properties();
750
751+ void test_property_matching();
752+
753 private:
754 QMainWindow *m_object;
755 };
756@@ -74,6 +77,7 @@
757
758 m_object->setObjectName("testWindow");
759 m_object->setProperty("dynamicTestProperty", "testValue");
760+ m_object->setProperty("dynamicStringProperty", QString("testValue"));
761 m_object->setProperty("myUInt", QVariant(quint8(5)));
762 m_object->setProperty("myStringList", QVariant(QStringList() << "string1" << "string2" << "string3"));
763 m_object->setProperty("myColor", QColor("red"));
764@@ -113,25 +117,155 @@
765 QTest::addColumn<QVariant>("firstResultPropertyValue");
766
767 #ifdef QT5_SUPPORT
768- QTest::newRow("/") << "/" << 1 << "/tst_introspection" << "Children" << QVariant(QStringList() << "QMainWindow" << "QWidgetWindow");
769- QTest::newRow("//QWidget[id=6]") << "//QWidget[id=6]" << 1 << "/tst_introspection/QMainWindow/QWidget" << "objectName" << QVariant("centralTestWidget");
770- QTest::newRow("//QPushButton[id=9]") << "//QPushButton[id=9]" << 1 << "/tst_introspection/QMainWindow/QWidget/QPushButton" << "objectName" << QVariant("myButton2");
771+ QTest::newRow("/")
772+ << "/"
773+ << 1
774+ << "/tst_introspection"
775+ << "Children"
776+ << QVariant(
777+ QVariantList()
778+ << 0
779+ << QVariant(
780+ QStringList()
781+ << "QMainWindow"
782+ << "QWidgetWindow"
783+ )
784+ );
785+
786+ QTest::newRow("//QWidget[id=6]")
787+ << "//QWidget[id=6]"
788+ << 1
789+ << "/tst_introspection/QMainWindow/QWidget"
790+ << "objectName"
791+ << QVariant(
792+ QVariantList()
793+ << 0
794+ << "centralTestWidget"
795+ );
796+
797+ QTest::newRow("//QPushButton[id=9]")
798+ << "//QPushButton[id=9]"
799+ << 1
800+ << "/tst_introspection/QMainWindow/QWidget/QPushButton"
801+ << "objectName"
802+ << QVariant(
803+ QVariantList()
804+ << 0
805+ << "myButton2"
806+ );
807 #else
808- QTest::newRow("/") << "/" << 1 << "/tst_introspection" << "Children" << QVariant(QStringList() << "QMainWindow");
809- QTest::newRow("//QWidget[id=5]") << "//QWidget[id=5]" << 1 << "/tst_introspection/QMainWindow/QWidget" << "objectName" << QVariant("centralTestWidget");
810+ QTest::newRow("/")
811+ << "/"
812+ << 1
813+ << "/tst_introspection"
814+ << "Children"
815+ << QVariant(
816+ QVariantList()
817+ << 0
818+ << "QMainWindow"
819+ );
820+
821+ QTest::newRow("//QWidget[id=5]")
822+ << "//QWidget[id=5]"
823+ << 1
824+ << "/tst_introspection/QMainWindow/QWidget"
825+ << "objectName"
826+ << QVariant(
827+ QVariantList()
828+ << 0
829+ << "centralTestWidget"
830+ );
831
832 // Depending on the environment, Qt4 could add a second QWidget at position 6. That moves other items down by one.
833- if (Introspect("//QWidget[id=6]").count() > 0) {
834- QTest::newRow("//QPushButton[id=9]") << "//QPushButton[id=9]" << 1 << "/tst_introspection/QMainWindow/QWidget/QPushButton" << "objectName" << QVariant("myButton2");
835- } else {
836- QTest::newRow("//QPushButton[id=8]") << "//QPushButton[id=8]" << 1 << "/tst_introspection/QMainWindow/QWidget/QPushButton" << "objectName" << QVariant("myButton2");
837+ if (Introspect("//QWidget[id=6]").count() > 0)
838+ {
839+ QTest::newRow("//QPushButton[id=9]")
840+ << "//QPushButton[id=9]"
841+ << 1
842+ << "/tst_introspection/QMainWindow/QWidget/QPushButton"
843+ << "objectName"
844+ << QVariant(
845+ QVariantList()
846+ << 0
847+ << "myButton2"
848+ );
849+ }
850+ else
851+ {
852+ QTest::newRow("//QPushButton[id=8]")
853+ << "//QPushButton[id=8]"
854+ << 1
855+ << "/tst_introspection/QMainWindow/QWidget/QPushButton"
856+ << "objectName"
857+ << QVariant(
858+ QVariantList()
859+ << 0
860+ << "myButton2"
861+ );
862 }
863 #endif
864
865- QTest::newRow("//GridLayout") << "//QGridLayout" << 1 << "/tst_introspection/QMainWindow/QWidget/QGridLayout" << "objectName" << QVariant("myTestLayout");
866- QTest::newRow("//QPushButton") << "//QPushButton" << 2 << "/tst_introspection/QMainWindow/QWidget/QPushButton" << "objectName" << QVariant("myButton1");
867- QTest::newRow("//QWidget/*") << "//QWidget/*" << 5 << "/tst_introspection/QMainWindow/QWidget/QGridLayout" << "objectName" << QVariant("myTestLayout");
868- QTest::newRow("broken query") << "broken query" << 0 << QString() << QString() << QVariant();
869+ QTest::newRow("/tst_introspection/QMainWindow/QWidget/QGridLayout")
870+ << "//QGridLayout"
871+ << 1
872+ << "/tst_introspection/QMainWindow/QWidget/QGridLayout"
873+ << "objectName"
874+ << QVariant(
875+ QVariantList()
876+ << 0
877+ << "myTestLayout"
878+ );
879+
880+ QTest::newRow("parent of leaf node")
881+ << "/tst_introspection/QMainWindow/QWidget/QGridLayout/.."
882+ << 1
883+ << "/tst_introspection/QMainWindow/QWidget"
884+ << "objectName"
885+ << QVariant(
886+ QVariantList()
887+ << 0
888+ << "centralTestWidget"
889+ );
890+
891+ QTest::newRow("parent of root node")
892+ << "/tst_introspection/.."
893+ << 1
894+ << "/tst_introspection"
895+ << "id"
896+ << QVariant(
897+ QVariantList()
898+ << 0
899+ << 1
900+ );
901+
902+ QTest::newRow("//QPushButton")
903+ << "//QPushButton"
904+ << 2
905+ << "/tst_introspection/QMainWindow/QWidget/QPushButton"
906+ << "objectName"
907+ << QVariant(
908+ QVariantList()
909+ << 0
910+ << "myButton1"
911+ );
912+
913+ QTest::newRow("//QWidget/*")
914+ << "//QWidget/*"
915+ << 5
916+ << "/tst_introspection/QMainWindow/QWidget/QGridLayout"
917+ << "objectName"
918+ << QVariant(
919+ QVariantList()
920+ << 0
921+ << "myTestLayout"
922+ );
923+
924+ QTest::newRow("broken query")
925+ << "broken query"
926+ << 0
927+ << QString()
928+ << QString()
929+ << QVariant();
930 }
931
932 void tst_Introspection::test_introspect()
933@@ -142,16 +276,15 @@
934 QFETCH(QString, firstResultPropertyName);
935 QFETCH(QVariant, firstResultPropertyValue);
936
937- QList<QVariant> resultList = Introspect(xpath);
938+ QList<NodeIntrospectionData> resultList = Introspect(xpath);
939
940 QCOMPARE(resultList.count(), resultCount);
941
942 if (resultCount > 0) {
943- QVariant firstResult = resultList.first();
944- QVariantMap firstResultProperties = firstResult.toList().last().toMap();
945+ NodeIntrospectionData first_object = resultList.first();
946
947- QCOMPARE(firstResult.toList().first().toString(), firstResultType);
948- QCOMPARE(firstResultProperties.value(firstResultPropertyName), firstResultPropertyValue);
949+ QCOMPARE(first_object.object_path, firstResultType);
950+ QCOMPARE(first_object.state.value(firstResultPropertyName), firstResultPropertyValue);
951 }
952 }
953
954@@ -171,9 +304,9 @@
955 qApp->setApplicationName(app_name);
956
957 #ifdef QT5_SUPPORT
958- QList<QVariant> result = Introspect("//QWidgetWindow");
959+ QList<NodeIntrospectionData> result = Introspect("//QWidgetWindow");
960 #else
961- QList<QVariant> result = Introspect("//QMainWindow");
962+ QList<NodeIntrospectionData> result = Introspect("//QMainWindow");
963 #endif
964
965 QVERIFY(!result.isEmpty());
966@@ -185,25 +318,169 @@
967 QTest::addColumn<QVariant>("propertyValue");
968 QTest::addColumn<bool>("fuzzyCompare");
969
970- QTest::newRow("static property") << "objectName" << QVariant(m_object->objectName()) << false;
971- QTest::newRow("dynamic property") << "dynamicTestProperty" << m_object->property("dynamicTestProperty") << false;
972-
973- QTest::newRow("int") << "width" << QVariant(m_object->width()) << false;
974- QTest::newRow("uint") << "myUInt" << m_object->property("myUInt") << false;
975- QTest::newRow("bool") << "visible" << QVariant(m_object->isVisible()) << false;
976- QTest::newRow("double") << "windowOpacity" << QVariant(m_object->windowOpacity()) << true;
977-
978- QTest::newRow("QString") << "objectName" << QVariant(m_object->objectName()) << false;
979- QTest::newRow("QStringList") << "myStringList" << m_object->property("myStringList") << false;
980- QTest::newRow("QSize") << "maximumSize" << QVariant(QList<QVariant>() << m_object->maximumWidth() << m_object->maximumHeight()) << false;
981- QTest::newRow("QPoint") << "pos" << QVariant(QList<QVariant>() << m_object->x() << m_object->y()) << false;
982- QTest::newRow("QRect") << "geometry" << QVariant(QList<QVariant>() << m_object->geometry().x() << m_object->geometry().y() << m_object->geometry().width() << m_object->geometry().height()) << false;
983- QTest::newRow("QColor") << "myColor" << QVariant(QList<QVariant>() << 255 << 0 << 0 << 255) << false;
984- QTest::newRow("QByteArray") << "myByteArray" << m_object->property("myByteArray") << false;
985- QTest::newRow("QUrl") << "myUrl" << m_object->property("myUrl") << false;
986- QTest::newRow("QDateTime") << "myDateTime" << QVariant(m_object->property("myDateTime").toDateTime().toTime_t()) << false;
987- QTest::newRow("QDate") << "myDate" << QVariant(m_object->property("myDate").toDateTime().toTime_t()) << false;
988- QTest::newRow("QTime") << "myTime" << QVariant(m_object->property("myTime").toTime().toString("hh:mm:ss")) << false;
989+ QTest::newRow("static property")
990+ << "objectName"
991+ << QVariant(
992+ QVariantList()
993+ << 0
994+ << m_object->objectName()
995+ )
996+ << false;
997+
998+ QTest::newRow("dynamic property")
999+ << "dynamicTestProperty"
1000+ << QVariant(
1001+ QVariantList()
1002+ << 0
1003+ << m_object->property("dynamicTestProperty")
1004+ )
1005+ << false;
1006+
1007+ QTest::newRow("int")
1008+ << "width"
1009+ << QVariant(
1010+ QVariantList()
1011+ << 0
1012+ << m_object->width()
1013+ )
1014+ << false;
1015+
1016+ QTest::newRow("uint")
1017+ << "myUInt"
1018+ << QVariant(
1019+ QVariantList()
1020+ << 0
1021+ << m_object->property("myUInt")
1022+ )
1023+ << false;
1024+
1025+ QTest::newRow("bool")
1026+ << "visible"
1027+ << QVariant(
1028+ QVariantList()
1029+ << 0
1030+ << m_object->isVisible()
1031+ )
1032+ << false;
1033+
1034+ QTest::newRow("double")
1035+ << "windowOpacity"
1036+ << QVariant(
1037+ QVariantList()
1038+ << 0
1039+ << m_object->windowOpacity()
1040+ )
1041+ << true;
1042+
1043+ QTest::newRow("QString")
1044+ << "objectName"
1045+ << QVariant(
1046+ QVariantList()
1047+ << 0
1048+ << m_object->objectName()
1049+ )
1050+ << false;
1051+
1052+ QTest::newRow("QStringList")
1053+ << "myStringList"
1054+ << QVariant(
1055+ QVariantList()
1056+ << 0
1057+ << m_object->property("myStringList")
1058+ )
1059+ << false;
1060+
1061+ QTest::newRow("QSize")
1062+ << "maximumSize"
1063+ << QVariant(
1064+ QVariantList()
1065+ << 3
1066+ << m_object->maximumWidth()
1067+ << m_object->maximumHeight()
1068+ )
1069+ << false;
1070+
1071+ QTest::newRow("QPoint")
1072+ << "pos"
1073+ << QVariant(
1074+ QVariantList()
1075+ << 2
1076+ << m_object->x()
1077+ << m_object->y()
1078+ )
1079+ << false;
1080+
1081+ QTest::newRow("QRect")
1082+ << "geometry"
1083+ << QVariant(
1084+ QVariantList()
1085+ << 1
1086+ << m_object->geometry().x()
1087+ << m_object->geometry().y()
1088+ << m_object->geometry().width()
1089+ << m_object->geometry().height()
1090+ )
1091+ << false;
1092+
1093+ QTest::newRow("QColor")
1094+ << "myColor"
1095+ << QVariant(
1096+ QVariantList()
1097+ << 4
1098+ << qvariant_cast<QColor>(m_object->property("myColor")).red()
1099+ << qvariant_cast<QColor>(m_object->property("myColor")).green()
1100+ << qvariant_cast<QColor>(m_object->property("myColor")).blue()
1101+ << qvariant_cast<QColor>(m_object->property("myColor")).alpha()
1102+ )
1103+ << false;
1104+
1105+ QTest::newRow("QByteArray")
1106+ << "myByteArray"
1107+ << QVariant(
1108+ QVariantList()
1109+ << 0
1110+ << m_object->property("myByteArray")
1111+ )
1112+ << false;
1113+
1114+ QTest::newRow("QUrl")
1115+ << "myUrl"
1116+ << QVariant(
1117+ QVariantList()
1118+ << 0
1119+ << m_object->property("myUrl")
1120+ )
1121+ << false;
1122+
1123+ QTest::newRow("QDateTime")
1124+ << "myDateTime"
1125+ << QVariant(
1126+ QVariantList()
1127+ << 5
1128+ << m_object->property("myDateTime").toDateTime().toTime_t()
1129+ )
1130+ << false;
1131+
1132+ QTest::newRow("QDate")
1133+ << "myDate"
1134+ << QVariant(
1135+ QVariantList()
1136+ << 5
1137+ << m_object->property("myDate").toDateTime().toTime_t()
1138+ )
1139+ << false;
1140+
1141+ QTest::newRow("QTime")
1142+ << "myTime"
1143+ << QVariant(
1144+ QVariantList()
1145+ << 6
1146+ << m_object->property("myTime").toTime().hour()
1147+ << m_object->property("myTime").toTime().minute()
1148+ << m_object->property("myTime").toTime().second()
1149+ << m_object->property("myTime").toTime().msec()
1150+ )
1151+ << false;
1152 }
1153
1154 void tst_Introspection::test_properties()
1155@@ -224,6 +501,16 @@
1156 }
1157 }
1158
1159+void tst_Introspection::test_property_matching()
1160+{
1161+ QtNode n(m_object);
1162+
1163+ QVERIFY(n.MatchStringProperty("dynamicStringProperty", "testValue") == true);
1164+ QVERIFY(n.MatchStringProperty("dynamicTestProperty", "testValue") == true);
1165+ QVERIFY(n.MatchIntegerProperty("myUInt", 5) == true);
1166+ QVERIFY(n.MatchBooleanProperty("visible", true) == true);
1167+}
1168+
1169 QTEST_MAIN(tst_Introspection)
1170
1171 #include "tst_introspection.moc"
1172
1173=== modified file 'tests/unittests/unittests.pro'
1174--- tests/unittests/unittests.pro 2013-03-17 16:53:30 +0000
1175+++ tests/unittests/unittests.pro 2013-09-16 18:00:39 +0000
1176@@ -5,7 +5,7 @@
1177
1178 QT += testlib dbus widgets quick
1179
1180-CONFIG += link_pkgconfig
1181+CONFIG += link_pkgconfig debug
1182 PKGCONFIG += xpathselect
1183 QMAKE_CXXFLAGS += -std=c++0x -Wl,--no-undefined
1184
1185@@ -15,7 +15,8 @@
1186
1187 INCLUDEPATH += ../../driver
1188
1189-SOURCES += tst_introspection.cpp \
1190+SOURCES += \
1191+ tst_introspection.cpp \
1192 ../../driver/introspection.cpp \
1193 ../../driver/rootnode.cpp \
1194 ../../driver/qtnode.cpp

Subscribers

People subscribed via source and target branches

to all changes: