From 611fed36be6c82ced08b49b8c9d7757b9899a91c Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 20 Jul 2021 20:19:45 +0200 Subject: [PATCH] [#1928] Copy assignment for class dictionary --- src/lib/dhcpsrv/client_class_def.cc | 13 +++++++ src/lib/dhcpsrv/client_class_def.h | 6 +++ .../tests/client_class_def_unittest.cc | 39 +++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/src/lib/dhcpsrv/client_class_def.cc b/src/lib/dhcpsrv/client_class_def.cc index 51ed095ba5..9b5a500e54 100644 --- a/src/lib/dhcpsrv/client_class_def.cc +++ b/src/lib/dhcpsrv/client_class_def.cc @@ -361,6 +361,19 @@ ClientClassDictionary::toElement() const { return (result); } +ClientClassDictionary& +ClientClassDictionary::operator=(const ClientClassDictionary& rhs) { + if (this != &rhs) { + list_->clear(); + map_->clear(); + for (auto cclass : *(rhs.list_)) { + ClientClassDefPtr copy(new ClientClassDef(*cclass)); + addClass(copy); + } + } + return (*this); +} + std::list builtinNames = { // DROP is not in this list because it is special but not built-in. diff --git a/src/lib/dhcpsrv/client_class_def.h b/src/lib/dhcpsrv/client_class_def.h index 293e84ee8e..aab8ddc186 100644 --- a/src/lib/dhcpsrv/client_class_def.h +++ b/src/lib/dhcpsrv/client_class_def.h @@ -391,6 +391,12 @@ public: return (!equals(other)); } + /// @brief Copy assignment operator. + /// + /// @param rhs Client class dictionary to be copied from. + /// @return Instance copy. + ClientClassDictionary& operator=(const ClientClassDictionary& rhs); + /// @brief Unparse a configuration object /// /// @return a pointer to unparsed configuration diff --git a/src/lib/dhcpsrv/tests/client_class_def_unittest.cc b/src/lib/dhcpsrv/tests/client_class_def_unittest.cc index 68f1328d30..d33f01b881 100644 --- a/src/lib/dhcpsrv/tests/client_class_def_unittest.cc +++ b/src/lib/dhcpsrv/tests/client_class_def_unittest.cc @@ -431,6 +431,45 @@ TEST(ClientClassDictionary, copyAndEquality) { EXPECT_TRUE(*dictionary != *dictionary2); } +// Verify that client class dictionaries are deep-copied. +TEST(ClientClassDictionary, copy) { + ClientClassDictionary dictionary; + ExpressionPtr expr; + CfgOptionPtr options; + + // Get a client class dictionary and fill it. + ASSERT_NO_THROW(dictionary.addClass("one", expr, "", false, + false, options)); + ASSERT_NO_THROW(dictionary.addClass("two", expr, "", false, + false, options)); + ASSERT_NO_THROW(dictionary.addClass("three", expr, "", false, + false, options)); + + // Make a copy with a copy constructor. Expect it to be a deep copy. + ClientClassDictionary dictionary_copy(dictionary); + ASSERT_NO_THROW(dictionary.removeClass("one")); + ASSERT_NO_THROW(dictionary.removeClass("two")); + ASSERT_NO_THROW(dictionary.removeClass("three")); + EXPECT_TRUE(dictionary.empty()); + EXPECT_FALSE(dictionary_copy.empty()); + + // Refill the client class dictionary. + ASSERT_NO_THROW(dictionary.addClass("one", expr, "", false, + false, options)); + ASSERT_NO_THROW(dictionary.addClass("two", expr, "", false, + false, options)); + ASSERT_NO_THROW(dictionary.addClass("three", expr, "", false, + false, options)); + + // Make a copy with operator=. Expect it to be a deep copy. + dictionary_copy = dictionary; + ASSERT_NO_THROW(dictionary.removeClass("one")); + ASSERT_NO_THROW(dictionary.removeClass("two")); + ASSERT_NO_THROW(dictionary.removeClass("three")); + EXPECT_TRUE(dictionary.empty()); + EXPECT_FALSE(dictionary_copy.empty()); +} + // Tests dependency. TEST(ClientClassDictionary, dependency) { ClientClassDictionaryPtr dictionary(new ClientClassDictionary());