Skip to content

Commit

Permalink
#674 Add add/assign nullptr test for array list
Browse files Browse the repository at this point in the history
  • Loading branch information
pnoltes committed Feb 7, 2024
1 parent 2105123 commit 5097e48
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 40 deletions.
26 changes: 23 additions & 3 deletions libs/utils/gtest/src/ArrayListErrorInjectionTestSuite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include <gtest/gtest.h>

#include "celix_array_list.h"
#include "celix_array_list_ei.h"
#include "celix_err.h"
#include "celix_utils_ei.h"
#include "celix_version_ei.h"
Expand All @@ -34,10 +33,28 @@ class ArrayListErrorInjectionTestSuite : public ::testing::Test {
celix_ei_expect_calloc(nullptr, 0, nullptr);
celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr);
celix_ei_expect_celix_version_copy(nullptr, 0, nullptr);
celix_err_resetErrors();
}
};

TEST_F(ArrayListErrorInjectionTestSuite, TestAddFunctions) {
TEST_F(ArrayListErrorInjectionTestSuite, CreateTest) {
//Given an error is injected for calloc (used for the array struct)
celix_ei_expect_calloc(CELIX_EI_UNKNOWN_CALLER, 1, nullptr);
//Then creating an array list should fail
EXPECT_EQ(nullptr, celix_arrayList_create());
//And an error is logged to the celix_err
EXPECT_EQ(1, celix_err_getErrorCount());

//Given an error is injected for malloc (used for the element data)
celix_ei_expect_malloc(CELIX_EI_UNKNOWN_CALLER, 0, nullptr);
//Then creating an array list should fail
EXPECT_EQ(nullptr, celix_arrayList_create());
//And an error is logged to the celix_err
EXPECT_EQ(2, celix_err_getErrorCount());
}


TEST_F(ArrayListErrorInjectionTestSuite, AddFunctionsTest) {
//Given an array list with a capacity of 10 (whitebox knowledge)
auto* list = celix_arrayList_create();

Expand All @@ -53,6 +70,8 @@ TEST_F(ArrayListErrorInjectionTestSuite, TestAddFunctions) {
//Then adding an element should fail
EXPECT_EQ(CELIX_ENOMEM, celix_arrayList_addInt(list, 10));
EXPECT_EQ(10, celix_arrayList_size(list));
//And an error is logged to the celix_err
EXPECT_EQ(1, celix_err_getErrorCount());

celix_arrayList_destroy(list);
}
Expand All @@ -70,7 +89,8 @@ TEST_F(ArrayListErrorInjectionTestSuite, AddStringAndAddVersionFailureTest) {
// When an error is injected for celix_version_copy
celix_ei_expect_celix_version_copy((void*)celix_arrayList_addVersion, 0, nullptr);
// Then adding a version should fail
EXPECT_EQ(CELIX_ENOMEM, celix_arrayList_addVersion(versionList, NULL));
celix_autoptr(celix_version_t) version = celix_version_createVersionFromString("1.0.0");
EXPECT_EQ(CELIX_ENOMEM, celix_arrayList_addVersion(versionList, version));
}

TEST_F(ArrayListErrorInjectionTestSuite, CopyArrayListFailureTest) {
Expand Down
64 changes: 64 additions & 0 deletions libs/utils/gtest/src/ArrayListTestSuite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -528,3 +528,67 @@ TEST_F(ArrayListTestSuite, AutoCleanupTest) {
celix_autoptr(celix_array_list_t) list = celix_arrayList_create();
EXPECT_NE(nullptr, list);
}

TEST_F(ArrayListTestSuite, AddNullTest) {
// Given an undefined type, string, string ref and version list
celix_autoptr(celix_array_list_t) list = celix_arrayList_create();
celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray();
celix_autoptr(celix_array_list_t) stringRefList = celix_arrayList_createStringRefArray();
celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray();

// When adding a null value to the lists
celix_arrayList_add(list, nullptr);
celix_arrayList_addString(stringList, nullptr);
celix_arrayList_addString(stringRefList, nullptr);
celix_arrayList_addVersion(versionList, nullptr);

// Then the lists contain the null value
EXPECT_EQ(1, celix_arrayList_size(list));
EXPECT_EQ(nullptr, celix_arrayList_get(list, 0));
EXPECT_EQ(1, celix_arrayList_size(stringList));
EXPECT_EQ(nullptr, celix_arrayList_getString(stringList, 0));
EXPECT_EQ(1, celix_arrayList_size(stringRefList));
EXPECT_EQ(nullptr, celix_arrayList_getString(stringRefList, 0));
EXPECT_EQ(1, celix_arrayList_size(versionList));
EXPECT_EQ(nullptr, celix_arrayList_getVersion(versionList, 0));

// When copying the lists
celix_autoptr(celix_array_list_t) listCopy = celix_arrayList_copy(list);
celix_autoptr(celix_array_list_t) stringListCopy = celix_arrayList_copy(stringList);
celix_autoptr(celix_array_list_t) stringRefListCopy = celix_arrayList_copy(stringRefList);
celix_autoptr(celix_array_list_t) versionListCopy = celix_arrayList_copy(versionList);

// Then the copied lists contain the null value
EXPECT_EQ(1, celix_arrayList_size(listCopy));
EXPECT_EQ(nullptr, celix_arrayList_get(listCopy, 0));
EXPECT_EQ(1, celix_arrayList_size(stringListCopy));
EXPECT_EQ(nullptr, celix_arrayList_getString(stringListCopy, 0));
EXPECT_EQ(1, celix_arrayList_size(stringRefListCopy));
EXPECT_EQ(nullptr, celix_arrayList_getString(stringRefListCopy, 0));
EXPECT_EQ(1, celix_arrayList_size(versionListCopy));
EXPECT_EQ(nullptr, celix_arrayList_getVersion(versionListCopy, 0));
}

TEST_F(ArrayListTestSuite, AssignNullTest) {
// Given a string and version list
celix_autoptr(celix_array_list_t) stringList = celix_arrayList_createStringArray();
celix_autoptr(celix_array_list_t) versionList = celix_arrayList_createVersionArray();

// When assigning a null value to the lists
celix_arrayList_assignString(stringList, nullptr);
celix_arrayList_assignVersion(versionList, nullptr);

// Then the lists contain the null value
EXPECT_EQ(1, celix_arrayList_size(stringList));
EXPECT_EQ(nullptr, celix_arrayList_getString(stringList, 0));
EXPECT_EQ(1, celix_arrayList_size(versionList));
EXPECT_EQ(nullptr, celix_arrayList_getVersion(versionList, 0));

// When copying the lists
celix_autoptr(celix_array_list_t) stringListCopy = celix_arrayList_copy(stringList);
celix_autoptr(celix_array_list_t) versionListCopy = celix_arrayList_copy(versionList);

// Then the copied lists contain the null value
EXPECT_EQ(1, celix_arrayList_size(stringListCopy));
EXPECT_EQ(nullptr, celix_arrayList_getString(stringListCopy, 0));
}
43 changes: 41 additions & 2 deletions libs/utils/include/celix_array_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,16 +177,20 @@ typedef struct celix_array_list_create_options {
*
* The remove, equals and compare callback will be NULL.
*
* @deprecated Use celix_arrayList_createWithOptions instead.
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_DEPRECATED_EXPORT
celix_array_list_t* celix_arrayList_create() __attribute__((deprecated("use create typed array list instead")));
celix_array_list_t* celix_arrayList_create();

/**
* @brief Creates a new empty array list with a pointer element type where the array list is not the owner of the
* pointers.
*
* The remove, equals and compare callback will be NULL.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createPointerArray();
Expand All @@ -196,6 +200,9 @@ celix_array_list_t* celix_arrayList_createPointerArray();
*
* The remove callback will be configured to free the string, and equals and compare callback will be configured for
* string comparison.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createStringArray();
Expand All @@ -206,6 +213,9 @@ celix_array_list_t* celix_arrayList_createStringArray();
*
* The remove callback will be configured to NULL, and equals and compare callback will be configured for
* string comparison.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createStringRefArray();
Expand All @@ -215,6 +225,9 @@ celix_array_list_t* celix_arrayList_createStringRefArray();
*
* The remove callback will be configured to NULL, and equals and compare callback will be configured for
* integer comparison.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createIntArray();
Expand All @@ -224,6 +237,9 @@ celix_array_list_t* celix_arrayList_createIntArray();
*
* The remove callback will be configured to NULL, and equals and compare callback will be configured for
* integer comparison.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createLongArray();
Expand All @@ -233,6 +249,9 @@ celix_array_list_t* celix_arrayList_createLongArray();
*
* The remove callback will be configured to NULL, and equals and compare callback will be configured for
* unsigned integer comparison.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createUIntArray();
Expand All @@ -242,6 +261,9 @@ celix_array_list_t* celix_arrayList_createUIntArray();
*
* The remove callback will be configured to NULL, and equals and compare callback will be configured for
* unsigned integer comparison.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createULongArray();
Expand All @@ -251,6 +273,9 @@ celix_array_list_t* celix_arrayList_createULongArray();
*
* The remove callback will be configured to NULL, and equals and compare callback will be configured for
* float comparison.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createFloatArray();
Expand All @@ -260,6 +285,9 @@ celix_array_list_t* celix_arrayList_createFloatArray();
*
* The remove callback will be configured to NULL, and equals and compare callback will be configured for
* double comparison.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createDoubleArray();
Expand All @@ -269,6 +297,9 @@ celix_array_list_t* celix_arrayList_createDoubleArray();
*
* The remove callback will be configured to NULL, and equals and compare callback will be configured for
* boolean comparison.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createBoolArray();
Expand All @@ -278,6 +309,9 @@ celix_array_list_t* celix_arrayList_createBoolArray();
*
* The remove callback will be configured to NULL, and equals and compare callback will be configured for
* unsigned integer comparison.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createSizeArray();
Expand All @@ -287,6 +321,9 @@ celix_array_list_t* celix_arrayList_createSizeArray();
*
* The remove callback will be configured to free a celix version, and equals and compare callback will be configured
* for celix version comparison.
*
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createVersionArray();
Expand All @@ -299,6 +336,8 @@ celix_array_list_t* celix_arrayList_createVersionArray();
* The provided callbacks in the options will override the default callbacks.
*
* @param opts The create options, only used during the creation of the array list.
* @return A new empty array list or NULL if the array list could not be created. If NULL is returned an error message
* is logged to celix_err.
*/
CELIX_UTILS_EXPORT
celix_array_list_t* celix_arrayList_createWithOptions(const celix_array_list_create_options_t* opts);
Expand Down
69 changes: 34 additions & 35 deletions libs/utils/src/array_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,23 +158,20 @@ static void celix_arrayList_callRemovedCallback(celix_array_list_t *list, int in
}

static celix_status_t celix_arrayList_ensureCapacity(celix_array_list_t* list, int capacity) {
celix_status_t status = CELIX_SUCCESS;
celix_array_list_entry_t *newList;
list->modCount++;
size_t oldCapacity = list->capacity;
if (capacity > oldCapacity) {
size_t newCapacity = (oldCapacity * 3) / 2 + 1;
if (newCapacity < capacity) {
newCapacity = capacity;
}
newList = realloc(list->elementData, sizeof(celix_array_list_entry_t) * newCapacity);
if (newList != NULL) {
list->capacity = newCapacity;
list->elementData = newList;
if (!newList) {
celix_err_push("Failed to reallocate memory for elementData");
return CELIX_ENOMEM;
}
status = newList == NULL ? CELIX_ENOMEM : CELIX_SUCCESS;
list->capacity = newCapacity;
list->elementData = newList;
}
return status;
return CELIX_SUCCESS;
}

static void celix_arrayList_setTypeSpecificCallbacks(celix_array_list_t* list) {
Expand Down Expand Up @@ -238,31 +235,34 @@ static void celix_arrayList_setTypeSpecificCallbacks(celix_array_list_t* list) {

celix_array_list_t* celix_arrayList_createWithOptions(const celix_array_list_create_options_t* opts) {
celix_autofree celix_array_list_t *list = calloc(1, sizeof(*list));
if (list) {
list->capacity = 10;
list->elementData = malloc(sizeof(celix_array_list_entry_t) * list->capacity);
if (!list->elementData) {
celix_err_push("Failed to allocate memory for elementData");
return NULL;
}
if (!list) {
celix_err_push("Failed to allocate memory for list");
return NULL;
}

list->elementType = opts->elementType;
celix_arrayList_setTypeSpecificCallbacks(list);
list->capacity = 10;
list->elementData = malloc(sizeof(celix_array_list_entry_t) * list->capacity);
if (!list->elementData) {
celix_err_push("Failed to allocate memory for elementData");
return NULL;
}

//if opts contains callbacks, use them and override the default ones
if (opts->simpleRemovedCallback) {
list->simpleRemovedCallback = opts->simpleRemovedCallback;
}
if (opts->removedCallback) {
list->removedCallback = opts->removedCallback;
list->removedCallbackData = opts->removedCallbackData;
}
if (opts->equalsCallback) {
list->equalsCallback = opts->equalsCallback;
}
if (opts->compareCallback) {
list->compareCallback = opts->compareCallback;
}
list->elementType = opts->elementType;
celix_arrayList_setTypeSpecificCallbacks(list);

//if opts contains callbacks, use them and override the default ones
if (opts->simpleRemovedCallback) {
list->simpleRemovedCallback = opts->simpleRemovedCallback;
}
if (opts->removedCallback) {
list->removedCallback = opts->removedCallback;
list->removedCallbackData = opts->removedCallbackData;
}
if (opts->equalsCallback) {
list->equalsCallback = opts->equalsCallback;
}
if (opts->compareCallback) {
list->compareCallback = opts->compareCallback;
}
return celix_steal_ptr(list);
}
Expand Down Expand Up @@ -439,7 +439,7 @@ celix_status_t celix_arrayList_addString(celix_array_list_t* list, const char* v
list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED);
celix_array_list_entry_t entry;
memset(&entry, 0, sizeof(entry));
if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING) {
if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING && val) {
entry.stringVal = celix_utils_strdup(val);
if (entry.stringVal == NULL) {
return CELIX_ENOMEM;
Expand Down Expand Up @@ -535,7 +535,7 @@ celix_status_t celix_arrayList_addVersion(celix_array_list_t* list, const celix_
list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_UNDEFINED);
celix_array_list_entry_t entry;
memset(&entry, 0, sizeof(entry));
if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION) {
if (list->elementType == CELIX_ARRAY_LIST_ELEMENT_TYPE_VERSION && value) {
entry.versionVal = celix_version_copy(value);
if (entry.versionVal == NULL) {
return CELIX_ENOMEM;
Expand Down Expand Up @@ -739,7 +739,6 @@ celix_array_list_t* celix_arrayList_copy(const celix_array_list_t* list) {
opts.simpleRemovedCallback = list->simpleRemovedCallback;
celix_autoptr(celix_array_list_t) copy = celix_arrayList_createWithOptions(&opts);
if (!copy) {
celix_err_push("Failed to create copy list. Out of memory.");
return NULL;
}

Expand Down

0 comments on commit 5097e48

Please sign in to comment.