diff --git a/CMakeLists.txt b/CMakeLists.txt index a53356c..e15e0b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(UDPConnection) set(UDPConnection_SOURCES src/UDPConnection.c - src/Deque.c + src/UDPC_Deque.c ) set(CMAKE_C_FLAGS "-Wall -Wno-missing-braces") @@ -19,3 +19,12 @@ endif() add_library(UDPConnection ${UDPConnection_SOURCES}) target_compile_features(UDPConnection PUBLIC c_std_11) +target_link_libraries(UDPConnection PUBLIC pthread) + +if(CMAKE_BUILD_TYPE MATCHES "Debug") + set(UDPC_UnitTest_SOURCES + src/test/UDPC_UnitTest.c) + add_executable(UnitTest ${UDPC_UnitTest_SOURCES}) + target_link_libraries(UnitTest PUBLIC UDPConnection) + target_include_directories(UnitTest PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) +endif() diff --git a/src/Deque.c b/src/UDPC_Deque.c similarity index 89% rename from src/Deque.c rename to src/UDPC_Deque.c index ea8dbba..64c30d1 100644 --- a/src/Deque.c +++ b/src/UDPC_Deque.c @@ -1,4 +1,4 @@ -#include "Deque.h" +#include "UDPC_Deque.h" #include #include @@ -41,6 +41,12 @@ int UDPC_Deque_realloc(UDPC_Deque *deque, uint32_t new_size) free(deque->buf); deque->buf = buf; deque->alloc_size = new_size; + deque->head = 0; + deque->tail = deque->size; + if(deque->tail == deque->alloc_size) + { + deque->tail = 0; + } return 1; } else @@ -59,7 +65,7 @@ int UDPC_Deque_realloc(UDPC_Deque *deque, uint32_t new_size) } } -int UDPC_Deque_push_back(UDPC_Deque *deque, const char *data, uint32_t size) +int UDPC_Deque_push_back(UDPC_Deque *deque, const void *data, uint32_t size) { if(deque->size + size > deque->alloc_size) { @@ -90,14 +96,14 @@ int UDPC_Deque_push_back(UDPC_Deque *deque, const char *data, uint32_t size) } if(size > 0) { - memcpy(&deque->buf[deque->tail], &data[temp], size); + memcpy(&deque->buf[deque->tail], &((const char*)data)[temp], size); deque->tail += size; deque->size += size; } return 1; } -int UDPC_Deque_push_front(UDPC_Deque *deque, const char *data, uint32_t size) +int UDPC_Deque_push_front(UDPC_Deque *deque, const void *data, uint32_t size) { if(deque->size + size > deque->alloc_size) { @@ -114,7 +120,7 @@ int UDPC_Deque_push_front(UDPC_Deque *deque, const char *data, uint32_t size) if(deque->head > 0) { - memcpy(deque->buf, &data[size - deque->head], deque->head); + memcpy(deque->buf, &((const char*)data)[size - deque->head], deque->head); deque->size += deque->head; size -= deque->head; deque->head = 0; @@ -138,7 +144,7 @@ uint32_t UDPC_Deque_get_used(UDPC_Deque *deque) return deque->size; } -int UDPC_Deque_get_back(UDPC_Deque *deque, char **data, uint32_t *size) +int UDPC_Deque_get_back(UDPC_Deque *deque, void **data, uint32_t *size) { int returnValue = 1; if(deque->size == 0) @@ -169,7 +175,7 @@ int UDPC_Deque_get_back(UDPC_Deque *deque, char **data, uint32_t *size) return returnValue; } -int UDPC_Deque_get_front(UDPC_Deque *deque, char **data, uint32_t *size) +int UDPC_Deque_get_front(UDPC_Deque *deque, void **data, uint32_t *size) { int returnValue = 1; if(deque->size == 0) @@ -252,11 +258,11 @@ void UDPC_Deque_pop_front(UDPC_Deque *deque, uint32_t size) } } -int UDPC_Deque_index(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, char **out) +int UDPC_Deque_index(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, void **out) { uint32_t pos = unitSize * index; uint32_t abspos; - if(pos >= deque->alloc_size) + if(pos >= deque->size) { *out = NULL; return 0; @@ -286,11 +292,11 @@ int UDPC_Deque_index(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, char return 1; } -int UDPC_Deque_index_rev(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, char **out) +int UDPC_Deque_index_rev(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, void **out) { uint32_t pos = unitSize * (index + 1); uint32_t abspos; - if(pos >= deque->alloc_size) + if(pos >= deque->size + unitSize) { *out = NULL; return 0; diff --git a/src/Deque.h b/src/UDPC_Deque.h similarity index 82% rename from src/Deque.h rename to src/UDPC_Deque.h index a67b7c3..56285e2 100644 --- a/src/Deque.h +++ b/src/UDPC_Deque.h @@ -33,13 +33,13 @@ int UDPC_Deque_realloc(UDPC_Deque *deque, uint32_t new_size); * If there was not enough space in the Deque, then no data is inserted at all. * \return non-zero on success (there was enough size to insert data) */ -int UDPC_Deque_push_back(UDPC_Deque *deque, const char *data, uint32_t size); +int UDPC_Deque_push_back(UDPC_Deque *deque, const void *data, uint32_t size); /*! * If there was not enough space in the Deque, then no data is inserted at all. * \return non-zero on success (there was enough size to insert data) */ -int UDPC_Deque_push_front(UDPC_Deque *deque, const char *data, uint32_t size); +int UDPC_Deque_push_front(UDPC_Deque *deque, const void *data, uint32_t size); /*! * \return size in bytes of available data @@ -58,7 +58,7 @@ uint32_t UDPC_Deque_get_used(UDPC_Deque *deque); * updated to allocated amount. If deque is empty, no data is allocated. * \return non-zero if full requested size was returned */ -int UDPC_Deque_get_back(UDPC_Deque *deque, char **data, uint32_t *size); +int UDPC_Deque_get_back(UDPC_Deque *deque, void **data, uint32_t *size); /*! * \brief Get data from front of deque @@ -67,7 +67,7 @@ int UDPC_Deque_get_back(UDPC_Deque *deque, char **data, uint32_t *size); * updated to allocated amount. If deque is empty, no data is allocated. * \return non-zero if full requested size was returned */ -int UDPC_Deque_get_front(UDPC_Deque *deque, char **data, uint32_t *size); +int UDPC_Deque_get_front(UDPC_Deque *deque, void **data, uint32_t *size); /*! * \brief "free" data from the back of the deque @@ -92,22 +92,22 @@ void UDPC_Deque_pop_front(UDPC_Deque *deque, uint32_t size); * The data will be indexed relative to the head of the Deque. * The out pointer will be malloc'd with size unitSize and will have a copy of * the data at the specified unitSize * index. - * Note that the out data must be free'd, but nothing will be malloc'd on fail + * Note that the out data must be free'd, but on fail nothing will be malloc'd * and *out will be set to NULL. - * \return non-zero if unitSize * index < allocated_size_of_Deque + * \return non-zero if unitSize * index < size */ -int UDPC_Deque_index(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, char **out); +int UDPC_Deque_index(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, void **out); /*! * \brief Get a unitSize sized chunk of data at position relative to tail * The out pointer will be malloc'd with size unitSize and will have a copy of - * the data at the specified unitSize * (index + 1) relative to tail in reverse + * the data at the specified unitSize * index relative to tail in reverse * direction. - * Note that the out data must be free'd, but nothing will be malloc'd on fail + * Note that the out data must be free'd, but on fail nothing will be malloc'd * and *out will be set to NULL. - * \return non-zero if unitSize * (index + 1) < allocated_size_of_Deque + * \return non-zero if unitSize * index < size */ -int UDPC_Deque_index_rev(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, char **out); +int UDPC_Deque_index_rev(UDPC_Deque *deque, uint32_t unitSize, uint32_t index, void **out); void UDPC_Deque_clear(UDPC_Deque *deque); diff --git a/src/test/UDPC_UnitTest.c b/src/test/UDPC_UnitTest.c new file mode 100644 index 0000000..f24926a --- /dev/null +++ b/src/test/UDPC_UnitTest.c @@ -0,0 +1,176 @@ +#include "UDPC_UnitTest.h" + +#include +#include + +static UnitTestState UDPC_uts = {0, 0}; + +int main() +{ + int arr[32]; + char *temp = NULL; + uint32_t size; + for(int x = 0; x < 32; ++x) + { + arr[x] = x; + } + UDPC_Deque deque; + + // init + ASSERT_TRUE(UDPC_Deque_init(&deque, sizeof(int) * 32)); + ASSERT_TRUE(deque.buf); + ASSERT_EQ(deque.head, 0); + ASSERT_EQ(deque.tail, 0); + ASSERT_EQ(deque.size, 0); + ASSERT_EQ(deque.alloc_size, sizeof(int) * 32); + + // realloc smaller success + ASSERT_TRUE(UDPC_Deque_realloc(&deque, sizeof(int) * 16)); + ASSERT_TRUE(deque.buf); + ASSERT_EQ(deque.head, 0); + ASSERT_EQ(deque.tail, 0); + ASSERT_EQ(deque.size, 0); + ASSERT_EQ(deque.alloc_size, sizeof(int) * 16); + + // push back success + ASSERT_TRUE(UDPC_Deque_push_back(&deque, arr, sizeof(int) * 4)); + ASSERT_EQ_MEM(arr, deque.buf, sizeof(int) * 4); + ASSERT_EQ(deque.size, sizeof(int) * 4); + + // push front success + ASSERT_TRUE(UDPC_Deque_push_front(&deque, &arr[4], sizeof(int) * 4)); + ASSERT_EQ_MEM(&arr[4], &deque.buf[sizeof(int) * 12], sizeof(int) * 4); + ASSERT_EQ(deque.size, sizeof(int) * 8); + + // realloc bigger success + ASSERT_TRUE(UDPC_Deque_realloc(&deque, sizeof(int) * 32)); + ASSERT_EQ_MEM(&arr[4], deque.buf, sizeof(int) * 4); + ASSERT_EQ_MEM(arr, &deque.buf[sizeof(int) * 4], sizeof(int) * 4); + ASSERT_EQ(deque.alloc_size, sizeof(int) * 32); + + // pop front success + UDPC_Deque_pop_front(&deque, sizeof(int) * 4); + ASSERT_EQ(deque.size, sizeof(int) * 4); + + // get front success + size = sizeof(int) * 4; + ASSERT_TRUE(UDPC_Deque_get_front(&deque, (void**)&temp, &size)); + ASSERT_EQ(size, sizeof(int) * 4); + ASSERT_EQ_MEM(arr, temp, size); + free(temp); + + // pop back success + UDPC_Deque_pop_back(&deque, sizeof(int) * 4); + ASSERT_EQ(deque.size, 0); + + // push front success + ASSERT_TRUE(UDPC_Deque_push_front(&deque, arr, sizeof(int) * 16)); + ASSERT_EQ(deque.size, sizeof(int) * 16); + + // get front success + size = sizeof(int) * 16; + ASSERT_TRUE(UDPC_Deque_get_front(&deque, (void**)&temp, &size)); + ASSERT_EQ(size, sizeof(int) * 16); + ASSERT_EQ_MEM(arr, temp, size); + free(temp); + + // get back success + size = sizeof(int) * 16; + ASSERT_TRUE(UDPC_Deque_get_back(&deque, (void**)&temp, &size)); + ASSERT_EQ(size, sizeof(int) * 16); + ASSERT_EQ_MEM(arr, temp, size); + free(temp); + + // realloc smaller fail + ASSERT_FALSE(UDPC_Deque_realloc(&deque, sizeof(int) * 8)); + ASSERT_EQ(deque.size, sizeof(int) * 16); + ASSERT_EQ(deque.alloc_size, sizeof(int) * 32); + + // realloc smaller success + ASSERT_TRUE(UDPC_Deque_realloc(&deque, sizeof(int) * 16)); + ASSERT_EQ(deque.size, sizeof(int) * 16); + ASSERT_EQ(deque.alloc_size, sizeof(int) * 16); + ASSERT_EQ_MEM(deque.buf, arr, sizeof(int) * 16); + + // push back fail + ASSERT_FALSE(UDPC_Deque_push_back(&deque, arr, sizeof(int) * 16)); + ASSERT_EQ(deque.size, sizeof(int) * 16); + ASSERT_EQ(deque.alloc_size, sizeof(int) * 16); + ASSERT_EQ_MEM(deque.buf, arr, sizeof(int) * 16); + + // push front fail + ASSERT_FALSE(UDPC_Deque_push_back(&deque, arr, sizeof(int) * 16)); + ASSERT_EQ(deque.size, sizeof(int) * 16); + ASSERT_EQ(deque.alloc_size, sizeof(int) * 16); + ASSERT_EQ_MEM(deque.buf, arr, sizeof(int) * 16); + + // pop back + UDPC_Deque_pop_back(&deque, sizeof(int) * 8); + + // get front success + size = sizeof(int) * 8; + ASSERT_TRUE(UDPC_Deque_get_front(&deque, (void**)&temp, &size)); + ASSERT_EQ(size, sizeof(int) * 8); + ASSERT_EQ_MEM(temp, arr, sizeof(int) * 8); + free(temp); + + // get front fail + size = sizeof(int) * 16; + ASSERT_FALSE(UDPC_Deque_get_front(&deque, (void**)&temp, &size)); + ASSERT_EQ(size, sizeof(int) * 8); + ASSERT_EQ_MEM(temp, arr, sizeof(int) * 8); + free(temp); + + // get back success + size = sizeof(int) * 8; + ASSERT_TRUE(UDPC_Deque_get_back(&deque, (void**)&temp, &size)); + ASSERT_EQ(size, sizeof(int) * 8); + ASSERT_EQ_MEM(temp, arr, sizeof(int) * 8); + free(temp); + + // get back fail + size = sizeof(int) * 16; + ASSERT_FALSE(UDPC_Deque_get_back(&deque, (void**)&temp, &size)); + ASSERT_EQ(size, sizeof(int) * 8); + ASSERT_EQ_MEM(temp, arr, sizeof(int) * 8); + free(temp); + + // index success + for(int x = 0; x < 8; ++x) + { + ASSERT_TRUE(UDPC_Deque_index(&deque, sizeof(int), x, (void**)&temp)); + if(temp) + { + ASSERT_EQ_MEM(temp, &arr[x], sizeof(int)); + free(temp); + } + } + + // index fail + ASSERT_FALSE(UDPC_Deque_index(&deque, sizeof(int), 8, (void**)&temp)); + ASSERT_FALSE(temp); + + // index_rev success + for(int x = 0; x < 8; ++x) + { + ASSERT_TRUE(UDPC_Deque_index_rev(&deque, sizeof(int), x, (void**)&temp)); + if(temp) + { + ASSERT_EQ_MEM(temp, &arr[7 - x], sizeof(int)); + free(temp); + } + } + + // index_rev fail + ASSERT_FALSE(UDPC_Deque_index_rev(&deque, sizeof(int), 8, (void**)&temp)); + ASSERT_FALSE(temp); + + /* + printf("asize %d, size %d, head %d, tail %d\n", + deque.alloc_size, deque.size, deque.head, deque.tail); + */ + + UDPC_Deque_destroy(&deque); + UNITTEST_REPORT() + return 0; +} diff --git a/src/test/UDPC_UnitTest.h b/src/test/UDPC_UnitTest.h new file mode 100644 index 0000000..83e4032 --- /dev/null +++ b/src/test/UDPC_UnitTest.h @@ -0,0 +1,46 @@ +#ifndef UDPC_UNIT_TEST_H +#define UDPC_UNIT_TEST_H + +#include +#include + +/* +#include +*/ + +#define ASSERT_TRUE(x) \ + if(!x) { printf("%d: ASSERT_TRUE(%s) FAILED\n", __LINE__, #x); \ + ++UDPC_uts.failed; } ++UDPC_uts.total; +#define ASSERT_FALSE(x) \ + if(x) { printf("%d: ASSERT_FALSE(%s) FAILED\n", __LINE__, #x); \ + ++UDPC_uts.failed; } ++UDPC_uts.total; +#define ASSERT_EQ(x, y) \ + if(x != y) { printf("%d: ASSERT_EQ(%s, %s) FAILED\n", __LINE__, #x, #y); \ + ++UDPC_uts.failed; } ++UDPC_uts.total; +#define ASSERT_NEQ(x, y) \ + if(x == y) { printf("%d: ASSERT_NEQ(%s, %s) FAILED\n", __LINE__, #x, #y); \ + ++UDPC_uts.failed; } ++UDPC_uts.total; +#define ASSERT_EQ_MEM(x, y, size) \ + if(memcmp(x, y, size) != 0) { printf("%d: ASSERT_EQ_MEM(%s, %s, %s) FAILED\n", \ + __LINE__, #x, #y, #size); ++UDPC_uts.failed; } ++UDPC_uts.total; +#define ASSERT_NEQ_MEM(x, y, size) \ + if(memcmp(x, y, size) == 0) { printf("%d: ASSERT_NEQ_MEM(%s, %s, %s) FAILED\n", \ + __LINE__, #x, #y, #size); ++UDPC_uts.failed; } ++UDPC_uts.total; + +#define UNITTEST_REPORT() printf("%d/%d tests failed\n", UDPC_uts.failed, UDPC_uts.total); + + +typedef struct +{ + int result; +} UnitTest_Test; + +typedef struct +{ + int failed; + int total; +} UnitTestState; + +static UnitTestState UDPC_uts; + +#endif