BIND 10 trac2490, updated. 35c3fb162500afbfaab41533d160629a3f48017f [2490] Support for creating options using a collection of string values.
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Nov 20 17:32:49 UTC 2012
The branch, trac2490 has been updated
via 35c3fb162500afbfaab41533d160629a3f48017f (commit)
from ce7728b0d2d217cb0299b1a5b54470ed8c13148d (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 35c3fb162500afbfaab41533d160629a3f48017f
Author: Marcin Siodelski <marcin at isc.org>
Date: Tue Nov 20 18:32:29 2012 +0100
[2490] Support for creating options using a collection of string values.
-----------------------------------------------------------------------
Summary of changes:
src/lib/dhcp/option_data_types.h | 7 +
src/lib/dhcp/option_definition.cc | 164 +++++++++++++-
src/lib/dhcp/option_definition.h | 17 +-
src/lib/dhcp/tests/option_definition_unittest.cc | 249 +++++++++++++++++++++-
4 files changed, 419 insertions(+), 18 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/dhcp/option_data_types.h b/src/lib/dhcp/option_data_types.h
index c4e1a9c..2d5d64e 100644
--- a/src/lib/dhcp/option_data_types.h
+++ b/src/lib/dhcp/option_data_types.h
@@ -30,6 +30,13 @@ public:
isc::Exception(file, line, what) { };
};
+/// @brief Exception to be thrown when cast to the data type was unsuccessful.
+class BadDataTypeCast : public Exception {
+public:
+ BadDataTypeCast(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
/// @brief Data types of DHCP option fields.
enum OptionDataType {
diff --git a/src/lib/dhcp/option_definition.cc b/src/lib/dhcp/option_definition.cc
index 1d672f9..2a214fd 100644
--- a/src/lib/dhcp/option_definition.cc
+++ b/src/lib/dhcp/option_definition.cc
@@ -20,6 +20,7 @@
#include <dhcp/option6_int.h>
#include <dhcp/option6_int_array.h>
#include <dhcp/option_definition.h>
+#include <util/encode/hex.h>
using namespace std;
using namespace isc::util;
@@ -44,11 +45,6 @@ OptionDefinition::DataTypeUtil::DataTypeUtil() {
data_types_["record"] = OPT_RECORD_TYPE;
}
-template<typename T>
-T OptionDefinition::DataTypeUtil::dataTypeCast(const std::string& value_str) const {
- return (T());
-}
-
OptionDataType
OptionDefinition::DataTypeUtil::getOptionDataType(const std::string& data_type) {
std::map<std::string, OptionDataType>::const_iterator data_type_it =
@@ -59,6 +55,135 @@ OptionDefinition::DataTypeUtil::getOptionDataType(const std::string& data_type)
return (OPT_UNKNOWN_TYPE);
}
+template<typename T>
+T OptionDefinition::DataTypeUtil::lexicalCastWithRangeCheck(const std::string& value_str) const {
+ if (!OptionDataTypeTraits<T>::integer_type &&
+ OptionDataTypeTraits<T>::type != OPT_BOOLEAN_TYPE) {
+ isc_throw(BadDataTypeCast, "unable to do lexical cast to non-integer and"
+ << " non-boolean data type");
+ }
+ int64_t result = 0;
+ try {
+ result = boost::lexical_cast<int64_t>(value_str);
+ } catch (const boost::bad_lexical_cast& ex) {
+ std::string data_type_str = "boolean";
+ if (OptionDataTypeTraits<T>::integer_type) {
+ data_type_str = "integer";
+ }
+ isc_throw(BadDataTypeCast, "unable to do lexical cast to " << data_type_str
+ << " data type for value " << value_str << ": " << ex.what());
+ }
+ if (OptionDataTypeTraits<T>::integer_type) {
+ if (result > numeric_limits<T>::max() ||
+ result < numeric_limits<T>::min()) {
+ isc_throw(BadDataTypeCast, "unable to do lexical cast for value "
+ << value_str << ". This value is expected to be in the range of "
+ << numeric_limits<T>::min() << ".." << numeric_limits<T>::max());
+ }
+ }
+ return (static_cast<T>(result));
+}
+
+void
+OptionDefinition::DataTypeUtil::writeToBuffer(const std::string& value, uint16_t type,
+ OptionBuffer& buf) {
+ switch (type) {
+ case OPT_BINARY_TYPE:
+ {
+ OptionBuffer binary;
+ try {
+ util::encode::decodeHex(value, binary);
+ } catch (const Exception& ex) {
+ isc_throw(BadDataTypeCast, "unable to cast " << value
+ << " to binary data type: " << ex.what());
+ }
+ buf.insert(buf.end(), binary.begin(), binary.end());
+ return;
+ }
+ case OPT_BOOLEAN_TYPE:
+ {
+ bool bool_value = lexicalCastWithRangeCheck<bool>(value);
+ if (bool_value) {
+ buf.push_back(static_cast<uint8_t>(1));
+ } else {
+ buf.push_back(static_cast<uint8_t>(0));
+ }
+ return;
+ }
+ case OPT_INT8_TYPE:
+ {
+ buf.push_back(static_cast<uint8_t>(lexicalCastWithRangeCheck<int8_t>(value)));
+ return;
+ }
+ case OPT_INT16_TYPE:
+ {
+ int16_t int_value = lexicalCastWithRangeCheck<int16_t>(value);
+ buf.resize(buf.size() + 2);
+ writeUint16(static_cast<uint16_t>(int_value), &buf[buf.size() - 2]);
+ return;
+ }
+ case OPT_INT32_TYPE:
+ {
+ int32_t int_value = lexicalCastWithRangeCheck<int32_t>(value);
+ buf.resize(buf.size() + 4);
+ writeUint32(static_cast<uint32_t>(int_value), &buf[buf.size() - 4]);
+ return;
+ }
+ case OPT_UINT8_TYPE:
+ {
+ buf.push_back(lexicalCastWithRangeCheck<int8_t>(value));
+ return;
+ }
+ case OPT_UINT16_TYPE:
+ {
+ uint16_t uint_value = lexicalCastWithRangeCheck<uint16_t>(value);
+ buf.resize(buf.size() + 2);
+ writeUint16(uint_value, &buf[buf.size() - 2]);
+ return;
+ }
+ case OPT_UINT32_TYPE:
+ {
+ uint32_t uint_value = lexicalCastWithRangeCheck<uint32_t>(value);
+ buf.resize(buf.size() + 4);
+ writeUint32(uint_value, &buf[buf.size() - 4]);
+ return;
+ }
+ case OPT_IPV4_ADDRESS_TYPE:
+ {
+ asiolink::IOAddress address(value);
+ if (!address.getAddress().is_v4()) {
+ isc_throw(BadDataTypeCast, "provided address " << address.toText()
+ << " is not a valid IPV4 address");
+ }
+ asio::ip::address_v4::bytes_type addr_bytes =
+ address.getAddress().to_v4().to_bytes();
+ buf.resize(buf.size() + addr_bytes.size());
+ std::copy_backward(addr_bytes.begin(), addr_bytes.end(),
+ buf.end());
+ return;
+ }
+ case OPT_IPV6_ADDRESS_TYPE:
+ {
+ asiolink::IOAddress address(value);
+ if (!address.getAddress().is_v6()) {
+ isc_throw(BadDataTypeCast, "provided address " << address.toText()
+ << " is not a valid IPV6 address");
+ }
+ asio::ip::address_v6::bytes_type addr_bytes =
+ address.getAddress().to_v6().to_bytes();
+ buf.resize(buf.size() + addr_bytes.size());
+ std::copy_backward(addr_bytes.begin(), addr_bytes.end(),
+ buf.end());
+ return;
+ }
+ default:
+ ;
+ }
+ isc_throw(isc::NotImplemented, "write of string, FQDN record into option buffer"
+ " is not supported yet");
+
+}
+
OptionDefinition::OptionDefinition(const std::string& name,
const uint16_t code,
const std::string& type,
@@ -148,9 +273,32 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
}
OptionPtr
-OptionDefinition::optionFactory(Option::Universe, uint16_t,
- const std::vector<std::string>&) const {
- return (OptionPtr());
+OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
+ const std::vector<std::string>& values) const {
+ validate();
+
+ OptionBuffer buf;
+ if (!array_type_ && type_ != OPT_RECORD_TYPE) {
+ if (values.size() == 0) {
+ isc_throw(InvalidOptionValue, "no option value specified");
+ }
+ DataTypeUtil::instance().writeToBuffer(values[0], type_, buf);
+ } else if (array_type_ && type_ != OPT_RECORD_TYPE) {
+ for (size_t i = 0; i < values.size(); ++i) {
+ DataTypeUtil::instance().writeToBuffer(values[i], type_, buf);
+ }
+ } else if (type_ == OPT_RECORD_TYPE) {
+ const RecordFieldsCollection& records = getRecordFields();
+ if (records.size() > values.size()) {
+ isc_throw(InvalidOptionValue, "number of data fields for the option"
+ << " type " << type_ << " is greater than number of values"
+ << " provided.");
+ }
+ for (size_t i = 0; i < records.size(); ++i) {
+ DataTypeUtil::instance().writeToBuffer(values[i], records[i], buf);
+ }
+ }
+ return (optionFactory(u, type, buf.begin(), buf.end()));
}
void
diff --git a/src/lib/dhcp/option_definition.h b/src/lib/dhcp/option_definition.h
index 3984028..5224499 100644
--- a/src/lib/dhcp/option_definition.h
+++ b/src/lib/dhcp/option_definition.h
@@ -27,6 +27,14 @@
namespace isc {
namespace dhcp {
+/// @brief Exception to be thrown when invalid option value has been
+/// specified for a particular option definition.
+class InvalidOptionValue : public Exception {
+public:
+ InvalidOptionValue(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
/// @brief Forward declaration to OptionDefinition.
class OptionDefinition;
@@ -137,9 +145,6 @@ private:
return (instance);
}
- template<typename T>
- T dataTypeCast(const std::string& value_str) const;
-
/// @brief Convert type given as string value to option data type.
///
/// @param data_type_name data type string.
@@ -147,6 +152,12 @@ private:
/// @return option data type.
OptionDataType getOptionDataType(const std::string& data_type_name);
+ template<typename T>
+ T lexicalCastWithRangeCheck(const std::string& value_str) const;
+
+ void writeToBuffer(const std::string& value, uint16_t type,
+ OptionBuffer& buf);
+
private:
/// @brief Private constructor.
///
diff --git a/src/lib/dhcp/tests/option_definition_unittest.cc b/src/lib/dhcp/tests/option_definition_unittest.cc
index 18b46bf..0f7191a 100644
--- a/src/lib/dhcp/tests/option_definition_unittest.cc
+++ b/src/lib/dhcp/tests/option_definition_unittest.cc
@@ -202,7 +202,7 @@ TEST_F(OptionDefinitionTest, factoryAddrList6) {
// can be used to create option instance with the optionFactory function.
TEST_F(OptionDefinitionTest, factoryTokenizedAddrList6) {
OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,
- "ipv6_address", true);
+ "ipv6-address", true);
// Create a vector of some V6 addresses.
std::vector<asiolink::IOAddress> addrs;
@@ -225,11 +225,7 @@ TEST_F(OptionDefinitionTest, factoryTokenizedAddrList6) {
option_v6 = opt_def.optionFactory(Option::V6, D6O_NIS_SERVERS,
addrs_str);
);
- // This is temporary check to make this test pass until factory function is
- // implemented and returns the pointer rather than NULL.
- ASSERT_FALSE(option_v6);
-
- /* // Non-null pointer option is supposed to be returned and it
+ // Non-null pointer option is supposed to be returned and it
// should have Option6AddrLst type.
ASSERT_TRUE(option_v6);
ASSERT_TRUE(typeid(*option_v6) == typeid(Option6AddrLst));
@@ -243,7 +239,7 @@ TEST_F(OptionDefinitionTest, factoryTokenizedAddrList6) {
option_cast_v6->getAddresses();
// Returned addresses must match the addresses that have been used to create
// the option instance.
- EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin())); */
+ EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
}
TEST_F(OptionDefinitionTest, factoryAddrList4) {
@@ -292,6 +288,50 @@ TEST_F(OptionDefinitionTest, factoryAddrList4) {
isc::OutOfRange);
}
+// This test checks that a vector of strings, holding IPv4 addresses,
+// can be used to create option instance with the optionFactory function.
+TEST_F(OptionDefinitionTest, factoryTokenizedAddrList4) {
+ OptionDefinition opt_def("OPTION_NIS_SERVERS", DHO_NIS_SERVERS,
+ "ipv4-address", true);
+
+ // Create a vector of some V6 addresses.
+ std::vector<asiolink::IOAddress> addrs;
+ addrs.push_back(asiolink::IOAddress("192.168.0.1"));
+ addrs.push_back(asiolink::IOAddress("172.16.1.1"));
+ addrs.push_back(asiolink::IOAddress("127.0.0.1"));
+ addrs.push_back(asiolink::IOAddress("213.41.23.12"));
+
+ // Create a vector of strings representing addresses given above.
+ std::vector<std::string> addrs_str;
+ for (std::vector<asiolink::IOAddress>::const_iterator it = addrs.begin();
+ it != addrs.end(); ++it) {
+ addrs_str.push_back(it->toText());
+ }
+
+ // Create DHCPv4 option using the list of IPv4 addresses given in the
+ // string form.
+ OptionPtr option_v4;
+ ASSERT_NO_THROW(
+ option_v4 = opt_def.optionFactory(Option::V4, DHO_NIS_SERVERS,
+ addrs_str);
+ );
+ // Non-null pointer option is supposed to be returned and it
+ // should have Option6AddrLst type.
+ ASSERT_TRUE(option_v4);
+ ASSERT_TRUE(typeid(*option_v4) == typeid(Option4AddrLst));
+ // Cast to the actual option type to get IPv4 addresses from it.
+ boost::shared_ptr<Option4AddrLst> option_cast_v4 =
+ boost::static_pointer_cast<Option4AddrLst>(option_v4);
+ // Check that cast was successful.
+ ASSERT_TRUE(option_cast_v4);
+ // Get the list of parsed addresses from the option object.
+ std::vector<asiolink::IOAddress> addrs_returned =
+ option_cast_v4->getAddresses();
+ // Returned addresses must match the addresses that have been used to create
+ // the option instance.
+ EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
+}
+
TEST_F(OptionDefinitionTest, factoryEmpty) {
OptionDefinition opt_def("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT, "empty");
@@ -362,6 +402,53 @@ TEST_F(OptionDefinitionTest, factoryBinary) {
buf.begin()));
}
+TEST_F(OptionDefinitionTest, factoryTokenizedBinary) {
+ OptionDefinition opt_def("OPTION_FOO", 1000, "binary", true);
+
+ // Prepare some dummy data (serverid): 0, 1, 2 etc.
+ OptionBuffer buf(16);
+ for (int i = 0; i < buf.size(); ++i) {
+ buf[i] = i;
+ }
+ std::vector<std::string> hex_data;
+ hex_data.push_back("00010203");
+ hex_data.push_back("04050607");
+ hex_data.push_back("08090A0B0C0D0E0F");
+
+ // Create option instance with the factory function.
+ // If the OptionDefinition code works properly than
+ // object of the type Option should be returned.
+ OptionPtr option_v6;
+ ASSERT_NO_THROW(
+ option_v6 = opt_def.optionFactory(Option::V6, 1000, hex_data);
+ );
+ // Expect base option type returned.
+ ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
+ // Sanity check on universe, length and size. These are
+ // the basic parameters identifying any option.
+ EXPECT_EQ(Option::V6, option_v6->getUniverse());
+ EXPECT_EQ(4, option_v6->getHeaderLen());
+ ASSERT_EQ(buf.size(), option_v6->getData().size());
+
+ // Get data from the option and compare against reference buffer.
+ // They are expected to match.
+ EXPECT_TRUE(std::equal(option_v6->getData().begin(),
+ option_v6->getData().end(),
+ buf.begin()));
+
+ // Repeat the same test scenario for DHCPv4 option.
+ OptionPtr option_v4;
+ ASSERT_NO_THROW(option_v4 = opt_def.optionFactory(Option::V4, 214, hex_data));
+ EXPECT_EQ(Option::V4, option_v4->getUniverse());
+ EXPECT_EQ(2, option_v4->getHeaderLen());
+ ASSERT_EQ(buf.size(), option_v4->getData().size());
+
+ EXPECT_TRUE(std::equal(option_v6->getData().begin(),
+ option_v6->getData().end(),
+ buf.begin()));
+}
+
+
TEST_F(OptionDefinitionTest, factoryIA6) {
// This option consists of IAID, T1 and T2 fields (each 4 bytes long).
const int option6_ia_len = 12;
@@ -444,6 +531,37 @@ TEST_F(OptionDefinitionTest, factoryIAAddr6) {
);
}
+TEST_F(OptionDefinitionTest, factoryTokenizedIAAddr6) {
+ // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
+ // valid-lifetime fields (each 4 bytes long).
+ OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
+ ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
+ ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
+ ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
+
+ // Check the positive scenario.
+ std::vector<std::string> data_field_values;
+ data_field_values.push_back("2001:0db8::ff00:0042:8329");
+ data_field_values.push_back("1234");
+ data_field_values.push_back("5678");
+
+ OptionPtr option_v6;
+ ASSERT_NO_THROW(option_v6 = opt_def.optionFactory(Option::V6, D6O_IAADDR,
+ data_field_values));
+ ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IAAddr));
+ boost::shared_ptr<Option6IAAddr> option_cast_v6 =
+ boost::static_pointer_cast<Option6IAAddr>(option_v6);
+ EXPECT_EQ("2001:db8::ff00:42:8329", option_cast_v6->getAddress().toText());
+ EXPECT_EQ(1234, option_cast_v6->getPreferred());
+ EXPECT_EQ(5678, option_cast_v6->getValid());
+
+ // This should work for DHCPv6 only, try passing in\valid universe value.
+ EXPECT_THROW(
+ opt_def.optionFactory(Option::V4, D6O_IAADDR, data_field_values),
+ isc::BadValue
+ );
+}
+
TEST_F(OptionDefinitionTest, factoryIntegerInvalidType) {
// The template function factoryInteger<> accepts integer values only
// as template typename. Here we try passing different type and
@@ -479,6 +597,31 @@ TEST_F(OptionDefinitionTest, factoryUint8) {
// @todo Add more cases for DHCPv4
}
+TEST_F(OptionDefinitionTest, factoryTokenizedUint8) {
+ OptionDefinition opt_def("OPTION_PREFERENCE", D6O_PREFERENCE, "uint8");
+
+ OptionPtr option_v6;
+ std::vector<std::string> values;
+ values.push_back("123");
+ values.push_back("456");
+ try {
+ option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, values);
+ } catch (std::exception& ex) {
+ std::cout << ex.what() << std::endl;
+ }
+ ASSERT_NO_THROW(
+ option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, values);
+ );
+ ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint8_t>));
+ // Validate the value.
+ boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
+ boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
+ EXPECT_EQ(123, option_cast_v6->getValue());
+
+ // @todo Add more cases for DHCPv4
+}
+
+
TEST_F(OptionDefinitionTest, factoryUint16) {
OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
@@ -505,6 +648,27 @@ TEST_F(OptionDefinitionTest, factoryUint16) {
// @todo Add more cases for DHCPv4
}
+TEST_F(OptionDefinitionTest, factoryTokenizedUint16) {
+ OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
+
+ OptionPtr option_v6;
+
+ std::vector<std::string> values;
+ values.push_back("1234");
+ values.push_back("5678");
+ ASSERT_NO_THROW(
+ option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, values);
+ );
+ ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint16_t>));
+ // Validate the value.
+ boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
+ boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
+ EXPECT_EQ(1234, option_cast_v6->getValue());
+
+ // @todo Add more cases for DHCPv4
+
+}
+
TEST_F(OptionDefinitionTest, factoryUint32) {
OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
@@ -532,6 +696,26 @@ TEST_F(OptionDefinitionTest, factoryUint32) {
// @todo Add more cases for DHCPv4
}
+TEST_F(OptionDefinitionTest, factoryTokenizedUint32) {
+ OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
+
+ OptionPtr option_v6;
+ std::vector<std::string> values;
+ values.push_back("123456");
+ values.push_back("789");
+ ASSERT_NO_THROW(
+ option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, values);
+ );
+ ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint32_t>));
+ // Validate the value.
+ boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
+ boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
+ EXPECT_EQ(123456, option_cast_v6->getValue());
+
+ // @todo Add more cases for DHCPv4
+}
+
+
TEST_F(OptionDefinitionTest, factoryUint16Array) {
// Let's define some dummy option.
const uint16_t opt_code = 79;
@@ -575,6 +759,30 @@ TEST_F(OptionDefinitionTest, factoryUint16Array) {
);
}
+TEST_F(OptionDefinitionTest, factoryTokenizedUint16Array) {
+ // Let's define some dummy option.
+ const uint16_t opt_code = 79;
+ OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
+
+ OptionPtr option_v6;
+ std::vector<std::string> str_values;
+ str_values.push_back("12345");
+ str_values.push_back("5679");
+ str_values.push_back("12");
+ EXPECT_NO_THROW(
+ option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
+ );
+ ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint16_t>));
+ boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
+ boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
+ // Get the values from the initiated options and validate.
+ std::vector<uint16_t> values = option_cast_v6->getValues();
+ EXPECT_EQ(12345, values[0]);
+ EXPECT_EQ(5679, values[1]);
+ EXPECT_EQ(12, values[2]);
+}
+
+
TEST_F(OptionDefinitionTest, factoryUint32Array) {
// Let's define some dummy option.
const uint16_t opt_code = 80;
@@ -619,6 +827,33 @@ TEST_F(OptionDefinitionTest, factoryUint32Array) {
);
}
+TEST_F(OptionDefinitionTest, factoryTokenizedUint32Array) {
+ // Let's define some dummy option.
+ const uint16_t opt_code = 80;
+
+ OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
+
+ OptionPtr option_v6;
+ std::vector<std::string> str_values;
+ str_values.push_back("123456");
+ str_values.push_back("7");
+ str_values.push_back("256");
+ str_values.push_back("1111");
+
+ EXPECT_NO_THROW(
+ option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
+ );
+ ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint32_t>));
+ boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
+ boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
+ // Get the values from the initiated options and validate.
+ std::vector<uint32_t> values = option_cast_v6->getValues();
+ EXPECT_EQ(123456, values[0]);
+ EXPECT_EQ(7, values[1]);
+ EXPECT_EQ(256, values[2]);
+ EXPECT_EQ(1111, values[3]);
+}
+
TEST_F(OptionDefinitionTest, recognizeFormat) {
// IA_NA option format.
OptionDefinition opt_def1("OPTION_IA_NA", D6O_IA_NA, "record");
More information about the bind10-changes
mailing list