Merge lp:~veebers/autopilot-qt/enable-datamodel-elements-add-new-nodes into lp:autopilot-qt

Proposed by Christopher Lee
Status: Merged
Approved by: Thomi Richards
Approved revision: 121
Merged at revision: 87
Proposed branch: lp:~veebers/autopilot-qt/enable-datamodel-elements-add-new-nodes
Merge into: lp:autopilot-qt
Prerequisite: lp:~veebers/autopilot-qt/enable-datamodel-elements-qtnode-name-change
Diff against target: 1332 lines (+1078/-92)
8 files modified
driver/qtnode.cpp (+481/-56)
driver/qtnode.h (+92/-6)
tests/unittests/tst_introspection.cpp (+3/-29)
tests/unittests/tst_introspection.h (+44/-0)
tests/unittests/tst_main.cpp (+30/-0)
tests/unittests/tst_qtnode.cpp (+345/-0)
tests/unittests/tst_qtnode.h (+78/-0)
tests/unittests/unittests.pro (+5/-1)
To merge this branch: bzr merge lp:~veebers/autopilot-qt/enable-datamodel-elements-add-new-nodes
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Thomi Richards (community) Approve
Review via email: mp+224061@code.launchpad.net

Commit message

Adding new data model nodes.

Description of the change

Implementing the new data-index style nodes so we can introspect them.

To post a comment you must log in.
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
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

Hi,

There's still a few things that need to be cleaned up - see diff comments below.

review: Needs Fixing
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

Just one comment, but I haven't given it an in-depth review.

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

27 +inline int32_t calclulate_ap_id(quint64 big_id)

I think this is a typo ^. It should be calculate. But you are using it in so many places, it might be one of those correct English variations I have never heard before.

It might be good to put a comment there, because it's not really clear why you are shortening a big id instead of using always a data type that fits small and big ids.

255 + // Do any special children handling if needed.
[...]
298 + }
299 +

It would be clearer to extract all the ifs into a method. Also, the only thing that changes on each condition is the cast type. That can be parameterized and put into a method, right?

340 + // Make an attempt to store the 'text' of a node to be user friendly-ish.
[...]
369 + properties["globalRect"] = PackProperty(global_rect);

It would also be clearer to extract some of the calls into methods.

I can't see anything obviously wrong, but as I told you there are so many new things in this branch that some big things might have escaped me.

Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :
Download full text (3.5 KiB)

Looks good, except for comments made in the diff and on IRC.

[09:59:27] <veebers> thomi: sure, https://code.launchpad.net/~veebers/autopilot-qt/enable-datamodel-elements-add-new-nodes/+merge/224061
[09:59:49] <thomi> ok
[10:00:17] <thomi> veebers: hmmm
[10:00:29] <thomi> do you mind making a seemingly trivial, but important change?
[10:00:34] <thomi> actually, scratch that..
[10:00:52] <thomi> instead, imagine I said "please make this seemingly trivial, but important change" :P
[10:01:02] <thomi> veebers: in C++, please prefer:
[10:01:26] <thomi> 'Type const& name' over 'const Type& name'
[10:01:48] <thomi> same with pointers, it should be: 'Type const* name'
[10:02:06] <thomi> you read type declarations right-to-left, so:
[10:02:12] <veebers> thomi: ah sure, I'll make that change in a moment
[10:02:24] <thomi> 'QString const& name' is 'name is a reference to a const QString'
[10:02:46] <thomi> this isn't so important for references (but please change it still), but for pointers it's more critical, for example:
[10:03:01] <thomi> 'Foo const* const p'
[10:03:03] <thomi> or
[10:03:14] <thomi> 'p is a const pointer to a const Foo'
[10:03:38] <veebers> make sense
[10:03:40] <thomi> since you can also have 'Foo* const p' and 'Foo const* p'
[10:03:47] <thomi> and they're all different things :)
[10:04:29] <thomi> veebers: also, in GetDataElementChildren, can parent be const?
[10:05:00] <thomi> it will require all the parent parameters in all the QtNode-type classes to also be const, but they should be anyway
[10:05:47] <veebers> thomi: I'm pretty sure it can be
[10:06:15] <veebers> cool, I'll get that sorted too
[10:07:07] <thomi> veebers: also in those functions, I wonder if you can make the qDebug messages a bit more useful?
[10:07:25] <thomi> "Unable to retrieve model for QTreeView" doesn't sound like it's going to be useful to us while trying to debug things
[10:07:46] <veebers> thomi: understood, i'll make the message better
[10:07:50] <thomi> why can't we get the items, and which tree view is it?
[10:15:54] <thomi> veebers: You don't need to mark this as explicit: "QModelIndexNode(QModelIndex index, QAbstractItemView* parent_view)"
[10:16:09] <thomi> C++ only does implicit type conversion on single parameter ctors
[10:16:21] <veebers> thomi: oh, noted. Good catch
[10:17:04] <thomi> veebers: do you really need two ctors?
[10:17:14] <thomi> What's the use case for the one without the dbu parent node?
[10:17:34] <veebers> thomi: hmm, that might be a mistake, I'll check that wehn I make the other changes
[10:18:31] <thomi> veebers: also, what's the rationale for wanting to split the unit tests into multiple projects?
[10:19:55] <veebers> thomi: I wanted to have a separation of the tests for introspection and tests for the QtNode and this was my attempt at doing so. I initially tried to use 2 classes in the same file etc. but ended up soing it this way so I could get the tests written
[10:20:11] <veebers> thomi: If there is a better way I'm more than happy to make it happen
[10:20:21] <thomi> but why not have two test files in the same project?
[10:20:40] <thomi> I don't think you need a separate project, and therefore separate executables for ea...

Read more...

review: Needs Fixing
110. By Christopher Lee

Fix spelling mistake.

111. By Christopher Lee

Fixed cont Type& to Type const&

112. By Christopher Lee

const change for operators too

113. By Christopher Lee

Improve qDebug messages

114. By Christopher Lee

Remove un-needed constructors (Always need a parent for these types.)

115. By Christopher Lee

Make unittests a single project and executable.

116. By Christopher Lee

Added comment as per MP

117. By Christopher Lee

Actually add the other test files.

118. By Christopher Lee

Fix broken test.

119. By Christopher Lee

Move special children check into reusable function.

120. By Christopher Lee

Fix failing test, need to break once collected special children.

121. By Christopher Lee

Clean up QModelIndexNode::GetProperties

Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

LGTM

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
122. By Christopher Lee

