xpathselect-1.4+15.10.20150824.1/ 0000755 0000153 0000161 00000000000 12566631574 016413 5 ustar pbuser pbgroup 0000000 0000000 xpathselect-1.4+15.10.20150824.1/lib/ 0000755 0000153 0000161 00000000000 12566631574 017161 5 ustar pbuser pbgroup 0000000 0000000 xpathselect-1.4+15.10.20150824.1/lib/xpathselect.cpp 0000644 0000153 0000161 00000015527 12566631427 022220 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include
#include
#include "xpathselect.h"
#include "xpathquerypart.h"
#include "parser.h"
namespace xpathselect
{
// anonymous namespace for internal-only utility class:
namespace
{
QueryList GetQueryPartsFromQuery(std::string const& query)
{
xpathselect::parser::xpath_grammar grammar;
QueryList query_parts;
auto begin = query.cbegin();
auto end = query.cend();
if (boost::spirit::qi::parse(begin, end, grammar, query_parts) && (begin == end))
{
#ifdef DEBUG
std::cout << "Query parts are: ";
for (auto n : query_parts)
n.Dump();
std::cout << std::endl;
#endif
return query_parts;
}
#ifdef DEBUG
std::cout << "Query failed." << std::endl;
#endif
return QueryList();
}
// Starting at each node listed in 'start_points', search the tree for nodes that match
// 'next_match'. next_match *must* be a normal query part object, not a search token.
NodeList SearchTreeForNode(NodeList const& start_points, XPathQueryPart const& next_match)
{
NodeList matches;
for (auto root: start_points)
{
// non-recursive BFS traversal to find starting points:
std::queue queue;
queue.push(root);
while (!queue.empty())
{
Node::Ptr node = queue.front();
queue.pop();
if (next_match.Matches(node))
{
// found one. We keep going deeper, as there may be another node beneath this one
// with the same node name.
matches.push_back(node);
}
// Add all children of current node to queue.
for(Node::Ptr child : node->Children())
{
queue.push(child);
}
}
}
return matches;
}
} // end of anonymous namespace
NodeVector SelectNodes(Node::Ptr const& root, std::string query)
{
// allow users to be lazy when specifying tree root:
if (query == "" || query == "/" || query == "//")
{
query = "/" + root->GetName();
}
QueryList query_parts = GetQueryPartsFromQuery(query);
if (query_parts.empty())
return NodeVector();
auto query_part = query_parts.cbegin();
NodeList start_nodes { root };
while (query_part != query_parts.cend())
{
// If the current query piece is a recursive search token ('//')...
if (query_part->Type() == XPathQueryPart::QueryPartType::Search)
{
// advance to look at the next piece.
++query_part;
// do some sanity checking...
if (query_part->Type() == XPathQueryPart::QueryPartType::Search)
// invalid query - cannot specify multiple search sequences in a row.
return NodeVector();
// then find all the nodes that match the new query part, and store them as
// the new start nodes. We pass in 'start_nodes' rather than 'root' since
// there's a chance we'll be doing more than one search in different parts of the tree.
start_nodes = SearchTreeForNode(start_nodes, *query_part);
}
else if (query_part->Type() == XPathQueryPart::QueryPartType::Parent)
{
// This part of the query selects the parent node. If the current node has no
// parent (i.e.- we're already at the root of the tree) then this is a no-op:
NodeList new_start_nodes;
for (auto n: start_nodes)
{
auto parent = n->GetParent();
new_start_nodes.push_back(parent ? parent : n);
}
start_nodes = new_start_nodes;
}
else
{
// this isn't a search token. Look at each node in the start_nodes list,
// and discard any that don't match the current query part.
// C++11 is the shit:
start_nodes.erase(
std::remove_if(
start_nodes.begin(),
start_nodes.end(),
[query_part](Node::Ptr n) -> bool {
return ! query_part->Matches(n);
}
),
start_nodes.end()
);
}
// then replace each node still in the list with all it's children.
// ... but only if we're not on the last query part, and only if the
// next query part is not a parent node...
auto next_query_part = query_part + 1;
if (next_query_part != query_parts.cend()
&& next_query_part->Type() != XPathQueryPart::QueryPartType::Parent)
{
NodeList new_start_nodes;
for (auto node: start_nodes)
{
auto children = node->Children();
if (children.size())
{
new_start_nodes.insert(
new_start_nodes.end(),
children.begin(),
children.end());
}
}
start_nodes = new_start_nodes;
}
++query_part;
}
// remove duplicate nodes by sorting & unique'ing:
// we could probably do this better, but since start_nodes is
// typically very small at this stage, I'm not sure it's worth it:
start_nodes.sort([](Node::Ptr a, Node::Ptr b) -> bool {
return a->GetId() < b->GetId();
});
start_nodes.unique([](Node::Ptr a, Node::Ptr b) -> bool {
return a->GetId() == b->GetId();
});
return NodeVector(start_nodes.begin(), start_nodes.end());
}
}
xpathselect-1.4+15.10.20150824.1/lib/parser.h 0000644 0000153 0000161 00000024273 12566631427 020633 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2013 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef _PARSER_H
#define _PARSER_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "xpathquerypart.h"
// this allows spirit to lazily construct these two structs...
BOOST_FUSION_ADAPT_STRUCT(
xpathselect::XPathQueryPart,
(std::string, node_name_)
(xpathselect::ParamList, parameter)
);
BOOST_FUSION_ADAPT_STRUCT(
xpathselect::XPathQueryParam,
(std::string, param_name)
(xpathselect::XPathQueryParam::ParamValueType, param_value)
);
namespace xpathselect
{
namespace parser
{
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
// python_bool_policy determines what can be considered truthy. We follow python
// repr format.
struct python_bool_policy : qi::bool_policies<>
{
template
static bool parse_true(Iterator& first, Iterator const& last, Attribute& attr)
{
if (qi::detail::string_parse("True", first, last, qi::unused))
{
boost::spirit::traits::assign_to(true, attr); // result is true
return true; // parsing succeeded
}
return false; // parsing failed
}
template
static bool parse_false(Iterator& first, Iterator const& last, Attribute& attr)
{
if (qi::detail::string_parse("False", first, last, qi::unused))
{
boost::spirit::traits::assign_to(false, attr); // result is false
return true;
}
return false;
}
};
// This is the main XPath grammar. It looks horrible, until you emerse yourself in it for a few
// days, then the beauty of boost::spirit creeps into your brain. To help future programmers,
// I've heavily commented this.
//
// The first template parameter to this grammar defines the type of iterator the grammer will operate
// on - it must adhere to std::forward_iterator. The second template parameter is the type
// that this grammar will produce (in this case: a list of XPathQueryPart objects).
template
struct xpath_grammar : qi::grammar
{
xpath_grammar() : xpath_grammar::base_type(node_sequence) // node_sequence is the start rule.
{
using namespace qi::labels;
// character escape codes. The input on the left will produce the output on
// the right:
unesc_char.add("\\a", '\a')
("\\b", '\b')
("\\f", '\f')
("\\n", '\n')
("\\r", '\r')
("\\t", '\t')
("\\v", '\v')
("\\\\", '\\')
("\\\'", '\'')
("\\\"", '\"');
unesc_str = '"' >> *(
unesc_char |
qi::alnum |
qi::space |
"\\x" >> qi::hex
) >> '"';
unesc_str = '"'
>> *(unesc_char | "\\x" >> qi::hex | (qi::print - '"'))
>> '"'
;
int_type = qi::int_parser();
// Parameter grammar:
// parameter name can contain some basic text (no spaces or '.')
param_name = +qi::char_("a-zA-Z0-9_\\-");
// parameter values can be several different types.
// Alternatives are tried left to right, and the first match found is the one used.
param_value = unesc_str | int_type | bool_type;
// parameter specification is simple: name=value
param %= param_name >> '=' >> param_value;
// a parameter list is a list of parameters separated by ',''s surrounded in '[...]'
param_list = '[' >> param % ',' >> ']';
// spec_node_name is a node name that has been explicitly specified.
// it must start and end with a non-space character, but you can have
// spaces in the middle.
spec_node_name = +qi::char_("a-zA-Z0-9_\\-") >> *(+qi::char_(" :") >> +qi::char_("a-zA-Z0-9_\\-"));
// a wildcard node name is simply a '*'
wildcard_node_name = qi::char_("*");
// a spec_node consists of a specified node name, followed by an *optional* parameter list.
spec_node %= spec_node_name >> -(param_list);
// a wildcard node is a '*' without parameters:
wildcard_node %= wildcard_node_name >> !param_list;
// wildcard nodes can also have parameters:
wildcard_node_with_params %= wildcard_node_name >> param_list;
// A parent node is '..' as long as it's followed by a normal separator or end of input:
parent_node = qi::lit("..")[qi::_val = XPathQueryPart("..")];
// node is simply any kind of code defined thus far:
node = spec_node | wildcard_node_with_params | wildcard_node | parent_node;
// a search node is '//' as long as it's followed by a spec node or a wildcard node with parameters.
// we don't allow '//*' since it would match everything in the tree, and cause HUGE amounts of
// data to be transmitted.
search_node = "//" >> &(spec_node | wildcard_node_with_params)[qi::_val = XPathQueryPart()];
// a normal separator is a '/' as long as it's followed by something other than another '/'
normal_sep = '/' >> !qi::lit('/');
separator = normal_sep | search_node; // nodes can be separated by normal_sep or search_node.
// this is the money shot: a node sequence is one or more of a separator, followed by an
// optional node.
node_sequence %= +(separator >> -node);
// DEBUGGING SUPPORT:
// define DEBUG in order to have boost::spirit spit out useful debug information:
#ifdef DEBUG
// this gives english names to all the grammar rules:
spec_node_name.name("spec_node_name");
wildcard_node_name.name("wildcard_node_name");
search_node.name("search_node");
normal_sep.name("normal_separator");
separator.name("separator");
param_name.name("param_name");
param_value.name("param_value");
param.name("param");
spec_node.name("spec_node");
wildcard_node.name("wildcard_node");
wildcard_node.name("wildcard_node_with_params");
node.name("node");
node_sequence.name("node_sequence");
param_list.name("param_list");
// set up error logging:
qi::on_error(
node_sequence,
std::cout
<< phoenix::val("Error! Expecting ")
<< qi::_4 // what failed?
<< phoenix::val(" here: \"")
<< phoenix::construct(qi::_3, qi::_2) // iterators to error-pos, end
<< phoenix::val("\"")
<< std::endl
);
// specify which rules we want debug info about (all of them):
qi::debug(spec_node_name);
qi::debug(wildcard_node_name);
qi::debug(search_node);
qi::debug(normal_sep);
qi::debug(separator);
qi::debug(param_name);
qi::debug(param_value);
qi::debug(param);
qi::debug(spec_node);
qi::debug(wildcard_node);
qi::debug(wildcard_node_with_params);
qi::debug(node);
qi::debug(node_sequence);
qi::debug(param_list);
#endif
}
// declare all the rules. The second template parameter is the type they produce.
// basic type rules:
// parse python Boolean represetnations 'True' or 'False':
qi::bool_parser bool_type;
// parse an escaped byte string.
qi::rule unesc_str;
// symbol table for chracter scape codes.
qi::symbols unesc_char;
// parse integers, first signed then unsigned:
qi::rule int_type;
// more complicated language rules:
qi::rule spec_node_name;
qi::rule wildcard_node_name;
qi::rule search_node;
qi::rule parent_node;
qi::rule normal_sep;
qi::rule separator;
qi::rule param_name;
qi::rule param_value;
qi::rule param;
qi::rule param_list;
qi::rule spec_node;
qi::rule wildcard_node;
qi::rule wildcard_node_with_params;
qi::rule node;
qi::rule node_sequence;
};
}
}
#endif
xpathselect-1.4+15.10.20150824.1/lib/parser.cpp 0000644 0000153 0000161 00000001174 12566631427 021161 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2013 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "parser.h"
xpathselect-1.4+15.10.20150824.1/lib/xpathselect.h 0000644 0000153 0000161 00000001575 12566631427 021663 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef _XPATHSELECT_H
#define _XPATHSELECT_H
#include "node.h"
namespace xpathselect
{
/// Search the node tree beginning with 'root' and return nodes that
/// match 'query'.
extern "C" NodeVector SelectNodes(Node::Ptr const& root, std::string query);
}
#endif
xpathselect-1.4+15.10.20150824.1/lib/xpathquerypart.h 0000644 0000153 0000161 00000006306 12566631427 022435 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2013 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef _XPATHQUERYPART_H
#define _XPATHQUERYPART_H
#include
#include
#include
#include
#include
#include
#include
#include "node.h"
namespace xpathselect
{
// stores a parameter name, value pair.
struct XPathQueryParam
{
typedef boost::variant ParamValueType;
std::string param_name;
ParamValueType param_value;
};
typedef std::vector ParamList;
// Stores a part of an XPath query.
struct XPathQueryPart
{
public:
XPathQueryPart() {}
XPathQueryPart(std::string node_name)
: node_name_(node_name)
{}
enum class QueryPartType {Normal, Search, Parent};
bool Matches(Node::Ptr const& node) const
{
bool matches = (node_name_ == "*" || node->GetName() == node_name_);
if (!parameter.empty())
{
for (auto param : parameter)
{
switch(param.param_value.which())
{
case 0:
{
matches &= node->MatchStringProperty(param.param_name, boost::get(param.param_value));
}
break;
case 1:
{
matches &= node->MatchBooleanProperty(param.param_name, boost::get(param.param_value));
}
break;
case 2:
{
matches &= node->MatchIntegerProperty(param.param_name, boost::get(param.param_value));
}
break;
}
}
}
return matches;
}
QueryPartType Type() const
{
if (node_name_ == "")
return QueryPartType::Search;
else if (node_name_ == "..")
return QueryPartType::Parent;
else
return QueryPartType::Normal;
}
void Dump() const
{
if (Type() == QueryPartType::Search)
std::cout << " ";
else
std::cout << "[" << node_name_ << "] ";
}
std::string node_name_;
ParamList parameter;
};
typedef std::vector QueryList;
}
#endif
xpathselect-1.4+15.10.20150824.1/lib/node.cpp 0000644 0000153 0000161 00000001172 12566631427 020610 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "node.h"
xpathselect-1.4+15.10.20150824.1/lib/node.h 0000644 0000153 0000161 00000003502 12566631427 020254 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef _NODE_H
#define _NODE_H
#include
#include
#include
#include
#include
namespace xpathselect
{
/// Represents a node in the object tree. Provide an implementation of
/// this class in your own code.
class Node
{
public:
typedef std::shared_ptr Ptr;
/// Get the node's name.
virtual std::string GetName() const =0;
/// Get the node's full path
virtual std::string GetPath() const =0;
/// Get this node's ID.
virtual int32_t GetId() const =0;
virtual bool MatchBooleanProperty(const std::string& name, bool value) const =0;
virtual bool MatchIntegerProperty(const std::string& name, int32_t value) const =0;
virtual bool MatchStringProperty(const std::string& name, const std::string& value) const =0;
/// Return a list of the children of this node.
virtual std::vector Children() const =0;
/// Return a pointer to the parent class.
virtual Node::Ptr GetParent() const =0;
};
/// NodeList is how we return lists of nodes.
typedef std::vector NodeVector;
typedef std::list NodeList;
}
#endif
xpathselect-1.4+15.10.20150824.1/lib/CMakeLists.txt 0000644 0000153 0000161 00000003233 12566631427 021717 0 ustar pbuser pbgroup 0000000 0000000 FIND_PACKAGE( Boost 1.40 REQUIRED )
INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wl,--no-undefined")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG" )
endif(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(SOURCES node.cpp xpathselect.h xpathselect.cpp parser.cpp parser.h)
set(HEADERS node.h xpathselect.h)
if(CMAKE_COMPILER_IS_GNUCXX)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)
message(STATUS "C++11 activated.")
add_definitions("-std=c++11")
elseif(GCC_VERSION VERSION_GREATER 4.3 OR GCC_VERSION VERSION_EQUAL 4.3)
message(WARNING "C++0x activated. If you get any errors update to a compiler which fully supports C++11")
add_definitions("-std=c++0x")
else ()
message(FATAL_ERROR "C++11 needed. Therefore a gcc compiler with a version higher than 4.3 is needed.")
endif()
else(CMAKE_COMPILER_IS_GNUCXX)
add_definitions("-std=c++11") #turn on and hope non-gnu compiler supports it
endif(CMAKE_COMPILER_IS_GNUCXX)
add_library(xpathselect SHARED ${SOURCES})
target_link_libraries(xpathselect ${Boost_LIBRARIES})
set_target_properties(xpathselect
PROPERTIES
VERSION ${VERSION}
SOVERSION ${VERSION})
install(TARGETS xpathselect
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES ${HEADERS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
configure_file(xpathselect.pc.in
xpathselect.pc
@ONLY)
install(FILES ${CMAKE_BINARY_DIR}/lib/xpathselect.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
xpathselect-1.4+15.10.20150824.1/lib/xpathselect.pc.in 0000644 0000153 0000161 00000000341 12566631427 022431 0 ustar pbuser pbgroup 0000000 0000000 prefix=@CMAKE_INSTALL_PREFIX@
libdir=${prefix}/lib/@CMAKE_LIBRARY_ARCHITECTURE@
includedir=${prefix}/include
Cflags: -I${includedir}
Libs: -lxpathselect
Name: libxpathselect
Description: libxpathselect.
Version: @VERSION@
xpathselect-1.4+15.10.20150824.1/test/ 0000755 0000153 0000161 00000000000 12566631574 017372 5 ustar pbuser pbgroup 0000000 0000000 xpathselect-1.4+15.10.20150824.1/test/test_parser.cpp 0000644 0000153 0000161 00000102736 12566631427 022437 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "gtest/gtest.h"
#include "parser.h"
#include "xpathquerypart.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace parser = xpathselect::parser;
// utility function to test parsers:
template
bool test_parser_attr(std::string input, P const& p, T& attr)
{
using boost::spirit::qi::parse;
std::string::iterator f = input.begin();
std::string::iterator l = input.end();
if (parse(f, l, p, attr) && (f == l))
{
return true;
}
else
{
return false;
}
}
template
bool test_parser_attr(std::string input, P const& p)
{
using boost::spirit::qi::parse;
std::string::iterator f = input.begin();
std::string::iterator l = input.end();
if (parse(f, l, p) && (f == l))
{
return true;
}
else
{
return false;
}
}
// a boost static visitor that checks value equality and type equality.
template
class variant_equality_assertion : public boost::static_visitor<>
{
public:
variant_equality_assertion( T const& expected)
: expected_(expected)
{}
void operator()( T & operand ) const
{
ASSERT_EQ(expected_, operand);
}
template void operator()( U & operand ) const
{
FAIL() << "Variant contained incorrect type! Expected: '"
<< expected_
<< "' Actual: '"
<< operand
<< "' Actual type is: "
<< typeid(U).name();
}
private:
T expected_;
};
//////////////////////////////////////
// Tests for basic type support:
//////////////////////////////////////
// Test python representations for boolean values:
TEST(TestXPathParser, test_basic_type_boolean)
{
bool result = false;
parser::xpath_grammar g;
ASSERT_TRUE(test_parser_attr("True", g.bool_type, result));
ASSERT_TRUE(result);
ASSERT_TRUE(test_parser_attr("False", g.bool_type, result));
ASSERT_FALSE(result);
ASSERT_FALSE(test_parser_attr("true", g.bool_type, result));
ASSERT_FALSE(test_parser_attr("false", g.bool_type, result));
ASSERT_FALSE(test_parser_attr("1", g.bool_type, result));
ASSERT_FALSE(test_parser_attr("0", g.bool_type, result));
}
// test character escape codes:
class TestXPathParserCharacterEscapeCodes : public ::testing::TestWithParam >
{
};
TEST_P(TestXPathParserCharacterEscapeCodes, test_character_escape_codes)
{
auto p = GetParam();
std::string input = p.first;
char expected_result = p.second;
char actual_result = 0;
parser::xpath_grammar g;
ASSERT_TRUE(test_parser_attr(input, g.unesc_char, actual_result));
ASSERT_EQ(expected_result, actual_result);
}
INSTANTIATE_TEST_CASE_P(BasicCharacterCodes,
TestXPathParserCharacterEscapeCodes,
::testing::Values(
std::pair("\\a", '\a'),
std::pair("\\b", '\b'),
std::pair("\\f", '\f'),
std::pair("\\n", '\n'),
std::pair("\\r", '\r'),
std::pair("\\t", '\t'),
std::pair("\\v", '\v'),
std::pair("\\\\", '\\'),
std::pair("\\\'", '\''),
std::pair("\\\"", '\"')
));
class QuotedStringTests : public ::testing::TestWithParam >
{
};
TEST_P(QuotedStringTests, quoted_string_parameter_test)
{
std::string input = std::get<0>(GetParam());
std::string expected_output = std::get<1>(GetParam());
bool expected_pass = std::get<2>(GetParam());
std::string actual_result;
parser::xpath_grammar g;
ASSERT_EQ(expected_pass, test_parser_attr(input, g.unesc_str, actual_result));
if (expected_pass)
ASSERT_EQ(expected_output, actual_result);
}
INSTANTIATE_TEST_CASE_P(BasicStrings,
QuotedStringTests,
::testing::Values(
std::make_tuple("\"Hello\"", "Hello", true),
std::make_tuple("\"Hello World\"", "Hello World", true),
std::make_tuple("\"a b c d\"", "a b c d", true),
std::make_tuple("\"\\x41\"", "A", true),
std::make_tuple("\"\\x08\"", "\b", true)
));
INSTANTIATE_TEST_CASE_P(PunctuationStrings,
QuotedStringTests,
::testing::Values(
std::make_tuple("\".\"", ".", true),
std::make_tuple("\",\"", ",", true),
std::make_tuple("\"<\"", "<", true),
std::make_tuple("\">\"", ">", true),
std::make_tuple("\"/\"", "/", true),
std::make_tuple("\"?\"", "?", true),
std::make_tuple("\":\"", ":", true),
std::make_tuple("\";\"", ";", true),
std::make_tuple("\"'\"", "'", true), // '"' tested below
std::make_tuple("\"[\"", "[", true),
std::make_tuple("\"]\"", "]", true),
std::make_tuple("\"{\"", "{", true),
std::make_tuple("\"}\"", "}", true),
std::make_tuple("\"\\\\\"", "\\", true),
std::make_tuple("\"|\"", "|", true),
std::make_tuple("\"~\"", "~", true),
std::make_tuple("\"`\"", "`", true),
std::make_tuple("\"!\"", "!", true),
std::make_tuple("\"@\"", "@", true),
std::make_tuple("\"#\"", "#", true),
std::make_tuple("\"$\"", "$", true),
std::make_tuple("\"%\"", "%", true),
std::make_tuple("\"^\"", "^", true),
std::make_tuple("\"&\"", "&", true),
std::make_tuple("\"*\"", "*", true),
std::make_tuple("\"(\"", "(", true),
std::make_tuple("\")\"", ")", true),
std::make_tuple("\"-\"", "-", true),
std::make_tuple("\"_\"", "_", true),
std::make_tuple("\"+\"", "+", true),
std::make_tuple("\"=\"", "=", true)
));
INSTANTIATE_TEST_CASE_P(QuoteStrings,
QuotedStringTests,
::testing::Values(
std::make_tuple("\"\\\"\"", "\"", true),
std::make_tuple("\"\\\'\"", "\'", true)
));
INSTANTIATE_TEST_CASE_P(NumberStrings,
QuotedStringTests,
::testing::Values(
std::make_tuple("\"0\"", "0", true),
std::make_tuple("\"1\"", "1", true),
std::make_tuple("\"2\"", "2", true),
std::make_tuple("\"3\"", "3", true),
std::make_tuple("\"4\"", "4", true),
std::make_tuple("\"5\"", "5", true),
std::make_tuple("\"6\"", "6", true),
std::make_tuple("\"7\"", "7", true),
std::make_tuple("\"8\"", "8", true),
std::make_tuple("\"9\"", "9", true)
));
TEST(TestIntegerTypes, test_signed_integers)
{
int result = 0;
parser::xpath_grammar g;
ASSERT_TRUE(test_parser_attr("123", g.int_type, result));
ASSERT_EQ(123, result);
ASSERT_TRUE(test_parser_attr("+456", g.int_type, result));
ASSERT_EQ(456, result);
ASSERT_TRUE(test_parser_attr("-123", g.int_type, result));
ASSERT_EQ(-123, result);
}
// This test fails due to a bug in boost::spirit: https://svn.boost.org/trac/boost/ticket/9007
// TEST(TestIntegerTypes, test_integer_overflow)
// {
// int result;
// // store range of int in a long, since we'll be extending them
// long min_int = std::numeric_limits::min();
// long max_int = std::numeric_limits::max();
// qi::int_parser r;
// ASSERT_TRUE(test_parser_attr(std::to_string(min_int), r, result));
// ASSERT_EQ(min_int, result);
// ASSERT_TRUE(test_parser_attr(std::to_string(max_int), r, result));
// ASSERT_EQ(max_int, result);
// min_int -= 1;
// max_int += 1;
// // these last two assertions are failing. I expect the parsing to fail, but it's passing
// // for some reason.
// ASSERT_FALSE(test_parser_attr(std::to_string(min_int), r, result)) << min_int;
// ASSERT_FALSE(test_parser_attr(std::to_string(max_int), r, result)) << max_int;
// }
////////////////////////////////////
// more complicated grammar tests
////////////////////////////////////
/// Tests for parameter names:
class TestXPathParserParamNames : public ::testing::TestWithParam >
{
};
TEST_P(TestXPathParserParamNames, test_param_name)
{
auto p = GetParam();
std::string input = p.first;
bool expect_pass = p.second;
parser::xpath_grammar g;
std::string result;
ASSERT_EQ( expect_pass, test_parser_attr(input, g.param_name, result) );
if (expect_pass)
ASSERT_EQ(input, result);
}
INSTANTIATE_TEST_CASE_P(BasicNodeNames,
TestXPathParserParamNames,
::testing::Values(
std::pair("a b", false),
std::pair("a*", false),
std::pair("HelloWorld", true),
std::pair("H", true),
std::pair("h", true),
std::pair("1", true),
std::pair("node-name", true),
std::pair("node_name", true),
std::pair("node\\name", true),
std::pair("node::name", false),
std::pair("node.name", false),
std::pair("node name", false),
std::pair("..", false)
));
/// Tests for parameter values. This test is much larger than it should be, since it seems to be
// impossible to parameterise tests for both type and value. The solution I use here is to have
// the actual test in a base class template method, and have several derive classes use different
// value parameters. Ugly, but probably the best we can do with google test.
class TestParamValues : public ::testing::Test
{
public:
template
void test_param_value(PairType const& input_pair) const
{
RecordProperty("FirstType", typeid(typename PairType::first_type).name());
RecordProperty("SecondType", typeid(typename PairType::second_type).name());
std::string input = input_pair.first;
typename PairType::second_type expected_result = input_pair.second;
parser::xpath_grammar g;
xpathselect::XPathQueryParam::ParamValueType result;
ASSERT_TRUE( test_parser_attr(input, g.param_value, result) );
boost::apply_visitor(
variant_equality_assertion(expected_result),
result
);
}
};
// test string parameter values:
class TestStringParamValues
: public ::testing::WithParamInterface >
, public TestParamValues
{
};
TEST_P(TestStringParamValues, test_param_value_str)
{
auto p = GetParam();
test_param_value(p);
}
INSTANTIATE_TEST_CASE_P(StringParams,
TestStringParamValues,
::testing::Values(
std::pair("\"a b\"", "a b" ),
std::pair("\"a.b,c/\\d^\"", "a.b,c/\\d^" )
));
// test boolean parameter values:
class TestBoolParamValues
: public ::testing::WithParamInterface >
, public TestParamValues
{
};
TEST_P(TestBoolParamValues, test_param_value_bool)
{
auto p = GetParam();
test_param_value(p);
}
INSTANTIATE_TEST_CASE_P(StringParams,
TestBoolParamValues,
::testing::Values(
std::pair("True", true ),
std::pair("False", false )
));
// test integer parameter values:
class TestIntParamValues
: public ::testing::WithParamInterface >
, public TestParamValues
{
};
TEST_P(TestIntParamValues, test_param_value_bool)
{
auto p = GetParam();
test_param_value(p);
}
INSTANTIATE_TEST_CASE_P(IntegerParams,
TestIntParamValues,
::testing::Values(
std::pair("123", 123 ),
std::pair("0", 0 ),
std::pair("-123", -123 )
));
/// Tests for the node names:
class TestXPathParserNodeNames : public ::testing::TestWithParam >
{
};
TEST_P(TestXPathParserNodeNames, test_spec_node_name)
{
auto p = GetParam();
std::string input = p.first;
bool expect_pass = p.second;
parser::xpath_grammar g;
std::string result;
ASSERT_EQ( expect_pass, test_parser_attr(input, g.spec_node_name, result) );
if (expect_pass)
ASSERT_EQ(input, result);
}
INSTANTIATE_TEST_CASE_P(BasicNodeNames,
TestXPathParserNodeNames,
::testing::Values(
std::pair("a b", true),
std::pair("a ", false),
std::pair(" ", false),
std::pair(" b", false),
std::pair("a b", true),
std::pair("a b b a", true),
std::pair("a*", false),
std::pair("HelloWorld", true),
std::pair("H", true),
std::pair("h", true),
std::pair("1", true),
std::pair("node-name", true),
std::pair("node_name", true),
std::pair("node\\name", true),
std::pair("node::name", true),
std::pair("node::name::extra", true)
));
class TestXPathParserWildcardNodeName : public ::testing::TestWithParam >
{
};
TEST_P(TestXPathParserWildcardNodeName, test_wildcard_node_name_rejects_everything_else)
{
auto p = GetParam();
std::string input = p.first;
bool expect_pass = p.second;
parser::xpath_grammar g;
std::string result;
ASSERT_EQ( expect_pass, test_parser_attr(input, g.wildcard_node_name, result) );
if (expect_pass)
ASSERT_EQ(input, result);
}
INSTANTIATE_TEST_CASE_P(BasicNodeNames,
TestXPathParserWildcardNodeName,
::testing::Values(
std::pair("", false),
std::pair("* ", false),
std::pair("**", false),
std::pair(" ", false),
std::pair("8", false),
std::pair("\t", false),
std::pair("node-name", false),
std::pair("node_name", false),
std::pair("*", true)
));
TEST(TestXPathParser, test_param_parser_string_value_works)
{
std::string input("name=\"value\"");
parser::xpath_grammar g;
xpathselect::XPathQueryParam result;
ASSERT_EQ( true, test_parser_attr(input, g.param, result) );
ASSERT_EQ("name", result.param_name);
boost::apply_visitor(
variant_equality_assertion("value"),
result.param_value
);
}
TEST(TestXPathParser, test_param_parser_bool_value_works)
{
std::string input("name=True");
parser::xpath_grammar g;
xpathselect::XPathQueryParam result;
ASSERT_EQ( true, test_parser_attr(input, g.param, result) );
ASSERT_EQ("name", result.param_name);
boost::apply_visitor(
variant_equality_assertion(true),
result.param_value
);
}
TEST(TestXPathParser, test_param_parser_string_int_works)
{
std::string input("name=123456");
parser::xpath_grammar g;
xpathselect::XPathQueryParam result;
ASSERT_EQ( true, test_parser_attr(input, g.param, result) );
ASSERT_EQ("name", result.param_name);
boost::apply_visitor(
variant_equality_assertion(123456),
result.param_value
);
}
TEST(TestXPathParser, test_param_parser_fails)
{
std::string input("name=");
parser::xpath_grammar g;
xpathselect::XPathQueryParam result;
ASSERT_FALSE( test_parser_attr(input, g.param, result) );
}
TEST(TestXPathParser, test_param_list_single_value)
{
std::string input("[name=123]");
parser::xpath_grammar g;
xpathselect::ParamList result;
ASSERT_EQ( true, test_parser_attr(input, g.param_list, result) );
ASSERT_EQ(1, result.size());
ASSERT_EQ("name", result.at(0).param_name);
boost::apply_visitor(
variant_equality_assertion(123),
result.at(0).param_value
);
}
TEST(TestXPathParser, test_param_list_two_values)
{
std::string input("[name=\"value\",visible=True]");
parser::xpath_grammar g;
xpathselect::ParamList result;
ASSERT_EQ( true, test_parser_attr(input, g.param_list, result) );
ASSERT_EQ(2, result.size());
ASSERT_EQ("name", result.at(0).param_name);
boost::apply_visitor(
variant_equality_assertion("value"),
result.at(0).param_value
);
ASSERT_EQ("visible", result.at(1).param_name);
boost::apply_visitor(
variant_equality_assertion(true),
result.at(1).param_value
);
}
TEST(TestXPathParser, test_spec_node_with_parameter)
{
std::string input("node_name[param_name=123]");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_EQ( true, test_parser_attr(input, g.spec_node, result) );
ASSERT_EQ("node_name", result.node_name_);
ASSERT_FALSE(result.parameter.empty());
ASSERT_EQ("param_name", result.parameter.at(0).param_name);
boost::apply_visitor(
variant_equality_assertion(123),
result.parameter.at(0).param_value
);
}
TEST(TestXPathParser, test_spec_node_without_parameter)
{
std::string input("node_name");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_EQ( true, test_parser_attr(input, g.spec_node, result) );
ASSERT_EQ("node_name", result.node_name_);
ASSERT_TRUE(result.parameter.empty());
}
TEST(TestXPathParser, test_wildcard_node)
{
std::string input("*");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_EQ( true, test_parser_attr(input, g.wildcard_node, result) );
ASSERT_EQ("*", result.node_name_);
ASSERT_TRUE(result.parameter.empty());
}
TEST(TestXPathParser, test_wildcard_node_rejects_parameters)
{
std::string input("*[foo=bar]");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_FALSE( test_parser_attr(input, g.wildcard_node, result) );
}
TEST(TestXPathParser, test_wildcard_node_with_params)
{
std::string input("*[param_name=123]");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_EQ( true, test_parser_attr(input, g.wildcard_node_with_params, result) );
ASSERT_EQ("*", result.node_name_);
ASSERT_FALSE(result.parameter.empty());
ASSERT_EQ("param_name", result.parameter.at(0).param_name);
boost::apply_visitor(
variant_equality_assertion(123),
result.parameter.at(0).param_value
);
}
TEST(TestXPathParser, test_node_can_be_a_wildcard_node_with_params)
{
std::string input("*[name=\"value\"]");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_EQ( true, test_parser_attr(input, g.node, result) );
ASSERT_EQ( "*", result.node_name_ );
ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() );
ASSERT_EQ( 1, result.parameter.size() );
ASSERT_EQ( "name", result.parameter.at(0).param_name );
boost::apply_visitor(
variant_equality_assertion("value"),
result.parameter.at(0).param_value
);
}
TEST(TestXPathParser, test_node_can_be_a_wildcard_node_without_params)
{
std::string input("*");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_EQ( true, test_parser_attr(input, g.node, result) );
ASSERT_EQ( "*", result.node_name_ );
ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() );
}
TEST(TestXPathParser, test_node_can_be_a_spec_node_with_params)
{
std::string input("foo[name=\"value\"]");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_EQ( true, test_parser_attr(input, g.node, result) );
ASSERT_EQ( "foo", result.node_name_ );
ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() );
ASSERT_EQ( 1, result.parameter.size() );
ASSERT_EQ( "name", result.parameter.at(0).param_name );
boost::apply_visitor(
variant_equality_assertion("value"),
result.parameter.at(0).param_value
);
}
TEST(TestXPathParser, test_node_can_be_a_spec_node_without_params)
{
std::string input("foo");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_EQ( true, test_parser_attr(input, g.node, result) );
ASSERT_EQ( "foo", result.node_name_ );
ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Normal, result.Type() );
}
TEST(TestXPathParser, test_node_can_be_a_parent_node)
{
std::string input("..");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_EQ( true, test_parser_attr(input, g.node, result) );
ASSERT_EQ( "..", result.node_name_ );
ASSERT_EQ( xpathselect::XPathQueryPart::QueryPartType::Parent, result.Type() );
}
TEST(TestXPathParser, test_search_node_followed_by_normal_node)
{
// the search_node grammar fails if it's at the end of the line, so we need
// to give it some more data, even though we're not actually matching it.
std::string input("//node_name");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
// however, this means we can't use the test_parser_attr function, since it
// returns false on a partial match. Use the parse(...) function directly:
ASSERT_TRUE( parse(input.begin(), input.end(),g.search_node, result) );
ASSERT_TRUE( result.Type() == xpathselect::XPathQueryPart::QueryPartType::Search );
}
TEST(TestXPathParser, test_search_node_followed_by_wildcard_node_with_parameters)
{
// the search_node grammar fails if it's at the end of the line, so we need
// to give it some more data, even though we're not actually matching it.
std::string input("//*[foo=\"bar\"]");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
// however, this means we can't use the test_parser_attr function, since it
// returns false on a partial match. Use the parse(...) function directly:
ASSERT_TRUE( parse(input.begin(), input.end(),g.search_node, result) );
ASSERT_TRUE( result.Type() == xpathselect::XPathQueryPart::QueryPartType::Search );
}
TEST(TestXPathParser, test_search_node_cannot_have_parameters)
{
std::string input("//[param_name=value]");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_FALSE( test_parser_attr(input, g.search_node, result) );
}
TEST(TestXPathParser, test_parent_node)
{
std::string input("..");
parser::xpath_grammar g;
xpathselect::XPathQueryPart result;
ASSERT_TRUE( test_parser_attr(input, g.parent_node, result) );
ASSERT_TRUE( result.Type() == xpathselect::XPathQueryPart::QueryPartType::Parent );
}
TEST(TestXPathParser, test_normal_sep_works)
{
std::string input("/");
parser::xpath_grammar g;
ASSERT_EQ( true, test_parser_attr(input, g.normal_sep) );
}
TEST(TestXPathParser, test_normal_sep_does_not_match_search_node)
{
std::string input("//");
parser::xpath_grammar g;
ASSERT_FALSE( test_parser_attr(input, g.normal_sep) );
}
TEST(TestXPathParser, test_can_extract_query_list)
{
std::string input("/node1/node2");
parser::xpath_grammar g;
xpathselect::QueryList result;
ASSERT_TRUE(test_parser_attr(input, g.node_sequence, result));
ASSERT_EQ(2, result.size());
ASSERT_EQ("node1", result.at(0).node_name_);
ASSERT_TRUE(result.at(0).parameter.empty());
ASSERT_EQ("node2", result.at(1).node_name_);
ASSERT_TRUE(result.at(1).parameter.empty());
}
TEST(TestXPathParser, test_can_extract_query_list_with_search)
{
std::string input("//node1");
parser::xpath_grammar g;
xpathselect::QueryList result;
ASSERT_TRUE(test_parser_attr(input, g.node_sequence, result));
ASSERT_EQ(2, result.size());
ASSERT_TRUE(result.at(0).Type() == xpathselect::XPathQueryPart::QueryPartType::Search );
ASSERT_TRUE(result.at(1).Type() == xpathselect::XPathQueryPart::QueryPartType::Normal );
ASSERT_TRUE(result.at(0).parameter.empty());
ASSERT_EQ("node1", result.at(1).node_name_);
ASSERT_TRUE(result.at(1).parameter.empty());
}
TEST(TestXPathParser, test_mix_search_and_normal)
{
std::string input("/node1//node2");
parser::xpath_grammar g;
xpathselect::QueryList result;
ASSERT_TRUE(test_parser_attr(input, g.node_sequence, result));
ASSERT_EQ(3, result.size());
ASSERT_EQ("node1", result.at(0).node_name_);
ASSERT_TRUE(result.at(0).Type() == xpathselect::XPathQueryPart::QueryPartType::Normal );
ASSERT_TRUE(result.at(0).parameter.empty());
ASSERT_TRUE(result.at(1).Type() == xpathselect::XPathQueryPart::QueryPartType::Search );
ASSERT_TRUE(result.at(1).parameter.empty());
ASSERT_EQ("node2", result.at(2).node_name_);
ASSERT_TRUE(result.at(2).Type() == xpathselect::XPathQueryPart::QueryPartType::Normal );
ASSERT_TRUE(result.at(2).parameter.empty());
}
TEST(TestXPathParser, test_mix_search_and_long_normal)
{
std::string input("/node1//node2[name=\"val\"]/node3");
parser::xpath_grammar g;
xpathselect::QueryList result;
ASSERT_TRUE(test_parser_attr(input, g.node_sequence, result));
ASSERT_EQ(4, result.size());
ASSERT_EQ("node1", result.at(0).node_name_);
ASSERT_TRUE(result.at(0).parameter.empty());
ASSERT_TRUE(result.at(1).Type() == xpathselect::XPathQueryPart::QueryPartType::Search );
ASSERT_TRUE(result.at(1).parameter.empty());
ASSERT_EQ("node2", result.at(2).node_name_);
ASSERT_EQ(1, result.at(2).parameter.size());
ASSERT_EQ("name", result.at(2).parameter.at(0).param_name);
boost::apply_visitor(
variant_equality_assertion("val"),
result.at(2).parameter.at(0).param_value
);
ASSERT_EQ("node3", result.at(3).node_name_);
ASSERT_TRUE(result.at(3).parameter.empty());
}
TEST(TestXPathParser, test_mix_normal_and_parent)
{
std::string input("/node1/..");
parser::xpath_grammar g;
xpathselect::QueryList result;
ASSERT_TRUE(test_parser_attr(input, g.node_sequence, result));
ASSERT_EQ(2, result.size());
ASSERT_EQ("node1", result.at(0).node_name_);
ASSERT_TRUE(result.at(0).parameter.empty());
ASSERT_TRUE(result.at(1).Type() == xpathselect::XPathQueryPart::QueryPartType::Parent );
ASSERT_TRUE(result.at(1).parameter.empty());
}
TEST(TestXPathParser, test_mix_normal_and_parent_and_wildcard)
{
std::string input("/node1/../*");
parser::xpath_grammar g;
xpathselect::QueryList result;
ASSERT_TRUE(test_parser_attr(input, g.node_sequence, result));
ASSERT_EQ(3, result.size());
ASSERT_EQ("node1", result.at(0).node_name_);
ASSERT_TRUE(result.at(0).parameter.empty());
ASSERT_TRUE(result.at(1).Type() == xpathselect::XPathQueryPart::QueryPartType::Parent );
ASSERT_TRUE(result.at(1).parameter.empty());
ASSERT_TRUE(result.at(2).node_name_ == "*" );
ASSERT_TRUE(result.at(2).parameter.empty());
}
class TestXPathParserQueryStrings : public ::testing::TestWithParam >
{};
TEST_P(TestXPathParserQueryStrings, test_query_acceptance)
{
auto p = GetParam();
std::string input = p.first;
bool expect_pass = p.second;
parser::xpath_grammar g;
xpathselect::QueryList result;
ASSERT_EQ( expect_pass, test_parser_attr(input, g, result) );
}
INSTANTIATE_TEST_CASE_P(BasicNodeNames,
TestXPathParserQueryStrings,
::testing::Values(
// queries that must all parse correctly:
std::pair("//root", true),
std::pair("/root", true),
std::pair("/root/node1", true),
std::pair("/root//node1", true),
std::pair("//root", true),
std::pair("/root//node1/node2", true),
std::pair("/root[p=1]//node1[p=\"2\"]/node3", true),
std::pair("/root[p=True,n=2,d=\"e3\"]", true),
std::pair("//root[p=1,n=2,d=\"e3\"]", true),
std::pair("/Root//*[p=1]", true),
std::pair("/Root//*[p=1,v=\"sj\",c=False]", true),
// queries that must not parse correctly:
std::pair("//", false),
std::pair("/root//", false),
std::pair("/root///", false),
std::pair("/ /", false),
std::pair("", false),
std::pair(" ", false),
std::pair("//*", false),
std::pair("/Root///Leaf", false),
std::pair("/Root////", false),
std::pair("/Root/..*", false),
std::pair("/Root/../Child//..", false)
));
xpathselect-1.4+15.10.20150824.1/test/test_xpath_tree.cpp 0000644 0000153 0000161 00000014711 12566631427 023301 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "gtest/gtest.h"
#include "xpathselect.h"
#include "node.h"
#include "dummynode.h"
#include
class TestTreeFixture: public ::testing::Test
{
public:
void SetUp() override
{
root_ = std::make_shared("Root");
child_l1_ = std::make_shared("ChildLeft1");
child_r1_ = std::make_shared("ChildRight1");
leaf_1_ = std::make_shared("Leaf");
leaf_2_ = std::make_shared("Leaf");
root_->AddChild(child_l1_);
root_->AddChild(child_r1_);
child_l1_->AddChild(leaf_1_);
child_l1_->AddChild(leaf_2_);
}
typedef std::shared_ptr NodePtr;
NodePtr root_;
NodePtr child_l1_;
NodePtr child_r1_;
NodePtr leaf_1_;
NodePtr leaf_2_;
};
TEST_F(TestTreeFixture, test_simple)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/");
ASSERT_EQ(1, result.size());
}
TEST_F(TestTreeFixture, test_simple_absolute)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1");
ASSERT_EQ(1, result.size());
auto expected = child_l1_;
auto actual = result.front();
ASSERT_EQ(expected, actual);
}
TEST_F(TestTreeFixture, test_simple_relative)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//ChildRight1");
ASSERT_EQ(1, result.size());
ASSERT_EQ(child_r1_, result.front());
}
TEST_F(TestTreeFixture, test_complex_relative)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//Root/ChildRight1");
ASSERT_EQ(1, result.size());
ASSERT_EQ(child_r1_, result.front());
}
TEST_F(TestTreeFixture, test_relative_multiple_return)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//Leaf");
ASSERT_EQ(2, result.size());
for(xpathselect::Node::Ptr n : result)
{
ASSERT_TRUE(n == leaf_1_ || n == leaf_2_ );
}
}
TEST_F(TestTreeFixture, test_relative_wildcard)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//ChildLeft1/*");
ASSERT_EQ(2, result.size());
for(xpathselect::Node::Ptr n : result)
{
ASSERT_TRUE(n == leaf_1_ || n == leaf_2_ );
}
}
TEST_F(TestTreeFixture, test_absolute_wildcard)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/*");
ASSERT_EQ(2, result.size());
for(xpathselect::Node::Ptr n : result)
{
ASSERT_TRUE(n == leaf_1_ || n == leaf_2_ );
}
}
TEST_F(TestTreeFixture, test_simple_absolute_property_match)
{
child_l1_->AddProperty("visible", "True");
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1[visible=True]");
ASSERT_EQ(1, result.size());
ASSERT_EQ(child_l1_, result.front());
}
TEST_F(TestTreeFixture, test_simple_relative_property_match)
{
child_l1_->AddProperty("visible", true);
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "//ChildLeft1[visible=True]");
ASSERT_EQ(1, result.size());
ASSERT_EQ(child_l1_, result.front());
}
TEST_F(TestTreeFixture, test_absolute_multiple_property_match)
{
root_->AddProperty("number", 45);
child_l1_->AddProperty("visible", true);
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root[number=45]/ChildLeft1[visible=True]");
ASSERT_EQ(1, result.size());
ASSERT_EQ(child_l1_, result.front());
}
TEST_F(TestTreeFixture, test_mixed_query_simple)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root//Leaf");
ASSERT_EQ(2, result.size());
for(auto n : result)
{
ASSERT_TRUE(n == leaf_1_ || n == leaf_2_ );
}
}
TEST_F(TestTreeFixture, test_mixed_query_property_match)
{
leaf_1_->AddProperty("visible", true);
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root//Leaf[visible=True]");
ASSERT_EQ(1, result.size());
ASSERT_EQ(leaf_1_, result.front());
}
TEST_F(TestTreeFixture, test_search_node_with_wildcard_and_property)
{
child_l1_->AddProperty("visible", true);
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root//*[visible=True]");
ASSERT_EQ(1, result.size());
ASSERT_EQ(child_l1_, result.front());
}
TEST_F(TestTreeFixture, test_wildcard)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/*");
ASSERT_EQ(2, result.size());
for(auto n : result)
{
ASSERT_TRUE(n == child_l1_ || n == child_r1_ );
}
}
TEST_F(TestTreeFixture, test_parent)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/..");
ASSERT_EQ(1, result.size());
ASSERT_EQ(root_, result.front());
}
TEST_F(TestTreeFixture, test_parent_on_root)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/..");
ASSERT_EQ(1, result.size());
ASSERT_EQ(root_, result.front());
}
TEST_F(TestTreeFixture, test_parent_on_leaf)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/Leaf/..");
ASSERT_EQ(1, result.size());
ASSERT_EQ(child_l1_, result.front());
}
TEST_F(TestTreeFixture, test_double_parent_on_leaf)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/Leaf/../..");
ASSERT_EQ(1, result.size());
ASSERT_EQ(root_, result.front());
}
TEST_F(TestTreeFixture, test_parent_and_child)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root/ChildLeft1/../ChildLeft1/../ChildLeft1");
ASSERT_EQ(1, result.size());
ASSERT_EQ(child_l1_, result.front());
}
TEST_F(TestTreeFixture, test_invalid_query_search)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root///Leaf");
ASSERT_EQ(0, result.size());
}
TEST_F(TestTreeFixture, test_invalid_query_multiple_searches)
{
xpathselect::NodeVector result = xpathselect::SelectNodes(root_, "/Root////");
ASSERT_EQ(0, result.size());
}
xpathselect-1.4+15.10.20150824.1/test/test_main.cpp 0000644 0000153 0000161 00000001352 12566631427 022057 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "gtest/gtest.h"
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
xpathselect-1.4+15.10.20150824.1/test/test_xpath_simple.cpp 0000644 0000153 0000161 00000004534 12566631427 023635 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "gtest/gtest.h"
#include "node.h"
#include "xpathselect.h"
#include "dummynode.h"
// empty query must select tree root.
TEST(TestXPath, test_select_empty_tree)
{
xpathselect::Node::Ptr tree_root = std::make_shared();
xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "");
ASSERT_EQ(1, result.size());
}
// test explicitly selecting tree root without node name
TEST(TestXPath, test_select_tree_root)
{
xpathselect::Node::Ptr tree_root = std::make_shared("RootNode");
xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "/");
ASSERT_EQ(result.size(), 1);
ASSERT_EQ(result.front(), tree_root);
}
// test explicitly selecting tree root without node name
TEST(TestXPath, test_select_tree_root_with_name)
{
xpathselect::Node::Ptr tree_root = std::make_shared("RootNode");
xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "/RootNode");
ASSERT_EQ(result.size(), 1);
ASSERT_EQ(result.front(), tree_root);
}
// test explicitly selecting tree root with relative query
TEST(TestXPath, test_select_tree_root_with_relative_query)
{
xpathselect::Node::Ptr tree_root = std::make_shared("RootNode");
xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "//RootNode");
ASSERT_EQ(result.size(), 1);
ASSERT_EQ(result.front(), tree_root);
}
// test explicitly selecting tree root with relative query
TEST(TestXPath, test_select_tree_root_with_empty_relative_query)
{
xpathselect::Node::Ptr tree_root = std::make_shared("RootNode");
xpathselect::NodeVector result = xpathselect::SelectNodes(tree_root, "//");
ASSERT_EQ(result.size(), 1);
ASSERT_EQ(result.front(), tree_root);
}
xpathselect-1.4+15.10.20150824.1/test/CMakeLists.txt 0000644 0000153 0000161 00000003507 12566631427 022134 0 ustar pbuser pbgroup 0000000 0000000
include_directories(../lib)
find_path(GTEST_SRC_DIR gtest.cc PATHS /usr/src/gtest/src)
set(CMAKE_CXX_FLAGS "-ggdb -O0 -Wall")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG" )
endif(CMAKE_BUILD_TYPE STREQUAL "Debug")
# Detect if C++11 support is available, and attempt fallback to C++0x support
if(CMAKE_COMPILER_IS_GNUCXX)
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7)
message(STATUS "C++11 activated.")
add_definitions("-std=c++11")
#run all tests
set(SOURCES test_main.cpp test_xpath_simple.cpp test_xpath_tree.cpp dummynode.h test_parser.cpp)
add_executable(test-runner ${SOURCES})
add_dependencies (test-runner gtest)
add_dependencies (test-runner ../lib)
target_link_libraries(test-runner gtest xpathselect)
elseif(GCC_VERSION VERSION_GREATER 4.3 OR GCC_VERSION VERSION_EQUAL 4.3)
message(WARNING "C++0x activated. Tests have been disabled")
add_definitions("-std=c++0x")
else ()
message(FATAL_ERROR "C++11 needed. Therefore a gcc compiler with a version higher than 4.3 is needed.")
endif()
else(CMAKE_COMPILER_IS_GNUCXX)
add_definitions("-std=c++11") #turn on and hope non-gnu compiler supports it
endif(CMAKE_COMPILER_IS_GNUCXX)
# Check for google test and build it locally
set(
GTEST_ROOT_DIR
"/usr/src/gtest" # Default value, adjustable by user with e.g., ccmake
CACHE
PATH
"Path to Google test srcs"
)
find_path(GTEST_INCLUDE_DIR gtest/gtest.h)
if (GTEST_INCLUDE_DIR)
#FIXME - hardcoded is bad!
add_subdirectory(
${GTEST_ROOT_DIR}
gtest
)
endif(GTEST_INCLUDE_DIR)
enable_testing()
add_test(TestSuite test-runner)
add_custom_target (test COMMAND ./test-runner)
xpathselect-1.4+15.10.20150824.1/test/dummynode.h 0000644 0000153 0000161 00000005770 12566631427 021552 0 ustar pbuser pbgroup 0000000 0000000 /*
* Copyright (C) 2012 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef _DUMMYNODE_H
#define _DUMMYNODE_H
#include "node.h"
#include