blob: 2ff3ff66c891c7e6472e3d3520b9b69442d95398 [file] [log] [blame]
/*
* 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 <string>
#include "celix/Properties.h"
#include "celix_cleanup.h"
#include "celix_convert_utils.h"
#include "celix_err.h"
#include "celix_properties.h"
#include "celix_properties_private.h"
#include "celix_utils_private_constants.h"
#include "celix_version.h"
#include "asprintf_ei.h"
#include "celix_array_list_ei.h"
#include "celix_string_hash_map_ei.h"
#include "celix_utils_ei.h"
#include "celix_version_ei.h"
#include "malloc_ei.h"
#include "stdio_ei.h"
class PropertiesErrorInjectionTestSuite : public ::testing::Test {
public:
PropertiesErrorInjectionTestSuite() = default;
~PropertiesErrorInjectionTestSuite() override {
celix_err_resetErrors();
celix_ei_expect_open_memstream(nullptr, 0, nullptr);
celix_ei_expect_asprintf(nullptr, 0, -1);
celix_ei_expect_malloc(nullptr, 0, nullptr);
celix_ei_expect_calloc(nullptr, 0, nullptr);
celix_ei_expect_celix_stringHashMap_createWithOptions(nullptr, 0, nullptr);
celix_ei_expect_celix_arrayList_copy(nullptr, 0, nullptr);
celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr);
celix_ei_expect_celix_stringHashMap_put(nullptr, 0, 0);
celix_ei_expect_celix_version_copy(nullptr, 0, nullptr);
celix_ei_expect_celix_arrayList_copy(nullptr, 0, nullptr);
}
/**
* Fills the optimization cache of the given properties object to ensure the next added entries will need
* allocation.
*/
void fillOptimizationCache(celix_properties_t* props) {
int index = 0;
size_t written = 0;
size_t nrOfEntries = 0;
while (written < CELIX_PROPERTIES_OPTIMIZATION_STRING_BUFFER_SIZE ||
nrOfEntries++ < CELIX_PROPERTIES_OPTIMIZATION_ENTRIES_BUFFER_SIZE) {
const char* val = "1234567890";
char key[10];
snprintf(key, sizeof(key), "key%i", index++);
written += strlen(key) + strlen(val) + 2;
celix_properties_set(props, key, val);
}
}
};
TEST_F(PropertiesErrorInjectionTestSuite, CreateFailureTest) {
// C API
celix_ei_expect_malloc((void*)celix_properties_create, 0, nullptr);
ASSERT_EQ(nullptr, celix_properties_create());
// C++ API
celix_ei_expect_malloc((void*)celix_properties_create, 0, nullptr);
ASSERT_THROW(celix::Properties(), std::bad_alloc);
}
TEST_F(PropertiesErrorInjectionTestSuite, CopyFailureTest) {
// C API
//Given a celix properties object with more entries than the optimization cache
celix_autoptr(celix_properties_t) prop = celix_properties_create();
ASSERT_NE(nullptr, prop);
fillOptimizationCache(prop);
celix_properties_set(prop, "additionalKey", "value");
// When a hash map create error injection is set for celix_properties_create
celix_ei_expect_celix_stringHashMap_createWithOptions((void*)celix_properties_create, 0, nullptr);
// Then the celix_properties_copy call fails
ASSERT_EQ(nullptr, celix_properties_copy(prop));
ASSERT_EQ(1, celix_err_getErrorCount());
celix_err_resetErrors();
// When a malloc error injection is set for celix_properties_allocEntry (during set)
celix_ei_expect_malloc((void*)celix_properties_allocEntry, 0, nullptr);
// Then the celix_properties_copy call fails
ASSERT_EQ(nullptr, celix_properties_copy(prop));
ASSERT_GE(celix_err_getErrorCount(), 1);
celix_err_resetErrors();
// C++ API
const celix::Properties cxxProp{};
celix_ei_expect_celix_stringHashMap_createWithOptions((void*)celix_properties_create, 0, nullptr);
ASSERT_THROW(celix::Properties{cxxProp}, std::bad_alloc);
}
TEST_F(PropertiesErrorInjectionTestSuite, SetFailureTest) {
// C API
// Given a celix properties object with a filled optimization cache
celix_autoptr(celix_properties_t) props = celix_properties_create();
fillOptimizationCache(props);
// When a malloc error injection is set for celix_properties_allocEntry (during set)
celix_ei_expect_malloc((void*)celix_properties_allocEntry, 0, nullptr);
// Then the celix_properties_set call fails
ASSERT_EQ(celix_properties_set(props, "key", "value"), CELIX_ENOMEM);
// When a celix_utils_strdup error injection is set for celix_properties_set (during strdup key)
celix_ei_expect_celix_utils_strdup((void*)celix_properties_createString, 0, nullptr);
// Then the celix_properties_set call fails
ASSERT_EQ(celix_properties_set(props, "key", "value"), CELIX_ENOMEM);
// When a celix_stringHashMap_put error injection is set for celix_properties_set with level 1 (during put)
celix_ei_expect_celix_stringHashMap_put((void*)celix_properties_set, 2, CELIX_ENOMEM);
// Then the celix_properties_set call fails
ASSERT_EQ(celix_properties_set(props, "key", "value"), CELIX_ENOMEM);
// When a celix_utils_strdup error injection is when calling celix_properties_set, for the creation of the
// key string.
celix_ei_expect_celix_utils_strdup((void*)celix_properties_createString, 0, nullptr, 2);
// Then the celix_properties_set call fails
ASSERT_EQ(celix_properties_set(props, "key", "value"), CELIX_ENOMEM);
celix_ei_expect_celix_utils_strdup((void*)celix_properties_createString, 0, nullptr);
ASSERT_EQ(CELIX_ENOMEM, celix_properties_setLong(props, "key", 1000));
celix_ei_expect_celix_utils_strdup((void*)celix_properties_createString, 0, nullptr);
ASSERT_EQ(CELIX_ENOMEM, celix_properties_setDouble(props, "key", 1.2));
double largeNumber = 123456789012345.0;
celix_ei_expect_asprintf((void*)celix_properties_setDouble, 3, -1);
ASSERT_EQ(CELIX_ENOMEM, celix_properties_setDouble(props, "key", largeNumber));
celix_autoptr(celix_array_list_t) list = celix_arrayList_createLongArray();
celix_ei_expect_open_memstream((void*)celix_utils_arrayListToString, 1, nullptr);
ASSERT_EQ(CELIX_ENOMEM, celix_properties_setArrayList(props, "key", list));
// C++ API
// Given a celix properties object with a filled optimization cache
celix::Properties cxxProps{};
for (int i = 0; i < 50; ++i) {
const char* val = "1234567890";
char key[10];
snprintf(key, sizeof(key), "key%i", i);
cxxProps.set(key, val);
}
// When a malloc error injection is set for celix_properties_set (during alloc entry)
celix_ei_expect_malloc((void*)celix_properties_allocEntry, 0, nullptr);
// Then the Properties:set throws a bad_alloc exception
ASSERT_THROW(cxxProps.set("key", "value"), std::bad_alloc);
}
TEST_F(PropertiesErrorInjectionTestSuite, GetAsVersionWithVersionCopyFailedTest) {
//Given a properties set with a version
celix_autoptr(celix_properties_t) props = celix_properties_create();
celix_version_t* v = celix_version_create(1, 2, 3, "qualifier");
celix_properties_assignVersion(props, "key", v);
// When a celix_version_copy error injection is set for celix_properties_getAsVersion
celix_ei_expect_celix_version_copy((void*)celix_properties_getAsVersion, 0, nullptr);
// Then the celix_properties_getAsVersion call fails
celix_version_t* version = nullptr;
auto status = celix_properties_getAsVersion(props, "key", nullptr, &version);
ASSERT_EQ(status, CELIX_ENOMEM);
ASSERT_EQ(nullptr, version);
}
TEST_F(PropertiesErrorInjectionTestSuite, GetAsArrayWithArrayListCopyFailedTest) {
//Given a properties set with a string array, long array, double array, bool array and version array
const char* str1 = "string1";
const char* str2 = "string2";
celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray();
celix_arrayList_addString(stringList, str1);
celix_arrayList_addString(stringList, str2);
celix_autoptr(celix_array_list_t) longList = celix_arrayList_createLongArray();
celix_arrayList_addLong(longList, 1);
celix_arrayList_addLong(longList, 2);
celix_autoptr(celix_array_list_t) doubleList = celix_arrayList_createDoubleArray();
celix_arrayList_addDouble(doubleList, 1.1);
celix_arrayList_addDouble(doubleList, 2.2);
celix_autoptr(celix_array_list_t) boolList = celix_arrayList_createBoolArray();
celix_arrayList_addBool(boolList, true);
celix_arrayList_addBool(boolList, false);
celix_autoptr(celix_version_t) v = celix_version_create(1, 2, 3, "qualifier");
celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray();
celix_arrayList_addVersion(versionList, v);
celix_arrayList_addVersion(versionList, v);
celix_autoptr(celix_properties_t) props = celix_properties_create();
celix_properties_setArrayList(props, "stringArray", stringList);
celix_properties_setArrayList(props, "longArray", longList);
celix_properties_setArrayList(props, "doubleArray", doubleList);
celix_properties_setArrayList(props, "boolArray", boolList);
celix_properties_setArrayList(props, "versionArray", versionList);
celix_properties_setString(props, "string", "Hello world");
// When a celix_arrayList_createWithOptions error injection is set for celix_properties_getAsStringArrayList
celix_ei_expect_celix_arrayList_copy((void*)celix_properties_getAsStringArrayList, 1, nullptr);
// Then the celix_properties_getAsStringArrayList call fails
celix_array_list_t* strings = nullptr;
auto status = celix_properties_getAsStringArrayList(props, "stringArray", nullptr, &strings);
ASSERT_EQ(status, CELIX_ENOMEM);
ASSERT_EQ(nullptr, strings);
//When a celix_arrayList_copy error injection is set for celix_properties_getAsLongArrayList
celix_ei_expect_celix_arrayList_copy((void*)celix_properties_getAsLongArrayList, 1, nullptr);
// Then the celix_properties_getAsLongArrayList call fails
celix_array_list_t* longs = nullptr;
status = celix_properties_getAsLongArrayList(props, "longArray", nullptr, &longs);
ASSERT_EQ(status, CELIX_ENOMEM);
ASSERT_EQ(nullptr, longs);
//When a celix_arrayList_copy error injection is set for celix_properties_getAsDoubleArrayList
celix_ei_expect_celix_arrayList_copy((void*)celix_properties_getAsDoubleArrayList, 1, nullptr);
// Then the celix_properties_getAsDoubleArrayList call fails
celix_array_list_t* doubles = nullptr;
status = celix_properties_getAsDoubleArrayList(props, "doubleArray", nullptr, &doubles);
ASSERT_EQ(status, CELIX_ENOMEM);
ASSERT_EQ(nullptr, doubles);
//When a celix_arrayList_copy error injection is set for celix_properties_getAsBoolArrayList
celix_ei_expect_celix_arrayList_copy((void*)celix_properties_getAsBoolArrayList, 1, nullptr);
// Then the celix_properties_getAsBoolArrayList call fails
celix_array_list_t* bools = nullptr;
status = celix_properties_getAsBoolArrayList(props, "boolArray", nullptr, &bools);
ASSERT_EQ(status, CELIX_ENOMEM);
ASSERT_EQ(nullptr, bools);
//When a celix_arrayList_createWithOptions error injection is set for celix_properties_getAsVersionArrayList
celix_ei_expect_celix_arrayList_copy((void*)celix_properties_getAsVersionArrayList, 1, nullptr);
// Then the celix_properties_getAsVersionArrayList call fails
celix_array_list_t* versions = nullptr;
status = celix_properties_getAsVersionArrayList(props, "versionArray", nullptr, &versions);
ASSERT_EQ(status, CELIX_ENOMEM);
ASSERT_EQ(nullptr, versions);
celix_ei_expect_open_memstream((void*)celix_utils_convertStringToVersionArrayList, 1, nullptr);
versions = nullptr;
status = celix_properties_getAsVersionArrayList(props, "string", nullptr, &versions);
ASSERT_EQ(status, CELIX_ENOMEM);
ASSERT_EQ(nullptr, versions);
}
TEST_F(PropertiesErrorInjectionTestSuite, SetArrayWithArrayListCopyFailedTest) {
//Given a properties set
celix_autoptr(celix_properties_t) props = celix_properties_create();
//And a (empty) array list
celix_autoptr(celix_array_list_t) list = celix_arrayList_createLongArray();
// When a celix_arrayList_copy error injection is set for celix_properties_setArrayList
celix_ei_expect_celix_arrayList_copy((void*)celix_properties_setArrayList, 0, nullptr);
// Then the celix_properties_setArrayList call fails
EXPECT_EQ(CELIX_ENOMEM, celix_properties_setArrayList(props, "longArray", list));
}
TEST_F(PropertiesErrorInjectionTestSuite, AssignFailureTest) {
//Given a filled properties and a key and value
celix_autoptr(celix_properties_t) props = celix_properties_create();
fillOptimizationCache(props);
char* key = celix_utils_strdup("key");
char* val = celix_utils_strdup("value");
// When a malloc error injection is set for celix_properties_setWithoutCopy (during alloc entry)
celix_ei_expect_malloc((void*)celix_properties_allocEntry, 0, nullptr);
// Then the celix_properties_setWithoutCopy call fails
auto status = celix_properties_assign(props, key, val);
ASSERT_EQ(status, CELIX_ENOMEM);
// And a celix err msg is set
ASSERT_EQ(1, celix_err_getErrorCount());
celix_err_resetErrors();
//Given an allocated key and valu
key = celix_utils_strdup("key");
val = celix_utils_strdup("value");
// When a celix_stringHashMap_put error injection is set for celix_properties_setWithoutCopy
celix_ei_expect_celix_stringHashMap_put((void*)celix_properties_assign, 0, CELIX_ENOMEM);
// Then the celix_properties_setWithoutCopy call fails
status = celix_properties_assign(props, key, val);
ASSERT_EQ(status, CELIX_ENOMEM);
// And a celix err msg is set
ASSERT_EQ(1, celix_err_getErrorCount());
celix_err_resetErrors();
}
TEST_F(PropertiesErrorInjectionTestSuite, SetVersionFailureTest) {
// Given a celix properties object
celix_autoptr(celix_properties_t) props = celix_properties_create();
// And a version object
celix_autoptr(celix_version_t) version = celix_version_create(1, 2, 3, "qualifier");
// When a celix_version_copy error injection is set for celix_properties_setVersion
celix_ei_expect_celix_version_copy((void*)celix_properties_setVersion, 0, nullptr);
// Then the celix_properties_setVersion call fails
auto status = celix_properties_setVersion(props, "key", version);
ASSERT_EQ(status, CELIX_ENOMEM);
//And a celix err msg is pushed
ASSERT_EQ(1, celix_err_getErrorCount());
celix_err_resetErrors();
celix_autoptr(celix_version_t) version2 = celix_version_create(1, 2, 3, "aaaaaaaaaaaaaaaaaaaaaaaaaa");
celix_ei_expect_calloc((void*) celix_version_create, 0, nullptr);
status = celix_properties_setVersion(props, "key", version2);
ASSERT_EQ(status, CELIX_ENOMEM);
EXPECT_EQ(2, celix_err_getErrorCount());
ASSERT_STREQ("Failed to copy version", celix_err_popLastError());
ASSERT_STREQ("Failed to allocate memory for celix_version_create", celix_err_popLastError());
celix_err_resetErrors();
fillOptimizationCache(props);
celix_ei_expect_celix_utils_strdup((void*)celix_properties_createString, 0, nullptr);
status = celix_properties_setVersion(props, "key1", version);
ASSERT_EQ(status, CELIX_ENOMEM);
//And a celix err msg is pushed
ASSERT_EQ(1, celix_err_getErrorCount());
celix_err_resetErrors();
}