Merge lp:~veebers/autopilot-qt/enable-datamodel-elements-add-new-nodes into lp:autopilot-qt
- enable-datamodel-elements-add-new-nodes
- Merge into trunk
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 |
Related bugs: |
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:93
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:95
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Hi,
There's still a few things that need to be cleaned up - see diff comments below.
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Just one comment, but I haven't given it an in-depth review.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:109
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Leo Arias (elopio) wrote : | # |
27 +inline int32_t calclulate_
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[
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.
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Looks good, except for comments made in the diff and on IRC.
[09:59:27] <veebers> thomi: sure, https:/
[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 GetDataElementC
[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: "QModelIndexNod
[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...
- 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
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
LGTM
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:121
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 122. By Christopher Lee
-
Remove inline from calculate_ap_id
Preview Diff
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 |
PASSED: Continuous integration, rev:87 jenkins. qa.ubuntu. com/job/ autopilot- qt-ci/16/ jenkins. qa.ubuntu. com/job/ autopilot- qt-utopic- amd64-ci/ 1 jenkins. qa.ubuntu. com/job/ autopilot- qt-utopic- armhf-ci/ 1 jenkins. qa.ubuntu. com/job/ autopilot- qt-utopic- armhf-ci/ 1/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ autopilot- qt-utopic- i386-ci/ 1
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/autopilot- qt-ci/16/ rebuild
http://