diff options
author | Francis Dupont <fdupont@isc.org> | 2024-08-07 19:54:07 +0200 |
---|---|---|
committer | Francis Dupont <fdupont@isc.org> | 2024-08-21 15:12:38 +0200 |
commit | 7d1f9176509502efe4580072f654000b5bc1f652 (patch) | |
tree | a5b02da8381afa9c3a62d10236ad62c991fdb43c | |
parent | [#3502] Checkpoint: add strict-* syntax (diff) | |
download | kea-7d1f9176509502efe4580072f654000b5bc1f652.tar.xz kea-7d1f9176509502efe4580072f654000b5bc1f652.zip |
[#3502] Checkpoint: changed strict- by s
-rw-r--r-- | src/lib/eval/lexer.ll | 6 | ||||
-rw-r--r-- | src/lib/eval/parser.yy | 16 | ||||
-rw-r--r-- | src/lib/eval/tests/boolean_unittest.cc | 33 | ||||
-rw-r--r-- | src/lib/eval/tests/context_unittest.cc | 132 |
4 files changed, 173 insertions, 14 deletions
diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll index 719d3ff131..b948271a25 100644 --- a/src/lib/eval/lexer.ll +++ b/src/lib/eval/lexer.ll @@ -221,7 +221,7 @@ addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]* "all" return isc::eval::EvalParser::make_ALL(loc); "concat" return isc::eval::EvalParser::make_CONCAT(loc); "ifelse" return isc::eval::EvalParser::make_IFELSE(loc); -"strict-ifelse" return isc::eval::EvalParser::make_STRICT_IFELSE(loc); +"sifelse" return isc::eval::EvalParser::make_SIFELSE(loc); "hexstring" return isc::eval::EvalParser::make_TOHEXSTRING(loc); "addrtotext" return isc::eval::EvalParser::make_ADDRTOTEXT(loc); "int8totext" return isc::eval::EvalParser::make_INT8TOTEXT(loc); @@ -232,9 +232,9 @@ addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]* "uint32totext" return isc::eval::EvalParser::make_UINT32TOTEXT(loc); "not" return isc::eval::EvalParser::make_NOT(loc); "and" return isc::eval::EvalParser::make_AND(loc); -"strict-and" return isc::eval::EvalParser::make_STRICT_AND(loc); +"sand" return isc::eval::EvalParser::make_SAND(loc); "or" return isc::eval::EvalParser::make_OR(loc); -"strict-or" return isc::eval::EvalParser::make_STRICT_OR(loc); +"sor" return isc::eval::EvalParser::make_SOR(loc); "member" return isc::eval::EvalParser::make_MEMBER(loc); "match" return isc::eval::EvalParser::make_MATCH(loc); "." return isc::eval::EvalParser::make_DOT(loc); diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy index 65573e723c..59fdaa74b5 100644 --- a/src/lib/eval/parser.yy +++ b/src/lib/eval/parser.yy @@ -47,9 +47,9 @@ using namespace isc::eval; RPAREN ")" NOT "not" AND "and" - STRICT_AND "strict-and" + SAND "sand" OR "or" - STRICT_OR "strict-or" + SOR "sor" EQUAL "==" OPTION "option" RELAY4 "relay4" @@ -83,7 +83,7 @@ using namespace isc::eval; CONCAT "concat" PLUS "+" IFELSE "ifelse" - STRICT_IFELSE "strict-ifelse" + SIFELSE "sifelse" TOHEXSTRING "hexstring" ADDRTOTEXT "addrtotext" INT8TOTEXT "int8totext" @@ -126,9 +126,9 @@ using namespace isc::eval; %type <TokenPkt6::FieldType> pkt6_field %left PLUS -%left STRICT_OR +%left SOR %left OR -%left STRICT_AND +%left SAND %left AND %precedence NOT @@ -161,7 +161,7 @@ bool_expr : "(" bool_expr ")" TokenPtr neg(new TokenAnd()); ctx.expression.push_back(neg); } - | bool_expr STRICT_AND bool_expr + | bool_expr SAND bool_expr { TokenPtr neg(new TokenAnd()); ctx.expression.push_back(neg); @@ -171,7 +171,7 @@ bool_expr : "(" bool_expr ")" TokenPtr neg(new TokenOr()); ctx.expression.push_back(neg); } - | bool_expr STRICT_OR bool_expr + | bool_expr SOR bool_expr { TokenPtr neg(new TokenOr()); ctx.expression.push_back(neg); @@ -423,7 +423,7 @@ string_expr : STRING TokenPtr cond(new TokenIfElse()); ctx.expression.push_back(cond); } - | STRICT_IFELSE "(" bool_expr "," string_expr "," string_expr ")" + | SIFELSE "(" bool_expr "," string_expr "," string_expr ")" { TokenPtr cond(new TokenIfElse()); ctx.expression.push_back(cond); diff --git a/src/lib/eval/tests/boolean_unittest.cc b/src/lib/eval/tests/boolean_unittest.cc index f620daeca4..8c883c155f 100644 --- a/src/lib/eval/tests/boolean_unittest.cc +++ b/src/lib/eval/tests/boolean_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2024 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -34,7 +34,34 @@ public: } }; -// A group of tests +// A group of tests (strict version) +TEST_F(BooleanTest, strict) { + // true and (false or false) + check("('a' == 'a') sand (('a' == 'b') sor ('b' == 'a'))", false); + // (true and false) or false + check("(('a' == 'a') sand ('a' == 'b')) sor ('b' == 'a')", false); + // not true + check("not ('a' == 'a')", false); + // not false + check("not ('a' == 'b')", true); + // true and true and true and false + check("('a' == 'a') sand ('b' == 'b') sand ('c' == 'c') sand ('a' == 'c')", + false); + // false or false or false or true + check("('a' == 'b') sor ('a' == 'c') sor ('b' == 'c') sor ('b' == 'b')", + true); + // true or false or false or false + check("('a' == 'a') sor ('a' == 'b') sor ('a' == 'c') sor ('b' == 'c')", + true); + // not (true or false) + check("not (('a' == 'a') sor ('a' == 'b'))", false); + // not (true and false) + check("not (('a' == 'a') sand ('a' == 'b'))", true); + // (not true) and false + check("(not ('a' == 'a')) sand ('a' == 'b')",false); +} + +// A group of tests (strict version) TEST_F(BooleanTest, tests) { // true and (false or false) check("('a' == 'a') and (('a' == 'b') or ('b' == 'a'))", false); @@ -61,4 +88,4 @@ TEST_F(BooleanTest, tests) { check("(not ('a' == 'a')) and ('a' == 'b')",false); } -}; +} diff --git a/src/lib/eval/tests/context_unittest.cc b/src/lib/eval/tests/context_unittest.cc index ca2ce3da1e..0bea61b772 100644 --- a/src/lib/eval/tests/context_unittest.cc +++ b/src/lib/eval/tests/context_unittest.cc @@ -1333,6 +1333,31 @@ TEST_F(EvalContextTest, logicalOps) { boost::dynamic_pointer_cast<TokenNot>(token); EXPECT_TRUE(tnot); + // sand + EvalContext evala(Option::V4); + EXPECT_NO_THROW(parsed_ = + evala.parseString("option[123].exists sand option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(3, evala.expression.size()); + token = evala.expression.at(2); + ASSERT_TRUE(token); + boost::shared_ptr<TokenAnd> tand = + boost::dynamic_pointer_cast<TokenAnd>(token); + EXPECT_TRUE(tand); + + // sor + EvalContext evalo(Option::V4); + EXPECT_NO_THROW(parsed_ = + evalo.parseString("option[123].exists sor option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(3, evalo.expression.size()); + token = evalo.expression.at(2); + ASSERT_TRUE(token); + boost::shared_ptr<TokenOr> tor = + boost::dynamic_pointer_cast<TokenOr>(token); + EXPECT_TRUE(tor); + +#if notyet // and EvalContext evala(Option::V4); EXPECT_NO_THROW(parsed_ = @@ -1356,6 +1381,7 @@ TEST_F(EvalContextTest, logicalOps) { boost::shared_ptr<TokenOr> tor = boost::dynamic_pointer_cast<TokenOr>(token); EXPECT_TRUE(tor); +#endif } // Test parsing of logical operators with precedence @@ -1363,6 +1389,32 @@ TEST_F(EvalContextTest, logicalPrecedence) { // not precedence > and precedence EvalContext evalna(Option::V4); EXPECT_NO_THROW(parsed_ = + evalna.parseString("not option[123].exists sand option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(4, evalna.expression.size()); + TokenPtr token = evalna.expression.at(3); + ASSERT_TRUE(token); + boost::shared_ptr<TokenAnd> tand = + boost::dynamic_pointer_cast<TokenAnd>(token); + EXPECT_TRUE(tand); + + // and precedence > or precedence + EvalContext evaloa(Option::V4); + EXPECT_NO_THROW(parsed_ = + evaloa.parseString("option[123].exists sor option[123].exists " + "and option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(5, evaloa.expression.size()); + token = evaloa.expression.at(4); + ASSERT_TRUE(token); + boost::shared_ptr<TokenOr> tor = + boost::dynamic_pointer_cast<TokenOr>(token); + EXPECT_TRUE(tor); + +#if notyet + // not precedence > and precedence + EvalContext evalna(Option::V4); + EXPECT_NO_THROW(parsed_ = evalna.parseString("not option[123].exists and option[123].exists")); EXPECT_TRUE(parsed_); ASSERT_EQ(4, evalna.expression.size()); @@ -1384,6 +1436,7 @@ TEST_F(EvalContextTest, logicalPrecedence) { boost::shared_ptr<TokenOr> tor = boost::dynamic_pointer_cast<TokenOr>(token); EXPECT_TRUE(tor); +#endif } // Test parsing of logical operators with parentheses (same than @@ -1392,6 +1445,32 @@ TEST_F(EvalContextTest, logicalParentheses) { // not precedence > and precedence EvalContext evalna(Option::V4); EXPECT_NO_THROW(parsed_ = + evalna.parseString("not (option[123].exists sand option[123].exists)")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(4, evalna.expression.size()); + TokenPtr token = evalna.expression.at(3); + ASSERT_TRUE(token); + boost::shared_ptr<TokenNot> tnot = + boost::dynamic_pointer_cast<TokenNot>(token); + EXPECT_TRUE(tnot); + + // and precedence > or precedence + EvalContext evaloa(Option::V4); + EXPECT_NO_THROW(parsed_ = + evaloa.parseString("(option[123].exists sor option[123].exists) " + "sand option[123].exists")); + EXPECT_TRUE(parsed_); + ASSERT_EQ(5, evaloa.expression.size()); + token = evaloa.expression.at(4); + ASSERT_TRUE(token); + boost::shared_ptr<TokenAnd> tand = + boost::dynamic_pointer_cast<TokenAnd>(token); + EXPECT_TRUE(tand); + +#if notyet + // not precedence > and precedence + EvalContext evalna(Option::V4); + EXPECT_NO_THROW(parsed_ = evalna.parseString("not (option[123].exists and option[123].exists)")); EXPECT_TRUE(parsed_); ASSERT_EQ(4, evalna.expression.size()); @@ -1413,6 +1492,7 @@ TEST_F(EvalContextTest, logicalParentheses) { boost::shared_ptr<TokenAnd> tand = boost::dynamic_pointer_cast<TokenAnd>(token); EXPECT_TRUE(tand); +#endif } // Test the parsing of a substring expression @@ -1519,7 +1599,28 @@ TEST_F(EvalContextTest, assocRightPlus) { checkTokenConcat(tmp5); } +// Test the parsing of a sifelse expression +TEST_F(EvalContextTest, strictIfElse) { + EvalContext eval(Option::V4); + + EXPECT_NO_THROW(parsed_ = + eval.parseString("sifelse('foo' == 'bar', 'us', 'them') == 'you'")); + + ASSERT_EQ(8, eval.expression.size()); + + TokenPtr tmp1 = eval.expression.at(2); + TokenPtr tmp2 = eval.expression.at(3); + TokenPtr tmp3 = eval.expression.at(4); + TokenPtr tmp4 = eval.expression.at(5); + + checkTokenEq(tmp1); + checkTokenString(tmp2, "us"); + checkTokenString(tmp3, "them"); + checkTokenIfElse(tmp4); +} + // Test the parsing of an ifelse expression +#if notyet TEST_F(EvalContextTest, ifElse) { EvalContext eval(Option::V4); @@ -1538,8 +1639,38 @@ TEST_F(EvalContextTest, ifElse) { checkTokenString(tmp3, "them"); checkTokenIfElse(tmp4); } +#endif + +// Test the parsing of a plus operator and sifelse expression +TEST_F(EvalContextTest, plusStrictIfElse) { + EvalContext eval(Option::V4); + + EXPECT_NO_THROW(parsed_ = + eval.parseString("'foo' + sifelse('a' == 'a', 'bar', '') == 'foobar'")); + + ASSERT_EQ(10, eval.expression.size()); + + TokenPtr tmp1 = eval.expression.at(0); + TokenPtr tmp2 = eval.expression.at(1); + TokenPtr tmp3 = eval.expression.at(2); + TokenPtr tmp4 = eval.expression.at(3); + TokenPtr tmp5 = eval.expression.at(4); + TokenPtr tmp6 = eval.expression.at(5); + TokenPtr tmp7 = eval.expression.at(6); + TokenPtr tmp8 = eval.expression.at(7); + + checkTokenString(tmp1, "foo"); + checkTokenString(tmp2, "a"); + checkTokenString(tmp3, "a"); + checkTokenEq(tmp4); + checkTokenString(tmp5, "bar"); + checkTokenString(tmp6, ""); + checkTokenIfElse(tmp7); + checkTokenConcat(tmp8); +} // Test the parsing of a plus operator and ifelse expression +#if notyet TEST_F(EvalContextTest, plusIfElse) { EvalContext eval(Option::V4); @@ -1566,6 +1697,7 @@ TEST_F(EvalContextTest, plusIfElse) { checkTokenIfElse(tmp7); checkTokenConcat(tmp8); } +#endif // Test the parsing of a hexstring expression TEST_F(EvalContextTest, toHexString) { |