Parcourir la source

[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
Thomas Markwalder il y a 9 ans
Parent
commit
87ed3316ec

+ 57 - 0
src/lib/dhcpsrv/client_class_def.cc

@@ -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

+ 59 - 0
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<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

+ 130 - 0
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<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