Merge lp:~autopilot/xpathselect/experimental into lp:xpathselect

Proposed by Thomi Richards
Status: Merged
Approved by: Martin Pitt
Approved revision: 51
Merged at revision: 38
Proposed branch: lp:~autopilot/xpathselect/experimental
Merge into: lp:xpathselect
Diff against target: 1575 lines (+812/-188)
12 files modified
CMakeLists.txt (+1/-1)
debian/changelog (+7/-0)
debian/control (+2/-2)
lib/node.h (+14/-6)
lib/parser.h (+91/-11)
lib/xpathquerypart.h (+34/-5)
lib/xpathselect.cpp (+31/-6)
lib/xpathselect.h (+1/-1)
test/dummynode.h (+62/-16)
test/test_parser.cpp (+503/-114)
test/test_xpath_simple.cpp (+5/-5)
test/test_xpath_tree.cpp (+61/-21)
To merge this branch: bzr merge lp:~autopilot/xpathselect/experimental
Reviewer Review Type Date Requested Status
Martin Pitt (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+185846@code.launchpad.net

Commit message

XPathSelect type changes and API/ABI bump.

Description of the change

Change for 1.4.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Martin Pitt (pitti) wrote :

I didn't re-review every single line of course, but structurally this seems okay. It properly bumps the SONAME and all that, and test coverage is fine.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2013-04-18 03:29:31 +0000
+++ CMakeLists.txt 2013-09-16 15:53:33 +0000
@@ -6,7 +6,7 @@
66
7include (GNUInstallDirs)7include (GNUInstallDirs)
88
9set (VERSION 1.3)9set (VERSION 1.4)
1010
11if(CMAKE_BUILD_TYPE STREQUAL "coverage")11if(CMAKE_BUILD_TYPE STREQUAL "coverage")
12 message("Building for coverage")12 message("Building for coverage")
1313
=== modified file 'debian/changelog'
--- debian/changelog 2013-06-05 09:01:46 +0000
+++ debian/changelog 2013-09-16 15:53:33 +0000
@@ -1,3 +1,10 @@
1xpathselect (1.4-0ubuntu1) saucy; urgency=low
2
3 [ Thomi Richards ]
4 * New API, bump version to 1.4.
5
6 -- Thomi Richards <thomi.richards@canonical.com> Thu, 15 Aug 2013 11:08:08 +1200
7
1xpathselect (1.3daily13.06.05.1-0ubuntu1) saucy; urgency=low8xpathselect (1.3daily13.06.05.1-0ubuntu1) saucy; urgency=low
29
3 [ Thomi Richards ]10 [ Thomi Richards ]
411
=== modified file 'debian/control'
--- debian/control 2013-04-18 03:29:31 +0000
+++ debian/control 2013-09-16 15:53:33 +0000
@@ -20,14 +20,14 @@
20Section: libdevel20Section: libdevel
21Architecture: any21Architecture: any
22Depends: ${misc:Depends},22Depends: ${misc:Depends},
23 libxpathselect1.3 (= ${binary:Version}),23 libxpathselect1.4 (= ${binary:Version}),
24Description: Select objects in an object tree using XPath queries - development files24Description: Select objects in an object tree using XPath queries - development files
25 This library allows you to select arbitrary objects in an object tree using a25 This library allows you to select arbitrary objects in an object tree using a
26 small subset of the XPath specification.26 small subset of the XPath specification.
27 .27 .
28 This package contains development files for xpathselect.28 This package contains development files for xpathselect.
2929
30Package: libxpathselect1.330Package: libxpathselect1.4
31Section: libs31Section: libs
32Architecture: any32Architecture: any
33Multi-Arch: same33Multi-Arch: same
3434
=== renamed file 'debian/libxpathselect1.3.install' => 'debian/libxpathselect1.4.install'
=== modified file 'lib/node.h'
--- lib/node.h 2013-04-22 02:18:53 +0000
+++ lib/node.h 2013-09-16 15:53:33 +0000
@@ -20,7 +20,9 @@
2020
21#include <string>21#include <string>
22#include <vector>22#include <vector>
23#include <list>
23#include <memory>24#include <memory>
25#include <cstdint>
2426
25namespace xpathselect27namespace xpathselect
26{28{
@@ -29,7 +31,7 @@
29 class Node31 class Node
30 {32 {
31 public:33 public:
32 typedef std::shared_ptr<Node> Ptr;34 typedef std::shared_ptr<const Node> Ptr;
3335
34 /// Get the node's name.36 /// Get the node's name.
35 virtual std::string GetName() const =0;37 virtual std::string GetName() const =0;
@@ -37,17 +39,23 @@
37 /// Get the node's full path39 /// Get the node's full path
38 virtual std::string GetPath() const =0;40 virtual std::string GetPath() const =0;
3941
40 /// Return true if the node matches the property with the given name & value42 /// Get this node's ID.
41 ///\note: All property values are treated as strings. It is the implementors43 virtual int32_t GetId() const =0;
42 /// responsibility to convert the value to the appropriate type.44
43 virtual bool MatchProperty(const std::string& name, const std::string& value) const =0;45 virtual bool MatchBooleanProperty(const std::string& name, bool value) const =0;
46 virtual bool MatchIntegerProperty(const std::string& name, int32_t value) const =0;
47 virtual bool MatchStringProperty(const std::string& name, const std::string& value) const =0;
4448
45 /// Return a list of the children of this node.49 /// Return a list of the children of this node.
46 virtual std::vector<Node::Ptr> Children() const =0;50 virtual std::vector<Node::Ptr> Children() const =0;
51
52 /// Return a pointer to the parent class.
53 virtual Node::Ptr GetParent() const =0;
47 };54 };
4855
49 /// NodeList is how we return lists of nodes.56 /// NodeList is how we return lists of nodes.
50 typedef std::vector<Node::Ptr> NodeList;57 typedef std::vector<Node::Ptr> NodeVector;
58 typedef std::list<Node::Ptr> NodeList;
51}59}
5260
53#endif61#endif
5462
=== modified file 'lib/parser.h'
--- lib/parser.h 2013-04-24 20:38:18 +0000
+++ lib/parser.h 2013-09-16 15:53:33 +0000
@@ -18,12 +18,15 @@
18#define _PARSER_H18#define _PARSER_H
1919
20#include <string>20#include <string>
21#include <cstdint>
2122
22#include <boost/config/warning_disable.hpp>23#include <boost/config/warning_disable.hpp>
23#include <boost/fusion/include/adapt_struct.hpp>24#include <boost/fusion/include/adapt_struct.hpp>
24#include <boost/spirit/include/phoenix_object.hpp>25#include <boost/spirit/include/phoenix_object.hpp>
25#include <boost/spirit/include/phoenix_operator.hpp>26#include <boost/spirit/include/phoenix_operator.hpp>
26#include <boost/spirit/include/qi.hpp>27#include <boost/spirit/include/qi.hpp>
28#include <boost/spirit/include/qi_bool.hpp>
29#include <boost/spirit/include/qi_int.hpp>
2730
28#include "xpathquerypart.h"31#include "xpathquerypart.h"
2932
@@ -37,7 +40,7 @@
37BOOST_FUSION_ADAPT_STRUCT(40BOOST_FUSION_ADAPT_STRUCT(
38 xpathselect::XPathQueryParam,41 xpathselect::XPathQueryParam,
39 (std::string, param_name)42 (std::string, param_name)
40 (std::string, param_value)43 (xpathselect::XPathQueryParam::ParamValueType, param_value)
41 );44 );
4245
43namespace xpathselect46namespace xpathselect
@@ -47,6 +50,33 @@
47namespace qi = boost::spirit::qi;50namespace qi = boost::spirit::qi;
48namespace phoenix = boost::phoenix;51namespace phoenix = boost::phoenix;
4952
53 // python_bool_policy determines what can be considered truthy. We follow python
54 // repr format.
55 struct python_bool_policy : qi::bool_policies<>
56 {
57 template <typename Iterator, typename Attribute>
58 static bool parse_true(Iterator& first, Iterator const& last, Attribute& attr)
59 {
60 if (qi::detail::string_parse("True", first, last, qi::unused))
61 {
62 boost::spirit::traits::assign_to(true, attr); // result is true
63 return true; // parsing succeeded
64 }
65 return false; // parsing failed
66 }
67
68 template <typename Iterator, typename Attribute>
69 static bool parse_false(Iterator& first, Iterator const& last, Attribute& attr)
70 {
71 if (qi::detail::string_parse("False", first, last, qi::unused))
72 {
73 boost::spirit::traits::assign_to(false, attr); // result is false
74 return true;
75 }
76 return false;
77 }
78 };
79
50 // This is the main XPath grammar. It looks horrible, until you emerse yourself in it for a few80 // This is the main XPath grammar. It looks horrible, until you emerse yourself in it for a few
51 // days, then the beauty of boost::spirit creeps into your brain. To help future programmers,81 // days, then the beauty of boost::spirit creeps into your brain. To help future programmers,
52 // I've heavily commented this.82 // I've heavily commented this.
@@ -61,6 +91,46 @@
61 {91 {
62 using namespace qi::labels;92 using namespace qi::labels;
6393
94 // character escape codes. The input on the left will produce the output on
95 // the right:
96 unesc_char.add("\\a", '\a')
97 ("\\b", '\b')
98 ("\\f", '\f')
99 ("\\n", '\n')
100 ("\\r", '\r')
101 ("\\t", '\t')
102 ("\\v", '\v')
103 ("\\\\", '\\')
104 ("\\\'", '\'')
105 ("\\\"", '\"');
106
107 unesc_str = '"' >> *(
108 unesc_char |
109 qi::alnum |
110 qi::space |
111 "\\x" >> qi::hex
112 ) >> '"';
113
114 unesc_str = '"'
115 >> *(unesc_char | "\\x" >> qi::hex | (qi::print - '"'))
116 >> '"'
117 ;
118
119 int_type = qi::int_parser<int32_t>();
120
121 // Parameter grammar:
122 // parameter name can contain some basic text (no spaces or '.')
123 param_name = +qi::char_("a-zA-Z0-9_\\-");
124
125 // parameter values can be several different types.
126 // Alternatives are tried left to right, and the first match found is the one used.
127 param_value = unesc_str | int_type | bool_type;
128 // parameter specification is simple: name=value
129 param %= param_name >> '=' >> param_value;
130 // a parameter list is a list of parameters separated by ',''s surrounded in '[...]'
131 param_list = '[' >> param % ',' >> ']';
132
133
64 // spec_node_name is a node name that has been explicitly specified.134 // spec_node_name is a node name that has been explicitly specified.
65 // it must start and end with a non-space character, but you can have135 // it must start and end with a non-space character, but you can have
66 // spaces in the middle.136 // spaces in the middle.
@@ -68,14 +138,6 @@
68 // a wildcard node name is simply a '*'138 // a wildcard node name is simply a '*'
69 wildcard_node_name = qi::char_("*");139 wildcard_node_name = qi::char_("*");
70140
71 // parameter name can contain some basic text (no spaces or '.')
72 param_name = +qi::char_("a-zA-Z0-9_\\-");
73 // parameter values can have more stuff in them.
74 param_value = +qi::char_("a-z.A-Z0-9_\\-") >> *(+qi::char_(" ") >> +qi::char_("a-z.A-Z0-9_\\-"));
75 // parameter specification is simple: name=value
76 param %= param_name >> '=' >> param_value;
77 // a parameter list is a list of parameters separated by ',''s surrounded in '[...]'
78 param_list = '[' >> param % ',' >> ']';
79141
80 // a spec_node consists of a specified node name, followed by an *optional* parameter list.142 // a spec_node consists of a specified node name, followed by an *optional* parameter list.
81 spec_node %= spec_node_name >> -(param_list);143 spec_node %= spec_node_name >> -(param_list);
@@ -83,15 +145,18 @@
83 wildcard_node %= wildcard_node_name >> !param_list;145 wildcard_node %= wildcard_node_name >> !param_list;
84 // wildcard nodes can also have parameters:146 // wildcard nodes can also have parameters:
85 wildcard_node_with_params %= wildcard_node_name >> param_list;147 wildcard_node_with_params %= wildcard_node_name >> param_list;
148 // A parent node is '..' as long as it's followed by a normal separator or end of input:
149 parent_node = qi::lit("..")[qi::_val = XPathQueryPart("..")];
86150
87 // node is simply any kind of code defined thus far:151 // node is simply any kind of code defined thus far:
88 node = spec_node | wildcard_node_with_params | wildcard_node;152 node = spec_node | wildcard_node_with_params | wildcard_node | parent_node;
89153
90 // a search node is '//' as long as it's followed by a spec node or a wildcard node with parameters.154 // a search node is '//' as long as it's followed by a spec node or a wildcard node with parameters.
91 // we don't allow '//*' since it would match everything in the tree, and cause HUGE amounts of155 // we don't allow '//*' since it would match everything in the tree, and cause HUGE amounts of
92 // data to be transmitted.156 // data to be transmitted.
93 search_node = "//" >> &(spec_node | wildcard_node_with_params)[qi::_val = XPathQueryPart()];157 search_node = "//" >> &(spec_node | wildcard_node_with_params)[qi::_val = XPathQueryPart()];
94158
159
95 // a normal separator is a '/' as long as it's followed by something other than another '/'160 // a normal separator is a '/' as long as it's followed by something other than another '/'
96 normal_sep = '/' >> !qi::lit('/');161 normal_sep = '/' >> !qi::lit('/');
97 separator = normal_sep | search_node; // nodes can be separated by normal_sep or search_node.162 separator = normal_sep | search_node; // nodes can be separated by normal_sep or search_node.
@@ -147,14 +212,29 @@
147#endif212#endif
148 }213 }
149 // declare all the rules. The second template parameter is the type they produce.214 // declare all the rules. The second template parameter is the type they produce.
215 // basic type rules:
216
217 // parse python Boolean represetnations 'True' or 'False':
218 qi::bool_parser<bool, python_bool_policy> bool_type;
219
220 // parse an escaped byte string.
221 qi::rule<Iterator, std::string()> unesc_str;
222 // symbol table for chracter scape codes.
223 qi::symbols<char const, char const> unesc_char;
224
225 // parse integers, first signed then unsigned:
226 qi::rule<Iterator, int32_t()> int_type;
227
228 // more complicated language rules:
150 qi::rule<Iterator, std::string()> spec_node_name;229 qi::rule<Iterator, std::string()> spec_node_name;
151 qi::rule<Iterator, std::string()> wildcard_node_name;230 qi::rule<Iterator, std::string()> wildcard_node_name;
152 qi::rule<Iterator, XPathQueryPart()> search_node;231 qi::rule<Iterator, XPathQueryPart()> search_node;
232 qi::rule<Iterator, XPathQueryPart()> parent_node;
153 qi::rule<Iterator> normal_sep;233 qi::rule<Iterator> normal_sep;
154 qi::rule<Iterator, xpathselect::QueryList()> separator;234 qi::rule<Iterator, xpathselect::QueryList()> separator;
155235
156 qi::rule<Iterator, std::string()> param_name;236 qi::rule<Iterator, std::string()> param_name;
157 qi::rule<Iterator, std::string()> param_value;237 qi::rule<Iterator, xpathselect::XPathQueryParam::ParamValueType()> param_value;
158 qi::rule<Iterator, XPathQueryParam()> param;238 qi::rule<Iterator, XPathQueryParam()> param;
159 qi::rule<Iterator, xpathselect::ParamList()> param_list;239 qi::rule<Iterator, xpathselect::ParamList()> param_list;
160240
161241
=== modified file 'lib/xpathquerypart.h'
--- lib/xpathquerypart.h 2013-06-05 07:31:01 +0000
+++ lib/xpathquerypart.h 2013-09-16 15:53:33 +0000
@@ -24,6 +24,8 @@
24#include <iostream>24#include <iostream>
2525
26#include <boost/optional/optional.hpp>26#include <boost/optional/optional.hpp>
27#include <boost/variant/variant.hpp>
28#include <boost/variant/get.hpp>
2729
28#include "node.h"30#include "node.h"
2931
@@ -32,8 +34,11 @@
32 // stores a parameter name, value pair.34 // stores a parameter name, value pair.
33 struct XPathQueryParam35 struct XPathQueryParam
34 {36 {
37 typedef boost::variant<std::string,
38 bool,
39 int> ParamValueType;
35 std::string param_name;40 std::string param_name;
36 std::string param_value;41 ParamValueType param_value;
37 };42 };
3843
39 typedef std::vector<XPathQueryParam> ParamList;44 typedef std::vector<XPathQueryParam> ParamList;
@@ -47,7 +52,7 @@
47 : node_name_(node_name)52 : node_name_(node_name)
48 {}53 {}
4954
50 enum class QueryPartType {Normal, Search};55 enum class QueryPartType {Normal, Search, Parent};
5156
52 bool Matches(Node::Ptr const& node) const57 bool Matches(Node::Ptr const& node) const
53 {58 {
@@ -56,15 +61,39 @@
56 {61 {
57 for (auto param : parameter)62 for (auto param : parameter)
58 {63 {
59 matches &= node->MatchProperty(param.param_name, param.param_value);64 switch(param.param_value.which())
6065 {
66 case 0:
67 {
68 matches &= node->MatchStringProperty(param.param_name, boost::get<std::string>(param.param_value));
69 }
70 break;
71 case 1:
72 {
73 matches &= node->MatchBooleanProperty(param.param_name, boost::get<bool>(param.param_value));
74 }
75 break;
76 case 2:
77 {
78 matches &= node->MatchIntegerProperty(param.param_name, boost::get<int>(param.param_value));
79 }
80 break;
81 }
61 }82 }
62 }83 }
6384
64 return matches;85 return matches;
65 }86 }
6687
67 QueryPartType Type() const { return (node_name_ == "") ? QueryPartType::Search : QueryPartType::Normal; }88 QueryPartType Type() const
89 {
90 if (node_name_ == "")
91 return QueryPartType::Search;
92 else if (node_name_ == "..")
93 return QueryPartType::Parent;
94 else
95 return QueryPartType::Normal;
96 }
6897
69 void Dump() const98 void Dump() const
70 {99 {
71100
=== modified file 'lib/xpathselect.cpp'
--- lib/xpathselect.cpp 2013-04-24 08:57:16 +0000
+++ lib/xpathselect.cpp 2013-09-16 15:53:33 +0000
@@ -82,7 +82,7 @@
82 }82 }
83 } // end of anonymous namespace83 } // end of anonymous namespace
8484
85 NodeList SelectNodes(Node::Ptr const& root, std::string query)85 NodeVector SelectNodes(Node::Ptr const& root, std::string query)
86 {86 {
87 // allow users to be lazy when specifying tree root:87 // allow users to be lazy when specifying tree root:
88 if (query == "" || query == "/" || query == "//")88 if (query == "" || query == "/" || query == "//")
@@ -92,7 +92,7 @@
9292
93 QueryList query_parts = GetQueryPartsFromQuery(query);93 QueryList query_parts = GetQueryPartsFromQuery(query);
94 if (query_parts.empty())94 if (query_parts.empty())
95 return NodeList();95 return NodeVector();
96 auto query_part = query_parts.cbegin();96 auto query_part = query_parts.cbegin();
97 NodeList start_nodes { root };97 NodeList start_nodes { root };
98 while (query_part != query_parts.cend())98 while (query_part != query_parts.cend())
@@ -105,12 +105,24 @@
105 // do some sanity checking...105 // do some sanity checking...
106 if (query_part->Type() == XPathQueryPart::QueryPartType::Search)106 if (query_part->Type() == XPathQueryPart::QueryPartType::Search)
107 // invalid query - cannot specify multiple search sequences in a row.107 // invalid query - cannot specify multiple search sequences in a row.
108 return NodeList();108 return NodeVector();
109 // then find all the nodes that match the new query part, and store them as109 // then find all the nodes that match the new query part, and store them as
110 // the new start nodes. We pass in 'start_nodes' rather than 'root' since110 // the new start nodes. We pass in 'start_nodes' rather than 'root' since
111 // there's a chance we'll be doing more than one search in different parts of the tree.111 // there's a chance we'll be doing more than one search in different parts of the tree.
112 start_nodes = SearchTreeForNode(start_nodes, *query_part);112 start_nodes = SearchTreeForNode(start_nodes, *query_part);
113 }113 }
114 else if (query_part->Type() == XPathQueryPart::QueryPartType::Parent)
115 {
116 // This part of the query selects the parent node. If the current node has no
117 // parent (i.e.- we're already at the root of the tree) then this is a no-op:
118 NodeList new_start_nodes;
119 for (auto n: start_nodes)
120 {
121 auto parent = n->GetParent();
122 new_start_nodes.push_back(parent ? parent : n);
123 }
124 start_nodes = new_start_nodes;
125 }
114 else126 else
115 {127 {
116 // this isn't a search token. Look at each node in the start_nodes list,128 // this isn't a search token. Look at each node in the start_nodes list,
@@ -128,8 +140,11 @@
128 );140 );
129 }141 }
130 // then replace each node still in the list with all it's children.142 // then replace each node still in the list with all it's children.
131 // ... but only if we're not on the last query part:143 // ... but only if we're not on the last query part, and only if the
132 if (query_part + 1 != query_parts.cend())144 // next query part is not a parent node...
145 auto next_query_part = query_part + 1;
146 if (next_query_part != query_parts.cend()
147 && next_query_part->Type() != XPathQueryPart::QueryPartType::Parent)
133 {148 {
134 NodeList new_start_nodes;149 NodeList new_start_nodes;
135 for (auto node: start_nodes)150 for (auto node: start_nodes)
@@ -147,6 +162,16 @@
147 }162 }
148 ++query_part;163 ++query_part;
149 }164 }
150 return start_nodes;165 // remove duplicate nodes by sorting & unique'ing:
166 // we could probably do this better, but since start_nodes is
167 // typically very small at this stage, I'm not sure it's worth it:
168 start_nodes.sort([](Node::Ptr a, Node::Ptr b) -> bool {
169 return a->GetId() < b->GetId();
170 });
171 start_nodes.unique([](Node::Ptr a, Node::Ptr b) -> bool {
172 return a->GetId() == b->GetId();
173 });
174
175 return NodeVector(start_nodes.begin(), start_nodes.end());
151 }176 }
152}177}
153178
=== modified file 'lib/xpathselect.h'
--- lib/xpathselect.h 2013-02-01 23:20:24 +0000
+++ lib/xpathselect.h 2013-09-16 15:53:33 +0000
@@ -24,7 +24,7 @@
24{24{
25 /// Search the node tree beginning with 'root' and return nodes that25 /// Search the node tree beginning with 'root' and return nodes that
26 /// match 'query'.26 /// match 'query'.
27 extern "C" NodeList SelectNodes(Node::Ptr const& root, std::string query);27 extern "C" NodeVector SelectNodes(Node::Ptr const& root, std::string query);
28}28}
2929
30#endif30#endif
3131
=== modified file 'test/dummynode.h'
--- test/dummynode.h 2013-04-18 03:29:31 +0000
+++ test/dummynode.h 2013-09-16 15:53:33 +0000
@@ -23,12 +23,17 @@
23#include <map>23#include <map>
2424
25// simple implementation of the node interface for testing purposes.25// simple implementation of the node interface for testing purposes.
26class DummyNode: public xpathselect::Node26class DummyNode: public xpathselect::Node, public std::enable_shared_from_this<DummyNode>
27{27{
28public:28public:
29 typedef std::shared_ptr<DummyNode> Ptr;
30
29 DummyNode(std::string name="DummyNode")31 DummyNode(std::string name="DummyNode")
30 : name_(name)32 : name_(name)
31 {}33 {
34 static int32_t id = 1;
35 id_ = id++;
36 }
3237
33 std::string GetName() const override38 std::string GetName() const override
34 {39 {
@@ -40,38 +45,79 @@
40 return std::string();45 return std::string();
41 }46 }
4247
48 int32_t GetId() const override
49 {
50 return id_;
51 }
52
43 void SetName(std::string const& name)53 void SetName(std::string const& name)
44 {54 {
45 name_ = name;55 name_ = name;
46 }56 }
4757
48 bool MatchProperty(const std::string& name, const std::string& value) const override58 bool MatchStringProperty(const std::string& name, const std::string& value) const override
49 {59 {
50 auto it = properties_.find(name);60 auto it = string_properties_.find(name);
51 if (it == properties_.end() || it->second != value)61 if (it == string_properties_.end() || it->second != value)
52 return false;62 return false;
53 return true;63 return true;
54 }64 }
5565
56 xpathselect::NodeList Children() const override66 bool MatchBooleanProperty(const std::string& name, bool value) const override
67 {
68 auto it = bool_properties_.find(name);
69 if (it == bool_properties_.end() || it->second != value)
70 return false;
71 return true;
72 }
73
74 bool MatchIntegerProperty(const std::string& name, int value) const override
75 {
76 auto it = int_properties_.find(name);
77 if (it == int_properties_.end() || it->second != value)
78 return false;
79 return true;
80 }
81
82 xpathselect::NodeVector Children() const override
57 {83 {
58 return children_;84 return children_;
59 }85 }
6086
61 void AddChild(Node::Ptr const& child)87 virtual Node::Ptr GetParent() const override
62 {88 {
89 return parent_;
90 }
91
92 void AddChild(Ptr const& child)
93 {
94 child->parent_ = shared_from_this();
63 children_.push_back(child);95 children_.push_back(child);
64 }96 }
6597
66 void AddProperty(std::string const& name, std::string const& value)98 void AddProperty(std::string const& name, std::string const& value)
67 {99 {
68 properties_[name] = value;100 string_properties_[name] = value;
101 }
102
103 void AddProperty(std::string const& name, bool value)
104 {
105 bool_properties_[name] = value;
106 }
107
108 void AddProperty(std::string const& name, int value)
109 {
110 int_properties_[name] = value;
69 }111 }
70112
71private:113private:
114 int32_t id_;
72 std::string name_;115 std::string name_;
73 xpathselect::NodeList children_;116 xpathselect::Node::Ptr parent_;
74 std::map<std::string, std::string> properties_;117 xpathselect::NodeVector children_;
118 std::map<std::string, std::string> string_properties_;
119 std::map<std::string, int> int_properties_;
120 std::map<std::string, bool> bool_properties_;
75};121};
76122
77123
78124
=== modified file 'test/test_parser.cpp'
--- test/test_parser.cpp 2013-04-24 09:38:10 +0000
+++ test/test_parser.cpp 2013-09-16 15:53:33 +0000
@@ -24,9 +24,13 @@
24#include <boost/spirit/include/phoenix_core.hpp>24#include <boost/spirit/include/phoenix_core.hpp>
25#include <boost/spirit/include/qi_char_class.hpp>25#include <boost/spirit/include/qi_char_class.hpp>
26#include <boost/spirit/include/phoenix_operator.hpp>26#include <boost/spirit/include/phoenix_operator.hpp>
27#include <boost/variant/variant.hpp>
28
27#include <iostream>29#include <iostream>
28#include <string>30#include <string>
29#include <cstdlib>31#include <cstdlib>
32#include <typeinfo>
33#include <limits>
3034
31namespace qi = boost::spirit::qi;35namespace qi = boost::spirit::qi;
32namespace ascii = boost::spirit::ascii;36namespace ascii = boost::spirit::ascii;
@@ -69,6 +73,355 @@
69 }73 }
70}74}
7175
76// a boost static visitor that checks value equality and type equality.
77template <typename T>
78class variant_equality_assertion : public boost::static_visitor<>
79{
80public:
81 variant_equality_assertion( T const& expected)
82 : expected_(expected)
83 {}
84
85 void operator()( T & operand ) const
86 {
87 ASSERT_EQ(expected_, operand);
88 }
89
90 template <typename U> void operator()( U & operand ) const
91 {
92 FAIL() << "Variant contained incorrect type! Expected: '"
93 << expected_
94 << "' Actual: '"
95 << operand
96 << "' Actual type is: "
97 << typeid(U).name();
98 }
99private:
100 T expected_;
101};
102
103//////////////////////////////////////
104// Tests for basic type support:
105//////////////////////////////////////
106
107
108// Test python representations for boolean values:
109TEST(TestXPathParser, test_basic_type_boolean)
110{
111 bool result = false;
112 parser::xpath_grammar<std::string::iterator> g;
113
114 ASSERT_TRUE(test_parser_attr("True", g.bool_type, result));
115 ASSERT_TRUE(result);
116
117 ASSERT_TRUE(test_parser_attr("False", g.bool_type, result));
118 ASSERT_FALSE(result);
119
120 ASSERT_FALSE(test_parser_attr("true", g.bool_type, result));
121 ASSERT_FALSE(test_parser_attr("false", g.bool_type, result));
122 ASSERT_FALSE(test_parser_attr("1", g.bool_type, result));
123 ASSERT_FALSE(test_parser_attr("0", g.bool_type, result));
124}
125
126
127// test character escape codes:
128class TestXPathParserCharacterEscapeCodes : public ::testing::TestWithParam<std::pair<std::string, char> >
129{
130};
131
132
133TEST_P(TestXPathParserCharacterEscapeCodes, test_character_escape_codes)
134{
135 auto p = GetParam();
136
137 std::string input = p.first;
138 char expected_result = p.second;
139
140 char actual_result = 0;
141 parser::xpath_grammar<std::string::iterator> g;
142
143 ASSERT_TRUE(test_parser_attr(input, g.unesc_char, actual_result));
144 ASSERT_EQ(expected_result, actual_result);
145}
146
147INSTANTIATE_TEST_CASE_P(BasicCharacterCodes,
148 TestXPathParserCharacterEscapeCodes,
149 ::testing::Values(
150 std::pair<std::string, char>("\\a", '\a'),
151 std::pair<std::string, char>("\\b", '\b'),
152 std::pair<std::string, char>("\\f", '\f'),
153 std::pair<std::string, char>("\\n", '\n'),
154 std::pair<std::string, char>("\\r", '\r'),
155 std::pair<std::string, char>("\\t", '\t'),
156 std::pair<std::string, char>("\\v", '\v'),
157 std::pair<std::string, char>("\\\\", '\\'),
158 std::pair<std::string, char>("\\\'", '\''),
159 std::pair<std::string, char>("\\\"", '\"')
160 ));
161
162
163class QuotedStringTests : public ::testing::TestWithParam<std::tuple<const char*, const char*, bool> >
164{
165};
166
167TEST_P(QuotedStringTests, quoted_string_parameter_test)
168{
169 std::string input = std::get<0>(GetParam());
170 std::string expected_output = std::get<1>(GetParam());
171 bool expected_pass = std::get<2>(GetParam());
172
173 std::string actual_result;
174 parser::xpath_grammar<std::string::iterator> g;
175
176 ASSERT_EQ(expected_pass, test_parser_attr(input, g.unesc_str, actual_result));
177 if (expected_pass)
178 ASSERT_EQ(expected_output, actual_result);
179}
180
181
182INSTANTIATE_TEST_CASE_P(BasicStrings,
183 QuotedStringTests,
184 ::testing::Values(
185 std::make_tuple("\"Hello\"", "Hello", true),
186 std::make_tuple("\"Hello World\"", "Hello World", true),
187 std::make_tuple("\"a b c d\"", "a b c d", true),
188 std::make_tuple("\"\\x41\"", "A", true),
189 std::make_tuple("\"\\x08\"", "\b", true)
190 ));
191
192INSTANTIATE_TEST_CASE_P(PunctuationStrings,
193 QuotedStringTests,
194 ::testing::Values(
195 std::make_tuple("\".\"", ".", true),
196 std::make_tuple("\",\"", ",", true),
197 std::make_tuple("\"<\"", "<", true),
198 std::make_tuple("\">\"", ">", true),
199 std::make_tuple("\"/\"", "/", true),
200 std::make_tuple("\"?\"", "?", true),
201 std::make_tuple("\":\"", ":", true),
202 std::make_tuple("\";\"", ";", true),
203 std::make_tuple("\"'\"", "'", true), // '"' tested below
204 std::make_tuple("\"[\"", "[", true),
205 std::make_tuple("\"]\"", "]", true),
206 std::make_tuple("\"{\"", "{", true),
207 std::make_tuple("\"}\"", "}", true),
208 std::make_tuple("\"\\\\\"", "\\", true),
209 std::make_tuple("\"|\"", "|", true),
210 std::make_tuple("\"~\"", "~", true),
211 std::make_tuple("\"`\"", "`", true),
212 std::make_tuple("\"!\"", "!", true),
213 std::make_tuple("\"@\"", "@", true),
214 std::make_tuple("\"#\"", "#", true),
215 std::make_tuple("\"$\"", "$", true),
216 std::make_tuple("\"%\"", "%", true),
217 std::make_tuple("\"^\"", "^", true),
218 std::make_tuple("\"&\"", "&", true),
219 std::make_tuple("\"*\"", "*", true),
220 std::make_tuple("\"(\"", "(", true),
221 std::make_tuple("\")\"", ")", true),
222 std::make_tuple("\"-\"", "-", true),
223 std::make_tuple("\"_\"", "_", true),
224 std::make_tuple("\"+\"", "+", true),
225 std::make_tuple("\"=\"", "=", true)
226 ));
227
228INSTANTIATE_TEST_CASE_P(QuoteStrings,
229 QuotedStringTests,
230 ::testing::Values(
231 std::make_tuple("\"\\\"\"", "\"", true),
232 std::make_tuple("\"\\\'\"", "\'", true)
233 ));
234
235INSTANTIATE_TEST_CASE_P(NumberStrings,
236 QuotedStringTests,
237 ::testing::Values(
238 std::make_tuple("\"0\"", "0", true),
239 std::make_tuple("\"1\"", "1", true),
240 std::make_tuple("\"2\"", "2", true),
241 std::make_tuple("\"3\"", "3", true),
242 std::make_tuple("\"4\"", "4", true),
243 std::make_tuple("\"5\"", "5", true),
244 std::make_tuple("\"6\"", "6", true),
245 std::make_tuple("\"7\"", "7", true),
246 std::make_tuple("\"8\"", "8", true),
247 std::make_tuple("\"9\"", "9", true)
248 ));
249
250
251TEST(TestIntegerTypes, test_signed_integers)
252{
253 int result = 0;
254 parser::xpath_grammar<std::string::iterator> g;
255
256 ASSERT_TRUE(test_parser_attr("123", g.int_type, result));
257 ASSERT_EQ(123, result);
258
259 ASSERT_TRUE(test_parser_attr("+456", g.int_type, result));
260 ASSERT_EQ(456, result);
261
262 ASSERT_TRUE(test_parser_attr("-123", g.int_type, result));
263 ASSERT_EQ(-123, result);
264}
265
266
267// This test fails due to a bug in boost::spirit: https://svn.boost.org/trac/boost/ticket/9007
268// TEST(TestIntegerTypes, test_integer_overflow)
269// {
270// int result;
271
272// // store range of int in a long, since we'll be extending them
273// long min_int = std::numeric_limits<int>::min();
274// long max_int = std::numeric_limits<int>::max();
275
276// qi::int_parser<int> r;
277
278// ASSERT_TRUE(test_parser_attr(std::to_string(min_int), r, result));
279// ASSERT_EQ(min_int, result);
280
281// ASSERT_TRUE(test_parser_attr(std::to_string(max_int), r, result));
282// ASSERT_EQ(max_int, result);
283
284// min_int -= 1;
285// max_int += 1;
286
287// // these last two assertions are failing. I expect the parsing to fail, but it's passing
288// // for some reason.
289// ASSERT_FALSE(test_parser_attr(std::to_string(min_int), r, result)) << min_int;
290// ASSERT_FALSE(test_parser_attr(std::to_string(max_int), r, result)) << max_int;
291// }
292
293
294////////////////////////////////////
295// more complicated grammar tests
296////////////////////////////////////
297
298/// Tests for parameter names:
299class TestXPathParserParamNames : public ::testing::TestWithParam<std::pair<std::string, bool> >
300{
301};
302
303TEST_P(TestXPathParserParamNames, test_param_name)
304{
305 auto p = GetParam();
306
307 std::string input = p.first;
308 bool expect_pass = p.second;
309
310 parser::xpath_grammar<std::string::iterator> g;
311
312 std::string result;
313 ASSERT_EQ( expect_pass, test_parser_attr(input, g.param_name, result) );
314 if (expect_pass)
315 ASSERT_EQ(input, result);
316}
317
318INSTANTIATE_TEST_CASE_P(BasicNodeNames,
319 TestXPathParserParamNames,
320 ::testing::Values(
321 std::pair<std::string, bool>("a b", false),
322 std::pair<std::string, bool>("a*", false),
323 std::pair<std::string, bool>("HelloWorld", true),
324 std::pair<std::string, bool>("H", true),
325 std::pair<std::string, bool>("h", true),
326 std::pair<std::string, bool>("1", true),
327 std::pair<std::string, bool>("node-name", true),
328 std::pair<std::string, bool>("node_name", true),
329 std::pair<std::string, bool>("node\\name", true),
330 std::pair<std::string, bool>("node.name", false),
331 std::pair<std::string, bool>("node name", false),
332 std::pair<std::string, bool>("..", false)
333 ));
334
335/// Tests for parameter values. This test is much larger than it should be, since it seems to be
336// impossible to parameterise tests for both type and value. The solution I use here is to have
337// the actual test in a base class template method, and have several derive classes use different
338// value parameters. Ugly, but probably the best we can do with google test.
339
340class TestParamValues : public ::testing::Test
341{
342public:
343 template <typename PairType>
344 void test_param_value(PairType const& input_pair) const
345 {
346 RecordProperty("FirstType", typeid(typename PairType::first_type).name());
347 RecordProperty("SecondType", typeid(typename PairType::second_type).name());
348 std::string input = input_pair.first;
349 typename PairType::second_type expected_result = input_pair.second;
350
351 parser::xpath_grammar<std::string::iterator> g;
352
353 xpathselect::XPathQueryParam::ParamValueType result;
354 ASSERT_TRUE( test_parser_attr(input, g.param_value, result) );
355 boost::apply_visitor(
356 variant_equality_assertion<typename PairType::second_type>(expected_result),
357 result
358 );
359 }
360};
361
362// test string parameter values:
363class TestStringParamValues
364 : public ::testing::WithParamInterface<std::pair<std::string, std::string> >
365 , public TestParamValues
366{
367};
368
369TEST_P(TestStringParamValues, test_param_value_str)
370{
371 auto p = GetParam();
372 test_param_value(p);
373}
374
375INSTANTIATE_TEST_CASE_P(StringParams,
376 TestStringParamValues,
377 ::testing::Values(
378 std::pair<std::string, std::string>("\"a b\"", "a b" ),
379 std::pair<std::string, std::string>("\"a.b,c/\\d^\"", "a.b,c/\\d^" )
380 ));
381
382// test boolean parameter values:
383class TestBoolParamValues
384 : public ::testing::WithParamInterface<std::pair<std::string, bool> >
385 , public TestParamValues
386{
387};
388
389TEST_P(TestBoolParamValues, test_param_value_bool)
390{
391 auto p = GetParam();
392 test_param_value(p);
393}
394
395INSTANTIATE_TEST_CASE_P(StringParams,
396 TestBoolParamValues,
397 ::testing::Values(
398 std::pair<std::string, bool>("True", true ),
399 std::pair<std::string, bool>("False", false )
400 ));
401
402// test integer parameter values:
403class TestIntParamValues
404 : public ::testing::WithParamInterface<std::pair<std::string, int> >
405 , public TestParamValues
406{
407};
408
409TEST_P(TestIntParamValues, test_param_value_bool)
410{
411 auto p = GetParam();
412 test_param_value(p);
413}
414
415INSTANTIATE_TEST_CASE_P(IntegerParams,
416 TestIntParamValues,
417 ::testing::Values(
418 std::pair<std::string, int>("123", 123 ),
419 std::pair<std::string, int>("0", 0 ),
420 std::pair<std::string, int>("-123", -123 )
421 ));
422
423
424/// Tests for the node names:
72class TestXPathParserNodeNames : public ::testing::TestWithParam<std::pair<std::string, bool> >425class TestXPathParserNodeNames : public ::testing::TestWithParam<std::pair<std::string, bool> >
73{426{
74};427};
@@ -108,87 +461,6 @@
108 std::pair<std::string, bool>("node\\name", true)461 std::pair<std::string, bool>("node\\name", true)
109 ));462 ));
110463
111class TestXPathParserParamNames : public ::testing::TestWithParam<std::pair<std::string, bool> >
112{
113};
114
115TEST_P(TestXPathParserParamNames, test_param_name)
116{
117 auto p = GetParam();
118
119 std::string input = p.first;
120 bool expect_pass = p.second;
121
122 parser::xpath_grammar<std::string::iterator> g;
123
124 std::string result;
125 ASSERT_EQ( expect_pass, test_parser_attr(input, g.param_name, result) );
126 if (expect_pass)
127 ASSERT_EQ(input, result);
128}
129
130INSTANTIATE_TEST_CASE_P(BasicNodeNames,
131 TestXPathParserParamNames,
132 ::testing::Values(
133 std::pair<std::string, bool>("a b", false),
134 std::pair<std::string, bool>("a*", false),
135 std::pair<std::string, bool>("HelloWorld", true),
136 std::pair<std::string, bool>("H", true),
137 std::pair<std::string, bool>("h", true),
138 std::pair<std::string, bool>("1", true),
139 std::pair<std::string, bool>("node-name", true),
140 std::pair<std::string, bool>("node_name", true),
141 std::pair<std::string, bool>("node\\name", true),
142 std::pair<std::string, bool>("node.name", false),
143 std::pair<std::string, bool>("node name", false)
144 ));
145
146class TestXPathParserParamValues : public ::testing::TestWithParam<std::pair<std::string, bool> >
147{
148};
149
150TEST_P(TestXPathParserParamValues, test_param_value)
151{
152 auto p = GetParam();
153
154 std::string input = p.first;
155 bool expect_pass = p.second;
156
157 parser::xpath_grammar<std::string::iterator> g;
158
159 std::string result;
160 ASSERT_EQ( expect_pass, test_parser_attr(input, g.param_value, result) );
161 if (expect_pass)
162 ASSERT_EQ(input, result);
163}
164
165INSTANTIATE_TEST_CASE_P(BasicNodeNames,
166 TestXPathParserParamValues,
167 ::testing::Values(
168 std::pair<std::string, bool>("a b", true),
169 std::pair<std::string, bool>("a*", false),
170 std::pair<std::string, bool>("HelloWorld", true),
171 std::pair<std::string, bool>("H", true),
172 std::pair<std::string, bool>("h", true),
173 std::pair<std::string, bool>("1", true),
174 std::pair<std::string, bool>("node-name", true),
175 std::pair<std::string, bool>("node_name", true),
176 std::pair<std::string, bool>("node\\name", true),
177 std::pair<std::string, bool>("node name", true),
178 std::pair<std::string, bool>("node.name", true)
179 ));
180
181
182TEST(TestXPathParser, test_wildcard_node_name_accepts_wildcards)
183{
184 std::string input("*");
185
186 parser::xpath_grammar<std::string::iterator> g;
187
188 std::string result;
189 ASSERT_EQ( true, test_parser_attr(input, g.wildcard_node_name, result) );
190 ASSERT_EQ(input, result);
191}
192464
193class TestXPathParserWildcardNodeName : public ::testing::TestWithParam<std::pair<std::string, bool> >465class TestXPathParserWildcardNodeName : public ::testing::TestWithParam<std::pair<std::string, bool> >
194{466{
@@ -224,16 +496,49 @@
224 ));496 ));
225497
226498
227TEST(TestXPathParser, test_param_parser_works)499TEST(TestXPathParser, test_param_parser_string_value_works)
228{500{
229 std::string input("name=value");501 std::string input("name=\"value\"");
230502
231 parser::xpath_grammar<std::string::iterator> g;503 parser::xpath_grammar<std::string::iterator> g;
232504
233 xpathselect::XPathQueryParam result;505 xpathselect::XPathQueryParam result;
234 ASSERT_EQ( true, test_parser_attr(input, g.param, result) );506 ASSERT_EQ( true, test_parser_attr(input, g.param, result) );
235 ASSERT_EQ("name", result.param_name);507 ASSERT_EQ("name", result.param_name);
236 ASSERT_EQ("value", result.param_value);508 boost::apply_visitor(
509 variant_equality_assertion<std::string>("value"),
510 result.param_value
511 );
512}
513
514TEST(TestXPathParser, test_param_parser_bool_value_works)
515{
516 std::string input("name=True");
517
518 parser::xpath_grammar<std::string::iterator> g;
519
520 xpathselect::XPathQueryParam result;
521 ASSERT_EQ( true, test_parser_attr(input, g.param, result) );
522 ASSERT_EQ("name", result.param_name);
523 boost::apply_visitor(
524 variant_equality_assertion<bool>(true),
525 result.param_value
526 );
527}
528
529TEST(TestXPathParser, test_param_parser_string_int_works)
530{
531 std::string input("name=123456");
532
533 parser::xpath_grammar<std::string::iterator> g;
534
535 xpathselect::XPathQueryParam result;
536 ASSERT_EQ( true, test_parser_attr(input, g.param, result) );
537 ASSERT_EQ("name", result.param_name);
538 boost::apply_visitor(
539 variant_equality_assertion<int>(123456),
540 result.param_value
541 );
237}542}
238543
239TEST(TestXPathParser, test_param_parser_fails)544TEST(TestXPathParser, test_param_parser_fails)
@@ -256,12 +561,15 @@
256 ASSERT_EQ( true, test_parser_attr(input, g.param_list, result) );561 ASSERT_EQ( true, test_parser_attr(input, g.param_list, result) );
257 ASSERT_EQ(1, result.size());562 ASSERT_EQ(1, result.size());
258 ASSERT_EQ("name", result.at(0).param_name);563 ASSERT_EQ("name", result.at(0).param_name);
259 ASSERT_EQ("123", result.at(0).param_value);564 boost::apply_visitor(
565 variant_equality_assertion<int>(123),
566 result.at(0).param_value
567 );
260}568}
261569
262TEST(TestXPathParser, test_param_list_two_values)570TEST(TestXPathParser, test_param_list_two_values)
263{571{
264 std::string input("[name=value,other=foo]");572 std::string input("[name=\"value\",visible=True]");
265573
266 parser::xpath_grammar<std::string::iterator> g;574 parser::xpath_grammar<std::string::iterator> g;
267575
@@ -269,9 +577,15 @@
269 ASSERT_EQ( true, test_parser_attr(input, g.param_list, result) );577 ASSERT_EQ( true, test_parser_attr(input, g.param_list, result) );
270 ASSERT_EQ(2, result.size());578 ASSERT_EQ(2, result.size());
271 ASSERT_EQ("name", result.at(0).param_name);579 ASSERT_EQ("name", result.at(0).param_name);
272 ASSERT_EQ("value", result.at(0).param_value);580 boost::apply_visitor(
273 ASSERT_EQ("other", result.at(1).param_name);581 variant_equality_assertion<std::string>("value"),
274 ASSERT_EQ("foo", result.at(1).param_value);582 result.at(0).param_value
583 );
584 ASSERT_EQ("visible", result.at(1).param_name);
585 boost::apply_visitor(
586 variant_equality_assertion<bool>(true),
587 result.at(1).param_value
588 );
275}589}
276590
277TEST(TestXPathParser, test_spec_node_with_parameter)591TEST(TestXPathParser, test_spec_node_with_parameter)
@@ -285,7 +599,10 @@
285 ASSERT_EQ("node_name", result.node_name_);599 ASSERT_EQ("node_name", result.node_name_);
286 ASSERT_FALSE(result.parameter.empty());600 ASSERT_FALSE(result.parameter.empty());
287 ASSERT_EQ("param_name", result.parameter.at(0).param_name);601 ASSERT_EQ("param_name", result.parameter.at(0).param_name);
288 ASSERT_EQ("123", result.parameter.at(0).param_value);602 boost::apply_visitor(
603 variant_equality_assertion<int>(123),
604 result.parameter.at(0).param_value
605 );
289}606}
290607
291TEST(TestXPathParser, test_spec_node_without_parameter)608TEST(TestXPathParser, test_spec_node_without_parameter)
@@ -333,13 +650,16 @@
333 ASSERT_EQ("*", result.node_name_);650 ASSERT_EQ("*", result.node_name_);
334 ASSERT_FALSE(result.parameter.empty());651 ASSERT_FALSE(result.parameter.empty());
335 ASSERT_EQ("param_name", result.parameter.at(0).param_name);652 ASSERT_EQ("param_name", result.parameter.at(0).param_name);
336 ASSERT_EQ("123", result.parameter.at(0).param_value);653 boost::apply_visitor(
654 variant_equality_assertion<int>(123),
655 result.parameter.at(0).param_value
656 );
337}657}
338658
339659
340TEST(TestXPathParser, test_node_can_be_a_wildcard_node_with_params)660TEST(TestXPathParser, test_node_can_be_a_wildcard_node_with_params)
341{661{
342 std::string input("*[name=value]");662 std::string input("*[name=\"value\"]");
343663
344 parser::xpath_grammar<std::string::iterator> g;664 parser::xpath_grammar<std::string::iterator> g;
345665
@@ -349,7 +669,10 @@
349 ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() );669 ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() );
350 ASSERT_EQ( 1, result.parameter.size() );670 ASSERT_EQ( 1, result.parameter.size() );
351 ASSERT_EQ( "name", result.parameter.at(0).param_name );671 ASSERT_EQ( "name", result.parameter.at(0).param_name );
352 ASSERT_EQ( "value", result.parameter.at(0).param_value );672 boost::apply_visitor(
673 variant_equality_assertion<std::string>("value"),
674 result.parameter.at(0).param_value
675 );
353}676}
354677
355TEST(TestXPathParser, test_node_can_be_a_wildcard_node_without_params)678TEST(TestXPathParser, test_node_can_be_a_wildcard_node_without_params)
@@ -366,7 +689,7 @@
366689
367TEST(TestXPathParser, test_node_can_be_a_spec_node_with_params)690TEST(TestXPathParser, test_node_can_be_a_spec_node_with_params)
368{691{
369 std::string input("foo[name=value]");692 std::string input("foo[name=\"value\"]");
370693
371 parser::xpath_grammar<std::string::iterator> g;694 parser::xpath_grammar<std::string::iterator> g;
372695
@@ -376,7 +699,10 @@
376 ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() );699 ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() );
377 ASSERT_EQ( 1, result.parameter.size() );700 ASSERT_EQ( 1, result.parameter.size() );
378 ASSERT_EQ( "name", result.parameter.at(0).param_name );701 ASSERT_EQ( "name", result.parameter.at(0).param_name );
379 ASSERT_EQ( "value", result.parameter.at(0).param_value );702 boost::apply_visitor(
703 variant_equality_assertion<std::string>("value"),
704 result.parameter.at(0).param_value
705 );
380}706}
381707
382TEST(TestXPathParser, test_node_can_be_a_spec_node_without_params)708TEST(TestXPathParser, test_node_can_be_a_spec_node_without_params)
@@ -391,6 +717,18 @@
391 ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() );717 ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() );
392}718}
393719
720TEST(TestXPathParser, test_node_can_be_a_parent_node)
721{
722 std::string input("..");
723
724 parser::xpath_grammar<std::string::iterator> g;
725
726 xpathselect::XPathQueryPart result;
727 ASSERT_EQ( true, test_parser_attr(input, g.node, result) );
728 ASSERT_EQ( "..", result.node_name_ );
729 ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Parent, result.Type() );
730}
731
394TEST(TestXPathParser, test_search_node_followed_by_normal_node)732TEST(TestXPathParser, test_search_node_followed_by_normal_node)
395{733{
396 // the search_node grammar fails if it's at the end of the line, so we need734 // the search_node grammar fails if it's at the end of the line, so we need
@@ -409,7 +747,7 @@
409{747{
410 // the search_node grammar fails if it's at the end of the line, so we need748 // the search_node grammar fails if it's at the end of the line, so we need
411 // to give it some more data, even though we're not actually matching it.749 // to give it some more data, even though we're not actually matching it.
412 std::string input("//*[foo=bar]");750 std::string input("//*[foo=\"bar\"]");
413 parser::xpath_grammar<std::string::iterator> g;751 parser::xpath_grammar<std::string::iterator> g;
414 xpathselect::XPathQueryPart result;752 xpathselect::XPathQueryPart result;
415753
@@ -429,6 +767,17 @@
429 ASSERT_FALSE( test_parser_attr(input, g.search_node, result) );767 ASSERT_FALSE( test_parser_attr(input, g.search_node, result) );
430}768}
431769
770TEST(TestXPathParser, test_parent_node)
771{
772 std::string input("..");
773
774 parser::xpath_grammar<std::string::iterator> g;
775
776 xpathselect::XPathQueryPart result;
777 ASSERT_TRUE( test_parser_attr(input, g.parent_node, result) );
778 ASSERT_TRUE( result.Type() == xpathselect::XPathQueryPart::QueryPartType::Parent );
779}
780
432TEST(TestXPathParser, test_normal_sep_works)781TEST(TestXPathParser, test_normal_sep_works)
433{782{
434 std::string input("/");783 std::string input("/");
@@ -503,7 +852,7 @@
503852
504TEST(TestXPathParser, test_mix_search_and_long_normal)853TEST(TestXPathParser, test_mix_search_and_long_normal)
505{854{
506 std::string input("/node1//node2[name=val]/node3");855 std::string input("/node1//node2[name=\"val\"]/node3");
507856
508 parser::xpath_grammar<std::string::iterator> g;857 parser::xpath_grammar<std::string::iterator> g;
509858
@@ -521,17 +870,55 @@
521 ASSERT_EQ("node2", result.at(2).node_name_);870 ASSERT_EQ("node2", result.at(2).node_name_);
522 ASSERT_EQ(1, result.at(2).parameter.size());871 ASSERT_EQ(1, result.at(2).parameter.size());
523 ASSERT_EQ("name", result.at(2).parameter.at(0).param_name);872 ASSERT_EQ("name", result.at(2).parameter.at(0).param_name);
524 ASSERT_EQ("val", result.at(2).parameter.at(0).param_value);873 boost::apply_visitor(
525874 variant_equality_assertion<std::string>("val"),
875 result.at(2).parameter.at(0).param_value
876 );
526 ASSERT_EQ("node3", result.at(3).node_name_);877 ASSERT_EQ("node3", result.at(3).node_name_);
527 ASSERT_TRUE(result.at(3).parameter.empty());878 ASSERT_TRUE(result.at(3).parameter.empty());
528}879}
529880
881TEST(TestXPathParser, test_mix_normal_and_parent)
882{
883 std::string input("/node1/..");
884
885 parser::xpath_grammar<std::string::iterator> g;
886
887 xpathselect::QueryList result;
888 ASSERT_TRUE(test_parser_attr(input, g.node_sequence, result));
889
890 ASSERT_EQ(2, result.size());
891
892 ASSERT_EQ("node1", result.at(0).node_name_);
893 ASSERT_TRUE(result.at(0).parameter.empty());
894
895 ASSERT_TRUE(result.at(1).Type() == xpathselect::XPathQueryPart::QueryPartType::Parent );
896 ASSERT_TRUE(result.at(1).parameter.empty());
897}
898
899TEST(TestXPathParser, test_mix_normal_and_parent_and_wildcard)
900{
901 std::string input("/node1/../*");
902
903 parser::xpath_grammar<std::string::iterator> g;
904
905 xpathselect::QueryList result;
906 ASSERT_TRUE(test_parser_attr(input, g.node_sequence, result));
907
908 ASSERT_EQ(3, result.size());
909
910 ASSERT_EQ("node1", result.at(0).node_name_);
911 ASSERT_TRUE(result.at(0).parameter.empty());
912
913 ASSERT_TRUE(result.at(1).Type() == xpathselect::XPathQueryPart::QueryPartType::Parent );
914 ASSERT_TRUE(result.at(1).parameter.empty());
915
916 ASSERT_TRUE(result.at(2).node_name_ == "*" );
917 ASSERT_TRUE(result.at(2).parameter.empty());
918}
530919
531class TestXPathParserQueryStrings : public ::testing::TestWithParam<std::pair<std::string, bool> >920class TestXPathParserQueryStrings : public ::testing::TestWithParam<std::pair<std::string, bool> >
532{921{};
533};
534
535922
536TEST_P(TestXPathParserQueryStrings, test_query_acceptance)923TEST_P(TestXPathParserQueryStrings, test_query_acceptance)
537{924{
@@ -556,11 +943,11 @@
556 std::pair<std::string, bool>("/root//node1", true),943 std::pair<std::string, bool>("/root//node1", true),
557 std::pair<std::string, bool>("//root", true),944 std::pair<std::string, bool>("//root", true),
558 std::pair<std::string, bool>("/root//node1/node2", true),945 std::pair<std::string, bool>("/root//node1/node2", true),
559 std::pair<std::string, bool>("/root[p=1]//node1[p=2]/node3", true),946 std::pair<std::string, bool>("/root[p=1]//node1[p=\"2\"]/node3", true),
560 std::pair<std::string, bool>("/root[p=1,n=2,d=e3]", true),947 std::pair<std::string, bool>("/root[p=True,n=2,d=\"e3\"]", true),
561 std::pair<std::string, bool>("//root[p=1,n=2,d=e3]", true),948 std::pair<std::string, bool>("//root[p=1,n=2,d=\"e3\"]", true),
562 std::pair<std::string, bool>("/Root//*[p=1]", true),949 std::pair<std::string, bool>("/Root//*[p=1]", true),
563 std::pair<std::string, bool>("/Root//*[p=1,v=sj,c=true]", true),950 std::pair<std::string, bool>("/Root//*[p=1,v=\"sj\",c=False]", true),
564 // queries that must not parse correctly:951 // queries that must not parse correctly:
565 std::pair<std::string, bool>("//", false),952 std::pair<std::string, bool>("//", false),
566 std::pair<std::string, bool>("/root//", false),953 std::pair<std::string, bool>("/root//", false),
@@ -570,5 +957,7 @@
570 std::pair<std::string, bool>(" ", false),957 std::pair<std::string, bool>(" ", false),
571 std::pair<std::string, bool>("//*", false),958 std::pair<std::string, bool>("//*", false),
572 std::pair<std::string, bool>("/Root///Leaf", false),959 std::pair<std::string, bool>("/Root///Leaf", false),
573 std::pair<std::string, bool>("/Root////", false)960 std::pair<std::string, bool>("/Root////", false),
961 std::pair<std::string, bool>("/Root/..*", false),
962 std::pair<std::string, bool>("/Root/../Child//..", false)
574 ));963 ));
575964
=== modified file 'test/test_xpath_simple.cpp'
--- test/test_xpath_simple.cpp 2012-08-10 04:06:05 +0000
+++ test/test_xpath_simple.cpp 2013-09-16 15:53:33 +0000
@@ -26,7 +26,7 @@
26TEST(TestXPath, test_select_empty_tree)26TEST(TestXPath, test_select_empty_tree)
27{27{
28 xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>();28 xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>();
29 xpathselect::NodeList result = xpathselect::SelectNodes(tree_root, "");29 xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "");
3030
31 ASSERT_EQ(1, result.size());31 ASSERT_EQ(1, result.size());
32}32}
@@ -35,7 +35,7 @@
35TEST(TestXPath, test_select_tree_root)35TEST(TestXPath, test_select_tree_root)
36{36{
37 xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode");37 xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode");
38 xpathselect::NodeList result = xpathselect::SelectNodes(tree_root, "/");38 xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "/");
3939
40 ASSERT_EQ(result.size(), 1);40 ASSERT_EQ(result.size(), 1);
41 ASSERT_EQ(result.front(), tree_root);41 ASSERT_EQ(result.front(), tree_root);
@@ -45,7 +45,7 @@
45TEST(TestXPath, test_select_tree_root_with_name)45TEST(TestXPath, test_select_tree_root_with_name)
46{46{
47 xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode");47 xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode");
48 xpathselect::NodeList result = xpathselect::SelectNodes(tree_root, "/RootNode");48 xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "/RootNode");
4949
50 ASSERT_EQ(result.size(), 1);50 ASSERT_EQ(result.size(), 1);
51 ASSERT_EQ(result.front(), tree_root);51 ASSERT_EQ(result.front(), tree_root);
@@ -55,7 +55,7 @@
55TEST(TestXPath, test_select_tree_root_with_relative_query)55TEST(TestXPath, test_select_tree_root_with_relative_query)
56{56{
57 xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode");57 xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode");
58 xpathselect::NodeList result = xpathselect::SelectNodes(tree_root, "//RootNode");58 xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "//RootNode");
5959
60 ASSERT_EQ(result.size(), 1);60 ASSERT_EQ(result.size(), 1);
61 ASSERT_EQ(result.front(), tree_root);61 ASSERT_EQ(result.front(), tree_root);
@@ -65,7 +65,7 @@
65TEST(TestXPath, test_select_tree_root_with_empty_relative_query)65TEST(TestXPath, test_select_tree_root_with_empty_relative_query)
66{66{
67 xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode");67 xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode");
68 xpathselect::NodeList result = xpathselect::SelectNodes(tree_root, "//");68 xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "//");
6969
70 ASSERT_EQ(result.size(), 1);70 ASSERT_EQ(result.size(), 1);
71 ASSERT_EQ(result.front(), tree_root);71 ASSERT_EQ(result.front(), tree_root);
7272
=== modified file 'test/test_xpath_tree.cpp'
--- test/test_xpath_tree.cpp 2013-04-24 03:48:30 +0000
+++ test/test_xpath_tree.cpp 2013-09-16 15:53:33 +0000
@@ -49,14 +49,14 @@
4949
50TEST_F(TestTreeFixture, test_simple)50TEST_F(TestTreeFixture, test_simple)
51{51{
52 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/");52 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/");
5353
54 ASSERT_EQ(1, result.size());54 ASSERT_EQ(1, result.size());
55}55}
5656
57TEST_F(TestTreeFixture, test_simple_absolute)57TEST_F(TestTreeFixture, test_simple_absolute)
58{58{
59 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1");59 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1");
6060
61 ASSERT_EQ(1, result.size());61 ASSERT_EQ(1, result.size());
62 auto expected = child_l1_;62 auto expected = child_l1_;
@@ -66,7 +66,7 @@
6666
67TEST_F(TestTreeFixture, test_simple_relative)67TEST_F(TestTreeFixture, test_simple_relative)
68{68{
69 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "//ChildRight1");69 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//ChildRight1");
7070
71 ASSERT_EQ(1, result.size());71 ASSERT_EQ(1, result.size());
72 ASSERT_EQ(child_r1_, result.front());72 ASSERT_EQ(child_r1_, result.front());
@@ -74,7 +74,7 @@
7474
75TEST_F(TestTreeFixture, test_complex_relative)75TEST_F(TestTreeFixture, test_complex_relative)
76{76{
77 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "//Root/ChildRight1");77 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//Root/ChildRight1");
7878
79 ASSERT_EQ(1, result.size());79 ASSERT_EQ(1, result.size());
80 ASSERT_EQ(child_r1_, result.front());80 ASSERT_EQ(child_r1_, result.front());
@@ -82,7 +82,7 @@
8282
83TEST_F(TestTreeFixture, test_relative_multiple_return)83TEST_F(TestTreeFixture, test_relative_multiple_return)
84{84{
85 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "//Leaf");85 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//Leaf");
8686
87 ASSERT_EQ(2, result.size());87 ASSERT_EQ(2, result.size());
8888
@@ -94,7 +94,7 @@
9494
95TEST_F(TestTreeFixture, test_relative_wildcard)95TEST_F(TestTreeFixture, test_relative_wildcard)
96{96{
97 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "//ChildLeft1/*");97 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//ChildLeft1/*");
9898
99 ASSERT_EQ(2, result.size());99 ASSERT_EQ(2, result.size());
100100
@@ -106,7 +106,7 @@
106106
107TEST_F(TestTreeFixture, test_absolute_wildcard)107TEST_F(TestTreeFixture, test_absolute_wildcard)
108{108{
109 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/*");109 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/*");
110110
111 ASSERT_EQ(2, result.size());111 ASSERT_EQ(2, result.size());
112112
@@ -119,7 +119,7 @@
119TEST_F(TestTreeFixture, test_simple_absolute_property_match)119TEST_F(TestTreeFixture, test_simple_absolute_property_match)
120{120{
121 child_l1_->AddProperty("visible", "True");121 child_l1_->AddProperty("visible", "True");
122 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1[visible=True]");122 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1[visible=True]");
123123
124 ASSERT_EQ(1, result.size());124 ASSERT_EQ(1, result.size());
125 ASSERT_EQ(child_l1_, result.front());125 ASSERT_EQ(child_l1_, result.front());
@@ -127,8 +127,8 @@
127127
128TEST_F(TestTreeFixture, test_simple_relative_property_match)128TEST_F(TestTreeFixture, test_simple_relative_property_match)
129{129{
130 child_l1_->AddProperty("visible", "True");130 child_l1_->AddProperty("visible", true);
131 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "//ChildLeft1[visible=True]");131 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//ChildLeft1[visible=True]");
132132
133 ASSERT_EQ(1, result.size());133 ASSERT_EQ(1, result.size());
134 ASSERT_EQ(child_l1_, result.front());134 ASSERT_EQ(child_l1_, result.front());
@@ -136,9 +136,9 @@
136136
137TEST_F(TestTreeFixture, test_absolute_multiple_property_match)137TEST_F(TestTreeFixture, test_absolute_multiple_property_match)
138{138{
139 root_->AddProperty("number", "45");139 root_->AddProperty("number", 45);
140 child_l1_->AddProperty("visible", "True");140 child_l1_->AddProperty("visible", true);
141 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root[number=45]/ChildLeft1[visible=True]");141 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root[number=45]/ChildLeft1[visible=True]");
142142
143 ASSERT_EQ(1, result.size());143 ASSERT_EQ(1, result.size());
144 ASSERT_EQ(child_l1_, result.front());144 ASSERT_EQ(child_l1_, result.front());
@@ -146,7 +146,7 @@
146146
147TEST_F(TestTreeFixture, test_mixed_query_simple)147TEST_F(TestTreeFixture, test_mixed_query_simple)
148{148{
149 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root//Leaf");149 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root//Leaf");
150 ASSERT_EQ(2, result.size());150 ASSERT_EQ(2, result.size());
151 for(auto n : result)151 for(auto n : result)
152 {152 {
@@ -156,8 +156,8 @@
156156
157TEST_F(TestTreeFixture, test_mixed_query_property_match)157TEST_F(TestTreeFixture, test_mixed_query_property_match)
158{158{
159 leaf_1_->AddProperty("visible", "True");159 leaf_1_->AddProperty("visible", true);
160 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root//Leaf[visible=True]");160 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root//Leaf[visible=True]");
161161
162 ASSERT_EQ(1, result.size());162 ASSERT_EQ(1, result.size());
163 ASSERT_EQ(leaf_1_, result.front());163 ASSERT_EQ(leaf_1_, result.front());
@@ -165,8 +165,8 @@
165165
166TEST_F(TestTreeFixture, test_search_node_with_wildcard_and_property)166TEST_F(TestTreeFixture, test_search_node_with_wildcard_and_property)
167{167{
168 child_l1_->AddProperty("visible", "True");168 child_l1_->AddProperty("visible", true);
169 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root//*[visible=True]");169 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root//*[visible=True]");
170170
171 ASSERT_EQ(1, result.size());171 ASSERT_EQ(1, result.size());
172 ASSERT_EQ(child_l1_, result.front());172 ASSERT_EQ(child_l1_, result.front());
@@ -174,7 +174,7 @@
174174
175TEST_F(TestTreeFixture, test_wildcard)175TEST_F(TestTreeFixture, test_wildcard)
176{176{
177 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root/*");177 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/*");
178 ASSERT_EQ(2, result.size());178 ASSERT_EQ(2, result.size());
179 for(auto n : result)179 for(auto n : result)
180 {180 {
@@ -182,14 +182,54 @@
182 }182 }
183}183}
184184
185TEST_F(TestTreeFixture, test_parent)
186{
187 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/..");
188
189 ASSERT_EQ(1, result.size());
190 ASSERT_EQ(root_, result.front());
191}
192
193TEST_F(TestTreeFixture, test_parent_on_root)
194{
195 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/..");
196
197 ASSERT_EQ(1, result.size());
198 ASSERT_EQ(root_, result.front());
199}
200
201TEST_F(TestTreeFixture, test_parent_on_leaf)
202{
203 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/Leaf/..");
204
205 ASSERT_EQ(1, result.size());
206 ASSERT_EQ(child_l1_, result.front());
207}
208
209TEST_F(TestTreeFixture, test_double_parent_on_leaf)
210{
211 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/Leaf/../..");
212
213 ASSERT_EQ(1, result.size());
214 ASSERT_EQ(root_, result.front());
215}
216
217TEST_F(TestTreeFixture, test_parent_and_child)
218{
219 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/../ChildLeft1/../ChildLeft1");
220
221 ASSERT_EQ(1, result.size());
222 ASSERT_EQ(child_l1_, result.front());
223}
224
185TEST_F(TestTreeFixture, test_invalid_query_search)225TEST_F(TestTreeFixture, test_invalid_query_search)
186{226{
187 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root///Leaf");227 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root///Leaf");
188 ASSERT_EQ(0, result.size());228 ASSERT_EQ(0, result.size());
189}229}
190230
191TEST_F(TestTreeFixture, test_invalid_query_multiple_searches)231TEST_F(TestTreeFixture, test_invalid_query_multiple_searches)
192{232{
193 xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root////");233 xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root////");
194 ASSERT_EQ(0, result.size());234 ASSERT_EQ(0, result.size());
195}235}

Subscribers

People subscribed via source and target branches

to all changes: