summaryrefslogtreecommitdiff
path: root/qpid/cpp/src/tests/Selector.cpp
diff options
context:
space:
mode:
authorAndrew Stitcher <astitcher@apache.org>2013-03-04 21:08:28 +0000
committerAndrew Stitcher <astitcher@apache.org>2013-03-04 21:08:28 +0000
commit7ac7cac4d371ff8498a5fd46b74278a6aa395c73 (patch)
treee635426966b31b2add1f8dc1f4d7f3dc70401983 /qpid/cpp/src/tests/Selector.cpp
parent5aa4b2dc7e531c12597323c2ca73ade8fa72793a (diff)
downloadqpid-python-7ac7cac4d371ff8498a5fd46b74278a6aa395c73.tar.gz
QPID-4558: Selectors for C++ broker
- Initial Selectors implemented: * Only string values supported (no numerics or bools) - Parses and executes the forms: * A=B * A<>B * I IS NULL * I IS NOT NULL - where A, B are strings or identifiers - I is an identifier * Conditional expressions can include the AND, OR and NOT operators and use parentheses. - Only limited special identifiers return useful values (although they are all recognised) - Unit tests for selector language git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1452523 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/cpp/src/tests/Selector.cpp')
-rw-r--r--qpid/cpp/src/tests/Selector.cpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/qpid/cpp/src/tests/Selector.cpp b/qpid/cpp/src/tests/Selector.cpp
new file mode 100644
index 0000000000..25080f3482
--- /dev/null
+++ b/qpid/cpp/src/tests/Selector.cpp
@@ -0,0 +1,220 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/broker/SelectorToken.h"
+#include "qpid/broker/Selector.h"
+
+#include "unit_test.h"
+
+#include <string>
+#include <map>
+
+using std::string;
+using std::map;
+
+namespace qb = qpid::broker;
+
+using qpid::broker::Token;
+using qpid::broker::TokenType;
+using qpid::broker::Tokeniser;
+using qpid::broker::tokeniseEos;
+using qpid::broker::tokeniseIdentifier;
+using qpid::broker::tokeniseIdentifierOrReservedWord;
+using qpid::broker::tokeniseReservedWord;
+using qpid::broker::tokeniseOperator;
+using qpid::broker::tokeniseParens;
+using qpid::broker::tokeniseNumeric;
+using qpid::broker::tokeniseString;
+
+namespace qpid {
+namespace tests {
+
+QPID_AUTO_TEST_SUITE(SelectorSuite)
+
+typedef bool (*TokeniseF)(string::const_iterator&,string::const_iterator&,Token&);
+
+void verifyTokeniserSuccess(TokeniseF t, const char* ss, TokenType tt, const char* tv, const char* fs) {
+ Token tok;
+ string s(ss);
+ string::const_iterator sb = s.begin();
+ string::const_iterator se = s.end();
+ BOOST_CHECK(t(sb, se, tok));
+ BOOST_CHECK_EQUAL(tok, Token(tt, tv));
+ BOOST_CHECK_EQUAL(string(sb, se), fs);
+}
+
+void verifyTokeniserFail(TokeniseF t, const char* c) {
+ Token tok;
+ string s(c);
+ string::const_iterator sb = s.begin();
+ string::const_iterator se = s.end();
+ BOOST_CHECK(!t(sb, se, tok));
+ BOOST_CHECK_EQUAL(string(sb, se), c);
+}
+
+QPID_AUTO_TEST_CASE(tokeniseSuccess)
+{
+ verifyTokeniserSuccess(&tokeniseEos, "", qb::T_EOS, "", "");
+ verifyTokeniserSuccess(&tokeniseIdentifier, "null_123+blah", qb::T_IDENTIFIER, "null_123", "+blah");
+ verifyTokeniserSuccess(&tokeniseIdentifierOrReservedWord, "null_123+blah", qb::T_IDENTIFIER, "null_123", "+blah");
+ verifyTokeniserSuccess(&tokeniseIdentifierOrReservedWord, "null+blah", qb::T_NULL, "null", "+blah");
+ verifyTokeniserSuccess(&tokeniseIdentifierOrReservedWord, "null+blah", qb::T_NULL, "null", "+blah");
+ verifyTokeniserSuccess(&tokeniseIdentifierOrReservedWord, "Is nOt null", qb::T_IS, "Is", " nOt null");
+ verifyTokeniserSuccess(&tokeniseIdentifierOrReservedWord, "nOt null", qb::T_NOT, "nOt", " null");
+ verifyTokeniserSuccess(&tokeniseIdentifierOrReservedWord, "Is nOt null", qb::T_IS, "Is", " nOt null");
+ verifyTokeniserSuccess(&tokeniseString, "'Hello World'", qb::T_STRING, "Hello World", "");
+ verifyTokeniserSuccess(&tokeniseString, "'Hello World''s end'a bit more", qb::T_STRING, "Hello World's end", "a bit more");
+ verifyTokeniserSuccess(&tokeniseOperator, "=blah", qb::T_OPERATOR, "=", "blah");
+ verifyTokeniserSuccess(&tokeniseOperator, "<> Identifier", qb::T_OPERATOR, "<>", " Identifier");
+ verifyTokeniserSuccess(&tokeniseParens, "(a and b) not c", qb::T_LPAREN, "(", "a and b) not c");
+ verifyTokeniserSuccess(&tokeniseParens, ") not c", qb::T_RPAREN, ")", " not c");
+}
+
+QPID_AUTO_TEST_CASE(tokeniseFailure)
+{
+ verifyTokeniserFail(&tokeniseEos, "hb23");
+ verifyTokeniserFail(&tokeniseIdentifier, "123");
+ verifyTokeniserFail(&tokeniseIdentifier, "'Embedded 123'");
+ verifyTokeniserFail(&tokeniseReservedWord, "1.2e5");
+ verifyTokeniserFail(&tokeniseReservedWord, "'Stringy thing'");
+ verifyTokeniserFail(&tokeniseReservedWord, "oR_andsomething");
+ verifyTokeniserFail(&tokeniseString, "'Embedded 123");
+ verifyTokeniserFail(&tokeniseString, "'This isn''t fair");
+ verifyTokeniserFail(&tokeniseOperator, "123");
+ verifyTokeniserFail(&tokeniseOperator, "'Stringy thing'");
+ verifyTokeniserFail(&tokeniseOperator, "NoT");
+ verifyTokeniserFail(&tokeniseOperator, "(a and b)");
+ verifyTokeniserFail(&tokeniseOperator, ")");
+ verifyTokeniserFail(&tokeniseParens, "=");
+ verifyTokeniserFail(&tokeniseParens, "what ho!");
+}
+
+QPID_AUTO_TEST_CASE(tokenString)
+{
+
+ string exp(" a =b");
+ string::const_iterator s = exp.begin();
+ string::const_iterator e = exp.end();
+ Tokeniser t(s, e);
+
+ BOOST_CHECK_EQUAL(t.nextToken(), Token(qb::T_IDENTIFIER, "a"));
+ BOOST_CHECK_EQUAL(t.nextToken(), Token(qb::T_OPERATOR, "="));
+ BOOST_CHECK_EQUAL(t.nextToken(), Token(qb::T_IDENTIFIER, "b"));
+ BOOST_CHECK_EQUAL(t.nextToken(), Token(qb::T_EOS, ""));
+
+ exp = " not 'hello kitty''s friend' = Is null ";
+ s = exp.begin();
+ e = exp.end();
+ Tokeniser u(s, e);
+
+ BOOST_CHECK_EQUAL(u.nextToken(), Token(qb::T_NOT, "not"));
+ BOOST_CHECK_EQUAL(u.nextToken(), Token(qb::T_STRING, "hello kitty's friend"));
+ BOOST_CHECK_EQUAL(u.nextToken(), Token(qb::T_OPERATOR, "="));
+ BOOST_CHECK_EQUAL(u.nextToken(), Token(qb::T_IS, "Is"));
+ BOOST_CHECK_EQUAL(u.nextToken(), Token(qb::T_NULL, "null"));
+ BOOST_CHECK_EQUAL(u.nextToken(), Token(qb::T_EOS, ""));
+ BOOST_CHECK_EQUAL(u.nextToken(), Token(qb::T_EOS, ""));
+
+ u.returnTokens(3);
+ BOOST_CHECK_EQUAL(u.nextToken(), Token(qb::T_IS, "Is"));
+ BOOST_CHECK_EQUAL(u.nextToken(), Token(qb::T_NULL, "null"));
+ BOOST_CHECK_EQUAL(u.nextToken(), Token(qb::T_EOS, ""));
+ BOOST_CHECK_EQUAL(u.nextToken(), Token(qb::T_EOS, ""));
+}
+
+QPID_AUTO_TEST_CASE(parseStringFail)
+{
+ BOOST_CHECK_THROW(qb::Selector e("'Daft' is not null"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A is null not"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A is null or not"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A is null or and"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A is null and 'hello out there'"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("A is null and (B='hello out there'"), std::range_error);
+ BOOST_CHECK_THROW(qb::Selector e("in='hello kitty'"), std::range_error);
+}
+
+class TestSelectorEnv : public qpid::broker::SelectorEnv {
+ map<string, string> values;
+
+ bool present(const std::string& v) const {
+ return values.find(v)!=values.end();
+ }
+
+ std::string value(const std::string& v) const {
+ return present(v) ? values.at(v) : "";
+ }
+
+public:
+ void set(const string& id, const string& value) {
+ values[id] = value;
+ }
+};
+
+QPID_AUTO_TEST_CASE(parseString)
+{
+ qb::Selector a("A is not null");
+ qb::Selector a1("A is null");
+ qb::Selector a2("A = C");
+ qb::Selector a3("A <> C");
+ qb::Selector c("C is not null");
+ qb::Selector c1("C is null");
+ qb::Selector d("A='hello kitty'");
+ qb::Selector e("A<>'hello kitty'");
+ qb::Selector f("A=B");
+ qb::Selector g("A<>B");
+ qb::Selector h("A='hello kitty' OR B='Bye, bye cruel world'");
+ qb::Selector i("B='hello kitty' OR A='Bye, bye cruel world'");
+ qb::Selector j("B='hello kitty' AnD A='Bye, bye cruel world'");
+ qb::Selector k("B='hello kitty' AnD B='Bye, bye cruel world'");
+ qb::Selector a4("A is null or A='Bye, bye cruel world'");
+ qb::Selector a5("Z is null OR A is not null and A<>'Bye, bye cruel world'");
+ qb::Selector a6("(Z is null OR A is not null) and A<>'Bye, bye cruel world'");
+ qb::Selector t("NOT C is not null OR C is null");
+ qb::Selector n("Not A='' or B=z");
+
+ TestSelectorEnv env;
+ env.set("A", "Bye, bye cruel world");
+ env.set("B", "hello kitty");
+
+ BOOST_CHECK(a.eval(env));
+ BOOST_CHECK(!a1.eval(env));
+ BOOST_CHECK(!a2.eval(env));
+ BOOST_CHECK(a3.eval(env));
+ BOOST_CHECK(!c.eval(env));
+ BOOST_CHECK(c1.eval(env));
+ BOOST_CHECK(!d.eval(env));
+ BOOST_CHECK(e.eval(env));
+ BOOST_CHECK(!f.eval(env));
+ BOOST_CHECK(g.eval(env));
+ BOOST_CHECK(!h.eval(env));
+ BOOST_CHECK(i.eval(env));
+ BOOST_CHECK(j.eval(env));
+ BOOST_CHECK(!k.eval(env));
+ BOOST_CHECK(a4.eval(env));
+ BOOST_CHECK(a5.eval(env));
+ BOOST_CHECK(!a6.eval(env));
+ BOOST_CHECK(t.eval(env));
+ BOOST_CHECK(n.eval(env));
+}
+
+QPID_AUTO_TEST_SUITE_END()
+
+}}