}
Pkt4Ptr query = ex.getQuery();
+ Pkt4Ptr resp = ex.getResponse();
+ std::vector<uint8_t> requested_opts;
// try to get the 'Parameter Request List' option which holds the
// codes of requested options.
OptionUint8ArrayPtr option_prl = boost::dynamic_pointer_cast<
OptionUint8Array>(query->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST));
- // If there is no PRL option in the message from the client then
- // there is nothing to do.
- if (!option_prl) {
- return;
+ // Get the codes of requested options.
+ if (option_prl) {
+ requested_opts = option_prl->getValues();
+ }
+ // Iterate on the configured option list to add persistent options
+ for (CfgOptionList::const_iterator copts = co_list.begin();
+ copts != co_list.end(); ++copts) {
+ const OptionContainerPtr& opts = (*copts)->getAll(DHCP4_OPTION_SPACE);
+ if (!opts) {
+ continue;
+ }
+ // Get persistent options
+ const OptionContainerPersistIndex& idx = opts->get<2>();
+ const OptionContainerPersistRange& range = idx.equal_range(true);
+ for (OptionContainerPersistIndex::const_iterator desc = range.first;
+ desc != range.second; ++desc) {
+ // Add the persistent option code to requested options
+ if (desc->option_) {
+ uint8_t code = static_cast<uint8_t>(desc->option_->getType());
+ requested_opts.push_back(code);
+ }
+ }
}
- Pkt4Ptr resp = ex.getResponse();
-
- // Get the codes of requested options.
- const std::vector<uint8_t>& requested_opts = option_prl->getValues();
// For each requested option code get the instance of the option
// to be returned to the client.
for (std::vector<uint8_t>::const_iterator opt = requested_opts.begin();
}
uint32_t vendor_id = vendor_req->getVendorId();
+ std::vector<uint8_t> requested_opts;
// Let's try to get ORO within that vendor-option
/// @todo This is very specific to vendor-id=4491 (Cable Labs). Other
/// vendors may have different policies.
OptionUint8ArrayPtr oro =
boost::dynamic_pointer_cast<OptionUint8Array>(vendor_req->getOption(DOCSIS3_V4_ORO));
+ // Get the list of options that client requested.
+ if (oro) {
+ requested_opts = oro->getValues();
+ }
+ // Iterate on the configured option list to add persistent options
+ for (CfgOptionList::const_iterator copts = co_list.begin();
+ copts != co_list.end(); ++copts) {
+ const OptionContainerPtr& opts = (*copts)->getAll(vendor_id);
+ if (!opts) {
+ continue;
+ }
+ // Get persistent options
+ const OptionContainerPersistIndex& idx = opts->get<2>();
+ const OptionContainerPersistRange& range = idx.equal_range(true);
+ for (OptionContainerPersistIndex::const_iterator desc = range.first;
+ desc != range.second; ++desc) {
+ // Add the persistent option code to requested options
+ if (desc->option_) {
+ uint8_t code = static_cast<uint8_t>(desc->option_->getType());
+ requested_opts.push_back(code);
+ }
+ }
+ }
- // Option ORO not found. Don't do anything then.
- if (!oro) {
+ // If there is nothing to add don't do anything then.
+ if (requested_opts.empty()) {
return;
}
// Get the list of options that client requested.
bool added = false;
- const std::vector<uint8_t>& requested_opts = oro->getValues();
-
for (std::vector<uint8_t>::const_iterator code = requested_opts.begin();
code != requested_opts.end(); ++code) {
if (!vendor_rsp->getOption(*code)) {
// Expect a single option with the code equal to 100.
ASSERT_EQ(1, std::distance(range.first, range.second));
const uint8_t foo_expected[] = {
- 0xAB, 0xCD, 0xEF, 0x01, 0x05
+ 0xAB, 0xCD, 0xEF, 0x01, 0x05
};
// Check if option is valid in terms of code and carried data.
testOption(*range.first, 56, foo_expected, sizeof(foo_expected));
// Expect a single option with the code equal to 100.
ASSERT_EQ(1, std::distance(range1.first, range1.second));
const uint8_t foo_expected[] = {
- 0xAB, 0xCD, 0xEF, 0x01, 0x05
+ 0xAB, 0xCD, 0xEF, 0x01, 0x05
};
// Check if option is valid in terms of code and carried data.
testOption(*range1.first, 56, foo_expected, sizeof(foo_expected));
const OptionContainerTypeIndex& idx2 = options2->get<1>();
std::pair<OptionContainerTypeIndex::const_iterator,
- OptionContainerTypeIndex::const_iterator> range2 =
- idx2.equal_range(23);
+ OptionContainerTypeIndex::const_iterator> range2 =
+ idx2.equal_range(23);
ASSERT_EQ(1, std::distance(range2.first, range2.second));
const uint8_t foo2_expected[] = {
0x01
EXPECT_EQ("192.0.2.2", addrs[1].toText());
}
+// This test checks if Option Request Option (ORO) in docsis (vendor-id=4491)
+// vendor options is parsed correctly and persistent options are actually assigned.
+TEST_F(Dhcpv4SrvTest, vendorPersistentOptions) {
+ IfaceMgrTestConfig test_config(true);
+ IfaceMgr::instance().openSockets4();
+
+ NakedDhcpv4Srv srv(0);
+
+ ConstElementPtr x;
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ " \"option-data\": [ {"
+ " \"name\": \"tftp-servers\","
+ " \"space\": \"vendor-4491\","
+ " \"code\": 2,"
+ " \"data\": \"192.0.2.1, 192.0.2.2\","
+ " \"csv-format\": true,"
+ " \"persistent\": true"
+ " }],"
+ "\"subnet4\": [ { "
+ " \"pools\": [ { \"pool\": \"192.0.2.0/25\" } ],"
+ " \"subnet\": \"192.0.2.0/24\", "
+ " \"rebind-timer\": 2000, "
+ " \"renew-timer\": 1000, "
+ " \"valid-lifetime\": 4000,"
+ " \"interface\": \"eth0\" "
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ ConstElementPtr json;
+ ASSERT_NO_THROW(json = parseDHCP4(config));
+
+ EXPECT_NO_THROW(x = configureDhcp4Server(srv, json));
+ ASSERT_TRUE(x);
+ comment_ = isc::config::parseAnswer(rcode_, x);
+ ASSERT_EQ(0, rcode_);
+
+ CfgMgr::instance().commit();
+
+ boost::shared_ptr<Pkt4> dis(new Pkt4(DHCPDISCOVER, 1234));
+ // Set the giaddr and hops to non-zero address as if it was relayed.
+ dis->setGiaddr(IOAddress("192.0.2.1"));
+ dis->setHops(1);
+
+ OptionPtr clientid = generateClientId();
+ dis->addOption(clientid);
+ // Set interface. It is required by the server to generate server id.
+ dis->setIface("eth0");
+
+ // Let's add a vendor-option (vendor-id=4491).
+ OptionPtr vendor(new OptionVendor(Option::V4, 4491));
+ dis->addOption(vendor);
+
+ // Pass it to the server and get an advertise
+ Pkt4Ptr offer = srv.processDiscover(dis);
+
+ // check if we get response at all
+ ASSERT_TRUE(offer);
+
+ // Check if there is a vendor option response
+ OptionPtr tmp = offer->getOption(DHO_VIVSO_SUBOPTIONS);
+ ASSERT_TRUE(tmp);
+
+ // The response should be OptionVendor object
+ boost::shared_ptr<OptionVendor> vendor_resp =
+ boost::dynamic_pointer_cast<OptionVendor>(tmp);
+ ASSERT_TRUE(vendor_resp);
+
+ OptionPtr docsis2 = vendor_resp->getOption(DOCSIS3_V4_TFTP_SERVERS);
+ ASSERT_TRUE(docsis2);
+
+ Option4AddrLstPtr tftp_srvs = boost::dynamic_pointer_cast<Option4AddrLst>(docsis2);
+ ASSERT_TRUE(tftp_srvs);
+
+ Option4AddrLst::AddressContainer addrs = tftp_srvs->getAddresses();
+ ASSERT_EQ(2, addrs.size());
+ EXPECT_EQ("192.0.2.1", addrs[0].toText());
+ EXPECT_EQ("192.0.2.2", addrs[1].toText());
+}
+
// Test checks whether it is possible to use option definitions defined in
// src/lib/dhcp/docsis3_option_defs.h.
TEST_F(Dhcpv4SrvTest, vendorOptionsDocsisDefinitions) {
EXPECT_NE(0, opt->getUint8());
}
+// Checks class options have the priority over global persistent options
+TEST_F(Dhcpv4SrvTest, classGlobalPersistency) {
+ IfaceMgrTestConfig test_config(true);
+ IfaceMgr::instance().openSockets4();
+
+ NakedDhcpv4Srv srv(0);
+
+ // A global ip-forwarding option is set in the response.
+ // The router class matches incoming packets with foo in a host-name
+ // option (code 12) and sets an ip-forwarding option in the response.
+ // Note the persistency flag follows a "OR" semantic so to set
+ // it to false (or to leave the default) has no effect.
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ] }, "
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"valid-lifetime\": 4000, "
+ "\"subnet4\": [ "
+ "{ \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ], "
+ " \"subnet\": \"192.0.2.0/24\" } ], "
+ "\"option-data\": ["
+ " { \"name\": \"ip-forwarding\", "
+ " \"data\": \"false\", "
+ " \"persistent\": true } ], "
+ "\"client-classes\": [ "
+ "{ \"name\": \"router\","
+ " \"option-data\": ["
+ " { \"name\": \"ip-forwarding\", "
+ " \"data\": \"true\", "
+ " \"persistent\": false } ], "
+ " \"test\": \"option[12].text == 'foo'\" } ] }";
+
+ ConstElementPtr json;
+ ASSERT_NO_THROW(json = parseDHCP4(config));
+ ConstElementPtr status;
+
+ // Configure the server and make sure the config is accepted
+ EXPECT_NO_THROW(status = configureDhcp4Server(srv, json));
+ ASSERT_TRUE(status);
+ comment_ = config::parseAnswer(rcode_, status);
+ ASSERT_EQ(0, rcode_);
+
+ CfgMgr::instance().commit();
+
+ // Create a packet with enough to select the subnet and go through
+ // the DISCOVER processing
+ Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 1234));
+ query->setRemoteAddr(IOAddress("192.0.2.1"));
+ OptionPtr clientid = generateClientId();
+ query->addOption(clientid);
+ query->setIface("eth1");
+
+ // Do not add a PRL
+ OptionPtr prl = query->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST);
+ EXPECT_FALSE(prl);
+
+ // Create and add a host-name option to the query
+ OptionStringPtr hostname(new OptionString(Option::V4, 12, "foo"));
+ ASSERT_TRUE(hostname);
+ query->addOption(hostname);
+
+ // Classify the packet
+ srv.classifyPacket(query);
+
+ // The packet should be in the router class
+ EXPECT_TRUE(query->inClass("router"));
+
+ // Process the query
+ Pkt4Ptr response = srv.processDiscover(query);
+
+ // Processing should add an ip-forwarding option
+ OptionPtr opt = response->getOption(DHO_IP_FORWARDING);
+ ASSERT_TRUE(opt);
+ ASSERT_GT(opt->len(), opt->getHeaderLen());
+ // Classification sets the value to true/1, global to false/0
+ // Here class has the priority
+ EXPECT_NE(0, opt->getUint8());
+}
+
// Checks if the client-class field is indeed used for subnet selection.
// Note that packet classification is already checked in Dhcpv4SrvTest
// .*Classification above.
Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer,
const CfgOptionList& co_list) {
+ // Unlikely short cut
+ if (co_list.empty()) {
+ return;
+ }
+
+ std::vector<uint16_t> requested_opts;
+
// Client requests some options using ORO option. Try to
// get this option from client's message.
boost::shared_ptr<OptionIntArray<uint16_t> > option_oro =
boost::dynamic_pointer_cast<OptionIntArray<uint16_t> >
(question->getOption(D6O_ORO));
- // If there is no ORO option, there is nothing more to do.
- if (!option_oro) {
- return;
-
- }
-
// Get the list of options that client requested.
- const std::vector<uint16_t>& requested_opts = option_oro->getValues();
+ if (option_oro) {
+ requested_opts = option_oro->getValues();
+ }
+ // Iterate on the configured option list to add persistent options
+ for (CfgOptionList::const_iterator copts = co_list.begin();
+ copts != co_list.end(); ++copts) {
+ const OptionContainerPtr& opts = (*copts)->getAll(DHCP6_OPTION_SPACE);
+ if (!opts) {
+ continue;
+ }
+ // Get persistent options
+ const OptionContainerPersistIndex& idx = opts->get<2>();
+ const OptionContainerPersistRange& range = idx.equal_range(true);
+ for (OptionContainerPersistIndex::const_iterator desc = range.first;
+ desc != range.second; ++desc) {
+ // Add the persistent option code to requested options
+ requested_opts.push_back(desc->option_->getType());
+ }
+ }
BOOST_FOREACH(uint16_t opt, requested_opts) {
// Iterate on the configured option list
return;
}
+ uint32_t vendor_id = vendor_req->getVendorId();
+ std::vector<uint16_t> requested_opts;
+
// Let's try to get ORO within that vendor-option
/// @todo This is very specific to vendor-id=4491 (Cable Labs). Other vendors
/// may have different policies.
boost::shared_ptr<OptionUint16Array> oro =
boost::dynamic_pointer_cast<OptionUint16Array>(vendor_req->getOption(DOCSIS3_V6_ORO));
+ if (oro) {
+ requested_opts = oro->getValues();
+ }
+ // Iterate on the configured option list to add persistent options
+ for (CfgOptionList::const_iterator copts = co_list.begin();
+ copts != co_list.end(); ++copts) {
+ const OptionContainerPtr& opts = (*copts)->getAll(vendor_id);
+ if (!opts) {
+ continue;
+ }
+ // Get persistent options
+ const OptionContainerPersistIndex& idx = opts->get<2>();
+ const OptionContainerPersistRange& range = idx.equal_range(true);
+ for (OptionContainerPersistIndex::const_iterator desc = range.first;
+ desc != range.second; ++desc) {
+ // Add the persistent option code to requested options
+ requested_opts.push_back(desc->option_->getType());
+ }
+ }
- // Option ORO not found. Don't do anything then.
- if (!oro) {
+ // If there is nothing to add don't do anything then.
+ if (requested_opts.empty()) {
return;
}
- uint32_t vendor_id = vendor_req->getVendorId();
-
boost::shared_ptr<OptionVendor> vendor_rsp(new OptionVendor(Option::V6, vendor_id));
// Get the list of options that client requested.
bool added = false;
- const std::vector<uint16_t>& requested_opts = oro->getValues();
+
BOOST_FOREACH(uint16_t opt, requested_opts) {
for (CfgOptionList::const_iterator copts = co_list.begin();
copts != co_list.end(); ++copts) {
-// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
EXPECT_NE(0, opt->getUint8());
}
+// Checks class options have the priority over global persistent options
+TEST_F(ClassifyTest, classGlobalPersistency) {
+ IfaceMgrTestConfig test_config(true);
+
+ NakedDhcpv6Srv srv(0);
+
+ // Subnet sets an ipv6-forwarding option in the response.
+ // The router class matches incoming packets with foo in a host-name
+ // option (code 1234) and sets an ipv6-forwarding option in the response.
+ // Note the persistency flag follows a "OR" semantic so to set
+ // it to false (or to leave the default) has no effect.
+ std::string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ] }, "
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"valid-lifetime\": 4000, "
+ "\"option-def\": [ "
+ "{ \"name\": \"host-name\","
+ " \"code\": 1234,"
+ " \"type\": \"string\" },"
+ "{ \"name\": \"ipv6-forwarding\","
+ " \"code\": 2345,"
+ " \"type\": \"boolean\" }],"
+ "\"option-data\": ["
+ " { \"name\": \"ipv6-forwarding\", "
+ " \"data\": \"false\", "
+ " \"persistent\": true } ], "
+ "\"subnet6\": [ "
+ "{ \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ], "
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth1\", "
+ " \"option-data\": ["
+ " { \"name\": \"ipv6-forwarding\", "
+ " \"data\": \"false\", "
+ " \"persistent\": false } ] } ] }";
+ ASSERT_NO_THROW(configure(config));
+
+ // Create a packet with enough to select the subnet and go through
+ // the SOLICIT processing
+ Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 1234));
+ query->setRemoteAddr(IOAddress("fe80::abcd"));
+ OptionPtr clientid = generateClientId();
+ query->addOption(clientid);
+ query->setIface("eth1");
+ query->addOption(generateIA(D6O_IA_NA, 123, 1500, 3000));
+
+ // Do not add an ORO.
+ OptionPtr oro = query->getOption(D6O_ORO);
+ EXPECT_FALSE(oro);
+
+ // Create and add a host-name option to the query
+ OptionStringPtr hostname(new OptionString(Option::V6, 1234, "foo"));
+ ASSERT_TRUE(hostname);
+ query->addOption(hostname);
+
+ // Process the query
+ Pkt6Ptr response = srv.processSolicit(query);
+
+ // Processing should add an ip-forwarding option
+ OptionPtr opt = response->getOption(2345);
+ ASSERT_TRUE(opt);
+ ASSERT_GT(opt->len(), opt->getHeaderLen());
+ // Global sets the value to true/1, subnet to false/0
+ // Here subnet has the priority
+ EXPECT_EQ(0, opt->getUint8());
+}
+
// Checks if the client-class field is indeed used for subnet selection.
// Note that packet classification is already checked in ClassifyTest
// .*Classification above.
EXPECT_EQ("normal_erouter_v6.cm", config_file->getValue());
}
+// This test checks if Option Request Option (ORO) in docsis (vendor-id=4491)
+// vendor options is parsed correctly and the persistent options are actually assigned.
+TEST_F(Dhcpv6SrvTest, vendorPersistentOptions) {
+
+ IfaceMgrTestConfig test_config(true);
+
+ string config = "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ " \"option-def\": [ {"
+ " \"name\": \"config-file\","
+ " \"code\": 33,"
+ " \"type\": \"string\","
+ " \"space\": \"vendor-4491\""
+ " } ],"
+ " \"option-data\": [ {"
+ " \"name\": \"config-file\","
+ " \"space\": \"vendor-4491\","
+ " \"data\": \"normal_erouter_v6.cm\","
+ " \"persistent\": true"
+ " }],"
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"renew-timer\": 1000, "
+ " \"rebind-timer\": 1000, "
+ " \"preferred-lifetime\": 3000,"
+ " \"valid-lifetime\": 4000,"
+ " \"interface-id\": \"\","
+ " \"interface\": \"eth0\""
+ " } ],"
+ "\"valid-lifetime\": 4000 }";
+
+ ASSERT_NO_THROW(configure(config));
+
+ Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+ sol->setRemoteAddr(IOAddress("fe80::abcd"));
+ sol->setIface("eth0");
+ sol->addOption(generateIA(D6O_IA_NA, 234, 1500, 3000));
+ OptionPtr clientid = generateClientId();
+ sol->addOption(clientid);
+
+ // Let's add a vendor-option (vendor-id=4491).
+ OptionPtr vendor(new OptionVendor(Option::V6, 4491));
+ sol->addOption(vendor);
+
+ // Pass it to the server and get an advertise
+ Pkt6Ptr adv = srv_.processSolicit(sol);
+
+ // check if we get response at all
+ ASSERT_TRUE(adv);
+
+ // Check if there is vendor option response
+ OptionPtr tmp = adv->getOption(D6O_VENDOR_OPTS);
+ ASSERT_TRUE(tmp);
+
+ // The response should be OptionVendor object
+ boost::shared_ptr<OptionVendor> vendor_resp =
+ boost::dynamic_pointer_cast<OptionVendor>(tmp);
+ ASSERT_TRUE(vendor_resp);
+
+ OptionPtr docsis33 = vendor_resp->getOption(33);
+ ASSERT_TRUE(docsis33);
+
+ OptionStringPtr config_file = boost::dynamic_pointer_cast<OptionString>(docsis33);
+ ASSERT_TRUE(config_file);
+ EXPECT_EQ("normal_erouter_v6.cm", config_file->getValue());
+}
+
// Test checks whether it is possible to use option definitions defined in
// src/lib/dhcp/docsis3_option_defs.h.
TEST_F(Dhcpv6SrvTest, vendorOptionsDocsisDefinitions) {
OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
/// Type of the index #2 - option persistency flag.
typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
+/// Pair of iterators to represent the range of options having the
+/// same persistency flag. The first element in this pair represents
+/// the beginning of the range, the second element represents the end.
+typedef std::pair<OptionContainerPersistIndex::const_iterator,
+ OptionContainerPersistIndex::const_iterator> OptionContainerPersistRange;
/// @brief Represents option data configuration for the DHCP server.
///
// Look for the codes 100-109.
for (uint16_t code = 100; code < 110; ++ code) {
// For each code we should get two instances of options->
- std::pair<OptionContainerTypeIndex::const_iterator,
- OptionContainerTypeIndex::const_iterator> range =
- idx.equal_range(code);
+ OptionContainerTypeRange range = idx.equal_range(code);
// Distance between iterators indicates how many options
// have been returned for the particular code.
ASSERT_EQ(2, distance(range.first, range.second));
// Let's try to find some non-exiting option.
const uint16_t non_existing_code = 150;
- std::pair<OptionContainerTypeIndex::const_iterator,
- OptionContainerTypeIndex::const_iterator> range =
- idx.equal_range(non_existing_code);
+ OptionContainerTypeRange range = idx.equal_range(non_existing_code);
// Empty set is expected.
EXPECT_EQ(0, distance(range.first, range.second));
}
OptionContainerPersistIndex& idx = options->get<2>();
// Get all persistent options->
- std::pair<OptionContainerPersistIndex::const_iterator,
- OptionContainerPersistIndex::const_iterator> range_persistent =
- idx.equal_range(true);
- // 3 out of 10 options have been flagged persistent.
+ OptionContainerPersistRange range_persistent = idx.equal_range(true);
+ // 7 out of 10 options have been flagged persistent.
ASSERT_EQ(7, distance(range_persistent.first, range_persistent.second));
// Get all non-persistent options->
- std::pair<OptionContainerPersistIndex::const_iterator,
- OptionContainerPersistIndex::const_iterator> range_non_persistent =
- idx.equal_range(false);
- // 7 out of 10 options have been flagged persistent.
+ OptionContainerPersistRange range_non_persistent = idx.equal_range(false);
+ // 3 out of 10 options have been flagged not persistent.
ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
}
// Look for the codes 100-109.
for (uint16_t code = 100; code < 110; ++ code) {
// For each code we should get two instances of options->
- std::pair<OptionContainerTypeIndex::const_iterator,
- OptionContainerTypeIndex::const_iterator> range =
- idx.equal_range(code);
+ OptionContainerTypeRange range = idx.equal_range(code);
// Distance between iterators indicates how many options
// have been returned for the particular code.
ASSERT_EQ(2, distance(range.first, range.second));
// Let's try to find some non-exiting option.
const uint16_t non_existing_code = 150;
- std::pair<OptionContainerTypeIndex::const_iterator,
- OptionContainerTypeIndex::const_iterator> range =
- idx.equal_range(non_existing_code);
+ OptionContainerTypeRange range = idx.equal_range(non_existing_code);
// Empty set is expected.
EXPECT_EQ(0, distance(range.first, range.second));
}
OptionContainerPersistIndex& idx = options->get<2>();
// Get all persistent options->
- std::pair<OptionContainerPersistIndex::const_iterator,
- OptionContainerPersistIndex::const_iterator> range_persistent =
- idx.equal_range(true);
- // 3 out of 10 options have been flagged persistent.
+ OptionContainerPersistRange range_persistent = idx.equal_range(true);
+ // 7 out of 10 options have been flagged persistent.
ASSERT_EQ(7, distance(range_persistent.first, range_persistent.second));
// Get all non-persistent options->
- std::pair<OptionContainerPersistIndex::const_iterator,
- OptionContainerPersistIndex::const_iterator> range_non_persistent =
- idx.equal_range(false);
- // 7 out of 10 options have been flagged persistent.
+ OptionContainerPersistRange range_non_persistent = idx.equal_range(false);
+ // 3 out of 10 options have been flagged not persistent.
ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
}