context_unittest.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. // Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <eval/token.h>
  8. #include <eval/eval_context.h>
  9. #include <eval/token.h>
  10. #include <dhcp/option.h>
  11. #include <dhcp/pkt4.h>
  12. #include <boost/shared_ptr.hpp>
  13. #include <boost/scoped_ptr.hpp>
  14. #include <gtest/gtest.h>
  15. using namespace std;
  16. using namespace isc::dhcp;
  17. namespace {
  18. /// @brief Test class for testing EvalContext aka class test parsing
  19. class EvalContextTest : public ::testing::Test {
  20. public:
  21. /// @brief constructor to initialize members
  22. EvalContextTest() : ::testing::Test(),
  23. universe_(Option::V4), parsed_(false)
  24. { }
  25. /// @brief checks if the given token is a string with the expected value
  26. void checkTokenString(const TokenPtr& token, const std::string& expected) {
  27. ASSERT_TRUE(token);
  28. boost::shared_ptr<TokenString> str =
  29. boost::dynamic_pointer_cast<TokenString>(token);
  30. ASSERT_TRUE(str);
  31. Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, 12345));
  32. ValueStack values;
  33. EXPECT_NO_THROW(token->evaluate(*pkt4, values));
  34. ASSERT_EQ(1, values.size());
  35. EXPECT_EQ(expected, values.top());
  36. }
  37. /// @brief checks if the given token is a hex string with the expected value
  38. void checkTokenHexString(const TokenPtr& token,
  39. const std::string& expected) {
  40. ASSERT_TRUE(token);
  41. boost::shared_ptr<TokenHexString> hex =
  42. boost::dynamic_pointer_cast<TokenHexString>(token);
  43. ASSERT_TRUE(hex);
  44. Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, 12345));
  45. ValueStack values;
  46. EXPECT_NO_THROW(token->evaluate(*pkt4, values));
  47. ASSERT_EQ(1, values.size());
  48. EXPECT_EQ(expected, values.top());
  49. }
  50. /// @brief checks if the given token is an equal operator
  51. void checkTokenEq(const TokenPtr& token) {
  52. ASSERT_TRUE(token);
  53. boost::shared_ptr<TokenEqual> eq =
  54. boost::dynamic_pointer_cast<TokenEqual>(token);
  55. EXPECT_TRUE(eq);
  56. }
  57. /// @brief checks if the given token is an option with the expected code
  58. /// and representation type
  59. /// @param token token to be checked
  60. /// @param expected_code expected option code
  61. /// @param expected_repr expected representation (text, hex, exists)
  62. void checkTokenOption(const TokenPtr& token,
  63. uint16_t expected_code,
  64. TokenOption::RepresentationType expected_repr) {
  65. ASSERT_TRUE(token);
  66. boost::shared_ptr<TokenOption> opt =
  67. boost::dynamic_pointer_cast<TokenOption>(token);
  68. ASSERT_TRUE(opt);
  69. EXPECT_EQ(expected_code, opt->getCode());
  70. EXPECT_EQ(expected_repr, opt->getRepresentation());
  71. }
  72. /// @brief check if the given token is relay4 with the expected code
  73. /// and representation type
  74. /// @param token token to be checked
  75. /// @param expected_code expected option code
  76. /// @param expected_repr expected representation (text, hex, exists)
  77. void checkTokenRelay4(const TokenPtr& token,
  78. uint16_t expected_code,
  79. TokenOption::RepresentationType expected_repr) {
  80. ASSERT_TRUE(token);
  81. boost::shared_ptr<TokenRelay4Option> relay4 =
  82. boost::dynamic_pointer_cast<TokenRelay4Option>(token);
  83. EXPECT_TRUE(relay4);
  84. if (relay4) {
  85. EXPECT_EQ(expected_code, relay4->getCode());
  86. EXPECT_EQ(expected_repr, relay4->getRepresentation());
  87. }
  88. }
  89. /// @brief checks if the given token is a substring operator
  90. void checkTokenSubstring(const TokenPtr& token) {
  91. ASSERT_TRUE(token);
  92. boost::shared_ptr<TokenSubstring> sub =
  93. boost::dynamic_pointer_cast<TokenSubstring>(token);
  94. EXPECT_TRUE(sub);
  95. }
  96. /// @brief checks if the given token is a concat operator
  97. void checkTokenConcat(const TokenPtr& token) {
  98. ASSERT_TRUE(token);
  99. boost::shared_ptr<TokenConcat> conc =
  100. boost::dynamic_pointer_cast<TokenConcat>(token);
  101. EXPECT_TRUE(conc);
  102. }
  103. /// @brief checks if the given expression raises the expected message
  104. /// when it is parsed.
  105. void checkError(const string& expr, const string& msg) {
  106. EvalContext eval(universe_);
  107. parsed_ = false;
  108. try {
  109. parsed_ = eval.parseString(expr);
  110. FAIL() << "Expected EvalParseError but nothing was raised";
  111. }
  112. catch (const EvalParseError& ex) {
  113. EXPECT_EQ(msg, ex.what());
  114. EXPECT_FALSE(parsed_);
  115. }
  116. catch (...) {
  117. FAIL() << "Expected EvalParseError but something else was raised";
  118. }
  119. }
  120. /// @brief sets the universe
  121. /// @note the default universe is DHCPv4
  122. void setUniverse(const Option::Universe& universe) {
  123. universe_ = universe;
  124. }
  125. Option::Universe universe_;
  126. bool parsed_; ///< Parsing status
  127. };
  128. // Test the parsing of a basic expression
  129. TEST_F(EvalContextTest, basic) {
  130. EvalContext eval(Option::V4);
  131. EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].text == 'MSFT'"));
  132. EXPECT_TRUE(parsed_);
  133. }
  134. // Test the parsing of a string terminal
  135. TEST_F(EvalContextTest, string) {
  136. EvalContext eval(Option::V4);
  137. EXPECT_NO_THROW(parsed_ = eval.parseString("'foo' == 'bar'"));
  138. EXPECT_TRUE(parsed_);
  139. ASSERT_EQ(3, eval.expression.size());
  140. TokenPtr tmp1 = eval.expression.at(0);
  141. TokenPtr tmp2 = eval.expression.at(1);
  142. checkTokenString(tmp1, "foo");
  143. checkTokenString(tmp2, "bar");
  144. }
  145. // Test the parsing of a basic expression using integers
  146. TEST_F(EvalContextTest, integer) {
  147. EvalContext eval(Option::V4);
  148. EXPECT_NO_THROW(parsed_ =
  149. eval.parseString("substring(option[123].text, 0, 2) == '42'"));
  150. EXPECT_TRUE(parsed_);
  151. }
  152. // Test the parsing of a hexstring terminal
  153. TEST_F(EvalContextTest, hexstring) {
  154. EvalContext eval(Option::V4);
  155. EXPECT_NO_THROW(parsed_ = eval.parseString("0x666f6f == 'foo'"));
  156. EXPECT_TRUE(parsed_);
  157. ASSERT_EQ(3, eval.expression.size());
  158. TokenPtr tmp = eval.expression.at(0);
  159. checkTokenHexString(tmp, "foo");
  160. }
  161. // Test the parsing of a hexstring terminal with an odd number of
  162. // hexadecimal digits
  163. TEST_F(EvalContextTest, oddHexstring) {
  164. EvalContext eval(Option::V4);
  165. EXPECT_NO_THROW(parsed_ = eval.parseString("0X7 == 'foo'"));
  166. EXPECT_TRUE(parsed_);
  167. ASSERT_EQ(3, eval.expression.size());
  168. TokenPtr tmp = eval.expression.at(0);
  169. checkTokenHexString(tmp, "\a");
  170. }
  171. // Test the parsing of an equal expression
  172. TEST_F(EvalContextTest, equal) {
  173. EvalContext eval(Option::V4);
  174. EXPECT_NO_THROW(parsed_ = eval.parseString("'foo' == 'bar'"));
  175. EXPECT_TRUE(parsed_);
  176. ASSERT_EQ(3, eval.expression.size());
  177. TokenPtr tmp1 = eval.expression.at(0);
  178. TokenPtr tmp2 = eval.expression.at(1);
  179. TokenPtr tmp3 = eval.expression.at(2);
  180. checkTokenString(tmp1, "foo");
  181. checkTokenString(tmp2, "bar");
  182. checkTokenEq(tmp3);
  183. }
  184. // Test the parsing of an option terminal
  185. TEST_F(EvalContextTest, option) {
  186. EvalContext eval(Option::V4);
  187. EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].text == 'foo'"));
  188. EXPECT_TRUE(parsed_);
  189. ASSERT_EQ(3, eval.expression.size());
  190. checkTokenOption(eval.expression.at(0), 123, TokenOption::TEXTUAL);
  191. }
  192. // Test parsing of an option identified by name.
  193. TEST_F(EvalContextTest, optionWithName) {
  194. EvalContext eval(Option::V4);
  195. // Option 'host-name' is a standard DHCPv4 option defined in the libdhcp++.
  196. EXPECT_NO_THROW(parsed_ = eval.parseString("option[host-name].text == 'foo'"));
  197. EXPECT_TRUE(parsed_);
  198. ASSERT_EQ(3, eval.expression.size());
  199. checkTokenOption(eval.expression.at(0), 12, TokenOption::TEXTUAL);
  200. }
  201. // Test parsing of an option existence
  202. TEST_F(EvalContextTest, optionExists) {
  203. EvalContext eval(Option::V4);
  204. EXPECT_NO_THROW(parsed_ = eval.parseString("option[100].exists"));
  205. EXPECT_TRUE(parsed_);
  206. ASSERT_EQ(1, eval.expression.size());
  207. checkTokenOption(eval.expression.at(0), 100, TokenOption::EXISTS);
  208. }
  209. // Test checking that whitespace can surround option name.
  210. TEST_F(EvalContextTest, optionWithNameAndWhitespace) {
  211. EvalContext eval(Option::V4);
  212. // Option 'host-name' is a standard DHCPv4 option defined in the libdhcp++.
  213. EXPECT_NO_THROW(parsed_ = eval.parseString("option[ host-name ].text == 'foo'"));
  214. EXPECT_TRUE(parsed_);
  215. ASSERT_EQ(3, eval.expression.size());
  216. checkTokenOption(eval.expression.at(0), 12, TokenOption::TEXTUAL);
  217. }
  218. // Test checking that newlines can surround option name.
  219. TEST_F(EvalContextTest, optionWithNameAndNewline) {
  220. EvalContext eval(Option::V4);
  221. // Option 'host-name' is a standard DHCPv4 option defined in the libdhcp++.
  222. EXPECT_NO_THROW(parsed_ =
  223. eval.parseString("option[\n host-name \n ].text == \n'foo'"));
  224. EXPECT_TRUE(parsed_);
  225. ASSERT_EQ(3, eval.expression.size());
  226. checkTokenOption(eval.expression.at(0), 12, TokenOption::TEXTUAL);
  227. }
  228. // Test parsing of an option represented as hexadecimal string.
  229. TEST_F(EvalContextTest, optionHex) {
  230. EvalContext eval(Option::V4);
  231. EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].hex == 0x666F6F"));
  232. EXPECT_TRUE(parsed_);
  233. ASSERT_EQ(3, eval.expression.size());
  234. checkTokenOption(eval.expression.at(0), 123, TokenOption::HEXADECIMAL);
  235. }
  236. // This test checks that the relay4[code].hex can be used in expressions.
  237. TEST_F(EvalContextTest, relay4Option) {
  238. EvalContext eval(Option::V4);
  239. EXPECT_NO_THROW(parsed_ =
  240. eval.parseString("relay4[13].hex == 'thirteen'"));
  241. EXPECT_TRUE(parsed_);
  242. ASSERT_EQ(3, eval.expression.size());
  243. TokenPtr tmp1 = eval.expression.at(0);
  244. TokenPtr tmp2 = eval.expression.at(1);
  245. TokenPtr tmp3 = eval.expression.at(2);
  246. checkTokenRelay4(tmp1, 13, TokenOption::HEXADECIMAL);
  247. checkTokenString(tmp2, "thirteen");
  248. checkTokenEq(tmp3);
  249. }
  250. // This test check the relay4[code].exists is supported.
  251. TEST_F(EvalContextTest, relay4Exists) {
  252. EvalContext eval(Option::V4);
  253. EXPECT_NO_THROW(parsed_ = eval.parseString("relay4[13].exists"));
  254. EXPECT_TRUE(parsed_);
  255. ASSERT_EQ(1, eval.expression.size());
  256. checkTokenRelay4(eval.expression.at(0), 13, TokenOption::EXISTS);
  257. }
  258. // Verify that relay4[13] is not usable in v6
  259. // There will be a separate relay accessor for v6.
  260. TEST_F(EvalContextTest, relay4Error) {
  261. universe_ = Option::V6;
  262. checkError("relay4[13].hex == 'thirteen'",
  263. "<string>:1.1-6: relay4 can only be used in DHCPv4.");
  264. }
  265. // Test parsing of logical operators
  266. TEST_F(EvalContextTest, logicalOps) {
  267. // option.exists
  268. EvalContext eval0(Option::V4);
  269. EXPECT_NO_THROW(parsed_ = eval0.parseString("option[123].exists"));
  270. EXPECT_TRUE(parsed_);
  271. ASSERT_EQ(1, eval0.expression.size());
  272. TokenPtr token = eval0.expression.at(0);
  273. ASSERT_TRUE(token);
  274. boost::shared_ptr<TokenOption> opt =
  275. boost::dynamic_pointer_cast<TokenOption>(token);
  276. EXPECT_TRUE(opt);
  277. // not
  278. EvalContext evaln(Option::V4);
  279. EXPECT_NO_THROW(parsed_ = evaln.parseString("not option[123].exists"));
  280. EXPECT_TRUE(parsed_);
  281. ASSERT_EQ(2, evaln.expression.size());
  282. token = evaln.expression.at(1);
  283. ASSERT_TRUE(token);
  284. boost::shared_ptr<TokenNot> tnot =
  285. boost::dynamic_pointer_cast<TokenNot>(token);
  286. EXPECT_TRUE(tnot);
  287. // and
  288. EvalContext evala(Option::V4);
  289. EXPECT_NO_THROW(parsed_ =
  290. evala.parseString("option[123].exists and option[123].exists"));
  291. EXPECT_TRUE(parsed_);
  292. ASSERT_EQ(3, evala.expression.size());
  293. token = evala.expression.at(2);
  294. ASSERT_TRUE(token);
  295. boost::shared_ptr<TokenAnd> tand =
  296. boost::dynamic_pointer_cast<TokenAnd>(token);
  297. EXPECT_TRUE(tand);
  298. // or
  299. EvalContext evalo(Option::V4);
  300. EXPECT_NO_THROW(parsed_ =
  301. evalo.parseString("option[123].exists or option[123].exists"));
  302. EXPECT_TRUE(parsed_);
  303. ASSERT_EQ(3, evalo.expression.size());
  304. token = evalo.expression.at(2);
  305. ASSERT_TRUE(token);
  306. boost::shared_ptr<TokenOr> tor =
  307. boost::dynamic_pointer_cast<TokenOr>(token);
  308. EXPECT_TRUE(tor);
  309. }
  310. // Test parsing of logical operators with precedence
  311. TEST_F(EvalContextTest, logicalPrecedence) {
  312. // not precedence > and precedence
  313. EvalContext evalna(Option::V4);
  314. EXPECT_NO_THROW(parsed_ =
  315. evalna.parseString("not option[123].exists and option[123].exists"));
  316. EXPECT_TRUE(parsed_);
  317. ASSERT_EQ(4, evalna.expression.size());
  318. TokenPtr token = evalna.expression.at(3);
  319. ASSERT_TRUE(token);
  320. boost::shared_ptr<TokenAnd> tand =
  321. boost::dynamic_pointer_cast<TokenAnd>(token);
  322. EXPECT_TRUE(tand);
  323. // and precedence > or precedence
  324. EvalContext evaloa(Option::V4);
  325. EXPECT_NO_THROW(parsed_ =
  326. evaloa.parseString("option[123].exists or option[123].exists "
  327. "and option[123].exists"));
  328. EXPECT_TRUE(parsed_);
  329. ASSERT_EQ(5, evaloa.expression.size());
  330. token = evaloa.expression.at(4);
  331. ASSERT_TRUE(token);
  332. boost::shared_ptr<TokenOr> tor =
  333. boost::dynamic_pointer_cast<TokenOr>(token);
  334. EXPECT_TRUE(tor);
  335. }
  336. // Test parsing of logical operators with parentheses (same than
  337. // with precedence but using parentheses to overwrite precedence)
  338. TEST_F(EvalContextTest, logicalParentheses) {
  339. // not precedence > and precedence
  340. EvalContext evalna(Option::V4);
  341. EXPECT_NO_THROW(parsed_ =
  342. evalna.parseString("not (option[123].exists and option[123].exists)"));
  343. EXPECT_TRUE(parsed_);
  344. ASSERT_EQ(4, evalna.expression.size());
  345. TokenPtr token = evalna.expression.at(3);
  346. ASSERT_TRUE(token);
  347. boost::shared_ptr<TokenNot> tnot =
  348. boost::dynamic_pointer_cast<TokenNot>(token);
  349. EXPECT_TRUE(tnot);
  350. // and precedence > or precedence
  351. EvalContext evaloa(Option::V4);
  352. EXPECT_NO_THROW(parsed_ =
  353. evaloa.parseString("(option[123].exists or option[123].exists) "
  354. "and option[123].exists"));
  355. EXPECT_TRUE(parsed_);
  356. ASSERT_EQ(5, evaloa.expression.size());
  357. token = evaloa.expression.at(4);
  358. ASSERT_TRUE(token);
  359. boost::shared_ptr<TokenAnd> tand =
  360. boost::dynamic_pointer_cast<TokenAnd>(token);
  361. EXPECT_TRUE(tand);
  362. }
  363. // Test the parsing of a substring expression
  364. TEST_F(EvalContextTest, substring) {
  365. EvalContext eval(Option::V4);
  366. EXPECT_NO_THROW(parsed_ =
  367. eval.parseString("substring('foobar',2,all) == 'obar'"));
  368. EXPECT_TRUE(parsed_);
  369. ASSERT_EQ(6, eval.expression.size());
  370. TokenPtr tmp1 = eval.expression.at(0);
  371. TokenPtr tmp2 = eval.expression.at(1);
  372. TokenPtr tmp3 = eval.expression.at(2);
  373. TokenPtr tmp4 = eval.expression.at(3);
  374. checkTokenString(tmp1, "foobar");
  375. checkTokenString(tmp2, "2");
  376. checkTokenString(tmp3, "all");
  377. checkTokenSubstring(tmp4);
  378. }
  379. // Test the parsing of a concat expression
  380. TEST_F(EvalContextTest, concat) {
  381. EvalContext eval(Option::V4);
  382. EXPECT_NO_THROW(parsed_ =
  383. eval.parseString("concat('foo','bar') == 'foobar'"));
  384. EXPECT_TRUE(parsed_);
  385. ASSERT_EQ(5, eval.expression.size());
  386. TokenPtr tmp1 = eval.expression.at(0);
  387. TokenPtr tmp2 = eval.expression.at(1);
  388. TokenPtr tmp3 = eval.expression.at(2);
  389. checkTokenString(tmp1, "foo");
  390. checkTokenString(tmp2, "bar");
  391. checkTokenConcat(tmp3);
  392. }
  393. // Test some scanner error cases
  394. TEST_F(EvalContextTest, scanErrors) {
  395. checkError("'", "<string>:1.1: Invalid character: '");
  396. checkError("'\''", "<string>:1.3: Invalid character: '");
  397. checkError("'\n'", "<string>:1.1: Invalid character: '");
  398. checkError("0x123h", "<string>:1.6: Invalid character: h");
  399. checkError("=", "<string>:1.1: Invalid character: =");
  400. checkError("subtring", "<string>:1.1: Invalid character: s");
  401. checkError("foo", "<string>:1.1: Invalid character: f");
  402. checkError(" bar", "<string>:1.2: Invalid character: b");
  403. checkError("relay[12].hex == 'foo'", "<string>:1.1: Invalid character: r");
  404. }
  405. // Tests some scanner/parser error cases
  406. TEST_F(EvalContextTest, scanParseErrors) {
  407. checkError("", "<string>:1.1: syntax error, unexpected end of file");
  408. checkError(" ", "<string>:1.2: syntax error, unexpected end of file");
  409. checkError("0x", "<string>:1.1: syntax error, unexpected integer");
  410. checkError("0abc",
  411. "<string>:1.1: syntax error, unexpected integer");
  412. checkError("===", "<string>:1.1-2: syntax error, unexpected ==");
  413. checkError("option[-1].text",
  414. "<string>:1.8-9: Option code has invalid "
  415. "value in -1. Allowed range: 0..255");
  416. checkError("option[256].text",
  417. "<string>:1.8-10: Option code has invalid "
  418. "value in 256. Allowed range: 0..255");
  419. setUniverse(Option::V6);
  420. checkError("option[65536].text",
  421. "<string>:1.8-12: Option code has invalid "
  422. "value in 65536. Allowed range: 0..65535");
  423. setUniverse(Option::V4);
  424. checkError("option[12345678901234567890].text",
  425. "<string>:1.8-27: Failed to convert 12345678901234567890 "
  426. "to an integer.");
  427. checkError("option[123]",
  428. "<string>:1.12: syntax error, unexpected end of file,"
  429. " expecting .");
  430. checkError("option[123].text < 'foo'", "<string>:1.18: Invalid"
  431. " character: <");
  432. checkError("option[-ab].text", "<string>:1.8: Invalid character: -");
  433. checkError("option[0ab].text",
  434. "<string>:1.9-10: syntax error, unexpected option name, "
  435. "expecting ]");
  436. checkError("option[ab_].hex", "<string>:1.8: Invalid character: a");
  437. checkError("option[\nhost-name\n].hex =\n= 'foo'",
  438. "<string>:3.7: Invalid character: =");
  439. checkError("substring('foo',12345678901234567890,1)",
  440. "<string>:1.17-36: Failed to convert 12345678901234567890 "
  441. "to an integer.");
  442. }
  443. // Tests some parser error cases
  444. TEST_F(EvalContextTest, parseErrors) {
  445. checkError("'foo''bar'",
  446. "<string>:1.6-10: syntax error, unexpected constant string, "
  447. "expecting ==");
  448. checkError("'foo' (",
  449. "<string>:1.7: syntax error, unexpected (, expecting ==");
  450. checkError("== 'ab'", "<string>:1.1-2: syntax error, unexpected ==");
  451. checkError("'foo' ==",
  452. "<string>:1.9: syntax error, unexpected end of file");
  453. checkError("('foo' == 'bar'",
  454. "<string>:1.16: syntax error, unexpected end of file, "
  455. "expecting ) or and or or");
  456. checkError("('foo' == 'bar') ''",
  457. "<string>:1.18-19: syntax error, unexpected constant string, "
  458. "expecting end of file");
  459. checkError("not",
  460. "<string>:1.4: syntax error, unexpected end of file");
  461. checkError("not 'foo'",
  462. "<string>:1.10: syntax error, unexpected end of file, "
  463. "expecting ==");
  464. checkError("not()",
  465. "<string>:1.5: syntax error, unexpected )");
  466. checkError("(not('foo' 'bar')",
  467. "<string>:1.12-16: syntax error, unexpected constant string, "
  468. "expecting ==");
  469. checkError("and",
  470. "<string>:1.1-3: syntax error, unexpected and");
  471. checkError("'foo' and",
  472. "<string>:1.7-9: syntax error, unexpected and, expecting ==");
  473. checkError("'foo' == 'bar' and",
  474. "<string>:1.19: syntax error, unexpected end of file");
  475. checkError("'foo' == 'bar' and ''",
  476. "<string>:1.22: syntax error, unexpected end of file, "
  477. "expecting ==");
  478. checkError("or",
  479. "<string>:1.1-2: syntax error, unexpected or");
  480. checkError("'foo' or",
  481. "<string>:1.7-8: syntax error, unexpected or, expecting ==");
  482. checkError("'foo' == 'bar' or",
  483. "<string>:1.18: syntax error, unexpected end of file");
  484. checkError("'foo' == 'bar' or ''",
  485. "<string>:1.21: syntax error, unexpected end of file, "
  486. "expecting ==");
  487. checkError("option 'ab'",
  488. "<string>:1.8-11: syntax error, unexpected "
  489. "constant string, expecting [");
  490. checkError("option(10) == 'ab'",
  491. "<string>:1.7: syntax error, "
  492. "unexpected (, expecting [");
  493. checkError("option['ab'].text == 'foo'",
  494. "<string>:1.8-11: syntax error, "
  495. "unexpected constant string, "
  496. "expecting integer or option name");
  497. checkError("option[ab].text == 'foo'",
  498. "<string>:1.8-9: option 'ab' is not defined");
  499. checkError("option[0xa].text == 'ab'",
  500. "<string>:1.8-10: syntax error, "
  501. "unexpected constant hexstring, "
  502. "expecting integer or option name");
  503. checkError("option[10].bin", "<string>:1.12: Invalid character: b");
  504. checkError("option[boot-size].bin", "<string>:1.19: Invalid character: b");
  505. checkError("option[10].exists == 'foo'",
  506. "<string>:1.19-20: syntax error, unexpected ==, "
  507. "expecting end of file");
  508. checkError("substring('foobar') == 'f'",
  509. "<string>:1.19: syntax error, unexpected ), expecting \",\"");
  510. checkError("substring('foobar',3) == 'bar'",
  511. "<string>:1.21: syntax error, unexpected ), expecting \",\"");
  512. checkError("substring('foobar','3',3) == 'bar'",
  513. "<string>:1.20-22: syntax error, unexpected constant string, "
  514. "expecting integer");
  515. checkError("substring('foobar',1,a) == 'foo'",
  516. "<string>:1.22: Invalid character: a");
  517. checkError("concat('foobar') == 'f'",
  518. "<string>:1.16: syntax error, unexpected ), expecting \",\"");
  519. checkError("concat('foo','bar','') == 'foobar'",
  520. "<string>:1.19: syntax error, unexpected \",\", expecting )");
  521. }
  522. // Tests some type error cases
  523. TEST_F(EvalContextTest, typeErrors) {
  524. checkError("'foobar'",
  525. "<string>:1.9: syntax error, unexpected end of file, "
  526. "expecting ==");
  527. checkError("substring('foobar',all,1) == 'foo'",
  528. "<string>:1.20-22: syntax error, unexpected all, "
  529. "expecting integer");
  530. checkError("substring('foobar',0x32,1) == 'foo'",
  531. "<string>:1.20-23: syntax error, unexpected constant "
  532. "hexstring, expecting integer");
  533. checkError("concat('foo',3) == 'foo3'",
  534. "<string>:1.14: syntax error, unexpected integer");
  535. checkError("concat(3,'foo') == '3foo'",
  536. "<string>:1.8: syntax error, unexpected integer");
  537. checkError("('foo' == 'bar') == 'false'",
  538. "<string>:1.18-19: syntax error, unexpected ==, "
  539. "expecting end of file");
  540. checkError("not 'true'",
  541. "<string>:1.11: syntax error, unexpected end of file, "
  542. "expecting ==");
  543. checkError("'true' and 'false'",
  544. "<string>:1.8-10: syntax error, unexpected and, expecting ==");
  545. checkError("'true' or 'false'",
  546. "<string>:1.8-9: syntax error, unexpected or, expecting ==");
  547. }
  548. };