continue;
}
- if (iface != (*subnet)->getIface()) {
+ if ((*subnet)->getIface() != iface) {
isc_throw(DhcpConfigError, "Subnet " << (*subnet)->toText()
<< " has specified interface " << (*subnet)->getIface()
<< ", but earlier subnet in the same shared-network"
<< " or the shared-network itself used " << iface);
}
- if (authoritative != (*subnet)->getAuthoritative()) {
+ if ((*subnet)->getAuthoritative() != authoritative) {
isc_throw(DhcpConfigError, "Subnet " << (*subnet)->toText()
<< " has different authoritative setting "
<< (*subnet)->getAuthoritative()
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
- EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText());
- EXPECT_EQ("foo", subnet->getSname());
- EXPECT_EQ("bar", subnet->getFilename());
+ EXPECT_EQ("1.2.3.4", subnet->getSiaddr().get().toText());
+ EXPECT_EQ("foo", subnet->getSname().get());
+ EXPECT_EQ("bar", subnet->getFilename().get());
}
// Checks if the next-server and other fixed BOOTP fields defined as
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
- EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText());
- EXPECT_EQ("foo", subnet->getSname());
- EXPECT_EQ("bar", subnet->getFilename());
+ EXPECT_EQ("1.2.3.4", subnet->getSiaddr().get().toText());
+ EXPECT_EQ("foo", subnet->getSname().get());
+ EXPECT_EQ("bar", subnet->getFilename().get());
}
// Test checks several negative scenarios for next-server configuration: bogus
Subnet4Ptr subnet = CfgMgr::instance().getStagingCfg()->
getCfgSubnets4()->selectSubnet(IOAddress("192.0.2.200"));
ASSERT_TRUE(subnet);
- EXPECT_EQ("1.2.3.4", subnet->getSiaddr().toText());
- EXPECT_EQ("some-name.example.org", subnet->getSname());
- EXPECT_EQ("bootfile.efi", subnet->getFilename());
+ EXPECT_EQ("1.2.3.4", subnet->getSiaddr().get().toText());
+ EXPECT_EQ("some-name.example.org", subnet->getSname().get());
+ EXPECT_EQ("bootfile.efi", subnet->getFilename().get());
}
// Check whether it is possible to configure echo-client-id
ASSERT_TRUE(s);
// These are values derived from shared network scope:
- EXPECT_EQ("eth0", s->getIface());
+ EXPECT_EQ("eth0", s->getIface().get());
EXPECT_FALSE(s->getMatchClientId());
EXPECT_TRUE(s->getAuthoritative());
EXPECT_EQ(IOAddress("1.2.3.4"), s->getSiaddr());
- EXPECT_EQ("foo", s->getSname());
- EXPECT_EQ("bar", s->getFilename());
+ EXPECT_EQ("foo", s->getSname().get());
+ EXPECT_EQ("bar", s->getFilename().get());
EXPECT_TRUE(s->hasRelayAddress(IOAddress("5.6.7.8")));
EXPECT_EQ(Network::HR_OUT_OF_POOL, s->getHostReservationMode());
s = checkSubnet(*subs, "192.0.2.0/24", 100, 200, 400);
// These are values derived from shared network scope:
- EXPECT_EQ("eth0", s->getIface());
+ EXPECT_EQ("eth0", s->getIface().get());
EXPECT_TRUE(s->getMatchClientId());
EXPECT_TRUE(s->getAuthoritative());
- EXPECT_EQ(IOAddress("11.22.33.44"), s->getSiaddr());
- EXPECT_EQ("some-name.example.org", s->getSname());
- EXPECT_EQ("bootfile.efi", s->getFilename());
+ EXPECT_EQ(IOAddress("11.22.33.44"), s->getSiaddr().get());
+ EXPECT_EQ("some-name.example.org", s->getSname().get());
+ EXPECT_EQ("bootfile.efi", s->getFilename().get());
EXPECT_TRUE(s->hasRelayAddress(IOAddress("55.66.77.88")));
EXPECT_EQ(Network::HR_DISABLED, s->getHostReservationMode());
// This subnet should derive its renew-timer from global scope.
// All other parameters should have default values.
s = checkSubnet(*subs, "192.0.3.0/24", 1, 2, 4);
- EXPECT_EQ("", s->getIface());
+ EXPECT_EQ("", s->getIface().get());
EXPECT_TRUE(s->getMatchClientId());
EXPECT_FALSE(s->getAuthoritative());
EXPECT_EQ(IOAddress("0.0.0.0"), s->getSiaddr());
SharedNetwork4Ptr net = nets->at(0);
ASSERT_TRUE(net);
- EXPECT_EQ("alpha", net->getClientClass());
+ EXPECT_EQ("alpha", net->getClientClass().get());
// The first shared network has two subnets.
const Subnet4Collection * subs = net->getAllSubnets();
// shared-network level.
Subnet4Ptr s = checkSubnet(*subs, "192.0.1.0/24", 1, 2, 4);
ASSERT_TRUE(s);
- EXPECT_EQ("alpha", s->getClientClass());
+ EXPECT_EQ("alpha", s->getClientClass().get());
// For the second subnet, the values are overridden on subnet level.
// The value should not be inherited.
s = checkSubnet(*subs, "192.0.2.0/24", 1, 2, 4);
- EXPECT_EQ("beta", s->getClientClass()); // beta defined on subnet level
+ EXPECT_EQ("beta", s->getClientClass().get()); // beta defined on subnet level
// Ok, now check the second shared network. It doesn't have anything defined
// on shared-network or subnet level, so everything should have default
-// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2019 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
continue;
}
- if (iface != (*subnet)->getIface()) {
+ if ((*subnet)->getIface() != iface) {
isc_throw(DhcpConfigError, "Subnet " << (*subnet)->toText()
<< " has specified interface " << (*subnet)->getIface()
<< ", but earlier subnet in the same shared-network"
-// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2019 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
Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
selectSubnet(IOAddress("2001:db8:1::5"), classify_);
ASSERT_TRUE(subnet);
- EXPECT_EQ(valid_iface_, subnet->getIface());
+ EXPECT_EQ(valid_iface_, subnet->getIface().get());
}
// This test checks if invalid interface name will be rejected in
// subnet6 level.
Subnet6Ptr s = checkSubnet(*subs, "2001:db1::/48", 900, 1800, 3600, 7200);
ASSERT_TRUE(s);
- EXPECT_EQ("eth0", s->getIface());
+ EXPECT_EQ("eth0", s->getIface().get());
// For the second subnet, the renew-timer should be 100, because it
// was specified explicitly. Other parameters a derived
// from global scope to shared-network level and later again to
// subnet6 level.
checkSubnet(*subs, "2001:db2::/48", 900, 1800, 3600, 7200);
- EXPECT_EQ("eth0", s->getIface());
+ EXPECT_EQ("eth0", s->getIface().get());
// Ok, now check the second shared subnet.
net = nets->at(1);
// This subnet should derive its renew-timer from global scope.
s = checkSubnet(*subs, "2001:db3::/48", 900, 1800, 3600, 7200);
- EXPECT_EQ("", s->getIface());
+ EXPECT_EQ("", s->getIface().get());
}
// Let's check the first one.
SharedNetwork6Ptr net = nets->at(0);
ASSERT_TRUE(net);
- EXPECT_EQ("alpha", net->getClientClass());
+ EXPECT_EQ("alpha", net->getClientClass().get());
const Subnet6Collection * subs = net->getAllSubnets();
ASSERT_TRUE(subs);
// shared-network level.
Subnet6Ptr s = checkSubnet(*subs, "2001:db1::/48", 900, 1800, 3600, 7200);
ASSERT_TRUE(s);
- EXPECT_EQ("alpha", s->getClientClass());
+ EXPECT_EQ("alpha", s->getClientClass().get());
// For the second subnet, the values are overridden on subnet level.
// The value should not be inherited.
s = checkSubnet(*subs, "2001:db2::/48", 900, 1800, 3600, 7200);
ASSERT_TRUE(s);
- EXPECT_EQ("beta", s->getClientClass()); // beta defined on subnet level
+ EXPECT_EQ("beta", s->getClientClass().get()); // beta defined on subnet level
// Ok, now check the second shared network. It doesn't have
// anything defined on shared-network or subnet level, so
MySqlBinding::condCreateString(subnet->getIface()),
MySqlBinding::createInteger<uint8_t>(static_cast<uint8_t>(subnet->getMatchClientId())),
MySqlBinding::createTimestamp(subnet->getModificationTime()),
- MySqlBinding::condCreateInteger<uint32_t>(subnet->getSiaddr().toUint32()),
+ MySqlBinding::condCreateInteger<uint32_t>(subnet->getSiaddr().get().toUint32()),
createBinding(subnet->getT2()),
createInputRelayBinding(subnet),
createBinding(subnet->getT1()),
-// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2019 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
// If interface name matches with the one specified for the subnet
// and the client is not rejected based on the classification,
// return the subnet.
- if ((iface_name == (*subnet)->getIface()) &&
+ if (((*subnet)->getIface() == iface_name) &&
(*subnet)->clientSupported(client_classes)) {
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE,
using namespace isc::asiolink;
using namespace isc::data;
+using namespace isc::util;
namespace isc {
namespace dhcp {
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/cfg_4o6.h>
#include <dhcpsrv/triplet.h>
+#include <util/optional.h>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <cstdint>
/// other resources to a client.
///
/// @param iface_name Interface name.
- void setIface(const std::string& iface_name) {
+ void setIface(const util::Optional<std::string>& iface_name) {
iface_name_ = iface_name;
}
/// selected.
///
/// @return Interface name as text.
- std::string getIface() const {
+ util::Optional<std::string> getIface() const {
return (iface_name_);
};
void requireClientClass(const isc::dhcp::ClientClass& class_name);
/// @brief Returns classes which are required to be evaluated
- const isc::dhcp::ClientClasses& getRequiredClasses() const;
+ const ClientClasses& getRequiredClasses() const;
/// @brief returns the client class
///
/// returned it is valid.
///
/// @return client class @ref client_class_
- const isc::dhcp::ClientClass& getClientClass() const {
+ const util::Optional<ClientClass>& getClientClass() const {
return (client_class_);
}
/// performance reasons.
///
/// @return whether in-pool host reservations are allowed.
- HRMode
+ util::Optional<HRMode>
getHostReservationMode() const {
return (host_reservation_mode_);
}
/// See @ref getHostReservationMode for details.
///
/// @param mode mode to be set
- void setHostReservationMode(HRMode mode) {
+ void setHostReservationMode(const util::Optional<HRMode>& mode) {
host_reservation_mode_ = mode;
}
}
/// @brief Returns whether or not T1/T2 calculation is enabled.
- bool getCalculateTeeTimes() const {
+ util::Optional<bool> getCalculateTeeTimes() const {
return (calculate_tee_times_);
}
/// @brief Sets whether or not T1/T2 calculation is enabled.
///
/// @param calculate_tee_times new value of enabled/disabled.
- void setCalculateTeeTimes(const bool& calculate_tee_times) {
+ void setCalculateTeeTimes(const util::Optional<bool>& calculate_tee_times) {
calculate_tee_times_ = calculate_tee_times;
}
/// @brief Returns percentage to use when calculating the T1 (renew timer).
- double getT1Percent() const {
+ util::Optional<double> getT1Percent() const {
return (t1_percent_);
}
/// @brief Sets new precentage for calculating T1 (renew timer).
///
/// @param t1_percent New percentage to use.
- void setT1Percent(const double& t1_percent) {
+ void setT1Percent(const util::Optional<double>& t1_percent) {
t1_percent_ = t1_percent;
}
/// @brief Returns percentage to use when calculating the T2 (rebind timer).
- double getT2Percent() const {
+ util::Optional<double> getT2Percent() const {
return (t2_percent_);
}
/// @brief Sets new precentage for calculating T2 (rebind timer).
///
/// @param t2_percent New percentage to use.
- void setT2Percent(const double& t2_percent) {
+ void setT2Percent(const util::Optional<double>& t2_percent) {
t2_percent_ = t2_percent;
}
protected:
/// @brief Holds interface name for which this network is selected.
- std::string iface_name_;
+ util::Optional<std::string> iface_name_;
/// @brief Relay information
///
/// If defined, only clients belonging to that class will be allowed to use
/// this particular network. The default value for this is an empty string,
/// which means that any client is allowed, regardless of its class.
- ClientClass client_class_;
+ util::Optional<ClientClass> client_class_;
/// @brief Required classes
///
/// @brief Specifies host reservation mode
///
/// See @ref HRMode type for details.
- HRMode host_reservation_mode_;
+ util::Optional<HRMode> host_reservation_mode_;
/// @brief Pointer to the option data configuration for this subnet.
CfgOptionPtr cfg_option_;
/// @brief Enables calculation of T1 and T2 timers
- bool calculate_tee_times_;
+ util::Optional<bool> calculate_tee_times_;
/// @brief Percentage of the lease lifetime to use when calculating T1 timer
- double t1_percent_;
+ util::Optional<double> t1_percent_;
/// @brief Percentage of the lease lifetime to use when calculating T2 timer
- double t2_percent_;
+ util::Optional<double> t2_percent_;
};
/// @brief Pointer to the @ref Network object.
/// be used to identify the client's lease.
///
/// @return true if client identifiers should be used, false otherwise.
- bool getMatchClientId() const {
+ util::Optional<bool> getMatchClientId() const {
return (match_client_id_);
}
///
/// @param match If this value is true, the client identifiers are not
/// used for lease lookup.
- void setMatchClientId(const bool match) {
+ void setMatchClientId(const util::Optional<bool>& match) {
match_client_id_ = match;
}
///
/// @return true if requests for unknown IP addresses should be rejected,
/// false otherwise.
- bool getAuthoritative() const {
+ util::Optional<bool> getAuthoritative() const {
return (authoritative_);
}
///
/// @param authoritative If this value is true, the requests for unknown IP
/// addresses will be rejected with DHCPNAK messages
- void setAuthoritative(const bool authoritative) {
+ void setAuthoritative(const util::Optional<bool>& authoritative) {
authoritative_ = authoritative;
}
/// @brief Should server use client identifiers for client lease
/// lookup.
- bool match_client_id_;
+ util::Optional<bool> match_client_id_;
/// @brief Should requests for unknown IP addresses be rejected.
- bool authoritative_;
+ util::Optional<bool> authoritative_;
};
/// @brief Specialization of the @ref Network object for DHCPv6 case.
/// is supported or unsupported for the subnet.
///
/// @return true if the Rapid Commit option is supported, false otherwise.
- bool getRapidCommit() const {
+ util::Optional<bool> getRapidCommit() const {
return (rapid_commit_);
}
///
/// @param rapid_commit A boolean value indicating that the Rapid Commit
/// option support is enabled (if true), or disabled (if false).
- void setRapidCommit(const bool rapid_commit) {
+ void setRapidCommit(const util::Optional<bool>& rapid_commit) {
rapid_commit_ = rapid_commit;
};
///
/// It's default value is false, which indicates that the Rapid
/// Commit is disabled for the subnet.
- bool rapid_commit_;
+ util::Optional<bool> rapid_commit_;
};
} // end of namespace isc::dhcp
-// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2019 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
using namespace isc::asiolink;
using namespace isc::data;
using namespace isc::dhcp;
+using namespace isc::util;
namespace {
return (Network4::clientSupported(client_classes));
}
-void Subnet4::setSiaddr(const isc::asiolink::IOAddress& siaddr) {
- if (!siaddr.isV4()) {
+void Subnet4::setSiaddr(const Optional<IOAddress>& siaddr) {
+ if (!siaddr.get().isV4()) {
isc_throw(BadValue, "Can't set siaddr to non-IPv4 address "
<< siaddr);
}
siaddr_ = siaddr;
}
-isc::asiolink::IOAddress Subnet4::getSiaddr() const {
+Optional<IOAddress> Subnet4::getSiaddr() const {
return (siaddr_);
}
-void Subnet4::setSname(const std::string& sname) {
+void Subnet4::setSname(const Optional<std::string>& sname) {
sname_ = sname;
}
-const std::string& Subnet4::getSname() const {
+const Optional<std::string>& Subnet4::getSname() const {
return (sname_);
}
-void Subnet4::setFilename(const std::string& filename) {
+void Subnet4::setFilename(const Optional<std::string>& filename) {
filename_ = filename;
}
-const std::string& Subnet4::getFilename() const {
+const Optional<std::string>& Subnet4::getFilename() const {
return (filename_);
}
isc::data::merge(map, d4o6.toElement());
// Set next-server
- map->set("next-server", Element::create(getSiaddr().toText()));
+ map->set("next-server", Element::create(getSiaddr().get().toText()));
// Set server-hostname
map->set("server-hostname", Element::create(getSname()));
-// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2019 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
#include <dhcpsrv/pool.h>
#include <dhcpsrv/subnet_id.h>
#include <dhcpsrv/triplet.h>
+#include <util/optional.h>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/indexed_by.hpp>
/// Will be used for siaddr field (the next server) that typically is used
/// as TFTP server. If not specified, the default value of 0.0.0.0 is
/// used.
- void setSiaddr(const isc::asiolink::IOAddress& siaddr);
+ void setSiaddr(const util::Optional<asiolink::IOAddress>& siaddr);
/// @brief Returns siaddr for this subnet
///
/// @return siaddr value
- isc::asiolink::IOAddress getSiaddr() const;
+ util::Optional<asiolink::IOAddress> getSiaddr() const;
/// @brief Sets server hostname for the Subnet4
///
/// Will be used for server hostname field (may be empty if not defined)
- void setSname(const std::string& sname);
+ void setSname(const util::Optional<std::string>& sname);
/// @brief Returns server hostname for this subnet
///
/// @return server hostname value
- const std::string& getSname() const;
+ const util::Optional<std::string>& getSname() const;
/// @brief Sets boot file name for the Subnet4
///
/// Will be used for boot file name (may be empty if not defined)
- void setFilename(const std::string& filename);
+ void setFilename(const util::Optional<std::string>& filename);
/// @brief Returns boot file name for this subnet
///
/// @return boot file name value
- const std::string& getFilename() const;
+ const util::Optional<std::string>& getFilename() const;
/// @brief Returns DHCP4o6 configuration parameters.
///
virtual void checkType(Lease::Type type) const;
/// @brief siaddr value for this subnet
- isc::asiolink::IOAddress siaddr_;
+ util::Optional<asiolink::IOAddress> siaddr_;
/// @brief server hostname for this subnet
- std::string sname_;
+ util::Optional<std::string> sname_;
/// @brief boot file name for this subnet
- std::string filename_;
+ util::Optional<std::string> filename_;
/// @brief All the information related to DHCP4o6
Cfg4o6 dhcp4o6_;
// Check basic parameters.
EXPECT_EQ("bird", network->getName());
- EXPECT_EQ("eth1", network->getIface());
+ EXPECT_EQ("eth1", network->getIface().get());
// Check user context.
ConstElementPtr context = network->getContext();
network = parser.parse(config_element);
ASSERT_TRUE(network);
- EXPECT_EQ("alpha", network->getClientClass());
+ EXPECT_EQ("alpha", network->getClientClass().get());
EXPECT_FALSE(network->getMatchClientId());
// Check basic parameters.
EXPECT_EQ("bird", network->getName());
- EXPECT_EQ("eth1", network->getIface());
+ EXPECT_EQ("eth1", network->getIface().get());
// Check user context.
ConstElementPtr context = network->getContext();
network = parser.parse(config_element);
ASSERT_TRUE(network);
- EXPECT_EQ("alpha", network->getClientClass());
+ EXPECT_EQ("alpha", network->getClientClass().get());
}
// This test verifies that it's possible to specify require-client-classes
-// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2019 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
SharedNetwork4Ptr network1 = cfg->getByName("bird");
ASSERT_TRUE(network1);
EXPECT_EQ("bird", network1->getName());
- EXPECT_EQ("eth0", network1->getIface());
+ EXPECT_EQ("eth0", network1->getIface().get());
EXPECT_FALSE(network1->getContext());
SharedNetwork4Ptr network2 = cfg->getByName("monkey");
ASSERT_TRUE(network2);
EXPECT_EQ("monkey", network2->getName());
- EXPECT_EQ("eth1", network2->getIface());
+ EXPECT_EQ("eth1", network2->getIface().get());
ASSERT_TRUE(network2->getContext());
EXPECT_EQ(1, network2->getContext()->size());
EXPECT_TRUE(network2->getContext()->get("comment"));
-// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2019 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
Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);
// Check if the default is 0.0.0.0
- EXPECT_EQ("0.0.0.0", subnet.getSiaddr().toText());
+ EXPECT_EQ("0.0.0.0", subnet.getSiaddr().get().toText());
// Check that we can set it up
EXPECT_NO_THROW(subnet.setSiaddr(IOAddress("1.2.3.4")));
// Check that we can get it back
- EXPECT_EQ("1.2.3.4", subnet.getSiaddr().toText());
+ EXPECT_EQ("1.2.3.4", subnet.getSiaddr().get().toText());
// Check that only v4 addresses are supported
EXPECT_THROW(subnet.setSiaddr(IOAddress("2001:db8::1")),
EXPECT_NO_THROW(subnet.setSname("foobar"));
// Check that we can get it back
- EXPECT_EQ("foobar", subnet.getSname());
+ EXPECT_EQ("foobar", subnet.getSname().get());
}
// Checks whether boot-file-name field can be set and retrieved correctly.
EXPECT_NO_THROW(subnet.setFilename("foobar"));
// Check that we can get it back
- EXPECT_EQ("foobar", subnet.getFilename());
+ EXPECT_EQ("foobar", subnet.getFilename().get());
}
// Checks if the match-client-id flag can be set and retrieved.
// Let's allow only clients belonging to "bar" class.
subnet->allowClientClass("bar");
- EXPECT_EQ("bar", subnet->getClientClass());
+ EXPECT_EQ("bar", subnet->getClientClass().get());
EXPECT_FALSE(subnet->clientSupported(no_class));
EXPECT_FALSE(subnet->clientSupported(foo_class));
// Let's allow only clients belonging to "bar" class.
subnet->allowClientClass("bar");
- EXPECT_EQ("bar", subnet->getClientClass());
+ EXPECT_EQ("bar", subnet->getClientClass().get());
EXPECT_FALSE(subnet->clientSupported(no_class));
EXPECT_FALSE(subnet->clientSupported(foo_class));
EXPECT_TRUE(subnet.getIface().empty());
subnet.setIface("en1");
- EXPECT_EQ("en1", subnet.getIface());
+ EXPECT_EQ("en1", subnet.getIface().get());
}
// This trivial test checks if the interface-id option can be set and
#ifndef OPTIONAL_H
#define OPTIONAL_H
+#include <exceptions/exceptions.h>
#include <ostream>
#include <string>
/// @brief Assigns a new value value and marks it "specified".
///
+ /// @tparam A Type of the value to be assigned. Typically this is @c T, but
+ /// may also be a type that can be cast to @c T.
/// @param other new actual value.
- Optional<T>& operator=(T other) {
+ template<typename A>
+ Optional<T>& operator=(A other) {
default_ = other;
unspecified_ = false;
return (*this);
return (default_);
}
+ /// @brief Equality operator.
+ ///
+ /// @param other value to be compared.
+ bool operator==(const T& other) const {
+ return (default_ == other);
+ }
+
+ /// @brief Inequality operator.
+ ///
+ /// @param other value to be compared.
+ bool operator!=(const T& other) const {
+ return (default_ != other);
+ }
+
/// @brief Default constructor.
///
- /// Sets the encapsulated value to 0.
+ /// Sets the encapsulated value to 0 and marks it as "unspecified".
Optional()
: default_(T(0)), unspecified_(true) {
}
/// @brief Constructor
///
- /// Creates optional value and marks it as "specified".
+ /// Sets an explicit value and marks it as "specified".
///
+ /// @tparam A Type of the value to be assigned. Typically this is @c T, but
+ /// may also be a type that can be cast to @c T.
/// @param value value to be assigned.
- explicit Optional(T value)
+ template<typename A>
+ Optional(A value)
: default_(value), unspecified_(false) {
}
- /// @brief Retrieves the actual value.
+ /// @brief Retrieves the encapsulated value.
T get() const {
return (default_);
}
return (unspecified_);
}
+ /// @brief Checks if the encapsulated value is empty.
+ ///
+ /// This method can be overloaded in the template specializations that
+ /// are dedicated to strings, vectors etc.
+ ///
+ /// @throw isc::InvalidOperation.
+ bool empty() const {
+ isc_throw(isc::InvalidOperation, "call to empty() not supported");
+ }
+
protected:
T default_; ///< Encapsulated value.
bool unspecified_; ///< Flag which indicates if the value is specified.
: default_(), unspecified_(true) {
}
+/// @brief Specialization of the @c Optional::empty method for strings.
+///
+/// @return true if the value is empty, false otherwise.
+template<>
+inline bool Optional<std::string>::empty() const {
+ return (default_.empty());
+}
+
/// @brief Inserts an optional value to a stream.
///
/// This function overloads the global operator<< to behave as in
EXPECT_TRUE(value2.unspecified());
}
+// This test checks if the constructors for a string value
+// work correctly.
TEST(OptionalTest, constructorString) {
Optional<std::string> value1("foo");
EXPECT_EQ("foo", value1.get());
+ EXPECT_FALSE(value1.unspecified());
Optional<std::string> value2;
EXPECT_TRUE(value2.get().empty());
+ EXPECT_TRUE(value2.unspecified());
}
// This test checks if the assignment operator assigning an actual
EXPECT_FALSE(value.unspecified());
}
+// This test checks if the assignment operator assigning an actual
+// string value to the optional value works as expected.
+TEST(OptionalTest, assignStringValue) {
+ Optional<std::string> value("foo");
+ EXPECT_EQ("foo", value.get());
+ EXPECT_FALSE(value.unspecified());
+
+ value = "bar";
+ EXPECT_EQ("bar", value.get());
+ EXPECT_FALSE(value.unspecified());
+
+ value = "foobar";
+ EXPECT_EQ("foobar", value.get());
+ EXPECT_FALSE(value.unspecified());
+}
+
// This test checks that it is possible to modify the flag that indicates
// if the value is specified or unspecified.
TEST(OptionalTest, modifyUnspecified) {
// This test checks if the type case operator returns correct value.
TEST(OptionalTest, typeCastOperator) {
Optional<int> value(-10);
- ASSERT_EQ(-10, value.get());
- ASSERT_FALSE(value.unspecified());
+ EXPECT_EQ(-10, value.get());
+ EXPECT_FALSE(value.unspecified());
int actual = value;
EXPECT_EQ(-10, actual);
}
+// This test checks if the type case operator returns correct string
+// value.
+TEST(OptionalTest, stringCastOperator) {
+ Optional<std::string> value("xyz");
+ EXPECT_EQ("xyz", value.get());
+ EXPECT_FALSE(value.unspecified());
+
+ std::string actual = value;
+ EXPECT_EQ("xyz", actual);
+}
+
+// This test checks that the equality operators work as expected.
+TEST(OptionalTest, equality) {
+ int exp_value = 1234;
+ Optional<int> value(1234);
+ EXPECT_TRUE(value == exp_value);
+ EXPECT_FALSE(value != exp_value);
+}
+
+// This test checks that the equality operators for strings work as
+// expected.
+TEST(OptionalTest, stringEquality) {
+ const char* exp_value = "foo";
+ Optional<std::string> value("foo");
+ EXPECT_TRUE(value == exp_value);
+ EXPECT_FALSE(value != exp_value);
+}
+
+// This test checks that an exception is thrown when calling an empty()
+// method on non-string optional value.
+TEST(OptionalTest, empty) {
+ Optional<int> value(10);
+ EXPECT_THROW(value.empty(), isc::InvalidOperation);
+}
+
+// This test checks that no exception is thrown when calling an empty()
+// method on string optional value and that it returns an expected
+// boolean value.
+TEST(OptionalTest, stringEmpty) {
+ Optional<std::string> value("foo");
+ bool is_empty = true;
+ ASSERT_NO_THROW(is_empty = value.empty());
+ EXPECT_FALSE(is_empty);
+
+ value = "";
+ ASSERT_NO_THROW(is_empty = value.empty());
+ EXPECT_TRUE(is_empty);
+}
+
} // end of anonymous namespace