Remove inline from calculate_ap_id

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'driver/qtnode.cpp'
2--- driver/qtnode.cpp 2014-07-24 23:49:59 +0000
3+++ driver/qtnode.cpp 2014-07-24 23:49:59 +0000
4@@ -17,8 +17,37 @@
5 #endif
6 #include <QDBusArgument>
7
8+#include <QAbstractItemView>
9+#include <QAbstractProxyModel>
10+#include <QTableWidget>
11+#include <QTreeView>
12+#include <QTreeWidget>
13+#include <QListView>
14+
15+const QByteArray AP_ID_NAME("_autopilot_id");
16+
17+void CollectSpecialChildren(QObject* object, xpathselect::NodeVector& children, DBusNode::Ptr parent);
18+
19+void GetDataElementChildren(QTableWidget* table, xpathselect::NodeVector& children, DBusNode::Ptr parent);
20+void GetDataElementChildren(QTreeView* tree_view, xpathselect::NodeVector& children, DBusNode::Ptr parent);
21+void GetDataElementChildren(QTreeWidget* tree_widget, xpathselect::NodeVector& children, DBusNode::Ptr parent);
22+void GetDataElementChildren(QListView* list_view, xpathselect::NodeVector& children, DBusNode::Ptr parent);
23+
24+void CollectAllIndices(QModelIndex index, QAbstractItemModel *model, QModelIndexList &collection);
25+QVariant SafePackProperty(QVariant const& prop);
26+
27+bool MatchProperty(QVariantMap const& packed_properties, std::string const& name, QVariant value);
28+
29+// Produce an id suitable for xpathselects' GetId
30+int32_t calculate_ap_id(quint64 big_id)
31+{
32+ int32_t high = static_cast<int32_t>(big_id >> 32);
33+ int32_t low = static_cast<int32_t>(big_id);
34+ return high ^ low;
35+}
36+
37 // Marshall the NodeIntrospectionData data into a D-Bus argument
38-QDBusArgument &operator<<(QDBusArgument &argument, const NodeIntrospectionData &node_data)
39+QDBusArgument &operator<<(QDBusArgument &argument, NodeIntrospectionData const& node_data)
40 {
41 argument.beginStructure();
42 argument << node_data.object_path << node_data.state;
43@@ -27,7 +56,7 @@
44 }
45
46 // Retrieve the NodeIntrospectionData data from the D-Bus argument
47-const QDBusArgument &operator>>(const QDBusArgument &argument, NodeIntrospectionData &node_data)
48+const QDBusArgument &operator>>(QDBusArgument const& argument, NodeIntrospectionData& node_data)
49 {
50 argument.beginStructure();
51 argument >> node_data.object_path >> node_data.state;
52@@ -35,7 +64,142 @@
53 return argument;
54 }
55
56-const QByteArray AP_ID_NAME("_autopilot_id");
57+void GetDataElementChildren(QTableWidget *table, xpathselect::NodeVector& children, DBusNode::Ptr parent)
58+{
59+ QList<QTableWidgetItem *> tablewidgetitems = table->findItems("*", Qt::MatchWildcard|Qt::MatchRecursive);
60+ foreach (QTableWidgetItem *item, tablewidgetitems){
61+ children.push_back(
62+ std::make_shared<QTableWidgetItemNode>(item, parent)
63+ );
64+ }
65+}
66+
67+void CollectAllIndices(QModelIndex index, QAbstractItemModel *model, QModelIndexList &collection)
68+{
69+ for(int c=0; c < model->columnCount(index); ++c) {
70+ for(int r=0; r < model->rowCount(index); ++r) {
71+ QModelIndex new_index = model->index(r, c, index);
72+ collection.push_back(new_index);
73+ if(new_index.isValid() && qHash(new_index) != qHash(index)) {
74+ CollectAllIndices(new_index, model, collection);
75+ }
76+ }
77+ }
78+}
79+
80+// Pack property, but return a default blank if the packed property is invalid.
81+QVariant SafePackProperty(QVariant const& prop)
82+{
83+ static QVariant blank_default = PackProperty("");
84+
85+ QVariant property_attempt = PackProperty(prop);
86+ if(property_attempt.isValid())
87+ return property_attempt;
88+ else
89+ return blank_default;
90+}
91+
92+bool MatchProperty(QVariantMap const& packed_properties, std::string const& name, QVariant value)
93+{
94+ QString qname = QString::fromStdString(name);
95+ if (! packed_properties.contains(qname))
96+ return false;
97+
98+ // Because the properties are packed, we need the value, not the type.
99+ QVariant object_value = qvariant_cast<QVariantList>(packed_properties[qname]).at(1);
100+ if (value.canConvert(object_value.type()))
101+ {
102+ value.convert(object_value.type());
103+ return value == object_value;
104+ }
105+ return false;
106+}
107+
108+
109+void GetDataElementChildren(QTreeView* tree_view, xpathselect::NodeVector& children, DBusNode::Ptr parent)
110+{
111+ QAbstractItemModel* abstract_model = tree_view->model();
112+ if(! abstract_model)
113+ {
114+ qDebug() << "Unable to get element children from QTreeView "
115+ << "with objectName '" << tree_view->objectName() << "'. "
116+ << "No model found.";
117+ return;
118+ }
119+
120+ QModelIndexList all_indices;
121+ for(int c=0; c < abstract_model->columnCount(); ++c) {
122+ for(int r=0; r < abstract_model->rowCount(); ++r) {
123+ QModelIndex index = abstract_model->index(r, c);
124+ all_indices.push_back(index);
125+ CollectAllIndices(index, abstract_model, all_indices);
126+ }
127+ }
128+
129+ foreach(QModelIndex index, all_indices)
130+ {
131+ if(index.isValid())
132+ {
133+ children.push_back(
134+ std::make_shared<QModelIndexNode>(
135+ index,
136+ tree_view,
137+ parent)
138+ );
139+ }
140+ }
141+}
142+
143+void GetDataElementChildren(QTreeWidget* tree_widget, xpathselect::NodeVector& children, DBusNode::Ptr parent)
144+{
145+ for(int i=0; i < tree_widget->topLevelItemCount(); ++i) {
146+ children.push_back(
147+ std::make_shared<QTreeWidgetItemNode>(
148+ tree_widget->topLevelItem(i),
149+ parent)
150+ );
151+ }
152+}
153+
154+void GetDataElementChildren(QListView* list_view, xpathselect::NodeVector& children, DBusNode::Ptr parent)
155+{
156+ QAbstractItemModel* abstract_model = list_view->model();
157+
158+ if(! abstract_model) {
159+ qDebug() << "Unable to get element children from QListView "
160+ << "with objectName '" << list_view->objectName() << "'. "
161+ << "No model found.";
162+ return;
163+ }
164+
165+ QModelIndexList all_indices;
166+ QModelIndex root_index = list_view->rootIndex();
167+ if(root_index.isValid()) {
168+ // The root item is the parent item to the view's toplevel items
169+ CollectAllIndices(root_index, abstract_model, all_indices);
170+ }
171+ else {
172+ for(int c=0; c < abstract_model->columnCount(); ++c) {
173+ for(int r=0; r < abstract_model->rowCount(); ++r) {
174+ QModelIndex index = abstract_model->index(r, c);
175+ all_indices.push_back(index);
176+ CollectAllIndices(index, abstract_model, all_indices);
177+ }
178+ }
179+ }
180+
181+ foreach(QModelIndex index, all_indices) {
182+ if(index.isValid())
183+ {
184+ children.push_back(
185+ std::make_shared<QModelIndexNode>(
186+ index,
187+ list_view,
188+ parent)
189+ );
190+ }
191+ }
192+}
193
194 QObjectNode::QObjectNode(QObject *obj, DBusNode::Ptr parent)
195 : object_(obj)
196@@ -70,7 +234,6 @@
197 QString name = object_->metaObject()->className();
198
199 // QML type names get mangled by Qt - they get _QML_N or _QMLTYPE_N appended.
200- //
201 if (name.contains('_'))
202 name = name.split('_').front();
203 return name.toStdString();
204@@ -97,71 +260,62 @@
205 return qvariant_cast<int32_t>(object_->property(AP_ID_NAME));
206 }
207
208-bool QObjectNode::MatchStringProperty(const std::string& name, const std::string& value) const
209+bool QObjectNode::MatchStringProperty(std::string const& name, std::string const& value) const
210 {
211- QVariantMap properties = GetNodeProperties(object_);
212-
213- QString qname = QString::fromStdString(name);
214- if (! properties.contains(qname))
215- return false;
216-
217- QVariant object_value = qvariant_cast<QVariantList>(properties[qname]).at(1);
218- QVariant check_value(QString::fromStdString(value));
219- if (check_value.canConvert(object_value.type()))
220- {
221- check_value.convert(object_value.type());
222- return check_value == object_value;
223- }
224-
225- return false;
226+ return MatchProperty(GetNodeProperties(object_), name, QString::fromStdString(value));
227 }
228
229-bool QObjectNode::MatchIntegerProperty(const std::string& name, int32_t value) const
230+bool QObjectNode::MatchIntegerProperty(std::string const& name, int32_t value) const
231 {
232 if (name == "id")
233 return value == GetId();
234
235- QVariantMap properties = GetNodeProperties(object_);
236-
237- QString qname = QString::fromStdString(name);
238- if (! properties.contains(qname))
239- return false;
240-
241- QVariant object_value = qvariant_cast<QVariantList>(properties[qname]).at(1);
242- QVariant check_value(value);
243- if (check_value.canConvert(object_value.type()))
244- {
245- check_value.convert(object_value.type());
246- return check_value == object_value;
247- }
248-
249- return false;
250-}
251-
252-bool QObjectNode::MatchBooleanProperty(const std::string& name, bool value) const
253-{
254- QVariantMap properties = GetNodeProperties(object_);
255-
256- QString qname = QString::fromStdString(name);
257- if (! properties.contains(qname))
258- return false;
259-
260- QVariant object_value = qvariant_cast<QVariantList>(properties[qname]).at(1);
261- QVariant check_value(value);
262-
263- if (check_value.canConvert(object_value.type()))
264- {
265- check_value.convert(object_value.type());
266- return check_value == object_value;
267- }
268-
269- return false;
270+ return MatchProperty(GetNodeProperties(object_), name, value);
271+}
272+
273+bool QObjectNode::MatchBooleanProperty(std::string const& name, bool value) const
274+{
275+ return MatchProperty(GetNodeProperties(object_), name, value);
276+}
277+
278+template <class T>
279+bool AttemptGetSpecialChildren(QObject* object, xpathselect::NodeVector& children, DBusNode::Ptr parent)
280+{
281+ auto className = T::staticMetaObject.className();
282+ if(object->inherits(className))
283+ {
284+ T* table = qobject_cast<T *>(object);
285+ if(table) {
286+ GetDataElementChildren(table, children, parent);
287+ }
288+ else {
289+ qDebug() << "Casting object (with objectName: " << object->objectName() << ") "
290+ << "to " << className
291+ << "failed. Unable to retrieve children.";
292+ return false;
293+ }
294+ return true;
295+ }
296+ return false;
297+}
298+
299+void CollectSpecialChildren(QObject* object, xpathselect::NodeVector& children, DBusNode::Ptr parent)
300+{
301+ // Need to make sure to make these checks in the correct order.
302+ // i.e. Because QTreeWidget inherits from QTreeView do it first otherwise
303+ // we would never reach the specific QTreeWidget code.
304+ AttemptGetSpecialChildren<QTableWidget>(object, children, parent)
305+ || AttemptGetSpecialChildren<QTreeWidget>(object, children, parent)
306+ || AttemptGetSpecialChildren<QTreeView>(object, children, parent)
307+ || AttemptGetSpecialChildren<QListView>(object, children, parent);
308 }
309
310 xpathselect::NodeVector QObjectNode::Children() const
311 {
312 xpathselect::NodeVector children;
313
314+ CollectSpecialChildren(object_, children, shared_from_this());
315+
316 #ifdef QT5_SUPPORT
317 // Qt5's hierarchy for QML has changed a bit:
318 // - On top there's a QQuickView which holds all the QQuick items
319@@ -219,3 +373,274 @@
320 {
321 return parent_;
322 }
323+
324+// QModelIndexNode
325+QModelIndexNode::QModelIndexNode(QModelIndex index, QAbstractItemView* parent_view, DBusNode::Ptr parent)
326+ : index_(index)
327+ , parent_view_(parent_view)
328+ , parent_(parent)
329+{
330+ std::string parent_path = parent ? parent->GetPath() : "";
331+ full_path_ = parent_path + "/" + GetName();
332+}
333+
334+NodeIntrospectionData QModelIndexNode::GetIntrospectionData() const
335+{
336+ NodeIntrospectionData data;
337+ data.object_path = QString::fromStdString(GetPath());
338+ data.state = GetProperties();
339+ data.state["id"] = PackProperty(GetId());
340+ return data;
341+}
342+
343+QVariantMap QModelIndexNode::GetProperties() const
344+{
345+ QVariantMap properties;
346+ const QAbstractItemModel* model = index_.model();
347+ if(model)
348+ {
349+ // Make an attempt to store the 'text' of a node to be user friendly-ish.
350+ properties["text"] = SafePackProperty(model->data(index_));
351+
352+ // Include any Role data (mung the role name with added "Role")
353+ const QHash<int, QByteArray> role_names = model->roleNames();
354+ QMap<int, QVariant> item_data = model->itemData(index_);
355+ foreach(int name, role_names.keys())
356+ {
357+ if(item_data.contains(name)) {
358+ properties[role_names[name]+"Role"] = SafePackProperty(item_data[name]);
359+ }
360+ else {
361+ properties[role_names[name]+"Role"] = PackProperty("");
362+ }
363+ }
364+ }
365+
366+ QRect rect = parent_view_->visualRect(index_);
367+ QRect global_rect(
368+ parent_view_->viewport()->mapToGlobal(rect.topLeft()),
369+ rect.size());
370+ QRect viewport_contents = parent_view_->viewport()->contentsRect();
371+ properties["onScreen"] = PackProperty(viewport_contents.contains(rect));
372+ properties["globalRect"] = PackProperty(global_rect);
373+
374+ return properties;
375+}
376+
377+xpathselect::Node::Ptr QModelIndexNode::GetParent() const
378+{
379+ return parent_;
380+}
381+
382+std::string QModelIndexNode::GetName() const
383+{
384+ return "QModelIndex";
385+}
386+
387+std::string QModelIndexNode::GetPath() const
388+{
389+ return full_path_;
390+}
391+
392+int32_t QModelIndexNode::GetId() const
393+{
394+ return calculate_ap_id(static_cast<quint64>(qHash(index_)));
395+}
396+
397+bool QModelIndexNode::MatchStringProperty(std::string const& name, std::string const& value) const
398+{
399+ return MatchProperty(GetProperties(), name, QString::fromStdString(value));
400+}
401+
402+bool QModelIndexNode::MatchIntegerProperty(std::string const& name, int32_t value) const
403+{
404+ if (name == "id")
405+ return value == GetId();
406+
407+ return MatchProperty(GetProperties(), name, value);
408+}
409+
410+bool QModelIndexNode::MatchBooleanProperty(std::string const& name, bool value) const
411+{
412+ return MatchProperty(GetProperties(), name, value);
413+}
414+
415+xpathselect::NodeVector QModelIndexNode::Children() const
416+{
417+ // Doesn't have any children.
418+ xpathselect::NodeVector children;
419+ return children;
420+}
421+
422+// QTableWidgetItemNode
423+QTableWidgetItemNode::QTableWidgetItemNode(QTableWidgetItem *item, DBusNode::Ptr parent)
424+ : item_(item)
425+ , parent_(parent)
426+{
427+ std::string parent_path = parent ? parent->GetPath() : "";
428+ full_path_ = parent_path + "/" + GetName();
429+}
430+
431+NodeIntrospectionData QTableWidgetItemNode::GetIntrospectionData() const
432+{
433+ NodeIntrospectionData data;
434+ data.object_path = QString::fromStdString(GetPath());
435+ data.state = GetProperties();
436+ data.state["id"] = PackProperty(GetId());
437+ return data;
438+}
439+
440+QVariantMap QTableWidgetItemNode::GetProperties() const
441+{
442+ QVariantMap properties;
443+
444+ QTableWidget* parent = item_->tableWidget();
445+ QRect cellrect = parent->visualItemRect(item_);
446+ QRect r = QRect(parent->mapToGlobal(cellrect.topLeft()), cellrect.size());
447+ properties["globalRect"] = PackProperty(r);
448+
449+ properties["text"] = SafePackProperty(PackProperty(item_->text()));
450+ properties["toolTip"] = SafePackProperty(PackProperty(item_->toolTip()));
451+ properties["icon"] = SafePackProperty(PackProperty(item_->icon()));
452+ properties["whatsThis"] = SafePackProperty(PackProperty(item_->whatsThis()));
453+ properties["row"] = SafePackProperty(PackProperty(item_->row()));
454+ properties["isSelected"] = SafePackProperty(PackProperty(item_->isSelected()));
455+ properties["column"] = SafePackProperty(PackProperty(item_->column()));
456+
457+ return properties;
458+}
459+
460+xpathselect::Node::Ptr QTableWidgetItemNode::GetParent() const
461+{
462+ return parent_;
463+}
464+
465+std::string QTableWidgetItemNode::GetName() const
466+{
467+ return "QTableWidgetItem";
468+}
469+
470+std::string QTableWidgetItemNode::GetPath() const
471+{
472+ return full_path_;
473+}
474+
475+int32_t QTableWidgetItemNode::GetId() const
476+{
477+ return calculate_ap_id(static_cast<quint64>(reinterpret_cast<quintptr>(item_)));
478+}
479+
480+bool QTableWidgetItemNode::MatchStringProperty(std::string const& name, std::string const& value) const
481+{
482+ return MatchProperty(GetProperties(), name, QString::fromStdString(value));
483+}
484+
485+bool QTableWidgetItemNode::MatchIntegerProperty(std::string const& name, int32_t value) const
486+{
487+ if (name == "id")
488+ return value == GetId();
489+
490+ return MatchProperty(GetProperties(), name, value);
491+}
492+
493+bool QTableWidgetItemNode::MatchBooleanProperty(std::string const& name, bool value) const
494+{
495+ return MatchProperty(GetProperties(), name, value);
496+}
497+
498+xpathselect::NodeVector QTableWidgetItemNode::Children() const
499+{
500+ // Doesn't have any children.
501+ xpathselect::NodeVector children;
502+ return children;
503+}
504+
505+// QTreeWidgetItemNode
506+QTreeWidgetItemNode::QTreeWidgetItemNode(QTreeWidgetItem *item, DBusNode::Ptr parent)
507+ : item_(item)
508+ , parent_(parent)
509+{
510+ std::string parent_path = parent ? parent->GetPath() : "";
511+ full_path_ = parent_path + "/" + GetName();
512+}
513+
514+NodeIntrospectionData QTreeWidgetItemNode::GetIntrospectionData() const
515+{
516+ NodeIntrospectionData data;
517+ data.object_path = QString::fromStdString(GetPath());
518+ data.state = GetProperties();
519+ data.state["id"] = PackProperty(GetId());
520+ return data;
521+}
522+
523+QVariantMap QTreeWidgetItemNode::GetProperties() const
524+{
525+ QVariantMap properties;
526+ QTreeWidget* parent = item_->treeWidget();
527+ QRect cellrect = parent->visualItemRect(item_);
528+ QRect r = QRect(parent->viewport()->mapToGlobal(cellrect.topLeft()), cellrect.size());
529+ properties["globalRect"] = PackProperty(r);
530+
531+ properties["text"] = SafePackProperty(item_->text(0));
532+ properties["columns"] = SafePackProperty(item_->columnCount());
533+ properties["checkState"] = SafePackProperty(item_->checkState(0));
534+
535+ properties["isDisabled"] = SafePackProperty(item_->isDisabled());
536+ properties["isExpanded"] = SafePackProperty(item_->isExpanded());
537+ properties["isFirstColumnSpanned"] = SafePackProperty(item_->isFirstColumnSpanned());
538+ properties["isHidden"] = SafePackProperty(item_->isHidden());
539+ properties["isSelected"] = SafePackProperty(item_->isSelected());
540+
541+ return properties;
542+}
543+
544+xpathselect::Node::Ptr QTreeWidgetItemNode::GetParent() const
545+{
546+ return parent_;
547+}
548+
549+std::string QTreeWidgetItemNode::GetName() const
550+{
551+ return "QTreeWidgetItem";
552+}
553+
554+std::string QTreeWidgetItemNode::GetPath() const
555+{
556+ return full_path_;
557+}
558+
559+int32_t QTreeWidgetItemNode::GetId() const
560+{
561+ return calculate_ap_id(static_cast<quint64>(reinterpret_cast<quintptr>(item_)));
562+}
563+
564+bool QTreeWidgetItemNode::MatchStringProperty(std::string const& name, std::string const& value) const
565+{
566+ return MatchProperty(GetProperties(), name, QString::fromStdString(value));
567+}
568+
569+bool QTreeWidgetItemNode::MatchIntegerProperty(std::string const& name, int32_t value) const
570+{
571+ if (name == "id")
572+ return value == GetId();
573+
574+ return MatchProperty(GetProperties(), name, value);
575+}
576+
577+bool QTreeWidgetItemNode::MatchBooleanProperty(std::string const& name, bool value) const
578+{
579+ return MatchProperty(GetProperties(), name, value);
580+}
581+
582+xpathselect::NodeVector QTreeWidgetItemNode::Children() const
583+{
584+ xpathselect::NodeVector children;
585+
586+ for(int i=0; i < item_->childCount(); ++i) {
587+ children.push_back(
588+ std::make_shared<QTreeWidgetItemNode>(item_->child(i),shared_from_this())
589+ );
590+ }
591+
592+ return children;
593+}
594
595=== modified file 'driver/qtnode.h'
596--- driver/qtnode.h 2014-07-24 23:49:59 +0000
597+++ driver/qtnode.h 2014-07-24 23:49:59 +0000
598@@ -6,6 +6,13 @@
599 #include <QDBusArgument>
600 #include <xpathselect/node.h>
601
602+#include <QModelIndex>
603+
604+class QAbstractItemView;
605+class QTableWidgetItem;
606+class QTreeView;
607+class QTreeWidgetItem;
608+
609 /// A simple data structure representing the state of a single node:
610 struct NodeIntrospectionData
611 {
612@@ -16,8 +23,8 @@
613 Q_DECLARE_METATYPE(NodeIntrospectionData);
614 Q_DECLARE_METATYPE(QList<NodeIntrospectionData>);
615
616-QDBusArgument &operator<<(QDBusArgument &argument, const NodeIntrospectionData &node_data);
617-const QDBusArgument &operator>>(const QDBusArgument &argument, NodeIntrospectionData &node_data);
618+QDBusArgument &operator<<(QDBusArgument &argument, NodeIntrospectionData const& node_data);
619+const QDBusArgument &operator>>(QDBusArgument const& argument, NodeIntrospectionData &node_data);
620
621 // Interface for Introspecting an object to query it's details.
622 class DBusNode : public xpathselect::Node
623@@ -33,7 +40,7 @@
624
625 /// Specialist class for all QObject object nodes.
626 /// This will cover a majority of what we use and we will only need to break
627-/// out to specilist classes for a couple of minor (i.e. QModelIndex)
628+/// out to specialist classes for a couple of minor edge-cases (i.e. QModelIndex)
629 ///
630 /// QObjectNode wraps a single QObject pointer. It derives from
631 /// xpathselect::Node (DBusNode) and, like that class, is designed to be
632@@ -56,9 +63,9 @@
633 virtual std::string GetName() const;
634 virtual std::string GetPath() const;
635 virtual int32_t GetId() const;
636- virtual bool MatchStringProperty(const std::string& name, const std::string& value) const;
637- virtual bool MatchIntegerProperty(const std::string& name, int32_t value) const;
638- virtual bool MatchBooleanProperty(const std::string& name, bool value) const;
639+ virtual bool MatchStringProperty(std::string const& name, std::string const& value) const;
640+ virtual bool MatchIntegerProperty(std::string const& name, int32_t value) const;
641+ virtual bool MatchBooleanProperty(std::string const& name, bool value) const;
642 virtual xpathselect::NodeVector Children() const;
643
644 private:
645@@ -67,4 +74,83 @@
646 DBusNode::Ptr parent_;
647 };
648
649+class QModelIndexNode : public DBusNode, public std::enable_shared_from_this<QModelIndexNode>
650+{
651+public:
652+ QModelIndexNode(QModelIndex index, QAbstractItemView* parent_view, DBusNode::Ptr parent);
653+
654+ // DBusNode
655+ virtual NodeIntrospectionData GetIntrospectionData() const;
656+
657+ // xpathselect::Node
658+ xpathselect::Node::Ptr GetParent() const;
659+ virtual std::string GetName() const;
660+ virtual std::string GetPath() const;
661+ virtual int32_t GetId() const;
662+ virtual bool MatchStringProperty(std::string const& name, std::string const& value) const;
663+ virtual bool MatchIntegerProperty(std::string const& name, int32_t value) const;
664+ virtual bool MatchBooleanProperty(std::string const& name, bool value) const;
665+ virtual xpathselect::NodeVector Children() const;
666+
667+private:
668+ QVariantMap GetProperties() const;
669+
670+ QModelIndex index_;
671+ QAbstractItemView* parent_view_;
672+ std::string full_path_;
673+ DBusNode::Ptr parent_;
674+};
675+
676+class QTableWidgetItemNode : public DBusNode, public std::enable_shared_from_this<QTableWidgetItemNode>
677+{
678+public:
679+ QTableWidgetItemNode(QTableWidgetItem *item, DBusNode::Ptr parent);
680+
681+ // DBusNode
682+ virtual NodeIntrospectionData GetIntrospectionData() const;
683+
684+ // xpathselect::Node
685+ xpathselect::Node::Ptr GetParent() const;
686+ virtual std::string GetName() const;
687+ virtual std::string GetPath() const;
688+ virtual int32_t GetId() const;
689+ virtual bool MatchStringProperty(std::string const& name, std::string const& value) const;
690+ virtual bool MatchIntegerProperty(std::string const& name, int32_t value) const;
691+ virtual bool MatchBooleanProperty(std::string const& name, bool value) const;
692+ virtual xpathselect::NodeVector Children() const;
693+
694+private:
695+ QVariantMap GetProperties() const;
696+
697+ QTableWidgetItem *item_;
698+ std::string full_path_;
699+ DBusNode::Ptr parent_;
700+};
701+
702+class QTreeWidgetItemNode : public DBusNode, public std::enable_shared_from_this<QTreeWidgetItemNode>
703+{
704+public:
705+ QTreeWidgetItemNode(QTreeWidgetItem *item, DBusNode::Ptr parent);
706+
707+ // DBusNode
708+ virtual NodeIntrospectionData GetIntrospectionData() const;
709+
710+ // xpathselect::Node
711+ xpathselect::Node::Ptr GetParent() const;
712+ virtual std::string GetName() const;
713+ virtual std::string GetPath() const;
714+ virtual int32_t GetId() const;
715+ virtual bool MatchStringProperty(std::string const& name, std::string const& value) const;
716+ virtual bool MatchIntegerProperty(std::string const& name, int32_t value) const;
717+ virtual bool MatchBooleanProperty(std::string const& name, bool value) const;
718+ virtual xpathselect::NodeVector Children() const;
719+
720+private:
721+ QVariantMap GetProperties() const;
722+
723+ QTreeWidgetItem *item_;
724+ std::string full_path_;
725+ DBusNode::Ptr parent_;
726+};
727+
728 #endif // QTNODE_H
729
730=== modified file 'tests/unittests/tst_introspection.cpp'
731--- tests/unittests/tst_introspection.cpp 2014-07-24 23:49:59 +0000
732+++ tests/unittests/tst_introspection.cpp 2014-07-24 23:49:59 +0000
733@@ -1,5 +1,5 @@
734 /*
735- * Copyright (C) 2013 Canonical, Ltd.
736+ * Copyright (C) 2013-2014 Canonical, Ltd.
737 *
738 * Authors:
739 * Michael Zanetti <michael.zanetti@canonical.com>
740@@ -25,35 +25,13 @@
741 #include <QGridLayout>
742 #include <QPushButton>
743
744+#include "tst_introspection.h"
745+
746 #include "introspection.h"
747 #include "qtnode.h"
748
749 QVariant IntrospectNode(QObject* obj);
750
751-class tst_Introspection : public QObject
752-{
753- Q_OBJECT
754-
755-private slots:
756- void initTestCase();
757- void cleanupTestCase();
758-
759- void test_introspect_data();
760- void test_introspect();
761-
762- void test_application_names_data();
763- void test_application_names();
764-
765- void test_properties_data();
766- void test_properties();
767-
768- void test_property_matching();
769-
770-private:
771- QMainWindow *m_object;
772-};
773-
774-
775 void tst_Introspection::initTestCase()
776 {
777 QApplication::setApplicationName("tst_introspection");
778@@ -510,7 +488,3 @@
779 QVERIFY(n.MatchIntegerProperty("myUInt", 5) == true);
780 QVERIFY(n.MatchBooleanProperty("visible", true) == true);
781 }
782-
783-QTEST_MAIN(tst_Introspection)
784-
785-#include "tst_introspection.moc"
786
787=== added file 'tests/unittests/tst_introspection.h'
788--- tests/unittests/tst_introspection.h 1970-01-01 00:00:00 +0000
789+++ tests/unittests/tst_introspection.h 2014-07-24 23:49:59 +0000
790@@ -0,0 +1,44 @@
791+/*
792+ * Copyright (C) 2014 Canonical, Ltd.
793+ *
794+ * Authors:
795+ * Christopher Lee <chris.lee@canonical.com>
796+ *
797+ * This program is free software; you can redistribute it and/or modify
798+ * it under the terms of the GNU General Public License as published by
799+ * the Free Software Foundation; version 3.
800+ *
801+ * This program is distributed in the hope that it will be useful,
802+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
803+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
804+ * GNU General Public License for more details.
805+ *
806+ * You should have received a copy of the GNU General Public License
807+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
808+ *
809+ */
810+
811+#include <QMainWindow>
812+
813+class tst_Introspection : public QObject
814+{
815+ Q_OBJECT
816+
817+private slots:
818+ void initTestCase();
819+ void cleanupTestCase();
820+
821+ void test_introspect_data();
822+ void test_introspect();
823+
824+ void test_application_names_data();
825+ void test_application_names();
826+
827+ void test_properties_data();
828+ void test_properties();
829+
830+ void test_property_matching();
831+
832+private:
833+ QMainWindow *m_object;
834+};
835
836=== added file 'tests/unittests/tst_main.cpp'
837--- tests/unittests/tst_main.cpp 1970-01-01 00:00:00 +0000
838+++ tests/unittests/tst_main.cpp 2014-07-24 23:49:59 +0000
839@@ -0,0 +1,30 @@
840+/*
841+ * Copyright (C) 2014 Canonical, Ltd.
842+ *
843+ * This program is free software; you can redistribute it and/or modify
844+ * it under the terms of the GNU General Public License as published by
845+ * the Free Software Foundation; version 3.
846+ *
847+ * This program is distributed in the hope that it will be useful,
848+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
849+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
850+ * GNU General Public License for more details.
851+ *
852+ * You should have received a copy of the GNU General Public License
853+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
854+ *
855+ */
856+
857+#include <QTest>
858+
859+#include "tst_qtnode.h"
860+#include "tst_introspection.h"
861+
862+int main(int argc, char *argv[])
863+{
864+ QApplication app(argc, argv);
865+
866+ tst_Introspection introspection_tc;
867+ tst_qtnode qtnode_tc;
868+ return QTest::qExec(&introspection_tc, argc, argv) || QTest::qExec(&qtnode_tc, argc, argv);
869+}
870
871=== added file 'tests/unittests/tst_qtnode.cpp'
872--- tests/unittests/tst_qtnode.cpp 1970-01-01 00:00:00 +0000
873+++ tests/unittests/tst_qtnode.cpp 2014-07-24 23:49:59 +0000
874@@ -0,0 +1,345 @@
875+/*
876+ * Copyright (C) 2014 Canonical, Ltd.
877+ *
878+ * Authors:
879+ * Christopher Lee <chris.lee@canonical.com>
880+ *
881+ * This program is free software; you can redistribute it and/or modify
882+ * it under the terms of the GNU General Public License as published by
883+ * the Free Software Foundation; version 3.
884+ *
885+ * This program is distributed in the hope that it will be useful,
886+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
887+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
888+ * GNU General Public License for more details.
889+ *
890+ * You should have received a copy of the GNU General Public License
891+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
892+ *
893+ */
894+
895+#include <QtTest>
896+
897+#include <QTreeView>
898+#include <QTreeWidget>
899+#include <QTableWidget>
900+#include <QListView>
901+#include <QModelIndex>
902+#include <QStandardItemModel>
903+
904+#include "tst_qtnode.h"
905+
906+#include "introspection.h"
907+#include "qtnode.h"
908+
909+int32_t calculate_ap_id(quint64 big_id);
910+void CollectSpecialChildren(QObject* object, xpathselect::NodeVector& children, DBusNode::Ptr parent);
911+void CollectAllIndices(QModelIndex index, QAbstractItemModel *model, QModelIndexList &collection);
912+bool MatchProperty(const QVariantMap& packed_properties, const std::string& name, QVariant value);
913+
914+void GetDataElementChildren(QTableWidget* table, xpathselect::NodeVector& children, DBusNode::Ptr parent);
915+void GetDataElementChildren(QTreeView* tree_view, xpathselect::NodeVector& children, DBusNode::Ptr parent);
916+void GetDataElementChildren(QTreeWidget* tree_widget, xpathselect::NodeVector& children, DBusNode::Ptr parent);
917+void GetDataElementChildren(QListView* list_view, xpathselect::NodeVector& children, DBusNode::Ptr parent);
918+
919+
920+void tst_qtnode::initTestCase()
921+{
922+ QApplication::setApplicationName("tst_qtnode");
923+}
924+
925+void tst_qtnode::test_calculate_ap_id_data()
926+{
927+ QTest::addColumn<quint64>("id");
928+ QTest::addColumn<int32_t>("expected_result");
929+
930+ QTest::newRow("1") << Q_UINT64_C(0xFFFFFFFF) << int(0xFFFFFFFF);
931+ QTest::newRow("2") << Q_UINT64_C(0x00000000FFFFFFFF) << int(0xFFFFFFFF);
932+ QTest::newRow("3") << Q_UINT64_C(0xFFFFFFFFFFFFFFFF) << int(0x0);
933+ QTest::newRow("4") << Q_UINT64_C(0x0F0F0F0F0F0F0F0F) << int(0x0);
934+ QTest::newRow("5") << Q_UINT64_C(0xF0F0F0FF0F0F0F0) << int(0xFFFFFFFF);
935+ QTest::newRow("6") << Q_UINT64_C(0xF0F0F0F0FFFFFFFF) << int(0xF0F0F0F);
936+}
937+
938+void tst_qtnode::test_calculate_ap_id()
939+{
940+ QFETCH(quint64, id);
941+ QFETCH(int32_t, expected_result);
942+
943+ QCOMPARE(calculate_ap_id(id), expected_result);
944+}
945+
946+void tst_qtnode::test_CollectAllIndices_collects_all_table_data()
947+{
948+ int row_count = 2;
949+ int col_count = 2;
950+ testModel = std::make_shared<QStandardItemModel>(row_count, col_count);
951+
952+ for (int row = 0; row < row_count; ++row) {
953+ for (int column = 0; column < col_count; ++column) {
954+ QStandardItem *item = new QStandardItem(
955+ QString("row %0, column %1").arg(row).arg(column));
956+ testModel->setItem(row, column, item);
957+ }
958+ }
959+}
960+
961+void tst_qtnode::test_CollectAllIndices_collects_all_table()
962+{
963+ QModelIndexList collection;
964+ QStandardItem *root_item = testModel->invisibleRootItem();
965+ CollectAllIndices(root_item->index(), testModel.get(), collection);
966+
967+ QCOMPARE(collection.size(), 4);
968+}
969+
970+void tst_qtnode::test_CollectAllIndices_collects_all_list_data()
971+{
972+ int listitem_count = 4;
973+ testModel = std::make_shared<QStandardItemModel>();
974+ QStandardItem *parentItem = testModel->invisibleRootItem();
975+ for (int i = 0; i < listitem_count; ++i) {
976+ QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
977+ parentItem->appendRow(item);
978+ parentItem = item;
979+ }
980+}
981+
982+void tst_qtnode::test_CollectAllIndices_collects_all_list()
983+{
984+ QModelIndexList collection;
985+ QStandardItem *root_item = testModel->invisibleRootItem();
986+ CollectAllIndices(root_item->index(), testModel.get(), collection);
987+
988+ QCOMPARE(collection.size(), 4);
989+}
990+
991+Q_DECLARE_METATYPE(std::string)
992+void tst_qtnode::test_MatchProperty_data()
993+{
994+ QTest::addColumn<QVariantMap>("packedProperties");
995+ QTest::addColumn<std::string>("name");
996+ QTest::addColumn<QVariant>("value");
997+ QTest::addColumn<bool>("expectedResult");
998+
999+ QVariantMap p;
1000+ p["string"] = PackProperty(QVariant("string"));
1001+ p["int"] = PackProperty(QVariant(1));
1002+ p["bool"] = PackProperty(QVariant(true));
1003+
1004+ QTest::newRow("Matches string") << p << std::string("string") << QVariant("string") << true;
1005+ QTest::newRow("Matches int") << p << std::string("int") << QVariant(1) << true;
1006+ QTest::newRow("Matches bool") << p << std::string("bool") << QVariant(true) << true;
1007+
1008+ QTest::newRow("Fails not present") << p << std::string("notpresent") << QVariant("string") << false;
1009+ QTest::newRow("Fails values do not match")
1010+ << p
1011+ << std::string("string")
1012+ << QVariant("notstring")
1013+ << false;
1014+}
1015+
1016+void tst_qtnode::test_MatchProperty()
1017+{
1018+ QFETCH(QVariantMap, packedProperties);
1019+ QFETCH(std::string, name);
1020+ QFETCH(QVariant, value);
1021+ QFETCH(bool, expectedResult);
1022+
1023+ QCOMPARE(MatchProperty(packedProperties, name, value), expectedResult);
1024+}
1025+
1026+void tst_qtnode::populate_QTreeView_with_data()
1027+{
1028+ testModel = std::make_shared<QStandardItemModel>();
1029+ testModel->setColumnCount(1);
1030+ testModel->setRowCount(5);
1031+ testModel->setData(testModel->index(0, 0), "test0");
1032+ testModel->setData(testModel->index(1, 0), "test1");
1033+ testModel->setData(testModel->index(2, 0), "test2");
1034+ testModel->setData(testModel->index(3, 0), "test3");
1035+ testModel->setData(testModel->index(4, 0), "test4");
1036+
1037+ treeView = std::make_shared<QTreeView>();
1038+ treeView->setModel(testModel.get());
1039+}
1040+
1041+void tst_qtnode::populate_QTreeWidget_with_data()
1042+{
1043+ treeWidget = std::make_shared<QTreeWidget>();
1044+ treeWidget->setColumnCount(1);
1045+ QList<QTreeWidgetItem *> items;
1046+ for (int i = 0; i < 5; ++i)
1047+ items.append(new QTreeWidgetItem());
1048+ treeWidget->insertTopLevelItems(0, items);
1049+}
1050+
1051+void tst_qtnode::populate_QListView_with_data()
1052+{
1053+ testModel = std::make_shared<QStandardItemModel>();
1054+ testModel->setColumnCount(1);
1055+ testModel->setRowCount(5);
1056+ testModel->setData(testModel->index(0, 0), "test0");
1057+ testModel->setData(testModel->index(1, 0), "test1");
1058+ testModel->setData(testModel->index(2, 0), "test2");
1059+ testModel->setData(testModel->index(3, 0), "test3");
1060+ testModel->setData(testModel->index(4, 0), "test4");
1061+
1062+ listView = std::make_shared<QListView>();
1063+ listView->setModel(testModel.get());
1064+}
1065+
1066+void tst_qtnode::populate_QTableWidget_with_data()
1067+{
1068+ tableWidget = std::make_shared<QTableWidget>();
1069+ tableWidget->setRowCount(4);
1070+ tableWidget->setColumnCount(2);
1071+
1072+ for (int row = 0; row < 4; ++row) {
1073+ for (int column = 0; column < 2; ++column) {
1074+ tableWidget->setItem(row, column, new QTableWidgetItem());
1075+ }
1076+ }
1077+}
1078+
1079+void tst_qtnode::test_GetDataElementChildren_QTreeView_collects_all_data()
1080+{
1081+ populate_QTreeView_with_data();
1082+}
1083+
1084+void tst_qtnode::test_GetDataElementChildren_QTreeView_collects_all()
1085+{
1086+ xpathselect::NodeVector children;
1087+ DBusNode::Ptr parent;
1088+
1089+ GetDataElementChildren(treeView.get(), children, parent);
1090+
1091+ QCOMPARE((int)children.size(), 5);
1092+
1093+ auto node_parent = children[0]->GetParent();
1094+ QVERIFY(node_parent == parent);
1095+}
1096+
1097+void tst_qtnode::test_GetDataElementChildren_QTreeWidget_collects_all_data()
1098+{
1099+ populate_QTreeWidget_with_data();
1100+}
1101+
1102+void tst_qtnode::test_GetDataElementChildren_QTreeWidget_collects_all()
1103+{
1104+ xpathselect::NodeVector children;
1105+ DBusNode::Ptr parent;
1106+ GetDataElementChildren(treeWidget.get(), children, parent);
1107+
1108+ QCOMPARE((int)children.size(), 5);
1109+
1110+ auto node_parent = children[0]->GetParent();
1111+ QVERIFY(node_parent == parent);
1112+}
1113+
1114+void tst_qtnode::test_GetDataElementChildren_QListView_collects_all_data()
1115+{
1116+ populate_QListView_with_data();
1117+}
1118+
1119+void tst_qtnode::test_GetDataElementChildren_QListView_collects_all()
1120+{
1121+ xpathselect::NodeVector children;
1122+ DBusNode::Ptr parent;
1123+
1124+ GetDataElementChildren(listView.get(), children, parent);
1125+
1126+ QCOMPARE((int)children.size(), 5);
1127+
1128+ auto node_parent = children[0]->GetParent();
1129+ QVERIFY(node_parent == parent);
1130+}
1131+
1132+void tst_qtnode::test_GetDataElementChildren_QTableWidget_collects_all_data()
1133+{
1134+ populate_QTableWidget_with_data();
1135+}
1136+
1137+void tst_qtnode::test_GetDataElementChildren_QTableWidget_collects_all()
1138+{
1139+ xpathselect::NodeVector children;
1140+ DBusNode::Ptr parent;
1141+
1142+ GetDataElementChildren(tableWidget.get(), children, parent);
1143+
1144+ QCOMPARE((int)children.size(), 8);
1145+
1146+ auto node_parent = children[0]->GetParent();
1147+ QVERIFY(node_parent == parent);
1148+}
1149+
1150+void tst_qtnode::test_CollectSpecialChildren_QTreeView_collects_all_data()
1151+{
1152+ populate_QTreeView_with_data();
1153+}
1154+
1155+void tst_qtnode::test_CollectSpecialChildren_QTreeView_collects_all()
1156+{
1157+ xpathselect::NodeVector children;
1158+ DBusNode::Ptr parent;
1159+
1160+ CollectSpecialChildren(treeView.get(), children, parent);
1161+
1162+ QCOMPARE((int)children.size(), 5);
1163+}
1164+
1165+void tst_qtnode::test_CollectSpecialChildren_QTreeWidget_collects_all_data()
1166+{
1167+ populate_QTreeWidget_with_data();
1168+}
1169+
1170+void tst_qtnode::test_CollectSpecialChildren_QTreeWidget_collects_all()
1171+{
1172+ xpathselect::NodeVector children;
1173+ DBusNode::Ptr parent;
1174+
1175+ CollectSpecialChildren(treeWidget.get(), children, parent);
1176+
1177+ QCOMPARE((int)children.size(), 5);
1178+}
1179+
1180+void tst_qtnode::test_CollectSpecialChildren_QListView_collects_all_data()
1181+{
1182+ populate_QListView_with_data();
1183+}
1184+
1185+void tst_qtnode::test_CollectSpecialChildren_QListView_collects_all()
1186+{
1187+ xpathselect::NodeVector children;
1188+ DBusNode::Ptr parent;
1189+
1190+ CollectSpecialChildren(listView.get(), children, parent);
1191+
1192+ QCOMPARE((int)children.size(), 5);
1193+}
1194+
1195+void tst_qtnode::test_CollectSpecialChildren_QTableWidget_collects_all_data()
1196+{
1197+ populate_QTableWidget_with_data();
1198+}
1199+
1200+void tst_qtnode::test_CollectSpecialChildren_QTableWidget_collects_all()
1201+{
1202+ xpathselect::NodeVector children;
1203+ DBusNode::Ptr parent;
1204+
1205+ CollectSpecialChildren(tableWidget.get(), children, parent);
1206+
1207+ QCOMPARE((int)children.size(), 8);
1208+}
1209+
1210+void tst_qtnode::test_CollectSpecialChildren_QObject_collects_nothing()
1211+{
1212+ xpathselect::NodeVector children;
1213+ DBusNode::Ptr parent;
1214+ std::shared_ptr<QObject> testObject = std::make_shared<QObject>();
1215+
1216+ CollectSpecialChildren(testObject.get(), children, parent);
1217+
1218+ QCOMPARE((int)children.size(), 0);
1219+}
1220
1221=== added file 'tests/unittests/tst_qtnode.h'
1222--- tests/unittests/tst_qtnode.h 1970-01-01 00:00:00 +0000
1223+++ tests/unittests/tst_qtnode.h 2014-07-24 23:49:59 +0000
1224@@ -0,0 +1,78 @@
1225+/*
1226+ * Copyright (C) 2014 Canonical, Ltd.
1227+ *
1228+ * Authors:
1229+ * Christopher Lee <chris.lee@canonical.com>
1230+ *
1231+ * This program is free software; you can redistribute it and/or modify
1232+ * it under the terms of the GNU General Public License as published by
1233+ * the Free Software Foundation; version 3.
1234+ *
1235+ * This program is distributed in the hope that it will be useful,
1236+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1237+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1238+ * GNU General Public License for more details.
1239+ *
1240+ * You should have received a copy of the GNU General Public License
1241+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1242+ *
1243+ */
1244+
1245+#include <memory>
1246+
1247+#include <QObject>
1248+
1249+class QStandardItemModel;
1250+class QStandardItemModel;
1251+class QTreeWidget;
1252+class QListView;
1253+class QTreeView;
1254+class QTableWidget;
1255+
1256+class tst_qtnode: public QObject
1257+{
1258+ Q_OBJECT
1259+
1260+private slots:
1261+ void initTestCase();
1262+ void test_calculate_ap_id_data();
1263+ void test_calculate_ap_id();
1264+
1265+ void test_CollectAllIndices_collects_all_table_data();
1266+ void test_CollectAllIndices_collects_all_table();
1267+ void test_CollectAllIndices_collects_all_list_data();
1268+ void test_CollectAllIndices_collects_all_list();
1269+
1270+ void test_MatchProperty_data();
1271+ void test_MatchProperty();
1272+
1273+ void populate_QTreeView_with_data();
1274+ void populate_QTreeWidget_with_data();
1275+ void populate_QListView_with_data();
1276+ void populate_QTableWidget_with_data();
1277+
1278+ void test_GetDataElementChildren_QTreeView_collects_all_data();
1279+ void test_GetDataElementChildren_QTreeView_collects_all();
1280+ void test_GetDataElementChildren_QTreeWidget_collects_all_data();
1281+ void test_GetDataElementChildren_QTreeWidget_collects_all();
1282+ void test_GetDataElementChildren_QListView_collects_all_data();
1283+ void test_GetDataElementChildren_QListView_collects_all();
1284+ void test_GetDataElementChildren_QTableWidget_collects_all_data();
1285+ void test_GetDataElementChildren_QTableWidget_collects_all();
1286+
1287+ void test_CollectSpecialChildren_QTreeView_collects_all_data();
1288+ void test_CollectSpecialChildren_QTreeView_collects_all();
1289+ void test_CollectSpecialChildren_QTreeWidget_collects_all_data();
1290+ void test_CollectSpecialChildren_QTreeWidget_collects_all();
1291+ void test_CollectSpecialChildren_QListView_collects_all_data();
1292+ void test_CollectSpecialChildren_QListView_collects_all();
1293+ void test_CollectSpecialChildren_QTableWidget_collects_all_data();
1294+ void test_CollectSpecialChildren_QTableWidget_collects_all();
1295+ void test_CollectSpecialChildren_QObject_collects_nothing();
1296+private:
1297+ std::shared_ptr<QStandardItemModel> testModel;
1298+ std::shared_ptr<QTreeWidget> treeWidget;
1299+ std::shared_ptr<QListView> listView;
1300+ std::shared_ptr<QTreeView> treeView;
1301+ std::shared_ptr<QTableWidget> tableWidget;
1302+};
1303
1304=== modified file 'tests/unittests/unittests.pro'
1305--- tests/unittests/unittests.pro 2013-08-29 02:36:52 +0000
1306+++ tests/unittests/unittests.pro 2014-07-24 23:49:59 +0000
1307@@ -1,7 +1,7 @@
1308 #include(../../coverage.pri)
1309
1310 CONFIG += testcase
1311-TARGET = tst_introspection
1312+TARGET = tst_libautopilot-qt
1313
1314 QT += testlib dbus widgets quick
1315
1316@@ -16,12 +16,16 @@
1317 INCLUDEPATH += ../../driver
1318
1319 SOURCES += \
1320+ tst_main.cpp \
1321+ tst_qtnode.cpp \
1322 tst_introspection.cpp \
1323 ../../driver/introspection.cpp \
1324 ../../driver/rootnode.cpp \
1325 ../../driver/qtnode.cpp
1326
1327 HEADERS += \
1328+ tst_qtnode.h \
1329+ tst_introspection.h \
1330 ../../driver/introspection.h \
1331 ../../driver/rootnode.h \
1332 ../../driver/qtnode.h

Subscribers

People subscribed via source and target branches