token_unittest.cc 37 KB

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