option6_int_array_unittest.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. // Copyright (C) 2012 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 <dhcp/dhcp6.h>
  16. #include <dhcp/option.h>
  17. #include <dhcp/option6_int_array.h>
  18. #include <dhcp/option6_iaaddr.h>
  19. #include <util/buffer.h>
  20. #include <boost/pointer_cast.hpp>
  21. #include <gtest/gtest.h>
  22. using namespace std;
  23. using namespace isc;
  24. using namespace isc::dhcp;
  25. using namespace isc::asiolink;
  26. using namespace isc::util;
  27. namespace {
  28. /// @brief Option6IntArray test class.
  29. class Option6IntArrayTest : public ::testing::Test {
  30. public:
  31. /// @brief Constructor.
  32. ///
  33. /// Initializes the option buffer with some data.
  34. Option6IntArrayTest(): buf_(255), out_buf_(255) {
  35. for (int i = 0; i < 255; i++) {
  36. buf_[i] = 255 - i;
  37. }
  38. }
  39. /// @brief Test parsing buffer into array of int8_t or uint8_t values.
  40. ///
  41. /// @warning this function does not perform type check. Make
  42. /// sure that only int8_t or uint8_t type is used.
  43. ///
  44. /// @tparam T int8_t or uint8_t.
  45. template<typename T>
  46. void bufferToIntTest8() {
  47. // Create option that conveys array of multiple uint8_t or int8_t values.
  48. // In fact there is no need to use this template class for array
  49. // of uint8_t values because Option class is sufficient - it
  50. // returns the buffer which is actually the array of uint8_t.
  51. // However, since we allow using uint8_t types with this template
  52. // class we have to test it here.
  53. boost::shared_ptr<Option6IntArray<T> > opt;
  54. const int opt_len = 10;
  55. const uint16_t opt_code = 80;
  56. // Constructor throws exception if provided buffer is empty.
  57. EXPECT_THROW(
  58. Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
  59. isc::OutOfRange
  60. );
  61. // Provided buffer is not empty so it should not throw exception.
  62. ASSERT_NO_THROW(
  63. opt = boost::shared_ptr<
  64. Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
  65. buf_.begin() + opt_len))
  66. );
  67. EXPECT_EQ(Option::V6, opt->getUniverse());
  68. EXPECT_EQ(opt_code, opt->getType());
  69. // Option should return the collection of int8_t or uint8_t values that
  70. // we can match with the buffer we used to create the option.
  71. std::vector<T> values = opt->getValues();
  72. // We need to copy values from the buffer to apply sign if signed
  73. // type is used.
  74. std::vector<T> reference_values;
  75. for (int i = 0; i < opt_len; ++i) {
  76. // Values have been read from the buffer in network
  77. // byte order. We put them back in the same order here.
  78. reference_values.push_back(static_cast<T>(buf_[i]));
  79. }
  80. // Compare the values against the reference buffer.
  81. ASSERT_EQ(opt_len, values.size());
  82. EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.begin()
  83. + opt_len, values.begin()));
  84. // test for pack()
  85. opt->pack(out_buf_);
  86. // Data length is 10 bytes.
  87. EXPECT_EQ(10, opt->len() - opt->getHeaderLen());
  88. EXPECT_EQ(opt_code, opt->getType());
  89. // The total length is 10 bytes for data and 4 bytes for header.
  90. ASSERT_EQ(14, out_buf_.getLength());
  91. // Check if pack worked properly:
  92. InputBuffer out(out_buf_.getData(), out_buf_.getLength());
  93. // if option type is correct
  94. EXPECT_EQ(opt_code, out.readUint16());
  95. // if option length is correct
  96. EXPECT_EQ(10, out.readUint16());
  97. // if data is correct
  98. std::vector<uint8_t> out_data;
  99. ASSERT_NO_THROW(out.readVector(out_data, opt_len));
  100. ASSERT_EQ(opt_len, out_data.size());
  101. EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
  102. }
  103. /// @brief Test parsing buffer into array of int16_t or uint16_t values.
  104. ///
  105. /// @warning this function does not perform type check. Make
  106. /// sure that only int16_t or uint16_t type is used.
  107. ///
  108. /// @tparam T int16_t or uint16_t.
  109. template<typename T>
  110. void bufferToIntTest16() {
  111. // Create option that conveys array of multiple uint16_t or int16_t values.
  112. boost::shared_ptr<Option6IntArray<T> > opt;
  113. const int opt_len = 20;
  114. const uint16_t opt_code = 81;
  115. // Constructor throws exception if provided buffer is empty.
  116. EXPECT_THROW(
  117. Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
  118. isc::OutOfRange
  119. );
  120. // Constructor throws exception if provided buffer's length is not
  121. // multiple of 2-bytes.
  122. EXPECT_THROW(
  123. Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin() + 5),
  124. isc::OutOfRange
  125. );
  126. // Now the buffer length is correct.
  127. ASSERT_NO_THROW(
  128. opt = boost::shared_ptr<
  129. Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
  130. buf_.begin() + opt_len))
  131. );
  132. EXPECT_EQ(Option::V6, opt->getUniverse());
  133. EXPECT_EQ(opt_code, opt->getType());
  134. // Option should return vector of uint16_t values which should be
  135. // constructed from the buffer we provided.
  136. std::vector<T> values = opt->getValues();
  137. ASSERT_EQ(opt_len, values.size() * sizeof(T));
  138. // Create reference values from the buffer so as we can
  139. // simply compare two vectors.
  140. std::vector<T> reference_values;
  141. for (int i = 0; i < opt_len; i += 2) {
  142. reference_values.push_back((buf_[i] << 8) |
  143. buf_[i + 1]);
  144. }
  145. EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
  146. values.begin()));
  147. // Test for pack()
  148. opt->pack(out_buf_);
  149. // Data length is 20 bytes.
  150. EXPECT_EQ(20, opt->len() - opt->getHeaderLen());
  151. EXPECT_EQ(opt_code, opt->getType());
  152. // The total length is 20 bytes for data and 4 bytes for header.
  153. ASSERT_EQ(24, out_buf_.getLength());
  154. // Check if pack worked properly:
  155. InputBuffer out(out_buf_.getData(), out_buf_.getLength());
  156. // if option type is correct
  157. EXPECT_EQ(opt_code, out.readUint16());
  158. // if option length is correct
  159. EXPECT_EQ(20, out.readUint16());
  160. // if data is correct
  161. std::vector<uint8_t> out_data;
  162. ASSERT_NO_THROW(out.readVector(out_data, opt_len));
  163. ASSERT_EQ(opt_len, out_data.size());
  164. EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
  165. }
  166. /// @brief Test parsing buffer into array of int32_t or uint32_t values.
  167. ///
  168. /// @warning this function does not perform type check. Make
  169. /// sure that only int32_t or uint32_t type is used.
  170. ///
  171. /// @tparam T int32_t or uint32_t.
  172. template<typename T>
  173. void bufferToIntTest32() {
  174. // Create option that conveys array of multiple uint16_t values.
  175. boost::shared_ptr<Option6IntArray<T> > opt;
  176. const int opt_len = 40;
  177. const uint16_t opt_code = 82;
  178. // Constructor throws exception if provided buffer is empty.
  179. EXPECT_THROW(
  180. Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
  181. isc::OutOfRange
  182. );
  183. // Constructor throws exception if provided buffer's length is not
  184. // multiple of 4-bytes.
  185. EXPECT_THROW(
  186. Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin() + 9),
  187. isc::OutOfRange
  188. );
  189. // Now the buffer length is correct.
  190. ASSERT_NO_THROW(
  191. opt = boost::shared_ptr<
  192. Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
  193. buf_.begin() + opt_len))
  194. );
  195. EXPECT_EQ(Option::V6, opt->getUniverse());
  196. EXPECT_EQ(opt_code, opt->getType());
  197. // Option should return vector of uint32_t values which should be
  198. // constructed from the buffer we provided.
  199. std::vector<T> values = opt->getValues();
  200. ASSERT_EQ(opt_len, values.size() * sizeof(T));
  201. // Create reference values from the buffer so as we can
  202. // simply compare two vectors.
  203. std::vector<T> reference_values;
  204. for (int i = 0; i < opt_len; i += 4) {
  205. reference_values.push_back((buf_[i] << 24) |
  206. (buf_[i + 1] << 16 & 0x00FF0000) |
  207. (buf_[i + 2] << 8 & 0xFF00) |
  208. (buf_[i + 3] & 0xFF));
  209. }
  210. EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
  211. values.begin()));
  212. // Test for pack()
  213. opt->pack(out_buf_);
  214. // Data length is 40 bytes.
  215. EXPECT_EQ(40, opt->len() - opt->getHeaderLen());
  216. EXPECT_EQ(opt_code, opt->getType());
  217. // The total length is 40 bytes for data and 4 bytes for header.
  218. ASSERT_EQ(44, out_buf_.getLength());
  219. // Check if pack worked properly:
  220. InputBuffer out(out_buf_.getData(), out_buf_.getLength());
  221. // if option type is correct
  222. EXPECT_EQ(opt_code, out.readUint16());
  223. // if option length is correct
  224. EXPECT_EQ(40, out.readUint16());
  225. // if data is correct
  226. std::vector<uint8_t> out_data;
  227. ASSERT_NO_THROW(out.readVector(out_data, opt_len));
  228. ASSERT_EQ(opt_len, out_data.size());
  229. EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
  230. }
  231. OptionBuffer buf_; ///< Option buffer
  232. OutputBuffer out_buf_; ///< Output buffer
  233. };
  234. /// @todo: below, there is a bunch of tests for options that
  235. /// convey unsigned values. We should maybe extend these tests for
  236. /// signed types too.
  237. TEST_F(Option6IntArrayTest, useInvalidType) {
  238. const uint16_t opt_code = 80;
  239. EXPECT_THROW(
  240. boost::scoped_ptr<
  241. Option6IntArray<bool> >(new Option6IntArray<bool>(opt_code, OptionBuffer(5))),
  242. InvalidDataType
  243. );
  244. EXPECT_THROW(
  245. boost::scoped_ptr<
  246. Option6IntArray<int64_t> >(new Option6IntArray<int64_t>(opt_code,
  247. OptionBuffer(10))),
  248. InvalidDataType
  249. );
  250. }
  251. TEST_F(Option6IntArrayTest, bufferToUint8) {
  252. bufferToIntTest8<uint8_t>();
  253. }
  254. TEST_F(Option6IntArrayTest, bufferToInt8) {
  255. bufferToIntTest8<int8_t>();
  256. }
  257. TEST_F(Option6IntArrayTest, bufferToUint16) {
  258. bufferToIntTest16<uint16_t>();
  259. }
  260. TEST_F(Option6IntArrayTest, bufferToInt16) {
  261. bufferToIntTest16<int16_t>();
  262. }
  263. TEST_F(Option6IntArrayTest, bufferToUint32) {
  264. bufferToIntTest32<uint32_t>();
  265. }
  266. TEST_F(Option6IntArrayTest, bufferToInt32) {
  267. bufferToIntTest32<int32_t>();
  268. }
  269. TEST_F(Option6IntArrayTest, setValuesUint8) {
  270. const uint16_t opt_code = 100;
  271. // Create option with empty vector of values.
  272. boost::shared_ptr<Option6IntArray<uint8_t> > opt(new Option6IntArray<uint8_t>(opt_code));
  273. // Initialize vector with some data and pass to the option.
  274. std::vector<uint8_t> values;
  275. for (int i = 0; i < 10; ++i) {
  276. values.push_back(numeric_limits<uint8_t>::max() - i);
  277. }
  278. opt->setValues(values);
  279. // Check if universe, option type and data was set correctly.
  280. EXPECT_EQ(Option::V6, opt->getUniverse());
  281. EXPECT_EQ(opt_code, opt->getType());
  282. std::vector<uint8_t> returned_values = opt->getValues();
  283. EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
  284. }
  285. TEST_F(Option6IntArrayTest, setValuesInt8) {
  286. const uint16_t opt_code = 100;
  287. // Create option with empty vector of values.
  288. boost::shared_ptr<Option6IntArray<int8_t> > opt(new Option6IntArray<int8_t>(opt_code));
  289. // Initialize vector with some data and pass to the option.
  290. std::vector<int8_t> values;
  291. for (int i = 0; i < 10; ++i) {
  292. values.push_back(numeric_limits<int8_t>::min() + i);
  293. }
  294. opt->setValues(values);
  295. // Check if universe, option type and data was set correctly.
  296. EXPECT_EQ(Option::V6, opt->getUniverse());
  297. EXPECT_EQ(opt_code, opt->getType());
  298. std::vector<int8_t> returned_values = opt->getValues();
  299. EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
  300. }
  301. TEST_F(Option6IntArrayTest, setValuesUint16) {
  302. const uint16_t opt_code = 101;
  303. // Create option with empty vector of values.
  304. boost::shared_ptr<Option6IntArray<uint16_t> > opt(new Option6IntArray<uint16_t>(opt_code));
  305. // Initialize vector with some data and pass to the option.
  306. std::vector<uint16_t> values;
  307. for (int i = 0; i < 10; ++i) {
  308. values.push_back(numeric_limits<uint16_t>::max() - i);
  309. }
  310. opt->setValues(values);
  311. // Check if universe, option type and data was set correctly.
  312. EXPECT_EQ(Option::V6, opt->getUniverse());
  313. EXPECT_EQ(opt_code, opt->getType());
  314. std::vector<uint16_t> returned_values = opt->getValues();
  315. EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
  316. }
  317. TEST_F(Option6IntArrayTest, setValuesInt16) {
  318. const uint16_t opt_code = 101;
  319. // Create option with empty vector of values.
  320. boost::shared_ptr<Option6IntArray<int16_t> > opt(new Option6IntArray<int16_t>(opt_code));
  321. // Initialize vector with some data and pass to the option.
  322. std::vector<int16_t> values;
  323. for (int i = 0; i < 10; ++i) {
  324. values.push_back(numeric_limits<int16_t>::min() + i);
  325. }
  326. opt->setValues(values);
  327. // Check if universe, option type and data was set correctly.
  328. EXPECT_EQ(Option::V6, opt->getUniverse());
  329. EXPECT_EQ(opt_code, opt->getType());
  330. std::vector<int16_t> returned_values = opt->getValues();
  331. EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
  332. }
  333. TEST_F(Option6IntArrayTest, setValuesUint32) {
  334. const uint32_t opt_code = 101;
  335. // Create option with empty vector of values.
  336. boost::shared_ptr<Option6IntArray<uint32_t> > opt(new Option6IntArray<uint32_t>(opt_code));
  337. // Initialize vector with some data and pass to the option.
  338. std::vector<uint32_t> values;
  339. for (int i = 0; i < 10; ++i) {
  340. values.push_back(numeric_limits<uint32_t>::max() - i);
  341. }
  342. opt->setValues(values);
  343. // Check if universe, option type and data was set correctly.
  344. EXPECT_EQ(Option::V6, opt->getUniverse());
  345. EXPECT_EQ(opt_code, opt->getType());
  346. std::vector<uint32_t> returned_values = opt->getValues();
  347. EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
  348. }
  349. TEST_F(Option6IntArrayTest, setValuesInt32) {
  350. const uint32_t opt_code = 101;
  351. // Create option with empty vector of values.
  352. boost::shared_ptr<Option6IntArray<int32_t> > opt(new Option6IntArray<int32_t>(opt_code));
  353. // Initialize vector with some data and pass to the option.
  354. std::vector<int32_t> values;
  355. for (int i = 0; i < 10; ++i) {
  356. values.push_back(numeric_limits<int32_t>::min() + i);
  357. }
  358. opt->setValues(values);
  359. // Check if universe, option type and data was set correctly.
  360. EXPECT_EQ(Option::V6, opt->getUniverse());
  361. EXPECT_EQ(opt_code, opt->getType());
  362. std::vector<int32_t> returned_values = opt->getValues();
  363. EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
  364. }
  365. } // anonymous namespace