token_unittest.cc 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  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 <dhcp/pkt4.h>
  9. #include <dhcp/pkt6.h>
  10. #include <dhcp/dhcp4.h>
  11. #include <dhcp/dhcp6.h>
  12. #include <dhcp/option_string.h>
  13. #include <boost/shared_ptr.hpp>
  14. #include <boost/scoped_ptr.hpp>
  15. #include <gtest/gtest.h>
  16. #include <arpa/inet.h>
  17. using namespace std;
  18. using namespace isc::dhcp;
  19. namespace {
  20. /// @brief Test fixture for testing Tokens.
  21. ///
  22. /// This class provides several convenience objects to be used during testing
  23. /// of the Token family of classes.
  24. class TokenTest : public ::testing::Test {
  25. public:
  26. /// @brief Initializes Pkt4,Pkt6 and options that can be useful for
  27. /// evaluation tests.
  28. TokenTest() {
  29. pkt4_.reset(new Pkt4(DHCPDISCOVER, 12345));
  30. pkt6_.reset(new Pkt6(DHCPV6_SOLICIT, 12345));
  31. // Add options with easily identifiable strings in them
  32. option_str4_.reset(new OptionString(Option::V4, 100, "hundred4"));
  33. option_str6_.reset(new OptionString(Option::V6, 100, "hundred6"));
  34. pkt4_->addOption(option_str4_);
  35. pkt6_->addOption(option_str6_);
  36. }
  37. /// @brief Inserts RAI option with several suboptions
  38. ///
  39. /// The structure inserted is:
  40. /// - RAI (option 82)
  41. /// - option 1 (containing string "one")
  42. /// - option 13 (containing string "thirteen")
  43. void insertRelay4Option() {
  44. // RAI (Relay Agent Information) option
  45. OptionPtr rai(new Option(Option::V4, DHO_DHCP_AGENT_OPTIONS));
  46. OptionPtr sub1(new OptionString(Option::V4, 1, "one"));
  47. OptionPtr sub13(new OptionString(Option::V4, 13, "thirteen"));
  48. rai->addOption(sub1);
  49. rai->addOption(sub13);
  50. pkt4_->addOption(rai);
  51. }
  52. /// @brief Convenience function. Removes token and values stacks.
  53. void clearStack() {
  54. while (!values_.empty()) {
  55. values_.pop();
  56. }
  57. t_.reset();
  58. }
  59. TokenPtr t_; ///< Just a convenience pointer
  60. ValueStack values_; ///< evaluated values will be stored here
  61. Pkt4Ptr pkt4_; ///< A stub DHCPv4 packet
  62. Pkt6Ptr pkt6_; ///< A stub DHCPv6 packet
  63. OptionPtr option_str4_; ///< A string option for DHCPv4
  64. OptionPtr option_str6_; ///< A string option for DHCPv6
  65. /// @brief Verify that the substring eval works properly
  66. ///
  67. /// This function takes the parameters and sets up the value
  68. /// stack then executes the eval and checks the results.
  69. ///
  70. /// @param test_string The string to operate on
  71. /// @param test_start The postion to start when getting a substring
  72. /// @param test_length The length of the substring to get
  73. /// @param result_string The expected result of the eval
  74. /// @param should_throw The eval will throw
  75. void verifySubstringEval(const std::string& test_string,
  76. const std::string& test_start,
  77. const std::string& test_length,
  78. const std::string& result_string,
  79. bool should_throw = false) {
  80. // create the token
  81. ASSERT_NO_THROW(t_.reset(new TokenSubstring()));
  82. // push values on stack
  83. values_.push(test_string);
  84. values_.push(test_start);
  85. values_.push(test_length);
  86. // evaluate the token
  87. if (should_throw) {
  88. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError);
  89. ASSERT_EQ(0, values_.size());
  90. } else {
  91. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  92. // verify results
  93. ASSERT_EQ(1, values_.size());
  94. EXPECT_EQ(result_string, values_.top());
  95. // remove result
  96. values_.pop();
  97. }
  98. }
  99. /// @todo: Add more option types here
  100. };
  101. // This tests the toBool() conversions
  102. TEST_F(TokenTest, toBool) {
  103. ASSERT_NO_THROW(Token::toBool("true"));
  104. EXPECT_TRUE(Token::toBool("true"));
  105. ASSERT_NO_THROW(Token::toBool("false"));
  106. EXPECT_FALSE(Token::toBool("false"));
  107. // Token::toBool() is case-sensitive
  108. EXPECT_THROW(Token::toBool("True"), EvalTypeError);
  109. EXPECT_THROW(Token::toBool("TRUE"), EvalTypeError);
  110. // Proposed aliases
  111. EXPECT_THROW(Token::toBool("1"), EvalTypeError);
  112. EXPECT_THROW(Token::toBool("0"), EvalTypeError);
  113. EXPECT_THROW(Token::toBool(""), EvalTypeError);
  114. }
  115. // This simple test checks that a TokenString, representing a constant string,
  116. // can be used in Pkt4 evaluation. (The actual packet is not used)
  117. TEST_F(TokenTest, string4) {
  118. // Store constant string "foo" in the TokenString object.
  119. ASSERT_NO_THROW(t_.reset(new TokenString("foo")));
  120. // Make sure that the token can be evaluated without exceptions.
  121. ASSERT_NO_THROW(t_->evaluate(*pkt4_, values_));
  122. // Check that the evaluation put its value on the values stack.
  123. ASSERT_EQ(1, values_.size());
  124. EXPECT_EQ("foo", values_.top());
  125. }
  126. // This simple test checks that a TokenString, representing a constant string,
  127. // can be used in Pkt6 evaluation. (The actual packet is not used)
  128. TEST_F(TokenTest, string6) {
  129. // Store constant string "foo" in the TokenString object.
  130. ASSERT_NO_THROW(t_.reset(new TokenString("foo")));
  131. // Make sure that the token can be evaluated without exceptions.
  132. ASSERT_NO_THROW(t_->evaluate(*pkt6_, values_));
  133. // Check that the evaluation put its value on the values stack.
  134. ASSERT_EQ(1, values_.size());
  135. EXPECT_EQ("foo", values_.top());
  136. }
  137. // This simple test checks that a TokenHexString, representing a constant
  138. // string coded in hexadecimal, can be used in Pkt4 evaluation.
  139. // (The actual packet is not used)
  140. TEST_F(TokenTest, hexstring4) {
  141. TokenPtr empty;
  142. TokenPtr bad;
  143. TokenPtr nodigit;
  144. TokenPtr baddigit;
  145. TokenPtr bell;
  146. TokenPtr foo;
  147. TokenPtr cookie;
  148. // Store constant empty hexstring "" ("") in the TokenHexString object.
  149. ASSERT_NO_THROW(empty.reset(new TokenHexString("")));
  150. // Store bad encoded hexstring "0abc" ("").
  151. ASSERT_NO_THROW(bad.reset(new TokenHexString("0abc")));
  152. // Store hexstring with no digits "0x" ("").
  153. ASSERT_NO_THROW(nodigit.reset(new TokenHexString("0x")));
  154. // Store hexstring with a bad hexdigit "0xxabc" ("").
  155. ASSERT_NO_THROW(baddigit.reset(new TokenHexString("0xxabc")));
  156. // Store hexstring with an odd number of hexdigits "0x7" ("\a").
  157. ASSERT_NO_THROW(bell.reset(new TokenHexString("0x7")));
  158. // Store constant hexstring "0x666f6f" ("foo").
  159. ASSERT_NO_THROW(foo.reset(new TokenHexString("0x666f6f")));
  160. // Store constant hexstring "0x63825363" (DHCP_OPTIONS_COOKIE).
  161. ASSERT_NO_THROW(cookie.reset(new TokenHexString("0x63825363")));
  162. // Make sure that tokens can be evaluated without exceptions.
  163. ASSERT_NO_THROW(empty->evaluate(*pkt4_, values_));
  164. ASSERT_NO_THROW(bad->evaluate(*pkt4_, values_));
  165. ASSERT_NO_THROW(nodigit->evaluate(*pkt4_, values_));
  166. ASSERT_NO_THROW(baddigit->evaluate(*pkt4_, values_));
  167. ASSERT_NO_THROW(bell->evaluate(*pkt4_, values_));
  168. ASSERT_NO_THROW(foo->evaluate(*pkt4_, values_));
  169. ASSERT_NO_THROW(cookie->evaluate(*pkt4_, values_));
  170. // Check that the evaluation put its value on the values stack.
  171. ASSERT_EQ(7, values_.size());
  172. uint32_t expected = htonl(DHCP_OPTIONS_COOKIE);
  173. EXPECT_EQ(4, values_.top().size());
  174. EXPECT_EQ(0, memcmp(&expected, &values_.top()[0], 4));
  175. values_.pop();
  176. EXPECT_EQ("foo", values_.top());
  177. values_.pop();
  178. EXPECT_EQ("\a", values_.top());
  179. values_.pop();
  180. EXPECT_EQ("", values_.top());
  181. values_.pop();
  182. EXPECT_EQ("", values_.top());
  183. values_.pop();
  184. EXPECT_EQ("", values_.top());
  185. values_.pop();
  186. EXPECT_EQ("", values_.top());
  187. }
  188. // This simple test checks that a TokenHexString, representing a constant
  189. // string coded in hexadecimal, can be used in Pkt6 evaluation.
  190. // (The actual packet is not used)
  191. TEST_F(TokenTest, hexstring6) {
  192. TokenPtr empty;
  193. TokenPtr bad;
  194. TokenPtr nodigit;
  195. TokenPtr baddigit;
  196. TokenPtr bell;
  197. TokenPtr foo;
  198. TokenPtr cookie;
  199. // Store constant empty hexstring "" ("") in the TokenHexString object.
  200. ASSERT_NO_THROW(empty.reset(new TokenHexString("")));
  201. // Store bad encoded hexstring "0abc" ("").
  202. ASSERT_NO_THROW(bad.reset(new TokenHexString("0abc")));
  203. // Store hexstring with no digits "0x" ("").
  204. ASSERT_NO_THROW(nodigit.reset(new TokenHexString("0x")));
  205. // Store hexstring with a bad hexdigit "0xxabc" ("").
  206. ASSERT_NO_THROW(baddigit.reset(new TokenHexString("0xxabc")));
  207. // Store hexstring with an odd number of hexdigits "0x7" ("\a").
  208. ASSERT_NO_THROW(bell.reset(new TokenHexString("0x7")));
  209. // Store constant hexstring "0x666f6f" ("foo").
  210. ASSERT_NO_THROW(foo.reset(new TokenHexString("0x666f6f")));
  211. // Store constant hexstring "0x63825363" (DHCP_OPTIONS_COOKIE).
  212. ASSERT_NO_THROW(cookie.reset(new TokenHexString("0x63825363")));
  213. // Make sure that tokens can be evaluated without exceptions.
  214. ASSERT_NO_THROW(empty->evaluate(*pkt6_, values_));
  215. ASSERT_NO_THROW(bad->evaluate(*pkt6_, values_));
  216. ASSERT_NO_THROW(nodigit->evaluate(*pkt6_, values_));
  217. ASSERT_NO_THROW(baddigit->evaluate(*pkt6_, values_));
  218. ASSERT_NO_THROW(bell->evaluate(*pkt6_, values_));
  219. ASSERT_NO_THROW(foo->evaluate(*pkt6_, values_));
  220. ASSERT_NO_THROW(cookie->evaluate(*pkt6_, values_));
  221. // Check that the evaluation put its value on the values stack.
  222. ASSERT_EQ(7, values_.size());
  223. uint32_t expected = htonl(DHCP_OPTIONS_COOKIE);
  224. EXPECT_EQ(4, values_.top().size());
  225. EXPECT_EQ(0, memcmp(&expected, &values_.top()[0], 4));
  226. values_.pop();
  227. EXPECT_EQ("foo", values_.top());
  228. values_.pop();
  229. EXPECT_EQ("\a", values_.top());
  230. values_.pop();
  231. EXPECT_EQ("", values_.top());
  232. values_.pop();
  233. EXPECT_EQ("", values_.top());
  234. values_.pop();
  235. EXPECT_EQ("", values_.top());
  236. values_.pop();
  237. EXPECT_EQ("", values_.top());
  238. }
  239. // This test checks that a TokenIpAddress, representing an IP address as
  240. // a constant string, can be used in Pkt4/Pkt6 evaluation.
  241. // (The actual packet is not used)
  242. TEST_F(TokenTest, ipaddress) {
  243. TokenPtr bad4;
  244. TokenPtr bad6;
  245. TokenPtr ip4;
  246. TokenPtr ip6;
  247. // Bad IP addresses
  248. ASSERT_NO_THROW(bad4.reset(new TokenIpAddress("10.0.0.0.1")));
  249. ASSERT_NO_THROW(bad6.reset(new TokenIpAddress(":::")));
  250. // IP addresses
  251. ASSERT_NO_THROW(ip4.reset(new TokenIpAddress("10.0.0.1")));
  252. ASSERT_NO_THROW(ip6.reset(new TokenIpAddress("2001:db8::1")));
  253. // Make sure that tokens can be evaluated without exceptions.
  254. ASSERT_NO_THROW(ip4->evaluate(*pkt4_, values_));
  255. ASSERT_NO_THROW(ip6->evaluate(*pkt6_, values_));
  256. ASSERT_NO_THROW(bad4->evaluate(*pkt4_, values_));
  257. ASSERT_NO_THROW(bad6->evaluate(*pkt6_, values_));
  258. // Check that the evaluation put its value on the values stack.
  259. ASSERT_EQ(4, values_.size());
  260. // Check bad addresses (they pushed '' on the value stack)
  261. EXPECT_EQ(0, values_.top().size());
  262. values_.pop();
  263. EXPECT_EQ(0, values_.top().size());
  264. values_.pop();
  265. // Check IPv6 address
  266. uint8_t expected6[] = { 0x20, 1, 0xd, 0xb8, 0, 0, 0, 0,
  267. 0, 0, 0, 0, 0, 0, 0, 1 };
  268. EXPECT_EQ(16, values_.top().size());
  269. EXPECT_EQ(0, memcmp(expected6, &values_.top()[0], 16));
  270. values_.pop();
  271. // Check IPv4 address
  272. uint8_t expected4[] = { 10, 0, 0, 1 };
  273. EXPECT_EQ(4, values_.top().size());
  274. EXPECT_EQ(0, memcmp(expected4, &values_.top()[0], 4));
  275. }
  276. // This test checks if a token representing an option value is able to extract
  277. // the option from an IPv4 packet and properly store the option's value.
  278. TEST_F(TokenTest, optionString4) {
  279. TokenPtr found;
  280. TokenPtr not_found;
  281. // The packets we use have option 100 with a string in them.
  282. ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::TEXTUAL)));
  283. ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::TEXTUAL)));
  284. // This should evaluate to the content of the option 100 (i.e. "hundred4")
  285. ASSERT_NO_THROW(found->evaluate(*pkt4_, values_));
  286. // This should evaluate to "" as there is no option 101.
  287. ASSERT_NO_THROW(not_found->evaluate(*pkt4_, values_));
  288. // There should be 2 values evaluated.
  289. ASSERT_EQ(2, values_.size());
  290. // This is a stack, so the pop order is inversed. We should get the empty
  291. // string first.
  292. EXPECT_EQ("", values_.top());
  293. values_.pop();
  294. // Then the content of the option 100.
  295. EXPECT_EQ("hundred4", values_.top());
  296. }
  297. // This test checks if a token representing option value is able to extract
  298. // the option from an IPv4 packet and properly store its value in a
  299. // hexadecimal format.
  300. TEST_F(TokenTest, optionHexString4) {
  301. TokenPtr found;
  302. TokenPtr not_found;
  303. // The packets we use have option 100 with a string in them.
  304. ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::HEXADECIMAL)));
  305. ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::HEXADECIMAL)));
  306. // This should evaluate to the content of the option 100 (i.e. "hundred4")
  307. ASSERT_NO_THROW(found->evaluate(*pkt4_, values_));
  308. // This should evaluate to "" as there is no option 101.
  309. ASSERT_NO_THROW(not_found->evaluate(*pkt4_, values_));
  310. // There should be 2 values evaluated.
  311. ASSERT_EQ(2, values_.size());
  312. // This is a stack, so the pop order is inversed. We should get the empty
  313. // string first.
  314. EXPECT_EQ("", values_.top());
  315. values_.pop();
  316. // Then the content of the option 100.
  317. EXPECT_EQ("hundred4", values_.top());
  318. }
  319. // This test checks if a token representing an option value is able to check
  320. // the existence of the option from an IPv4 packet.
  321. TEST_F(TokenTest, optionExistsString4) {
  322. TokenPtr found;
  323. TokenPtr not_found;
  324. // The packets we use have option 100 with a string in them.
  325. ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::EXISTS)));
  326. ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::EXISTS)));
  327. ASSERT_NO_THROW(found->evaluate(*pkt4_, values_));
  328. ASSERT_NO_THROW(not_found->evaluate(*pkt4_, values_));
  329. // There should be 2 values evaluated.
  330. ASSERT_EQ(2, values_.size());
  331. // This is a stack, so the pop order is inversed.
  332. EXPECT_EQ("false", values_.top());
  333. values_.pop();
  334. EXPECT_EQ("true", values_.top());
  335. }
  336. // This test checks if a token representing an option value is able to extract
  337. // the option from an IPv6 packet and properly store the option's value.
  338. TEST_F(TokenTest, optionString6) {
  339. TokenPtr found;
  340. TokenPtr not_found;
  341. // The packets we use have option 100 with a string in them.
  342. ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::TEXTUAL)));
  343. ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::TEXTUAL)));
  344. // This should evaluate to the content of the option 100 (i.e. "hundred6")
  345. ASSERT_NO_THROW(found->evaluate(*pkt6_, values_));
  346. // This should evaluate to "" as there is no option 101.
  347. ASSERT_NO_THROW(not_found->evaluate(*pkt6_, values_));
  348. // There should be 2 values evaluated.
  349. ASSERT_EQ(2, values_.size());
  350. // This is a stack, so the pop order is inversed. We should get the empty
  351. // string first.
  352. EXPECT_EQ("", values_.top());
  353. values_.pop();
  354. // Then the content of the option 100.
  355. EXPECT_EQ("hundred6", values_.top());
  356. }
  357. // This test checks if a token representing an option value is able to extract
  358. // the option from an IPv6 packet and properly store its value in hexadecimal
  359. // format.
  360. TEST_F(TokenTest, optionHexString6) {
  361. TokenPtr found;
  362. TokenPtr not_found;
  363. // The packets we use have option 100 with a string in them.
  364. ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::HEXADECIMAL)));
  365. ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::HEXADECIMAL)));
  366. // This should evaluate to the content of the option 100 (i.e. "hundred6")
  367. ASSERT_NO_THROW(found->evaluate(*pkt6_, values_));
  368. // This should evaluate to "" as there is no option 101.
  369. ASSERT_NO_THROW(not_found->evaluate(*pkt6_, values_));
  370. // There should be 2 values evaluated.
  371. ASSERT_EQ(2, values_.size());
  372. // This is a stack, so the pop order is inversed. We should get the empty
  373. // string first.
  374. EXPECT_EQ("", values_.top());
  375. values_.pop();
  376. // Then the content of the option 100.
  377. EXPECT_EQ("hundred6", values_.top());
  378. }
  379. // This test checks if a token representing an option value is able to check
  380. // the existence of the option from an IPv6 packet.
  381. TEST_F(TokenTest, optionExistsString6) {
  382. TokenPtr found;
  383. TokenPtr not_found;
  384. // The packets we use have option 100 with a string in them.
  385. ASSERT_NO_THROW(found.reset(new TokenOption(100, TokenOption::EXISTS)));
  386. ASSERT_NO_THROW(not_found.reset(new TokenOption(101, TokenOption::EXISTS)));
  387. ASSERT_NO_THROW(found->evaluate(*pkt6_, values_));
  388. ASSERT_NO_THROW(not_found->evaluate(*pkt6_, values_));
  389. // There should be 2 values evaluated.
  390. ASSERT_EQ(2, values_.size());
  391. // This is a stack, so the pop order is inversed.
  392. EXPECT_EQ("false", values_.top());
  393. values_.pop();
  394. EXPECT_EQ("true", values_.top());
  395. }
  396. // This test checks that the existing relay option can be found.
  397. TEST_F(TokenTest, relayOption) {
  398. // Insert relay option with sub-options 1 and 13
  399. insertRelay4Option();
  400. // Creating the token should be safe.
  401. ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
  402. // We should be able to evaluate it.
  403. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  404. // we should have one value on the stack
  405. ASSERT_EQ(1, values_.size());
  406. // The option should be found and relay[13] should evaluate to the
  407. // content of that sub-option, i.e. "thirteen"
  408. EXPECT_EQ("thirteen", values_.top());
  409. }
  410. // This test checks that the code properly handles cases when
  411. // there is a RAI option, but there's no requested sub-option.
  412. TEST_F(TokenTest, relayOptionNoSuboption) {
  413. // Insert relay option with sub-options 1 and 13
  414. insertRelay4Option();
  415. // Creating the token should be safe.
  416. ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(15, TokenOption::TEXTUAL)));
  417. // We should be able to evaluate it.
  418. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  419. // we should have one value on the stack
  420. ASSERT_EQ(1, values_.size());
  421. // The option should NOT be found (there is no sub-option 15),
  422. // so the expression should evaluate to ""
  423. EXPECT_EQ("", values_.top());
  424. }
  425. // This test checks that the code properly handles cases when
  426. // there's no RAI option at all.
  427. TEST_F(TokenTest, relayOptionNoRai) {
  428. // We didn't call insertRelay4Option(), so there's no RAI option.
  429. // Creating the token should be safe.
  430. ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
  431. // We should be able to evaluate it.
  432. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  433. // we should have one value on the stack
  434. ASSERT_EQ(1, values_.size());
  435. // The option should NOT be found (there is no sub-option 13),
  436. // so the expression should evaluate to ""
  437. EXPECT_EQ("", values_.top());
  438. }
  439. // This test checks that only the RAI is searched for the requested
  440. // sub-option.
  441. TEST_F(TokenTest, relayRAIOnly) {
  442. // Insert relay option with sub-options 1 and 13
  443. insertRelay4Option();
  444. // Add options 13 and 70 to the packet.
  445. OptionPtr opt13(new OptionString(Option::V4, 13, "THIRTEEN"));
  446. OptionPtr opt70(new OptionString(Option::V4, 70, "SEVENTY"));
  447. pkt4_->addOption(opt13);
  448. pkt4_->addOption(opt70);
  449. // The situation is as follows:
  450. // Packet:
  451. // - option 13 (containing "THIRTEEN")
  452. // - option 82 (rai)
  453. // - option 1 (containing "one")
  454. // - option 13 (containing "thirteen")
  455. // Let's try to get option 13. It should get the one from RAI
  456. ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(13, TokenOption::TEXTUAL)));
  457. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  458. ASSERT_EQ(1, values_.size());
  459. EXPECT_EQ("thirteen", values_.top());
  460. // Try to get option 1. It should get the one from RAI
  461. clearStack();
  462. ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(1, TokenOption::TEXTUAL)));
  463. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  464. ASSERT_EQ(1, values_.size());
  465. EXPECT_EQ("one", values_.top());
  466. // Try to get option 70. It should fail, as there's no such
  467. // sub option in RAI.
  468. clearStack();
  469. ASSERT_NO_THROW(t_.reset(new TokenRelay4Option(70, TokenOption::TEXTUAL)));
  470. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  471. ASSERT_EQ(1, values_.size());
  472. EXPECT_EQ("", values_.top());
  473. }
  474. // This test checks if a token representing an == operator is able to
  475. // compare two values (with incorrectly built stack).
  476. TEST_F(TokenTest, optionEqualInvalid) {
  477. ASSERT_NO_THROW(t_.reset(new TokenEqual()));
  478. // CASE 1: There's not enough values on the stack. == is an operator that
  479. // takes two parameters. There are 0 on the stack.
  480. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  481. // CASE 2: One value is still not enough.
  482. values_.push("foo");
  483. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  484. }
  485. // This test checks if a token representing an == operator is able to
  486. // compare two different values.
  487. TEST_F(TokenTest, optionEqualFalse) {
  488. ASSERT_NO_THROW(t_.reset(new TokenEqual()));
  489. values_.push("foo");
  490. values_.push("bar");
  491. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  492. // After evaluation there should be a single value that represents
  493. // result of "foo" == "bar" comparision.
  494. ASSERT_EQ(1, values_.size());
  495. EXPECT_EQ("false", values_.top());
  496. }
  497. // This test checks if a token representing an == operator is able to
  498. // compare two identical values.
  499. TEST_F(TokenTest, optionEqualTrue) {
  500. ASSERT_NO_THROW(t_.reset(new TokenEqual()));
  501. values_.push("foo");
  502. values_.push("foo");
  503. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  504. // After evaluation there should be a single value that represents
  505. // result of "foo" == "foo" comparision.
  506. ASSERT_EQ(1, values_.size());
  507. EXPECT_EQ("true", values_.top());
  508. }
  509. // This test checks if a token representing a not is able to
  510. // negate a boolean value (with incorrectly built stack).
  511. TEST_F(TokenTest, operatorNotInvalid) {
  512. ASSERT_NO_THROW(t_.reset(new TokenNot()));
  513. // CASE 1: The stack is empty.
  514. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  515. // CASE 2: The top value is not a boolean
  516. values_.push("foo");
  517. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError);
  518. }
  519. // This test checks if a token representing a not operator is able to
  520. // negate a boolean value.
  521. TEST_F(TokenTest, operatorNot) {
  522. ASSERT_NO_THROW(t_.reset(new TokenNot()));
  523. values_.push("true");
  524. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  525. // After evaluation there should be the negation of the value.
  526. ASSERT_EQ(1, values_.size());
  527. EXPECT_EQ("false", values_.top());
  528. // Double negation is identity.
  529. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  530. ASSERT_EQ(1, values_.size());
  531. EXPECT_EQ("true", values_.top());
  532. }
  533. // This test checks if a token representing an and is able to
  534. // conjugate two values (with incorrectly built stack).
  535. TEST_F(TokenTest, operatorAndInvalid) {
  536. ASSERT_NO_THROW(t_.reset(new TokenAnd()));
  537. // CASE 1: There's not enough values on the stack. and is an operator that
  538. // takes two parameters. There are 0 on the stack.
  539. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  540. // CASE 2: One value is still not enough.
  541. values_.push("foo");
  542. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  543. // CASE 3: The two values must be logical
  544. values_.push("true");
  545. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError);
  546. // Swap the 2 values
  547. values_.push("true");
  548. values_.push("foo");
  549. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError);
  550. }
  551. // This test checks if a token representing an and operator is able to
  552. // conjugate false with another logical
  553. TEST_F(TokenTest, operatorAndFalse) {
  554. ASSERT_NO_THROW(t_.reset(new TokenAnd()));
  555. values_.push("true");
  556. values_.push("false");
  557. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  558. // After evaluation there should be a single "false" value
  559. ASSERT_EQ(1, values_.size());
  560. EXPECT_EQ("false", values_.top());
  561. // After true and false, checks false and true
  562. values_.push("true");
  563. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  564. ASSERT_EQ(1, values_.size());
  565. EXPECT_EQ("false", values_.top());
  566. // And false and false
  567. values_.push("false");
  568. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  569. ASSERT_EQ(1, values_.size());
  570. EXPECT_EQ("false", values_.top());
  571. }
  572. // This test checks if a token representing an and is able to
  573. // conjugate two true values.
  574. TEST_F(TokenTest, operatorAndTrue) {
  575. ASSERT_NO_THROW(t_.reset(new TokenAnd()));
  576. values_.push("true");
  577. values_.push("true");
  578. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  579. // After evaluation there should be a single "true" value
  580. ASSERT_EQ(1, values_.size());
  581. EXPECT_EQ("true", values_.top());
  582. }
  583. // This test checks if a token representing an or is able to
  584. // combinate two values (with incorrectly built stack).
  585. TEST_F(TokenTest, operatorOrInvalid) {
  586. ASSERT_NO_THROW(t_.reset(new TokenOr()));
  587. // CASE 1: There's not enough values on the stack. or is an operator that
  588. // takes two parameters. There are 0 on the stack.
  589. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  590. // CASE 2: One value is still not enough.
  591. values_.push("foo");
  592. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  593. // CASE 3: The two values must be logical
  594. values_.push("true");
  595. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError);
  596. // Swap the 2 values
  597. values_.push("true");
  598. values_.push("foo");
  599. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalTypeError);
  600. }
  601. // This test checks if a token representing an or is able to
  602. // conjugate two false values.
  603. TEST_F(TokenTest, operatorOrFalse) {
  604. ASSERT_NO_THROW(t_.reset(new TokenOr()));
  605. values_.push("false");
  606. values_.push("false");
  607. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  608. // After evaluation there should be a single "false" value
  609. ASSERT_EQ(1, values_.size());
  610. EXPECT_EQ("false", values_.top());
  611. }
  612. // This test checks if a token representing an == operator is able to
  613. // conjugate true with another logical
  614. TEST_F(TokenTest, operatorOrTrue) {
  615. ASSERT_NO_THROW(t_.reset(new TokenOr()));
  616. values_.push("false");
  617. values_.push("true");
  618. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  619. // After evaluation there should be a single "true" value
  620. ASSERT_EQ(1, values_.size());
  621. EXPECT_EQ("true", values_.top());
  622. // After false or true, checks true or false
  623. values_.push("false");
  624. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  625. ASSERT_EQ(1, values_.size());
  626. EXPECT_EQ("true", values_.top());
  627. // And true or true
  628. values_.push("true");
  629. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  630. ASSERT_EQ(1, values_.size());
  631. EXPECT_EQ("true", values_.top());
  632. }
  633. };
  634. // This test checks if a token representing a substring request
  635. // throws an exception if there aren't enough values on the stack.
  636. // The stack from the top is: length, start, string.
  637. // The actual packet is not used.
  638. TEST_F(TokenTest, substringNotEnoughValues) {
  639. ASSERT_NO_THROW(t_.reset(new TokenSubstring()));
  640. // Subsring requires three values on the stack, try
  641. // with 0, 1 and 2 all should throw an exception
  642. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  643. values_.push("");
  644. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  645. values_.push("0");
  646. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  647. // Three should work
  648. values_.push("0");
  649. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  650. // As we had an empty string to start with we should have an empty
  651. // one after the evaluate
  652. ASSERT_EQ(1, values_.size());
  653. EXPECT_EQ("", values_.top());
  654. }
  655. // Test getting the whole string in different ways
  656. TEST_F(TokenTest, substringWholeString) {
  657. // Get the whole string
  658. verifySubstringEval("foobar", "0", "6", "foobar");
  659. // Get the whole string with "all"
  660. verifySubstringEval("foobar", "0", "all", "foobar");
  661. // Get the whole string with an extra long number
  662. verifySubstringEval("foobar", "0", "123456", "foobar");
  663. // Get the whole string counting from the back
  664. verifySubstringEval("foobar", "-6", "all", "foobar");
  665. }
  666. // Test getting a suffix, in this case the last 3 characters
  667. TEST_F(TokenTest, substringTrailer) {
  668. verifySubstringEval("foobar", "3", "3", "bar");
  669. verifySubstringEval("foobar", "3", "all", "bar");
  670. verifySubstringEval("foobar", "-3", "all", "bar");
  671. verifySubstringEval("foobar", "-3", "123", "bar");
  672. }
  673. // Test getting the middle of the string in different ways
  674. TEST_F(TokenTest, substringMiddle) {
  675. verifySubstringEval("foobar", "1", "4", "ooba");
  676. verifySubstringEval("foobar", "-5", "4", "ooba");
  677. verifySubstringEval("foobar", "-1", "-4", "ooba");
  678. verifySubstringEval("foobar", "5", "-4", "ooba");
  679. }
  680. // Test getting the last letter in different ways
  681. TEST_F(TokenTest, substringLastLetter) {
  682. verifySubstringEval("foobar", "5", "all", "r");
  683. verifySubstringEval("foobar", "5", "1", "r");
  684. verifySubstringEval("foobar", "5", "5", "r");
  685. verifySubstringEval("foobar", "-1", "all", "r");
  686. verifySubstringEval("foobar", "-1", "1", "r");
  687. verifySubstringEval("foobar", "-1", "5", "r");
  688. }
  689. // Test we get only what is available if we ask for a longer string
  690. TEST_F(TokenTest, substringLength) {
  691. // Test off the front
  692. verifySubstringEval("foobar", "0", "-4", "");
  693. verifySubstringEval("foobar", "1", "-4", "f");
  694. verifySubstringEval("foobar", "2", "-4", "fo");
  695. verifySubstringEval("foobar", "3", "-4", "foo");
  696. // and the back
  697. verifySubstringEval("foobar", "3", "4", "bar");
  698. verifySubstringEval("foobar", "4", "4", "ar");
  699. verifySubstringEval("foobar", "5", "4", "r");
  700. verifySubstringEval("foobar", "6", "4", "");
  701. }
  702. // Test that we get nothing if the starting postion is out of the string
  703. TEST_F(TokenTest, substringStartingPosition) {
  704. // Off the front
  705. verifySubstringEval("foobar", "-7", "1", "");
  706. verifySubstringEval("foobar", "-7", "-11", "");
  707. verifySubstringEval("foobar", "-7", "all", "");
  708. // and the back
  709. verifySubstringEval("foobar", "6", "1", "");
  710. verifySubstringEval("foobar", "6", "-11", "");
  711. verifySubstringEval("foobar", "6", "all", "");
  712. }
  713. // Check what happens if we use strings that aren't numbers for start or length
  714. // We should return the empty string
  715. TEST_F(TokenTest, substringBadParams) {
  716. verifySubstringEval("foobar", "0ick", "all", "", true);
  717. verifySubstringEval("foobar", "ick0", "all", "", true);
  718. verifySubstringEval("foobar", "ick", "all", "", true);
  719. verifySubstringEval("foobar", "0", "ick", "", true);
  720. verifySubstringEval("foobar", "0", "0ick", "", true);
  721. verifySubstringEval("foobar", "0", "ick0", "", true);
  722. verifySubstringEval("foobar", "0", "allaboard", "", true);
  723. }
  724. // lastly check that we don't get anything if the string is empty or
  725. // we don't ask for any characters from it.
  726. TEST_F(TokenTest, substringReturnEmpty) {
  727. verifySubstringEval("", "0", "all", "");
  728. verifySubstringEval("foobar", "0", "0", "");
  729. }
  730. // Check if we can use the substring and equal tokens together
  731. // We put the result on the stack first then the substring values
  732. // then evaluate the substring which should leave the original
  733. // result on the bottom with the substring result on next.
  734. // Evaulating the equals should produce true for the first
  735. // and false for the second.
  736. // throws an exception if there aren't enough values on the stack.
  737. // The stack from the top is: length, start, string.
  738. // The actual packet is not used.
  739. TEST_F(TokenTest, substringEquals) {
  740. TokenPtr tequal;
  741. ASSERT_NO_THROW(t_.reset(new TokenSubstring()));
  742. ASSERT_NO_THROW(tequal.reset(new TokenEqual()));
  743. // The final expected value
  744. values_.push("ooba");
  745. // The substring values
  746. // Subsring requires three values on the stack, try
  747. // with 0, 1 and 2 all should throw an exception
  748. values_.push("foobar");
  749. values_.push("1");
  750. values_.push("4");
  751. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  752. // we should have two values on the stack
  753. ASSERT_EQ(2, values_.size());
  754. // next the equals eval
  755. EXPECT_NO_THROW(tequal->evaluate(*pkt4_, values_));
  756. ASSERT_EQ(1, values_.size());
  757. EXPECT_EQ("true", values_.top());
  758. // get rid of the result
  759. values_.pop();
  760. // and try it again but with a bad final value
  761. // The final expected value
  762. values_.push("foob");
  763. // The substring values
  764. // Subsring requires three values on the stack, try
  765. // with 0, 1 and 2 all should throw an exception
  766. values_.push("foobar");
  767. values_.push("1");
  768. values_.push("4");
  769. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  770. // we should have two values on the stack
  771. ASSERT_EQ(2, values_.size());
  772. // next the equals eval
  773. EXPECT_NO_THROW(tequal->evaluate(*pkt4_, values_));
  774. ASSERT_EQ(1, values_.size());
  775. EXPECT_EQ("false", values_.top());
  776. }
  777. // This test checks if a token representing a concat request
  778. // throws an exception if there aren't enough values on the stack.
  779. // The actual packet is not used.
  780. TEST_F(TokenTest, concat) {
  781. ASSERT_NO_THROW(t_.reset(new TokenConcat()));
  782. // Concat requires two values on the stack, try
  783. // with 0 and 1 both should throw an exception
  784. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  785. values_.push("foo");
  786. EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
  787. // Two should work
  788. values_.push("bar");
  789. EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
  790. // Check the result
  791. ASSERT_EQ(1, values_.size());
  792. EXPECT_EQ("foobar", values_.top());
  793. }