Merge lp:~autopilot/xpathselect/experimental into lp:xpathselect
- experimental
- Merge into trunk
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 | ||||||||||||
Related bugs: |
|
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
1 | === modified file 'CMakeLists.txt' | |||
2 | --- CMakeLists.txt 2013-04-18 03:29:31 +0000 | |||
3 | +++ CMakeLists.txt 2013-09-16 15:53:33 +0000 | |||
4 | @@ -6,7 +6,7 @@ | |||
5 | 6 | 6 | ||
6 | 7 | include (GNUInstallDirs) | 7 | include (GNUInstallDirs) |
7 | 8 | 8 | ||
9 | 9 | set (VERSION 1.3) | 9 | set (VERSION 1.4) |
10 | 10 | 10 | ||
11 | 11 | if(CMAKE_BUILD_TYPE STREQUAL "coverage") | 11 | if(CMAKE_BUILD_TYPE STREQUAL "coverage") |
12 | 12 | message("Building for coverage") | 12 | message("Building for coverage") |
13 | 13 | 13 | ||
14 | === modified file 'debian/changelog' | |||
15 | --- debian/changelog 2013-06-05 09:01:46 +0000 | |||
16 | +++ debian/changelog 2013-09-16 15:53:33 +0000 | |||
17 | @@ -1,3 +1,10 @@ | |||
18 | 1 | xpathselect (1.4-0ubuntu1) saucy; urgency=low | ||
19 | 2 | |||
20 | 3 | [ Thomi Richards ] | ||
21 | 4 | * New API, bump version to 1.4. | ||
22 | 5 | |||
23 | 6 | -- Thomi Richards <thomi.richards@canonical.com> Thu, 15 Aug 2013 11:08:08 +1200 | ||
24 | 7 | |||
25 | 1 | xpathselect (1.3daily13.06.05.1-0ubuntu1) saucy; urgency=low | 8 | xpathselect (1.3daily13.06.05.1-0ubuntu1) saucy; urgency=low |
26 | 2 | 9 | ||
27 | 3 | [ Thomi Richards ] | 10 | [ Thomi Richards ] |
28 | 4 | 11 | ||
29 | === modified file 'debian/control' | |||
30 | --- debian/control 2013-04-18 03:29:31 +0000 | |||
31 | +++ debian/control 2013-09-16 15:53:33 +0000 | |||
32 | @@ -20,14 +20,14 @@ | |||
33 | 20 | Section: libdevel | 20 | Section: libdevel |
34 | 21 | Architecture: any | 21 | Architecture: any |
35 | 22 | Depends: ${misc:Depends}, | 22 | Depends: ${misc:Depends}, |
37 | 23 | libxpathselect1.3 (= ${binary:Version}), | 23 | libxpathselect1.4 (= ${binary:Version}), |
38 | 24 | Description: Select objects in an object tree using XPath queries - development files | 24 | Description: Select objects in an object tree using XPath queries - development files |
39 | 25 | This library allows you to select arbitrary objects in an object tree using a | 25 | This library allows you to select arbitrary objects in an object tree using a |
40 | 26 | small subset of the XPath specification. | 26 | small subset of the XPath specification. |
41 | 27 | . | 27 | . |
42 | 28 | This package contains development files for xpathselect. | 28 | This package contains development files for xpathselect. |
43 | 29 | 29 | ||
45 | 30 | Package: libxpathselect1.3 | 30 | Package: libxpathselect1.4 |
46 | 31 | Section: libs | 31 | Section: libs |
47 | 32 | Architecture: any | 32 | Architecture: any |
48 | 33 | Multi-Arch: same | 33 | Multi-Arch: same |
49 | 34 | 34 | ||
50 | === renamed file 'debian/libxpathselect1.3.install' => 'debian/libxpathselect1.4.install' | |||
51 | === modified file 'lib/node.h' | |||
52 | --- lib/node.h 2013-04-22 02:18:53 +0000 | |||
53 | +++ lib/node.h 2013-09-16 15:53:33 +0000 | |||
54 | @@ -20,7 +20,9 @@ | |||
55 | 20 | 20 | ||
56 | 21 | #include <string> | 21 | #include <string> |
57 | 22 | #include <vector> | 22 | #include <vector> |
58 | 23 | #include <list> | ||
59 | 23 | #include <memory> | 24 | #include <memory> |
60 | 25 | #include <cstdint> | ||
61 | 24 | 26 | ||
62 | 25 | namespace xpathselect | 27 | namespace xpathselect |
63 | 26 | { | 28 | { |
64 | @@ -29,7 +31,7 @@ | |||
65 | 29 | class Node | 31 | class Node |
66 | 30 | { | 32 | { |
67 | 31 | public: | 33 | public: |
69 | 32 | typedef std::shared_ptr<Node> Ptr; | 34 | typedef std::shared_ptr<const Node> Ptr; |
70 | 33 | 35 | ||
71 | 34 | /// Get the node's name. | 36 | /// Get the node's name. |
72 | 35 | virtual std::string GetName() const =0; | 37 | virtual std::string GetName() const =0; |
73 | @@ -37,17 +39,23 @@ | |||
74 | 37 | /// Get the node's full path | 39 | /// Get the node's full path |
75 | 38 | virtual std::string GetPath() const =0; | 40 | virtual std::string GetPath() const =0; |
76 | 39 | 41 | ||
81 | 40 | /// Return true if the node matches the property with the given name & value | 42 | /// Get this node's ID. |
82 | 41 | ///\note: All property values are treated as strings. It is the implementors | 43 | virtual int32_t GetId() const =0; |
83 | 42 | /// responsibility to convert the value to the appropriate type. | 44 | |
84 | 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; |
85 | 46 | virtual bool MatchIntegerProperty(const std::string& name, int32_t value) const =0; | ||
86 | 47 | virtual bool MatchStringProperty(const std::string& name, const std::string& value) const =0; | ||
87 | 44 | 48 | ||
88 | 45 | /// Return a list of the children of this node. | 49 | /// Return a list of the children of this node. |
89 | 46 | virtual std::vector<Node::Ptr> Children() const =0; | 50 | virtual std::vector<Node::Ptr> Children() const =0; |
90 | 51 | |||
91 | 52 | /// Return a pointer to the parent class. | ||
92 | 53 | virtual Node::Ptr GetParent() const =0; | ||
93 | 47 | }; | 54 | }; |
94 | 48 | 55 | ||
95 | 49 | /// NodeList is how we return lists of nodes. | 56 | /// NodeList is how we return lists of nodes. |
97 | 50 | typedef std::vector<Node::Ptr> NodeList; | 57 | typedef std::vector<Node::Ptr> NodeVector; |
98 | 58 | typedef std::list<Node::Ptr> NodeList; | ||
99 | 51 | } | 59 | } |
100 | 52 | 60 | ||
101 | 53 | #endif | 61 | #endif |
102 | 54 | 62 | ||
103 | === modified file 'lib/parser.h' | |||
104 | --- lib/parser.h 2013-04-24 20:38:18 +0000 | |||
105 | +++ lib/parser.h 2013-09-16 15:53:33 +0000 | |||
106 | @@ -18,12 +18,15 @@ | |||
107 | 18 | #define _PARSER_H | 18 | #define _PARSER_H |
108 | 19 | 19 | ||
109 | 20 | #include <string> | 20 | #include <string> |
110 | 21 | #include <cstdint> | ||
111 | 21 | 22 | ||
112 | 22 | #include <boost/config/warning_disable.hpp> | 23 | #include <boost/config/warning_disable.hpp> |
113 | 23 | #include <boost/fusion/include/adapt_struct.hpp> | 24 | #include <boost/fusion/include/adapt_struct.hpp> |
114 | 24 | #include <boost/spirit/include/phoenix_object.hpp> | 25 | #include <boost/spirit/include/phoenix_object.hpp> |
115 | 25 | #include <boost/spirit/include/phoenix_operator.hpp> | 26 | #include <boost/spirit/include/phoenix_operator.hpp> |
116 | 26 | #include <boost/spirit/include/qi.hpp> | 27 | #include <boost/spirit/include/qi.hpp> |
117 | 28 | #include <boost/spirit/include/qi_bool.hpp> | ||
118 | 29 | #include <boost/spirit/include/qi_int.hpp> | ||
119 | 27 | 30 | ||
120 | 28 | #include "xpathquerypart.h" | 31 | #include "xpathquerypart.h" |
121 | 29 | 32 | ||
122 | @@ -37,7 +40,7 @@ | |||
123 | 37 | BOOST_FUSION_ADAPT_STRUCT( | 40 | BOOST_FUSION_ADAPT_STRUCT( |
124 | 38 | xpathselect::XPathQueryParam, | 41 | xpathselect::XPathQueryParam, |
125 | 39 | (std::string, param_name) | 42 | (std::string, param_name) |
127 | 40 | (std::string, param_value) | 43 | (xpathselect::XPathQueryParam::ParamValueType, param_value) |
128 | 41 | ); | 44 | ); |
129 | 42 | 45 | ||
130 | 43 | namespace xpathselect | 46 | namespace xpathselect |
131 | @@ -47,6 +50,33 @@ | |||
132 | 47 | namespace qi = boost::spirit::qi; | 50 | namespace qi = boost::spirit::qi; |
133 | 48 | namespace phoenix = boost::phoenix; | 51 | namespace phoenix = boost::phoenix; |
134 | 49 | 52 | ||
135 | 53 | // python_bool_policy determines what can be considered truthy. We follow python | ||
136 | 54 | // repr format. | ||
137 | 55 | struct python_bool_policy : qi::bool_policies<> | ||
138 | 56 | { | ||
139 | 57 | template <typename Iterator, typename Attribute> | ||
140 | 58 | static bool parse_true(Iterator& first, Iterator const& last, Attribute& attr) | ||
141 | 59 | { | ||
142 | 60 | if (qi::detail::string_parse("True", first, last, qi::unused)) | ||
143 | 61 | { | ||
144 | 62 | boost::spirit::traits::assign_to(true, attr); // result is true | ||
145 | 63 | return true; // parsing succeeded | ||
146 | 64 | } | ||
147 | 65 | return false; // parsing failed | ||
148 | 66 | } | ||
149 | 67 | |||
150 | 68 | template <typename Iterator, typename Attribute> | ||
151 | 69 | static bool parse_false(Iterator& first, Iterator const& last, Attribute& attr) | ||
152 | 70 | { | ||
153 | 71 | if (qi::detail::string_parse("False", first, last, qi::unused)) | ||
154 | 72 | { | ||
155 | 73 | boost::spirit::traits::assign_to(false, attr); // result is false | ||
156 | 74 | return true; | ||
157 | 75 | } | ||
158 | 76 | return false; | ||
159 | 77 | } | ||
160 | 78 | }; | ||
161 | 79 | |||
162 | 50 | // This is the main XPath grammar. It looks horrible, until you emerse yourself in it for a few | 80 | // This is the main XPath grammar. It looks horrible, until you emerse yourself in it for a few |
163 | 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, |
164 | 52 | // I've heavily commented this. | 82 | // I've heavily commented this. |
165 | @@ -61,6 +91,46 @@ | |||
166 | 61 | { | 91 | { |
167 | 62 | using namespace qi::labels; | 92 | using namespace qi::labels; |
168 | 63 | 93 | ||
169 | 94 | // character escape codes. The input on the left will produce the output on | ||
170 | 95 | // the right: | ||
171 | 96 | unesc_char.add("\\a", '\a') | ||
172 | 97 | ("\\b", '\b') | ||
173 | 98 | ("\\f", '\f') | ||
174 | 99 | ("\\n", '\n') | ||
175 | 100 | ("\\r", '\r') | ||
176 | 101 | ("\\t", '\t') | ||
177 | 102 | ("\\v", '\v') | ||
178 | 103 | ("\\\\", '\\') | ||
179 | 104 | ("\\\'", '\'') | ||
180 | 105 | ("\\\"", '\"'); | ||
181 | 106 | |||
182 | 107 | unesc_str = '"' >> *( | ||
183 | 108 | unesc_char | | ||
184 | 109 | qi::alnum | | ||
185 | 110 | qi::space | | ||
186 | 111 | "\\x" >> qi::hex | ||
187 | 112 | ) >> '"'; | ||
188 | 113 | |||
189 | 114 | unesc_str = '"' | ||
190 | 115 | >> *(unesc_char | "\\x" >> qi::hex | (qi::print - '"')) | ||
191 | 116 | >> '"' | ||
192 | 117 | ; | ||
193 | 118 | |||
194 | 119 | int_type = qi::int_parser<int32_t>(); | ||
195 | 120 | |||
196 | 121 | // Parameter grammar: | ||
197 | 122 | // parameter name can contain some basic text (no spaces or '.') | ||
198 | 123 | param_name = +qi::char_("a-zA-Z0-9_\\-"); | ||
199 | 124 | |||
200 | 125 | // parameter values can be several different types. | ||
201 | 126 | // Alternatives are tried left to right, and the first match found is the one used. | ||
202 | 127 | param_value = unesc_str | int_type | bool_type; | ||
203 | 128 | // parameter specification is simple: name=value | ||
204 | 129 | param %= param_name >> '=' >> param_value; | ||
205 | 130 | // a parameter list is a list of parameters separated by ',''s surrounded in '[...]' | ||
206 | 131 | param_list = '[' >> param % ',' >> ']'; | ||
207 | 132 | |||
208 | 133 | |||
209 | 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. |
210 | 65 | // it must start and end with a non-space character, but you can have | 135 | // it must start and end with a non-space character, but you can have |
211 | 66 | // spaces in the middle. | 136 | // spaces in the middle. |
212 | @@ -68,14 +138,6 @@ | |||
213 | 68 | // a wildcard node name is simply a '*' | 138 | // a wildcard node name is simply a '*' |
214 | 69 | wildcard_node_name = qi::char_("*"); | 139 | wildcard_node_name = qi::char_("*"); |
215 | 70 | 140 | ||
216 | 71 | // parameter name can contain some basic text (no spaces or '.') | ||
217 | 72 | param_name = +qi::char_("a-zA-Z0-9_\\-"); | ||
218 | 73 | // parameter values can have more stuff in them. | ||
219 | 74 | param_value = +qi::char_("a-z.A-Z0-9_\\-") >> *(+qi::char_(" ") >> +qi::char_("a-z.A-Z0-9_\\-")); | ||
220 | 75 | // parameter specification is simple: name=value | ||
221 | 76 | param %= param_name >> '=' >> param_value; | ||
222 | 77 | // a parameter list is a list of parameters separated by ',''s surrounded in '[...]' | ||
223 | 78 | param_list = '[' >> param % ',' >> ']'; | ||
224 | 79 | 141 | ||
225 | 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. |
226 | 81 | spec_node %= spec_node_name >> -(param_list); | 143 | spec_node %= spec_node_name >> -(param_list); |
227 | @@ -83,15 +145,18 @@ | |||
228 | 83 | wildcard_node %= wildcard_node_name >> !param_list; | 145 | wildcard_node %= wildcard_node_name >> !param_list; |
229 | 84 | // wildcard nodes can also have parameters: | 146 | // wildcard nodes can also have parameters: |
230 | 85 | wildcard_node_with_params %= wildcard_node_name >> param_list; | 147 | wildcard_node_with_params %= wildcard_node_name >> param_list; |
231 | 148 | // A parent node is '..' as long as it's followed by a normal separator or end of input: | ||
232 | 149 | parent_node = qi::lit("..")[qi::_val = XPathQueryPart("..")]; | ||
233 | 86 | 150 | ||
234 | 87 | // node is simply any kind of code defined thus far: | 151 | // node is simply any kind of code defined thus far: |
236 | 88 | node = spec_node | wildcard_node_with_params | wildcard_node; | 152 | node = spec_node | wildcard_node_with_params | wildcard_node | parent_node; |
237 | 89 | 153 | ||
238 | 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. |
239 | 91 | // we don't allow '//*' since it would match everything in the tree, and cause HUGE amounts of | 155 | // we don't allow '//*' since it would match everything in the tree, and cause HUGE amounts of |
240 | 92 | // data to be transmitted. | 156 | // data to be transmitted. |
241 | 93 | search_node = "//" >> &(spec_node | wildcard_node_with_params)[qi::_val = XPathQueryPart()]; | 157 | search_node = "//" >> &(spec_node | wildcard_node_with_params)[qi::_val = XPathQueryPart()]; |
242 | 94 | 158 | ||
243 | 159 | |||
244 | 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 '/' |
245 | 96 | normal_sep = '/' >> !qi::lit('/'); | 161 | normal_sep = '/' >> !qi::lit('/'); |
246 | 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. |
247 | @@ -147,14 +212,29 @@ | |||
248 | 147 | #endif | 212 | #endif |
249 | 148 | } | 213 | } |
250 | 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. |
251 | 215 | // basic type rules: | ||
252 | 216 | |||
253 | 217 | // parse python Boolean represetnations 'True' or 'False': | ||
254 | 218 | qi::bool_parser<bool, python_bool_policy> bool_type; | ||
255 | 219 | |||
256 | 220 | // parse an escaped byte string. | ||
257 | 221 | qi::rule<Iterator, std::string()> unesc_str; | ||
258 | 222 | // symbol table for chracter scape codes. | ||
259 | 223 | qi::symbols<char const, char const> unesc_char; | ||
260 | 224 | |||
261 | 225 | // parse integers, first signed then unsigned: | ||
262 | 226 | qi::rule<Iterator, int32_t()> int_type; | ||
263 | 227 | |||
264 | 228 | // more complicated language rules: | ||
265 | 150 | qi::rule<Iterator, std::string()> spec_node_name; | 229 | qi::rule<Iterator, std::string()> spec_node_name; |
266 | 151 | qi::rule<Iterator, std::string()> wildcard_node_name; | 230 | qi::rule<Iterator, std::string()> wildcard_node_name; |
267 | 152 | qi::rule<Iterator, XPathQueryPart()> search_node; | 231 | qi::rule<Iterator, XPathQueryPart()> search_node; |
268 | 232 | qi::rule<Iterator, XPathQueryPart()> parent_node; | ||
269 | 153 | qi::rule<Iterator> normal_sep; | 233 | qi::rule<Iterator> normal_sep; |
270 | 154 | qi::rule<Iterator, xpathselect::QueryList()> separator; | 234 | qi::rule<Iterator, xpathselect::QueryList()> separator; |
271 | 155 | 235 | ||
272 | 156 | qi::rule<Iterator, std::string()> param_name; | 236 | qi::rule<Iterator, std::string()> param_name; |
274 | 157 | qi::rule<Iterator, std::string()> param_value; | 237 | qi::rule<Iterator, xpathselect::XPathQueryParam::ParamValueType()> param_value; |
275 | 158 | qi::rule<Iterator, XPathQueryParam()> param; | 238 | qi::rule<Iterator, XPathQueryParam()> param; |
276 | 159 | qi::rule<Iterator, xpathselect::ParamList()> param_list; | 239 | qi::rule<Iterator, xpathselect::ParamList()> param_list; |
277 | 160 | 240 | ||
278 | 161 | 241 | ||
279 | === modified file 'lib/xpathquerypart.h' | |||
280 | --- lib/xpathquerypart.h 2013-06-05 07:31:01 +0000 | |||
281 | +++ lib/xpathquerypart.h 2013-09-16 15:53:33 +0000 | |||
282 | @@ -24,6 +24,8 @@ | |||
283 | 24 | #include <iostream> | 24 | #include <iostream> |
284 | 25 | 25 | ||
285 | 26 | #include <boost/optional/optional.hpp> | 26 | #include <boost/optional/optional.hpp> |
286 | 27 | #include <boost/variant/variant.hpp> | ||
287 | 28 | #include <boost/variant/get.hpp> | ||
288 | 27 | 29 | ||
289 | 28 | #include "node.h" | 30 | #include "node.h" |
290 | 29 | 31 | ||
291 | @@ -32,8 +34,11 @@ | |||
292 | 32 | // stores a parameter name, value pair. | 34 | // stores a parameter name, value pair. |
293 | 33 | struct XPathQueryParam | 35 | struct XPathQueryParam |
294 | 34 | { | 36 | { |
295 | 37 | typedef boost::variant<std::string, | ||
296 | 38 | bool, | ||
297 | 39 | int> ParamValueType; | ||
298 | 35 | std::string param_name; | 40 | std::string param_name; |
300 | 36 | std::string param_value; | 41 | ParamValueType param_value; |
301 | 37 | }; | 42 | }; |
302 | 38 | 43 | ||
303 | 39 | typedef std::vector<XPathQueryParam> ParamList; | 44 | typedef std::vector<XPathQueryParam> ParamList; |
304 | @@ -47,7 +52,7 @@ | |||
305 | 47 | : node_name_(node_name) | 52 | : node_name_(node_name) |
306 | 48 | {} | 53 | {} |
307 | 49 | 54 | ||
309 | 50 | enum class QueryPartType {Normal, Search}; | 55 | enum class QueryPartType {Normal, Search, Parent}; |
310 | 51 | 56 | ||
311 | 52 | bool Matches(Node::Ptr const& node) const | 57 | bool Matches(Node::Ptr const& node) const |
312 | 53 | { | 58 | { |
313 | @@ -56,15 +61,39 @@ | |||
314 | 56 | { | 61 | { |
315 | 57 | for (auto param : parameter) | 62 | for (auto param : parameter) |
316 | 58 | { | 63 | { |
319 | 59 | matches &= node->MatchProperty(param.param_name, param.param_value); | 64 | switch(param.param_value.which()) |
320 | 60 | 65 | { | |
321 | 66 | case 0: | ||
322 | 67 | { | ||
323 | 68 | matches &= node->MatchStringProperty(param.param_name, boost::get<std::string>(param.param_value)); | ||
324 | 69 | } | ||
325 | 70 | break; | ||
326 | 71 | case 1: | ||
327 | 72 | { | ||
328 | 73 | matches &= node->MatchBooleanProperty(param.param_name, boost::get<bool>(param.param_value)); | ||
329 | 74 | } | ||
330 | 75 | break; | ||
331 | 76 | case 2: | ||
332 | 77 | { | ||
333 | 78 | matches &= node->MatchIntegerProperty(param.param_name, boost::get<int>(param.param_value)); | ||
334 | 79 | } | ||
335 | 80 | break; | ||
336 | 81 | } | ||
337 | 61 | } | 82 | } |
338 | 62 | } | 83 | } |
339 | 63 | 84 | ||
340 | 64 | return matches; | 85 | return matches; |
341 | 65 | } | 86 | } |
342 | 66 | 87 | ||
344 | 67 | QueryPartType Type() const { return (node_name_ == "") ? QueryPartType::Search : QueryPartType::Normal; } | 88 | QueryPartType Type() const |
345 | 89 | { | ||
346 | 90 | if (node_name_ == "") | ||
347 | 91 | return QueryPartType::Search; | ||
348 | 92 | else if (node_name_ == "..") | ||
349 | 93 | return QueryPartType::Parent; | ||
350 | 94 | else | ||
351 | 95 | return QueryPartType::Normal; | ||
352 | 96 | } | ||
353 | 68 | 97 | ||
354 | 69 | void Dump() const | 98 | void Dump() const |
355 | 70 | { | 99 | { |
356 | 71 | 100 | ||
357 | === modified file 'lib/xpathselect.cpp' | |||
358 | --- lib/xpathselect.cpp 2013-04-24 08:57:16 +0000 | |||
359 | +++ lib/xpathselect.cpp 2013-09-16 15:53:33 +0000 | |||
360 | @@ -82,7 +82,7 @@ | |||
361 | 82 | } | 82 | } |
362 | 83 | } // end of anonymous namespace | 83 | } // end of anonymous namespace |
363 | 84 | 84 | ||
365 | 85 | NodeList SelectNodes(Node::Ptr const& root, std::string query) | 85 | NodeVector SelectNodes(Node::Ptr const& root, std::string query) |
366 | 86 | { | 86 | { |
367 | 87 | // allow users to be lazy when specifying tree root: | 87 | // allow users to be lazy when specifying tree root: |
368 | 88 | if (query == "" || query == "/" || query == "//") | 88 | if (query == "" || query == "/" || query == "//") |
369 | @@ -92,7 +92,7 @@ | |||
370 | 92 | 92 | ||
371 | 93 | QueryList query_parts = GetQueryPartsFromQuery(query); | 93 | QueryList query_parts = GetQueryPartsFromQuery(query); |
372 | 94 | if (query_parts.empty()) | 94 | if (query_parts.empty()) |
374 | 95 | return NodeList(); | 95 | return NodeVector(); |
375 | 96 | auto query_part = query_parts.cbegin(); | 96 | auto query_part = query_parts.cbegin(); |
376 | 97 | NodeList start_nodes { root }; | 97 | NodeList start_nodes { root }; |
377 | 98 | while (query_part != query_parts.cend()) | 98 | while (query_part != query_parts.cend()) |
378 | @@ -105,12 +105,24 @@ | |||
379 | 105 | // do some sanity checking... | 105 | // do some sanity checking... |
380 | 106 | if (query_part->Type() == XPathQueryPart::QueryPartType::Search) | 106 | if (query_part->Type() == XPathQueryPart::QueryPartType::Search) |
381 | 107 | // invalid query - cannot specify multiple search sequences in a row. | 107 | // invalid query - cannot specify multiple search sequences in a row. |
383 | 108 | return NodeList(); | 108 | return NodeVector(); |
384 | 109 | // then find all the nodes that match the new query part, and store them as | 109 | // then find all the nodes that match the new query part, and store them as |
385 | 110 | // the new start nodes. We pass in 'start_nodes' rather than 'root' since | 110 | // the new start nodes. We pass in 'start_nodes' rather than 'root' since |
386 | 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. |
387 | 112 | start_nodes = SearchTreeForNode(start_nodes, *query_part); | 112 | start_nodes = SearchTreeForNode(start_nodes, *query_part); |
388 | 113 | } | 113 | } |
389 | 114 | else if (query_part->Type() == XPathQueryPart::QueryPartType::Parent) | ||
390 | 115 | { | ||
391 | 116 | // This part of the query selects the parent node. If the current node has no | ||
392 | 117 | // parent (i.e.- we're already at the root of the tree) then this is a no-op: | ||
393 | 118 | NodeList new_start_nodes; | ||
394 | 119 | for (auto n: start_nodes) | ||
395 | 120 | { | ||
396 | 121 | auto parent = n->GetParent(); | ||
397 | 122 | new_start_nodes.push_back(parent ? parent : n); | ||
398 | 123 | } | ||
399 | 124 | start_nodes = new_start_nodes; | ||
400 | 125 | } | ||
401 | 114 | else | 126 | else |
402 | 115 | { | 127 | { |
403 | 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, |
404 | @@ -128,8 +140,11 @@ | |||
405 | 128 | ); | 140 | ); |
406 | 129 | } | 141 | } |
407 | 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. |
410 | 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 |
411 | 132 | if (query_part + 1 != query_parts.cend()) | 144 | // next query part is not a parent node... |
412 | 145 | auto next_query_part = query_part + 1; | ||
413 | 146 | if (next_query_part != query_parts.cend() | ||
414 | 147 | && next_query_part->Type() != XPathQueryPart::QueryPartType::Parent) | ||
415 | 133 | { | 148 | { |
416 | 134 | NodeList new_start_nodes; | 149 | NodeList new_start_nodes; |
417 | 135 | for (auto node: start_nodes) | 150 | for (auto node: start_nodes) |
418 | @@ -147,6 +162,16 @@ | |||
419 | 147 | } | 162 | } |
420 | 148 | ++query_part; | 163 | ++query_part; |
421 | 149 | } | 164 | } |
423 | 150 | return start_nodes; | 165 | // remove duplicate nodes by sorting & unique'ing: |
424 | 166 | // we could probably do this better, but since start_nodes is | ||
425 | 167 | // typically very small at this stage, I'm not sure it's worth it: | ||
426 | 168 | start_nodes.sort([](Node::Ptr a, Node::Ptr b) -> bool { | ||
427 | 169 | return a->GetId() < b->GetId(); | ||
428 | 170 | }); | ||
429 | 171 | start_nodes.unique([](Node::Ptr a, Node::Ptr b) -> bool { | ||
430 | 172 | return a->GetId() == b->GetId(); | ||
431 | 173 | }); | ||
432 | 174 | |||
433 | 175 | return NodeVector(start_nodes.begin(), start_nodes.end()); | ||
434 | 151 | } | 176 | } |
435 | 152 | } | 177 | } |
436 | 153 | 178 | ||
437 | === modified file 'lib/xpathselect.h' | |||
438 | --- lib/xpathselect.h 2013-02-01 23:20:24 +0000 | |||
439 | +++ lib/xpathselect.h 2013-09-16 15:53:33 +0000 | |||
440 | @@ -24,7 +24,7 @@ | |||
441 | 24 | { | 24 | { |
442 | 25 | /// Search the node tree beginning with 'root' and return nodes that | 25 | /// Search the node tree beginning with 'root' and return nodes that |
443 | 26 | /// match 'query'. | 26 | /// match 'query'. |
445 | 27 | extern "C" NodeList SelectNodes(Node::Ptr const& root, std::string query); | 27 | extern "C" NodeVector SelectNodes(Node::Ptr const& root, std::string query); |
446 | 28 | } | 28 | } |
447 | 29 | 29 | ||
448 | 30 | #endif | 30 | #endif |
449 | 31 | 31 | ||
450 | === modified file 'test/dummynode.h' | |||
451 | --- test/dummynode.h 2013-04-18 03:29:31 +0000 | |||
452 | +++ test/dummynode.h 2013-09-16 15:53:33 +0000 | |||
453 | @@ -23,12 +23,17 @@ | |||
454 | 23 | #include <map> | 23 | #include <map> |
455 | 24 | 24 | ||
456 | 25 | // simple implementation of the node interface for testing purposes. | 25 | // simple implementation of the node interface for testing purposes. |
458 | 26 | class DummyNode: public xpathselect::Node | 26 | class DummyNode: public xpathselect::Node, public std::enable_shared_from_this<DummyNode> |
459 | 27 | { | 27 | { |
460 | 28 | public: | 28 | public: |
461 | 29 | typedef std::shared_ptr<DummyNode> Ptr; | ||
462 | 30 | |||
463 | 29 | DummyNode(std::string name="DummyNode") | 31 | DummyNode(std::string name="DummyNode") |
464 | 30 | : name_(name) | 32 | : name_(name) |
466 | 31 | {} | 33 | { |
467 | 34 | static int32_t id = 1; | ||
468 | 35 | id_ = id++; | ||
469 | 36 | } | ||
470 | 32 | 37 | ||
471 | 33 | std::string GetName() const override | 38 | std::string GetName() const override |
472 | 34 | { | 39 | { |
473 | @@ -40,38 +45,79 @@ | |||
474 | 40 | return std::string(); | 45 | return std::string(); |
475 | 41 | } | 46 | } |
476 | 42 | 47 | ||
477 | 48 | int32_t GetId() const override | ||
478 | 49 | { | ||
479 | 50 | return id_; | ||
480 | 51 | } | ||
481 | 52 | |||
482 | 43 | void SetName(std::string const& name) | 53 | void SetName(std::string const& name) |
483 | 44 | { | 54 | { |
484 | 45 | name_ = name; | 55 | name_ = name; |
485 | 46 | } | 56 | } |
486 | 47 | 57 | ||
496 | 48 | bool MatchProperty(const std::string& name, const std::string& value) const override | 58 | bool MatchStringProperty(const std::string& name, const std::string& value) const override |
497 | 49 | { | 59 | { |
498 | 50 | auto it = properties_.find(name); | 60 | auto it = string_properties_.find(name); |
499 | 51 | if (it == properties_.end() || it->second != value) | 61 | if (it == string_properties_.end() || it->second != value) |
500 | 52 | return false; | 62 | return false; |
501 | 53 | return true; | 63 | return true; |
502 | 54 | } | 64 | } |
503 | 55 | 65 | ||
504 | 56 | xpathselect::NodeList Children() const override | 66 | bool MatchBooleanProperty(const std::string& name, bool value) const override |
505 | 67 | { | ||
506 | 68 | auto it = bool_properties_.find(name); | ||
507 | 69 | if (it == bool_properties_.end() || it->second != value) | ||
508 | 70 | return false; | ||
509 | 71 | return true; | ||
510 | 72 | } | ||
511 | 73 | |||
512 | 74 | bool MatchIntegerProperty(const std::string& name, int value) const override | ||
513 | 75 | { | ||
514 | 76 | auto it = int_properties_.find(name); | ||
515 | 77 | if (it == int_properties_.end() || it->second != value) | ||
516 | 78 | return false; | ||
517 | 79 | return true; | ||
518 | 80 | } | ||
519 | 81 | |||
520 | 82 | xpathselect::NodeVector Children() const override | ||
521 | 57 | { | 83 | { |
522 | 58 | return children_; | 84 | return children_; |
523 | 59 | } | 85 | } |
524 | 60 | 86 | ||
527 | 61 | void AddChild(Node::Ptr const& child) | 87 | virtual Node::Ptr GetParent() const override |
528 | 62 | { | 88 | { |
529 | 89 | return parent_; | ||
530 | 90 | } | ||
531 | 91 | |||
532 | 92 | void AddChild(Ptr const& child) | ||
533 | 93 | { | ||
534 | 94 | child->parent_ = shared_from_this(); | ||
535 | 63 | children_.push_back(child); | 95 | children_.push_back(child); |
536 | 64 | } | 96 | } |
537 | 65 | 97 | ||
538 | 66 | void AddProperty(std::string const& name, std::string const& value) | 98 | void AddProperty(std::string const& name, std::string const& value) |
539 | 67 | { | 99 | { |
541 | 68 | properties_[name] = value; | 100 | string_properties_[name] = value; |
542 | 101 | } | ||
543 | 102 | |||
544 | 103 | void AddProperty(std::string const& name, bool value) | ||
545 | 104 | { | ||
546 | 105 | bool_properties_[name] = value; | ||
547 | 106 | } | ||
548 | 107 | |||
549 | 108 | void AddProperty(std::string const& name, int value) | ||
550 | 109 | { | ||
551 | 110 | int_properties_[name] = value; | ||
552 | 69 | } | 111 | } |
553 | 70 | 112 | ||
554 | 71 | private: | 113 | private: |
555 | 114 | int32_t id_; | ||
556 | 72 | std::string name_; | 115 | std::string name_; |
559 | 73 | xpathselect::NodeList children_; | 116 | xpathselect::Node::Ptr parent_; |
560 | 74 | std::map<std::string, std::string> properties_; | 117 | xpathselect::NodeVector children_; |
561 | 118 | std::map<std::string, std::string> string_properties_; | ||
562 | 119 | std::map<std::string, int> int_properties_; | ||
563 | 120 | std::map<std::string, bool> bool_properties_; | ||
564 | 75 | }; | 121 | }; |
565 | 76 | 122 | ||
566 | 77 | 123 | ||
567 | 78 | 124 | ||
568 | === modified file 'test/test_parser.cpp' | |||
569 | --- test/test_parser.cpp 2013-04-24 09:38:10 +0000 | |||
570 | +++ test/test_parser.cpp 2013-09-16 15:53:33 +0000 | |||
571 | @@ -24,9 +24,13 @@ | |||
572 | 24 | #include <boost/spirit/include/phoenix_core.hpp> | 24 | #include <boost/spirit/include/phoenix_core.hpp> |
573 | 25 | #include <boost/spirit/include/qi_char_class.hpp> | 25 | #include <boost/spirit/include/qi_char_class.hpp> |
574 | 26 | #include <boost/spirit/include/phoenix_operator.hpp> | 26 | #include <boost/spirit/include/phoenix_operator.hpp> |
575 | 27 | #include <boost/variant/variant.hpp> | ||
576 | 28 | |||
577 | 27 | #include <iostream> | 29 | #include <iostream> |
578 | 28 | #include <string> | 30 | #include <string> |
579 | 29 | #include <cstdlib> | 31 | #include <cstdlib> |
580 | 32 | #include <typeinfo> | ||
581 | 33 | #include <limits> | ||
582 | 30 | 34 | ||
583 | 31 | namespace qi = boost::spirit::qi; | 35 | namespace qi = boost::spirit::qi; |
584 | 32 | namespace ascii = boost::spirit::ascii; | 36 | namespace ascii = boost::spirit::ascii; |
585 | @@ -69,6 +73,355 @@ | |||
586 | 69 | } | 73 | } |
587 | 70 | } | 74 | } |
588 | 71 | 75 | ||
589 | 76 | // a boost static visitor that checks value equality and type equality. | ||
590 | 77 | template <typename T> | ||
591 | 78 | class variant_equality_assertion : public boost::static_visitor<> | ||
592 | 79 | { | ||
593 | 80 | public: | ||
594 | 81 | variant_equality_assertion( T const& expected) | ||
595 | 82 | : expected_(expected) | ||
596 | 83 | {} | ||
597 | 84 | |||
598 | 85 | void operator()( T & operand ) const | ||
599 | 86 | { | ||
600 | 87 | ASSERT_EQ(expected_, operand); | ||
601 | 88 | } | ||
602 | 89 | |||
603 | 90 | template <typename U> void operator()( U & operand ) const | ||
604 | 91 | { | ||
605 | 92 | FAIL() << "Variant contained incorrect type! Expected: '" | ||
606 | 93 | << expected_ | ||
607 | 94 | << "' Actual: '" | ||
608 | 95 | << operand | ||
609 | 96 | << "' Actual type is: " | ||
610 | 97 | << typeid(U).name(); | ||
611 | 98 | } | ||
612 | 99 | private: | ||
613 | 100 | T expected_; | ||
614 | 101 | }; | ||
615 | 102 | |||
616 | 103 | ////////////////////////////////////// | ||
617 | 104 | // Tests for basic type support: | ||
618 | 105 | ////////////////////////////////////// | ||
619 | 106 | |||
620 | 107 | |||
621 | 108 | // Test python representations for boolean values: | ||
622 | 109 | TEST(TestXPathParser, test_basic_type_boolean) | ||
623 | 110 | { | ||
624 | 111 | bool result = false; | ||
625 | 112 | parser::xpath_grammar<std::string::iterator> g; | ||
626 | 113 | |||
627 | 114 | ASSERT_TRUE(test_parser_attr("True", g.bool_type, result)); | ||
628 | 115 | ASSERT_TRUE(result); | ||
629 | 116 | |||
630 | 117 | ASSERT_TRUE(test_parser_attr("False", g.bool_type, result)); | ||
631 | 118 | ASSERT_FALSE(result); | ||
632 | 119 | |||
633 | 120 | ASSERT_FALSE(test_parser_attr("true", g.bool_type, result)); | ||
634 | 121 | ASSERT_FALSE(test_parser_attr("false", g.bool_type, result)); | ||
635 | 122 | ASSERT_FALSE(test_parser_attr("1", g.bool_type, result)); | ||
636 | 123 | ASSERT_FALSE(test_parser_attr("0", g.bool_type, result)); | ||
637 | 124 | } | ||
638 | 125 | |||
639 | 126 | |||
640 | 127 | // test character escape codes: | ||
641 | 128 | class TestXPathParserCharacterEscapeCodes : public ::testing::TestWithParam<std::pair<std::string, char> > | ||
642 | 129 | { | ||
643 | 130 | }; | ||
644 | 131 | |||
645 | 132 | |||
646 | 133 | TEST_P(TestXPathParserCharacterEscapeCodes, test_character_escape_codes) | ||
647 | 134 | { | ||
648 | 135 | auto p = GetParam(); | ||
649 | 136 | |||
650 | 137 | std::string input = p.first; | ||
651 | 138 | char expected_result = p.second; | ||
652 | 139 | |||
653 | 140 | char actual_result = 0; | ||
654 | 141 | parser::xpath_grammar<std::string::iterator> g; | ||
655 | 142 | |||
656 | 143 | ASSERT_TRUE(test_parser_attr(input, g.unesc_char, actual_result)); | ||
657 | 144 | ASSERT_EQ(expected_result, actual_result); | ||
658 | 145 | } | ||
659 | 146 | |||
660 | 147 | INSTANTIATE_TEST_CASE_P(BasicCharacterCodes, | ||
661 | 148 | TestXPathParserCharacterEscapeCodes, | ||
662 | 149 | ::testing::Values( | ||
663 | 150 | std::pair<std::string, char>("\\a", '\a'), | ||
664 | 151 | std::pair<std::string, char>("\\b", '\b'), | ||
665 | 152 | std::pair<std::string, char>("\\f", '\f'), | ||
666 | 153 | std::pair<std::string, char>("\\n", '\n'), | ||
667 | 154 | std::pair<std::string, char>("\\r", '\r'), | ||
668 | 155 | std::pair<std::string, char>("\\t", '\t'), | ||
669 | 156 | std::pair<std::string, char>("\\v", '\v'), | ||
670 | 157 | std::pair<std::string, char>("\\\\", '\\'), | ||
671 | 158 | std::pair<std::string, char>("\\\'", '\''), | ||
672 | 159 | std::pair<std::string, char>("\\\"", '\"') | ||
673 | 160 | )); | ||
674 | 161 | |||
675 | 162 | |||
676 | 163 | class QuotedStringTests : public ::testing::TestWithParam<std::tuple<const char*, const char*, bool> > | ||
677 | 164 | { | ||
678 | 165 | }; | ||
679 | 166 | |||
680 | 167 | TEST_P(QuotedStringTests, quoted_string_parameter_test) | ||
681 | 168 | { | ||
682 | 169 | std::string input = std::get<0>(GetParam()); | ||
683 | 170 | std::string expected_output = std::get<1>(GetParam()); | ||
684 | 171 | bool expected_pass = std::get<2>(GetParam()); | ||
685 | 172 | |||
686 | 173 | std::string actual_result; | ||
687 | 174 | parser::xpath_grammar<std::string::iterator> g; | ||
688 | 175 | |||
689 | 176 | ASSERT_EQ(expected_pass, test_parser_attr(input, g.unesc_str, actual_result)); | ||
690 | 177 | if (expected_pass) | ||
691 | 178 | ASSERT_EQ(expected_output, actual_result); | ||
692 | 179 | } | ||
693 | 180 | |||
694 | 181 | |||
695 | 182 | INSTANTIATE_TEST_CASE_P(BasicStrings, | ||
696 | 183 | QuotedStringTests, | ||
697 | 184 | ::testing::Values( | ||
698 | 185 | std::make_tuple("\"Hello\"", "Hello", true), | ||
699 | 186 | std::make_tuple("\"Hello World\"", "Hello World", true), | ||
700 | 187 | std::make_tuple("\"a b c d\"", "a b c d", true), | ||
701 | 188 | std::make_tuple("\"\\x41\"", "A", true), | ||
702 | 189 | std::make_tuple("\"\\x08\"", "\b", true) | ||
703 | 190 | )); | ||
704 | 191 | |||
705 | 192 | INSTANTIATE_TEST_CASE_P(PunctuationStrings, | ||
706 | 193 | QuotedStringTests, | ||
707 | 194 | ::testing::Values( | ||
708 | 195 | std::make_tuple("\".\"", ".", true), | ||
709 | 196 | std::make_tuple("\",\"", ",", true), | ||
710 | 197 | std::make_tuple("\"<\"", "<", true), | ||
711 | 198 | std::make_tuple("\">\"", ">", true), | ||
712 | 199 | std::make_tuple("\"/\"", "/", true), | ||
713 | 200 | std::make_tuple("\"?\"", "?", true), | ||
714 | 201 | std::make_tuple("\":\"", ":", true), | ||
715 | 202 | std::make_tuple("\";\"", ";", true), | ||
716 | 203 | std::make_tuple("\"'\"", "'", true), // '"' tested below | ||
717 | 204 | std::make_tuple("\"[\"", "[", true), | ||
718 | 205 | std::make_tuple("\"]\"", "]", true), | ||
719 | 206 | std::make_tuple("\"{\"", "{", true), | ||
720 | 207 | std::make_tuple("\"}\"", "}", true), | ||
721 | 208 | std::make_tuple("\"\\\\\"", "\\", true), | ||
722 | 209 | std::make_tuple("\"|\"", "|", true), | ||
723 | 210 | std::make_tuple("\"~\"", "~", true), | ||
724 | 211 | std::make_tuple("\"`\"", "`", true), | ||
725 | 212 | std::make_tuple("\"!\"", "!", true), | ||
726 | 213 | std::make_tuple("\"@\"", "@", true), | ||
727 | 214 | std::make_tuple("\"#\"", "#", true), | ||
728 | 215 | std::make_tuple("\"$\"", "$", true), | ||
729 | 216 | std::make_tuple("\"%\"", "%", true), | ||
730 | 217 | std::make_tuple("\"^\"", "^", true), | ||
731 | 218 | std::make_tuple("\"&\"", "&", true), | ||
732 | 219 | std::make_tuple("\"*\"", "*", true), | ||
733 | 220 | std::make_tuple("\"(\"", "(", true), | ||
734 | 221 | std::make_tuple("\")\"", ")", true), | ||
735 | 222 | std::make_tuple("\"-\"", "-", true), | ||
736 | 223 | std::make_tuple("\"_\"", "_", true), | ||
737 | 224 | std::make_tuple("\"+\"", "+", true), | ||
738 | 225 | std::make_tuple("\"=\"", "=", true) | ||
739 | 226 | )); | ||
740 | 227 | |||
741 | 228 | INSTANTIATE_TEST_CASE_P(QuoteStrings, | ||
742 | 229 | QuotedStringTests, | ||
743 | 230 | ::testing::Values( | ||
744 | 231 | std::make_tuple("\"\\\"\"", "\"", true), | ||
745 | 232 | std::make_tuple("\"\\\'\"", "\'", true) | ||
746 | 233 | )); | ||
747 | 234 | |||
748 | 235 | INSTANTIATE_TEST_CASE_P(NumberStrings, | ||
749 | 236 | QuotedStringTests, | ||
750 | 237 | ::testing::Values( | ||
751 | 238 | std::make_tuple("\"0\"", "0", true), | ||
752 | 239 | std::make_tuple("\"1\"", "1", true), | ||
753 | 240 | std::make_tuple("\"2\"", "2", true), | ||
754 | 241 | std::make_tuple("\"3\"", "3", true), | ||
755 | 242 | std::make_tuple("\"4\"", "4", true), | ||
756 | 243 | std::make_tuple("\"5\"", "5", true), | ||
757 | 244 | std::make_tuple("\"6\"", "6", true), | ||
758 | 245 | std::make_tuple("\"7\"", "7", true), | ||
759 | 246 | std::make_tuple("\"8\"", "8", true), | ||
760 | 247 | std::make_tuple("\"9\"", "9", true) | ||
761 | 248 | )); | ||
762 | 249 | |||
763 | 250 | |||
764 | 251 | TEST(TestIntegerTypes, test_signed_integers) | ||
765 | 252 | { | ||
766 | 253 | int result = 0; | ||
767 | 254 | parser::xpath_grammar<std::string::iterator> g; | ||
768 | 255 | |||
769 | 256 | ASSERT_TRUE(test_parser_attr("123", g.int_type, result)); | ||
770 | 257 | ASSERT_EQ(123, result); | ||
771 | 258 | |||
772 | 259 | ASSERT_TRUE(test_parser_attr("+456", g.int_type, result)); | ||
773 | 260 | ASSERT_EQ(456, result); | ||
774 | 261 | |||
775 | 262 | ASSERT_TRUE(test_parser_attr("-123", g.int_type, result)); | ||
776 | 263 | ASSERT_EQ(-123, result); | ||
777 | 264 | } | ||
778 | 265 | |||
779 | 266 | |||
780 | 267 | // This test fails due to a bug in boost::spirit: https://svn.boost.org/trac/boost/ticket/9007 | ||
781 | 268 | // TEST(TestIntegerTypes, test_integer_overflow) | ||
782 | 269 | // { | ||
783 | 270 | // int result; | ||
784 | 271 | |||
785 | 272 | // // store range of int in a long, since we'll be extending them | ||
786 | 273 | // long min_int = std::numeric_limits<int>::min(); | ||
787 | 274 | // long max_int = std::numeric_limits<int>::max(); | ||
788 | 275 | |||
789 | 276 | // qi::int_parser<int> r; | ||
790 | 277 | |||
791 | 278 | // ASSERT_TRUE(test_parser_attr(std::to_string(min_int), r, result)); | ||
792 | 279 | // ASSERT_EQ(min_int, result); | ||
793 | 280 | |||
794 | 281 | // ASSERT_TRUE(test_parser_attr(std::to_string(max_int), r, result)); | ||
795 | 282 | // ASSERT_EQ(max_int, result); | ||
796 | 283 | |||
797 | 284 | // min_int -= 1; | ||
798 | 285 | // max_int += 1; | ||
799 | 286 | |||
800 | 287 | // // these last two assertions are failing. I expect the parsing to fail, but it's passing | ||
801 | 288 | // // for some reason. | ||
802 | 289 | // ASSERT_FALSE(test_parser_attr(std::to_string(min_int), r, result)) << min_int; | ||
803 | 290 | // ASSERT_FALSE(test_parser_attr(std::to_string(max_int), r, result)) << max_int; | ||
804 | 291 | // } | ||
805 | 292 | |||
806 | 293 | |||
807 | 294 | //////////////////////////////////// | ||
808 | 295 | // more complicated grammar tests | ||
809 | 296 | //////////////////////////////////// | ||
810 | 297 | |||
811 | 298 | /// Tests for parameter names: | ||
812 | 299 | class TestXPathParserParamNames : public ::testing::TestWithParam<std::pair<std::string, bool> > | ||
813 | 300 | { | ||
814 | 301 | }; | ||
815 | 302 | |||
816 | 303 | TEST_P(TestXPathParserParamNames, test_param_name) | ||
817 | 304 | { | ||
818 | 305 | auto p = GetParam(); | ||
819 | 306 | |||
820 | 307 | std::string input = p.first; | ||
821 | 308 | bool expect_pass = p.second; | ||
822 | 309 | |||
823 | 310 | parser::xpath_grammar<std::string::iterator> g; | ||
824 | 311 | |||
825 | 312 | std::string result; | ||
826 | 313 | ASSERT_EQ( expect_pass, test_parser_attr(input, g.param_name, result) ); | ||
827 | 314 | if (expect_pass) | ||
828 | 315 | ASSERT_EQ(input, result); | ||
829 | 316 | } | ||
830 | 317 | |||
831 | 318 | INSTANTIATE_TEST_CASE_P(BasicNodeNames, | ||
832 | 319 | TestXPathParserParamNames, | ||
833 | 320 | ::testing::Values( | ||
834 | 321 | std::pair<std::string, bool>("a b", false), | ||
835 | 322 | std::pair<std::string, bool>("a*", false), | ||
836 | 323 | std::pair<std::string, bool>("HelloWorld", true), | ||
837 | 324 | std::pair<std::string, bool>("H", true), | ||
838 | 325 | std::pair<std::string, bool>("h", true), | ||
839 | 326 | std::pair<std::string, bool>("1", true), | ||
840 | 327 | std::pair<std::string, bool>("node-name", true), | ||
841 | 328 | std::pair<std::string, bool>("node_name", true), | ||
842 | 329 | std::pair<std::string, bool>("node\\name", true), | ||
843 | 330 | std::pair<std::string, bool>("node.name", false), | ||
844 | 331 | std::pair<std::string, bool>("node name", false), | ||
845 | 332 | std::pair<std::string, bool>("..", false) | ||
846 | 333 | )); | ||
847 | 334 | |||
848 | 335 | /// Tests for parameter values. This test is much larger than it should be, since it seems to be | ||
849 | 336 | // impossible to parameterise tests for both type and value. The solution I use here is to have | ||
850 | 337 | // the actual test in a base class template method, and have several derive classes use different | ||
851 | 338 | // value parameters. Ugly, but probably the best we can do with google test. | ||
852 | 339 | |||
853 | 340 | class TestParamValues : public ::testing::Test | ||
854 | 341 | { | ||
855 | 342 | public: | ||
856 | 343 | template <typename PairType> | ||
857 | 344 | void test_param_value(PairType const& input_pair) const | ||
858 | 345 | { | ||
859 | 346 | RecordProperty("FirstType", typeid(typename PairType::first_type).name()); | ||
860 | 347 | RecordProperty("SecondType", typeid(typename PairType::second_type).name()); | ||
861 | 348 | std::string input = input_pair.first; | ||
862 | 349 | typename PairType::second_type expected_result = input_pair.second; | ||
863 | 350 | |||
864 | 351 | parser::xpath_grammar<std::string::iterator> g; | ||
865 | 352 | |||
866 | 353 | xpathselect::XPathQueryParam::ParamValueType result; | ||
867 | 354 | ASSERT_TRUE( test_parser_attr(input, g.param_value, result) ); | ||
868 | 355 | boost::apply_visitor( | ||
869 | 356 | variant_equality_assertion<typename PairType::second_type>(expected_result), | ||
870 | 357 | result | ||
871 | 358 | ); | ||
872 | 359 | } | ||
873 | 360 | }; | ||
874 | 361 | |||
875 | 362 | // test string parameter values: | ||
876 | 363 | class TestStringParamValues | ||
877 | 364 | : public ::testing::WithParamInterface<std::pair<std::string, std::string> > | ||
878 | 365 | , public TestParamValues | ||
879 | 366 | { | ||
880 | 367 | }; | ||
881 | 368 | |||
882 | 369 | TEST_P(TestStringParamValues, test_param_value_str) | ||
883 | 370 | { | ||
884 | 371 | auto p = GetParam(); | ||
885 | 372 | test_param_value(p); | ||
886 | 373 | } | ||
887 | 374 | |||
888 | 375 | INSTANTIATE_TEST_CASE_P(StringParams, | ||
889 | 376 | TestStringParamValues, | ||
890 | 377 | ::testing::Values( | ||
891 | 378 | std::pair<std::string, std::string>("\"a b\"", "a b" ), | ||
892 | 379 | std::pair<std::string, std::string>("\"a.b,c/\\d^\"", "a.b,c/\\d^" ) | ||
893 | 380 | )); | ||
894 | 381 | |||
895 | 382 | // test boolean parameter values: | ||
896 | 383 | class TestBoolParamValues | ||
897 | 384 | : public ::testing::WithParamInterface<std::pair<std::string, bool> > | ||
898 | 385 | , public TestParamValues | ||
899 | 386 | { | ||
900 | 387 | }; | ||
901 | 388 | |||
902 | 389 | TEST_P(TestBoolParamValues, test_param_value_bool) | ||
903 | 390 | { | ||
904 | 391 | auto p = GetParam(); | ||
905 | 392 | test_param_value(p); | ||
906 | 393 | } | ||
907 | 394 | |||
908 | 395 | INSTANTIATE_TEST_CASE_P(StringParams, | ||
909 | 396 | TestBoolParamValues, | ||
910 | 397 | ::testing::Values( | ||
911 | 398 | std::pair<std::string, bool>("True", true ), | ||
912 | 399 | std::pair<std::string, bool>("False", false ) | ||
913 | 400 | )); | ||
914 | 401 | |||
915 | 402 | // test integer parameter values: | ||
916 | 403 | class TestIntParamValues | ||
917 | 404 | : public ::testing::WithParamInterface<std::pair<std::string, int> > | ||
918 | 405 | , public TestParamValues | ||
919 | 406 | { | ||
920 | 407 | }; | ||
921 | 408 | |||
922 | 409 | TEST_P(TestIntParamValues, test_param_value_bool) | ||
923 | 410 | { | ||
924 | 411 | auto p = GetParam(); | ||
925 | 412 | test_param_value(p); | ||
926 | 413 | } | ||
927 | 414 | |||
928 | 415 | INSTANTIATE_TEST_CASE_P(IntegerParams, | ||
929 | 416 | TestIntParamValues, | ||
930 | 417 | ::testing::Values( | ||
931 | 418 | std::pair<std::string, int>("123", 123 ), | ||
932 | 419 | std::pair<std::string, int>("0", 0 ), | ||
933 | 420 | std::pair<std::string, int>("-123", -123 ) | ||
934 | 421 | )); | ||
935 | 422 | |||
936 | 423 | |||
937 | 424 | /// Tests for the node names: | ||
938 | 72 | class TestXPathParserNodeNames : public ::testing::TestWithParam<std::pair<std::string, bool> > | 425 | class TestXPathParserNodeNames : public ::testing::TestWithParam<std::pair<std::string, bool> > |
939 | 73 | { | 426 | { |
940 | 74 | }; | 427 | }; |
941 | @@ -108,87 +461,6 @@ | |||
942 | 108 | std::pair<std::string, bool>("node\\name", true) | 461 | std::pair<std::string, bool>("node\\name", true) |
943 | 109 | )); | 462 | )); |
944 | 110 | 463 | ||
945 | 111 | class TestXPathParserParamNames : public ::testing::TestWithParam<std::pair<std::string, bool> > | ||
946 | 112 | { | ||
947 | 113 | }; | ||
948 | 114 | |||
949 | 115 | TEST_P(TestXPathParserParamNames, test_param_name) | ||
950 | 116 | { | ||
951 | 117 | auto p = GetParam(); | ||
952 | 118 | |||
953 | 119 | std::string input = p.first; | ||
954 | 120 | bool expect_pass = p.second; | ||
955 | 121 | |||
956 | 122 | parser::xpath_grammar<std::string::iterator> g; | ||
957 | 123 | |||
958 | 124 | std::string result; | ||
959 | 125 | ASSERT_EQ( expect_pass, test_parser_attr(input, g.param_name, result) ); | ||
960 | 126 | if (expect_pass) | ||
961 | 127 | ASSERT_EQ(input, result); | ||
962 | 128 | } | ||
963 | 129 | |||
964 | 130 | INSTANTIATE_TEST_CASE_P(BasicNodeNames, | ||
965 | 131 | TestXPathParserParamNames, | ||
966 | 132 | ::testing::Values( | ||
967 | 133 | std::pair<std::string, bool>("a b", false), | ||
968 | 134 | std::pair<std::string, bool>("a*", false), | ||
969 | 135 | std::pair<std::string, bool>("HelloWorld", true), | ||
970 | 136 | std::pair<std::string, bool>("H", true), | ||
971 | 137 | std::pair<std::string, bool>("h", true), | ||
972 | 138 | std::pair<std::string, bool>("1", true), | ||
973 | 139 | std::pair<std::string, bool>("node-name", true), | ||
974 | 140 | std::pair<std::string, bool>("node_name", true), | ||
975 | 141 | std::pair<std::string, bool>("node\\name", true), | ||
976 | 142 | std::pair<std::string, bool>("node.name", false), | ||
977 | 143 | std::pair<std::string, bool>("node name", false) | ||
978 | 144 | )); | ||
979 | 145 | |||
980 | 146 | class TestXPathParserParamValues : public ::testing::TestWithParam<std::pair<std::string, bool> > | ||
981 | 147 | { | ||
982 | 148 | }; | ||
983 | 149 | |||
984 | 150 | TEST_P(TestXPathParserParamValues, test_param_value) | ||
985 | 151 | { | ||
986 | 152 | auto p = GetParam(); | ||
987 | 153 | |||
988 | 154 | std::string input = p.first; | ||
989 | 155 | bool expect_pass = p.second; | ||
990 | 156 | |||
991 | 157 | parser::xpath_grammar<std::string::iterator> g; | ||
992 | 158 | |||
993 | 159 | std::string result; | ||
994 | 160 | ASSERT_EQ( expect_pass, test_parser_attr(input, g.param_value, result) ); | ||
995 | 161 | if (expect_pass) | ||
996 | 162 | ASSERT_EQ(input, result); | ||
997 | 163 | } | ||
998 | 164 | |||
999 | 165 | INSTANTIATE_TEST_CASE_P(BasicNodeNames, | ||
1000 | 166 | TestXPathParserParamValues, | ||
1001 | 167 | ::testing::Values( | ||
1002 | 168 | std::pair<std::string, bool>("a b", true), | ||
1003 | 169 | std::pair<std::string, bool>("a*", false), | ||
1004 | 170 | std::pair<std::string, bool>("HelloWorld", true), | ||
1005 | 171 | std::pair<std::string, bool>("H", true), | ||
1006 | 172 | std::pair<std::string, bool>("h", true), | ||
1007 | 173 | std::pair<std::string, bool>("1", true), | ||
1008 | 174 | std::pair<std::string, bool>("node-name", true), | ||
1009 | 175 | std::pair<std::string, bool>("node_name", true), | ||
1010 | 176 | std::pair<std::string, bool>("node\\name", true), | ||
1011 | 177 | std::pair<std::string, bool>("node name", true), | ||
1012 | 178 | std::pair<std::string, bool>("node.name", true) | ||
1013 | 179 | )); | ||
1014 | 180 | |||
1015 | 181 | |||
1016 | 182 | TEST(TestXPathParser, test_wildcard_node_name_accepts_wildcards) | ||
1017 | 183 | { | ||
1018 | 184 | std::string input("*"); | ||
1019 | 185 | |||
1020 | 186 | parser::xpath_grammar<std::string::iterator> g; | ||
1021 | 187 | |||
1022 | 188 | std::string result; | ||
1023 | 189 | ASSERT_EQ( true, test_parser_attr(input, g.wildcard_node_name, result) ); | ||
1024 | 190 | ASSERT_EQ(input, result); | ||
1025 | 191 | } | ||
1026 | 192 | 464 | ||
1027 | 193 | class TestXPathParserWildcardNodeName : public ::testing::TestWithParam<std::pair<std::string, bool> > | 465 | class TestXPathParserWildcardNodeName : public ::testing::TestWithParam<std::pair<std::string, bool> > |
1028 | 194 | { | 466 | { |
1029 | @@ -224,16 +496,49 @@ | |||
1030 | 224 | )); | 496 | )); |
1031 | 225 | 497 | ||
1032 | 226 | 498 | ||
1043 | 227 | TEST(TestXPathParser, test_param_parser_works) | 499 | TEST(TestXPathParser, test_param_parser_string_value_works) |
1044 | 228 | { | 500 | { |
1045 | 229 | std::string input("name=value"); | 501 | std::string input("name=\"value\""); |
1046 | 230 | 502 | ||
1047 | 231 | parser::xpath_grammar<std::string::iterator> g; | 503 | parser::xpath_grammar<std::string::iterator> g; |
1048 | 232 | 504 | ||
1049 | 233 | xpathselect::XPathQueryParam result; | 505 | xpathselect::XPathQueryParam result; |
1050 | 234 | ASSERT_EQ( true, test_parser_attr(input, g.param, result) ); | 506 | ASSERT_EQ( true, test_parser_attr(input, g.param, result) ); |
1051 | 235 | ASSERT_EQ("name", result.param_name); | 507 | ASSERT_EQ("name", result.param_name); |
1052 | 236 | ASSERT_EQ("value", result.param_value); | 508 | boost::apply_visitor( |
1053 | 509 | variant_equality_assertion<std::string>("value"), | ||
1054 | 510 | result.param_value | ||
1055 | 511 | ); | ||
1056 | 512 | } | ||
1057 | 513 | |||
1058 | 514 | TEST(TestXPathParser, test_param_parser_bool_value_works) | ||
1059 | 515 | { | ||
1060 | 516 | std::string input("name=True"); | ||
1061 | 517 | |||
1062 | 518 | parser::xpath_grammar<std::string::iterator> g; | ||
1063 | 519 | |||
1064 | 520 | xpathselect::XPathQueryParam result; | ||
1065 | 521 | ASSERT_EQ( true, test_parser_attr(input, g.param, result) ); | ||
1066 | 522 | ASSERT_EQ("name", result.param_name); | ||
1067 | 523 | boost::apply_visitor( | ||
1068 | 524 | variant_equality_assertion<bool>(true), | ||
1069 | 525 | result.param_value | ||
1070 | 526 | ); | ||
1071 | 527 | } | ||
1072 | 528 | |||
1073 | 529 | TEST(TestXPathParser, test_param_parser_string_int_works) | ||
1074 | 530 | { | ||
1075 | 531 | std::string input("name=123456"); | ||
1076 | 532 | |||
1077 | 533 | parser::xpath_grammar<std::string::iterator> g; | ||
1078 | 534 | |||
1079 | 535 | xpathselect::XPathQueryParam result; | ||
1080 | 536 | ASSERT_EQ( true, test_parser_attr(input, g.param, result) ); | ||
1081 | 537 | ASSERT_EQ("name", result.param_name); | ||
1082 | 538 | boost::apply_visitor( | ||
1083 | 539 | variant_equality_assertion<int>(123456), | ||
1084 | 540 | result.param_value | ||
1085 | 541 | ); | ||
1086 | 237 | } | 542 | } |
1087 | 238 | 543 | ||
1088 | 239 | TEST(TestXPathParser, test_param_parser_fails) | 544 | TEST(TestXPathParser, test_param_parser_fails) |
1089 | @@ -256,12 +561,15 @@ | |||
1090 | 256 | ASSERT_EQ( true, test_parser_attr(input, g.param_list, result) ); | 561 | ASSERT_EQ( true, test_parser_attr(input, g.param_list, result) ); |
1091 | 257 | ASSERT_EQ(1, result.size()); | 562 | ASSERT_EQ(1, result.size()); |
1092 | 258 | ASSERT_EQ("name", result.at(0).param_name); | 563 | ASSERT_EQ("name", result.at(0).param_name); |
1094 | 259 | ASSERT_EQ("123", result.at(0).param_value); | 564 | boost::apply_visitor( |
1095 | 565 | variant_equality_assertion<int>(123), | ||
1096 | 566 | result.at(0).param_value | ||
1097 | 567 | ); | ||
1098 | 260 | } | 568 | } |
1099 | 261 | 569 | ||
1100 | 262 | TEST(TestXPathParser, test_param_list_two_values) | 570 | TEST(TestXPathParser, test_param_list_two_values) |
1101 | 263 | { | 571 | { |
1103 | 264 | std::string input("[name=value,other=foo]"); | 572 | std::string input("[name=\"value\",visible=True]"); |
1104 | 265 | 573 | ||
1105 | 266 | parser::xpath_grammar<std::string::iterator> g; | 574 | parser::xpath_grammar<std::string::iterator> g; |
1106 | 267 | 575 | ||
1107 | @@ -269,9 +577,15 @@ | |||
1108 | 269 | ASSERT_EQ( true, test_parser_attr(input, g.param_list, result) ); | 577 | ASSERT_EQ( true, test_parser_attr(input, g.param_list, result) ); |
1109 | 270 | ASSERT_EQ(2, result.size()); | 578 | ASSERT_EQ(2, result.size()); |
1110 | 271 | ASSERT_EQ("name", result.at(0).param_name); | 579 | ASSERT_EQ("name", result.at(0).param_name); |
1114 | 272 | ASSERT_EQ("value", result.at(0).param_value); | 580 | boost::apply_visitor( |
1115 | 273 | ASSERT_EQ("other", result.at(1).param_name); | 581 | variant_equality_assertion<std::string>("value"), |
1116 | 274 | ASSERT_EQ("foo", result.at(1).param_value); | 582 | result.at(0).param_value |
1117 | 583 | ); | ||
1118 | 584 | ASSERT_EQ("visible", result.at(1).param_name); | ||
1119 | 585 | boost::apply_visitor( | ||
1120 | 586 | variant_equality_assertion<bool>(true), | ||
1121 | 587 | result.at(1).param_value | ||
1122 | 588 | ); | ||
1123 | 275 | } | 589 | } |
1124 | 276 | 590 | ||
1125 | 277 | TEST(TestXPathParser, test_spec_node_with_parameter) | 591 | TEST(TestXPathParser, test_spec_node_with_parameter) |
1126 | @@ -285,7 +599,10 @@ | |||
1127 | 285 | ASSERT_EQ("node_name", result.node_name_); | 599 | ASSERT_EQ("node_name", result.node_name_); |
1128 | 286 | ASSERT_FALSE(result.parameter.empty()); | 600 | ASSERT_FALSE(result.parameter.empty()); |
1129 | 287 | ASSERT_EQ("param_name", result.parameter.at(0).param_name); | 601 | ASSERT_EQ("param_name", result.parameter.at(0).param_name); |
1131 | 288 | ASSERT_EQ("123", result.parameter.at(0).param_value); | 602 | boost::apply_visitor( |
1132 | 603 | variant_equality_assertion<int>(123), | ||
1133 | 604 | result.parameter.at(0).param_value | ||
1134 | 605 | ); | ||
1135 | 289 | } | 606 | } |
1136 | 290 | 607 | ||
1137 | 291 | TEST(TestXPathParser, test_spec_node_without_parameter) | 608 | TEST(TestXPathParser, test_spec_node_without_parameter) |
1138 | @@ -333,13 +650,16 @@ | |||
1139 | 333 | ASSERT_EQ("*", result.node_name_); | 650 | ASSERT_EQ("*", result.node_name_); |
1140 | 334 | ASSERT_FALSE(result.parameter.empty()); | 651 | ASSERT_FALSE(result.parameter.empty()); |
1141 | 335 | ASSERT_EQ("param_name", result.parameter.at(0).param_name); | 652 | ASSERT_EQ("param_name", result.parameter.at(0).param_name); |
1143 | 336 | ASSERT_EQ("123", result.parameter.at(0).param_value); | 653 | boost::apply_visitor( |
1144 | 654 | variant_equality_assertion<int>(123), | ||
1145 | 655 | result.parameter.at(0).param_value | ||
1146 | 656 | ); | ||
1147 | 337 | } | 657 | } |
1148 | 338 | 658 | ||
1149 | 339 | 659 | ||
1150 | 340 | TEST(TestXPathParser, test_node_can_be_a_wildcard_node_with_params) | 660 | TEST(TestXPathParser, test_node_can_be_a_wildcard_node_with_params) |
1151 | 341 | { | 661 | { |
1153 | 342 | std::string input("*[name=value]"); | 662 | std::string input("*[name=\"value\"]"); |
1154 | 343 | 663 | ||
1155 | 344 | parser::xpath_grammar<std::string::iterator> g; | 664 | parser::xpath_grammar<std::string::iterator> g; |
1156 | 345 | 665 | ||
1157 | @@ -349,7 +669,10 @@ | |||
1158 | 349 | ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() ); | 669 | ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() ); |
1159 | 350 | ASSERT_EQ( 1, result.parameter.size() ); | 670 | ASSERT_EQ( 1, result.parameter.size() ); |
1160 | 351 | ASSERT_EQ( "name", result.parameter.at(0).param_name ); | 671 | ASSERT_EQ( "name", result.parameter.at(0).param_name ); |
1162 | 352 | ASSERT_EQ( "value", result.parameter.at(0).param_value ); | 672 | boost::apply_visitor( |
1163 | 673 | variant_equality_assertion<std::string>("value"), | ||
1164 | 674 | result.parameter.at(0).param_value | ||
1165 | 675 | ); | ||
1166 | 353 | } | 676 | } |
1167 | 354 | 677 | ||
1168 | 355 | TEST(TestXPathParser, test_node_can_be_a_wildcard_node_without_params) | 678 | TEST(TestXPathParser, test_node_can_be_a_wildcard_node_without_params) |
1169 | @@ -366,7 +689,7 @@ | |||
1170 | 366 | 689 | ||
1171 | 367 | TEST(TestXPathParser, test_node_can_be_a_spec_node_with_params) | 690 | TEST(TestXPathParser, test_node_can_be_a_spec_node_with_params) |
1172 | 368 | { | 691 | { |
1174 | 369 | std::string input("foo[name=value]"); | 692 | std::string input("foo[name=\"value\"]"); |
1175 | 370 | 693 | ||
1176 | 371 | parser::xpath_grammar<std::string::iterator> g; | 694 | parser::xpath_grammar<std::string::iterator> g; |
1177 | 372 | 695 | ||
1178 | @@ -376,7 +699,10 @@ | |||
1179 | 376 | ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() ); | 699 | ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() ); |
1180 | 377 | ASSERT_EQ( 1, result.parameter.size() ); | 700 | ASSERT_EQ( 1, result.parameter.size() ); |
1181 | 378 | ASSERT_EQ( "name", result.parameter.at(0).param_name ); | 701 | ASSERT_EQ( "name", result.parameter.at(0).param_name ); |
1183 | 379 | ASSERT_EQ( "value", result.parameter.at(0).param_value ); | 702 | boost::apply_visitor( |
1184 | 703 | variant_equality_assertion<std::string>("value"), | ||
1185 | 704 | result.parameter.at(0).param_value | ||
1186 | 705 | ); | ||
1187 | 380 | } | 706 | } |
1188 | 381 | 707 | ||
1189 | 382 | TEST(TestXPathParser, test_node_can_be_a_spec_node_without_params) | 708 | TEST(TestXPathParser, test_node_can_be_a_spec_node_without_params) |
1190 | @@ -391,6 +717,18 @@ | |||
1191 | 391 | ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() ); | 717 | ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() ); |
1192 | 392 | } | 718 | } |
1193 | 393 | 719 | ||
1194 | 720 | TEST(TestXPathParser, test_node_can_be_a_parent_node) | ||
1195 | 721 | { | ||
1196 | 722 | std::string input(".."); | ||
1197 | 723 | |||
1198 | 724 | parser::xpath_grammar<std::string::iterator> g; | ||
1199 | 725 | |||
1200 | 726 | xpathselect::XPathQueryPart result; | ||
1201 | 727 | ASSERT_EQ( true, test_parser_attr(input, g.node, result) ); | ||
1202 | 728 | ASSERT_EQ( "..", result.node_name_ ); | ||
1203 | 729 | ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Parent, result.Type() ); | ||
1204 | 730 | } | ||
1205 | 731 | |||
1206 | 394 | TEST(TestXPathParser, test_search_node_followed_by_normal_node) | 732 | TEST(TestXPathParser, test_search_node_followed_by_normal_node) |
1207 | 395 | { | 733 | { |
1208 | 396 | // the search_node grammar fails if it's at the end of the line, so we need | 734 | // the search_node grammar fails if it's at the end of the line, so we need |
1209 | @@ -409,7 +747,7 @@ | |||
1210 | 409 | { | 747 | { |
1211 | 410 | // the search_node grammar fails if it's at the end of the line, so we need | 748 | // the search_node grammar fails if it's at the end of the line, so we need |
1212 | 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. |
1214 | 412 | std::string input("//*[foo=bar]"); | 750 | std::string input("//*[foo=\"bar\"]"); |
1215 | 413 | parser::xpath_grammar<std::string::iterator> g; | 751 | parser::xpath_grammar<std::string::iterator> g; |
1216 | 414 | xpathselect::XPathQueryPart result; | 752 | xpathselect::XPathQueryPart result; |
1217 | 415 | 753 | ||
1218 | @@ -429,6 +767,17 @@ | |||
1219 | 429 | ASSERT_FALSE( test_parser_attr(input, g.search_node, result) ); | 767 | ASSERT_FALSE( test_parser_attr(input, g.search_node, result) ); |
1220 | 430 | } | 768 | } |
1221 | 431 | 769 | ||
1222 | 770 | TEST(TestXPathParser, test_parent_node) | ||
1223 | 771 | { | ||
1224 | 772 | std::string input(".."); | ||
1225 | 773 | |||
1226 | 774 | parser::xpath_grammar<std::string::iterator> g; | ||
1227 | 775 | |||
1228 | 776 | xpathselect::XPathQueryPart result; | ||
1229 | 777 | ASSERT_TRUE( test_parser_attr(input, g.parent_node, result) ); | ||
1230 | 778 | ASSERT_TRUE( result.Type() == xpathselect::XPathQueryPart::QueryPartType::Parent ); | ||
1231 | 779 | } | ||
1232 | 780 | |||
1233 | 432 | TEST(TestXPathParser, test_normal_sep_works) | 781 | TEST(TestXPathParser, test_normal_sep_works) |
1234 | 433 | { | 782 | { |
1235 | 434 | std::string input("/"); | 783 | std::string input("/"); |
1236 | @@ -503,7 +852,7 @@ | |||
1237 | 503 | 852 | ||
1238 | 504 | TEST(TestXPathParser, test_mix_search_and_long_normal) | 853 | TEST(TestXPathParser, test_mix_search_and_long_normal) |
1239 | 505 | { | 854 | { |
1241 | 506 | std::string input("/node1//node2[name=val]/node3"); | 855 | std::string input("/node1//node2[name=\"val\"]/node3"); |
1242 | 507 | 856 | ||
1243 | 508 | parser::xpath_grammar<std::string::iterator> g; | 857 | parser::xpath_grammar<std::string::iterator> g; |
1244 | 509 | 858 | ||
1245 | @@ -521,17 +870,55 @@ | |||
1246 | 521 | ASSERT_EQ("node2", result.at(2).node_name_); | 870 | ASSERT_EQ("node2", result.at(2).node_name_); |
1247 | 522 | ASSERT_EQ(1, result.at(2).parameter.size()); | 871 | ASSERT_EQ(1, result.at(2).parameter.size()); |
1248 | 523 | ASSERT_EQ("name", result.at(2).parameter.at(0).param_name); | 872 | ASSERT_EQ("name", result.at(2).parameter.at(0).param_name); |
1251 | 524 | ASSERT_EQ("val", result.at(2).parameter.at(0).param_value); | 873 | boost::apply_visitor( |
1252 | 525 | 874 | variant_equality_assertion<std::string>("val"), | |
1253 | 875 | result.at(2).parameter.at(0).param_value | ||
1254 | 876 | ); | ||
1255 | 526 | ASSERT_EQ("node3", result.at(3).node_name_); | 877 | ASSERT_EQ("node3", result.at(3).node_name_); |
1256 | 527 | ASSERT_TRUE(result.at(3).parameter.empty()); | 878 | ASSERT_TRUE(result.at(3).parameter.empty()); |
1257 | 528 | } | 879 | } |
1258 | 529 | 880 | ||
1259 | 881 | TEST(TestXPathParser, test_mix_normal_and_parent) | ||
1260 | 882 | { | ||
1261 | 883 | std::string input("/node1/.."); | ||
1262 | 884 | |||
1263 | 885 | parser::xpath_grammar<std::string::iterator> g; | ||
1264 | 886 | |||
1265 | 887 | xpathselect::QueryList result; | ||
1266 | 888 | ASSERT_TRUE(test_parser_attr(input, g.node_sequence, result)); | ||
1267 | 889 | |||
1268 | 890 | ASSERT_EQ(2, result.size()); | ||
1269 | 891 | |||
1270 | 892 | ASSERT_EQ("node1", result.at(0).node_name_); | ||
1271 | 893 | ASSERT_TRUE(result.at(0).parameter.empty()); | ||
1272 | 894 | |||
1273 | 895 | ASSERT_TRUE(result.at(1).Type() == xpathselect::XPathQueryPart::QueryPartType::Parent ); | ||
1274 | 896 | ASSERT_TRUE(result.at(1).parameter.empty()); | ||
1275 | 897 | } | ||
1276 | 898 | |||
1277 | 899 | TEST(TestXPathParser, test_mix_normal_and_parent_and_wildcard) | ||
1278 | 900 | { | ||
1279 | 901 | std::string input("/node1/../*"); | ||
1280 | 902 | |||
1281 | 903 | parser::xpath_grammar<std::string::iterator> g; | ||
1282 | 904 | |||
1283 | 905 | xpathselect::QueryList result; | ||
1284 | 906 | ASSERT_TRUE(test_parser_attr(input, g.node_sequence, result)); | ||
1285 | 907 | |||
1286 | 908 | ASSERT_EQ(3, result.size()); | ||
1287 | 909 | |||
1288 | 910 | ASSERT_EQ("node1", result.at(0).node_name_); | ||
1289 | 911 | ASSERT_TRUE(result.at(0).parameter.empty()); | ||
1290 | 912 | |||
1291 | 913 | ASSERT_TRUE(result.at(1).Type() == xpathselect::XPathQueryPart::QueryPartType::Parent ); | ||
1292 | 914 | ASSERT_TRUE(result.at(1).parameter.empty()); | ||
1293 | 915 | |||
1294 | 916 | ASSERT_TRUE(result.at(2).node_name_ == "*" ); | ||
1295 | 917 | ASSERT_TRUE(result.at(2).parameter.empty()); | ||
1296 | 918 | } | ||
1297 | 530 | 919 | ||
1298 | 531 | class TestXPathParserQueryStrings : public ::testing::TestWithParam<std::pair<std::string, bool> > | 920 | class TestXPathParserQueryStrings : public ::testing::TestWithParam<std::pair<std::string, bool> > |
1302 | 532 | { | 921 | {}; |
1300 | 533 | }; | ||
1301 | 534 | |||
1303 | 535 | 922 | ||
1304 | 536 | TEST_P(TestXPathParserQueryStrings, test_query_acceptance) | 923 | TEST_P(TestXPathParserQueryStrings, test_query_acceptance) |
1305 | 537 | { | 924 | { |
1306 | @@ -556,11 +943,11 @@ | |||
1307 | 556 | std::pair<std::string, bool>("/root//node1", true), | 943 | std::pair<std::string, bool>("/root//node1", true), |
1308 | 557 | std::pair<std::string, bool>("//root", true), | 944 | std::pair<std::string, bool>("//root", true), |
1309 | 558 | std::pair<std::string, bool>("/root//node1/node2", true), | 945 | std::pair<std::string, bool>("/root//node1/node2", true), |
1313 | 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), |
1314 | 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), |
1315 | 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), |
1316 | 562 | std::pair<std::string, bool>("/Root//*[p=1]", true), | 949 | std::pair<std::string, bool>("/Root//*[p=1]", true), |
1318 | 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), |
1319 | 564 | // queries that must not parse correctly: | 951 | // queries that must not parse correctly: |
1320 | 565 | std::pair<std::string, bool>("//", false), | 952 | std::pair<std::string, bool>("//", false), |
1321 | 566 | std::pair<std::string, bool>("/root//", false), | 953 | std::pair<std::string, bool>("/root//", false), |
1322 | @@ -570,5 +957,7 @@ | |||
1323 | 570 | std::pair<std::string, bool>(" ", false), | 957 | std::pair<std::string, bool>(" ", false), |
1324 | 571 | std::pair<std::string, bool>("//*", false), | 958 | std::pair<std::string, bool>("//*", false), |
1325 | 572 | std::pair<std::string, bool>("/Root///Leaf", false), | 959 | std::pair<std::string, bool>("/Root///Leaf", false), |
1327 | 573 | std::pair<std::string, bool>("/Root////", false) | 960 | std::pair<std::string, bool>("/Root////", false), |
1328 | 961 | std::pair<std::string, bool>("/Root/..*", false), | ||
1329 | 962 | std::pair<std::string, bool>("/Root/../Child//..", false) | ||
1330 | 574 | )); | 963 | )); |
1331 | 575 | 964 | ||
1332 | === modified file 'test/test_xpath_simple.cpp' | |||
1333 | --- test/test_xpath_simple.cpp 2012-08-10 04:06:05 +0000 | |||
1334 | +++ test/test_xpath_simple.cpp 2013-09-16 15:53:33 +0000 | |||
1335 | @@ -26,7 +26,7 @@ | |||
1336 | 26 | TEST(TestXPath, test_select_empty_tree) | 26 | TEST(TestXPath, test_select_empty_tree) |
1337 | 27 | { | 27 | { |
1338 | 28 | xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>(); | 28 | xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>(); |
1340 | 29 | xpathselect::NodeList result = xpathselect::SelectNodes(tree_root, ""); | 29 | xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, ""); |
1341 | 30 | 30 | ||
1342 | 31 | ASSERT_EQ(1, result.size()); | 31 | ASSERT_EQ(1, result.size()); |
1343 | 32 | } | 32 | } |
1344 | @@ -35,7 +35,7 @@ | |||
1345 | 35 | TEST(TestXPath, test_select_tree_root) | 35 | TEST(TestXPath, test_select_tree_root) |
1346 | 36 | { | 36 | { |
1347 | 37 | xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode"); | 37 | xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode"); |
1349 | 38 | xpathselect::NodeList result = xpathselect::SelectNodes(tree_root, "/"); | 38 | xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "/"); |
1350 | 39 | 39 | ||
1351 | 40 | ASSERT_EQ(result.size(), 1); | 40 | ASSERT_EQ(result.size(), 1); |
1352 | 41 | ASSERT_EQ(result.front(), tree_root); | 41 | ASSERT_EQ(result.front(), tree_root); |
1353 | @@ -45,7 +45,7 @@ | |||
1354 | 45 | TEST(TestXPath, test_select_tree_root_with_name) | 45 | TEST(TestXPath, test_select_tree_root_with_name) |
1355 | 46 | { | 46 | { |
1356 | 47 | xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode"); | 47 | xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode"); |
1358 | 48 | xpathselect::NodeList result = xpathselect::SelectNodes(tree_root, "/RootNode"); | 48 | xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "/RootNode"); |
1359 | 49 | 49 | ||
1360 | 50 | ASSERT_EQ(result.size(), 1); | 50 | ASSERT_EQ(result.size(), 1); |
1361 | 51 | ASSERT_EQ(result.front(), tree_root); | 51 | ASSERT_EQ(result.front(), tree_root); |
1362 | @@ -55,7 +55,7 @@ | |||
1363 | 55 | TEST(TestXPath, test_select_tree_root_with_relative_query) | 55 | TEST(TestXPath, test_select_tree_root_with_relative_query) |
1364 | 56 | { | 56 | { |
1365 | 57 | xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode"); | 57 | xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode"); |
1367 | 58 | xpathselect::NodeList result = xpathselect::SelectNodes(tree_root, "//RootNode"); | 58 | xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "//RootNode"); |
1368 | 59 | 59 | ||
1369 | 60 | ASSERT_EQ(result.size(), 1); | 60 | ASSERT_EQ(result.size(), 1); |
1370 | 61 | ASSERT_EQ(result.front(), tree_root); | 61 | ASSERT_EQ(result.front(), tree_root); |
1371 | @@ -65,7 +65,7 @@ | |||
1372 | 65 | TEST(TestXPath, test_select_tree_root_with_empty_relative_query) | 65 | TEST(TestXPath, test_select_tree_root_with_empty_relative_query) |
1373 | 66 | { | 66 | { |
1374 | 67 | xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode"); | 67 | xpathselect::Node::Ptr tree_root = std::make_shared<DummyNode>("RootNode"); |
1376 | 68 | xpathselect::NodeList result = xpathselect::SelectNodes(tree_root, "//"); | 68 | xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "//"); |
1377 | 69 | 69 | ||
1378 | 70 | ASSERT_EQ(result.size(), 1); | 70 | ASSERT_EQ(result.size(), 1); |
1379 | 71 | ASSERT_EQ(result.front(), tree_root); | 71 | ASSERT_EQ(result.front(), tree_root); |
1380 | 72 | 72 | ||
1381 | === modified file 'test/test_xpath_tree.cpp' | |||
1382 | --- test/test_xpath_tree.cpp 2013-04-24 03:48:30 +0000 | |||
1383 | +++ test/test_xpath_tree.cpp 2013-09-16 15:53:33 +0000 | |||
1384 | @@ -49,14 +49,14 @@ | |||
1385 | 49 | 49 | ||
1386 | 50 | TEST_F(TestTreeFixture, test_simple) | 50 | TEST_F(TestTreeFixture, test_simple) |
1387 | 51 | { | 51 | { |
1389 | 52 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/"); | 52 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/"); |
1390 | 53 | 53 | ||
1391 | 54 | ASSERT_EQ(1, result.size()); | 54 | ASSERT_EQ(1, result.size()); |
1392 | 55 | } | 55 | } |
1393 | 56 | 56 | ||
1394 | 57 | TEST_F(TestTreeFixture, test_simple_absolute) | 57 | TEST_F(TestTreeFixture, test_simple_absolute) |
1395 | 58 | { | 58 | { |
1397 | 59 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1"); | 59 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1"); |
1398 | 60 | 60 | ||
1399 | 61 | ASSERT_EQ(1, result.size()); | 61 | ASSERT_EQ(1, result.size()); |
1400 | 62 | auto expected = child_l1_; | 62 | auto expected = child_l1_; |
1401 | @@ -66,7 +66,7 @@ | |||
1402 | 66 | 66 | ||
1403 | 67 | TEST_F(TestTreeFixture, test_simple_relative) | 67 | TEST_F(TestTreeFixture, test_simple_relative) |
1404 | 68 | { | 68 | { |
1406 | 69 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "//ChildRight1"); | 69 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//ChildRight1"); |
1407 | 70 | 70 | ||
1408 | 71 | ASSERT_EQ(1, result.size()); | 71 | ASSERT_EQ(1, result.size()); |
1409 | 72 | ASSERT_EQ(child_r1_, result.front()); | 72 | ASSERT_EQ(child_r1_, result.front()); |
1410 | @@ -74,7 +74,7 @@ | |||
1411 | 74 | 74 | ||
1412 | 75 | TEST_F(TestTreeFixture, test_complex_relative) | 75 | TEST_F(TestTreeFixture, test_complex_relative) |
1413 | 76 | { | 76 | { |
1415 | 77 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "//Root/ChildRight1"); | 77 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//Root/ChildRight1"); |
1416 | 78 | 78 | ||
1417 | 79 | ASSERT_EQ(1, result.size()); | 79 | ASSERT_EQ(1, result.size()); |
1418 | 80 | ASSERT_EQ(child_r1_, result.front()); | 80 | ASSERT_EQ(child_r1_, result.front()); |
1419 | @@ -82,7 +82,7 @@ | |||
1420 | 82 | 82 | ||
1421 | 83 | TEST_F(TestTreeFixture, test_relative_multiple_return) | 83 | TEST_F(TestTreeFixture, test_relative_multiple_return) |
1422 | 84 | { | 84 | { |
1424 | 85 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "//Leaf"); | 85 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//Leaf"); |
1425 | 86 | 86 | ||
1426 | 87 | ASSERT_EQ(2, result.size()); | 87 | ASSERT_EQ(2, result.size()); |
1427 | 88 | 88 | ||
1428 | @@ -94,7 +94,7 @@ | |||
1429 | 94 | 94 | ||
1430 | 95 | TEST_F(TestTreeFixture, test_relative_wildcard) | 95 | TEST_F(TestTreeFixture, test_relative_wildcard) |
1431 | 96 | { | 96 | { |
1433 | 97 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "//ChildLeft1/*"); | 97 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//ChildLeft1/*"); |
1434 | 98 | 98 | ||
1435 | 99 | ASSERT_EQ(2, result.size()); | 99 | ASSERT_EQ(2, result.size()); |
1436 | 100 | 100 | ||
1437 | @@ -106,7 +106,7 @@ | |||
1438 | 106 | 106 | ||
1439 | 107 | TEST_F(TestTreeFixture, test_absolute_wildcard) | 107 | TEST_F(TestTreeFixture, test_absolute_wildcard) |
1440 | 108 | { | 108 | { |
1442 | 109 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/*"); | 109 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/*"); |
1443 | 110 | 110 | ||
1444 | 111 | ASSERT_EQ(2, result.size()); | 111 | ASSERT_EQ(2, result.size()); |
1445 | 112 | 112 | ||
1446 | @@ -119,7 +119,7 @@ | |||
1447 | 119 | TEST_F(TestTreeFixture, test_simple_absolute_property_match) | 119 | TEST_F(TestTreeFixture, test_simple_absolute_property_match) |
1448 | 120 | { | 120 | { |
1449 | 121 | child_l1_->AddProperty("visible", "True"); | 121 | child_l1_->AddProperty("visible", "True"); |
1451 | 122 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1[visible=True]"); | 122 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1[visible=True]"); |
1452 | 123 | 123 | ||
1453 | 124 | ASSERT_EQ(1, result.size()); | 124 | ASSERT_EQ(1, result.size()); |
1454 | 125 | ASSERT_EQ(child_l1_, result.front()); | 125 | ASSERT_EQ(child_l1_, result.front()); |
1455 | @@ -127,8 +127,8 @@ | |||
1456 | 127 | 127 | ||
1457 | 128 | TEST_F(TestTreeFixture, test_simple_relative_property_match) | 128 | TEST_F(TestTreeFixture, test_simple_relative_property_match) |
1458 | 129 | { | 129 | { |
1461 | 130 | child_l1_->AddProperty("visible", "True"); | 130 | child_l1_->AddProperty("visible", true); |
1462 | 131 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "//ChildLeft1[visible=True]"); | 131 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//ChildLeft1[visible=True]"); |
1463 | 132 | 132 | ||
1464 | 133 | ASSERT_EQ(1, result.size()); | 133 | ASSERT_EQ(1, result.size()); |
1465 | 134 | ASSERT_EQ(child_l1_, result.front()); | 134 | ASSERT_EQ(child_l1_, result.front()); |
1466 | @@ -136,9 +136,9 @@ | |||
1467 | 136 | 136 | ||
1468 | 137 | TEST_F(TestTreeFixture, test_absolute_multiple_property_match) | 137 | TEST_F(TestTreeFixture, test_absolute_multiple_property_match) |
1469 | 138 | { | 138 | { |
1473 | 139 | root_->AddProperty("number", "45"); | 139 | root_->AddProperty("number", 45); |
1474 | 140 | child_l1_->AddProperty("visible", "True"); | 140 | child_l1_->AddProperty("visible", true); |
1475 | 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]"); |
1476 | 142 | 142 | ||
1477 | 143 | ASSERT_EQ(1, result.size()); | 143 | ASSERT_EQ(1, result.size()); |
1478 | 144 | ASSERT_EQ(child_l1_, result.front()); | 144 | ASSERT_EQ(child_l1_, result.front()); |
1479 | @@ -146,7 +146,7 @@ | |||
1480 | 146 | 146 | ||
1481 | 147 | TEST_F(TestTreeFixture, test_mixed_query_simple) | 147 | TEST_F(TestTreeFixture, test_mixed_query_simple) |
1482 | 148 | { | 148 | { |
1484 | 149 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root//Leaf"); | 149 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root//Leaf"); |
1485 | 150 | ASSERT_EQ(2, result.size()); | 150 | ASSERT_EQ(2, result.size()); |
1486 | 151 | for(auto n : result) | 151 | for(auto n : result) |
1487 | 152 | { | 152 | { |
1488 | @@ -156,8 +156,8 @@ | |||
1489 | 156 | 156 | ||
1490 | 157 | TEST_F(TestTreeFixture, test_mixed_query_property_match) | 157 | TEST_F(TestTreeFixture, test_mixed_query_property_match) |
1491 | 158 | { | 158 | { |
1494 | 159 | leaf_1_->AddProperty("visible", "True"); | 159 | leaf_1_->AddProperty("visible", true); |
1495 | 160 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root//Leaf[visible=True]"); | 160 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root//Leaf[visible=True]"); |
1496 | 161 | 161 | ||
1497 | 162 | ASSERT_EQ(1, result.size()); | 162 | ASSERT_EQ(1, result.size()); |
1498 | 163 | ASSERT_EQ(leaf_1_, result.front()); | 163 | ASSERT_EQ(leaf_1_, result.front()); |
1499 | @@ -165,8 +165,8 @@ | |||
1500 | 165 | 165 | ||
1501 | 166 | TEST_F(TestTreeFixture, test_search_node_with_wildcard_and_property) | 166 | TEST_F(TestTreeFixture, test_search_node_with_wildcard_and_property) |
1502 | 167 | { | 167 | { |
1505 | 168 | child_l1_->AddProperty("visible", "True"); | 168 | child_l1_->AddProperty("visible", true); |
1506 | 169 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root//*[visible=True]"); | 169 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root//*[visible=True]"); |
1507 | 170 | 170 | ||
1508 | 171 | ASSERT_EQ(1, result.size()); | 171 | ASSERT_EQ(1, result.size()); |
1509 | 172 | ASSERT_EQ(child_l1_, result.front()); | 172 | ASSERT_EQ(child_l1_, result.front()); |
1510 | @@ -174,7 +174,7 @@ | |||
1511 | 174 | 174 | ||
1512 | 175 | TEST_F(TestTreeFixture, test_wildcard) | 175 | TEST_F(TestTreeFixture, test_wildcard) |
1513 | 176 | { | 176 | { |
1515 | 177 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root/*"); | 177 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/*"); |
1516 | 178 | ASSERT_EQ(2, result.size()); | 178 | ASSERT_EQ(2, result.size()); |
1517 | 179 | for(auto n : result) | 179 | for(auto n : result) |
1518 | 180 | { | 180 | { |
1519 | @@ -182,14 +182,54 @@ | |||
1520 | 182 | } | 182 | } |
1521 | 183 | } | 183 | } |
1522 | 184 | 184 | ||
1523 | 185 | TEST_F(TestTreeFixture, test_parent) | ||
1524 | 186 | { | ||
1525 | 187 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/.."); | ||
1526 | 188 | |||
1527 | 189 | ASSERT_EQ(1, result.size()); | ||
1528 | 190 | ASSERT_EQ(root_, result.front()); | ||
1529 | 191 | } | ||
1530 | 192 | |||
1531 | 193 | TEST_F(TestTreeFixture, test_parent_on_root) | ||
1532 | 194 | { | ||
1533 | 195 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/.."); | ||
1534 | 196 | |||
1535 | 197 | ASSERT_EQ(1, result.size()); | ||
1536 | 198 | ASSERT_EQ(root_, result.front()); | ||
1537 | 199 | } | ||
1538 | 200 | |||
1539 | 201 | TEST_F(TestTreeFixture, test_parent_on_leaf) | ||
1540 | 202 | { | ||
1541 | 203 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/Leaf/.."); | ||
1542 | 204 | |||
1543 | 205 | ASSERT_EQ(1, result.size()); | ||
1544 | 206 | ASSERT_EQ(child_l1_, result.front()); | ||
1545 | 207 | } | ||
1546 | 208 | |||
1547 | 209 | TEST_F(TestTreeFixture, test_double_parent_on_leaf) | ||
1548 | 210 | { | ||
1549 | 211 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/Leaf/../.."); | ||
1550 | 212 | |||
1551 | 213 | ASSERT_EQ(1, result.size()); | ||
1552 | 214 | ASSERT_EQ(root_, result.front()); | ||
1553 | 215 | } | ||
1554 | 216 | |||
1555 | 217 | TEST_F(TestTreeFixture, test_parent_and_child) | ||
1556 | 218 | { | ||
1557 | 219 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/../ChildLeft1/../ChildLeft1"); | ||
1558 | 220 | |||
1559 | 221 | ASSERT_EQ(1, result.size()); | ||
1560 | 222 | ASSERT_EQ(child_l1_, result.front()); | ||
1561 | 223 | } | ||
1562 | 224 | |||
1563 | 185 | TEST_F(TestTreeFixture, test_invalid_query_search) | 225 | TEST_F(TestTreeFixture, test_invalid_query_search) |
1564 | 186 | { | 226 | { |
1566 | 187 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root///Leaf"); | 227 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root///Leaf"); |
1567 | 188 | ASSERT_EQ(0, result.size()); | 228 | ASSERT_EQ(0, result.size()); |
1568 | 189 | } | 229 | } |
1569 | 190 | 230 | ||
1570 | 191 | TEST_F(TestTreeFixture, test_invalid_query_multiple_searches) | 231 | TEST_F(TestTreeFixture, test_invalid_query_multiple_searches) |
1571 | 192 | { | 232 | { |
1573 | 193 | xpathselect::NodeList result = xpathselect::SelectNodes(root_, "/Root////"); | 233 | xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root////"); |
1574 | 194 | ASSERT_EQ(0, result.size()); | 234 | ASSERT_EQ(0, result.size()); |
1575 | 195 | } | 235 | } |
PASSED: Continuous integration, rev:51 jenkins. qa.ubuntu. com/job/ xpathselect- ci/5/ jenkins. qa.ubuntu. com/job/ xpathselect- saucy-amd64- ci/1 jenkins. qa.ubuntu. com/job/ xpathselect- saucy-armhf- ci/1
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ xpathselect- ci/5/rebuild
http://