From c8a8dba4706d8bd00b8e4fc2109db93051b14c04 Mon Sep 17 00:00:00 2001 From: fpagliughi Date: Mon, 26 Oct 2020 20:15:36 -0400 Subject: [PATCH] Finished implementation of name_value_collection --- src/mqtt/string_collection.h | 45 ++++++++- src/string_collection.cpp | 3 +- test/unit/test_string_collection.cpp | 132 ++++++++++++++++++++++++--- 3 files changed, 164 insertions(+), 16 deletions(-) diff --git a/src/mqtt/string_collection.h b/src/mqtt/string_collection.h index 172844e..ddd051a 100644 --- a/src/mqtt/string_collection.h +++ b/src/mqtt/string_collection.h @@ -266,6 +266,7 @@ public: /** Smart/shared pointer to a const object of this type */ using const_ptr_t = std::shared_ptr; + using value_type = collection_type::value_type; /** * Default construtor for an empty collection. */ @@ -298,6 +299,49 @@ public: */ name_value_collection(name_value_collection&& other) = default; /** + * Constructs the collection with an initializer list. + * + * This works identically to initializing a std::map<> with string/tring + * pairs. + * + * @param init Initializer list to construct the members of the + * collection. + */ + name_value_collection(std::initializer_list init) + : map_{ init } { + update_c_arr(); + } + /** + * Determines if the collection is empty. + * @return @em true if the container is empty, @em false if it contains + * one or more items. + */ + bool empty() const { return map_.empty(); } + /** + * Gets the number of name/value pairs in the collection. + * @return The number of name/value pairs in the collection. + */ + size_t size() const { return map_.size(); } + /** + * Removes all items from the collection. + */ + void clear() { + map_.clear(); + update_c_arr(); + } + /** + * Inserts a name/value pair into the collection. + * @param nvpair The name/value string pair. + * @return @em true if the inert happened, @em false if not. + */ + bool insert(const value_type& nvpair) { + if (map_.insert(nvpair).second) { + update_c_arr(); + return true; + } + return false; + } + /** * Gets a pointer to an array of NUL-terminated C string pointer pairs. * This is a collection type supported by the underlying Paho C * library. The returned pointer is guaranteed valid so long as the @@ -306,7 +350,6 @@ public: * rather request the value when needed. * @return pointer to an array of NUL-terminated C string pointer pairs * for name/values. The array is terminated by a NULL/NULL pair. - * */ char* const* c_arr() const { return (char* const *) cArr_.data(); } }; diff --git a/src/string_collection.cpp b/src/string_collection.cpp index 39b2695..788517a 100644 --- a/src/string_collection.cpp +++ b/src/string_collection.cpp @@ -99,12 +99,13 @@ void string_collection::clear() void name_value_collection::update_c_arr() { cArr_.clear(); - cArr_.reserve(map_.size()); + cArr_.reserve(map_.size()+1); for (const auto& m : map_) { cArr_.push_back( MQTTAsync_nameValue{ m.first.c_str(), m.second.c_str() } ); } + cArr_.push_back(MQTTAsync_nameValue{ nullptr, nullptr }); } ///////////////////////////////////////////////////////////////////////////// diff --git a/test/unit/test_string_collection.cpp b/test/unit/test_string_collection.cpp index e73a83d..ad3b49d 100644 --- a/test/unit/test_string_collection.cpp +++ b/test/unit/test_string_collection.cpp @@ -32,11 +32,18 @@ using namespace mqtt; static const string STR { "Some random string" }; static const std::vector VEC { "test0", "test1", "test2" }; +static const std::map NV_PAIRS { + { "name0", "value0" }, + { "name1", "value1" }, + { "name2", "value2" } +}; + + // ---------------------------------------------------------------------- // Test the default constructor // ---------------------------------------------------------------------- -TEST_CASE("test_dflt_ctor", "[collections]") +TEST_CASE("string_collection default ctor", "[collections]") { string_collection sc; @@ -48,7 +55,7 @@ TEST_CASE("test_dflt_ctor", "[collections]") // Test the string copy constructor // ---------------------------------------------------------------------- -TEST_CASE("test_str_copy_ctor", "[collections]") +TEST_CASE("string_collection str copy ctor", "[collections]") { string_collection sc(STR); @@ -64,7 +71,7 @@ TEST_CASE("test_str_copy_ctor", "[collections]") // Test the string move constructor // ---------------------------------------------------------------------- -TEST_CASE("test_str_move_ctor", "[collections]") +TEST_CASE("string_collection str move ctor", "[collections]") { string str(STR); string_collection sc(std::move(str)); @@ -81,7 +88,7 @@ TEST_CASE("test_str_move_ctor", "[collections]") // Test the vector copy constructor // ---------------------------------------------------------------------- -TEST_CASE("test_vec_copy_ctor", "[collections]") +TEST_CASE("string_collection vec copy ctor", "[collections]") { string_collection sc(VEC); @@ -102,7 +109,7 @@ TEST_CASE("test_vec_copy_ctor", "[collections]") // Test the vector move constructor // ---------------------------------------------------------------------- -TEST_CASE("test_vec_move_ctor", "[collections]") +TEST_CASE("string_collection vec move ctor", "[collections]") { std::vector vec{ VEC }; @@ -125,7 +132,7 @@ TEST_CASE("test_vec_move_ctor", "[collections]") // Test the ini vector constructor // ---------------------------------------------------------------------- -TEST_CASE("test_ini_str_ctor", "[collections]") +TEST_CASE("string_collection ini str ctor", "[collections]") { string_collection sc( { VEC[0], VEC[1], VEC[2] } ); @@ -146,7 +153,7 @@ TEST_CASE("test_ini_str_ctor", "[collections]") // Test the ini vector constructor // ---------------------------------------------------------------------- -TEST_CASE("test_ini_cstr_ctor", "[collections]") +TEST_CASE("string_collection ini cstr ctor", "[collections]") { string_collection sc( { "test0", "test1", "test2" } ); @@ -167,7 +174,7 @@ TEST_CASE("test_ini_cstr_ctor", "[collections]") // Test the copy constructor // ---------------------------------------------------------------------- -TEST_CASE("test_copy_ctor", "[collections]") +TEST_CASE("string_collection copy ctor", "[collections]") { string_collection orgSC(VEC); string_collection sc(orgSC);; @@ -189,7 +196,7 @@ TEST_CASE("test_copy_ctor", "[collections]") // Test the move constructor // ---------------------------------------------------------------------- -TEST_CASE("test_move_ctor", "[collections]") +TEST_CASE("string_collection move ctor", "[collections]") { string_collection orgSC(VEC); string_collection sc(std::move(orgSC)); @@ -211,7 +218,7 @@ TEST_CASE("test_move_ctor", "[collections]") // Test the copy assignment // ---------------------------------------------------------------------- -TEST_CASE("test_copy_assignment", "[collections]") +TEST_CASE("string_collection copy assignment", "[collections]") { string_collection orgSC(VEC); string_collection sc; @@ -235,7 +242,7 @@ TEST_CASE("test_copy_assignment", "[collections]") // Test the move assignment // ---------------------------------------------------------------------- -TEST_CASE("test_move_assignment", "[collections]") +TEST_CASE("string_collection move assignment", "[collections]") { string_collection orgSC(VEC); string_collection sc; @@ -259,7 +266,7 @@ TEST_CASE("test_move_assignment", "[collections]") // Test the push back of strings // ---------------------------------------------------------------------- -TEST_CASE("test_push_str", "[collections]") +TEST_CASE("string_collection push str", "[collections]") { string_collection sc; @@ -283,7 +290,7 @@ TEST_CASE("test_push_str", "[collections]") // Test the push back of C strings // ---------------------------------------------------------------------- -TEST_CASE("test_push_cstr", "[collections]") +TEST_CASE("string_collection push cstr", "[collections]") { string_collection sc; @@ -307,7 +314,7 @@ TEST_CASE("test_push_cstr", "[collections]") // Test the clear method // ---------------------------------------------------------------------- -TEST_CASE("test_clear", "[collections]") +TEST_CASE("string_collection clear", "[collections]") { string_collection sc(VEC); @@ -319,3 +326,100 @@ TEST_CASE("test_clear", "[collections]") REQUIRE(size_t(0) == sc.size()); } +///////////////////////////////////////////////////////////////////////////// +// name_value_collection +///////////////////////////////////////////////////////////////////////////// + +TEST_CASE("name_value_collection default ctor", "[collections]") +{ + name_value_collection nvc; + REQUIRE(nvc.empty()); + REQUIRE(0 == nvc.size()); +} + +TEST_CASE("name_value_collection initializer ctor", "[collections]") +{ + name_value_collection nvc { + { "name0", "value0" }, + { "name1", "value1" }, + { "name2", "value2" } + }; + + REQUIRE_FALSE(nvc.empty()); + REQUIRE(3 == nvc.size()); + + auto cArr = nvc.c_arr(); + + REQUIRE(0 == strcmp("name0", cArr[0])); + REQUIRE(0 == strcmp("value0", cArr[1])); + REQUIRE(0 == strcmp("name1", cArr[2])); + REQUIRE(0 == strcmp("value1", cArr[3])); + REQUIRE(0 == strcmp("name2", cArr[4])); + REQUIRE(0 == strcmp("value2", cArr[5])); + + REQUIRE(nullptr == cArr[6]); + REQUIRE(nullptr == cArr[7]); +} + +TEST_CASE("name_value_collection coll ctor", "[collections]") +{ + name_value_collection nvc { NV_PAIRS }; + + std::map nvPairs { NV_PAIRS }; + const size_t SZ = nvPairs.size(); + + REQUIRE_FALSE(nvc.empty()); + REQUIRE(SZ == nvc.size()); + + auto cArr = nvc.c_arr(); + + for (size_t i=0; ifirst == key); + REQUIRE(it->second == val); + nvPairs.erase(it); + } + + REQUIRE(nvPairs.empty()); +} + +TEST_CASE("name_value_collection insert", "[collections]") +{ + name_value_collection nvc; + + std::map nvPairs { NV_PAIRS }; + for (const auto& nv : nvPairs) { + nvc.insert(nv); + } + + const size_t SZ = nvPairs.size(); + + REQUIRE_FALSE(nvc.empty()); + REQUIRE(SZ == nvc.size()); + + auto cArr = nvc.c_arr(); + + for (size_t i=0; ifirst == key); + REQUIRE(it->second == val); + nvPairs.erase(it); + } + + REQUIRE(nvPairs.empty()); +} +