This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/type_support_for_properties
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 4f86a3d3ac585446710fa1662c2b8665381a0063
Author: Pepijn Noltes <[email protected]>
AuthorDate: Sun Jan 8 22:12:33 2023 +0100

    Improve codecov and replace usage of CELIX_PROPERTIES_FOR_EACH with _ITERATE
---
 .../subscriber/private/src/pubsub_subscriber.c     |   6 +-
 .../gtest/PubSubInterceptorTestSuite.cc            |   5 +-
 .../pubsub_admin_udp_mc/src/pubsub_udpmc_admin.c   |   5 +-
 .../src/pubsub_websocket_admin.c                   |  10 +-
 .../pubsub_discovery/src/pubsub_discovery_impl.c   |   6 +-
 .../src/pubsub_wire_protocol_common.c              |   9 +-
 bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c    |   5 +-
 .../src/endpoint_descriptor_writer.c               |  11 +-
 .../src/remote_service_admin_dfi.c                 |  15 +--
 bundles/shell/shell/src/query_command.c            |  12 +--
 .../include/celix/dm/DependencyManager_Impl.h      |   7 +-
 libs/framework/src/celix_launcher.c                |  30 +++---
 libs/framework/src/service_reference.c             |   5 +-
 libs/utils/gtest/src/CxxPropertiesTestSuite.cc     |   7 +-
 libs/utils/gtest/src/CxxVersionTestSuite.cc        |   2 +
 libs/utils/gtest/src/PropertiesTestSuite.cc        | 112 +++++++++++++++++----
 libs/utils/include/celix/Version.h                 |   3 +-
 libs/utils/include/celix_properties.h              |  10 --
 libs/utils/src/properties.c                        |  36 ++++---
 19 files changed, 165 insertions(+), 131 deletions(-)

