Commit 87ed3316 authored by Thomas Markwalder's avatar Thomas Markwalder
Browse files

[4096] Added copy constructors and equality tools to client class storage

In anticipation adding client class storage to SrvConfig:

src/lib/dhcpsrv/client_class_def.h
src/lib/dhcpsrv/client_class_def.cc
    added copy contructor, equals() method, ==, != operators
    To ClientClassDef and ClientClassDictionary

src/lib/dhcpsrv/tests/client_class_def_unittest.cc
    Added copyAndEquality tests for ClientClassDef and
    ClientClassDictionary
parent dd80413a
......@@ -13,6 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE.
#include "client_class_def.h"
#include <boost/foreach.hpp>
namespace isc {
namespace dhcp {
......@@ -36,6 +37,20 @@ ClientClassDef::ClientClassDef(const std::string& name,
}
}
ClientClassDef::ClientClassDef(const ClientClassDef& rhs)
: name_(rhs.name_), match_expr_(ExpressionPtr()),
cfg_option_(new CfgOption()) {
if (rhs.match_expr_) {
match_expr_.reset(new Expression());
*match_expr_ = *(rhs.match_expr_);
}
if (rhs.cfg_option_) {
rhs.cfg_option_->copyTo(*cfg_option_);
}
}
ClientClassDef::~ClientClassDef() {
}
......@@ -69,6 +84,17 @@ ClientClassDef::setCfgOption(const CfgOptionPtr& cfg_option) {
cfg_option_ = cfg_option;
}
bool
ClientClassDef::equals(const ClientClassDef& other) const {
return ((name_ == other.name_) &&
((!match_expr_ && !other.match_expr_) ||
(match_expr_ && other.match_expr_ &&
(*match_expr_ == *(other.match_expr_)))) &&
((!cfg_option_ && !other.cfg_option_) ||
(cfg_option_ && other.cfg_option_ &&
(*cfg_option_ == *other.cfg_option_))));
}
std::ostream& operator<<(std::ostream& os, const ClientClassDef& x) {
os << "ClientClassDef:" << x.getName();
return (os);
......@@ -80,6 +106,14 @@ ClientClassDictionary::ClientClassDictionary()
: classes_(new ClientClassDefMap()) {
}
ClientClassDictionary::ClientClassDictionary(const ClientClassDictionary& rhs)
: classes_(new ClientClassDefMap()) {
BOOST_FOREACH(ClientClassMapPair cclass, *(rhs.classes_)) {
ClientClassDefPtr copy(new ClientClassDef(*(cclass.second)));
addClass(copy);
}
}
ClientClassDictionary::~ClientClassDictionary() {
}
......@@ -126,5 +160,28 @@ ClientClassDictionary::getClasses() const {
return (classes_);
}
bool
ClientClassDictionary::equals(const ClientClassDictionary& other) const {
if (classes_->size() != other.classes_->size()) {
return (false);
}
ClientClassDefMap::iterator this_class = classes_->begin();
ClientClassDefMap::iterator other_class = other.classes_->begin();
while (this_class != classes_->end() &&
other_class != other.classes_->end()) {
if (!(*this_class).second || !(*other_class).second ||
(*(*this_class).second) != (*(*other_class).second)) {
return false;
}
++this_class;
++other_class;
}
return (true);
}
} // namespace isc::dhcp
} // namespace isc
......@@ -55,6 +55,10 @@ class ClientClassDef {
ClientClassDef(const std::string& name, const ExpressionPtr& match_expr,
const CfgOptionPtr& options = CfgOptionPtr());
/// Copy constructor
ClientClassDef(const ClientClassDef& rhs);
/// @brief Destructor
virtual ~ClientClassDef();
......@@ -82,6 +86,31 @@ class ClientClassDef {
/// @param options the option collection to assign the class
void setCfgOption(const CfgOptionPtr& cfg_option);
/// @brief Compares two @c ClientClassDef objects for equality.
///
/// @param other Other client class definition to compare to.
///
/// @return true if objects are equal, false otherwise.
bool equals(const ClientClassDef& other) const;
/// @brief Equality operator.
///
/// @param other Other client class definition to compare to.
///
/// @return true if the definitions equal, false otherwise.
bool operator==(const ClientClassDef& other) const {
return (equals(other));
}
/// @brief Inequality operator.
///
/// @param other Other client class definition to compare to.
///
/// @return true if the definitions are not equal, false otherwise.
bool operator!=(const ClientClassDef& other) const {
return (!(equals(other)));
}
/// @brief Provides a convenient text representation of the class
friend std::ostream& operator<<(std::ostream& os, const ClientClassDef& x);
......@@ -106,6 +135,9 @@ typedef std::map<std::string,ClientClassDefPtr> ClientClassDefMap;
/// @brief Defines a pointer to a ClientClassDictionary
typedef boost::shared_ptr<ClientClassDefMap> ClientClassDefMapPtr;
/// @brief Defines a pair for working wiht ClientClassMap
typedef std::pair<std::string,ClientClassDefPtr> ClientClassMapPair;
/// @brief Maintains a list of ClientClassDef's
class ClientClassDictionary {
......@@ -113,6 +145,8 @@ class ClientClassDictionary {
/// @brief Constructor
ClientClassDictionary();
ClientClassDictionary(const ClientClassDictionary& rhs);
/// @brief Destructor
~ClientClassDictionary();
......@@ -157,6 +191,31 @@ class ClientClassDictionary {
/// @return ClientClassDefMapPtr to the map of classes
const ClientClassDefMapPtr& getClasses() const;
/// @brief Compares two @c ClientClassDictionary objects for equality.
///
/// @param other Other client class definition to compare to.
///
/// @return true if descriptors equal, false otherwise.
bool equals(const ClientClassDictionary& other) const;
/// @brief Equality operator.
///
/// @param other Other client class dictionary to compare to.
///
/// @return true if the dictionaries are equal, false otherwise.
bool operator==(const ClientClassDictionary& other) const {
return (equals(other));
}
/// @brief Inequality operator.
///
/// @param other Other client class dictionary to compare to.
///
/// @return true if the dictionaries are not equal, false otherwise.
bool operator!=(const ClientClassDictionary& other) const {
return (!equals(other));
}
private:
/// @brief Map of the class definitions
......
......@@ -102,6 +102,95 @@ TEST(ClientClassDef, cfgOptionBasics) {
EXPECT_EQ(100, opt_desc.option_->getType());
}
// Verifies copy constructor and equality tools (methods/operators)
TEST(ClientClassDef, copyAndEquality) {
boost::scoped_ptr<ClientClassDef> cclass;
ExpressionPtr expr;
CfgOptionPtr test_options;
OptionPtr opt;
// Make an expression
expr.reset(new Expression());
TokenPtr token(new TokenString("boo"));
expr->push_back(token);
// Create an option container with an option
OptionPtr option;
test_options.reset(new CfgOption());
option.reset(new Option(Option::V4, 17, OptionBuffer(10, 0xFF)));
ASSERT_NO_THROW(test_options->add(option, false, "dhcp4"));
// Now remake the client class with cfg_option
ASSERT_NO_THROW(cclass.reset(new ClientClassDef("class_one", expr,
test_options)));
// Now lets make a copy of it.
boost::scoped_ptr<ClientClassDef> cclass2;
ASSERT_NO_THROW(cclass2.reset(new ClientClassDef(*cclass)));
// The allocated Expression pointers should not match
EXPECT_TRUE(cclass->getMatchExpr().get() !=
cclass2->getMatchExpr().get());
// The allocated CfgOption pointers should not match
EXPECT_TRUE(cclass->getCfgOption().get() !=
cclass2->getCfgOption().get());
// Verify the equality tools reflect that the classes are equal.
EXPECT_TRUE(cclass->equals(*cclass2));
EXPECT_TRUE(*cclass == *cclass2);
EXPECT_FALSE(*cclass != *cclass2);
// Make a class that differs from the first class only by name and
// verify that the equality tools reflect that the classes are not equal.
ASSERT_NO_THROW(cclass2.reset(new ClientClassDef("class_two", expr,
test_options)));
EXPECT_FALSE(cclass->equals(*cclass2));
EXPECT_FALSE(*cclass == *cclass2);
EXPECT_TRUE(*cclass != *cclass2);
// Make a class with the same name and options, but no expression
// verify that the equality tools reflect that the classes are not equal.
expr.reset();
ASSERT_NO_THROW(cclass2.reset(new ClientClassDef("class_one", expr,
test_options)));
EXPECT_FALSE(cclass->equals(*cclass2));
EXPECT_FALSE(*cclass == *cclass2);
EXPECT_TRUE(*cclass != *cclass2);
// Make a class with the same name and options, but different expression,
// verify that the equality tools reflect that the classes are not equal.
expr.reset(new Expression());
token.reset(new TokenString("yah"));
expr->push_back(token);
ASSERT_NO_THROW(cclass2.reset(new ClientClassDef("class_one", expr,
test_options)));
EXPECT_FALSE(cclass->equals(*cclass2));
EXPECT_FALSE(*cclass == *cclass2);
EXPECT_TRUE(*cclass != *cclass2);
// Make a class with same name and expression, but no options
// verify that the equality tools reflect that the classes are not equal.
test_options.reset(new CfgOption());
ASSERT_NO_THROW(cclass2.reset(new ClientClassDef("class_one", expr,
test_options)));
EXPECT_FALSE(cclass->equals(*cclass2));
EXPECT_FALSE(*cclass == *cclass2);
EXPECT_TRUE(*cclass != *cclass2);
// Make a class that with same name and expression, but different options
// verify that the equality tools reflect that the classes are not equal.
option.reset(new Option(Option::V4, 20, OptionBuffer(10, 0xFF)));
ASSERT_NO_THROW(test_options->add(option, false, "dhcp4"));
ASSERT_NO_THROW(cclass2.reset(new ClientClassDef("class_one", expr,
test_options)));
EXPECT_FALSE(cclass->equals(*cclass2));
EXPECT_FALSE(*cclass == *cclass2);
EXPECT_TRUE(*cclass != *cclass2);
}
// Tests the basic operation of ClientClassDictionary
// This includes adding, finding, and removing classes
TEST(ClientClassDictionary, basics) {
......@@ -176,4 +265,45 @@ TEST(ClientClassDictionary, basics) {
EXPECT_EQ(2, classes->size());
}
// Verifies copy constructor and equality tools (methods/operators)
TEST(ClientClassDictionary, copyAndEquality) {
ClientClassDictionaryPtr dictionary;
ClientClassDictionaryPtr dictionary2;
ClientClassDefPtr cclass;
ExpressionPtr expr;
CfgOptionPtr options;
dictionary.reset(new ClientClassDictionary());
ASSERT_NO_THROW(dictionary->addClass("one", expr, options));
ASSERT_NO_THROW(dictionary->addClass("two", expr, options));
ASSERT_NO_THROW(dictionary->addClass("three", expr, options));
// Copy constructor should succeed.
ASSERT_NO_THROW(dictionary2.reset(new ClientClassDictionary(*dictionary)));
// Allocated class map pointers should not be equal
EXPECT_NE(dictionary->getClasses().get(), dictionary2->getClasses().get());
// Equality tools should reflect that the dictionaries are equal.
EXPECT_TRUE(dictionary->equals(*dictionary2));
EXPECT_TRUE(*dictionary == *dictionary2);
EXPECT_FALSE(*dictionary != *dictionary2);
// Remove a class from dictionary2.
ASSERT_NO_THROW(dictionary2->removeClass("two"));
// Equality tools should reflect that the dictionaries are not equal.
EXPECT_FALSE(dictionary->equals(*dictionary2));
EXPECT_FALSE(*dictionary == *dictionary2);
EXPECT_TRUE(*dictionary != *dictionary2);
// Create an empty dictionary.
dictionary2.reset(new ClientClassDictionary());
// Equality tools should reflect that the dictionaries are not equal.
EXPECT_FALSE(dictionary->equals(*dictionary2));
EXPECT_FALSE(*dictionary == *dictionary2);
EXPECT_TRUE(*dictionary != *dictionary2);
}
} // end of anonymous namespace
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment