option_custom_unittest.cc 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171
  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 <asiolink/io_address.h>
  16. #include <dhcp/option_custom.h>
  17. #include <boost/scoped_ptr.hpp>
  18. #include <gtest/gtest.h>
  19. using namespace isc;
  20. using namespace isc::asiolink;
  21. using namespace isc::dhcp;
  22. namespace {
  23. /// @brief OptionCustomTest test class.
  24. class OptionCustomTest : public ::testing::Test {
  25. public:
  26. /// @brief Constructor.
  27. OptionCustomTest() { }
  28. /// @brief Write IP address into a buffer.
  29. ///
  30. /// @param address address to be written.
  31. /// @param [out] buf output buffer.
  32. void writeAddress(const asiolink::IOAddress& address,
  33. std::vector<uint8_t>& buf) {
  34. short family = address.getFamily();
  35. if (family == AF_INET) {
  36. asio::ip::address_v4::bytes_type buf_addr =
  37. address.getAddress().to_v4().to_bytes();
  38. buf.insert(buf.end(), buf_addr.begin(), buf_addr.end());
  39. } else if (family == AF_INET6) {
  40. asio::ip::address_v6::bytes_type buf_addr =
  41. address.getAddress().to_v6().to_bytes();
  42. buf.insert(buf.end(), buf_addr.begin(), buf_addr.end());
  43. }
  44. }
  45. /// @brief Write integer (signed or unsigned) into a buffer.
  46. ///
  47. /// @param value integer value.
  48. /// @param [out] buf output buffer.
  49. /// @tparam integer type.
  50. template<typename T>
  51. void writeInt(T value, std::vector<uint8_t>& buf) {
  52. for (int i = 0; i < sizeof(T); ++i) {
  53. buf.push_back(value >> ((sizeof(T) - i - 1) * 8) & 0xFF);
  54. }
  55. }
  56. /// @brief Write a string into a buffer.
  57. ///
  58. /// @param value string to be written into a buffer.
  59. /// @param buf output buffer.
  60. void writeString(const std::string& value,
  61. std::vector<uint8_t>& buf) {
  62. buf.resize(buf.size() + value.size());
  63. std::copy_backward(value.c_str(), value.c_str() + value.size(),
  64. buf.end());
  65. }
  66. };
  67. // The purpose of this test is to check that parameters passed to
  68. // a custom option's constructor are used to initialize class
  69. // members.
  70. TEST_F(OptionCustomTest, constructor) {
  71. // Create option definition for a DHCPv6 option.
  72. OptionDefinition opt_def1("OPTION_FOO", 1000, "boolean", true);
  73. // Initialize some dummy buffer that holds single boolean value.
  74. OptionBuffer buf;
  75. buf.push_back(1);
  76. // Create DHCPv6 option.
  77. boost::scoped_ptr<OptionCustom> option;
  78. ASSERT_NO_THROW(
  79. option.reset(new OptionCustom(opt_def1, Option::V6, buf));
  80. );
  81. ASSERT_TRUE(option);
  82. // Check if constructor initialized the universe and type correctly.
  83. EXPECT_EQ(Option::V6, option->getUniverse());
  84. EXPECT_EQ(1000, option->getType());
  85. // Do another round of testing for DHCPv4 option.
  86. OptionDefinition opt_def2("OPTION_FOO", 232, "boolean");
  87. ASSERT_NO_THROW(
  88. option.reset(new OptionCustom(opt_def2, Option::V4, buf.begin(), buf.end()));
  89. );
  90. ASSERT_TRUE(option);
  91. EXPECT_EQ(Option::V4, option->getUniverse());
  92. EXPECT_EQ(232, option->getType());
  93. // Try to create an option using 'empty data' constructor
  94. OptionDefinition opt_def3("OPTION_FOO", 1000, "uint32");
  95. ASSERT_NO_THROW(
  96. option.reset(new OptionCustom(opt_def3, Option::V6));
  97. );
  98. ASSERT_TRUE(option);
  99. EXPECT_EQ(Option::V6, option->getUniverse());
  100. EXPECT_EQ(1000, option->getType());
  101. }
  102. // The purpose of this test is to verify that 'empty' option definition can
  103. // be used to create an instance of custom option.
  104. TEST_F(OptionCustomTest, emptyData) {
  105. OptionDefinition opt_def("OPTION_FOO", 232, "empty");
  106. boost::scoped_ptr<OptionCustom> option;
  107. ASSERT_NO_THROW(
  108. option.reset(new OptionCustom(opt_def, Option::V4, OptionBuffer()));
  109. );
  110. ASSERT_TRUE(option);
  111. // Option is 'empty' so no data fields are expected.
  112. EXPECT_EQ(0, option->getDataFieldsNum());
  113. }
  114. // The purpose of this test is to verify that the option definition comprising
  115. // a binary value can be used to create an instance of custom option.
  116. TEST_F(OptionCustomTest, binaryData) {
  117. OptionDefinition opt_def("OPTION_FOO", 231, "binary");
  118. // Create a buffer holding some binary data. This data will be
  119. // used as reference when we read back the data from a created
  120. // option.
  121. OptionBuffer buf_in(14);
  122. for (int i = 0; i < 14; ++i) {
  123. buf_in[i] = i;
  124. }
  125. // Use scoped pointer because it allows to declare the option
  126. // in the function scope and initialize it under ASSERT.
  127. boost::scoped_ptr<OptionCustom> option;
  128. // Custom option may throw exception if the provided buffer is
  129. // malformed.
  130. ASSERT_NO_THROW(
  131. option.reset(new OptionCustom(opt_def, Option::V4, buf_in));
  132. );
  133. ASSERT_TRUE(option);
  134. // We should have just one data field.
  135. ASSERT_EQ(1, option->getDataFieldsNum());
  136. // The custom option should hold just one buffer that can be
  137. // accessed using index 0.
  138. OptionBuffer buf_out;
  139. ASSERT_NO_THROW(buf_out = option->readBinary(0));
  140. // Read buffer must match exactly with the buffer used to
  141. // create option instance.
  142. ASSERT_EQ(buf_in.size(), buf_out.size());
  143. EXPECT_TRUE(std::equal(buf_in.begin(), buf_in.end(), buf_out.begin()));
  144. // Check that option with "no data" is rejected.
  145. EXPECT_THROW(
  146. option.reset(new OptionCustom(opt_def, Option::V4, OptionBuffer())),
  147. isc::OutOfRange
  148. );
  149. }
  150. // The purpose of this test is to verify that an option definition comprising
  151. // a single boolean value can be used to create an instance of custom option.
  152. TEST_F(OptionCustomTest, booleanData) {
  153. OptionDefinition opt_def("OPTION_FOO", 1000, "boolean");
  154. OptionBuffer buf;
  155. // Push back the value that represents 'false'.
  156. buf.push_back(0);
  157. // Push back the 'true' value. Note that this value should
  158. // be ignored by custom option because it holds single boolean
  159. // value (according to option definition).
  160. buf.push_back(1);
  161. boost::scoped_ptr<OptionCustom> option;
  162. ASSERT_NO_THROW(
  163. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  164. );
  165. ASSERT_TRUE(option);
  166. // We should have just one data field.
  167. ASSERT_EQ(1, option->getDataFieldsNum());
  168. // Initialize the value to true because we want to make sure
  169. // that it is modified to 'false' by readBoolean below.
  170. bool value = true;
  171. // Read the boolean value from only one available buffer indexed
  172. // with 0. It is expected to be 'false'.
  173. ASSERT_NO_THROW(value = option->readBoolean(0));
  174. EXPECT_FALSE(value);
  175. // Check that the option with "no data" is rejected.
  176. EXPECT_THROW(
  177. option.reset(new OptionCustom(opt_def, Option::V6, OptionBuffer())),
  178. isc::OutOfRange
  179. );
  180. }
  181. // The purpose of this test is to verify that the data from a buffer
  182. // can be read as FQDN.
  183. TEST_F(OptionCustomTest, fqdnData) {
  184. OptionDefinition opt_def("OPTION_FOO", 1000, "fqdn");
  185. const char data[] = {
  186. 8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
  187. 7, 101, 120, 97, 109, 112, 108, 101, // "example"
  188. 3, 99, 111, 109, // "com"
  189. 0,
  190. };
  191. std::vector<uint8_t> buf(data, data + sizeof(data));
  192. boost::scoped_ptr<OptionCustom> option;
  193. ASSERT_NO_THROW(
  194. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
  195. );
  196. ASSERT_TRUE(option);
  197. ASSERT_EQ(1, option->getDataFieldsNum());
  198. std::string domain0 = option->readFqdn(0);
  199. EXPECT_EQ("mydomain.example.com.", domain0);
  200. // Check that the option with truncated data can't be created.
  201. EXPECT_THROW(
  202. option.reset(new OptionCustom(opt_def, Option::V6,
  203. buf.begin(), buf.begin() + 4)),
  204. isc::dhcp::BadDataTypeCast
  205. );
  206. }
  207. // The purpose of this test is to verify that the option definition comprising
  208. // 16-bit signed integer value can be used to create an instance of custom option.
  209. TEST_F(OptionCustomTest, int16Data) {
  210. OptionDefinition opt_def("OPTION_FOO", 1000, "int16");
  211. OptionBuffer buf;
  212. // Store signed integer value in the input buffer.
  213. writeInt<int16_t>(-234, buf);
  214. // Create custom option.
  215. boost::scoped_ptr<OptionCustom> option;
  216. ASSERT_NO_THROW(
  217. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  218. );
  219. ASSERT_TRUE(option);
  220. // We should have just one data field.
  221. ASSERT_EQ(1, option->getDataFieldsNum());
  222. // Initialize value to 0 explicitely to make sure that is
  223. // modified by readInteger function to expected -234.
  224. int16_t value = 0;
  225. ASSERT_NO_THROW(value = option->readInteger<int16_t>(0));
  226. EXPECT_EQ(-234, value);
  227. // Check that the option is not created when a buffer is
  228. // too short (1 byte instead of 2 bytes).
  229. EXPECT_THROW(
  230. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 1)),
  231. isc::OutOfRange
  232. );
  233. }
  234. // The purpose of this test is to verify that the option definition comprising
  235. // 32-bit signed integer value can be used to create an instance of custom option.
  236. TEST_F(OptionCustomTest, int32Data) {
  237. OptionDefinition opt_def("OPTION_FOO", 1000, "int32");
  238. OptionBuffer buf;
  239. writeInt<int32_t>(-234, buf);
  240. writeInt<int32_t>(100, buf);
  241. // Create custom option.
  242. boost::scoped_ptr<OptionCustom> option;
  243. ASSERT_NO_THROW(
  244. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  245. );
  246. ASSERT_TRUE(option);
  247. // We should have just one data field.
  248. ASSERT_EQ(1, option->getDataFieldsNum());
  249. // Initialize value to 0 explicitely to make sure that is
  250. // modified by readInteger function to expected -234.
  251. int32_t value = 0;
  252. ASSERT_NO_THROW(value = option->readInteger<int32_t>(0));
  253. EXPECT_EQ(-234, value);
  254. // Check that the option is not created when a buffer is
  255. // too short (3 bytes instead of 4 bytes).
  256. EXPECT_THROW(
  257. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 3)),
  258. isc::OutOfRange
  259. );
  260. }
  261. // The purpose of this test is to verify that the option definition comprising
  262. // single IPv4 addres can be used to create an instance of custom option.
  263. TEST_F(OptionCustomTest, ipv4AddressData) {
  264. OptionDefinition opt_def("OPTION_FOO", 231, "ipv4-address");
  265. // Create input buffer.
  266. OptionBuffer buf;
  267. writeAddress(IOAddress("192.168.100.50"), buf);
  268. // Create custom option.
  269. boost::scoped_ptr<OptionCustom> option;
  270. ASSERT_NO_THROW(
  271. option.reset(new OptionCustom(opt_def, Option::V4, buf));
  272. );
  273. ASSERT_TRUE(option);
  274. // We should have just one data field.
  275. ASSERT_EQ(1, option->getDataFieldsNum());
  276. IOAddress address("127.0.0.1");
  277. // Read IPv4 address from using index 0.
  278. ASSERT_NO_THROW(address = option->readAddress(0));
  279. EXPECT_EQ("192.168.100.50", address.toText());
  280. // Check that option is not created if the provided buffer is
  281. // too short (use 3 bytes instead of 4).
  282. EXPECT_THROW(
  283. option.reset(new OptionCustom(opt_def, Option::V4, buf.begin(), buf.begin() + 3)),
  284. isc::OutOfRange
  285. );
  286. }
  287. // The purpose of this test is to verify that the option definition comprising
  288. // single IPv6 addres can be used to create an instance of custom option.
  289. TEST_F(OptionCustomTest, ipv6AddressData) {
  290. OptionDefinition opt_def("OPTION_FOO", 1000, "ipv6-address");
  291. // Initialize input buffer.
  292. OptionBuffer buf;
  293. writeAddress(IOAddress("2001:db8:1::100"), buf);
  294. // Create custom option using input buffer.
  295. boost::scoped_ptr<OptionCustom> option;
  296. ASSERT_NO_THROW(
  297. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  298. );
  299. ASSERT_TRUE(option);
  300. // We should have just one data field.
  301. ASSERT_EQ(1, option->getDataFieldsNum());
  302. // Custom option should comprise exactly one buffer that represents
  303. // IPv6 address.
  304. IOAddress address("::1");
  305. // Read an address from buffer #0.
  306. ASSERT_NO_THROW(address = option->readAddress(0));
  307. EXPECT_EQ("2001:db8:1::100", address.toText());
  308. // Check that option is not created if the provided buffer is
  309. // too short (use 15 bytes instead of 16).
  310. EXPECT_THROW(
  311. option.reset(new OptionCustom(opt_def, Option::V4, buf.begin(),
  312. buf.begin() + 15)),
  313. isc::OutOfRange
  314. );
  315. }
  316. // The purpose of this test is to verify that the option definition comprising
  317. // string value can be used to create an instance of custom option.
  318. TEST_F(OptionCustomTest, stringData) {
  319. OptionDefinition opt_def("OPTION_FOO", 1000, "string");
  320. // Create an input buffer holding some string value.
  321. OptionBuffer buf;
  322. writeString("hello world!", buf);
  323. // Create custom option using input buffer.
  324. boost::scoped_ptr<OptionCustom> option;
  325. ASSERT_NO_THROW(
  326. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
  327. );
  328. ASSERT_TRUE(option);
  329. // We should have just one data field.
  330. ASSERT_EQ(1, option->getDataFieldsNum());
  331. // Custom option should now comprise single string value that
  332. // can be accessed using index 0.
  333. std::string value;
  334. ASSERT_NO_THROW(value = option->readString(0));
  335. EXPECT_EQ("hello world!", value);
  336. // Check that option will not be created if empty buffer is provided.
  337. EXPECT_THROW(
  338. option.reset(new OptionCustom(opt_def, Option::V6, OptionBuffer())),
  339. isc::OutOfRange
  340. );
  341. }
  342. // The purpose of this test is to verify that the option definition comprising
  343. // an array of boolean values can be used to create an instance of custom option.
  344. TEST_F(OptionCustomTest, booleanDataArray) {
  345. OptionDefinition opt_def("OPTION_FOO", 1000, "boolean", true);
  346. // Create a buffer with 5 values that represent array of
  347. // booleans.
  348. OptionBuffer buf(5);
  349. buf[0] = 1; // true
  350. buf[1] = 0; // false
  351. buf[2] = 0; // false
  352. buf[3] = 1; // true
  353. buf[4] = 1; // true
  354. // Use the input buffer to create custom option.
  355. boost::scoped_ptr<OptionCustom> option;
  356. ASSERT_NO_THROW(
  357. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
  358. );
  359. ASSERT_TRUE(option);
  360. // We should have 5 data fields.
  361. ASSERT_EQ(5, option->getDataFieldsNum());
  362. // Read values from custom option using indexes 0..4 and
  363. // check that they are valid.
  364. bool value0 = false;
  365. ASSERT_NO_THROW(value0 = option->readBoolean(0));
  366. EXPECT_TRUE(value0);
  367. bool value1 = true;
  368. ASSERT_NO_THROW(value1 = option->readBoolean(1));
  369. EXPECT_FALSE(value1);
  370. bool value2 = true;
  371. ASSERT_NO_THROW(value2 = option->readBoolean(2));
  372. EXPECT_FALSE(value2);
  373. bool value3 = false;
  374. ASSERT_NO_THROW(value3 = option->readBoolean(3));
  375. EXPECT_TRUE(value3);
  376. bool value4 = false;
  377. ASSERT_NO_THROW(value4 = option->readBoolean(4));
  378. EXPECT_TRUE(value4);
  379. // Check that empty buffer can't be used to create option holding
  380. // array of boolean values.
  381. EXPECT_THROW(
  382. option.reset(new OptionCustom(opt_def, Option::V6, OptionBuffer())),
  383. isc::OutOfRange
  384. );
  385. }
  386. // The purpose of this test is to verify that the option definition comprising
  387. // an array of 32-bit signed integer values can be used to create an instance
  388. // of custom option.
  389. TEST_F(OptionCustomTest, uint32DataArray) {
  390. OptionDefinition opt_def("OPTION_FOO", 1000, "uint32", true);
  391. // Create an input buffer that holds 4 uint32 values that
  392. // represent an array.
  393. std::vector<uint32_t> values;
  394. values.push_back(71234);
  395. values.push_back(12234);
  396. values.push_back(54362);
  397. values.push_back(1234);
  398. // Store these values in a buffer.
  399. OptionBuffer buf;
  400. for (int i = 0; i < values.size(); ++i) {
  401. writeInt<uint32_t>(values[i], buf);
  402. }
  403. // Create custom option using the input buffer.
  404. boost::scoped_ptr<OptionCustom> option;
  405. ASSERT_NO_THROW(
  406. // Note that we just use a part of the whole buffer here: 13 bytes. We want to
  407. // check that buffer length which is non-divisible by 4 (size of uint32_t) is
  408. // accepted and only 3 (instead of 4) elements will be stored in a custom option.
  409. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 13));
  410. );
  411. ASSERT_TRUE(option);
  412. // We should have 3 data fields.
  413. ASSERT_EQ(3, option->getDataFieldsNum());
  414. // Expect only 3 values.
  415. for (int i = 0; i < 3; ++i) {
  416. uint32_t value = 0;
  417. ASSERT_NO_THROW(value = option->readInteger<uint32_t>(i));
  418. EXPECT_EQ(values[i], value);
  419. }
  420. // Check that too short buffer can't be used to create the option.
  421. // Using buffer having length of 3 bytes. The length of 4 bytes is
  422. // a minimal length to create the option with single uint32_t value.
  423. EXPECT_THROW(
  424. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(),
  425. buf.begin() + 3)),
  426. isc::OutOfRange
  427. );
  428. }
  429. // The purpose of this test is to verify that the option definition comprising
  430. // an array of IPv4 addresses can be used to create an instance of custom option.
  431. TEST_F(OptionCustomTest, ipv4AddressDataArray) {
  432. OptionDefinition opt_def("OPTION_FOO", 231, "ipv4-address", true);
  433. // Initialize reference data.
  434. std::vector<IOAddress> addresses;
  435. addresses.push_back(IOAddress("192.168.0.1"));
  436. addresses.push_back(IOAddress("127.0.0.1"));
  437. addresses.push_back(IOAddress("10.10.1.2"));
  438. // Store the collection of IPv4 addresses into the buffer.
  439. OptionBuffer buf;
  440. for (int i = 0; i < addresses.size(); ++i) {
  441. writeAddress(addresses[i], buf);
  442. }
  443. // Use the input buffer to create custom option.
  444. boost::scoped_ptr<OptionCustom> option;
  445. ASSERT_NO_THROW(
  446. option.reset(new OptionCustom(opt_def, Option::V4, buf));
  447. );
  448. ASSERT_TRUE(option);
  449. // We should have 3 data fields.
  450. ASSERT_EQ(3, option->getDataFieldsNum());
  451. // We expect 3 IPv4 addresses being stored in the option.
  452. for (int i = 0; i < 3; ++i) {
  453. IOAddress address("10.10.10.10");
  454. ASSERT_NO_THROW(address = option->readAddress(i));
  455. EXPECT_EQ(addresses[i].toText(), address.toText());
  456. }
  457. // Check that it is ok if buffer length is not a multiple of IPv4
  458. // address length. Resize it by two bytes.
  459. buf.resize(buf.size() + 2);
  460. EXPECT_NO_THROW(
  461. option.reset(new OptionCustom(opt_def, Option::V4, buf));
  462. );
  463. // Check that option is not created when the provided buffer
  464. // is too short. At least a buffer length of 4 bytes is needed.
  465. EXPECT_THROW(
  466. option.reset(new OptionCustom(opt_def, Option::V4, buf.begin(),
  467. buf.begin() + 2)),
  468. isc::OutOfRange
  469. );
  470. }
  471. // The purpose of this test is to verify that the option definition comprising
  472. // an array of IPv6 addresses can be used to create an instance of custom option.
  473. TEST_F(OptionCustomTest, ipv6AddressDataArray) {
  474. OptionDefinition opt_def("OPTION_FOO", 1000, "ipv6-address", true);
  475. // Initialize reference data.
  476. std::vector<IOAddress> addresses;
  477. addresses.push_back(IOAddress("2001:db8:1::3"));
  478. addresses.push_back(IOAddress("::1"));
  479. addresses.push_back(IOAddress("fe80::3"));
  480. // Store the collection of IPv6 addresses into the buffer.
  481. OptionBuffer buf;
  482. for (int i = 0; i < addresses.size(); ++i) {
  483. writeAddress(addresses[i], buf);
  484. }
  485. // Use the input buffer to create custom option.
  486. boost::scoped_ptr<OptionCustom> option;
  487. ASSERT_NO_THROW(
  488. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  489. );
  490. ASSERT_TRUE(option);
  491. // We should have 3 data fields.
  492. ASSERT_EQ(3, option->getDataFieldsNum());
  493. // We expect 3 IPv6 addresses being stored in the option.
  494. for (int i = 0; i < 3; ++i) {
  495. IOAddress address("fe80::4");
  496. ASSERT_NO_THROW(address = option->readAddress(i));
  497. EXPECT_EQ(addresses[i].toText(), address.toText());
  498. }
  499. // Check that it is ok if buffer length is not a multiple of IPv6
  500. // address length. Resize it by two bytes.
  501. buf.resize(buf.size() + 2);
  502. EXPECT_NO_THROW(
  503. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  504. );
  505. // Check that option is not created when the provided buffer
  506. // is too short. At least a buffer length of 16 bytes is needed.
  507. EXPECT_THROW(
  508. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(),
  509. buf.begin() + 15)),
  510. isc::OutOfRange
  511. );
  512. }
  513. // The purpose of this test is to verify that the option comprising
  514. // an array of FQDN values can be created from a buffer which holds
  515. // multiple FQDN values encoded as described in the RFC1035, section
  516. // 3.1
  517. TEST_F(OptionCustomTest, fqdnDataArray) {
  518. OptionDefinition opt_def("OPTION_FOO", 1000, "fqdn", true);
  519. const char data[] = {
  520. 8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
  521. 7, 101, 120, 97, 109, 112, 108, 101, // "example"
  522. 3, 99, 111, 109, // "com"
  523. 0,
  524. 7, 101, 120, 97, 109, 112, 108, 101, // "example"
  525. 3, 99, 111, 109, // "com"
  526. 0
  527. };
  528. // Create a buffer that holds two FQDNs.
  529. std::vector<uint8_t> buf(data, data + sizeof(data));
  530. // Create an option from using a buffer.
  531. boost::scoped_ptr<OptionCustom> option;
  532. ASSERT_NO_THROW(
  533. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  534. );
  535. ASSERT_TRUE(option);
  536. // We expect that two FQDN values have been extracted
  537. // from a buffer.
  538. ASSERT_EQ(2, option->getDataFieldsNum());
  539. // Validate both values.
  540. std::string domain0 = option->readFqdn(0);
  541. EXPECT_EQ("mydomain.example.com.", domain0);
  542. std::string domain1 = option->readFqdn(1);
  543. EXPECT_EQ("example.com.", domain1);
  544. }
  545. // The purpose of this test is to verify that the option definition comprising
  546. // a record of various data fields can be used to create an instance of
  547. // custom option.
  548. TEST_F(OptionCustomTest, recordData) {
  549. // Create the definition of an option which comprises
  550. // a record of fields of different types.
  551. OptionDefinition opt_def("OPTION_FOO", 1000, "record");
  552. ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
  553. ASSERT_NO_THROW(opt_def.addRecordField("boolean"));
  554. ASSERT_NO_THROW(opt_def.addRecordField("fqdn"));
  555. ASSERT_NO_THROW(opt_def.addRecordField("ipv4-address"));
  556. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  557. ASSERT_NO_THROW(opt_def.addRecordField("string"));
  558. const char fqdn_data[] = {
  559. 8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
  560. 7, 101, 120, 97, 109, 112, 108, 101, // "example"
  561. 3, 99, 111, 109, // "com"
  562. 0,
  563. };
  564. OptionBuffer buf;
  565. // Initialize field 0.
  566. writeInt<uint16_t>(8712, buf);
  567. // Initialize field 1 to 'true'
  568. buf.push_back(static_cast<unsigned short>(1));
  569. // Initialize field 2.
  570. buf.insert(buf.end(), fqdn_data, fqdn_data + sizeof(fqdn_data));
  571. // Initialize field 3 to IPv4 address.
  572. writeAddress(IOAddress("192.168.0.1"), buf);
  573. // Initialize field 4 to IPv6 address.
  574. writeAddress(IOAddress("2001:db8:1::1"), buf);
  575. // Initialize field 5 to string value.
  576. writeString("ABCD", buf);
  577. boost::scoped_ptr<OptionCustom> option;
  578. try {
  579. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
  580. } catch (const Exception& ex) {
  581. std::cout << ex.what() << std::endl;
  582. }
  583. ASSERT_NO_THROW(
  584. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
  585. );
  586. ASSERT_TRUE(option);
  587. // We should have 5 data fields.
  588. ASSERT_EQ(6, option->getDataFieldsNum());
  589. // Verify value in the field 0.
  590. uint16_t value0 = 0;
  591. ASSERT_NO_THROW(value0 = option->readInteger<uint16_t>(0));
  592. EXPECT_EQ(8712, value0);
  593. // Verify value in the field 1.
  594. bool value1 = false;
  595. ASSERT_NO_THROW(value1 = option->readBoolean(1));
  596. EXPECT_TRUE(value1);
  597. // Verify value in the field 2.
  598. std::string value2 = "";
  599. ASSERT_NO_THROW(value2 = option->readFqdn(2));
  600. EXPECT_EQ("mydomain.example.com.", value2);
  601. // Verify value in the field 3.
  602. IOAddress value3("127.0.0.1");
  603. ASSERT_NO_THROW(value3 = option->readAddress(3));
  604. EXPECT_EQ("192.168.0.1", value3.toText());
  605. // Verify value in the field 4.
  606. IOAddress value4("::1");
  607. ASSERT_NO_THROW(value4 = option->readAddress(4));
  608. EXPECT_EQ("2001:db8:1::1", value4.toText());
  609. // Verify value in the field 4.
  610. std::string value5;
  611. ASSERT_NO_THROW(value5 = option->readString(5));
  612. EXPECT_EQ("ABCD", value5);
  613. }
  614. // The purpose of this test is to verify that truncated buffer
  615. // can't be used to create an option being a record of value of
  616. // different types.
  617. TEST_F(OptionCustomTest, recordDataTruncated) {
  618. // Create the definition of an option which comprises
  619. // a record of fields of different types.
  620. OptionDefinition opt_def("OPTION_FOO", 1000, "record");
  621. ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
  622. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  623. ASSERT_NO_THROW(opt_def.addRecordField("string"));
  624. OptionBuffer buf;
  625. // Initialize field 0.
  626. writeInt<uint16_t>(8712, buf);
  627. // Initialize field 1 to IPv6 address.
  628. writeAddress(IOAddress("2001:db8:1::1"), buf);
  629. // Initialize field 2 to string value.
  630. writeString("ABCD", buf);
  631. boost::scoped_ptr<OptionCustom> option;
  632. // Constructor should not throw exception here because the length of the
  633. // buffer meets the minimum length. The first 19 bytes hold data for
  634. // all option fields: uint16, IPv4 address and first letter of string.
  635. // Note that string will be truncated but this is acceptable because
  636. // constructor have no way to determine the length of the original string.
  637. EXPECT_NO_THROW(
  638. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 19));
  639. );
  640. // Reduce the buffer length by one byte should cause the constructor
  641. // to fail. This is because 18 bytes can only hold first two data fields:
  642. // 2 bytes of uint16_t value and IPv6 address. Option definitions specifies
  643. // 3 data fields for this option but the length of the data is insufficient
  644. // to initialize 3 data field.
  645. EXPECT_THROW(
  646. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 18)),
  647. isc::OutOfRange
  648. );
  649. // Try to further reduce the length of the buffer to make it insufficient
  650. // to even initialize the second data field.
  651. EXPECT_THROW(
  652. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.begin() + 17)),
  653. isc::OutOfRange
  654. );
  655. }
  656. // The purpose of this test is to verify that an option comprising
  657. // single data field with binary data can be used and that this
  658. // binary data is properly initialized to a default value. This
  659. // test also checks that it is possible to override this default
  660. // value.
  661. TEST_F(OptionCustomTest, setBinaryData) {
  662. OptionDefinition opt_def("OPTION_FOO", 1000, "binary");
  663. // Create an option and let the data field be initialized
  664. // to default value (do not provide any data buffer).
  665. boost::scoped_ptr<OptionCustom> option;
  666. ASSERT_NO_THROW(
  667. option.reset(new OptionCustom(opt_def, Option::V6));
  668. );
  669. ASSERT_TRUE(option);
  670. // Get the default binary value.
  671. OptionBuffer buf;
  672. ASSERT_NO_THROW(option->readBinary());
  673. // The buffer is by default empty.
  674. EXPECT_TRUE(buf.empty());
  675. // Prepare input buffer with some dummy data.
  676. OptionBuffer buf_in(10);
  677. for (int i = 0; i < buf_in.size(); ++i) {
  678. buf_in[i] = i;
  679. }
  680. // Try to override the default binary buffer.
  681. ASSERT_NO_THROW(option->writeBinary(buf_in));
  682. // And check that it has been actually overriden.
  683. ASSERT_NO_THROW(buf = option->readBinary());
  684. ASSERT_EQ(buf_in.size(), buf.size());
  685. EXPECT_TRUE(std::equal(buf_in.begin(), buf_in.end(), buf.begin()));
  686. }
  687. // The purpose of this test is to verify that an option comprising
  688. // single boolean data field can be created and that its default
  689. // value can be overriden by a new value.
  690. TEST_F(OptionCustomTest, setBooleanData) {
  691. OptionDefinition opt_def("OPTION_FOO", 1000, "boolean");
  692. // Create an option and let the data field be initialized
  693. // to default value (do not provide any data buffer).
  694. boost::scoped_ptr<OptionCustom> option;
  695. ASSERT_NO_THROW(
  696. option.reset(new OptionCustom(opt_def, Option::V6));
  697. );
  698. ASSERT_TRUE(option);
  699. // Check that the default boolean value is false.
  700. bool value = false;
  701. ASSERT_NO_THROW(value = option->readBoolean());
  702. EXPECT_FALSE(value);
  703. // Check that we can override the default value.
  704. ASSERT_NO_THROW(option->writeBoolean(true));
  705. // Finally, check that it has been actually overriden.
  706. ASSERT_NO_THROW(value = option->readBoolean());
  707. EXPECT_TRUE(value);
  708. }
  709. /// The purpose of this test is to verify that the data field value
  710. /// can be overriden by a new value.
  711. TEST_F(OptionCustomTest, setUint32Data) {
  712. // Create a definition of an option that holds single
  713. // uint32 value.
  714. OptionDefinition opt_def("OPTION_FOO", 1000, "uint32");
  715. // Create an option and let the data field be initialized
  716. // to default value (do not provide any data buffer).
  717. boost::scoped_ptr<OptionCustom> option;
  718. ASSERT_NO_THROW(
  719. option.reset(new OptionCustom(opt_def, Option::V6));
  720. );
  721. ASSERT_TRUE(option);
  722. // The default value for integer data fields is 0.
  723. uint32_t value = 0;
  724. ASSERT_NO_THROW(option->readInteger<uint32_t>());
  725. EXPECT_EQ(0, value);
  726. // Try to set the data field value to something different
  727. // than 0.
  728. ASSERT_NO_THROW(option->writeInteger<uint32_t>(1234));
  729. // Verify that it has been set.
  730. ASSERT_NO_THROW(value = option->readInteger<uint32_t>());
  731. EXPECT_EQ(1234, value);
  732. }
  733. // The purpose of this test is to verify that an opton comprising
  734. // single IPv4 address can be created and that this address can
  735. // be overriden by a new value.
  736. TEST_F(OptionCustomTest, setIpv4AddressData) {
  737. OptionDefinition opt_def("OPTION_FOO", 232, "ipv4-address");
  738. // Create an option and let the data field be initialized
  739. // to default value (do not provide any data buffer).
  740. boost::scoped_ptr<OptionCustom> option;
  741. ASSERT_NO_THROW(
  742. option.reset(new OptionCustom(opt_def, Option::V4));
  743. );
  744. ASSERT_TRUE(option);
  745. asiolink::IOAddress address("127.0.0.1");
  746. ASSERT_NO_THROW(address = option->readAddress());
  747. EXPECT_EQ("0.0.0.0", address.toText());
  748. EXPECT_NO_THROW(option->writeAddress(IOAddress("192.168.0.1")));
  749. EXPECT_NO_THROW(address = option->readAddress());
  750. EXPECT_EQ("192.168.0.1", address.toText());
  751. }
  752. // The purpose of this test is to verify that an opton comprising
  753. // single IPv6 address can be created and that this address can
  754. // be overriden by a new value.
  755. TEST_F(OptionCustomTest, setIpv6AddressData) {
  756. OptionDefinition opt_def("OPTION_FOO", 1000, "ipv6-address");
  757. // Create an option and let the data field be initialized
  758. // to default value (do not provide any data buffer).
  759. boost::scoped_ptr<OptionCustom> option;
  760. ASSERT_NO_THROW(
  761. option.reset(new OptionCustom(opt_def, Option::V6));
  762. );
  763. ASSERT_TRUE(option);
  764. asiolink::IOAddress address("::1");
  765. ASSERT_NO_THROW(address = option->readAddress());
  766. EXPECT_EQ("::", address.toText());
  767. EXPECT_NO_THROW(option->writeAddress(IOAddress("2001:db8:1::1")));
  768. EXPECT_NO_THROW(address = option->readAddress());
  769. EXPECT_EQ("2001:db8:1::1", address.toText());
  770. }
  771. // The purpose of this test is to verify that an option comprising
  772. // single string value can be created and that this value
  773. // is initialized to the default value. Also, this test checks that
  774. // this value can be overwritten by a new value.
  775. TEST_F(OptionCustomTest, setStringData) {
  776. OptionDefinition opt_def("OPTION_FOO", 1000, "string");
  777. // Create an option and let the data field be initialized
  778. // to default value (do not provide any data buffer).
  779. boost::scoped_ptr<OptionCustom> option;
  780. ASSERT_NO_THROW(
  781. option.reset(new OptionCustom(opt_def, Option::V6));
  782. );
  783. ASSERT_TRUE(option);
  784. // Get the default value of the option.
  785. std::string value;
  786. ASSERT_NO_THROW(value = option->readString());
  787. // By default the string data field is empty.
  788. EXPECT_TRUE(value.empty());
  789. // Write some text to this field.
  790. EXPECT_NO_THROW(option->writeString("hello world"));
  791. // Check that it has been actually written.
  792. EXPECT_NO_THROW(value = option->readString());
  793. EXPECT_EQ("hello world", value);
  794. }
  795. // The purpose of this test is to verify that pack function for
  796. // DHCPv4 custom option works correctly.
  797. TEST_F(OptionCustomTest, pack4) {
  798. OptionDefinition opt_def("OPTION_FOO", 234, "record");
  799. ASSERT_NO_THROW(opt_def.addRecordField("uint8"));
  800. ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
  801. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  802. OptionBuffer buf;
  803. writeInt<uint8_t>(1, buf);
  804. writeInt<uint16_t>(1000, buf);
  805. writeInt<uint32_t>(100000, buf);
  806. boost::scoped_ptr<OptionCustom> option;
  807. ASSERT_NO_THROW(
  808. option.reset(new OptionCustom(opt_def, Option::V4, buf));
  809. );
  810. ASSERT_TRUE(option);
  811. util::OutputBuffer buf_out(7);
  812. ASSERT_NO_THROW(option->pack(buf_out));
  813. ASSERT_EQ(9, buf_out.getLength());
  814. // The original buffer holds the option data but it lacks a header.
  815. // We append data length and option code so as it can be directly
  816. // compared with the output buffer that holds whole option.
  817. buf.insert(buf.begin(), 7);
  818. buf.insert(buf.begin(), 234);
  819. // Validate the buffer.
  820. EXPECT_EQ(0, memcmp(&buf[0], buf_out.getData(), 7));
  821. }
  822. // The purpose of this test is to verify that pack function for
  823. // DHCPv6 custom option works correctly.
  824. TEST_F(OptionCustomTest, pack6) {
  825. OptionDefinition opt_def("OPTION_FOO", 1000, "record");
  826. ASSERT_NO_THROW(opt_def.addRecordField("boolean"));
  827. ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
  828. ASSERT_NO_THROW(opt_def.addRecordField("string"));
  829. OptionBuffer buf;
  830. buf.push_back(1);
  831. writeInt<uint16_t>(1000, buf);
  832. writeString("hello world", buf);
  833. boost::scoped_ptr<OptionCustom> option;
  834. ASSERT_NO_THROW(
  835. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  836. );
  837. ASSERT_TRUE(option);
  838. util::OutputBuffer buf_out(buf.size() + option->getHeaderLen());
  839. ASSERT_NO_THROW(option->pack(buf_out));
  840. ASSERT_EQ(buf.size() + option->getHeaderLen(), buf_out.getLength());
  841. // The original buffer holds the option data but it lacks a header.
  842. // We append data length and option code so as it can be directly
  843. // compared with the output buffer that holds whole option.
  844. OptionBuffer tmp;
  845. writeInt<uint16_t>(1000, tmp);
  846. writeInt<uint16_t>(buf.size(), tmp);
  847. buf.insert(buf.begin(), tmp.begin(), tmp.end());
  848. // Validate the buffer.
  849. EXPECT_EQ(0, memcmp(&buf[0], buf_out.getData(), 7));
  850. }
  851. // The purpose of this test is to verify that unpack function works
  852. // correctly for a custom option.
  853. TEST_F(OptionCustomTest, unpack) {
  854. OptionDefinition opt_def("OPTION_FOO", 231, "ipv4-address", true);
  855. // Initialize reference data.
  856. std::vector<IOAddress> addresses;
  857. addresses.push_back(IOAddress("192.168.0.1"));
  858. addresses.push_back(IOAddress("127.0.0.1"));
  859. addresses.push_back(IOAddress("10.10.1.2"));
  860. // Store the collection of IPv4 addresses into the buffer.
  861. OptionBuffer buf;
  862. for (int i = 0; i < addresses.size(); ++i) {
  863. writeAddress(addresses[i], buf);
  864. }
  865. // Use the input buffer to create custom option.
  866. boost::scoped_ptr<OptionCustom> option;
  867. ASSERT_NO_THROW(
  868. option.reset(new OptionCustom(opt_def, Option::V4, buf.begin(), buf.end()));
  869. );
  870. ASSERT_TRUE(option);
  871. // We should have 3 data fields.
  872. ASSERT_EQ(3, option->getDataFieldsNum());
  873. // We expect 3 IPv4 addresses being stored in the option.
  874. for (int i = 0; i < 3; ++i) {
  875. IOAddress address("10.10.10.10");
  876. ASSERT_NO_THROW(address = option->readAddress(i));
  877. EXPECT_EQ(addresses[i].toText(), address.toText());
  878. }
  879. // Remove all addresses we had added. We are going to replace
  880. // them with a new set of addresses.
  881. addresses.clear();
  882. // Add new addresses.
  883. addresses.push_back(IOAddress("10.1.2.3"));
  884. addresses.push_back(IOAddress("85.26.43.234"));
  885. // Clear the buffer as we need to store new addresses in it.
  886. buf.clear();
  887. for (int i = 0; i < addresses.size(); ++i) {
  888. writeAddress(addresses[i], buf);
  889. }
  890. // Perform 'unpack'.
  891. ASSERT_NO_THROW(option->unpack(buf.begin(), buf.end()));
  892. // Now we should have only 2 data fields.
  893. ASSERT_EQ(2, option->getDataFieldsNum());
  894. // Verify that the addresses have been overwritten.
  895. for (int i = 0; i < 2; ++i) {
  896. IOAddress address("10.10.10.10");
  897. ASSERT_NO_THROW(address = option->readAddress(i));
  898. EXPECT_EQ(addresses[i].toText(), address.toText());
  899. }
  900. }
  901. // The purpose of this test is to verify that new data can be set for
  902. // a custom option.
  903. TEST_F(OptionCustomTest, setData) {
  904. OptionDefinition opt_def("OPTION_FOO", 1000, "ipv6-address", true);
  905. // Initialize reference data.
  906. std::vector<IOAddress> addresses;
  907. addresses.push_back(IOAddress("2001:db8:1::3"));
  908. addresses.push_back(IOAddress("::1"));
  909. addresses.push_back(IOAddress("fe80::3"));
  910. // Store the collection of IPv6 addresses into the buffer.
  911. OptionBuffer buf;
  912. for (int i = 0; i < addresses.size(); ++i) {
  913. writeAddress(addresses[i], buf);
  914. }
  915. // Use the input buffer to create custom option.
  916. boost::scoped_ptr<OptionCustom> option;
  917. ASSERT_NO_THROW(
  918. option.reset(new OptionCustom(opt_def, Option::V6, buf.begin(), buf.end()));
  919. );
  920. ASSERT_TRUE(option);
  921. // We should have 3 data fields.
  922. ASSERT_EQ(3, option->getDataFieldsNum());
  923. // We expect 3 IPv6 addresses being stored in the option.
  924. for (int i = 0; i < 3; ++i) {
  925. IOAddress address("fe80::4");
  926. ASSERT_NO_THROW(address = option->readAddress(i));
  927. EXPECT_EQ(addresses[i].toText(), address.toText());
  928. }
  929. // Clear addresses we had previously added.
  930. addresses.clear();
  931. // Store new addresses.
  932. addresses.push_back(IOAddress("::1"));
  933. addresses.push_back(IOAddress("fe80::10"));
  934. // Clear the buffer as we need to store new addresses in it.
  935. buf.clear();
  936. for (int i = 0; i < addresses.size(); ++i) {
  937. writeAddress(addresses[i], buf);
  938. }
  939. // Replace the option data.
  940. ASSERT_NO_THROW(option->setData(buf.begin(), buf.end()));
  941. // Now we should have only 2 data fields.
  942. ASSERT_EQ(2, option->getDataFieldsNum());
  943. // Check that it has been replaced.
  944. for (int i = 0; i < 2; ++i) {
  945. IOAddress address("10.10.10.10");
  946. ASSERT_NO_THROW(address = option->readAddress(i));
  947. EXPECT_EQ(addresses[i].toText(), address.toText());
  948. }
  949. }
  950. // The purpose of this test is to verify that an invalid index
  951. // value can't be used to access option data fields.
  952. TEST_F(OptionCustomTest, invalidIndex) {
  953. OptionDefinition opt_def("OPTION_FOO", 999, "uint32", true);
  954. OptionBuffer buf;
  955. for (int i = 0; i < 10; ++i) {
  956. writeInt<uint32_t>(i, buf);
  957. }
  958. // Use the input buffer to create custom option.
  959. boost::scoped_ptr<OptionCustom> option;
  960. ASSERT_NO_THROW(
  961. option.reset(new OptionCustom(opt_def, Option::V6, buf));
  962. );
  963. ASSERT_TRUE(option);
  964. // We expect that there are 10 uint32_t values stored in
  965. // the option. The 10th element is accessed by index eq 9.
  966. // Check that 9 is accepted.
  967. EXPECT_NO_THROW(option->readInteger<uint32_t>(9));
  968. // Check that index value beyond 9 is not accepted.
  969. EXPECT_THROW(option->readInteger<uint32_t>(10), isc::OutOfRange);
  970. EXPECT_THROW(option->readInteger<uint32_t>(11), isc::OutOfRange);
  971. }
  972. } // anonymous namespace