evaluate_unittest.cc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. // Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <eval/evaluate.h>
  16. #include <eval/token.h>
  17. #include <dhcp/pkt4.h>
  18. #include <dhcp/pkt6.h>
  19. #include <dhcp/dhcp4.h>
  20. #include <dhcp/dhcp6.h>
  21. #include <dhcp/option_string.h>
  22. #include <boost/shared_ptr.hpp>
  23. #include <boost/scoped_ptr.hpp>
  24. #include <gtest/gtest.h>
  25. using namespace std;
  26. using namespace isc::dhcp;
  27. namespace {
  28. /// @brief Test fixture for testing evaluation.
  29. ///
  30. /// This class provides several convenience objects to be used during testing
  31. /// of the evaluation of classification expressions.
  32. class EvaluateTest : public ::testing::Test {
  33. public:
  34. /// @brief Initializes Pkt4,Pkt6 and options that can be useful for
  35. /// evaluation tests.
  36. EvaluateTest() {
  37. e_.clear();
  38. pkt4_.reset(new Pkt4(DHCPDISCOVER, 12345));
  39. pkt6_.reset(new Pkt6(DHCPV6_SOLICIT, 12345));
  40. // Add options with easily identifiable strings in them
  41. option_str4_.reset(new OptionString(Option::V4, 100, "hundred4"));
  42. option_str6_.reset(new OptionString(Option::V6, 100, "hundred6"));
  43. pkt4_->addOption(option_str4_);
  44. pkt6_->addOption(option_str6_);
  45. }
  46. Expression e_; ///< An expression
  47. bool result_; ///< A decision
  48. Pkt4Ptr pkt4_; ///< A stub DHCPv4 packet
  49. Pkt6Ptr pkt6_; ///< A stub DHCPv6 packet
  50. OptionPtr option_str4_; ///< A string option for DHCPv4
  51. OptionPtr option_str6_; ///< A string option for DHCPv6
  52. /// @todo: Add more option types here
  53. };
  54. // This checks the empty expression: it should raise EvalBadStack
  55. // when evaluated with a Pkt4. (The actual packet is not used)
  56. TEST_F(EvaluateTest, empty4) {
  57. ASSERT_THROW(evaluate(e_, *pkt4_), EvalBadStack);
  58. }
  59. // This checks the empty expression: it should raise EvalBadStack
  60. // when evaluated with a Pkt6. (The actual packet is not used)
  61. TEST_F(EvaluateTest, empty6) {
  62. ASSERT_THROW(evaluate(e_, *pkt6_), EvalBadStack);
  63. }
  64. // This checks the { "false" } expression: it should return false
  65. // when evaluated with a Pkt4. (The actual packet is not used)
  66. TEST_F(EvaluateTest, false4) {
  67. TokenPtr tfalse;
  68. ASSERT_NO_THROW(tfalse.reset(new TokenString("false")));
  69. e_.push_back(tfalse);
  70. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt4_));
  71. EXPECT_FALSE(result_);
  72. }
  73. // This checks the { "false" } expression: it should return false
  74. // when evaluated with a Pkt6. (The actual packet is not used)
  75. TEST_F(EvaluateTest, false6) {
  76. TokenPtr tfalse;
  77. ASSERT_NO_THROW(tfalse.reset(new TokenString("false")));
  78. e_.push_back(tfalse);
  79. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt6_));
  80. EXPECT_FALSE(result_);
  81. }
  82. // This checks the { "true" } expression: it should return true
  83. // when evaluated with a Pkt4. (The actual packet is not used)
  84. TEST_F(EvaluateTest, true4) {
  85. TokenPtr ttrue;
  86. ASSERT_NO_THROW(ttrue.reset(new TokenString("true")));
  87. e_.push_back(ttrue);
  88. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt4_));
  89. EXPECT_TRUE(result_);
  90. }
  91. // This checks the { "true" } expression: it should return true
  92. // when evaluated with a Pkt6. (The actual packet is not used)
  93. TEST_F(EvaluateTest, true6) {
  94. TokenPtr ttrue;
  95. ASSERT_NO_THROW(ttrue.reset(new TokenString("true")));
  96. e_.push_back(ttrue);
  97. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt6_));
  98. EXPECT_TRUE(result_);
  99. }
  100. // This checks the evaluation must lead to "false" or "true"
  101. // with a Pkt4. (The actual packet is not used)
  102. TEST_F(EvaluateTest, bad4) {
  103. TokenPtr bad;
  104. ASSERT_NO_THROW(bad.reset(new TokenString("bad")));
  105. e_.push_back(bad);
  106. ASSERT_THROW(evaluate(e_, *pkt4_), EvalTypeError);
  107. }
  108. // This checks the evaluation must lead to "false" or "true"
  109. // with a Pkt6. (The actual packet is not used)
  110. TEST_F(EvaluateTest, bad6) {
  111. TokenPtr bad;
  112. ASSERT_NO_THROW(bad.reset(new TokenString("bad")));
  113. e_.push_back(bad);
  114. ASSERT_THROW(evaluate(e_, *pkt6_), EvalTypeError);
  115. }
  116. // This checks the evaluation must leave only one value on the stack
  117. // with a Pkt4. (The actual packet is not used)
  118. TEST_F(EvaluateTest, two4) {
  119. TokenPtr ttrue;
  120. ASSERT_NO_THROW(ttrue.reset(new TokenString("true")));
  121. e_.push_back(ttrue);
  122. e_.push_back(ttrue);
  123. ASSERT_THROW(evaluate(e_, *pkt4_), EvalBadStack);
  124. }
  125. // This checks the evaluation must leave only one value on the stack
  126. // with a Pkt6. (The actual packet is not used)
  127. TEST_F(EvaluateTest, two6) {
  128. TokenPtr ttrue;
  129. ASSERT_NO_THROW(ttrue.reset(new TokenString("true")));
  130. e_.push_back(ttrue);
  131. e_.push_back(ttrue);
  132. ASSERT_THROW(evaluate(e_, *pkt6_), EvalBadStack);
  133. }
  134. // A more complex test evaluated with a Pkt4. (The actual packet is not used)
  135. TEST_F(EvaluateTest, compare4) {
  136. TokenPtr tfoo;
  137. TokenPtr tbar;
  138. TokenPtr tequal;
  139. ASSERT_NO_THROW(tfoo.reset(new TokenString("foo")));
  140. e_.push_back(tfoo);
  141. ASSERT_NO_THROW(tbar.reset(new TokenString("bar")));
  142. e_.push_back(tbar);
  143. ASSERT_NO_THROW(tequal.reset(new TokenEqual()));
  144. e_.push_back(tequal);
  145. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt4_));
  146. EXPECT_FALSE(result_);
  147. }
  148. // A more complex test evaluated with a Pkt6. (The actual packet is not used)
  149. TEST_F(EvaluateTest, compare6) {
  150. TokenPtr tfoo;
  151. TokenPtr tbar;
  152. TokenPtr tequal;
  153. ASSERT_NO_THROW(tfoo.reset(new TokenString("foo")));
  154. e_.push_back(tfoo);
  155. ASSERT_NO_THROW(tbar.reset(new TokenString("bar")));
  156. e_.push_back(tbar);
  157. ASSERT_NO_THROW(tequal.reset(new TokenEqual()));
  158. e_.push_back(tequal);
  159. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt6_));
  160. EXPECT_FALSE(result_);
  161. }
  162. // A test using packets.
  163. TEST_F(EvaluateTest, packet) {
  164. TokenPtr toption;
  165. TokenPtr tstring;
  166. TokenPtr tequal;
  167. ASSERT_NO_THROW(toption.reset(new TokenOption(100, TokenOption::TEXTUAL)));
  168. e_.push_back(toption);
  169. ASSERT_NO_THROW(tstring.reset(new TokenString("hundred4")));
  170. e_.push_back(tstring);
  171. ASSERT_NO_THROW(tequal.reset(new TokenEqual()));
  172. e_.push_back(tequal);
  173. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt4_));
  174. EXPECT_TRUE(result_);
  175. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt6_));
  176. EXPECT_FALSE(result_);
  177. }
  178. // A test which compares option value represented in hexadecimal format.
  179. TEST_F(EvaluateTest, optionHex) {
  180. TokenPtr toption;
  181. TokenPtr tstring;
  182. TokenPtr tequal;
  183. ASSERT_NO_THROW(toption.reset(new TokenOption(100, TokenOption::HEXADECIMAL)));
  184. e_.push_back(toption);
  185. ASSERT_NO_THROW(tstring.reset(new TokenString("hundred4")));
  186. e_.push_back(tstring);
  187. ASSERT_NO_THROW(tequal.reset(new TokenEqual()));
  188. e_.push_back(tequal);
  189. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt4_));
  190. EXPECT_TRUE(result_);
  191. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt6_));
  192. EXPECT_FALSE(result_);
  193. }
  194. // A test using substring on an option.
  195. TEST_F(EvaluateTest, complex) {
  196. TokenPtr toption;
  197. TokenPtr tstart;
  198. TokenPtr tlength;
  199. TokenPtr tsubstring;
  200. TokenPtr tstring;
  201. TokenPtr tequal;
  202. // Get the option, i.e., "hundred[46]"
  203. ASSERT_NO_THROW(toption.reset(new TokenOption(100, TokenOption::TEXTUAL)));
  204. e_.push_back(toption);
  205. // Get substring("hundred[46]", 0, 7), i.e., "hundred"
  206. ASSERT_NO_THROW(tstart.reset(new TokenString("0")));
  207. e_.push_back(tstart);
  208. ASSERT_NO_THROW(tlength.reset(new TokenString("7")));
  209. e_.push_back(tlength);
  210. ASSERT_NO_THROW(tsubstring.reset(new TokenSubstring()));
  211. e_.push_back(tsubstring);
  212. // Compare with "hundred"
  213. ASSERT_NO_THROW(tstring.reset(new TokenString("hundred")));
  214. e_.push_back(tstring);
  215. ASSERT_NO_THROW(tequal.reset(new TokenEqual()));
  216. e_.push_back(tequal);
  217. // Should return true for v4 and v6 packets
  218. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt4_));
  219. EXPECT_TRUE(result_);
  220. ASSERT_NO_THROW(result_ = evaluate(e_, *pkt6_));
  221. EXPECT_TRUE(result_);
  222. }
  223. };