it is easier to use decimal notation to represent integers, but it is also
possible to use hex notation. When using hex notation to represent an
integer care should be taken to make sure the value is represented as 32
- bits, e.g. use 0x00000001 instead of 0x1 or 0x01.
+ bits, e.g. use 0x00000001 instead of 0x1 or 0x01. Also, make
+ sure the value is specified in network order, e.g. 1 is
+ represented as 0x00000001.
</para>
<para>
} catch (const boost::bad_lexical_cast &) {
error(loc, "Invalid value in " + number);
}
- if (n >= std::numeric_limits<uint32_t>::max()) {
+ if (n > std::numeric_limits<uint32_t>::max()) {
error(loc, "Invalid value in "
+ number + ". Allowed range: 0..4294967295");
}
std::string tmp(yytext);
try {
- static_cast<void>(boost::lexical_cast<int>(tmp));
+ // In substring we want to use negative values (e.g. -1).
+ // In enterprise-id we need to use values up to 0xffffffff.
+ // To cover both of those use cases, we need at least
+ // int64_t.
+ static_cast<void>(boost::lexical_cast<int64_t>(tmp));
} catch (const boost::bad_lexical_cast &) {
driver.error(loc, "Failed to convert " + tmp + " to an integer.");
}
TokenVendor::DATA, index));
ctx.expression.push_back(vendor_class);
}
- | integer_expr
+ | integer_expr
{
TokenPtr integer(new TokenInteger($1));
ctx.expression.push_back(integer);
}
;
-integer_expr: INTEGER
- {
- $$ = ctx.convertUint32($1, @1);
- }
- ;
+integer_expr : INTEGER
+ {
+ $$ = ctx.convertUint32($1, @1);
+ }
+ ;
option_code : INTEGER
{
EXPECT_TRUE(eq);
}
+ /// @brief Checks if the given token is integer with expected value
+ ///
+ /// @param token token to be inspected
+ /// @param exp_value expected integer value of the token
void checkTokenInteger(const TokenPtr& token, uint32_t exp_value) {
ASSERT_TRUE(token);
boost::shared_ptr<TokenInteger> integer =
bool result;
bool parsed;
- EXPECT_NO_THROW(parsed = eval.parseString(expr));
+ EXPECT_NO_THROW(parsed = eval.parseString(expr))
+ << " while parsing expression " << expr;
EXPECT_TRUE(parsed) << " for expression " << expr;
switch (u) {
EXPECT_EQ(exp_result, result) << " for expression " << expr;
}
+
+ /// @brief Checks that specified expression throws expected exception.
+ ///
+ /// @tparam ex exception type expected to be thrown
+ /// @param expr expression to be evaluated
+ template<typename ex>
+ void testExpressionNegative(const std::string& expr,
+ const Option::Universe& u = Option::V4) {
+ EvalContext eval(u);
+
+ EXPECT_THROW(eval.parseString(expr), ex) << "while parsing expression "
+ << expr;
+ }
};
// This is a quick way to check if certain expressions are valid or not and
testExpression(Option::V4, "pkt4.mac == 0x010203040506", true);
}
+// Test if expressions message type can be detected in Pkt4.
+// It also doubles as a check for integer comparison here.
TEST_F(ExpressionsTest, expressionsPkt4type) {
// We can inspect the option content directly, but
testExpression(Option::V4, "pkt4.msgtype == 2", false);
}
+// This tests if inappropriate values (negative, too large) are
+// rejected, but extremal value still allowed for uint32_t are ok.
+TEST_F(ExpressionsTest, invalidIntegers) {
+
+ // These are the extremal uint32_t values that still should be accepted.
+ testExpression(Option::V4, "4294967295 == 0", false);
+
+ // Negative integers should be rejected.
+ testExpressionNegative<EvalParseError>("4294967295 == -1");
+
+ // Oops, one too much.
+ testExpressionNegative<EvalParseError>("4294967296 == 0");
+}
};