Merge lp:~brandontschaefer/unity/remove-rev-3098 into lp:unity
- remove-rev-3098
- Merge into trunk
Proposed by
Brandon Schaefer
Status: | Merged |
---|---|
Approved by: | Andrea Azzarone |
Approved revision: | no longer in the source branch. |
Merged at revision: | 3100 |
Proposed branch: | lp:~brandontschaefer/unity/remove-rev-3098 |
Merge into: | lp:unity |
Diff against target: |
1045 lines (+724/-180) 8 files modified
debian/control (+5/-7) tests/CMakeLists.txt (+1/-0) tests/test_introspection.cpp (+356/-0) unity-shared/CMakeLists.txt (+1/-0) unity-shared/DebugDBusInterface.cpp (+128/-173) unity-shared/DebugDBusInterface.h (+2/-0) unity-shared/XPathQueryPart.cpp (+186/-0) unity-shared/XPathQueryPart.h (+45/-0) |
To merge this branch: | bzr merge lp:~brandontschaefer/unity/remove-rev-3098 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrea Azzarone (community) | Approve | ||
PS Jenkins bot | continuous-integration | Pending | |
Review via email: mp+146221@code.launchpad.net |
Commit message
This is causing problem with all the AP tests...ie. Every single AP was failing.
Description of the change
This is causing problem with all the AP tests...ie. Every single AP was failing.
To post a comment you must log in.
Revision history for this message
Andrea Azzarone (azzar1) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/control' |
2 | --- debian/control 2013-02-01 17:01:09 +0000 |
3 | +++ debian/control 2013-02-01 20:35:26 +0000 |
4 | @@ -43,7 +43,6 @@ |
5 | libxfixes-dev (>= 1:5.0-4ubuntu4), |
6 | libgtest-dev, |
7 | google-mock, |
8 | - libxpathselect-dev, |
9 | Standards-Version: 3.9.3 |
10 | Homepage: https://launchpad.net/unity |
11 | # If you aren't a member of ~unity-team but need to upload packaging changes, |
12 | @@ -168,7 +167,6 @@ |
13 | Architecture: all |
14 | Depends: ${misc:Depends}, |
15 | ${python:Depends}, |
16 | - libxpathselect1.1, |
17 | Description: Autopiloted tests for Unity |
18 | We test Unity automatically through autopilot, a framework which enables us |
19 | to trigger keyboard and mouse events on the fly as well as introspecting |
20 | @@ -187,7 +185,7 @@ |
21 | Depends: unity, ${misc:Depends} |
22 | Architecture: all |
23 | Section: oldlibs |
24 | -Description: transitional dummy package |
25 | +Description: transitional dummy package |
26 | This is a transitional dummy package for unity-2d -> unity migration. |
27 | It can safely be removed. |
28 | |
29 | @@ -195,7 +193,7 @@ |
30 | Depends: unity, ${misc:Depends} |
31 | Architecture: all |
32 | Section: oldlibs |
33 | -Description: transitional dummy package |
34 | +Description: transitional dummy package |
35 | This is a transitional dummy package for unity-2d -> unity migration. |
36 | It can safely be removed. |
37 | |
38 | @@ -203,7 +201,7 @@ |
39 | Depends: unity, ${misc:Depends} |
40 | Architecture: all |
41 | Section: oldlibs |
42 | -Description: transitional dummy package |
43 | +Description: transitional dummy package |
44 | This is a transitional dummy package for unity-2d -> unity migration. |
45 | It can safely be removed. |
46 | |
47 | @@ -211,7 +209,7 @@ |
48 | Depends: unity, ${misc:Depends} |
49 | Architecture: all |
50 | Section: oldlibs |
51 | -Description: transitional dummy package |
52 | +Description: transitional dummy package |
53 | This is a transitional dummy package for unity-2d -> unity migration. |
54 | It can safely be removed. |
55 | |
56 | @@ -219,7 +217,7 @@ |
57 | Depends: unity, ${misc:Depends} |
58 | Architecture: all |
59 | Section: oldlibs |
60 | -Description: transitional dummy package |
61 | +Description: transitional dummy package |
62 | This is a transitional dummy package for unity-2d -> unity migration. |
63 | It can safely be removed. |
64 | |
65 | |
66 | === modified file 'tests/CMakeLists.txt' |
67 | --- tests/CMakeLists.txt 2013-02-01 17:01:09 +0000 |
68 | +++ tests/CMakeLists.txt 2013-02-01 20:35:26 +0000 |
69 | @@ -112,6 +112,7 @@ |
70 | test_indicator_appmenu.cpp |
71 | test_indicator_entry.cpp |
72 | test_indicators.cpp |
73 | + test_introspection.cpp |
74 | test_favorite_store.cpp |
75 | test_favorite_store_gsettings.cpp |
76 | test_favorite_store_private.cpp |
77 | |
78 | === added file 'tests/test_introspection.cpp' |
79 | --- tests/test_introspection.cpp 1970-01-01 00:00:00 +0000 |
80 | +++ tests/test_introspection.cpp 2013-02-01 20:35:26 +0000 |
81 | @@ -0,0 +1,356 @@ |
82 | +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
83 | +/* |
84 | + * Copyright (C) 2010 Canonical Ltd |
85 | + * |
86 | + * This program is free software: you can redistribute it and/or modify |
87 | + * it under the terms of the GNU General Public License version 3 as |
88 | + * published by the Free Software Foundation. |
89 | + * |
90 | + * This program is distributed in the hope that it will be useful, |
91 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
92 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
93 | + * GNU General Public License for more details. |
94 | + * |
95 | + * You should have received a copy of the GNU General Public License |
96 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
97 | + * |
98 | + * Authored by: Thomi Richards <thomi.richards@canonical.com> |
99 | + */ |
100 | +#include <gtest/gtest.h> |
101 | +#include <glib.h> |
102 | +#include <memory> |
103 | +#include <boost/foreach.hpp> |
104 | + |
105 | +#include "Introspectable.h" |
106 | +#include "DebugDBusInterface.h" |
107 | + |
108 | + |
109 | +using namespace unity::debug; |
110 | + |
111 | +class MockIntrospectable : public Introspectable |
112 | +{ |
113 | +public: |
114 | + MockIntrospectable(std::string const& name) |
115 | + : name_(name) |
116 | + {} |
117 | + |
118 | + std::string GetName() const |
119 | + { |
120 | + return name_; |
121 | + } |
122 | + void AddProperties(GVariantBuilder* builder) |
123 | + { |
124 | + g_variant_builder_add (builder, "{sv}", "Name", g_variant_new_string (name_.c_str()) ); |
125 | + g_variant_builder_add (builder, "{sv}", "SomeProperty", g_variant_new_string ("SomeValue") ); |
126 | + g_variant_builder_add (builder, "{sv}", "BoolPropertyTrue", g_variant_new_boolean (TRUE) ); |
127 | + g_variant_builder_add (builder, "{sv}", "BoolPropertyFalse", g_variant_new_boolean (FALSE) ); |
128 | + // 8-bit integer types: |
129 | + g_variant_builder_add (builder, "{sv}", "BytePropertyPos", g_variant_new_byte (12) ); |
130 | + // 16-bit integer types: |
131 | + g_variant_builder_add (builder, "{sv}", "Int16PropertyPos", g_variant_new_int16 (1012) ); |
132 | + g_variant_builder_add (builder, "{sv}", "Int16PropertyNeg", g_variant_new_int16 (-1034) ); |
133 | + g_variant_builder_add (builder, "{sv}", "UInt16PropertyPos", g_variant_new_uint16 (1056) ); |
134 | + // 32-bit integer types: |
135 | + g_variant_builder_add (builder, "{sv}", "Int32PropertyPos", g_variant_new_int32 (100012) ); |
136 | + g_variant_builder_add (builder, "{sv}", "Int32PropertyNeg", g_variant_new_int32 (-100034) ); |
137 | + g_variant_builder_add (builder, "{sv}", "UInt32PropertyPos", g_variant_new_uint32 (100056) ); |
138 | + // 64-bit integer types |
139 | + g_variant_builder_add (builder, "{sv}", "Int64PropertyPos", g_variant_new_int32 (100000012) ); |
140 | + g_variant_builder_add (builder, "{sv}", "Int64PropertyNeg", g_variant_new_int32 (-100000034) ); |
141 | + g_variant_builder_add (builder, "{sv}", "UInt64PropertyPos", g_variant_new_uint32 (100000056) ); |
142 | + |
143 | + } |
144 | +private: |
145 | + std::string name_; |
146 | +}; |
147 | + |
148 | +class TestIntrospection : public ::testing::Test |
149 | +{ |
150 | +public: |
151 | + TestIntrospection() |
152 | + : root_(new MockIntrospectable("Unity")), |
153 | + dc_(new MockIntrospectable("DashController")), |
154 | + pc_(new MockIntrospectable("PanelController")), |
155 | + foo1_(new MockIntrospectable("Foo")), |
156 | + foo2_(new MockIntrospectable("Foo")), |
157 | + foo3_(new MockIntrospectable("Foo")) |
158 | + { |
159 | + root_->AddChild(dc_.get()); |
160 | + root_->AddChild(pc_.get()); |
161 | + dc_->AddChild(foo1_.get()); |
162 | + dc_->AddChild(foo2_.get()); |
163 | + dc_->AddChild(foo3_.get()); |
164 | + |
165 | + //root_->SetProperty(g_variant_new("{sv}", "SomeProperty", g_variant_new_string("SomeValue"))); |
166 | + } |
167 | + |
168 | +protected: |
169 | + std::shared_ptr<MockIntrospectable> root_; |
170 | + std::shared_ptr<MockIntrospectable> dc_; |
171 | + std::shared_ptr<MockIntrospectable> pc_; |
172 | + std::shared_ptr<MockIntrospectable> foo1_; |
173 | + std::shared_ptr<MockIntrospectable> foo2_; |
174 | + std::shared_ptr<MockIntrospectable> foo3_; |
175 | + |
176 | +}; |
177 | + |
178 | +TEST_F(TestIntrospection, TestTest) |
179 | +{ |
180 | + ASSERT_STREQ("Unity", root_->GetName().c_str()); |
181 | +} |
182 | + |
183 | +TEST_F(TestIntrospection, TestVariousRootQueries) |
184 | +{ |
185 | + std::list<Introspectable*> results; |
186 | + std::string query; |
187 | + |
188 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
189 | + ASSERT_EQ(1, results.size()); |
190 | + EXPECT_STREQ("Unity", results.front()->GetName().c_str()); |
191 | + |
192 | + query = "/"; |
193 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
194 | + ASSERT_EQ(1, results.size()); |
195 | + EXPECT_STREQ("Unity", results.front()->GetName().c_str()); |
196 | + |
197 | + query = "/Unity"; |
198 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
199 | + ASSERT_EQ(1, results.size()); |
200 | + EXPECT_STREQ("Unity", results.front()->GetName().c_str()); |
201 | +} |
202 | + |
203 | +TEST_F(TestIntrospection, TestAsteriskWildcard) |
204 | +{ |
205 | + std::list<Introspectable*> results; |
206 | + std::string query = "/Unity/*"; |
207 | + |
208 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
209 | + ASSERT_EQ(2, results.size()); |
210 | + |
211 | + for(auto p : results) |
212 | + { |
213 | + ASSERT_TRUE( |
214 | + p->GetName() == "DashController" || |
215 | + p->GetName() == "PanelController" |
216 | + ); |
217 | + } |
218 | +} |
219 | + |
220 | +TEST_F(TestIntrospection, TestRelativeAsteriskWildcard) |
221 | +{ |
222 | + std::list<Introspectable*> results; |
223 | + std::string query = "//DashController/*"; |
224 | + |
225 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
226 | + ASSERT_EQ(3, results.size()); |
227 | + |
228 | + for(auto p : results) |
229 | + { |
230 | + ASSERT_TRUE(p->GetName() == "Foo"); |
231 | + } |
232 | +} |
233 | + |
234 | +TEST_F(TestIntrospection, TestAbsoluteQueries) |
235 | +{ |
236 | + std::list<Introspectable*> results; |
237 | + std::string query = "/Unity/DashController"; |
238 | + |
239 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
240 | + ASSERT_EQ(1, results.size()); |
241 | + EXPECT_STREQ("DashController", results.front()->GetName().c_str()); |
242 | +} |
243 | + |
244 | +TEST_F(TestIntrospection, TestMalformedRelativeQueries) |
245 | +{ |
246 | + std::list<Introspectable*> results; |
247 | + std::string query = "Unity"; |
248 | + |
249 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
250 | + ASSERT_EQ(1, results.size()); |
251 | + EXPECT_STREQ("Unity", results.front()->GetName().c_str()); |
252 | + |
253 | + query = "Foo"; |
254 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
255 | + ASSERT_EQ(3, results.size()); |
256 | + for(auto p : results) |
257 | + { |
258 | + EXPECT_STREQ("Foo", p->GetName().c_str()); |
259 | + } |
260 | +} |
261 | + |
262 | +TEST_F(TestIntrospection, TestSimpleRelativeQueries) |
263 | +{ |
264 | + std::list<Introspectable*> results; |
265 | + std::string query = "//Unity"; |
266 | + |
267 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
268 | + ASSERT_EQ(1, results.size()); |
269 | + EXPECT_STREQ("Unity", results.front()->GetName().c_str()); |
270 | + |
271 | + query = "//Foo"; |
272 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
273 | + ASSERT_EQ(3, results.size()); |
274 | + for(auto p : results) |
275 | + { |
276 | + EXPECT_STREQ("Foo", p->GetName().c_str()); |
277 | + } |
278 | +} |
279 | + |
280 | +TEST_F(TestIntrospection, TestComplexRelativeQueries) |
281 | +{ |
282 | + std::list<Introspectable*> results; |
283 | + std::string query = "//DashController/Foo"; |
284 | + |
285 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
286 | + ASSERT_EQ(3, results.size()); |
287 | + for(auto p : results) |
288 | + { |
289 | + EXPECT_STREQ("Foo", p->GetName().c_str()); |
290 | + } |
291 | +} |
292 | + |
293 | +TEST_F(TestIntrospection, TestQueriesWithNoResults) |
294 | +{ |
295 | + std::list<Introspectable*> results; |
296 | + std::string query = "//Does/Not/Exist"; |
297 | + |
298 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
299 | + ASSERT_EQ(0, results.size()); |
300 | + |
301 | + query = "DoesNotEverExist"; |
302 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
303 | + ASSERT_EQ(0, results.size()); |
304 | + |
305 | + query = "/Does/Not/Ever/Exist"; |
306 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
307 | + ASSERT_EQ(0, results.size()); |
308 | +} |
309 | + |
310 | +TEST_F(TestIntrospection, TestQueriesWithParams) |
311 | +{ |
312 | + std::list<Introspectable*> results; |
313 | + // this should find our root node: |
314 | + results = GetIntrospectableNodesFromQuery("/Unity[SomeProperty=SomeValue]", root_.get()); |
315 | + ASSERT_EQ(1, results.size()); |
316 | + EXPECT_STREQ("Unity", results.front()->GetName().c_str()); |
317 | + // but this should find nothing: |
318 | + results = GetIntrospectableNodesFromQuery("/Unity[SomeProperty=SomeOtherValue]", root_.get()); |
319 | + ASSERT_EQ(0, results.size()); |
320 | + |
321 | + // make sure relative paths work: |
322 | + results = GetIntrospectableNodesFromQuery("//Foo[Name=Foo]", root_.get()); |
323 | + ASSERT_EQ(3, results.size()); |
324 | + for(auto p : results) |
325 | + { |
326 | + EXPECT_STREQ("Foo", p->GetName().c_str()); |
327 | + } |
328 | + |
329 | + // make sure param queries work with descendant nodes as well: |
330 | + results = GetIntrospectableNodesFromQuery("/Unity[SomeProperty=SomeValue]/DashController[Name=DashController]/Foo", root_.get()); |
331 | + ASSERT_EQ(3, results.size()); |
332 | + for(auto p : results) |
333 | + { |
334 | + EXPECT_STREQ("Foo", p->GetName().c_str()); |
335 | + } |
336 | +} |
337 | + |
338 | +TEST_F(TestIntrospection, TestQueryTypeBool) |
339 | +{ |
340 | + std::list<Introspectable*> results; |
341 | + |
342 | + // These are all equivilent and should return the root item and nothing more: |
343 | + std::list<std::string> queries = {"/Unity[BoolPropertyTrue=True]", |
344 | + "/Unity[BoolPropertyTrue=true]", |
345 | + "/Unity[BoolPropertyTrue=trUE]", |
346 | + "/Unity[BoolPropertyTrue=yes]", |
347 | + "/Unity[BoolPropertyTrue=ON]", |
348 | + "/Unity[BoolPropertyTrue=1]"}; |
349 | + |
350 | + for(auto query : queries) |
351 | + { |
352 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
353 | + ASSERT_EQ(1, results.size()); |
354 | + EXPECT_STREQ("Unity", results.front()->GetName().c_str()); |
355 | + } |
356 | + |
357 | + // For boolean properties, anything that's not True, Yes, On or 1 is treated as false: |
358 | + queries = {"/Unity[BoolPropertyTrue=False]", |
359 | + "/Unity[BoolPropertyTrue=fAlSE]", |
360 | + "/Unity[BoolPropertyTrue=No]", |
361 | + "/Unity[BoolPropertyTrue=OFF]", |
362 | + "/Unity[BoolPropertyTrue=0]", |
363 | + "/Unity[BoolPropertyTrue=ThereWasAManFromNantucket]"}; |
364 | + for(auto query : queries) |
365 | + { |
366 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
367 | + ASSERT_EQ(0, results.size()); |
368 | + } |
369 | +} |
370 | + |
371 | +TEST_F(TestIntrospection, TestQueryTypeInt) |
372 | +{ |
373 | + std::list<Introspectable*> results; |
374 | + |
375 | + // these should all select the root Unity node: |
376 | + std::list<std::string> queries = {"/Unity[BytePropertyPos=12]", |
377 | + "/Unity[Int16PropertyPos=1012]", |
378 | + "/Unity[Int16PropertyNeg=-1034]", |
379 | + "/Unity[UInt16PropertyPos=1056]", |
380 | + "/Unity[Int32PropertyPos=100012]", |
381 | + "/Unity[Int32PropertyNeg=-100034]", |
382 | + "/Unity[UInt32PropertyPos=100056]", |
383 | + "/Unity[Int64PropertyPos=100000012]", |
384 | + "/Unity[Int64PropertyNeg=-100000034]", |
385 | + "/Unity[UInt64PropertyPos=100000056]"}; |
386 | + for(auto query : queries) |
387 | + { |
388 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
389 | + ASSERT_EQ(1, results.size()) << "Failing query: " << query; |
390 | + EXPECT_STREQ("Unity", results.front()->GetName().c_str()); |
391 | + } |
392 | + |
393 | + // but these shouldn't: |
394 | + queries = {"/Unity[BytePropertyPos=1234]", |
395 | + "/Unity[Int16PropertyPos=0]", |
396 | + "/Unity[Int16PropertyNeg=-0]", |
397 | + "/Unity[Int16PropertyNeg=-]", |
398 | + "/Unity[UInt16PropertyPos=-1056]", |
399 | + "/Unity[Int32PropertyPos=999999999999999]", |
400 | + "/Unity[Int32PropertyNeg=Garbage]", |
401 | + "/Unity[UInt32PropertyPos=-23]"}; |
402 | + for(auto query : queries) |
403 | + { |
404 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
405 | + ASSERT_EQ(0, results.size()); |
406 | + } |
407 | +} |
408 | + |
409 | +TEST_F(TestIntrospection, TestMalformedQueries) |
410 | +{ |
411 | + // this should work - we have not yet specified a parameter to test against. |
412 | + std::list<Introspectable*> results = GetIntrospectableNodesFromQuery("/Unity[", root_.get()); |
413 | + ASSERT_EQ(1, results.size()); |
414 | + |
415 | + std::list<std::string> queries = {"/Unity[BoolPropertyTrue", |
416 | + "/Unity[BoolPropertyTrue=", |
417 | + "/Unity[BoolPropertyTrue=]", |
418 | + "/Unity[BytePropertyPos=", |
419 | + "/Unity[BytePropertyPos=]", |
420 | + "/Unity[Int16PropertyPos=", |
421 | + "/Unity[Int16PropertyPos=]", |
422 | + "/Unity[Int16PropertyNeg=", |
423 | + "/Unity[Int16PropertyNeg=]", |
424 | + "/Unity[UInt16PropertyPos[=]]", |
425 | + "/Unity[Int32PropertyPos[[", |
426 | + "/Unity[Int32PropertyNeg]", |
427 | + "/Unity[UInt32PropertyPos=[", |
428 | + "/Unity[Int64PropertyPos[[", |
429 | + "/Unity[Int64PropertyNeg", |
430 | + "/Unity[UInt64PropertyPos]"}; |
431 | + |
432 | + for (std::string query : queries) |
433 | + { |
434 | + results = GetIntrospectableNodesFromQuery(query, root_.get()); |
435 | + ASSERT_EQ(0, results.size()) << "Failing query: " << query; |
436 | + } |
437 | +} |
438 | |
439 | === modified file 'unity-shared/CMakeLists.txt' |
440 | --- unity-shared/CMakeLists.txt 2013-02-01 17:01:09 +0000 |
441 | +++ unity-shared/CMakeLists.txt 2013-02-01 20:35:26 +0000 |
442 | @@ -64,6 +64,7 @@ |
443 | VScrollBarOverlayWindow.cpp |
444 | WindowButtons.cpp |
445 | WindowManager.cpp |
446 | + XPathQueryPart.cpp |
447 | ) |
448 | |
449 | if(ENABLE_X_SUPPORT) |
450 | |
451 | === modified file 'unity-shared/DebugDBusInterface.cpp' |
452 | --- unity-shared/DebugDBusInterface.cpp 2013-01-24 04:53:37 +0000 |
453 | +++ unity-shared/DebugDBusInterface.cpp 2013-02-01 20:35:26 +0000 |
454 | @@ -28,12 +28,10 @@ |
455 | #include <boost/bind.hpp> |
456 | #include <NuxCore/Logger.h> |
457 | #include <NuxCore/LoggingWriter.h> |
458 | -#include <xpathselect/node.h> |
459 | -#include <xpathselect/xpathselect.h> |
460 | -#include <dlfcn.h> |
461 | |
462 | #include "DebugDBusInterface.h" |
463 | #include "Introspectable.h" |
464 | +#include "XPathQueryPart.h" |
465 | |
466 | namespace unity |
467 | { |
468 | @@ -47,149 +45,9 @@ |
469 | namespace local |
470 | { |
471 | std::ofstream output_file; |
472 | - |
473 | - class IntrospectableAdapter: public xpathselect::Node |
474 | - { |
475 | - public: |
476 | - typedef std::shared_ptr<IntrospectableAdapter> Ptr; |
477 | - IntrospectableAdapter(Introspectable* node) |
478 | - : node_(node) |
479 | - {} |
480 | - |
481 | - std::string GetName() const |
482 | - { |
483 | - return node_->GetName(); |
484 | - } |
485 | - |
486 | - bool MatchProperty(const std::string& name, const std::string& value) const |
487 | - { |
488 | - bool matches = false; |
489 | - |
490 | - GVariantBuilder child_builder; |
491 | - g_variant_builder_init(&child_builder, G_VARIANT_TYPE("a{sv}")); |
492 | - g_variant_builder_add(&child_builder, "{sv}", "id", g_variant_new_uint64(node_->GetIntrospectionId())); |
493 | - node_->AddProperties(&child_builder); |
494 | - GVariant* prop_dict = g_variant_builder_end(&child_builder); |
495 | - GVariant *prop_value = g_variant_lookup_value(prop_dict, name.c_str(), NULL); |
496 | - |
497 | - if (prop_value != NULL) |
498 | - { |
499 | - GVariantClass prop_val_type = g_variant_classify(prop_value); |
500 | - // it'd be nice to be able to do all this with one method. However, the booleans need |
501 | - // special treatment, and I can't figure out how to group all the integer types together |
502 | - // without resorting to template functions.... and we all know what happens when you |
503 | - // start doing that... |
504 | - switch (prop_val_type) |
505 | - { |
506 | - case G_VARIANT_CLASS_STRING: |
507 | - { |
508 | - const gchar* prop_val = g_variant_get_string(prop_value, NULL); |
509 | - if (g_strcmp0(prop_val, value.c_str()) == 0) |
510 | - { |
511 | - matches = true; |
512 | - } |
513 | - } |
514 | - break; |
515 | - case G_VARIANT_CLASS_BOOLEAN: |
516 | - { |
517 | - std::string value = boost::to_upper_copy(value); |
518 | - bool p = value == "TRUE" || |
519 | - value == "ON" || |
520 | - value == "YES" || |
521 | - value == "1"; |
522 | - matches = (g_variant_get_boolean(prop_value) == p); |
523 | - } |
524 | - break; |
525 | - case G_VARIANT_CLASS_BYTE: |
526 | - { |
527 | - // It would be nice if I could do all the integer types together, but I couldn't see how... |
528 | - std::stringstream stream(value); |
529 | - int val; // changing this to guchar causes problems. |
530 | - stream >> val; |
531 | - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
532 | - val == g_variant_get_byte(prop_value); |
533 | - } |
534 | - break; |
535 | - case G_VARIANT_CLASS_INT16: |
536 | - { |
537 | - std::stringstream stream(value); |
538 | - gint16 val; |
539 | - stream >> val; |
540 | - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
541 | - val == g_variant_get_int16(prop_value); |
542 | - } |
543 | - break; |
544 | - case G_VARIANT_CLASS_UINT16: |
545 | - { |
546 | - std::stringstream stream(value); |
547 | - guint16 val; |
548 | - stream >> val; |
549 | - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
550 | - val == g_variant_get_uint16(prop_value); |
551 | - } |
552 | - break; |
553 | - case G_VARIANT_CLASS_INT32: |
554 | - { |
555 | - std::stringstream stream(value); |
556 | - gint32 val; |
557 | - stream >> val; |
558 | - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
559 | - val == g_variant_get_int32(prop_value); |
560 | - } |
561 | - break; |
562 | - case G_VARIANT_CLASS_UINT32: |
563 | - { |
564 | - std::stringstream stream(value); |
565 | - guint32 val; |
566 | - stream >> val; |
567 | - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
568 | - val == g_variant_get_uint32(prop_value); |
569 | - } |
570 | - break; |
571 | - case G_VARIANT_CLASS_INT64: |
572 | - { |
573 | - std::stringstream stream(value); |
574 | - gint64 val; |
575 | - stream >> val; |
576 | - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
577 | - val == g_variant_get_int64(prop_value); |
578 | - } |
579 | - break; |
580 | - case G_VARIANT_CLASS_UINT64: |
581 | - { |
582 | - std::stringstream stream(value); |
583 | - guint64 val; |
584 | - stream >> val; |
585 | - matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
586 | - val == g_variant_get_uint64(prop_value); |
587 | - } |
588 | - break; |
589 | - default: |
590 | - LOG_WARNING(logger) << "Unable to match against property of unknown type."; |
591 | - }; |
592 | - } |
593 | - g_variant_unref(prop_value); |
594 | - g_variant_unref(prop_dict); |
595 | - return matches; |
596 | - } |
597 | - |
598 | - std::vector<xpathselect::Node::Ptr> Children() const |
599 | - { |
600 | - std::vector<xpathselect::Node::Ptr> children; |
601 | - for(auto child: node_->GetIntrospectableChildren()) |
602 | - { |
603 | - children.push_back(std::make_shared<IntrospectableAdapter>(child)); |
604 | - } |
605 | - return children; |
606 | - |
607 | - } |
608 | - |
609 | - Introspectable* node_; |
610 | - }; |
611 | -} |
612 | -} |
613 | - |
614 | -bool TryLoadXPathImplementation(); |
615 | +} |
616 | +} |
617 | + |
618 | GVariant* GetState(std::string const& query); |
619 | void StartLogToFile(std::string const& file_path); |
620 | void ResetLogging(); |
621 | @@ -363,40 +221,20 @@ |
622 | } |
623 | } |
624 | |
625 | + |
626 | GVariant* GetState(std::string const& query) |
627 | { |
628 | + // process the XPath query: |
629 | + std::list<Introspectable*> parts = GetIntrospectableNodesFromQuery(query, _parent_introspectable); |
630 | GVariantBuilder builder; |
631 | g_variant_builder_init(&builder, G_VARIANT_TYPE("a(sv)")); |
632 | - |
633 | - // try load the xpathselect library: |
634 | - void* driver = dlopen("libxpathselect.so", RTLD_LAZY); |
635 | - if (driver) |
636 | + if (parts.empty()) |
637 | { |
638 | - typedef decltype(&xpathselect::SelectNodes) entry_t; |
639 | - // clear errors: |
640 | - dlerror(); |
641 | - entry_t entry_point = (entry_t) dlsym(driver, "SelectNodes"); |
642 | - const char* err = dlerror(); |
643 | - if (err) |
644 | - { |
645 | - LOG_ERROR(logger) << "Unable to load entry point in libxpathselect: " << err; |
646 | - } |
647 | - else |
648 | - { |
649 | - // process the XPath query: |
650 | - local::IntrospectableAdapter::Ptr root_node = std::make_shared<local::IntrospectableAdapter>(_parent_introspectable); |
651 | - auto nodes = entry_point(root_node, query); |
652 | - for (auto n : nodes) |
653 | - { |
654 | - auto p = std::static_pointer_cast<local::IntrospectableAdapter>(n); |
655 | - if (p) |
656 | - g_variant_builder_add(&builder, "(sv)", p->node_->GetName().c_str(), p->node_->Introspect()); |
657 | - } |
658 | - } |
659 | + LOG_WARNING(logger) << "Query '" << query << "' Did not match anything."; |
660 | } |
661 | - else |
662 | + for (Introspectable *node : parts) |
663 | { |
664 | - LOG_WARNING(logger) << "Cannot complete introspection request because libxpathselect is not installed."; |
665 | + g_variant_builder_add(&builder, "(sv)", node->GetName().c_str(), node->Introspect()); |
666 | } |
667 | |
668 | return g_variant_new("(a(sv))", &builder); |
669 | @@ -436,5 +274,122 @@ |
670 | } |
671 | } |
672 | |
673 | +/* |
674 | + * Do a breadth-first search of the introspection tree and find all nodes that match the |
675 | + * query. |
676 | + */ |
677 | +std::list<Introspectable*> GetIntrospectableNodesFromQuery(std::string const& query, Introspectable* tree_root) |
678 | +{ |
679 | + std::list<Introspectable*> start_points; |
680 | + std::string sanitised_query; |
681 | + // Allow user to be lazy when specifying root node. |
682 | + if (query == "" || query == "/") |
683 | + { |
684 | + sanitised_query = "/" + tree_root->GetName(); |
685 | + } |
686 | + else |
687 | + { |
688 | + sanitised_query = query; |
689 | + } |
690 | + // split query into parts |
691 | + std::list<XPathQueryPart> query_parts; |
692 | + |
693 | + { |
694 | + std::list<std::string> query_strings; |
695 | + boost::algorithm::split(query_strings, sanitised_query, boost::algorithm::is_any_of("/")); |
696 | + // Boost's split() implementation does not match it's documentation! According to the |
697 | + // docs, it's not supposed to add empty strings, but it does, which is a PITA. This |
698 | + // next line removes them: |
699 | + query_strings.erase( std::remove_if( query_strings.begin(), |
700 | + query_strings.end(), |
701 | + boost::bind( &std::string::empty, _1 ) ), |
702 | + query_strings.end()); |
703 | + for (auto part : query_strings) |
704 | + { |
705 | + query_parts.push_back(XPathQueryPart(part)); |
706 | + } |
707 | + } |
708 | + |
709 | + // absolute or relative query string? |
710 | + if (sanitised_query.at(0) == '/' && sanitised_query.at(1) != '/') |
711 | + { |
712 | + // absolute query - start point is tree root node. |
713 | + if (query_parts.front().Matches(tree_root)) |
714 | + { |
715 | + start_points.push_back(tree_root); |
716 | + } |
717 | + } |
718 | + else |
719 | + { |
720 | + // relative - need to do a depth first tree search for all nodes that match the |
721 | + // first node in the query. |
722 | + |
723 | + // warn about malformed queries (all queries must start with '/') |
724 | + if (sanitised_query.at(0) != '/') |
725 | + { |
726 | + LOG_WARNING(logger) << "Malformed relative introspection query: '" << query << "'."; |
727 | + } |
728 | + |
729 | + // non-recursive BFS traversal to find starting points: |
730 | + std::queue<Introspectable*> queue; |
731 | + queue.push(tree_root); |
732 | + while (!queue.empty()) |
733 | + { |
734 | + Introspectable *node = queue.front(); |
735 | + queue.pop(); |
736 | + if (query_parts.front().Matches(node)) |
737 | + { |
738 | + // found one. We keep going deeper, as there may be another node beneath this one |
739 | + // with the same node name. |
740 | + start_points.push_back(node); |
741 | + } |
742 | + // Add all children of current node to queue. |
743 | + for (Introspectable* child : node->GetIntrospectableChildren()) |
744 | + { |
745 | + queue.push(child); |
746 | + } |
747 | + } |
748 | + } |
749 | + |
750 | + // now we have the tree start points, process them: |
751 | + query_parts.pop_front(); |
752 | + typedef std::pair<Introspectable*, std::list<XPathQueryPart>::iterator> node_match_pair; |
753 | + |
754 | + std::queue<node_match_pair> traverse_queue; |
755 | + for (Introspectable *node : start_points) |
756 | + { |
757 | + traverse_queue.push(node_match_pair(node, query_parts.begin())); |
758 | + } |
759 | + start_points.clear(); |
760 | + |
761 | + while (!traverse_queue.empty()) |
762 | + { |
763 | + node_match_pair p = traverse_queue.front(); |
764 | + traverse_queue.pop(); |
765 | + |
766 | + Introspectable *node = p.first; |
767 | + auto query_it = p.second; |
768 | + |
769 | + if (query_it == query_parts.end()) |
770 | + { |
771 | + // found a match: |
772 | + start_points.push_back(node); |
773 | + } |
774 | + else |
775 | + { |
776 | + // push all children of current node to start of queue, advance search iterator, and loop again. |
777 | + for (Introspectable* child : node->GetIntrospectableChildren()) |
778 | + { |
779 | + if (query_it->Matches(child)) |
780 | + { |
781 | + auto it_copy(query_it); |
782 | + ++it_copy; |
783 | + traverse_queue.push(node_match_pair(child, it_copy)); |
784 | + } |
785 | + } |
786 | + } |
787 | + } |
788 | + return start_points; |
789 | +} |
790 | } |
791 | } |
792 | |
793 | === modified file 'unity-shared/DebugDBusInterface.h' |
794 | --- unity-shared/DebugDBusInterface.h 2013-01-24 04:53:37 +0000 |
795 | +++ unity-shared/DebugDBusInterface.h 2013-02-01 20:35:26 +0000 |
796 | @@ -31,6 +31,8 @@ |
797 | namespace debug |
798 | { |
799 | class Introspectable; |
800 | +std::list<Introspectable*> GetIntrospectableNodesFromQuery(std::string const& query, Introspectable *tree_root); |
801 | + |
802 | class DebugDBusInterface |
803 | { |
804 | public: |
805 | |
806 | === added file 'unity-shared/XPathQueryPart.cpp' |
807 | --- unity-shared/XPathQueryPart.cpp 1970-01-01 00:00:00 +0000 |
808 | +++ unity-shared/XPathQueryPart.cpp 2013-02-01 20:35:26 +0000 |
809 | @@ -0,0 +1,186 @@ |
810 | +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
811 | +/* |
812 | + * Copyright (C) 2010 Canonical Ltd |
813 | + * |
814 | + * This program is free software: you can redistribute it and/or modify |
815 | + * it under the terms of the GNU General Public License version 3 as |
816 | + * published by the Free Software Foundation. |
817 | + * |
818 | + * This program is distributed in the hope that it will be useful, |
819 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
820 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
821 | + * GNU General Public License for more details. |
822 | + * |
823 | + * You should have received a copy of the GNU General Public License |
824 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
825 | + * |
826 | + * Authored by: Thomi Richards <thomi.richards@canonical.com> |
827 | + */ |
828 | + |
829 | +#include <sstream> |
830 | +#include <boost/algorithm/string.hpp> |
831 | +#include <boost/algorithm/string/split.hpp> |
832 | +#include <boost/algorithm/string/classification.hpp> |
833 | +#include <boost/bind.hpp> |
834 | +#include <NuxCore/Logger.h> |
835 | +#include "XPathQueryPart.h" |
836 | +#include "Introspectable.h" |
837 | + |
838 | +namespace unity |
839 | +{ |
840 | + |
841 | +namespace debug |
842 | +{ |
843 | +DECLARE_LOGGER(logger, "unity.debug.xpath"); |
844 | + |
845 | +// Stores a part of an XPath query. |
846 | +XPathQueryPart::XPathQueryPart(std::string const& query_part) |
847 | +{ |
848 | + std::vector<std::string> part_pieces; |
849 | + boost::algorithm::split(part_pieces, query_part, boost::algorithm::is_any_of("[]=")); |
850 | + // Boost's split() implementation does not match it's documentation! According to the |
851 | + // docs, it's not supposed to add empty strings, but it does, which is a PITA. This |
852 | + // next line removes them: |
853 | + part_pieces.erase( std::remove_if( part_pieces.begin(), |
854 | + part_pieces.end(), |
855 | + boost::bind( &std::string::empty, _1 ) ), |
856 | + part_pieces.end()); |
857 | + if (part_pieces.size() == 1) |
858 | + { |
859 | + node_name_ = part_pieces.at(0); |
860 | + } |
861 | + else if (part_pieces.size() == 3) |
862 | + { |
863 | + node_name_ = part_pieces.at(0); |
864 | + param_name_ = part_pieces.at(1); |
865 | + param_value_ = part_pieces.at(2); |
866 | + } |
867 | + else |
868 | + { |
869 | + LOG_WARNING(logger) << "Malformed query part: " << query_part; |
870 | + // assume it's just a node name: |
871 | + node_name_ = query_part; |
872 | + } |
873 | +} |
874 | + |
875 | +bool XPathQueryPart::Matches(Introspectable* node) const |
876 | +{ |
877 | + bool matches = false; |
878 | + if (param_name_ == "") |
879 | + { |
880 | + matches = (node_name_ == "*" || node->GetName() == node_name_); |
881 | + } |
882 | + else |
883 | + { |
884 | + GVariantBuilder child_builder; |
885 | + g_variant_builder_init(&child_builder, G_VARIANT_TYPE("a{sv}")); |
886 | + g_variant_builder_add(&child_builder, "{sv}", "id", g_variant_new_uint64(node->GetIntrospectionId())); |
887 | + node->AddProperties(&child_builder); |
888 | + GVariant* prop_dict = g_variant_builder_end(&child_builder); |
889 | + GVariant *prop_value = g_variant_lookup_value(prop_dict, param_name_.c_str(), NULL); |
890 | + |
891 | + if (prop_value != NULL) |
892 | + { |
893 | + GVariantClass prop_val_type = g_variant_classify(prop_value); |
894 | + // it'd be nice to be able to do all this with one method. However, the booleans need |
895 | + // special treatment, and I can't figure out how to group all the integer types together |
896 | + // without resorting to template functions.... and we all know what happens when you |
897 | + // start doing that... |
898 | + switch (prop_val_type) |
899 | + { |
900 | + case G_VARIANT_CLASS_STRING: |
901 | + { |
902 | + const gchar* prop_val = g_variant_get_string(prop_value, NULL); |
903 | + if (g_strcmp0(prop_val, param_value_.c_str()) == 0) |
904 | + { |
905 | + matches = true; |
906 | + } |
907 | + } |
908 | + break; |
909 | + case G_VARIANT_CLASS_BOOLEAN: |
910 | + { |
911 | + std::string value = boost::to_upper_copy(param_value_); |
912 | + bool p = value == "TRUE" || |
913 | + value == "ON" || |
914 | + value == "YES" || |
915 | + value == "1"; |
916 | + matches = (g_variant_get_boolean(prop_value) == p); |
917 | + } |
918 | + break; |
919 | + case G_VARIANT_CLASS_BYTE: |
920 | + { |
921 | + // It would be nice if I could do all the integer types together, but I couldn't see how... |
922 | + std::stringstream stream(param_value_); |
923 | + int val; // changing this to guchar causes problems. |
924 | + stream >> val; |
925 | + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
926 | + val == g_variant_get_byte(prop_value); |
927 | + } |
928 | + break; |
929 | + case G_VARIANT_CLASS_INT16: |
930 | + { |
931 | + std::stringstream stream(param_value_); |
932 | + gint16 val; |
933 | + stream >> val; |
934 | + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
935 | + val == g_variant_get_int16(prop_value); |
936 | + } |
937 | + break; |
938 | + case G_VARIANT_CLASS_UINT16: |
939 | + { |
940 | + std::stringstream stream(param_value_); |
941 | + guint16 val; |
942 | + stream >> val; |
943 | + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
944 | + val == g_variant_get_uint16(prop_value); |
945 | + } |
946 | + break; |
947 | + case G_VARIANT_CLASS_INT32: |
948 | + { |
949 | + std::stringstream stream(param_value_); |
950 | + gint32 val; |
951 | + stream >> val; |
952 | + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
953 | + val == g_variant_get_int32(prop_value); |
954 | + } |
955 | + break; |
956 | + case G_VARIANT_CLASS_UINT32: |
957 | + { |
958 | + std::stringstream stream(param_value_); |
959 | + guint32 val; |
960 | + stream >> val; |
961 | + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
962 | + val == g_variant_get_uint32(prop_value); |
963 | + } |
964 | + break; |
965 | + case G_VARIANT_CLASS_INT64: |
966 | + { |
967 | + std::stringstream stream(param_value_); |
968 | + gint64 val; |
969 | + stream >> val; |
970 | + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
971 | + val == g_variant_get_int64(prop_value); |
972 | + } |
973 | + break; |
974 | + case G_VARIANT_CLASS_UINT64: |
975 | + { |
976 | + std::stringstream stream(param_value_); |
977 | + guint64 val; |
978 | + stream >> val; |
979 | + matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 && |
980 | + val == g_variant_get_uint64(prop_value); |
981 | + } |
982 | + break; |
983 | + default: |
984 | + LOG_WARNING(logger) << "Unable to match against property of unknown type."; |
985 | + }; |
986 | + } |
987 | + g_variant_unref(prop_value); |
988 | + g_variant_unref(prop_dict); |
989 | + } |
990 | + |
991 | + return matches; |
992 | +} |
993 | + |
994 | +} |
995 | +} |
996 | |
997 | === added file 'unity-shared/XPathQueryPart.h' |
998 | --- unity-shared/XPathQueryPart.h 1970-01-01 00:00:00 +0000 |
999 | +++ unity-shared/XPathQueryPart.h 2013-02-01 20:35:26 +0000 |
1000 | @@ -0,0 +1,45 @@ |
1001 | +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
1002 | +/* |
1003 | + * Copyright (C) 2010 Canonical Ltd |
1004 | + * |
1005 | + * This program is free software: you can redistribute it and/or modify |
1006 | + * it under the terms of the GNU General Public License version 3 as |
1007 | + * published by the Free Software Foundation. |
1008 | + * |
1009 | + * This program is distributed in the hope that it will be useful, |
1010 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1011 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1012 | + * GNU General Public License for more details. |
1013 | + * |
1014 | + * You should have received a copy of the GNU General Public License |
1015 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1016 | + * |
1017 | + * Authored by: Thomi Richards <thomi.richards@canonical.com> |
1018 | + */ |
1019 | + |
1020 | +#include <string> |
1021 | + |
1022 | +#ifndef _XPATH_QUERY_PART |
1023 | +#define _XPATH_QUERY_PART |
1024 | + |
1025 | +namespace unity |
1026 | +{ |
1027 | +namespace debug |
1028 | +{ |
1029 | + class Introspectable; |
1030 | + // Stores a part of an XPath query. |
1031 | + class XPathQueryPart |
1032 | + { |
1033 | + public: |
1034 | + XPathQueryPart(std::string const& query_part); |
1035 | + bool Matches(Introspectable* node) const; |
1036 | + private: |
1037 | + std::string node_name_; |
1038 | + std::string param_name_; |
1039 | + std::string param_value_; |
1040 | + }; |
1041 | + |
1042 | +} |
1043 | +} |
1044 | + |
1045 | +#endif |