From: Thomas Markwalder Date: Tue, 17 Nov 2015 14:07:54 +0000 (-0500) Subject: [4096] Added copy constructors and equality tools to client class storage X-Git-Tag: trac4097a_base~1^2~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=87ed3316ecdcd0c152adeb4c83da818362715285;p=thirdparty%2Fkea.git [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 --- diff --git a/src/lib/dhcpsrv/client_class_def.cc b/src/lib/dhcpsrv/client_class_def.cc index 67a2f34620..45fcccaf33 100644 --- a/src/lib/dhcpsrv/client_class_def.cc +++ b/src/lib/dhcpsrv/client_class_def.cc @@ -13,6 +13,7 @@ // PERFORMANCE OF THIS SOFTWARE. #include "client_class_def.h" +#include 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 diff --git a/src/lib/dhcpsrv/client_class_def.h b/src/lib/dhcpsrv/client_class_def.h index 01d56222ea..626a3acffd 100644 --- a/src/lib/dhcpsrv/client_class_def.h +++ b/src/lib/dhcpsrv/client_class_def.h @@ -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 ClientClassDefMap; /// @brief Defines a pointer to a ClientClassDictionary typedef boost::shared_ptr ClientClassDefMapPtr; +/// @brief Defines a pair for working wiht ClientClassMap +typedef std::pair 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 diff --git a/src/lib/dhcpsrv/tests/client_class_def_unittest.cc b/src/lib/dhcpsrv/tests/client_class_def_unittest.cc index 7770b3bb44..8fef39c181 100644 --- a/src/lib/dhcpsrv/tests/client_class_def_unittest.cc +++ b/src/lib/dhcpsrv/tests/client_class_def_unittest.cc @@ -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 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 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