This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/685-properties-json-serialization in repository https://gitbox.apache.org/repos/asf/celix.git
commit 99e503aa62a02173818a7d518c102f7dd8edaa12 Author: Pepijn Noltes <pnol...@apache.org> AuthorDate: Sun Apr 14 16:54:16 2024 +0200 gh-685: Add error injection test for properties encoding --- conanfile.py | 4 +- libs/error_injector/jansson/CMakeLists.txt | 2 + libs/error_injector/jansson/include/jansson_ei.h | 2 + libs/error_injector/jansson/src/jansson_ei.cc | 58 ++-- .../error_injector/celix_version/CMakeLists.txt | 1 + .../celix_version/include/celix_version_ei.h | 2 + .../celix_version/src/celix_version_ei.cc | 7 + libs/utils/gtest/CMakeLists.txt | 2 + .../PropertiesEncodingErrorInjectionTestSuite.cc | 305 +++++++++++++++++++++ .../utils/gtest/src/PropertiesEncodingTestSuite.cc | 30 +- libs/utils/src/properties.c | 3 +- libs/utils/src/properties_encoding.c | 53 ++-- 12 files changed, 403 insertions(+), 66 deletions(-) diff --git a/conanfile.py b/conanfile.py index 609082c8..63d9ac00 100644 --- a/conanfile.py +++ b/conanfile.py @@ -309,7 +309,7 @@ class CelixConan(ConanFile): self.options['openssl'].shared = True if self.options.build_celix_dfi: self.options['libffi'].shared = True - if self.options.build_celix_dfi or self.options.build_celix_etcdlib: + if self.options.build_utils or self.options.build_celix_dfi or self.options.build_celix_etcdlib: self.options['jansson'].shared = True def requirements(self): @@ -332,7 +332,7 @@ class CelixConan(ConanFile): self.requires("civetweb/1.16") if self.options.build_celix_dfi: self.requires("libffi/[>=3.2.1 <4.0.0]") - if self.options.build_celix_dfi or self.options.build_celix_etcdlib: + if self.option.build_utils or self.options.build_celix_dfi or self.options.build_celix_etcdlib: self.requires("jansson/[>=2.12 <3.0.0]") if self.options.build_rsa_discovery_zeroconf: # TODO: To be replaced with mdnsresponder/1790.80.10, resolve some problems of mdnsresponder diff --git a/libs/error_injector/jansson/CMakeLists.txt b/libs/error_injector/jansson/CMakeLists.txt index b536956a..b093901d 100644 --- a/libs/error_injector/jansson/CMakeLists.txt +++ b/libs/error_injector/jansson/CMakeLists.txt @@ -35,5 +35,7 @@ target_link_options(jansson_ei INTERFACE LINKER:--wrap,json_integer LINKER:--wrap,json_string LINKER:--wrap,json_real + LINKER:--wrap,json_vsprintf + LINKER:--wrap,json_sprintf ) add_library(Celix::jansson_ei ALIAS jansson_ei) diff --git a/libs/error_injector/jansson/include/jansson_ei.h b/libs/error_injector/jansson/include/jansson_ei.h index 60f04e45..167ace85 100644 --- a/libs/error_injector/jansson/include/jansson_ei.h +++ b/libs/error_injector/jansson/include/jansson_ei.h @@ -34,6 +34,8 @@ CELIX_EI_DECLARE(json_array_append_new, int); CELIX_EI_DECLARE(json_integer, json_t*); CELIX_EI_DECLARE(json_string, json_t*); CELIX_EI_DECLARE(json_real, json_t*); +CELIX_EI_DECLARE(json_vsprintf,json_t*); +CELIX_EI_DECLARE(json_sprintf, json_t*); #ifdef __cplusplus } diff --git a/libs/error_injector/jansson/src/jansson_ei.cc b/libs/error_injector/jansson/src/jansson_ei.cc index 57033c0c..1d820629 100644 --- a/libs/error_injector/jansson/src/jansson_ei.cc +++ b/libs/error_injector/jansson/src/jansson_ei.cc @@ -23,69 +23,87 @@ extern "C" { -size_t __real_json_array_size(const json_t *array); +size_t __real_json_array_size(const json_t* array); CELIX_EI_DEFINE(json_array_size, size_t) -size_t __wrap_json_array_size(const json_t *array) { +size_t __wrap_json_array_size(const json_t* array) { CELIX_EI_IMPL(json_array_size); return __real_json_array_size(array); } -char *__real_json_dumps(const json_t *json, size_t flags); +char* __real_json_dumps(const json_t* json, size_t flags); CELIX_EI_DEFINE(json_dumps, char*) -char *__wrap_json_dumps(const json_t *json, size_t flags) { +char* __wrap_json_dumps(const json_t* json, size_t flags) { CELIX_EI_IMPL(json_dumps); return __real_json_dumps(json, flags); } -json_t *__real_json_object(void); +json_t* __real_json_object(void); CELIX_EI_DEFINE(json_object, json_t*) -json_t *__wrap_json_object(void) { +json_t* __wrap_json_object(void) { CELIX_EI_IMPL(json_object); return __real_json_object(); } -int __real_json_object_set_new(json_t *object, const char *key, json_t *value); +int __real_json_object_set_new(json_t* object, const char* key, json_t* value); CELIX_EI_DEFINE(json_object_set_new, int) -int __wrap_json_object_set_new(json_t *object, const char *key, json_t *value) { - json_auto_t *val = value; +int __wrap_json_object_set_new(json_t* object, const char* key, json_t* value) { + json_auto_t* val = value; CELIX_EI_IMPL(json_object_set_new); return __real_json_object_set_new(object, key, celix_steal_ptr(val)); } -json_t *__real_json_array(void); +json_t* __real_json_array(void); CELIX_EI_DEFINE(json_array, json_t*) -json_t *__wrap_json_array(void) { +json_t* __wrap_json_array(void) { CELIX_EI_IMPL(json_array); return __real_json_array(); } -int __real_json_array_append_new(json_t *array, json_t *value); +int __real_json_array_append_new(json_t* array, json_t* value); CELIX_EI_DEFINE(json_array_append_new, int) -int __wrap_json_array_append_new(json_t *array, json_t *value) { - json_auto_t *val = value; +int __wrap_json_array_append_new(json_t* array, json_t* value) { + json_auto_t* val = value; CELIX_EI_IMPL(json_array_append_new); return __real_json_array_append_new(array, celix_steal_ptr(val)); } -json_t *__real_json_integer(json_int_t value); +json_t* __real_json_integer(json_int_t value); CELIX_EI_DEFINE(json_integer, json_t*) -json_t *__wrap_json_integer(json_int_t value) { +json_t* __wrap_json_integer(json_int_t value) { CELIX_EI_IMPL(json_integer); return __real_json_integer(value); } -json_t *__real_json_string(const char *value); +json_t* __real_json_string(const char* value); CELIX_EI_DEFINE(json_string, json_t*) -json_t *__wrap_json_string(const char *value) { +json_t* __wrap_json_string(const char* value) { CELIX_EI_IMPL(json_string); return __real_json_string(value); } -json_t *__real_json_real(double value); +json_t* __real_json_real(double value); CELIX_EI_DEFINE(json_real, json_t*) -json_t *__wrap_json_real(double value) { +json_t* __wrap_json_real(double value) { CELIX_EI_IMPL(json_real); return __real_json_real(value); } +json_t* __real_json_vsprintf(const char* fmt, va_list ap); +CELIX_EI_DEFINE(json_vsprintf, json_t*) +json_t* __wrap_json_vsprintf(const char* fmt, va_list ap) { + CELIX_EI_IMPL(json_vsprintf); + return __real_json_vsprintf(fmt, ap); +} + +json_t* __real_json_sprintf(const char* fmt, ...); +CELIX_EI_DEFINE(json_sprintf, json_t*) +json_t* __wrap_json_sprintf(const char* fmt, ...) { + CELIX_EI_IMPL(json_sprintf); + va_list args; + va_start(args, fmt); + json_t* obj = __real_json_vsprintf(fmt, args); + va_end(args); + return obj; +} + } \ No newline at end of file diff --git a/libs/utils/error_injector/celix_version/CMakeLists.txt b/libs/utils/error_injector/celix_version/CMakeLists.txt index ed7aadcd..81886a5f 100644 --- a/libs/utils/error_injector/celix_version/CMakeLists.txt +++ b/libs/utils/error_injector/celix_version/CMakeLists.txt @@ -24,5 +24,6 @@ target_link_options(version_ei INTERFACE LINKER:--wrap,celix_version_createVersionFromString LINKER:--wrap,celix_version_parse LINKER:--wrap,celix_version_copy + LINKER:--wrap,celix_version_toString ) add_library(Celix::version_ei ALIAS version_ei) diff --git a/libs/utils/error_injector/celix_version/include/celix_version_ei.h b/libs/utils/error_injector/celix_version/include/celix_version_ei.h index a8231857..e5d510f7 100644 --- a/libs/utils/error_injector/celix_version/include/celix_version_ei.h +++ b/libs/utils/error_injector/celix_version/include/celix_version_ei.h @@ -31,6 +31,8 @@ CELIX_EI_DECLARE(celix_version_parse, celix_status_t); CELIX_EI_DECLARE(celix_version_copy, celix_version_t*); +CELIX_EI_DECLARE(celix_version_toString, char*); + #ifdef __cplusplus } #endif diff --git a/libs/utils/error_injector/celix_version/src/celix_version_ei.cc b/libs/utils/error_injector/celix_version/src/celix_version_ei.cc index eefad50d..ddcdf9f8 100644 --- a/libs/utils/error_injector/celix_version/src/celix_version_ei.cc +++ b/libs/utils/error_injector/celix_version/src/celix_version_ei.cc @@ -41,4 +41,11 @@ celix_version_t* __wrap_celix_version_copy(const celix_version_t* version) { return __real_celix_version_copy(version); } +char* __real_celix_version_toString(const celix_version_t* version); +CELIX_EI_DEFINE(celix_version_toString, char*); +char* __wrap_celix_version_toString(const celix_version_t* version) { + CELIX_EI_IMPL(celix_version_toString); + return __real_celix_version_toString(version); +} + } \ No newline at end of file diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt index 11c6ec00..08be2b58 100644 --- a/libs/utils/gtest/CMakeLists.txt +++ b/libs/utils/gtest/CMakeLists.txt @@ -127,6 +127,7 @@ if (EI_TESTS) src/VersionErrorInjectionTestSuite.cc src/HashMapErrorInjectionTestSuite.cc src/FilterErrorInjectionTestSuite.cc + src/PropertiesEncodingErrorInjectionTestSuite.cc ) target_link_libraries(test_utils_with_ei PRIVATE Celix::zip_ei @@ -143,6 +144,7 @@ if (EI_TESTS) Celix::long_hash_map_ei Celix::version_ei Celix::array_list_ei + Celix::jansson_ei GTest::gtest GTest::gtest_main ) target_include_directories(test_utils_with_ei PRIVATE ../src) #for version_private (needs refactoring of test) diff --git a/libs/utils/gtest/src/PropertiesEncodingErrorInjectionTestSuite.cc b/libs/utils/gtest/src/PropertiesEncodingErrorInjectionTestSuite.cc new file mode 100644 index 00000000..9e2d3bc3 --- /dev/null +++ b/libs/utils/gtest/src/PropertiesEncodingErrorInjectionTestSuite.cc @@ -0,0 +1,305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <gtest/gtest.h> + +#include "celix_err.h" +#include "celix_properties.h" + +#include "celix_array_list_ei.h" +#include "celix_utils_ei.h" +#include "celix_version_ei.h" +#include "jansson_ei.h" +#include "malloc_ei.h" +#include "stdio_ei.h" + +class PropertiesEncodingErrorInjectionTestSuite : public ::testing::Test { + public: + PropertiesEncodingErrorInjectionTestSuite() = default; + + ~PropertiesEncodingErrorInjectionTestSuite() override { + celix_ei_expect_json_object(nullptr, 0, nullptr); + celix_ei_expect_open_memstream(nullptr, 0, nullptr); + celix_ei_expect_celix_utils_writeOrCreateString(nullptr, 0, nullptr); + celix_ei_expect_json_object_set_new(nullptr, 0, -1); + celix_ei_expect_json_sprintf(nullptr, 0, nullptr); + celix_ei_expect_celix_version_toString(nullptr, 0, nullptr); + celix_ei_expect_malloc(nullptr, 0, nullptr); + celix_ei_expect_celix_arrayList_createWithOptions(nullptr, 0, nullptr); + celix_ei_expect_celix_arrayList_addString(nullptr, 0, CELIX_SUCCESS); + + } +}; + +TEST_F(PropertiesEncodingErrorInjectionTestSuite, SaveErrorTest) { + //Given a dummy properties object + celix_autoptr(celix_properties_t) props = celix_properties_create(); + celix_properties_set(props, "key", "value"); + + //When an error injected is prepared for json_object() from saveToStream + celix_ei_expect_json_object((void*)celix_properties_saveToStream, 0, nullptr); + + //And a dummy stream is created + FILE* stream = fopen("/dev/null", "w"); + + //When I call celix_properties_saveToStream + celix_status_t status = celix_properties_saveToStream(props, stream, 0); + + //Then I expect an error + EXPECT_EQ(CELIX_ENOMEM, status); + fclose(stream); + + //When an error injected is prepared for open_memstream()n from save + celix_ei_expect_open_memstream((void*)celix_properties_saveToString, 0, nullptr); + + //When I call celix_properties_saveToString + char* out = nullptr; + status = celix_properties_saveToString(props, 0, &out); + + //Then I expect an error + EXPECT_EQ(ENOMEM, status); + + //And I expect 2 error messages in celix_err + EXPECT_EQ(2, celix_err_getErrorCount()); + celix_err_printErrors(stderr, "Test Error: ", "\n"); +} + +TEST_F(PropertiesEncodingErrorInjectionTestSuite, EncodeErrorTest) { + // Given a dummy properties object + celix_autoptr(celix_properties_t) props = celix_properties_create(); + celix_properties_set(props, "key/with/slash", "value"); + celix_properties_set(props, "key-with-out-slash", "value"); + + // When an error injected is prepared for celix_utils_writeOrCreateString() from celix_properties_saveToString + celix_ei_expect_celix_utils_writeOrCreateString((void*)celix_properties_saveToString, 2, nullptr); + + // And I call celix_properties_saveToString using NESTED encoding (whitebox-knowledge) + char* out = nullptr; + auto status = celix_properties_saveToString(props, CELIX_PROPERTIES_ENCODE_NESTED, &out); + + // Then I expect an error + EXPECT_EQ(ENOMEM, status); + + // When an error injected is prepared for json_object() from celix_properties_saveToString + celix_ei_expect_json_object((void*)celix_properties_saveToString, 2, nullptr); + + // And I call celix_properties_saveToString using NESTED encoding (whitebox-knowledge) + status = celix_properties_saveToString(props, CELIX_PROPERTIES_ENCODE_NESTED, &out); + + // Then I expect an error + EXPECT_EQ(ENOMEM, status); + + // When an error injected is prepared for json_object_set_new() from celix_properties_saveToString + celix_ei_expect_json_object_set_new((void*)celix_properties_saveToString, 2, -1); + + // And I call celix_properties_saveToString using NESTED encoding (whitebox-knowledge) + status = celix_properties_saveToString(props, CELIX_PROPERTIES_ENCODE_NESTED, &out); + + // Then I expect an error + EXPECT_EQ(ENOMEM, status); + + // When an error injected is prepared for json_string() from celix_properties_saveToString + celix_ei_expect_json_string((void*)celix_properties_saveToString, 3, nullptr); + + // And I call celix_properties_saveToString using NESTED encoding (whitebox-knowledge) + status = celix_properties_saveToString(props, CELIX_PROPERTIES_ENCODE_NESTED, &out); + + // Then I expect an error + EXPECT_EQ(ENOMEM, status); + + // When an error injected is prepared for json_object_set_new() from celix_properties_saveToString + celix_ei_expect_json_object_set_new((void*)celix_properties_saveToString, 3, -1); + + // And I call celix_properties_saveToString using FLAT encoding (whitebox-knowledge) + status = celix_properties_saveToString(props, CELIX_PROPERTIES_ENCODE_FLAT, &out); + + // Then I expect an error + EXPECT_EQ(ENOMEM, status); + + // And I expect 5 error message in celix_err + EXPECT_EQ(5, celix_err_getErrorCount()); + celix_err_printErrors(stderr, "Test Error: ", "\n"); +} + +TEST_F(PropertiesEncodingErrorInjectionTestSuite, EncodeArrayErrorTest) { + // Given a dummy properties object with an array + celix_autoptr(celix_properties_t) props = celix_properties_create(); + auto* arr = celix_arrayList_createStringArray(); + celix_arrayList_addString(arr, "value1"); + celix_arrayList_addString(arr, "value2"); + celix_properties_assignArrayList(props, "key", arr); + + // When an error injected is prepared for json_array() from celix_properties_saveToString + celix_ei_expect_json_array((void*)celix_properties_saveToString, 4, nullptr); + + // And I call celix_properties_saveToString + char* out = nullptr; + auto status = celix_properties_saveToString(props, 0, &out); + + // Then I expect an error + EXPECT_EQ(ENOMEM, status); + + + //When an error injected is prepared for json_array_append_new() from loadFromString2 + celix_ei_expect_json_array_append_new((void*)celix_properties_saveToString, 4, -1); + + //And I call celix_properties_saveToString + status = celix_properties_saveToString(props, 0, &out); + + //Then I expect an error + EXPECT_EQ(ENOMEM, status); + + //When an error injected is prepared for json_string() from loadFromString2 + celix_ei_expect_json_string((void*)celix_properties_saveToString, 5, nullptr); + + //And I call celix_properties_saveToString + status = celix_properties_saveToString(props, 0, &out); + + //Then I expect an error + EXPECT_EQ(ENOMEM, status); + + // And I expect 3 error message in celix_err + EXPECT_EQ(3, celix_err_getErrorCount()); + celix_err_printErrors(stderr, "Test Error: ", "\n"); +} + +TEST_F(PropertiesEncodingErrorInjectionTestSuite, EncodeVersionErrorTest) { + // Given a dummy properties object with a version + celix_autoptr(celix_properties_t) props = celix_properties_create(); + auto* version = celix_version_create(1, 2, 3, "qualifier"); + celix_properties_assignVersion(props, "key", version); + + // When an error injected is prepared for json_sprintf() from celix_properties_saveToString + celix_ei_expect_json_sprintf((void*)celix_properties_saveToString, 4, nullptr); + + // And I call celix_properties_saveToString + char* out = nullptr; + auto status = celix_properties_saveToString(props, 0, &out); + + // Then I expect an error + EXPECT_EQ(ENOMEM, status); + + // When an error injected is prepared for celix_version_toString() from celix_properties_saveToString + celix_ei_expect_celix_version_toString((void*)celix_properties_saveToString, 4, nullptr); + + // And I call celix_properties_saveToString + status = celix_properties_saveToString(props, 0, &out); + + // Then I expect an error + EXPECT_EQ(ENOMEM, status); + + // And I expect 2 error message in celix_err + EXPECT_EQ(2, celix_err_getErrorCount()); + celix_err_printErrors(stderr, "Test Error: ", "\n"); +} + +TEST_F(PropertiesEncodingErrorInjectionTestSuite, LoadErrorTest) { + //Given a dummy json string + const char* json = R"({"key":"value"})"; + + //When an error injected is prepared for fmemopen() from loadFromString2 + celix_ei_expect_fmemopen((void*)celix_properties_loadFromString2, 0, nullptr); + + //When I call celix_properties_loadFromString + celix_properties_t* props; + auto status = celix_properties_loadFromString2(json, 0, &props); + + //Then I expect an error + EXPECT_EQ(ENOMEM, status); + + //And I expect 1 error message in celix_err + EXPECT_EQ(1, celix_err_getErrorCount()); + celix_err_printErrors(stderr, "Test Error: ", "\n"); +} + +TEST_F(PropertiesEncodingErrorInjectionTestSuite, DecodeErrorTest) { + //Given a dummy json string + const char* json = R"({"key":"value", "object": {"key":"value"}})"; + + //When an error injected is prepared for celix_properties_create()->malloc() from celix_properties_loadFromString2 + celix_ei_expect_malloc((void*)celix_properties_loadFromString2, 3, nullptr); + + //When I call celix_properties_loadFromString + celix_properties_t* props; + auto status = celix_properties_loadFromString2(json, 0, &props); + + //Then I expect an error + EXPECT_EQ(ENOMEM, status); + + //When an error injected is prepared for celix_utils_writeOrCreateString() from celix_properties_loadFromString2 + celix_ei_expect_celix_utils_writeOrCreateString((void*)celix_properties_loadFromString2, 3, nullptr); + + //When I call celix_properties_loadFromString + status = celix_properties_loadFromString2(json, 0, &props); + + //Then I expect an error + EXPECT_EQ(ENOMEM, status); + + //And I expect 2 error message in celix_err + EXPECT_EQ(2, celix_err_getErrorCount()); + celix_err_printErrors(stderr, "Test Error: ", "\n"); +} + +TEST_F(PropertiesEncodingErrorInjectionTestSuite, DecodeArrayErrorTest) { + //Given a dummy json string + const char* json = R"({"key":["value1", "value2"]})"; + + // When an error injected is prepared for celix_arrayList_createWithOptions() from celix_properties_loadFromString2 + celix_ei_expect_celix_arrayList_createWithOptions((void*)celix_properties_loadFromString2, 4, nullptr); + + //When I call celix_properties_loadFromString + celix_properties_t* props; + auto status = celix_properties_loadFromString2(json, 0, &props); + + //Then I expect an error + EXPECT_EQ(ENOMEM, status); + + // When an error injected is prepared for celix_arrayList_addString() from celix_properties_loadFromString2 + celix_ei_expect_celix_arrayList_addString((void*)celix_properties_loadFromString2, 4, ENOMEM); + + //When I call celix_properties_loadFromString + status = celix_properties_loadFromString2(json, 0, &props); + + //Then I expect an error + EXPECT_EQ(ENOMEM, status); + + // And I expect 0 error message in celix_err. Note because errors are injected for celix_array_list_t, celix_err is + // not used + EXPECT_EQ(0, celix_err_getErrorCount()); + celix_err_printErrors(stderr, "Test Error: ", "\n"); +} + +TEST_F(PropertiesEncodingErrorInjectionTestSuite, DecodeVersionErrorTest) { + // Given a dummy json version string + const char* json = R"({"key":"version<1.2.3.qualifier>"})"; + + // When an error injected is prepared for celix_utils_writeOrCreateString() from celix_properties_loadFromString2 + celix_ei_expect_celix_utils_writeOrCreateString((void*)celix_properties_loadFromString2, 4, nullptr); + + // And I call celix_properties_loadFromString + celix_properties_t* props; + auto status = celix_properties_loadFromString2(json, 0, &props); + + // Then I expect an error + EXPECT_EQ(ENOMEM, status); + + // And I expect 1 error message in celix_err + EXPECT_EQ(1, celix_err_getErrorCount()); + celix_err_printErrors(stderr, "Test Error: ", "\n"); +} diff --git a/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc b/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc index b854e183..bece2147 100644 --- a/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc +++ b/libs/utils/gtest/src/PropertiesEncodingTestSuite.cc @@ -17,16 +17,14 @@ * under the License. */ -#include <cmath> #include <gtest/gtest.h> +#include <cmath> #include <jansson.h> #include "celix_err.h" #include "celix_properties.h" #include "celix_stdlib_cleanup.h" -using ::testing::MatchesRegex; - class PropertiesSerializationTestSuite : public ::testing::Test { public: PropertiesSerializationTestSuite() { celix_err_resetErrors(); } @@ -189,7 +187,7 @@ TEST_F(PropertiesSerializationTestSuite, SaveEmptyArrayTest) { //And at least one error message is added to celix_err EXPECT_GE(celix_err_getErrorCount(), 1); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); } TEST_F(PropertiesSerializationTestSuite, SaveJPathKeysTest) { @@ -349,7 +347,7 @@ TEST_F(PropertiesSerializationTestSuite, SavePropertiesWithKeyCollision) { //And at least one error message is added to celix_err EXPECT_GE(celix_err_getErrorCount(), 1); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); } TEST_F(PropertiesSerializationTestSuite, SavePropertiesWithAndWithoutStrictFlagTest) { @@ -373,7 +371,7 @@ TEST_F(PropertiesSerializationTestSuite, SavePropertiesWithAndWithoutStrictFlagT //And at least one error message is added to celix_err EXPECT_GE(celix_err_getErrorCount(), 1); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); } TEST_F(PropertiesSerializationTestSuite, SavePropertiesWithPrettyPrintTest) { @@ -410,7 +408,7 @@ TEST_F(PropertiesSerializationTestSuite, SaveWithInvalidStreamTest) { EXPECT_EQ(2, celix_err_getErrorCount()); fclose(readStream); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); } TEST_F(PropertiesSerializationTestSuite, LoadEmptyPropertiesTest) { @@ -563,11 +561,11 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithInvalidInputTest) { auto status = celix_properties_loadFromStream(stream, 0, &props); //Then loading fails - EXPECT_EQ(CELIX_ILLEGAL_ARGUMENT, status); + EXPECT_NE(CELIX_SUCCESS, status); //And at least one error message is added to celix_err EXPECT_GE(celix_err_getErrorCount(), 1); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); fclose(stream); } @@ -661,7 +659,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithDuplicatesTest) { // And at least one error message is added to celix_err EXPECT_GE(celix_err_getErrorCount(), 1); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); } TEST_F(PropertiesSerializationTestSuite, LoadPropertiesEscapedSlashesTest) { @@ -713,7 +711,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesEscapedSlashesTest) { // And at least one error message is added to celix_err EXPECT_GE(celix_err_getErrorCount(), 1); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); // When decoding the properties from a string using a flag that allows collisions celix_autoptr(celix_properties_t) props3 = nullptr; @@ -724,7 +722,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesEscapedSlashesTest) { // And at least one error message is added to celix_err EXPECT_GE(celix_err_getErrorCount(), 1); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); } TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithAndWithoutStrictFlagTest) { @@ -770,7 +768,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithAndWithoutStrictFlagT //And at least one error message is added to celix_err EXPECT_GE(celix_err_getErrorCount(), 1); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); fclose(stream); } @@ -795,7 +793,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithSlashesInTheKeysTest) // When loading the properties from the stream celix_autoptr(celix_properties_t) props = nullptr; auto status = celix_properties_loadFromStream(stream, 0, &props); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); ASSERT_EQ(CELIX_SUCCESS, status); // Then the properties object contains the nested objects @@ -821,7 +819,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadPropertiesWithInvalidVersionsTest) // And at least one error message is added to celix_err EXPECT_GE(celix_err_getErrorCount(), 1); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); // Given a JSON object with an invalid version strings, that are not recognized as versions jsonInput = @@ -857,7 +855,7 @@ TEST_F(PropertiesSerializationTestSuite, LoadWithInvalidStreamTest) { fclose(stream); free(buf); - celix_err_printErrors(stderr, "Error: ", "\n"); + celix_err_printErrors(stderr, "Test Error: ", "\n"); } TEST_F(PropertiesSerializationTestSuite, SaveAndLoadFlatProperties) { diff --git a/libs/utils/src/properties.c b/libs/utils/src/properties.c index 024d849d..10787e23 100644 --- a/libs/utils/src/properties.c +++ b/libs/utils/src/properties.c @@ -334,6 +334,8 @@ celix_properties_t* celix_properties_create() { free(props); props = NULL; } + } else { + celix_err_push("Cannot allocate memory for properties"); } return props; } @@ -451,7 +453,6 @@ celix_properties_t* celix_properties_loadWithStream(FILE* file) { celix_autoptr(celix_properties_t) props = celix_properties_create(); if (!props) { - celix_err_push("Failed to create properties"); return NULL; } diff --git a/libs/utils/src/properties_encoding.c b/libs/utils/src/properties_encoding.c index 087590f7..0b5f189c 100644 --- a/libs/utils/src/properties_encoding.c +++ b/libs/utils/src/properties_encoding.c @@ -35,12 +35,12 @@ static celix_status_t celix_properties_versionToJson(const celix_version_t* vers celix_autofree char* versionStr = celix_version_toString(version); if (!versionStr) { celix_err_push("Failed to create version string."); - return CELIX_ENOMEM; + return ENOMEM; } *out = json_sprintf("version<%s>", versionStr); if (!*out) { celix_err_push("Failed to create json string."); - return CELIX_ENOMEM; + return ENOMEM; } return CELIX_SUCCESS; } @@ -72,7 +72,7 @@ static celix_status_t celix_properties_arrayElementEntryValueToJson(celix_array_ } if (!*out) { celix_err_push("Failed to create json value."); - return CELIX_ENOMEM; + return ENOMEM; } return CELIX_SUCCESS; } @@ -90,10 +90,10 @@ static celix_status_t celix_properties_arrayEntryValueToJson(const char* key, return CELIX_SUCCESS; // empty array -> treat as unset property } - json_t* array = json_array(); + json_auto_t* array = json_array(); if (!array) { celix_err_push("Failed to create json array."); - return CELIX_ENOMEM; + return ENOMEM; } for (int i = 0; i < celix_arrayList_size(entry->typed.arrayValue); ++i) { @@ -102,7 +102,6 @@ static celix_status_t celix_properties_arrayEntryValueToJson(const char* key, json_t* jsonValue; celix_status_t status = celix_properties_arrayElementEntryValueToJson(elType, arrayEntry, &jsonValue); if (status != CELIX_SUCCESS) { - json_decref(array); return status; } else if (!jsonValue) { // ignore unset values @@ -110,13 +109,12 @@ static celix_status_t celix_properties_arrayEntryValueToJson(const char* key, int rc = json_array_append_new(array, jsonValue); if (rc != 0) { celix_err_push("Failed to append json string to array."); - json_decref(array); - return CELIX_ENOMEM; + return ENOMEM; } } } - *out = array; + *out = celix_steal_ptr(array); return CELIX_SUCCESS; } @@ -146,14 +144,14 @@ celix_properties_entryValueToJson(const char* key, const celix_properties_entry_ return celix_properties_arrayEntryValueToJson(key, entry, flags, out); default: // LCOV_EXCL_START - celix_err_pushf("Invalid properties entry type %d.", entry->valueType); + celix_err_pushf("Unexpected properties entry type %d.", entry->valueType); return CELIX_ILLEGAL_ARGUMENT; // LCOV_EXCL_STOP } if (!*out) { celix_err_pushf("Failed to create json value for key '%s'.", key); - return CELIX_ENOMEM; + return ENOMEM; } return CELIX_SUCCESS; } @@ -175,7 +173,7 @@ static celix_status_t celix_properties_addJsonValueToJson(json_t* value, const c int rc = json_object_set_new(obj, key, value); if (rc != 0) { celix_err_push("Failed to set json object"); - return CELIX_ENOMEM; + return ENOMEM; } return CELIX_SUCCESS; } @@ -205,7 +203,7 @@ static celix_status_t celix_properties_addPropertiesEntryToJson(const celix_prop celix_auto(celix_utils_string_guard_t) strGuard = celix_utils_stringGuard_init(buf, name); if (!name) { celix_err_push("Failed to create name string"); - return CELIX_ENOMEM; + return ENOMEM; } json_t* subObj = json_object_get(jsonObj, name); if (!subObj || !json_is_object(subObj)) { @@ -216,12 +214,12 @@ static celix_status_t celix_properties_addPropertiesEntryToJson(const celix_prop subObj = json_object(); if (!subObj) { celix_err_push("Failed to create json object"); - return CELIX_ENOMEM; + return ENOMEM; } int rc = json_object_set_new(jsonObj, name, subObj); if (rc != 0) { celix_err_push("Failed to set json object"); - return CELIX_ENOMEM; + return ENOMEM; } } @@ -242,6 +240,7 @@ celix_status_t celix_properties_saveToStream(const celix_properties_t* propertie json_t* root = json_object(); if (!root) { celix_err_push("Failed to create json object"); + return ENOMEM; } if (!(encodeFlags & CELIX_PROPERTIES_ENCODE_FLAT) && !(encodeFlags & CELIX_PROPERTIES_ENCODE_NESTED)) { @@ -295,7 +294,7 @@ celix_status_t celix_properties_saveToString(const celix_properties_t* propertie FILE* stream = open_memstream(&buffer, &size); if (!stream) { celix_err_push("Failed to open memstream."); - return CELIX_FILE_IO_EXCEPTION; + return ENOMEM; } celix_status_t status = celix_properties_saveToStream(properties, stream, encodeFlags); @@ -310,13 +309,13 @@ static celix_status_t celix_properties_parseVersion(const char* value, celix_ver // precondition: value is a valid version string (8 chars prefix and 1 char suffix) *out = NULL;; char buf[32]; - char* corrected = celix_utils_writeOrCreateString(buf, sizeof(buf), "%.*s", (int)strlen(value) - 9, value + 8); - celix_auto(celix_utils_string_guard_t) guard = celix_utils_stringGuard_init(buf, corrected); - if (!corrected) { - celix_err_push("Failed to create corrected version string."); + char* extracted = celix_utils_writeOrCreateString(buf, sizeof(buf), "%.*s", (int)strlen(value) - 9, value + 8); + celix_auto(celix_utils_string_guard_t) guard = celix_utils_stringGuard_init(buf, extracted); + if (!extracted) { + celix_err_push("Failed to create extracted version string."); return ENOMEM; } - celix_status_t status = celix_version_parse(corrected, out); + celix_status_t status = celix_version_parse(extracted, out); if (status != CELIX_SUCCESS) { celix_err_push("Failed to parse version string."); return status; @@ -412,7 +411,7 @@ celix_properties_decodeArray(celix_properties_t* props, const char* key, const j opts.elementType = elType; celix_autoptr(celix_array_list_t) array = celix_arrayList_createWithOptions(&opts); if (!array) { - return CELIX_ENOMEM; + return ENOMEM; } json_t* value; @@ -439,7 +438,7 @@ celix_properties_decodeArray(celix_properties_t* props, const char* key, const j } default: // LCOV_EXCL_START - celix_err_pushf("Invalid array list element type %d for key %s.", elType, key); + celix_err_pushf("Unexpected array list element type %d for key %s.", elType, key); return CELIX_ILLEGAL_ARGUMENT; // LCOV_EXCL_STOP } @@ -488,7 +487,7 @@ celix_properties_decodeValue(celix_properties_t* props, const char* key, json_t* celix_auto(celix_utils_string_guard_t) strGuard = celix_utils_stringGuard_init(buf, combinedKey); if (!combinedKey) { celix_err_push("Failed to create sub key."); - return CELIX_ENOMEM; + return ENOMEM; } status = celix_properties_decodeValue(props, combinedKey, fieldValue, flags); if (status != CELIX_SUCCESS) { @@ -514,7 +513,7 @@ celix_properties_decodeValue(celix_properties_t* props, const char* key, json_t* return CELIX_SUCCESS; } else { // LCOV_EXCL_START - celix_err_pushf("Invalid json value type for key '%s'.", key); + celix_err_pushf("Unexpected json value type for key '%s'.", key); return CELIX_ILLEGAL_ARGUMENT; // LCOV_EXCL_STOP } @@ -529,7 +528,7 @@ static celix_status_t celix_properties_decodeFromJson(json_t* obj, int flags, ce celix_autoptr(celix_properties_t) props = celix_properties_create(); if (!props) { - return CELIX_ENOMEM; + return ENOMEM; } const char* key; @@ -574,7 +573,7 @@ celix_status_t celix_properties_loadFromString2(const char* input, int decodeFla FILE* stream = fmemopen((void*)input, strlen(input), "r"); if (!stream) { celix_err_push("Failed to open memstream."); - return CELIX_FILE_IO_EXCEPTION; + return ENOMEM; } celix_status_t status = celix_properties_loadFromStream(stream, decodeFlags, out); fclose(stream);