// PERFORMANCE OF THIS SOFTWARE.
#include "client_class_def.h"
+#include <boost/foreach.hpp>
namespace isc {
namespace dhcp {
}
}
+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() {
}
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);
: 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() {
}
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
ClientClassDef(const std::string& name, const ExpressionPtr& match_expr,
const CfgOptionPtr& options = CfgOptionPtr());
+
+ /// Copy constructor
+ ClientClassDef(const ClientClassDef& rhs);
+
/// @brief Destructor
virtual ~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);
/// @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 {
/// @brief Constructor
ClientClassDictionary();
+ ClientClassDictionary(const ClientClassDictionary& rhs);
+
/// @brief Destructor
~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
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) {
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