From 0df7845f2ce202e57573d088338b2a0648cc2a20 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Tue, 6 Jan 2026 11:02:26 -0600 Subject: [PATCH] Added memory checks --- src/item/backpack.h | 9 +++ src/item/inventory.c | 34 ++++++++- src/item/inventory.h | 16 +++- src/item/item.c | 10 +++ src/item/item.h | 10 ++- src/item/itemtype.h | 2 +- src/util/CMakeLists.txt | 2 + src/util/array.c | 39 ++++++++++ src/util/array.h | 22 ++++++ src/util/memory.c | 6 ++ src/util/memory.h | 9 +++ src/util/sort.c | 71 ++++++++++++++++++ src/util/sort.h | 56 ++++++++++++++ test/item/test_inventory.c | 38 +++++++++- test/util/CMakeLists.txt | 4 +- test/util/test_array.c | 68 +++++++++++++++++ test/util/test_memory.c | 65 +++++++++++++++- test/util/test_sort.c | 149 +++++++++++++++++++++++++++++++++++++ test/util/test_string.c | 43 +++++++++++ 19 files changed, 640 insertions(+), 13 deletions(-) create mode 100644 src/item/backpack.h create mode 100644 src/util/array.c create mode 100644 src/util/array.h create mode 100644 src/util/sort.c create mode 100644 src/util/sort.h create mode 100644 test/util/test_array.c create mode 100644 test/util/test_sort.c diff --git a/src/item/backpack.h b/src/item/backpack.h new file mode 100644 index 0000000..6050da7 --- /dev/null +++ b/src/item/backpack.h @@ -0,0 +1,9 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "inventory.h" \ No newline at end of file diff --git a/src/item/inventory.c b/src/item/inventory.c index daae2d6..797a375 100644 --- a/src/item/inventory.c +++ b/src/item/inventory.c @@ -7,6 +7,7 @@ #include "inventory.h" #include "util/memory.h" +#include "util/sort.h" #include "assert/assert.h" void inventoryInit( @@ -113,7 +114,11 @@ void inventoryRemove(inventory_t *inventory, const itemid_t item) { if(stack->item != item) continue; // Match found, shift everything else down - memoryMove(stack, stack + 1, end - (stack + 1)); + memoryMove( + stack, + stack + 1, + (end - (stack + 1)) * sizeof(inventorystack_t) + ); // Clear last stack. inventorystack_t *last = end - 1; @@ -162,4 +167,31 @@ bool_t inventoryIsFull(const inventory_t *inventory) { bool_t inventoryItemFull(const inventory_t *inventory, const itemid_t item) { return inventoryGetCount(inventory, item) == ITEM_STACK_QUANTITY_MAX; +} + +void inventorySortById(inventory_t *inventory) { + assertNotNull(inventory, "Inventory pointer is NULL."); + assertNotNull(inventory->storage, "Storage pointer is NULL."); + assertTrue(inventory->storageSize > 0, "Storage too small."); + + // Get count of used stacks + size_t count = 0; + inventorystack_t *stack = inventory->storage; + inventorystack_t *end = stack + inventory->storageSize; + do { + if(stack->item == ITEM_ID_NULL) break; + count++; + } while(++stack < end); + + if(count == 0) return; // Nothing to sort + + int_t comparator(const void *a, const void *b) { + const inventorystack_t *stackA = (const inventorystack_t*)a; + const inventorystack_t *stackB = (const inventorystack_t*)b; + if(stackA->item < stackB->item) return -1; + if(stackA->item > stackB->item) return 1; + return 0; + } + + sort((void*)inventory->storage, count, sizeof(inventorystack_t), comparator); } \ No newline at end of file diff --git a/src/item/inventory.h b/src/item/inventory.h index bd939f9..2a30fba 100644 --- a/src/item/inventory.h +++ b/src/item/inventory.h @@ -100,4 +100,18 @@ bool_t inventoryIsFull(const inventory_t *inventory); * @param item The item ID to check. * @return true if the item stack is full, false otherwise. */ -bool_t inventoryItemFull(const inventory_t *inventory, const itemid_t item); \ No newline at end of file +bool_t inventoryItemFull(const inventory_t *inventory, const itemid_t item); + +/** + * Sorts the inventory by item ID in ascending order. + * + * @param inventory The inventory to sort. + */ +void inventorySortById(inventory_t *inventory); + +/** + * Sorts the inventory by item type in ascending order. + * + * @param inventory The inventory to sort. + */ +void inventorySortByType(inventory_t *inventory); \ No newline at end of file diff --git a/src/item/item.c b/src/item/item.c index 2a06839..e8a53f3 100644 --- a/src/item/item.c +++ b/src/item/item.c @@ -16,4 +16,14 @@ const item_t ITEMS[] = { [ITEM_ID_POTION] = { .type = ITEM_TYPE_MEDICINE }, + + // Potato + [ITEM_ID_POTATO] = { + .type = ITEM_TYPE_INGREDIENT + }, + + // Apple + [ITEM_ID_APPLE] = { + .type = ITEM_TYPE_INGREDIENT + } }; \ No newline at end of file diff --git a/src/item/item.h b/src/item/item.h index 6df27be..8f09aee 100644 --- a/src/item/item.h +++ b/src/item/item.h @@ -12,10 +12,12 @@ typedef struct { itemtype_t type; } item_t; -typedef uint8_t itemid_t; +typedef enum { + ITEM_ID_NULL = 0, -#define ITEM_ID_NULL 0 -#define ITEM_ID_POTION 1 -#define ITEM_ID_POTATO 2 + ITEM_ID_POTION, + ITEM_ID_POTATO, + ITEM_ID_APPLE +} itemid_t; extern const item_t ITEMS[]; \ No newline at end of file diff --git a/src/item/itemtype.h b/src/item/itemtype.h index cde6d3e..9defc8e 100644 --- a/src/item/itemtype.h +++ b/src/item/itemtype.h @@ -9,7 +9,7 @@ #include "dusk.h" typedef enum { - ITEM_TYPE_NULL, + ITEM_TYPE_NULL = 0, ITEM_TYPE_MEDICINE, ITEM_TYPE_INGREDIENT, diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 13cb205..095cfb7 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -6,7 +6,9 @@ # Sources target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC + array.c memory.c string.c math.c + sort.c ) \ No newline at end of file diff --git a/src/util/array.c b/src/util/array.c new file mode 100644 index 0000000..214f841 --- /dev/null +++ b/src/util/array.c @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "array.h" +#include "assert/assert.h" +#include "util/memory.h" + +void arrayReverse( + void *array, + const size_t count, + const size_t size +) { + assertNotNull(array, "Cannot reverse NULL memory."); + assertTrue(size > 0, "Element size must be greater than zero."); + + if(count == 0) return; + + // For half the array length, swap elements + uint8_t *start = (uint8_t*)array; + uint8_t *end = start + (count - 1) * size; + uint8_t *temp = (uint8_t*)memoryAllocate(size); + + // Floorf + size_t i; + for(i = 0; i < count / 2; i++) { + // Swap start and end + memoryCopy(temp, start, size); + memoryCopy(start, end, size); + memoryCopy(end, temp, size); + start += size; + end -= size; + } + + memoryFree(temp); +} \ No newline at end of file diff --git a/src/util/array.h b/src/util/array.h new file mode 100644 index 0000000..ff2d539 --- /dev/null +++ b/src/util/array.h @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +/** + * Reverses the order of elements in an array. + * + * @param array The array to reverse. + * @param count The number of elements in the array. + * @param size The size of each element (the stride). + */ +void arrayReverse( + void *array, + const size_t count, + const size_t size +); \ No newline at end of file diff --git a/src/util/memory.c b/src/util/memory.c index 933089e..40d609e 100644 --- a/src/util/memory.c +++ b/src/util/memory.c @@ -9,16 +9,22 @@ #include "assert/assert.h" #include "util/math.h" +size_t memoryGetAllocatedCount(void) { + return MEMORY_POINTERS_IN_USE; +} + void * memoryAllocate(const size_t size) { assertTrue(size > 0, "Cannot allocate 0 bytes of memory."); void *ptr = malloc(size); assertNotNull(ptr, "Memory allocation failed."); + MEMORY_POINTERS_IN_USE++; return ptr; } void memoryFree(void *ptr) { assertNotNull(ptr, "Cannot free NULL memory."); free(ptr); + MEMORY_POINTERS_IN_USE--; } diff --git a/src/util/memory.h b/src/util/memory.h index 1e08137..0bf38a9 100644 --- a/src/util/memory.h +++ b/src/util/memory.h @@ -8,6 +8,15 @@ #pragma once #include "dusk.h" +static size_t MEMORY_POINTERS_IN_USE = 0; + +/** + * Gets the number of currently allocated memory blocks. + * + * @return The number of allocated memory blocks. + */ +size_t memoryGetAllocatedCount(void); + /** * Allocates memory. * diff --git a/src/util/sort.c b/src/util/sort.c new file mode 100644 index 0000000..59fb280 --- /dev/null +++ b/src/util/sort.c @@ -0,0 +1,71 @@ +#include +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "sort.h" +#include "assert/assert.h" +#include "util/memory.h" + +void sortBubble( + void *array, + const size_t count, + const size_t size, + const sortcompare_t compare +) { + assertNotNull(array, "Cannot sort NULL memory."); + assertTrue(count > 0, "Cannot sort 0 elements."); + assertTrue(size > 0, "Element size must be greater than zero."); + assertNotNull(compare, "Compare function cannot be NULL."); + + // Create variables + uint8_t *temp = (uint8_t*)memoryAllocate(size); + bool_t swapped; + uint8_t *a, *b; + size_t i; + + do { + swapped = false; + for(i = 1; i < count; i++) { + a = array + (i - 1) * size; + b = array + i * size; + if(compare(a, b) > 0) { + // Swap + memoryCopy(temp, a, size); + memoryCopy(a, b, size); + memoryCopy(b, temp, size); + swapped = true; + } + } + } while(swapped); + + memoryFree(temp); +} + +void sortQuick( + void *array, + const size_t count, + const size_t size, + const sortcompare_t compare +) { + assertNotNull(array, "Cannot sort NULL memory."); + assertTrue(count > 0, "Cannot sort 0 elements."); + assertTrue(size > 0, "Element size must be greater than zero."); + assertNotNull(compare, "Compare function cannot be NULL."); + + // qsort expects a comparator returning int, which matches sortcompare_t + qsort(array, count, size, compare); +} + +void sortArrayU8(uint8_t *array, const size_t count) { + int_t compare(const void *a, const void *b) { + uint8_t valA = *(const uint8_t*)a; + uint8_t valB = *(const uint8_t*)b; + return (valA > valB) - (valA < valB); + } + + return sort((void*)array, count, sizeof(uint8_t), compare); +} \ No newline at end of file diff --git a/src/util/sort.h b/src/util/sort.h new file mode 100644 index 0000000..0292ac2 --- /dev/null +++ b/src/util/sort.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +typedef int_t (*sortcompare_t)(const void*, const void*); + +/** + * Sorts an array using the bubble sort algorithm. + * + * @param array The array to sort. + * @param count The number of elements in the array. + * @param size The size of each element. + * @param compare The comparison function. + */ +void sortBubble( + void *array, + const size_t count, + const size_t size, + const sortcompare_t compare +); + +/** + * Sorts an array using the quicksort algorithm. + * + * @param array The array to sort. + * @param count The number of elements in the array. + * @param size The size of each element. + * @param compare The comparison function. + */ +void sortQuick( + void *array, + const size_t count, + const size_t size, + const sortcompare_t compare +); + +/** + * Preferred sort function. + * + * @see sortQuick + */ +#define sort sortQuick + +/** + * Sorts an array of uint8_t in ascending order. + * + * @param array The array to sort. + * @param count The number of elements in the array. + */ +void sortArrayU8(uint8_t *array, const size_t count); \ No newline at end of file diff --git a/test/item/test_inventory.c b/test/item/test_inventory.c index d8fb81e..c8d6349 100644 --- a/test/item/test_inventory.c +++ b/test/item/test_inventory.c @@ -104,9 +104,10 @@ static void test_inventorySet(void **state) { assert_int_equal(inventory.storage[0].quantity, 1); assert_int_equal(inventory.storage[1].item, ITEM_ID_POTATO); assert_int_equal(inventory.storage[1].quantity, 5); + assert_int_equal(inventory.storage[2].item, ITEM_ID_NULL); // Setting early item to 0 should shift others down - inventorySet(&inventory, ITEM_ID_POTION, 0); + inventorySet(&inventory, ITEM_ID_POTION, 0);// Item 0 removed assert_int_equal(inventory.storage[0].item, ITEM_ID_POTATO); assert_int_equal(inventory.storage[0].quantity, 5); assert_int_equal(inventory.storage[1].item, ITEM_ID_NULL); @@ -325,6 +326,40 @@ static void test_inventoryItemFull(void **state) { inventory.storageSize = 2; } +static void test_inventorySortById(void **state) { + (void)state; + + inventorystack_t storage[5]; + inventory_t inventory; + inventoryInit(&inventory, storage, 5); + + // Add items out of order + inventorySet(&inventory, ITEM_ID_POTATO, 3); + inventorySet(&inventory, ITEM_ID_APPLE, 5); + inventorySet(&inventory, ITEM_ID_POTION, 2); + + // Sort by ID + inventorySortById(&inventory); + + // Check order + assert_int_equal(inventory.storage[0].item, ITEM_ID_POTION); + assert_int_equal(inventory.storage[1].item, ITEM_ID_POTATO); + assert_int_equal(inventory.storage[2].item, ITEM_ID_APPLE); + + // Should fail when given NULL inventory pointer + expect_assert_failure(inventorySortById(NULL)); + + // Should fail when given NULL storage pointer + inventory.storage = NULL; + expect_assert_failure(inventorySortById(&inventory)); + inventory.storage = storage; + + // Should fail when given zero storage size + inventory.storageSize = 0; + expect_assert_failure(inventorySortById(&inventory)); + inventory.storageSize = 5; +} + int main(int argc, char** argv) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_inventoryInit), @@ -335,6 +370,7 @@ int main(int argc, char** argv) { cmocka_unit_test(test_inventoryGetCount), cmocka_unit_test(test_inventoryIsFull), cmocka_unit_test(test_inventoryItemFull), + cmocka_unit_test(test_inventorySortById) }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/test/util/CMakeLists.txt b/test/util/CMakeLists.txt index c393ae8..325295c 100644 --- a/test/util/CMakeLists.txt +++ b/test/util/CMakeLists.txt @@ -6,6 +6,8 @@ include(dusktest) # Tests +dusktest(test_array.c) dusktest(test_math.c) dusktest(test_memory.c) -dusktest(test_string.c) \ No newline at end of file +dusktest(test_string.c) +dusktest(test_sort.c) \ No newline at end of file diff --git a/test/util/test_array.c b/test/util/test_array.c new file mode 100644 index 0000000..0c9098d --- /dev/null +++ b/test/util/test_array.c @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "dusktest.h" +#include "util/memory.h" +#include "util/array.h" + +static void test_arrayReverse(void **state) { + (void)state; + + uint8_t array1[] = { 1, 2, 3, 4, 5 }; + arrayReverse(array1, 5, sizeof(uint8_t)); + uint8_t expected1[] = {5,4,3,2,1}; + assert_memory_equal(array1, expected1, sizeof(uint8_t) * 5); + + uint8_t array2[] = { 10, 20, 30, 40 }; + arrayReverse(array2, 4, sizeof(uint8_t)); + uint8_t expected2[] = {40,30,20,10}; + assert_memory_equal(array2, expected2, sizeof(uint8_t) * 4); + + uint8_t array3[] = { 7 }; + arrayReverse(array3, 1, sizeof(uint8_t)); + uint8_t expected3[] = {7}; + assert_memory_equal(array3, expected3, sizeof(uint8_t) * 1); + + uint8_t array4[] = {}; + arrayReverse(array4, 0, sizeof(uint8_t)); + uint8_t expected4[] = {}; + assert_memory_equal(array4, expected4, sizeof(uint8_t) * 0); + + // Can reverse arrays of larger element sizes + uint16_t array5[] = { 1000, 2000, 3000 }; + arrayReverse(array5, 3, sizeof(uint16_t)); + uint16_t expected5[] = {3000,2000,1000}; + assert_memory_equal(array5, expected5, sizeof(uint16_t) * 3); + + uint64_t array6[] = { 100000, 200000, 300000, 400000 }; + arrayReverse(array6, 4, sizeof(uint64_t)); + uint64_t expected6[] = {400000,300000,200000,100000}; + assert_memory_equal(array6, expected6, sizeof(uint64_t) * 4); + + // Will only sort provided array length, anything after is untouched + uint8_t array7[] = { 1, 2, 3, 4, 5, 6, 7 }; + arrayReverse(array7, 5, sizeof(uint8_t)); + uint8_t expected7[] = {5,4,3,2,1,6,7}; + assert_memory_equal(array7, expected7, sizeof(uint8_t) * 7); + + // Should fail when given NULL array pointer + expect_assert_failure(arrayReverse(NULL, 5, sizeof(uint8_t))); + + // Should fail when given zero size + expect_assert_failure(arrayReverse(array1, 5, 0)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); +} + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_arrayReverse), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} \ No newline at end of file diff --git a/test/util/test_memory.c b/test/util/test_memory.c index ab89b0b..93c2cc3 100644 --- a/test/util/test_memory.c +++ b/test/util/test_memory.c @@ -11,31 +11,64 @@ static void test_memoryAllocate(void **state) { (void)state; - size_t size = 128; - void *ptr = memoryAllocate(size); + // Memory should allocate + void *ptr = memoryAllocate(128); assert_non_null(ptr); + + // Allocating should be tracked + assert_int_equal(memoryGetAllocatedCount(), 1); + + void *ptr2 = memoryAllocate(256); + assert_non_null(ptr2); + assert_int_equal(memoryGetAllocatedCount(), 2); + + // Free memory memoryFree(ptr); + assert_int_equal(memoryGetAllocatedCount(), 1); + memoryFree(ptr2); + assert_int_equal(memoryGetAllocatedCount(), 0); // Should not be able to allocate 0 bytes expect_assert_failure(memoryAllocate(0)); // Should not be able to allocate more memory than possible expect_assert_failure(memoryAllocate(SIZE_MAX)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_memoryFree(void **state) { (void)state; // Create some memory - size_t size = 64; - void *ptr = memoryAllocate(size); + void *ptr = memoryAllocate(64); assert_non_null(ptr); + assert_int_equal(memoryGetAllocatedCount(), 1); // Free memoryFree(ptr); + // Allocated count should decrease + assert_int_equal(memoryGetAllocatedCount(), 0); + + ptr = memoryAllocate(32); + assert_non_null(ptr); + void *ptr2 = memoryAllocate(32); + assert_non_null(ptr2); + assert_int_equal(memoryGetAllocatedCount(), 2); + + // Free both + memoryFree(ptr); + assert_int_equal(memoryGetAllocatedCount(), 1); + memoryFree(ptr2); + assert_int_equal(memoryGetAllocatedCount(), 0); + // Expect unable to free NULL expect_assert_failure(memoryFree(NULL)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_memoryCopy(void **state) { @@ -73,6 +106,9 @@ static void test_memoryCopy(void **state) { memoryFree(src); memoryFree(dest); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_memorySet(void **state) { @@ -104,6 +140,9 @@ static void test_memorySet(void **state) { } memoryFree(ptr); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_memoryZero(void **state) { @@ -129,6 +168,9 @@ static void test_memoryZero(void **state) { expect_assert_failure(memoryZero(ptr, 0)); memoryFree(ptr); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_memoryCopyRangeSafe(void **state) { @@ -175,6 +217,9 @@ static void test_memoryCopyRangeSafe(void **state) { memoryFree(src); memoryFree(dest); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_memoryMove(void **state) { @@ -225,6 +270,9 @@ static void test_memoryMove(void **state) { expect_assert_failure(memoryMove(ptr, ptr, size)); memoryFree(ptr); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_memoryCompare(void **state) { @@ -273,6 +321,9 @@ static void test_memoryCompare(void **state) { memoryFree(a); memoryFree(b); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_memoryReallocate(void **state) { @@ -303,6 +354,9 @@ static void test_memoryReallocate(void **state) { // All we really care about is that the pointer is valid after reallocations memoryFree(ptr); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_memoryResize(void **state) { @@ -356,6 +410,9 @@ static void test_memoryResize(void **state) { expect_assert_failure(memoryResize(&ptr, smallerSize, SIZE_MAX)); memoryFree(ptr); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } int main(int argc, char **argv) { diff --git a/test/util/test_sort.c b/test/util/test_sort.c new file mode 100644 index 0000000..5cb6295 --- /dev/null +++ b/test/util/test_sort.c @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "dusktest.h" +#include "util/sort.h" +#include "util/memory.h" + +typedef struct { + int_t key; + char value; +} teststruct_t; + +void testSortMethod( + void (*sortMethod)( + void *array, + const size_t count, + const size_t size, + const sortcompare_t compare + ), + const char *methodName +) { + // Create an array of integers + size_t count = 5; + int_t *array = (int_t*)memoryAllocate(count * sizeof(int_t)); + assert_non_null(array); + + // Initialize with unsorted data + array[0] = 5; + array[1] = 3; + array[2] = 4; + array[3] = 1; + array[4] = 2; + + // Comparator function + int_t compareInts(const void *a, const void *b) { + int_t intA = *(const int_t*)a; + int_t intB = *(const int_t*)b; + return (intA > intB) - (intA < intB); + } + + // Sort the array + sortMethod(array, count, sizeof(int_t), compareInts); + + // Check that the array is sorted + for(size_t i = 0; i < count; i++) { + assert_int_equal(array[i], (int_t)(i + 1)); + } + + // Test with custom struct comparator + teststruct_t unsortedStructs[4] = { + {3, 'b'}, + {1, 'd'}, + {4, 'a'}, + {2, 'c'} + }; + teststruct_t structArray[4]; + + // Test with number comparator + memoryCopy(structArray, unsortedStructs, sizeof(unsortedStructs)); + int_t compareStructsKeys(const void *a, const void *b) { + const teststruct_t *structA = (const teststruct_t*)a; + const teststruct_t *structB = (const teststruct_t*)b; + return (structA->key > structB->key) - (structA->key < structB->key); + } + + sortMethod(structArray, 4, sizeof(teststruct_t), compareStructsKeys); + for(size_t i = 0; i < 4; i++) { + assert_int_equal(structArray[i].key, (int_t)(i + 1)); + } + + // Test with char comparator + memoryCopy(structArray, unsortedStructs, sizeof(unsortedStructs)); + int_t compareStructsValues(const void *a, const void *b) { + const teststruct_t *structA = (const teststruct_t*)a; + const teststruct_t *structB = (const teststruct_t*)b; + return (structA->value > structB->value) - (structA->value < structB->value); + } + sortMethod(structArray, 4, sizeof(teststruct_t), compareStructsValues); + char expectedValues[4] = {'a', 'b', 'c', 'd'}; + for(size_t i = 0; i < 4; i++) { + assert_int_equal(structArray[i].value, expectedValues[i]); + } + + // Cannot sort NULL base + expect_assert_failure(sortMethod(NULL, count, sizeof(int_t), compareInts)); + + // Cannot sort 0 elements + expect_assert_failure(sortMethod(array, 0, sizeof(int_t), compareInts)); + + // Cannot sort with size 0 + expect_assert_failure(sortMethod(array, count, 0, compareInts)); + + // Cannot sort with NULL comparator + expect_assert_failure(sortMethod(array, count, sizeof(int_t), NULL)); + + memoryFree(array); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); +} + +static void test_sortBubble(void **state) { + (void)state; + testSortMethod(sortBubble, "sortBubble"); +} + +static void test_sortQuick(void **state) { + (void)state; + testSortMethod(sortQuick, "sortQuick"); +} + +static void test_sortArrayU8(void **state) { + (void)state; + + // Create an array of uint8_t + size_t count = 6; + uint8_t array[6] = {5, 2, 4, 1, 3, 0}; + + // Sort the array + sortArrayU8(array, count); + + // Check that the array is sorted + for(size_t i = 0; i < count; i++) { + assert_int_equal(array[i], (uint8_t)i); + } + + // Cannot sort NULL array + expect_assert_failure(sortArrayU8(NULL, count)); + + // Cannot sort 0 elements + expect_assert_failure(sortArrayU8(array, 0)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); +} + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_sortBubble), + cmocka_unit_test(test_sortQuick), + cmocka_unit_test(test_sortArrayU8), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} \ No newline at end of file diff --git a/test/util/test_string.c b/test/util/test_string.c index ce22ebf..3b8fe24 100644 --- a/test/util/test_string.c +++ b/test/util/test_string.c @@ -7,6 +7,7 @@ #include "dusktest.h" #include "util/string.h" +#include "util/memory.h" static void test_stringIsWhitespace(void **state) { (void)state; @@ -20,6 +21,9 @@ static void test_stringIsWhitespace(void **state) { assert_false(stringIsWhitespace('1')); // '1' is not whitespace assert_false(stringIsWhitespace('_')); // '_' is not whitespace assert_false(stringIsWhitespace('-')); // '-' is not whitespace + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringCopy(void **state) { @@ -47,6 +51,9 @@ static void test_stringCopy(void **state) { // Must have destSize large enough for source expect_assert_failure(stringCopy(dest, "this string is too long", 10)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringCompare(void **state) { @@ -69,6 +76,9 @@ static void test_stringCompare(void **state) { // Cannot compare NULL strings expect_assert_failure(stringCompare(NULL, "abc")); expect_assert_failure(stringCompare("abc", NULL)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringCompareInsensitive(void **state) { @@ -84,6 +94,9 @@ static void test_stringCompareInsensitive(void **state) { // Cannot compare NULL strings expect_assert_failure(stringCompareInsensitive(NULL, "abc")); expect_assert_failure(stringCompareInsensitive("abc", NULL)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringTrim(void **state) { @@ -127,6 +140,9 @@ static void test_stringTrim(void **state) { stringCopy(buf, "", sizeof(buf)); stringTrim(buf); assert_string_equal(buf, ""); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringFindLastChar(void **state) { @@ -148,6 +164,9 @@ static void test_stringFindLastChar(void **state) { // Cannot search NULL string expect_assert_failure(stringFindLastChar(NULL, 'a')); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringFormat(void **state) { @@ -204,6 +223,9 @@ static void test_stringFormat(void **state) { // Must have destSize > 0 if dest is not NULL expect_assert_failure(stringFormat(buffer, 0, "Hello")); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringToI32(void **state) { @@ -330,6 +352,9 @@ static void test_stringToI32(void **state) { // Cannot have NULL output pointer stringCopy(buffer, "123", sizeof(buffer)); expect_assert_failure(stringToI32(buffer, NULL)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringToI64(void **state) { @@ -456,6 +481,9 @@ static void test_stringToI64(void **state) { // Cannot have NULL output pointer stringCopy(buffer, "123", sizeof(buffer)); expect_assert_failure(stringToI64(buffer, NULL)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringToI16(void **state) { @@ -574,6 +602,9 @@ static void test_stringToI16(void **state) { // Cannot have NULL output pointer stringCopy(buffer, "123", sizeof(buffer)); expect_assert_failure(stringToI16(buffer, NULL)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringToU16(void **state) { @@ -688,6 +719,9 @@ static void test_stringToU16(void **state) { // Cannot have NULL output pointer stringCopy(buffer, "123", sizeof(buffer)); expect_assert_failure(stringToU16(buffer, NULL)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringToF32(void **state) { @@ -819,6 +853,9 @@ static void test_stringToF32(void **state) { // Cannot have NULL output pointer stringCopy(buffer, "1.23", sizeof(buffer)); expect_assert_failure(stringToF32(buffer, NULL)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringEndsWith(void **state) { @@ -834,6 +871,9 @@ static void test_stringEndsWith(void **state) { // Cannot have NULL strings expect_assert_failure(stringEndsWith(NULL, "world")); expect_assert_failure(stringEndsWith("hello", NULL)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } static void test_stringEndsWithCaseInsensitive(void **state) { @@ -848,6 +888,9 @@ static void test_stringEndsWithCaseInsensitive(void **state) { // Cannot have NULL strings expect_assert_failure(stringEndsWithCaseInsensitive(NULL, "WORLD")); expect_assert_failure(stringEndsWithCaseInsensitive("hello", NULL)); + + // Expect no leaks + assert_int_equal(memoryGetAllocatedCount(), 0); } int main(int argc, char **argv) {