option_definition_unittest.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  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 <iostream>
  16. #include <sstream>
  17. #include <gtest/gtest.h>
  18. #include <boost/shared_ptr.hpp>
  19. #include <boost/pointer_cast.hpp>
  20. #include <exceptions/exceptions.h>
  21. #include <asiolink/io_address.h>
  22. #include "dhcp/dhcp4.h"
  23. #include "dhcp/dhcp6.h"
  24. #include "dhcp/option4_addrlst.h"
  25. #include "dhcp/option6_addrlst.h"
  26. #include "dhcp/option6_ia.h"
  27. #include "dhcp/option6_iaaddr.h"
  28. #include "dhcp/option6_int.h"
  29. #include "dhcp/option6_int_array.h"
  30. #include "dhcp/option_definition.h"
  31. using namespace std;
  32. using namespace isc;
  33. using namespace isc::dhcp;
  34. using namespace isc::util;
  35. namespace {
  36. /// @brief OptionDefinition test class.
  37. ///
  38. /// This class does not do anything useful but we keep
  39. /// it around for the future.
  40. class OptionDefinitionTest : public ::testing::Test {
  41. public:
  42. // @brief Constructor.
  43. OptionDefinitionTest() { }
  44. };
  45. TEST_F(OptionDefinitionTest, constructor) {
  46. // Specify the option data type as string. This should get converted
  47. // to enum value returned by getType().
  48. OptionDefinition opt_def1("OPTION_CLIENTID", 1, "string");
  49. EXPECT_EQ("OPTION_CLIENTID", opt_def1.getName());
  50. EXPECT_EQ(1, opt_def1.getCode());
  51. EXPECT_EQ(OptionDefinition::STRING_TYPE, opt_def1.getType());
  52. EXPECT_FALSE(opt_def1.getArrayType());
  53. // Specify the option data type as an enum value.
  54. OptionDefinition opt_def2("OPTION_RAPID_COMMIT", 14,
  55. OptionDefinition::EMPTY_TYPE);
  56. EXPECT_EQ("OPTION_RAPID_COMMIT", opt_def2.getName());
  57. EXPECT_EQ(14, opt_def2.getCode());
  58. EXPECT_EQ(OptionDefinition::EMPTY_TYPE, opt_def2.getType());
  59. EXPECT_FALSE(opt_def2.getArrayType());
  60. // Check if it is possible to set that option is an array.
  61. OptionDefinition opt_def3("OPTION_NIS_SERVERS", 27,
  62. OptionDefinition::IPV6_ADDRESS_TYPE,
  63. true);
  64. EXPECT_EQ("OPTION_NIS_SERVERS", opt_def3.getName());
  65. EXPECT_EQ(27, opt_def3.getCode());
  66. EXPECT_EQ(OptionDefinition::IPV6_ADDRESS_TYPE, opt_def3.getType());
  67. EXPECT_TRUE(opt_def3.getArrayType());
  68. // The created object is invalid if invalid data type is specified but
  69. // constructor shouldn't throw exception. The object is validated after
  70. // it has been created.
  71. EXPECT_NO_THROW(
  72. OptionDefinition opt_def4("OPTION_SERVERID",
  73. OptionDefinition::UNKNOWN_TYPE + 10,
  74. OptionDefinition::STRING_TYPE);
  75. );
  76. }
  77. TEST_F(OptionDefinitionTest, addRecordField) {
  78. // We can only add fields to record if the option type has been
  79. // specified as 'record'. We try all other types but 'record'
  80. // here and expect exception to be thrown.
  81. for (int i = 0; i < OptionDefinition::UNKNOWN_TYPE; ++i) {
  82. // Do not try for 'record' type because this is the only
  83. // type for which adding record will succeed.
  84. if (i == OptionDefinition::RECORD_TYPE) {
  85. continue;
  86. }
  87. OptionDefinition opt_def("OPTION_IAADDR", 5,
  88. static_cast<OptionDefinition::DataType>(i));
  89. EXPECT_THROW(opt_def.addRecordField("uint8"), isc::InvalidOperation);
  90. }
  91. // Positive scenario starts here.
  92. OptionDefinition opt_def("OPTION_IAADDR", 5, "record");
  93. EXPECT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  94. EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
  95. // It should not matter if we specify field type by its name or using enum.
  96. EXPECT_NO_THROW(opt_def.addRecordField(OptionDefinition::UINT32_TYPE));
  97. // Check what we have actually added.
  98. OptionDefinition::RecordFieldsCollection fields = opt_def.getRecordFields();
  99. ASSERT_EQ(3, fields.size());
  100. EXPECT_EQ(OptionDefinition::IPV6_ADDRESS_TYPE, fields[0]);
  101. EXPECT_EQ(OptionDefinition::UINT32_TYPE, fields[1]);
  102. EXPECT_EQ(OptionDefinition::UINT32_TYPE, fields[2]);
  103. // Let's try some more negative scenarios: use invalid data types.
  104. EXPECT_THROW(opt_def.addRecordField("unknown_type_xyz"), isc::BadValue);
  105. OptionDefinition::DataType invalid_type =
  106. static_cast<OptionDefinition::DataType>(OptionDefinition::UNKNOWN_TYPE + 10);
  107. EXPECT_THROW(opt_def.addRecordField(invalid_type), isc::BadValue);
  108. }
  109. TEST_F(OptionDefinitionTest, factoryAddrList6) {
  110. OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,
  111. "ipv6-address", true);
  112. Option::Factory* factory(NULL);
  113. EXPECT_NO_THROW(factory = opt_def.getFactory());
  114. ASSERT_TRUE(factory != NULL);
  115. // Create a list of some V6 addresses.
  116. std::vector<asiolink::IOAddress> addrs;
  117. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:8329"));
  118. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:2319"));
  119. addrs.push_back(asiolink::IOAddress("::1"));
  120. addrs.push_back(asiolink::IOAddress("::2"));
  121. // Write addresses to the buffer.
  122. OptionBuffer buf;
  123. for (int i = 0; i < addrs.size(); ++i) {
  124. unsigned char* data = addrs[i].getAddress().to_v6().to_bytes().data();
  125. // @todo Are there any sanity checks needed here on this raw pointer?
  126. buf.insert(buf.end(), data, data + asiolink::V6ADDRESS_LEN);
  127. }
  128. // Create DHCPv6 option from this buffer. Once option is created it is
  129. // supposed to have internal list of addresses that it parses out from
  130. // the provided buffer.
  131. OptionPtr option_v6;
  132. ASSERT_NO_THROW(
  133. option_v6 = factory(Option::V6, D6O_NIS_SERVERS, buf);
  134. );
  135. ASSERT_EQ(typeid(*option_v6), typeid(Option6AddrLst));
  136. boost::shared_ptr<Option6AddrLst> option_cast_v6 =
  137. boost::static_pointer_cast<Option6AddrLst>(option_v6);
  138. ASSERT_TRUE(option_cast_v6);
  139. // Get the list of parsed addresses from the option object.
  140. std::vector<asiolink::IOAddress> addrs_returned =
  141. option_cast_v6->getAddresses();
  142. // The list of addresses must exactly match addresses that we
  143. // stored in the buffer to create the option from it.
  144. EXPECT_EQ(addrs, addrs_returned);
  145. // The provided buffer's length must be a multiple of V6 address length.
  146. // Let's extend the buffer by one byte so as this condition is not
  147. // fulfilled anymore.
  148. buf.insert(buf.end(), 1, 1);
  149. // It should throw exception then.
  150. EXPECT_THROW(
  151. factory(Option::V6, D6O_NIS_SERVERS, buf),
  152. isc::OutOfRange
  153. );
  154. }
  155. TEST_F(OptionDefinitionTest, factoryAddrList4) {
  156. OptionDefinition opt_def("OPTION_NAME_SERVERS", D6O_NIS_SERVERS,
  157. "ipv4-address", true);
  158. Option::Factory* factory(NULL);
  159. EXPECT_NO_THROW(factory = opt_def.getFactory());
  160. ASSERT_TRUE(factory != NULL);
  161. // Create a list of some V6 addresses.
  162. std::vector<asiolink::IOAddress> addrs;
  163. addrs.push_back(asiolink::IOAddress("192.168.0.1"));
  164. addrs.push_back(asiolink::IOAddress("172.16.1.1"));
  165. addrs.push_back(asiolink::IOAddress("127.0.0.1"));
  166. addrs.push_back(asiolink::IOAddress("213.41.23.12"));
  167. // Write addresses to the buffer.
  168. OptionBuffer buf;
  169. for (int i = 0; i < addrs.size(); ++i) {
  170. unsigned char* data = addrs[i].getAddress().to_v4().to_bytes().data();
  171. // @todo Are there any sanity checks needed here on this raw pointer?
  172. buf.insert(buf.end(), data, data + asiolink::V4ADDRESS_LEN);
  173. }
  174. // Create DHCPv6 option from this buffer. Once option is created it is
  175. // supposed to have internal list of addresses that it parses out from
  176. // the provided buffer.
  177. OptionPtr option_v4;
  178. ASSERT_NO_THROW(
  179. option_v4 = factory(Option::V4, DHO_NAME_SERVERS, buf)
  180. );
  181. ASSERT_EQ(typeid(*option_v4), typeid(Option4AddrLst));
  182. // Get the list of parsed addresses from the option object.
  183. boost::shared_ptr<Option4AddrLst> option_cast_v4 =
  184. boost::static_pointer_cast<Option4AddrLst>(option_v4);
  185. std::vector<asiolink::IOAddress> addrs_returned =
  186. option_cast_v4->getAddresses();
  187. // The list of addresses must exactly match addresses that we
  188. // stored in the buffer to create the option from it.
  189. EXPECT_EQ(addrs, addrs_returned);
  190. // The provided buffer's length must be a multiple of V4 address length.
  191. // Let's extend the buffer by one byte so as this condition is not
  192. // fulfilled anymore.
  193. buf.insert(buf.end(), 1, 1);
  194. // It should throw exception then.
  195. EXPECT_THROW(factory(Option::V4, DHO_NIS_SERVERS, buf), isc::OutOfRange);
  196. }
  197. TEST_F(OptionDefinitionTest, factoryEmpty) {
  198. OptionDefinition opt_def("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT, "empty");
  199. Option::Factory* factory(NULL);
  200. EXPECT_NO_THROW(factory = opt_def.getFactory());
  201. ASSERT_TRUE(factory != NULL);
  202. // Create option instance and provide empty buffer as expected.
  203. OptionPtr option_v6;
  204. ASSERT_NO_THROW(
  205. option_v6 = factory(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())
  206. );
  207. ASSERT_EQ(typeid(*option_v6), typeid(Option));
  208. // Expect 'empty' DHCPv6 option.
  209. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  210. EXPECT_EQ(4, option_v6->getHeaderLen());
  211. EXPECT_EQ(0, option_v6->getData().size());
  212. // Repeat the same test scenario for DHCPv4 option.
  213. EXPECT_THROW(factory(Option::V4, 214, OptionBuffer(2)),isc::BadValue);
  214. OptionPtr option_v4;
  215. ASSERT_NO_THROW(option_v4 = factory(Option::V4, 214, OptionBuffer()));
  216. // Expect 'empty' DHCPv4 option.
  217. EXPECT_EQ(Option::V4, option_v4->getUniverse());
  218. EXPECT_EQ(2, option_v4->getHeaderLen());
  219. EXPECT_EQ(0, option_v4->getData().size());
  220. // This factory produces empty option (consisting of option type
  221. // and length). Attempt to provide some data in the buffer should
  222. // result in exception.
  223. EXPECT_THROW(factory(Option::V6, D6O_RAPID_COMMIT,OptionBuffer(2)),isc::BadValue);
  224. }
  225. TEST_F(OptionDefinitionTest, factoryIA6) {
  226. // This option consists of IAID, T1 and T2 fields (each 4 bytes long).
  227. const int option6_ia_len = 12;
  228. // Get the factory function pointer.
  229. OptionDefinition opt_def("OPTION_IA_NA", D6O_IA_NA, "record", true);
  230. // Each data field is uint32.
  231. for (int i = 0; i < 3; ++i) {
  232. EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
  233. }
  234. Option::Factory* factory(NULL);
  235. EXPECT_NO_THROW(factory = opt_def.getFactory());
  236. ASSERT_TRUE(factory != NULL);
  237. // Check the positive scenario.
  238. OptionBuffer buf(12);
  239. for (int i = 0; i < buf.size(); ++i) {
  240. buf[i] = i;
  241. }
  242. OptionPtr option_v6;
  243. ASSERT_NO_THROW(option_v6 = factory(Option::V6, D6O_IA_NA, buf));
  244. ASSERT_EQ(typeid(*option_v6), typeid(Option6IA));
  245. boost::shared_ptr<Option6IA> option_cast_v6 =
  246. boost::static_pointer_cast<Option6IA>(option_v6);
  247. EXPECT_EQ(0x00010203, option_cast_v6->getIAID());
  248. EXPECT_EQ(0x04050607, option_cast_v6->getT1());
  249. EXPECT_EQ(0x08090A0B, option_cast_v6->getT2());
  250. // This should work for DHCPv6 only, try passing invalid universe value.
  251. EXPECT_THROW(
  252. factory(Option::V4, D6O_IA_NA, OptionBuffer(option6_ia_len)),
  253. isc::BadValue
  254. );
  255. // The length of the buffer must be 12 bytes.
  256. // Check too short buffer.
  257. EXPECT_THROW(
  258. factory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len - 1)),
  259. isc::OutOfRange
  260. );
  261. // Check too long buffer.
  262. EXPECT_THROW(
  263. factory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len + 1)),
  264. isc::OutOfRange
  265. );
  266. }
  267. TEST_F(OptionDefinitionTest, factoryIAAddr6) {
  268. // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
  269. // valid-lifetime fields (each 4 bytes long).
  270. const int option6_iaaddr_len = 24;
  271. OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
  272. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  273. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  274. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  275. Option::Factory* factory(NULL);
  276. EXPECT_NO_THROW(factory = opt_def.getFactory());
  277. ASSERT_TRUE(factory != NULL);
  278. // Check the positive scenario.
  279. OptionPtr option_v6;
  280. asiolink::IOAddress addr_v6("2001:0db8::ff00:0042:8329");
  281. ASSERT_TRUE(addr_v6.getAddress().is_v6());
  282. unsigned char* addr_bytes_v6 = addr_v6.getAddress().to_v6().to_bytes().data();
  283. ASSERT_TRUE(addr_bytes_v6 != NULL);
  284. OptionBuffer buf;
  285. buf.insert(buf.end(), addr_bytes_v6, addr_bytes_v6 + asiolink::V6ADDRESS_LEN);
  286. for (int i = 0; i < option6_iaaddr_len - asiolink::V6ADDRESS_LEN; ++i) {
  287. buf.push_back(i);
  288. }
  289. // ASSERT_NO_THROW(option_v6 = factory(Option::V6, D6O_IAADDR, buf));
  290. try {
  291. option_v6 = factory(Option::V6, D6O_IAADDR, buf);
  292. } catch (const Exception& e) {
  293. std::cout << e.what() << std::endl;
  294. }
  295. ASSERT_EQ(typeid(*option_v6), typeid(Option6IAAddr));
  296. boost::shared_ptr<Option6IAAddr> option_cast_v6 =
  297. boost::static_pointer_cast<Option6IAAddr>(option_v6);
  298. EXPECT_EQ(addr_v6, option_cast_v6->getAddress());
  299. EXPECT_EQ(0x00010203, option_cast_v6->getPreferred());
  300. EXPECT_EQ(0x04050607, option_cast_v6->getValid());
  301. // This should work for DHCPv6 only, try passing invalid universe value.
  302. EXPECT_THROW(
  303. factory(Option::V4, D6O_IAADDR, OptionBuffer(option6_iaaddr_len)),
  304. isc::BadValue
  305. );
  306. // The length of the buffer must be 12 bytes.
  307. // Check too short buffer.
  308. EXPECT_THROW(
  309. factory(Option::V6, D6O_IAADDR, OptionBuffer(option6_iaaddr_len - 1)),
  310. isc::OutOfRange
  311. );
  312. // Check too long buffer.
  313. EXPECT_THROW(
  314. factory(Option::V6, D6O_IAADDR, OptionBuffer(option6_iaaddr_len + 1)),
  315. isc::OutOfRange
  316. );
  317. }
  318. TEST_F(OptionDefinitionTest, factoryIntegerInvalidType) {
  319. // The template function factoryInteger<> accepts integer values only
  320. // as template typename. Here we try passing different type and
  321. // see if it rejects it.
  322. EXPECT_THROW(
  323. OptionDefinition::factoryInteger<bool>(Option::V6, D6O_PREFERENCE, OptionBuffer(1)),
  324. isc::dhcp::InvalidDataType
  325. );
  326. }
  327. TEST_F(OptionDefinitionTest, factoryUint8) {
  328. OptionDefinition opt_def("OPTION_PREFERENCE", D6O_PREFERENCE, "uint8");
  329. Option::Factory* factory(NULL);
  330. EXPECT_NO_THROW(factory = opt_def.getFactory());
  331. ASSERT_TRUE(factory != NULL);
  332. OptionPtr option_v6;
  333. // Try to use correct buffer length = 1 byte.
  334. ASSERT_NO_THROW(
  335. option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer(1, 1));
  336. );
  337. ASSERT_EQ(typeid(*option_v6), typeid(Option6Int<uint8_t>)); // Validate the value.
  338. boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
  339. boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
  340. EXPECT_EQ(1, option_cast_v6->getValue());
  341. // Try to provide too large buffer. Expect exception.
  342. EXPECT_THROW(
  343. option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer(3)),
  344. isc::OutOfRange
  345. );
  346. // Try to provide zero-length buffer. Expect exception.
  347. EXPECT_THROW(
  348. option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer()),
  349. isc::OutOfRange
  350. );
  351. // @todo Add more cases for DHCPv4
  352. }
  353. TEST_F(OptionDefinitionTest, factoryUint16) {
  354. OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
  355. Option::Factory* factory(NULL);
  356. EXPECT_NO_THROW(factory = opt_def.getFactory());
  357. ASSERT_TRUE(factory != NULL);
  358. OptionPtr option_v6;
  359. // Try to use correct buffer length = 2 bytes.
  360. OptionBuffer buf;
  361. buf.push_back(1);
  362. buf.push_back(2);
  363. ASSERT_NO_THROW(
  364. option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, buf);
  365. );
  366. ASSERT_EQ(typeid(*option_v6), typeid(Option6Int<uint16_t>));
  367. // Validate the value.
  368. boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
  369. boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
  370. EXPECT_EQ(0x0102, option_cast_v6->getValue());
  371. // Try to provide too large buffer. Expect exception.
  372. EXPECT_THROW(
  373. option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(3)),
  374. isc::OutOfRange
  375. );
  376. // Try to provide zero-length buffer. Expect exception.
  377. EXPECT_THROW(
  378. option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(1)),
  379. isc::OutOfRange
  380. );
  381. // @todo Add more cases for DHCPv4
  382. }
  383. TEST_F(OptionDefinitionTest, factoryUint32) {
  384. OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
  385. Option::Factory* factory(NULL);
  386. EXPECT_NO_THROW(factory = opt_def.getFactory());
  387. ASSERT_TRUE(factory != NULL);
  388. OptionPtr option_v6;
  389. OptionBuffer buf;
  390. buf.push_back(1);
  391. buf.push_back(2);
  392. buf.push_back(3);
  393. buf.push_back(4);
  394. ASSERT_NO_THROW(
  395. option_v6 = factory(Option::V6, D6O_CLT_TIME, buf);
  396. );
  397. ASSERT_EQ(typeid(*option_v6), typeid(Option6Int<uint32_t>));
  398. // Validate the value.
  399. boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
  400. boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
  401. EXPECT_EQ(0x01020304, option_cast_v6->getValue());
  402. // Try to provide too large buffer. Expect exception.
  403. EXPECT_THROW(
  404. option_v6 = factory(Option::V6, D6O_CLT_TIME, OptionBuffer(5)),
  405. isc::OutOfRange
  406. );
  407. // Try to provide zero-length buffer. Expect exception.
  408. EXPECT_THROW(
  409. option_v6 = factory(Option::V6, D6O_CLT_TIME, OptionBuffer(2)),
  410. isc::OutOfRange
  411. );
  412. // @todo Add more cases for DHCPv4
  413. }
  414. TEST_F(OptionDefinitionTest, factoryUint16Array) {
  415. // Let's define some dummy option.
  416. const uint16_t opt_code = 79;
  417. OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
  418. Option::Factory* factory(NULL);
  419. EXPECT_NO_THROW(factory = opt_def.getFactory());
  420. ASSERT_TRUE(factory != NULL);
  421. OptionPtr option_v6;
  422. // Positive scenario, initiate the buffer with length being
  423. // multiple of uint16_t size.
  424. // buffer elements will be: 0x112233.
  425. OptionBuffer buf(6);
  426. for (int i = 0; i < 6; ++i) {
  427. buf[i] = i / 2;
  428. }
  429. // Constructor should succeed because buffer has correct size.
  430. EXPECT_NO_THROW(
  431. option_v6 = factory(Option::V6, opt_code, buf);
  432. );
  433. ASSERT_EQ(typeid(*option_v6), typeid(Option6IntArray<uint16_t>));
  434. boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
  435. boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
  436. // Get the values from the initiated options and validate.
  437. Option6IntArray<uint16_t>::ValuesCollection values =
  438. option_cast_v6->getValues();
  439. for (int i = 0; i < values.size(); ++i) {
  440. // Expected value is calculated using on the same pattern
  441. // as the one we used to initiate buffer:
  442. // for i=0, expected = 0x00, for i = 1, expected == 0x11 etc.
  443. uint16_t expected = (i << 8) | i;
  444. EXPECT_EQ(expected, values[i]);
  445. }
  446. // Provided buffer size must be greater than zero. Check if we
  447. // get exception if we provide zero-length buffer.
  448. EXPECT_THROW(
  449. option_v6 = factory(Option::V6, opt_code, OptionBuffer()),
  450. isc::OutOfRange
  451. );
  452. // Buffer length must be multiple of data type size.
  453. EXPECT_THROW(
  454. option_v6 = factory(Option::V6, opt_code, OptionBuffer(5)),
  455. isc::OutOfRange
  456. );
  457. }
  458. TEST_F(OptionDefinitionTest, factoryUint32Array) {
  459. // Let's define some dummy option.
  460. const uint16_t opt_code = 80;
  461. OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
  462. Option::Factory* factory(NULL);
  463. EXPECT_NO_THROW(factory = opt_def.getFactory());
  464. ASSERT_TRUE(factory != NULL);
  465. OptionPtr option_v6;
  466. // Positive scenario, initiate the buffer with length being
  467. // multiple of uint16_t size.
  468. // buffer elements will be: 0x111122223333.
  469. OptionBuffer buf(12);
  470. for (int i = 0; i < buf.size(); ++i) {
  471. buf[i] = i / 4;
  472. }
  473. // Constructor should succeed because buffer has correct size.
  474. EXPECT_NO_THROW(
  475. option_v6 = factory(Option::V6, opt_code, buf);
  476. );
  477. ASSERT_EQ(typeid(*option_v6), typeid(Option6IntArray<uint32_t>));
  478. boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
  479. boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
  480. // Get the values from the initiated options and validate.
  481. Option6IntArray<uint32_t>::ValuesCollection values =
  482. option_cast_v6->getValues();
  483. for (int i = 0; i < values.size(); ++i) {
  484. // Expected value is calculated using on the same pattern
  485. // as the one we used to initiate buffer:
  486. // for i=0, expected = 0x0000, for i = 1, expected == 0x1111 etc.
  487. uint32_t expected = 0x01010101 * i;
  488. EXPECT_EQ(expected, values[i]);
  489. }
  490. // Provided buffer size must be greater than zero. Check if we
  491. // get exception if we provide zero-length buffer.
  492. EXPECT_THROW(
  493. option_v6 = factory(Option::V6, opt_code, OptionBuffer()),
  494. isc::OutOfRange
  495. );
  496. // Buffer length must be multiple of data type size.
  497. EXPECT_THROW(
  498. option_v6 = factory(Option::V6, opt_code, OptionBuffer(5)),
  499. isc::OutOfRange
  500. );
  501. }
  502. } // anonymous namespace