diff --git 
a/bundles/pubsub/examples/pubsub/subscriber/private/src/pubsub_subscriber.c 
b/bundles/pubsub/examples/pubsub/subscriber/private/src/pubsub_subscriber.c
index 272ff746..c05df1ee 100644
--- a/bundles/pubsub/examples/pubsub/subscriber/private/src/pubsub_subscriber.c
+++ b/bundles/pubsub/examples/pubsub/subscriber/private/src/pubsub_subscriber.c
@@ -62,10 +62,8 @@ int pubsub_subscriber_recv(void* handle, const char* 
msgType, unsigned int msgTy
     if (metadata == NULL || celix_properties_size(metadata) == 0) {
         printf("No metadata\n");
     } else {
-        const char *key;
-        CELIX_PROPERTIES_FOR_EACH(metadata, key) {
-            const char *val = celix_properties_get(metadata, key, "!Error!");
-            printf("%s=%s\n", key, val);
+        CELIX_PROPERTIES_ITERATE(metadata, iter) {
+            printf("%s=%s\n", iter.key, iter.entry.value);
         }
     }
 
diff --git a/bundles/pubsub/integration/gtest/PubSubInterceptorTestSuite.cc 
b/bundles/pubsub/integration/gtest/PubSubInterceptorTestSuite.cc
index e8218ccf..0c4c7c0b 100644
--- a/bundles/pubsub/integration/gtest/PubSubInterceptorTestSuite.cc
+++ b/bundles/pubsub/integration/gtest/PubSubInterceptorTestSuite.cc
@@ -110,9 +110,8 @@ public:
             const auto *msg = static_cast<const msg_t*>(rawMsg);
             EXPECT_GE(msg->seqNr, 0);
             EXPECT_STREQ(celix_properties_get(metadata, "test", nullptr), 
"preSend");
-            const char *key;
-            CELIX_PROPERTIES_FOR_EACH(metadata, key) {
-                printf("got property %s=%s\n", key, 
celix_properties_get(metadata, key, nullptr));
+            CELIX_PROPERTIES_ITERATE(metadata, iter) {
+                printf("got property %s=%s\n", iter.key, iter.entry.value);
             }
             fprintf(stdout, "Got message in postSend interceptor %s/%s for 
type %s and ser %s with seq nr %i\n", intProps->scope, intProps->topic, 
intProps->psaType, intProps->serializationType, msg->seqNr);
 
diff --git a/bundles/pubsub/pubsub_admin_udp_mc/src/pubsub_udpmc_admin.c 
b/bundles/pubsub/pubsub_admin_udp_mc/src/pubsub_udpmc_admin.c
index 9257ac87..91ec6b1b 100644
--- a/bundles/pubsub/pubsub_admin_udp_mc/src/pubsub_udpmc_admin.c
+++ b/bundles/pubsub/pubsub_admin_udp_mc/src/pubsub_udpmc_admin.c
@@ -455,9 +455,8 @@ static celix_status_t 
pubsub_udpmcAdmin_connectEndpointToReceiver(pubsub_udpmc_a
 
     if (sockAddress == NULL || sockPort < 0) {
         L_WARN("[PSA UPDMC] Error got endpoint without udpmc socket 
address/port or endpoint type. Properties:");
-        const char *key = NULL;
-        CELIX_PROPERTIES_FOR_EACH(endpoint, key) {
-            L_WARN("[PSA UPDMC] |- %s=%s\n", key, 
celix_properties_get(endpoint, key, NULL));
+        CELIX_PROPERTIES_ITERATE(endpoint, iter) {
+            L_WARN("[PSA UPDMC] |- %s=%s\n", iter.key, iter.entry.value);
         }
         status = CELIX_BUNDLE_EXCEPTION;
     } else {
diff --git a/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_admin.c 
b/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_admin.c
index 2a103eec..765e416d 100644
--- a/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_admin.c
+++ b/bundles/pubsub/pubsub_admin_websocket/src/pubsub_websocket_admin.c
@@ -379,9 +379,8 @@ static celix_status_t 
pubsub_websocketAdmin_connectEndpointToReceiver(pubsub_web
 
     if (publisher && (sockAddress == NULL || sockPort < 0)) {
         L_WARN("[PSA WEBSOCKET] Error got endpoint without websocket 
address/port or endpoint type. Properties:");
-        const char *key = NULL;
-        CELIX_PROPERTIES_FOR_EACH(endpoint, key) {
-            L_WARN("[PSA WEBSOCKET] |- %s=%s\n", key, 
celix_properties_get(endpoint, key, NULL));
+        CELIX_PROPERTIES_ITERATE(endpoint, iter) {
+            L_WARN("[PSA WEBSOCKET] |- %s=%s\n", iter.key, iter.entry.value);
         }
         status = CELIX_BUNDLE_EXCEPTION;
     } else {
@@ -436,9 +435,8 @@ static celix_status_t 
pubsub_websocketAdmin_disconnectEndpointFromReceiver(pubsu
 
     if (publisher && (sockAddress == NULL || sockPort < 0)) {
         L_WARN("[PSA WEBSOCKET] Error got endpoint without websocket 
address/port or endpoint type. Properties:");
-        const char *key = NULL;
-        CELIX_PROPERTIES_FOR_EACH(endpoint, key) {
-            L_WARN("[PSA WEBSOCKET] |- %s=%s\n", key, 
celix_properties_get(endpoint, key, NULL));
+        CELIX_PROPERTIES_ITERATE(endpoint, iter) {
+            L_WARN("[PSA WEBSOCKET] |- %s=%s\n", iter.key, iter.entry.value);
         }
         status = CELIX_BUNDLE_EXCEPTION;
     } else if (eTopic != NULL && strncmp(eTopic, topic, 1024 * 1024) == 0) {
diff --git a/bundles/pubsub/pubsub_discovery/src/pubsub_discovery_impl.c 
b/bundles/pubsub/pubsub_discovery/src/pubsub_discovery_impl.c
index 4815bd92..d7c2501d 100644
--- a/bundles/pubsub/pubsub_discovery/src/pubsub_discovery_impl.c
+++ b/bundles/pubsub/pubsub_discovery/src/pubsub_discovery_impl.c
@@ -557,10 +557,8 @@ static char* pubsub_discovery_createJsonEndpoint(const 
celix_properties_t *props
     //note props is already check for validity (pubsubEndpoint_isValid)
 
     json_t *jsEndpoint = json_object();
-    const char* propKey = NULL;
-    CELIX_PROPERTIES_FOR_EACH(props, propKey) {
-        const char* val = celix_properties_get(props, propKey, NULL);
-        json_object_set_new(jsEndpoint, propKey, json_string(val));
+    CELIX_PROPERTIES_ITERATE(props, iter) {
+        json_object_set_new(jsEndpoint, iter.key, 
json_string(iter.entry.value));
     }
     char* str = json_dumps(jsEndpoint, JSON_COMPACT);
     json_decref(jsEndpoint);
diff --git 
a/bundles/pubsub/pubsub_protocol/pubsub_protocol_lib/src/pubsub_wire_protocol_common.c
 
b/bundles/pubsub/pubsub_protocol/pubsub_protocol_lib/src/pubsub_wire_protocol_common.c
index 1d123d7b..390b43e4 100644
--- 
a/bundles/pubsub/pubsub_protocol/pubsub_protocol_lib/src/pubsub_wire_protocol_common.c
+++ 
b/bundles/pubsub/pubsub_protocol/pubsub_protocol_lib/src/pubsub_wire_protocol_common.c
@@ -199,16 +199,13 @@ celix_status_t 
pubsubProtocol_encodeMetadata(pubsub_protocol_message_t *message,
     size_t len = 0;
 
     if (message->metadata.metadata != NULL && 
celix_properties_size(message->metadata.metadata) > 0) {
-        const char *key;
         char *keyNetString = NULL;
         int netStringMemoryLength = 0;
 
-        CELIX_PROPERTIES_FOR_EACH(message->metadata.metadata, key) {
-            const char *val = celix_properties_get(message->metadata.metadata, 
key, "!Error!");
-
+        CELIX_PROPERTIES_ITERATE(message->metadata.metadata, iter) {
             //refactoring these two copies to a function leads to a slow down 
of about 2x
             int strlenKeyNetString = 0;
-            status = pubsubProtocol_createNetstring(key, &keyNetString, 
&strlenKeyNetString, &netStringMemoryLength);
+            status = pubsubProtocol_createNetstring(iter.key, &keyNetString, 
&strlenKeyNetString, &netStringMemoryLength);
             if (status != CELIX_SUCCESS) {
                 break;
             }
@@ -227,7 +224,7 @@ celix_status_t 
pubsubProtocol_encodeMetadata(pubsub_protocol_message_t *message,
             memcpy(line + idx, keyNetString, strlenKeyNetString);
             idx += strlenKeyNetString;
 
-            status = pubsubProtocol_createNetstring(val, &keyNetString, 
&strlenKeyNetString, &netStringMemoryLength);
+            status = pubsubProtocol_createNetstring(iter.entry.value, 
&keyNetString, &strlenKeyNetString, &netStringMemoryLength);
             if (status != CELIX_SUCCESS) {
                 break;
             }
diff --git a/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c 
b/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c
index 9d1ffe9e..25f133e1 100644
--- a/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c
+++ b/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c
@@ -46,9 +46,8 @@ static void pubsubEndpoint_setFields(celix_properties_t *ep, 
const char* fwUUID,
 
     //copy topic properties
     if (topic_props != NULL) {
-        const char *key = NULL;
-        CELIX_PROPERTIES_FOR_EACH((celix_properties_t *) topic_props, key) {
-            celix_properties_set(ep, key, celix_properties_get(topic_props, 
key, NULL));
+        CELIX_PROPERTIES_ITERATE((celix_properties_t *) topic_props, iter) {
+            celix_properties_set(ep, iter.key, iter.entry.value);
         }
     }
 
diff --git 
a/bundles/remote_services/discovery_common/src/endpoint_descriptor_writer.c 
b/bundles/remote_services/discovery_common/src/endpoint_descriptor_writer.c
index 66580b5a..5c4b585c 100644
--- a/bundles/remote_services/discovery_common/src/endpoint_descriptor_writer.c
+++ b/bundles/remote_services/discovery_common/src/endpoint_descriptor_writer.c
@@ -139,16 +139,15 @@ static celix_status_t 
endpointDescriptorWriter_writeEndpoint(endpoint_descriptor
     } else {
         xmlTextWriterStartElement(writer->writer, ENDPOINT_DESCRIPTION);
 
-        const char* propertyName;
-        CELIX_PROPERTIES_FOR_EACH(endpoint->properties, propertyName) {
-                       const xmlChar* propertyValue = (const xmlChar*) 
celix_properties_get(endpoint->properties, propertyName, "");
+        CELIX_PROPERTIES_ITERATE(endpoint->properties, iter) {
+                       const xmlChar* propertyValue = (const xmlChar*) 
celix_properties_get(endpoint->properties, iter.key, "");
             xmlTextWriterStartElement(writer->writer, PROPERTY);
-            xmlTextWriterWriteAttribute(writer->writer, NAME, (const 
xmlChar*)propertyName);
+            xmlTextWriterWriteAttribute(writer->writer, NAME, (const 
xmlChar*)iter.key);
 
-            if (strcmp(OSGI_FRAMEWORK_OBJECTCLASS, (char*) propertyName) == 0) 
{
+            if (strcmp(OSGI_FRAMEWORK_OBJECTCLASS, (char*) iter.key) == 0) {
                // objectClass *must* be represented as array of string 
values...
                endpointDescriptorWriter_writeArrayValue(writer->writer, 
propertyValue);
-            } else if (strcmp(OSGI_RSA_ENDPOINT_SERVICE_ID, (char*) 
propertyName) == 0) {
+            } else if (strcmp(OSGI_RSA_ENDPOINT_SERVICE_ID, (char*) iter.key) 
== 0) {
                // endpoint.service.id *must* be represented as long value...
                endpointDescriptorWriter_writeTypedValue(writer->writer, 
VALUE_TYPE_LONG, propertyValue);
             } else {
diff --git 
a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c
 
b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c
index 656b3773..2b5fc335 100644
--- 
a/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c
+++ 
b/bundles/remote_services/remote_service_admin_dfi/src/remote_service_admin_dfi.c
@@ -747,9 +747,8 @@ static celix_status_t 
remoteServiceAdmin_createEndpointDescription(remote_servic
     celix_properties_set(endpointProperties, RSA_DFI_ENDPOINT_URL, url);
 
     if (props != NULL) {
-        const char* key;
-        CELIX_PROPERTIES_FOR_EACH(props, key) {
-            celix_properties_set(endpointProperties, key, 
celix_properties_get(props, key, ""));
+        CELIX_PROPERTIES_ITERATE(props, iter) {
+            celix_properties_set(endpointProperties, iter.key, 
iter.entry.value);
         }
     }
 
@@ -947,14 +946,10 @@ static celix_status_t remoteServiceAdmin_send(void 
*handle, endpoint_description
     } else {
         struct curl_slist *metadataHeader = NULL;
         if (metadata != NULL && celix_properties_size(metadata) > 0) {
-            const char *key = NULL;
-            CELIX_PROPERTIES_FOR_EACH(metadata, key) {
-                const char *val = celix_properties_get(metadata, key, "");
-                size_t length = strlen(key) + strlen(val) + 18; // 
"X-RSA-Metadata-key: val\0"
-
+            CELIX_PROPERTIES_ITERATE(metadata, iter) {
+                size_t length = strlen(iter.key) + strlen(iter.entry.value) + 
18; // "X-RSA-Metadata-key: val\0"
                 char header[length];
-
-                snprintf(header, length, "X-RSA-Metadata-%s: %s", key, val);
+                snprintf(header, length, "X-RSA-Metadata-%s: %s", iter.key, 
iter.entry.value);
                 metadataHeader = curl_slist_append(metadataHeader, header);
             }
 
diff --git a/bundles/shell/shell/src/query_command.c 
b/bundles/shell/shell/src/query_command.c
index 739d3450..93cf69cb 100644
--- a/bundles/shell/shell/src/query_command.c
+++ b/bundles/shell/shell/src/query_command.c
@@ -95,18 +95,10 @@ static void queryCommand_callback(void *handle, const 
celix_bundle_t *bnd) {
                 queryCommand_printBundleHeader(data->sout, bnd, 
&printBundleCalled);
                 fprintf(data->sout, "|- Provided service '%s' [id = %li]\n", 
entry->serviceName, entry->serviceId);
                 if (data->opts->verbose) {
-                    const char *cmpUUID = 
celix_properties_get(entry->serviceProperties, "component.uuid", NULL);
-                    if (cmpUUID != NULL) {
-                        //TODO add context to opts
-                        //TODO add celix_dependencyManager_createInfoForUUID() 
                   }
-                        //TODO print component name
-                    }
                     fprintf(data->sout, "   |- Is factory: %s\n", 
entry->factory ? "true" : "false");
                     fprintf(data->sout, "   |- Properties:\n");
-                    const char *key;
-                    CELIX_PROPERTIES_FOR_EACH(entry->serviceProperties, key) {
-                        const char *val = 
celix_properties_get(entry->serviceProperties, key, "!ERROR!");
-                        fprintf(data->sout, "      |- %20s = %s\n", key, val);
+                    CELIX_PROPERTIES_ITERATE(entry->serviceProperties, iter) {
+                        fprintf(data->sout, "      |- %20s = %s\n", iter.key, 
iter.entry.value);
                     }
                 }
             }
diff --git a/libs/framework/include/celix/dm/DependencyManager_Impl.h 
b/libs/framework/include/celix/dm/DependencyManager_Impl.h
index f3e9f075..05e262d9 100644
--- a/libs/framework/include/celix/dm/DependencyManager_Impl.h
+++ b/libs/framework/include/celix/dm/DependencyManager_Impl.h
@@ -174,10 +174,8 @@ static celix::dm::DependencyManagerInfo 
createDepManInfoFromC(celix_dependency_m
             auto* cIntInfo = 
static_cast<dm_interface_info_t*>(celix_arrayList_get(cCmpInfo->interfaces, k));
             celix::dm::InterfaceInfo intInfo{};
             intInfo.serviceName = std::string{cIntInfo->name};
-            const char* key;
-            CELIX_PROPERTIES_FOR_EACH(cIntInfo->properties, key) {
-                const char* val =celix_properties_get(cIntInfo->properties, 
key, nullptr);
-                intInfo.properties[std::string{key}] = std::string{val};
+            CELIX_PROPERTIES_ITERATE(cIntInfo->properties, iter) {
+                intInfo.properties[std::string{iter.key}] = 
std::string{iter.entry.value};
             }
             cmpInfo.interfacesInfo.emplace_back(std::move(intInfo));
         }
@@ -206,7 +204,6 @@ inline celix::dm::DependencyManagerInfo 
DependencyManager::getInfo() const {
     return result;
 }
 
-
 inline std::vector<celix::dm::DependencyManagerInfo> 
DependencyManager::getInfos() const {
     std::vector<celix::dm::DependencyManagerInfo> result{};
     auto* cInfos = celix_dependencyManager_createInfos(cDependencyManager());
diff --git a/libs/framework/src/celix_launcher.c 
b/libs/framework/src/celix_launcher.c
index 60b0c8ec..394e0a15 100644
--- a/libs/framework/src/celix_launcher.c
+++ b/libs/framework/src/celix_launcher.c
@@ -188,17 +188,15 @@ void celixLauncher_stop(celix_framework_t* framework) {
 }
 
 static void show_properties(celix_properties_t *embeddedProps, const char 
*configFile) {
-       const char *key = NULL;
        celix_properties_t *keys = celix_properties_create(); //only to store 
the keys
 
        printf("Embedded properties:\n");
        if (embeddedProps == NULL || celix_properties_size(embeddedProps) == 0) 
{
                printf("|- Empty!\n");
        } else {
-               CELIX_PROPERTIES_FOR_EACH(embeddedProps, key) {
-                       const char *val = celix_properties_get(embeddedProps, 
key, "!Error!");
-                       printf("|- %s=%s\n", key, val);
-            celix_properties_set(keys, key, NULL);
+        CELIX_PROPERTIES_ITERATE(embeddedProps, iter) {
+                       printf("|- %s=%s\n", iter.key, iter.entry.value);
+            celix_properties_set(keys, iter.key, NULL);
         }
        }
        printf("\n");
@@ -211,10 +209,9 @@ static void show_properties(celix_properties_t 
*embeddedProps, const char *confi
        if (runtimeProps == NULL || celix_properties_size(runtimeProps) == 0) {
                printf("|- Empty!\n");
        } else {
-               CELIX_PROPERTIES_FOR_EACH(runtimeProps, key) {
-                       const char *val = celix_properties_get(runtimeProps, 
key, "!Error!");
-                       printf("|- %s=%s\n", key, val);
-            celix_properties_set(keys, key, NULL);
+        CELIX_PROPERTIES_ITERATE(runtimeProps, iter) {
+                       printf("|- %s=%s\n", iter.key, iter.entry.value);
+            celix_properties_set(keys, iter.key, NULL);
                }
        }
     printf("\n");
@@ -225,13 +222,13 @@ static void show_properties(celix_properties_t 
*embeddedProps, const char *confi
        if (celix_properties_size(keys) == 0) {
                printf("|- Empty!\n");
        } else {
-               CELIX_PROPERTIES_FOR_EACH(keys, key) {
-                       const char *valEm = celix_properties_get(embeddedProps, 
key, NULL);
-            const char *valRt = celix_properties_get(runtimeProps, key, NULL);
-            const char *envVal = getenv(key);
+        CELIX_PROPERTIES_ITERATE(keys, iter) {
+                       const char *valEm = celix_properties_get(embeddedProps, 
iter.key, NULL);
+            const char *valRt = celix_properties_get(runtimeProps, iter.key, 
NULL);
+            const char *envVal = getenv(iter.key);
             const char *val = envVal != NULL ? envVal : valRt != NULL ? valRt 
: valEm;
             const char *source = envVal != NULL ? "environment" : valRt != 
NULL ? "runtime" : "embedded";
-                       printf("|- %s=%s (source %s)\n", key, val, source);
+                       printf("|- %s=%s (source %s)\n", iter.key, val, source);
                }
        }
     printf("\n");
@@ -258,9 +255,8 @@ static void printEmbeddedBundles() {
 
 static void combine_properties(celix_properties_t *original, const 
celix_properties_t *append) {
        if (original != NULL && append != NULL) {
-               const char *key = NULL;
-               CELIX_PROPERTIES_FOR_EACH(append, key) {
-                       celix_properties_set(original, key, 
celix_properties_get(append, key, NULL));
+               CELIX_PROPERTIES_ITERATE(append, iter) {
+                       celix_properties_set(original, iter.key, 
iter.entry.value);
                }
        }
 }
diff --git a/libs/framework/src/service_reference.c 
b/libs/framework/src/service_reference.c
index a7faebd7..0160ae8e 100644
--- a/libs/framework/src/service_reference.c
+++ b/libs/framework/src/service_reference.c
@@ -204,9 +204,8 @@ FRAMEWORK_EXPORT celix_status_t 
serviceReference_getPropertyKeys(service_referen
     int vsize = celix_properties_size(props);
     *size = (unsigned int)vsize;
     *keys = malloc(vsize * sizeof(**keys));
-    const char* key;
-    CELIX_PROPERTIES_FOR_EACH(props, key) {
-        (*keys)[i++] = (char*)key;
+    CELIX_PROPERTIES_ITERATE(props, iter) {
+        (*keys)[i++] = (char*)iter.key;
     }
     return status;
 }
diff --git a/libs/utils/gtest/src/CxxPropertiesTestSuite.cc 
b/libs/utils/gtest/src/CxxPropertiesTestSuite.cc
index b2f39192..7d4f3532 100644
--- a/libs/utils/gtest/src/CxxPropertiesTestSuite.cc
+++ b/libs/utils/gtest/src/CxxPropertiesTestSuite.cc
@@ -176,7 +176,12 @@ TEST_F(CxxPropertiesTestSuite, StoreAndLoadTest) {
     EXPECT_NO_THROW(loadedProps = celix::Properties::load(path));
     EXPECT_EQ(props.size(), loadedProps.size());
 
-    EXPECT_THROW(loadedProps = celix::Properties::load("non-existence"), 
celix::IOException);
+    try {
+        loadedProps = celix::Properties::load("non-existence");
+        FAIL() << "Expected exception not thrown";
+    } catch (const celix::IOException& e) {
+        EXPECT_TRUE(strstr(e.what(), "Cannot load celix::Properties"));
+    }
 }
 
 #if __cplusplus >= 201703L //C++17 or higher
diff --git a/libs/utils/gtest/src/CxxVersionTestSuite.cc 
b/libs/utils/gtest/src/CxxVersionTestSuite.cc
index 0055d5c4..ac7266c3 100644
--- a/libs/utils/gtest/src/CxxVersionTestSuite.cc
+++ b/libs/utils/gtest/src/CxxVersionTestSuite.cc
@@ -18,6 +18,8 @@
  */
 
 #include <gtest/gtest.h>
+#include <unordered_map>
+#include <map>
 
 #include "celix/Version.h"
 
diff --git a/libs/utils/gtest/src/PropertiesTestSuite.cc 
b/libs/utils/gtest/src/PropertiesTestSuite.cc
index f21b4049..6904652e 100644
--- a/libs/utils/gtest/src/PropertiesTestSuite.cc
+++ b/libs/utils/gtest/src/PropertiesTestSuite.cc
@@ -21,6 +21,7 @@
 
 #include "celix_properties.h"
 #include "celix_utils.h"
+#include "properties.h"
 
 using ::testing::MatchesRegex;
 
@@ -56,6 +57,16 @@ TEST_F(PropertiesTestSuite, LoadTest) {
     celix_properties_destroy(properties);
 }
 
+TEST_F(PropertiesTestSuite, LoadFromStringTest) {
+    const char* string = "key1=value1\nkey2=value2";
+    auto* props = celix_properties_loadFromString(string);
+    EXPECT_EQ(2, celix_properties_size(props));
+    EXPECT_STREQ("value1", celix_properties_get(props, "key1", ""));
+    EXPECT_STREQ("value2", celix_properties_get(props, "key2", ""));
+    celix_properties_destroy(props);
+}
+
+
 TEST_F(PropertiesTestSuite, StoreTest) {
     const char* propertiesFile = "resources-test/properties_out.txt";
     auto* properties = celix_properties_create();
@@ -99,23 +110,6 @@ TEST_F(PropertiesTestSuite, GetAsLongTest) {
     celix_properties_destroy(props);
 }
 
-TEST_F(PropertiesTestSuite, CopyTest) {
-    char propertiesFile[] = "resources-test/properties.txt";
-    auto* properties = celix_properties_load(propertiesFile);
-    EXPECT_EQ(4, celix_properties_size(properties));
-
-    celix_properties_t *copy = celix_properties_copy(properties);
-
-    char keyA[] = "a";
-    const char *valueA = celix_properties_get(copy, keyA, nullptr);
-    EXPECT_STREQ("b", valueA);
-    const char keyB[] = "b";
-    EXPECT_STREQ("c \t d", celix_properties_get(copy, keyB, nullptr));
-
-    celix_properties_destroy(properties);
-    celix_properties_destroy(copy);
-}
-
 TEST_F(PropertiesTestSuite, GetSetTest) {
     auto* properties = celix_properties_create();
     char keyA[] = "x";
@@ -169,6 +163,13 @@ TEST_F(PropertiesTestSuite, SetUnsetTest) {
     celix_properties_unset(properties, keyD);
     EXPECT_EQ(nullptr, celix_properties_get(properties, keyA, nullptr));
     EXPECT_EQ(nullptr, celix_properties_get(properties, "a", nullptr));
+    EXPECT_EQ(0, celix_properties_size(properties));
+
+    celix_properties_set(properties, keyA, nullptr);
+    EXPECT_EQ(1, celix_properties_size(properties));
+    celix_properties_unset(properties, keyA);
+    EXPECT_EQ(0, celix_properties_size(properties));
+
     celix_properties_destroy(properties);
 }
 
@@ -202,6 +203,35 @@ TEST_F(PropertiesTestSuite, GetLongTest) {
     celix_properties_destroy(properties);
 }
 
+TEST_F(PropertiesTestSuite, GetAsDoubleTest) {
+    auto* properties = celix_properties_create();
+
+    celix_properties_set(properties, "a", "2");
+    celix_properties_set(properties, "b", "-10032L");
+    celix_properties_set(properties, "c", "1.2");
+    celix_properties_setDouble(properties, "d", 1.4);
+    celix_properties_set(properties, "e", "");
+    celix_properties_set(properties, "f", "garbage");
+
+    double a = celix_properties_getAsDouble(properties, "a", -1);
+    double b = celix_properties_getAsDouble(properties, "b", -1);
+    double c = celix_properties_getAsDouble(properties, "c", -1);
+    double d = celix_properties_getAsDouble(properties, "d", -1);
+    double e = celix_properties_getAsDouble(properties, "e", -1);
+    double f = celix_properties_getAsDouble(properties, "f", -1);
+    double g = celix_properties_getAsDouble(properties, "g", -1); //does not 
exist
+
+    EXPECT_EQ(2, a);
+    EXPECT_EQ(-10032L, b);
+    EXPECT_EQ(1.2, c);
+    EXPECT_EQ(1.4, d);
+    EXPECT_EQ(-1L, e);
+    EXPECT_EQ(-1L, f);
+    EXPECT_EQ(-1L, g);
+
+    celix_properties_destroy(properties);
+}
+
 TEST_F(PropertiesTestSuite, GetBoolTest) {
     auto* properties = celix_properties_create();
 
@@ -295,7 +325,7 @@ TEST_F(PropertiesTestSuite, SizeAndIteratorTest) {
     celix_properties_destroy(props);
 }
 
-TEST_F(PropertiesTestSuite, GetTypeTest) {
+TEST_F(PropertiesTestSuite, GetTypeAndCopyTest) {
     auto* props = celix_properties_create();
     celix_properties_set(props, "string", "value");
     celix_properties_setLong(props, "long", 123);
@@ -304,6 +334,7 @@ TEST_F(PropertiesTestSuite, GetTypeTest) {
     auto* version = celix_version_createVersion(1, 2, 3, nullptr);
     celix_properties_setVersion(props, "version", version);
 
+    EXPECT_EQ(5, celix_properties_size(props));
     EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_STRING, 
celix_properties_getType(props, "string"));
     EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_LONG, 
celix_properties_getType(props, "long"));
     EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_DOUBLE, 
celix_properties_getType(props, "double"));
@@ -311,8 +342,17 @@ TEST_F(PropertiesTestSuite, GetTypeTest) {
     EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_VERSION, 
celix_properties_getType(props, "version"));
     EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_UNSET, 
celix_properties_getType(props, "missing"));
 
+    auto* copy = celix_properties_copy(props);
+    EXPECT_EQ(5, celix_properties_size(copy));
+    EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_STRING, 
celix_properties_getType(copy, "string"));
+    EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_LONG, celix_properties_getType(copy, 
"long"));
+    EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_DOUBLE, 
celix_properties_getType(copy, "double"));
+    EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_BOOL, celix_properties_getType(copy, 
"bool"));
+    EXPECT_EQ(CELIX_PROPERTIES_VALUE_TYPE_VERSION, 
celix_properties_getType(copy, "version"));
+
     celix_version_destroy(version);
     celix_properties_destroy(props);
+    celix_properties_destroy(copy);
 }
 
 TEST_F(PropertiesTestSuite, GetEntryTest) {
@@ -509,4 +549,38 @@ TEST_F(PropertiesTestSuite, EndOfEmptyPropertiesTest) {
     celix_properties_destroy(props);
 }
 
-//TODO test replace and replace WithCopy
\ No newline at end of file
+TEST_F(PropertiesTestSuite, SetWithCopyTest) {
+    auto* props = celix_properties_create();
+    celix_properties_setWithoutCopy(props, celix_utils_strdup("key"), 
celix_utils_strdup("value2"));
+    //replace, should free old value and provided key
+    celix_properties_setWithoutCopy(props, celix_utils_strdup("key"), 
celix_utils_strdup("value2"));
+    EXPECT_EQ(1, celix_properties_size(props));
+    celix_properties_destroy(props);
+}
+
+TEST_F(PropertiesTestSuite, DeprecatedApiTest) {
+    //Check if the deprecated api can still be used
+    auto* props = properties_create();
+    properties_set(props, "key", "value");
+    EXPECT_EQ(1, celix_properties_size(props));
+    EXPECT_STREQ("value", properties_get(props, "key"));
+    EXPECT_STREQ("notfound", properties_getWithDefault(props, "non-existing", 
"notfound"));
+    properties_unset(props, "key");
+    EXPECT_EQ(0, celix_properties_size(props));
+    celix_properties_t * copy = nullptr;
+    EXPECT_EQ(CELIX_SUCCESS, properties_copy(props, &copy));
+    properties_destroy(copy);
+
+
+    properties_store(props, "deprecated-api-stored.properties", "");
+    auto* loaded = properties_load("deprecated-api-stored.properties");
+    EXPECT_NE(nullptr, loaded);
+    properties_destroy(loaded);
+
+    loaded = properties_loadFromString("key=value");
+    EXPECT_EQ(1, celix_properties_size(loaded));
+    properties_destroy(loaded);
+
+
+    properties_destroy(props);
+}
diff --git a/libs/utils/include/celix/Version.h 
b/libs/utils/include/celix/Version.h
index 556f4e92..c019d14a 100644
--- a/libs/utils/include/celix/Version.h
+++ b/libs/utils/include/celix/Version.h
@@ -45,8 +45,6 @@ namespace celix {
             cVersion{createVersion(celix_version_createEmptyVersion())},
             qualifier{celix_version_getQualifier(cVersion.get())} {}
 
-#if __cplusplus >= 201703L //C++17 or higher
-
         /**
          * @brief Constructs a new version with the given components and 
qualifier.
          * @param major The major component of the version.
@@ -54,6 +52,7 @@ namespace celix {
          * @param micro The micro component of the version.
          * @param qualifier The qualifier string of the version.
          */
+#if __cplusplus >= 201703L //C++17 or higher
         Version(int major, int minor, int micro, std::string_view qualifier = 
{}) :
             cVersion{createVersion(celix_version_create(major, minor, micro, 
qualifier.empty() ? "" : qualifier.data()))},
             qualifier{celix_version_getQualifier(cVersion.get())} {}
diff --git a/libs/utils/include/celix_properties.h 
b/libs/utils/include/celix_properties.h
index 71bc0f53..45bbef17 100644
--- a/libs/utils/include/celix_properties.h
+++ b/libs/utils/include/celix_properties.h
@@ -405,14 +405,6 @@ void 
celix_propertiesIterator_next(celix_properties_iterator_t* iter);
  */
 bool celix_propertiesIterator_isEnd(const celix_properties_iterator_t* iter);
 
-/**
- * @brief Get the property set being iterated over.
- *
- * @param[in] iter The iterator to get the property set from.
- * @return The property set being iterated over.
- */
-celix_properties_t* celix_propertiesIterator_properties(const 
celix_properties_iterator_t *iter);
-
 /**
  * @brief Determine whether two iterators are equal.
  *
@@ -517,8 +509,6 @@ const char* 
celix_propertiesIterator_nextKey(celix_properties_iterator_t* iter)
     for(celix_properties_iterator_t iter_##key = 
celix_propertiesIterator_construct(properties); \
        celix_propertiesIterator_hasNext(&iter_##key), (key) = 
celix_propertiesIterator_nextKey(&iter_##key);)
 
-
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/utils/src/properties.c b/libs/utils/src/properties.c
index dbbc2048..cf9df264 100644
--- a/libs/utils/src/properties.c
+++ b/libs/utils/src/properties.c
@@ -141,7 +141,10 @@ static void updateBuffers(char **key, char ** value, char 
**output, int outputPo
  * optimization string buffer.
  */
 static char* celix_properties_createString(celix_properties_t* properties, 
const char* str) {
-    size_t len = str == NULL ? 0 : strnlen(str, CELIX_UTILS_MAX_STRLEN) + 1;
+    if (str == NULL) {
+        return NULL;
+    }
+    size_t len = strnlen(str, CELIX_UTILS_MAX_STRLEN) + 1;
     size_t left = CELIX_SHORT_PROPERTIES_OPTIMIZATION_STRING_BUFFER_SIZE - 
properties->currentStringBufferIndex;
     char* result;
     if (len < left) {
@@ -160,7 +163,7 @@ static char* 
celix_properties_createString(celix_properties_t* properties, const
 static celix_status_t celix_properties_fillEntry(
         celix_properties_t *properties,
         celix_properties_entry_t* entry,
-        const char *strValue,
+        const char** strValue,
         const long* longValue,
         const double* doubleValue,
         const bool* boolValue,
@@ -168,7 +171,7 @@ static celix_status_t celix_properties_fillEntry(
     char convertedValueBuffer[32];
     if (strValue != NULL) {
         entry->valueType = CELIX_PROPERTIES_VALUE_TYPE_STRING;
-        entry->value = celix_properties_createString(properties, strValue);
+        entry->value = celix_properties_createString(properties, *strValue);
         entry->typed.strValue = entry->value;
     } else if (longValue != NULL) {
         entry->valueType = CELIX_PROPERTIES_VALUE_TYPE_LONG;
@@ -250,7 +253,7 @@ static celix_properties_entry_t* 
celix_properties_createEntryWithNoCopy(celix_pr
 static celix_properties_entry_t* celix_properties_createEntry(
         celix_properties_t *properties,
         const char *key,
-        const char *strValue,
+        const char** strValue,
         const long* longValue,
         const double* doubleValue,
         const bool* boolValue,
@@ -276,7 +279,7 @@ static celix_properties_entry_t* 
celix_properties_createEntry(
 static void celix_properties_createAndSetEntry(
         celix_properties_t *properties,
         const char *key,
-        const char *strValue,
+        const char** strValue,
         const long* longValue,
         const double* doubleValue,
         const bool* boolValue,
@@ -348,13 +351,13 @@ celix_properties_t* celix_properties_create(void) {
 void celix_properties_destroy(celix_properties_t *props) {
     if (props != NULL) {
         //TODO measure print nr of entries and total size of the string keys 
and values
-//        fprintf(stdout, "Properties size; %d", celix_properties_size(props));
-//        size_t size = 0;
-//        CELIX_PROPERTIES_ITERATE(props, iter) {
-//            size += strlen(iter.entry.key) + 1;
-//            size += strlen(iter.entry.value) + 1;
-//        }
-//        fprintf(stdout, "Properties string size: %zu", size);
+        fprintf(stdout, "Properties entries size: %d\n", 
celix_properties_size(props));
+        size_t size = 0;
+        CELIX_PROPERTIES_ITERATE(props, iter) {
+            size += strlen(iter.key) + 1;
+            size += strlen(iter.entry.value) + 1;
+        }
+        fprintf(stdout, "Properties total string size: %zu\n\n", size);
 
         celix_stringHashMap_destroy(props->map);
         free(props);
@@ -628,8 +631,8 @@ celix_properties_entry_t* celix_properties_getEntry(const 
celix_properties_t* pr
 }
 
 void celix_properties_set(celix_properties_t *properties, const char *key, 
const char *value) {
-    if (properties != NULL && key != NULL && value != NULL) {
-        celix_properties_createAndSetEntry(properties, key, value, NULL, NULL, 
NULL, NULL);
+    if (properties != NULL && key != NULL) {
+        celix_properties_createAndSetEntry(properties, key, &value, NULL, 
NULL, NULL, NULL);
     }
 }
 
@@ -863,8 +866,3 @@ bool celix_propertiesIterator_equals(const 
celix_properties_iterator_t* a, const
     return celix_stringHashMapIterator_equals(&internalIterA.mapIter, 
&internalIterB.mapIter);
 }
 
-celix_properties_t* celix_propertiesIterator_properties(const 
celix_properties_iterator_t *iter) {
-    celix_properties_iterator_internal_t internalIter;
-    memcpy(&internalIter, iter, sizeof(internalIter));
-    return (celix_properties_t*)internalIter.props;
-}


Reply via email to