summaryrefslogtreecommitdiff
diff options
-rw-r--r--debian/control11
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/test_introspection.cpp356
-rw-r--r--unity-shared/CMakeLists.txt1
-rw-r--r--unity-shared/DebugDBusInterface.cpp304
-rw-r--r--unity-shared/DebugDBusInterface.h1
-rw-r--r--unity-shared/XPathQueryPart.cpp186
-rw-r--r--unity-shared/XPathQueryPart.h45
8 files changed, 185 insertions, 720 deletions
diff --git a/debian/control b/debian/control
index 550384a1e..cba288189 100644
--- a/debian/control
+++ b/debian/control
@@ -165,6 +165,7 @@ Architecture: all
Depends: ${misc:Depends},
${python:Depends},
python-windowmocker,
+ libxpathselect (>= 1.3),
Description: Autopiloted tests for Unity
We test Unity automatically through autopilot, a framework which enables us
to trigger keyboard and mouse events on the fly as well as introspecting
@@ -183,7 +184,7 @@ Package: libunity-2d-private0
Depends: unity, ${misc:Depends}
Architecture: all
Section: oldlibs
-Description: transitional dummy package
+Description: transitional dummy package
This is a transitional dummy package for unity-2d -> unity migration.
It can safely be removed.
@@ -191,7 +192,7 @@ Package: libunity-2d-private-dev
Depends: unity, ${misc:Depends}
Architecture: all
Section: oldlibs
-Description: transitional dummy package
+Description: transitional dummy package
This is a transitional dummy package for unity-2d -> unity migration.
It can safely be removed.
@@ -199,7 +200,7 @@ Package: unity-2d-panel
Depends: unity, ${misc:Depends}
Architecture: all
Section: oldlibs
-Description: transitional dummy package
+Description: transitional dummy package
This is a transitional dummy package for unity-2d -> unity migration.
It can safely be removed.
@@ -207,7 +208,7 @@ Package: unity-2d-spread
Depends: unity, ${misc:Depends}
Architecture: all
Section: oldlibs
-Description: transitional dummy package
+Description: transitional dummy package
This is a transitional dummy package for unity-2d -> unity migration.
It can safely be removed.
@@ -215,7 +216,7 @@ Package: unity-2d-common
Depends: unity, ${misc:Depends}
Architecture: all
Section: oldlibs
-Description: transitional dummy package
+Description: transitional dummy package
This is a transitional dummy package for unity-2d -> unity migration.
It can safely be removed.
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 04fd3dd35..e5219d3af 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -146,7 +146,6 @@ if (GTEST_SRC_DIR AND
test_indicator_appmenu.cpp
test_indicator_entry.cpp
test_indicators.cpp
- test_introspection.cpp
test_favorite_store.cpp
test_favorite_store_gsettings.cpp
test_favorite_store_private.cpp
diff --git a/tests/test_introspection.cpp b/tests/test_introspection.cpp
deleted file mode 100644
index 53b9f626a..000000000
--- a/tests/test_introspection.cpp
+++ /dev/null
@@ -1,356 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2010 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authored by: Thomi Richards <thomi.richards@canonical.com>
- */
-#include <gtest/gtest.h>
-#include <glib.h>
-#include <memory>
-#include <boost/foreach.hpp>
-
-#include "Introspectable.h"
-#include "DebugDBusInterface.h"
-
-
-using namespace unity::debug;
-
-class MockIntrospectable : public Introspectable
-{
-public:
- MockIntrospectable(std::string const& name)
- : name_(name)
- {}
-
- std::string GetName() const
- {
- return name_;
- }
- void AddProperties(GVariantBuilder* builder)
- {
- g_variant_builder_add (builder, "{sv}", "Name", g_variant_new_string (name_.c_str()) );
- g_variant_builder_add (builder, "{sv}", "SomeProperty", g_variant_new_string ("SomeValue") );
- g_variant_builder_add (builder, "{sv}", "BoolPropertyTrue", g_variant_new_boolean (TRUE) );
- g_variant_builder_add (builder, "{sv}", "BoolPropertyFalse", g_variant_new_boolean (FALSE) );
- // 8-bit integer types:
- g_variant_builder_add (builder, "{sv}", "BytePropertyPos", g_variant_new_byte (12) );
- // 16-bit integer types:
- g_variant_builder_add (builder, "{sv}", "Int16PropertyPos", g_variant_new_int16 (1012) );
- g_variant_builder_add (builder, "{sv}", "Int16PropertyNeg", g_variant_new_int16 (-1034) );
- g_variant_builder_add (builder, "{sv}", "UInt16PropertyPos", g_variant_new_uint16 (1056) );
- // 32-bit integer types:
- g_variant_builder_add (builder, "{sv}", "Int32PropertyPos", g_variant_new_int32 (100012) );
- g_variant_builder_add (builder, "{sv}", "Int32PropertyNeg", g_variant_new_int32 (-100034) );
- g_variant_builder_add (builder, "{sv}", "UInt32PropertyPos", g_variant_new_uint32 (100056) );
- // 64-bit integer types
- g_variant_builder_add (builder, "{sv}", "Int64PropertyPos", g_variant_new_int32 (100000012) );
- g_variant_builder_add (builder, "{sv}", "Int64PropertyNeg", g_variant_new_int32 (-100000034) );
- g_variant_builder_add (builder, "{sv}", "UInt64PropertyPos", g_variant_new_uint32 (100000056) );
-
- }
-private:
- std::string name_;
-};
-
-class TestIntrospection : public ::testing::Test
-{
-public:
- TestIntrospection()
- : root_(new MockIntrospectable("Unity")),
- dc_(new MockIntrospectable("DashController")),
- pc_(new MockIntrospectable("PanelController")),
- foo1_(new MockIntrospectable("Foo")),
- foo2_(new MockIntrospectable("Foo")),
- foo3_(new MockIntrospectable("Foo"))
- {
- root_->AddChild(dc_.get());
- root_->AddChild(pc_.get());
- dc_->AddChild(foo1_.get());
- dc_->AddChild(foo2_.get());
- dc_->AddChild(foo3_.get());
-
- //root_->SetProperty(g_variant_new("{sv}", "SomeProperty", g_variant_new_string("SomeValue")));
- }
-
-protected:
- std::shared_ptr<MockIntrospectable> root_;
- std::shared_ptr<MockIntrospectable> dc_;
- std::shared_ptr<MockIntrospectable> pc_;
- std::shared_ptr<MockIntrospectable> foo1_;
- std::shared_ptr<MockIntrospectable> foo2_;
- std::shared_ptr<MockIntrospectable> foo3_;
-
-};
-
-TEST_F(TestIntrospection, TestTest)
-{
- ASSERT_STREQ("Unity", root_->GetName().c_str());
-}
-
-TEST_F(TestIntrospection, TestVariousRootQueries)
-{
- std::list<Introspectable*> results;
- std::string query;
-
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(1, results.size());
- EXPECT_STREQ("Unity", results.front()->GetName().c_str());
-
- query = "/";
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(1, results.size());
- EXPECT_STREQ("Unity", results.front()->GetName().c_str());
-
- query = "/Unity";
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(1, results.size());
- EXPECT_STREQ("Unity", results.front()->GetName().c_str());
-}
-
-TEST_F(TestIntrospection, TestAsteriskWildcard)
-{
- std::list<Introspectable*> results;
- std::string query = "/Unity/*";
-
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(2, results.size());
-
- for(auto p : results)
- {
- ASSERT_TRUE(
- p->GetName() == "DashController" ||
- p->GetName() == "PanelController"
- );
- }
-}
-
-TEST_F(TestIntrospection, TestRelativeAsteriskWildcard)
-{
- std::list<Introspectable*> results;
- std::string query = "//DashController/*";
-
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(3, results.size());
-
- for(auto p : results)
- {
- ASSERT_TRUE(p->GetName() == "Foo");
- }
-}
-
-TEST_F(TestIntrospection, TestAbsoluteQueries)
-{
- std::list<Introspectable*> results;
- std::string query = "/Unity/DashController";
-
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(1, results.size());
- EXPECT_STREQ("DashController", results.front()->GetName().c_str());
-}
-
-TEST_F(TestIntrospection, TestMalformedRelativeQueries)
-{
- std::list<Introspectable*> results;
- std::string query = "Unity";
-
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(1, results.size());
- EXPECT_STREQ("Unity", results.front()->GetName().c_str());
-
- query = "Foo";
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(3, results.size());
- for(auto p : results)
- {
- EXPECT_STREQ("Foo", p->GetName().c_str());
- }
-}
-
-TEST_F(TestIntrospection, TestSimpleRelativeQueries)
-{
- std::list<Introspectable*> results;
- std::string query = "//Unity";
-
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(1, results.size());
- EXPECT_STREQ("Unity", results.front()->GetName().c_str());
-
- query = "//Foo";
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(3, results.size());
- for(auto p : results)
- {
- EXPECT_STREQ("Foo", p->GetName().c_str());
- }
-}
-
-TEST_F(TestIntrospection, TestComplexRelativeQueries)
-{
- std::list<Introspectable*> results;
- std::string query = "//DashController/Foo";
-
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(3, results.size());
- for(auto p : results)
- {
- EXPECT_STREQ("Foo", p->GetName().c_str());
- }
-}
-
-TEST_F(TestIntrospection, TestQueriesWithNoResults)
-{
- std::list<Introspectable*> results;
- std::string query = "//Does/Not/Exist";
-
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(0, results.size());
-
- query = "DoesNotEverExist";
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(0, results.size());
-
- query = "/Does/Not/Ever/Exist";
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(0, results.size());
-}
-
-TEST_F(TestIntrospection, TestQueriesWithParams)
-{
- std::list<Introspectable*> results;
- // this should find our root node:
- results = GetIntrospectableNodesFromQuery("/Unity[SomeProperty=SomeValue]", root_.get());
- ASSERT_EQ(1, results.size());
- EXPECT_STREQ("Unity", results.front()->GetName().c_str());
- // but this should find nothing:
- results = GetIntrospectableNodesFromQuery("/Unity[SomeProperty=SomeOtherValue]", root_.get());
- ASSERT_EQ(0, results.size());
-
- // make sure relative paths work:
- results = GetIntrospectableNodesFromQuery("//Foo[Name=Foo]", root_.get());
- ASSERT_EQ(3, results.size());
- for(auto p : results)
- {
- EXPECT_STREQ("Foo", p->GetName().c_str());
- }
-
- // make sure param queries work with descendant nodes as well:
- results = GetIntrospectableNodesFromQuery("/Unity[SomeProperty=SomeValue]/DashController[Name=DashController]/Foo", root_.get());
- ASSERT_EQ(3, results.size());
- for(auto p : results)
- {
- EXPECT_STREQ("Foo", p->GetName().c_str());
- }
-}
-
-TEST_F(TestIntrospection, TestQueryTypeBool)
-{
- std::list<Introspectable*> results;
-
- // These are all equivilent and should return the root item and nothing more:
- std::list<std::string> queries = {"/Unity[BoolPropertyTrue=True]",
- "/Unity[BoolPropertyTrue=true]",
- "/Unity[BoolPropertyTrue=trUE]",
- "/Unity[BoolPropertyTrue=yes]",
- "/Unity[BoolPropertyTrue=ON]",
- "/Unity[BoolPropertyTrue=1]"};
-
- for(auto query : queries)
- {
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(1, results.size());
- EXPECT_STREQ("Unity", results.front()->GetName().c_str());
- }
-
- // For boolean properties, anything that's not True, Yes, On or 1 is treated as false:
- queries = {"/Unity[BoolPropertyTrue=False]",
- "/Unity[BoolPropertyTrue=fAlSE]",
- "/Unity[BoolPropertyTrue=No]",
- "/Unity[BoolPropertyTrue=OFF]",
- "/Unity[BoolPropertyTrue=0]",
- "/Unity[BoolPropertyTrue=ThereWasAManFromNantucket]"};
- for(auto query : queries)
- {
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(0, results.size());
- }
-}
-
-TEST_F(TestIntrospection, TestQueryTypeInt)
-{
- std::list<Introspectable*> results;
-
- // these should all select the root Unity node:
- std::list<std::string> queries = {"/Unity[BytePropertyPos=12]",
- "/Unity[Int16PropertyPos=1012]",
- "/Unity[Int16PropertyNeg=-1034]",
- "/Unity[UInt16PropertyPos=1056]",
- "/Unity[Int32PropertyPos=100012]",
- "/Unity[Int32PropertyNeg=-100034]",
- "/Unity[UInt32PropertyPos=100056]",
- "/Unity[Int64PropertyPos=100000012]",
- "/Unity[Int64PropertyNeg=-100000034]",
- "/Unity[UInt64PropertyPos=100000056]"};
- for(auto query : queries)
- {
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(1, results.size()) << "Failing query: " << query;
- EXPECT_STREQ("Unity", results.front()->GetName().c_str());
- }
-
- // but these shouldn't:
- queries = {"/Unity[BytePropertyPos=1234]",
- "/Unity[Int16PropertyPos=0]",
- "/Unity[Int16PropertyNeg=-0]",
- "/Unity[Int16PropertyNeg=-]",
- "/Unity[UInt16PropertyPos=-1056]",
- "/Unity[Int32PropertyPos=999999999999999]",
- "/Unity[Int32PropertyNeg=Garbage]",
- "/Unity[UInt32PropertyPos=-23]"};
- for(auto query : queries)
- {
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(0, results.size());
- }
-}
-
-TEST_F(TestIntrospection, TestMalformedQueries)
-{
- // this should work - we have not yet specified a parameter to test against.
- std::list<Introspectable*> results = GetIntrospectableNodesFromQuery("/Unity[", root_.get());
- ASSERT_EQ(1, results.size());
-
- std::list<std::string> queries = {"/Unity[BoolPropertyTrue",
- "/Unity[BoolPropertyTrue=",
- "/Unity[BoolPropertyTrue=]",
- "/Unity[BytePropertyPos=",
- "/Unity[BytePropertyPos=]",
- "/Unity[Int16PropertyPos=",
- "/Unity[Int16PropertyPos=]",
- "/Unity[Int16PropertyNeg=",
- "/Unity[Int16PropertyNeg=]",
- "/Unity[UInt16PropertyPos[=]]",
- "/Unity[Int32PropertyPos[[",
- "/Unity[Int32PropertyNeg]",
- "/Unity[UInt32PropertyPos=[",
- "/Unity[Int64PropertyPos[[",
- "/Unity[Int64PropertyNeg",
- "/Unity[UInt64PropertyPos]"};
-
- for (std::string query : queries)
- {
- results = GetIntrospectableNodesFromQuery(query, root_.get());
- ASSERT_EQ(0, results.size()) << "Failing query: " << query;
- }
-}
diff --git a/unity-shared/CMakeLists.txt b/unity-shared/CMakeLists.txt
index b4078c418..de923de86 100644
--- a/unity-shared/CMakeLists.txt
+++ b/unity-shared/CMakeLists.txt
@@ -65,7 +65,6 @@ set (UNITY_SHARED_SOURCES
VScrollBarOverlayWindow.cpp
WindowButtons.cpp
WindowManager.cpp
- XPathQueryPart.cpp
)
if(ENABLE_X_SUPPORT)
diff --git a/unity-shared/DebugDBusInterface.cpp b/unity-shared/DebugDBusInterface.cpp
index 8d6888433..2792c6d31 100644
--- a/unity-shared/DebugDBusInterface.cpp
+++ b/unity-shared/DebugDBusInterface.cpp
@@ -28,10 +28,12 @@
#include <boost/bind.hpp>
#include <NuxCore/Logger.h>
#include <NuxCore/LoggingWriter.h>
+#include <xpathselect/node.h>
+#include <xpathselect/xpathselect.h>
+#include <dlfcn.h>
#include "DebugDBusInterface.h"
#include "Introspectable.h"
-#include "XPathQueryPart.h"
namespace unity
{
@@ -44,9 +46,158 @@ namespace
namespace local
{
std::ofstream output_file;
+
+ class IntrospectableAdapter: public xpathselect::Node
+ {
+ public:
+ typedef std::shared_ptr<IntrospectableAdapter> Ptr;
+ IntrospectableAdapter(Introspectable* node, std::string const& parent_path)
+ : node_(node)
+ {
+ full_path_ = parent_path + "/" + GetName();
+ }
+
+ std::string GetName() const
+ {
+ return node_->GetName();
+ }
+
+ std::string GetPath() const
+ {
+ return full_path_;
+ }
+
+ bool MatchProperty(const std::string& name, const std::string& value) const
+ {
+ bool matches = false;
+
+ GVariantBuilder child_builder;
+ g_variant_builder_init(&child_builder, G_VARIANT_TYPE("a{sv}"));
+ g_variant_builder_add(&child_builder, "{sv}", "id", g_variant_new_uint64(node_->GetIntrospectionId()));
+ node_->AddProperties(&child_builder);
+ GVariant* prop_dict = g_variant_builder_end(&child_builder);
+ GVariant *prop_value = g_variant_lookup_value(prop_dict, name.c_str(), NULL);
+
+ if (prop_value != NULL)
+ {
+ GVariantClass prop_val_type = g_variant_classify(prop_value);
+ // it'd be nice to be able to do all this with one method. However, the booleans need
+ // special treatment, and I can't figure out how to group all the integer types together
+ // without resorting to template functions.... and we all know what happens when you
+ // start doing that...
+ switch (prop_val_type)
+ {
+ case G_VARIANT_CLASS_STRING:
+ {
+ const gchar* prop_val = g_variant_get_string(prop_value, NULL);
+ if (g_strcmp0(prop_val, value.c_str()) == 0)
+ {
+ matches = true;
+ }
+ }
+ break;
+ case G_VARIANT_CLASS_BOOLEAN:
+ {
+ std::string value = boost::to_upper_copy(value);
+ bool p = value == "TRUE" ||
+ value == "ON" ||
+ value == "YES" ||
+ value == "1";
+ matches = (g_variant_get_boolean(prop_value) == p);
+ }
+ break;
+ case G_VARIANT_CLASS_BYTE:
+ {
+ // It would be nice if I could do all the integer types together, but I couldn't see how...
+ std::stringstream stream(value);
+ int val; // changing this to guchar causes problems.
+ stream >> val;
+ matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
+ val == g_variant_get_byte(prop_value);
+ }
+ break;
+ case G_VARIANT_CLASS_INT16:
+ {
+ std::stringstream stream(value);
+ gint16 val;
+ stream >> val;
+ matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
+ val == g_variant_get_int16(prop_value);
+ }
+ break;
+ case G_VARIANT_CLASS_UINT16:
+ {
+ std::stringstream stream(value);
+ guint16 val;
+ stream >> val;
+ matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
+ val == g_variant_get_uint16(prop_value);
+ }
+ break;
+ case G_VARIANT_CLASS_INT32:
+ {
+ std::stringstream stream(value);
+ gint32 val;
+ stream >> val;
+ matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
+ val == g_variant_get_int32(prop_value);
+ }
+ break;
+ case G_VARIANT_CLASS_UINT32:
+ {
+ std::stringstream stream(value);
+ guint32 val;
+ stream >> val;
+ matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
+ val == g_variant_get_uint32(prop_value);
+ }
+ break;
+ case G_VARIANT_CLASS_INT64:
+ {
+ std::stringstream stream(value);
+ gint64 val;
+ stream >> val;
+ matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
+ val == g_variant_get_int64(prop_value);
+ }
+ break;
+ case G_VARIANT_CLASS_UINT64:
+ {
+ std::stringstream stream(value);
+ guint64 val;
+ stream >> val;
+ matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
+ val == g_variant_get_uint64(prop_value);
+ }
+ break;
+ default:
+ LOG_WARNING(logger) << "Unable to match against property of unknown type.";
+ };
+ }
+ g_variant_unref(prop_value);
+ g_variant_unref(prop_dict);
+ return matches;
+ }
+
+ std::vector<xpathselect::Node::Ptr> Children() const
+ {
+ std::vector<xpathselect::Node::Ptr> children;
+ for(auto child: node_->GetIntrospectableChildren())
+ {
+ children.push_back(std::make_shared<IntrospectableAdapter>(child, GetPath() ));
+ }
+ return children;
+
+ }
+
+ Introspectable* node_;
+ private:
+ std::string full_path_;
+ };
}
}
+bool TryLoadXPathImplementation();
GVariant* GetState(std::string const& query);
void StartLogToFile(std::string const& file_path);
void ResetLogging();
@@ -155,20 +306,40 @@ GVariant* DebugDBusInterface::HandleDBusMethodCall(std::string const& method, GV
return nullptr;
}
-
GVariant* GetState(std::string const& query)
{
- // process the XPath query:
- std::list<Introspectable*> parts = GetIntrospectableNodesFromQuery(query, _parent_introspectable);
GVariantBuilder builder;
g_variant_builder_init(&builder, G_VARIANT_TYPE("a(sv)"));
- if (parts.empty())
+
+ // try load the xpathselect library:
+ void* driver = dlopen("libxpathselect.so", RTLD_LAZY);
+ if (driver)
{
- LOG_WARNING(logger) << "Query '" << query << "' Did not match anything.";
+ typedef decltype(&xpathselect::SelectNodes) entry_t;
+ // clear errors:
+ dlerror();
+ entry_t entry_point = (entry_t) dlsym(driver, "SelectNodes");
+ const char* err = dlerror();
+ if (err)
+ {
+ LOG_ERROR(logger) << "Unable to load entry point in libxpathselect: " << err;
+ }
+ else
+ {
+ // process the XPath query:
+ local::IntrospectableAdapter::Ptr root_node = std::make_shared<local::IntrospectableAdapter>(_parent_introspectable, std::string());
+ auto nodes = entry_point(root_node, query);
+ for (auto n : nodes)
+ {
+ auto p = std::static_pointer_cast<local::IntrospectableAdapter>(n);
+ if (p)
+ g_variant_builder_add(&builder, "(sv)", p->GetPath().c_str(), p->node_->Introspect());
+ }
+ }
}
- for (Introspectable *node : parts)
+ else
{
- g_variant_builder_add(&builder, "(sv)", node->GetName().c_str(), node->Introspect());
+ LOG_WARNING(logger) << "Cannot complete introspection request because libxpathselect is not installed.";
}
return g_variant_new("(a(sv))", &builder);
@@ -208,122 +379,5 @@ void LogMessage(std::string const& severity,
}
}
-/*
- * Do a breadth-first search of the introspection tree and find all nodes that match the
- * query.
- */
-std::list<Introspectable*> GetIntrospectableNodesFromQuery(std::string const& query, Introspectable* tree_root)
-{
- std::list<Introspectable*> start_points;
- std::string sanitised_query;
- // Allow user to be lazy when specifying root node.
- if (query == "" || query == "/")
- {
- sanitised_query = "/" + tree_root->GetName();
- }
- else
- {
- sanitised_query = query;
- }
- // split query into parts
- std::list<XPathQueryPart> query_parts;
-
- {
- std::list<std::string> query_strings;
- boost::algorithm::split(query_strings, sanitised_query, boost::algorithm::is_any_of("/"));
- // Boost's split() implementation does not match it's documentation! According to the
- // docs, it's not supposed to add empty strings, but it does, which is a PITA. This
- // next line removes them:
- query_strings.erase( std::remove_if( query_strings.begin(),
- query_strings.end(),
- boost::bind( &std::string::empty, _1 ) ),
- query_strings.end());
- for (auto part : query_strings)
- {
- query_parts.push_back(XPathQueryPart(part));
- }
- }
-
- // absolute or relative query string?
- if (sanitised_query.at(0) == '/' && sanitised_query.at(1) != '/')
- {
- // absolute query - start point is tree root node.
- if (query_parts.front().Matches(tree_root))
- {
- start_points.push_back(tree_root);
- }
- }
- else
- {
- // relative - need to do a depth first tree search for all nodes that match the
- // first node in the query.
-
- // warn about malformed queries (all queries must start with '/')
- if (sanitised_query.at(0) != '/')
- {
- LOG_WARNING(logger) << "Malformed relative introspection query: '" << query << "'.";
- }
-
- // non-recursive BFS traversal to find starting points:
- std::queue<Introspectable*> queue;
- queue.push(tree_root);
- while (!queue.empty())
- {
- Introspectable *node = queue.front();
- queue.pop();
- if (query_parts.front().Matches(node))
- {
- // found one. We keep going deeper, as there may be another node beneath this one
- // with the same node name.
- start_points.push_back(node);
- }
- // Add all children of current node to queue.
- for (Introspectable* child : node->GetIntrospectableChildren())
- {
- queue.push(child);
- }
- }
- }
-
- // now we have the tree start points, process them:
- query_parts.pop_front();
- typedef std::pair<Introspectable*, std::list<XPathQueryPart>::iterator> node_match_pair;
-
- std::queue<node_match_pair> traverse_queue;
- for (Introspectable *node : start_points)
- {
- traverse_queue.push(node_match_pair(node, query_parts.begin()));
- }
- start_points.clear();
-
- while (!traverse_queue.empty())
- {
- node_match_pair p = traverse_queue.front();
- traverse_queue.pop();
-
- Introspectable *node = p.first;
- auto query_it = p.second;
-
- if (query_it == query_parts.end())
- {
- // found a match:
- start_points.push_back(node);
- }
- else
- {
- // push all children of current node to start of queue, advance search iterator, and loop again.
- for (Introspectable* child : node->GetIntrospectableChildren())
- {
- if (query_it->Matches(child))
- {
- auto it_copy(query_it);
- ++it_copy;
- traverse_queue.push(node_match_pair(child, it_copy));
- }
- }
- }
- }
- return start_points;
-}
}
}
diff --git a/unity-shared/DebugDBusInterface.h b/unity-shared/DebugDBusInterface.h
index 99dbb1751..59fd06268 100644
--- a/unity-shared/DebugDBusInterface.h
+++ b/unity-shared/DebugDBusInterface.h
@@ -33,7 +33,6 @@ extern const std::string DBUS_BUS_NAME;
namespace debug
{
class Introspectable;
-std::list<Introspectable*> GetIntrospectableNodesFromQuery(std::string const& query, Introspectable *tree_root);
class DebugDBusInterface
{
diff --git a/unity-shared/XPathQueryPart.cpp b/unity-shared/XPathQueryPart.cpp
deleted file mode 100644
index 3608a50b4..000000000
--- a/unity-shared/XPathQueryPart.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2010 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authored by: Thomi Richards <thomi.richards@canonical.com>
- */
-
-#include <sstream>
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/split.hpp>
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/bind.hpp>
-#include <NuxCore/Logger.h>
-#include "XPathQueryPart.h"
-#include "Introspectable.h"
-
-namespace unity
-{
-
-namespace debug
-{
-DECLARE_LOGGER(logger, "unity.debug.xpath");
-
-// Stores a part of an XPath query.
-XPathQueryPart::XPathQueryPart(std::string const& query_part)
-{
- std::vector<std::string> part_pieces;
- boost::algorithm::split(part_pieces, query_part, boost::algorithm::is_any_of("[]="));
- // Boost's split() implementation does not match it's documentation! According to the
- // docs, it's not supposed to add empty strings, but it does, which is a PITA. This
- // next line removes them:
- part_pieces.erase( std::remove_if( part_pieces.begin(),
- part_pieces.end(),
- boost::bind( &std::string::empty, _1 ) ),
- part_pieces.end());
- if (part_pieces.size() == 1)
- {
- node_name_ = part_pieces.at(0);
- }
- else if (part_pieces.size() == 3)
- {
- node_name_ = part_pieces.at(0);
- param_name_ = part_pieces.at(1);
- param_value_ = part_pieces.at(2);
- }
- else
- {
- LOG_WARNING(logger) << "Malformed query part: " << query_part;
- // assume it's just a node name:
- node_name_ = query_part;
- }
-}
-
-bool XPathQueryPart::Matches(Introspectable* node) const
-{
- bool matches = false;
- if (param_name_ == "")
- {
- matches = (node_name_ == "*" || node->GetName() == node_name_);
- }
- else
- {
- GVariantBuilder child_builder;
- g_variant_builder_init(&child_builder, G_VARIANT_TYPE("a{sv}"));
- g_variant_builder_add(&child_builder, "{sv}", "id", g_variant_new_uint64(node->GetIntrospectionId()));
- node->AddProperties(&child_builder);
- GVariant* prop_dict = g_variant_builder_end(&child_builder);
- GVariant *prop_value = g_variant_lookup_value(prop_dict, param_name_.c_str(), NULL);
-
- if (prop_value != NULL)
- {
- GVariantClass prop_val_type = g_variant_classify(prop_value);
- // it'd be nice to be able to do all this with one method. However, the booleans need
- // special treatment, and I can't figure out how to group all the integer types together
- // without resorting to template functions.... and we all know what happens when you
- // start doing that...
- switch (prop_val_type)
- {
- case G_VARIANT_CLASS_STRING:
- {
- const gchar* prop_val = g_variant_get_string(prop_value, NULL);
- if (g_strcmp0(prop_val, param_value_.c_str()) == 0)
- {
- matches = true;
- }
- }
- break;
- case G_VARIANT_CLASS_BOOLEAN:
- {
- std::string value = boost::to_upper_copy(param_value_);
- bool p = value == "TRUE" ||
- value == "ON" ||
- value == "YES" ||
- value == "1";
- matches = (g_variant_get_boolean(prop_value) == p);
- }
- break;
- case G_VARIANT_CLASS_BYTE:
- {
- // It would be nice if I could do all the integer types together, but I couldn't see how...
- std::stringstream stream(param_value_);
- int val; // changing this to guchar causes problems.
- stream >> val;
- matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
- val == g_variant_get_byte(prop_value);
- }
- break;
- case G_VARIANT_CLASS_INT16:
- {
- std::stringstream stream(param_value_);
- gint16 val;
- stream >> val;
- matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
- val == g_variant_get_int16(prop_value);
- }
- break;
- case G_VARIANT_CLASS_UINT16:
- {
- std::stringstream stream(param_value_);
- guint16 val;
- stream >> val;
- matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
- val == g_variant_get_uint16(prop_value);
- }
- break;
- case G_VARIANT_CLASS_INT32:
- {
- std::stringstream stream(param_value_);
- gint32 val;
- stream >> val;
- matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
- val == g_variant_get_int32(prop_value);
- }
- break;
- case G_VARIANT_CLASS_UINT32:
- {
- std::stringstream stream(param_value_);
- guint32 val;
- stream >> val;
- matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
- val == g_variant_get_uint32(prop_value);
- }
- break;
- case G_VARIANT_CLASS_INT64:
- {
- std::stringstream stream(param_value_);
- gint64 val;
- stream >> val;
- matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
- val == g_variant_get_int64(prop_value);
- }
- break;
- case G_VARIANT_CLASS_UINT64:
- {
- std::stringstream stream(param_value_);
- guint64 val;
- stream >> val;
- matches = (stream.rdstate() & (stream.badbit|stream.failbit)) == 0 &&
- val == g_variant_get_uint64(prop_value);
- }
- break;
- default:
- LOG_WARNING(logger) << "Unable to match against property of unknown type.";
- };
- }
- g_variant_unref(prop_value);
- g_variant_unref(prop_dict);
- }
-
- return matches;
-}
-
-}
-}
diff --git a/unity-shared/XPathQueryPart.h b/unity-shared/XPathQueryPart.h
deleted file mode 100644
index b5beb3f4f..000000000
--- a/unity-shared/XPathQueryPart.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
-/*
- * Copyright (C) 2010 Canonical Ltd
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Authored by: Thomi Richards <thomi.richards@canonical.com>
- */
-
-#include <string>
-
-#ifndef _XPATH_QUERY_PART
-#define _XPATH_QUERY_PART
-
-namespace unity
-{
-namespace debug
-{
- class Introspectable;
- // Stores a part of an XPath query.
- class XPathQueryPart
- {
- public:
- XPathQueryPart(std::string const& query_part);
- bool Matches(Introspectable* node) const;
- private:
- std::string node_name_;
- std::string param_name_;
- std::string param_value_;
- };
-
-}
-}
-
-#endif