From 1d0e324c6fc06303686ca50de0674d56afb440b4 Mon Sep 17 00:00:00 2001 From: jmpenn Date: Thu, 5 Oct 2023 13:33:38 -0500 Subject: [PATCH] Fix a variety of bugs found in dllist.c while addressing Issue #1559. (#1577) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix a variety of bugs found in dllist.c while addressing Issue #1559. * Added More descriptive error messages. * Wrote google-test based unit tests for the DLL List library. * Deleted old, incomplete test program. * Added new function DLL_ListContainsPos which determines whether the given list contains the node at the given pos. * DLLFind bug: Added check to determine whether a compare function has been specified, and emit an error message if it hasn’t. * DLL_FindIndex bug: Corrected bounds checking. * DLL_GetAt bug: Added check to ensure that the specified pos is actually in the given list. * DLL_SetAt bug: Added check to ensure that the specified pos is actually in the given list. * DLL_RemoveAt: corrected logic mistake in NULL ptr check. Added check to ensure that the specified pos is actually in the given list. * DLL_InsertBefore bug: element count not correctly updated. * DLL_InsertAfter: next and prev ptrs not correctly updated, which corrupted the list. * DLL_GetNext bug: logic error in NULL ptr checks. Added check to ensure that the specified pos is actually in the given list. * DLL_GetPrev bug: logic error in NULL ptr checks. Added check to ensure that the specified pos is actually in the given list. * DLL_AddHead: Fixed NULL check logic error. * DLL_AddTail: Fixed NULL check logic error. * Address review comments, remove extraneous make target. * Change false to 0 in dllist.c --- .../trick_utils/trick_adt/src/dllist.c | 250 ++-- .../trick_utils/trick_adt/test/Makefile | 60 + .../trick_adt/test/dllist_unittest.cpp | 1051 +++++++++++++++++ .../trick_adt/test_program/makefile | 236 ---- .../trick_utils/trick_adt/test_program/test.c | 103 -- 5 files changed, 1236 insertions(+), 464 deletions(-) create mode 100644 trick_source/trick_utils/trick_adt/test/Makefile create mode 100644 trick_source/trick_utils/trick_adt/test/dllist_unittest.cpp delete mode 100644 trick_source/trick_utils/trick_adt/test_program/makefile delete mode 100644 trick_source/trick_utils/trick_adt/test_program/test.c diff --git a/trick_source/trick_utils/trick_adt/src/dllist.c b/trick_source/trick_utils/trick_adt/src/dllist.c index 810dd176..eaae77fc 100644 --- a/trick_source/trick_utils/trick_adt/src/dllist.c +++ b/trick_source/trick_utils/trick_adt/src/dllist.c @@ -19,12 +19,13 @@ DLLIST *DLL_Create(void) /* initializes a list */ /* return: none */ - +// JMP: This should return a status to let us know whether or not we succeeded void DLL_Delete(DLLIST * list) { if (list == NULL) { - fprintf(stderr, "List is NULL"); + fprintf(stderr, "Error (%s): List is NULL.\n", __FUNCTION__); + fflush(stderr); return; } @@ -34,15 +35,31 @@ void DLL_Delete(DLLIST * list) } } +/* Determine whether the given list contains the node at the given pos. + If it does, return 1, otherwise return 0. +*/ +static int DLL_ListContainsPos( DLLPOS pos, DLLIST * list) { + + if ((list == NULL) || (pos == NULL)) { + return 0; + } + DLLPOS lpos = list->head; + while ((lpos != pos) && (lpos != NULL)) { + lpos = lpos->next; + } + if (lpos == NULL) { + return 0; + } + return 1; +} -/* returns number of elements in list */ -/* return: count */ - +// JMP: This should return a status to let us know whether or not we succeeded void DLL_Init(DLLIST * list) { if (list == NULL) { - fprintf(stderr, "List is NULL"); + fprintf(stderr, "Error (%s): List is NULL.\n", __FUNCTION__); + fflush(stderr); return; } @@ -62,7 +79,8 @@ int DLL_GetCount(DLLIST * list) { if (list == NULL) { - fprintf(stderr, "List is NULL"); + fprintf(stderr, "Error (%s): List is NULL.\n", __FUNCTION__); + fflush(stderr); return -1; } @@ -80,9 +98,14 @@ void *DLL_Find(void *data, DLLIST * list) { DLLPOS pos; - if (list == NULL) { - fprintf(stderr, "List is NULL"); + fprintf(stderr, "Error (%s): List is NULL.\n", __FUNCTION__); + fflush(stderr); + return NULL; + } + if (list->compare == NULL) { + fprintf(stderr, "Error (%s): List doesn't have a compare function.\n", __FUNCTION__); + fflush(stderr); return NULL; } @@ -105,7 +128,8 @@ DLLPOS DLL_FindPos(void *data, DLLIST * list) if (list == NULL) { - fprintf(stderr, "List is NULL"); + fprintf(stderr, "Error (%s): List is NULL.\n", __FUNCTION__); + fflush(stderr); return NULL; } @@ -122,6 +146,7 @@ DLLPOS DLL_FindPos(void *data, DLLIST * list) /* find position at given index */ /* return: position of nth element */ + DLLPOS DLL_FindIndex(int n, DLLIST * list) { int nPos = 0; @@ -129,13 +154,14 @@ DLLPOS DLL_FindIndex(int n, DLLIST * list) if (list == NULL) { - fprintf(stderr, "List is NULL"); + fprintf(stderr, "Error (%s): List is NULL.\n", __FUNCTION__); + fflush(stderr); return NULL; } - - if (n < 0 && n >= list->count) { - fprintf(stderr, "Index is either negative or exceeds the number of elements in the list"); + if ( (n < 0) || (n >= list->count) ) { + fprintf(stderr, "Error (%s): Index is either negative or exceeds the number of elements in the list.\n", __FUNCTION__); + fflush(stderr); return NULL; } @@ -154,22 +180,17 @@ DLLPOS DLL_FindIndex(int n, DLLIST * list) void *DLL_GetAt(DLLPOS pos, DLLIST * list) { - - if (list == NULL) { - fprintf(stderr, "List is NULL"); + if ((list == NULL) || (pos == NULL)) { + fprintf(stderr, "Error (%s): Either pos, list, or both are NULL.\n", __FUNCTION__); + fflush(stderr); return NULL; } - - - if (pos == NULL) { - fprintf(stderr, "Position is NULL"); + if ( !DLL_ListContainsPos(pos, list) ) { + fprintf(stderr, "Error (%s): The specified list doesn't contain the specified node (pos).\n", __FUNCTION__); + fflush(stderr); return NULL; } - - if (list) { - return pos->info; - } - return (NULL); + return pos->info; } @@ -178,21 +199,19 @@ void *DLL_GetAt(DLLPOS pos, DLLIST * list) void *DLL_SetAt(DLLPOS pos, void *info, DLLIST * list) { - - void *ret; - - - if (pos == NULL && list == NULL) { - fprintf(stderr, "List and Position are NULL"); + if ((list == NULL) || (pos == NULL)) { + fprintf(stderr, "Error (%s): Either pos, list, or both are NULL.\n", __FUNCTION__); + fflush(stderr); return NULL; } - - if (pos != NULL && list != NULL) { - ret = pos->info; - pos->info = info; - return ret; + if ( !DLL_ListContainsPos(pos, list) ) { + fprintf(stderr, "Error (%s): The specified list doesn't contain the specified node (pos).\n", __FUNCTION__); + fflush(stderr); + return NULL; } - return (NULL); + void* prev_info = pos->info; + pos->info = info; + return prev_info; } @@ -203,34 +222,37 @@ void *DLL_RemoveAt(DLLPOS pos, DLLIST * list) { void *ret; - - if (pos == NULL && list == NULL) { - fprintf(stderr, "List and Position are NULL"); + if ((pos == NULL) || (list == NULL)) { + fprintf(stderr, "Error (%s): List or Position is NULL.\n", __FUNCTION__); + fflush(stderr); return NULL; } - if (pos != NULL && list != NULL) { - list->count--; - if (pos->prev != NULL) { - pos->prev->next = pos->next; - if (pos->next != NULL) - pos->next->prev = pos->prev; - else - list->tail = pos->prev; - } else if (pos->next != NULL) { - list->head = pos->next; - pos->next->prev = NULL; - } else { - list->head = NULL; - list->tail = NULL; - } - ret = pos->info; - - free(pos); - return ret; - + if ( !DLL_ListContainsPos(pos, list) ) { + fprintf(stderr, "Error (%s): The specified list doesn't contain the specified node (pos).\n", __FUNCTION__); + fflush(stderr); + return NULL; } - return (NULL); + + if (pos->prev != NULL) { // check whether pos is the head + pos->prev->next = pos->next; // pos is not the head + if (pos->next != NULL) // check whether pos is the tail + pos->next->prev = pos->prev; // pos is not the tail + else + list->tail = pos->prev; // pos is the tail + } else if (pos->next != NULL) { // pos is the head, check whether it's also the tail + list->head = pos->next; // pos not the tail + pos->next->prev = NULL; + } else { // pos is both the head and the tail + list->head = NULL; + list->tail = NULL; + } + + list->count --; + ret = pos->info; + free(pos); + return ret; + } @@ -244,7 +266,8 @@ void DLL_RemoveAll(DLLIST * list) if (list == NULL) { - fprintf(stderr, "List is NULL"); + fprintf(stderr, "Error (%s): List is NULL.\n", __FUNCTION__); + fflush(stderr); return; } @@ -263,13 +286,6 @@ DLLPOS DLL_InsertBefore(DLLPOS pos, void *data, DLLIST * list) { if (pos != NULL && list != NULL) { DLLPOS newpos = (DLLPOS) malloc(sizeof(DLLNODE)); - - - if (pos == NULL && list == NULL) { - fprintf(stderr, "List and Position are NULL"); - return NULL; - } - newpos->info = data; if (pos->prev == NULL) { newpos->next = list->head; @@ -282,8 +298,11 @@ DLLPOS DLL_InsertBefore(DLLPOS pos, void *data, DLLIST * list) newpos->next = pos; pos->prev = newpos; } + list->count++; return newpos; } + fprintf(stderr, "Error (%s): Either List, Position, or both are NULL.\n", __FUNCTION__); + fflush(stderr); return (NULL); } @@ -295,16 +314,9 @@ DLLPOS DLL_InsertAfter(DLLPOS pos, void *data, DLLIST * list) { if (pos != NULL && list != NULL) { DLLPOS newpos = (DLLPOS) malloc(sizeof(DLLNODE)); - - - if (pos == NULL && list == NULL) { - fprintf(stderr, "List and Position are NULL"); - return NULL; - } - newpos->info = data; if (pos->next == NULL) { - newpos->next = list->tail; + newpos->prev = list->tail; newpos->next = NULL; list->tail = newpos; pos->next = newpos; @@ -314,57 +326,54 @@ DLLPOS DLL_InsertAfter(DLLPOS pos, void *data, DLLIST * list) newpos->prev = pos; pos->next = newpos; } + list->count++; return newpos; } - + fprintf(stderr, "Error (%s): Either List, Position, or both are NULL.\n", __FUNCTION__); + fflush(stderr); return (NULL); } - /* gets the next position in the list */ /* return: the data at the current pos */ -void *DLL_GetNext(DLLPOS * pos, DLLIST * list) +void *DLL_GetNext(DLLPOS* pos_p, DLLIST * list) { - void *ret; - - - if (pos == NULL && list == NULL) { - fprintf(stderr, "List and Position are NULL"); + if ((list == NULL) || (pos_p == NULL)) { + fprintf(stderr, "Error (%s): Either the List, the Position pointer, or both are NULL.\n", __FUNCTION__); + fflush(stderr); + return (NULL); + } + if ( !DLL_ListContainsPos(*pos_p, list) ) { + fprintf(stderr, "Error (%s): List doesn't contain a node at the given position.\n", __FUNCTION__); + fflush(stderr); return NULL; } - - if (pos != NULL && list != NULL) { - ret = (*pos)->info; - *pos = (*pos)->next; - return ret; - } - return (NULL); + void* data = (*pos_p)->info; + *pos_p = (*pos_p)->next; + return data; } - /* gets the previous position in the list */ /* return: the data at the current position */ -void *DLL_GetPrev(DLLPOS * pos, DLLIST * list) +void *DLL_GetPrev(DLLPOS * pos_p, DLLIST * list) { - void *ret; - - - if (pos == NULL && list == NULL) { - fprintf(stderr, "List and Position are NULL"); + if ((list == NULL) || (pos_p == NULL)) { + fprintf(stderr, "Error (%s): Either the List, the Position pointer, or both are NULL.\n", __FUNCTION__); + fflush(stderr); + return (NULL); + } + if ( !DLL_ListContainsPos(*pos_p, list) ) { + fprintf(stderr, "Error (%s): List doesn't contain a node at the given position.\n", __FUNCTION__); + fflush(stderr); return NULL; } - - if (pos != NULL && list != NULL) { - ret = (*pos)->info; - *pos = (*pos)->prev; - return ret; - } - return (NULL); + void* data = (*pos_p)->info; + *pos_p = (*pos_p)->prev; + return data; } - /* adds an element to the head of the list */ /* return: the position of the new element */ @@ -372,13 +381,6 @@ DLLPOS DLL_AddHead(void *data, DLLIST * list) { if (list != NULL) { DLLPOS newpos = (DLLPOS) malloc(sizeof(DLLNODE)); - - - if (list == NULL) { - fprintf(stderr, "List is NULL"); - return NULL; - } - newpos->info = data; if (list->head == NULL) { list->head = newpos; @@ -394,6 +396,8 @@ DLLPOS DLL_AddHead(void *data, DLLIST * list) list->count++; return newpos; } + fprintf(stderr, "Error (%s): List is NULL.\n", __FUNCTION__); + fflush(stderr); return (NULL); } @@ -405,13 +409,6 @@ DLLPOS DLL_AddTail(void *data, DLLIST * list) { if (list != NULL) { DLLPOS newpos = (DLLPOS) malloc(sizeof(DLLNODE)); - - - if (list == NULL) { - fprintf(stderr, "List is NULL"); - return NULL; - } - newpos->info = data; if (list->tail == NULL) { list->head = newpos; @@ -427,6 +424,8 @@ DLLPOS DLL_AddTail(void *data, DLLIST * list) list->count++; return newpos; } + fprintf(stderr, "Error (%s): List is NULL.\n", __FUNCTION__); + fflush(stderr); return (NULL); } @@ -438,7 +437,8 @@ DLLPOS DLL_GetHeadPosition(DLLIST * list) { if (list == NULL) { - fprintf(stderr, "List is NULL"); + fprintf(stderr, "Error (%s): List is NULL.\n", __FUNCTION__); + fflush(stderr); return NULL; } @@ -454,9 +454,9 @@ DLLPOS DLL_GetHeadPosition(DLLIST * list) DLLPOS DLL_GetTailPosition(DLLIST * list) { - if (list == NULL) { - fprintf(stderr, "List is NULL"); + fprintf(stderr, "Error (%s): List is NULL.\n", __FUNCTION__); + fflush(stderr); return NULL; } diff --git a/trick_source/trick_utils/trick_adt/test/Makefile b/trick_source/trick_utils/trick_adt/test/Makefile new file mode 100644 index 00000000..82d593e2 --- /dev/null +++ b/trick_source/trick_utils/trick_adt/test/Makefile @@ -0,0 +1,60 @@ +#SYNOPSIS: +# +# make [all] - makes everything. +# make TARGET - makes the given target. +# make clean - removes all files generated by make. + +include ${TRICK_HOME}/share/trick/makefiles/Makefile.common + +# Flags passed to the preprocessor. +TRICK_CXXFLAGS += -I$(GTEST_HOME)/include -I$(TRICK_HOME)/include -g -Wall -Wextra ${TRICK_SYSTEM_CXXFLAGS} ${TRICK_TEST_FLAGS} + +TRICK_LIBS = ${TRICK_LIB_DIR}/libtrick.a +TRICK_EXEC_LINK_LIBS += -L${GTEST_HOME}/lib64 -L${GTEST_HOME}/lib -lgtest -lgtest_main -lpthread + +# Added for Ubuntu... not required for other systems. +TRICK_EXEC_LINK_LIBS += -lpthread + +# ================================================================================== +# All tests produced by this Makefile. Add new tests you create to this list. +# ================================================================================== +TESTS = dllist_unittest + +# List of XML files produced by the tests. +unittest_results = $(patsubst %,%.xml,$(TESTS)) + +# List if Test-specific object files. +unittest_objects = $(patsubst %,%.o,$(TESTS)) + +# House-keeping build targets. + +# ================================================================================== +# TARGETS +# ================================================================================== +all : test + +test: unit_tests $(unittest_results) + +unit_tests: $(TESTS) + +clean : + rm -f $(TESTS) + rm -f *.o + +# ================================================================================== +# Generate JUNIT (XML) Test Results +# ================================================================================== +$(unittest_results): %.xml: % + ./$< --gtest_output=xml:${TRICK_HOME}/trick_test/$@ + +# ================================================================================== +# Build Unit test Objects +# ================================================================================== +$(unittest_objects): %.o: %.cpp + $(TRICK_CXX) $(TRICK_CXXFLAGS) -c $< + +# ================================================================================== +# Build Unit test programs +# ================================================================================== +$(TESTS) : %: %.o + $(TRICK_CXX) $(TRICK_SYSTEM_LDFLAGS) -o $@ $^ -L${TRICK_HOME}/lib_${TRICK_HOST_CPU} $(TRICK_LIBS) $(TRICK_EXEC_LINK_LIBS) diff --git a/trick_source/trick_utils/trick_adt/test/dllist_unittest.cpp b/trick_source/trick_utils/trick_adt/test/dllist_unittest.cpp new file mode 100644 index 00000000..0d7f5b83 --- /dev/null +++ b/trick_source/trick_utils/trick_adt/test/dllist_unittest.cpp @@ -0,0 +1,1051 @@ +#include +#include +#include "trick/dllist.h" + +/* ========================================================================== +DLL_Delete deletes all of the nodes, and then the list. Returns Nothing. +PROTOTYPE: + void DLL_Delete(DLLIST*); + +NOTE: The following test, "DLL_Delete_null_list" exercises error handling + behavior. DLL_Delete is called in numerous other test cases below. +*/ + +TEST( dllist_test, DLL_Delete_null_list) { + std::cout << "NOTE: An error message is expected to follow." << std::endl; + DLL_Init( nullptr); + // ALAS, there is nothing to check. +} + +/* ========================================================================== +DLL_Create allocates and initializes an empty DLLIST object. Returns +the initialized list object. +PROTOTYPE: + DLLIST* DLL_Create(); +*/ + +TEST( dllist_test, DLL_Create) { + + DLLIST* result = DLL_Create(); + + EXPECT_NE(result, nullptr); + EXPECT_EQ(result->count, 0); + EXPECT_EQ(result->head, nullptr); + EXPECT_EQ(result->tail, nullptr); + EXPECT_EQ(result->compare, nullptr); + + DLL_Delete(result); +} + +/* ========================================================================== +DLL_Init +Initializes an empty DLLIST object. +Returns nothing. + +PROTOTYPE: + void DLL_Init(DLLIST * list) +*/ + +TEST( dllist_test, DLL_Init) { + + DLLIST list; + DLL_Init( &list); + + EXPECT_EQ(list.count, 0); + EXPECT_EQ(list.head, nullptr); + EXPECT_EQ(list.tail, nullptr); + EXPECT_EQ(list.compare, nullptr); + +} + +TEST( dllist_test, DLL_Init_null_list) { + std::cout << "NOTE: An error message is expected to follow." << std::endl; + DLL_Init( nullptr); + + // ALAS, there is nothing to check. +} + +/* ========================================================================== +DLL_GetCount returns the number of elements in the given list, unless list is +null, in which case it returns -1. +PROTOTYPE: + int DLL_GetCount(DLLIST* list); + +NOTE: The following test, "DLL_GetCount_null_list" tests error handling +behavior. Normal behavior of DLL_GetCount is tested in: "DLL_AddHead", +"DLL_AddTail", "DLL_InsertBefore", and "DLL_InsertAfter". +*/ + +TEST( dllist_test, DLL_GetCount_null_list) { + std::cout << "NOTE: An error message is expected to follow." << std::endl; + int result = DLL_GetCount(nullptr); + EXPECT_EQ(result, -1); +} + +/* ========================================================================== +DLL_GetHeadPosition returns a the head node position of the given list, +unless the list is null, in which case it returns NULL. +PROTOTYPE: + DLLPOS DLL_GetHeadPosition(DLLIST* list); + +NOTE: The following test, "DLL_GetHeadPosition_null_list" tests error handling +behavior. Normal behavior of DLL_GetHeadPosition is tested in: "DLL_AddHead", +"DLL_AddTail", "DLL_InsertBefore", and "DLL_InsertAfter". +*/ + +TEST( dllist_test, DLL_GetHeadPosition_null_list) { + std::cout << "NOTE: An error message is expected to follow." << std::endl; + DLLPOS result = DLL_GetHeadPosition(nullptr); + EXPECT_EQ(result, nullptr); +} + +/* ========================================================================== +DLL_GetTailPosition returns a the tail node position of the given list, +unless the list is null, in which case it returns NULL. +PROTOTYPE: + DLLPOS DLL_GetTailPosition(DLLIST* list); + +NOTE: The error case is tested in "DLL_GetTailPosition_null_list". +Normal behavior is tested in: "DLL_AddHead", "DLL_AddTail", +"DLL_InsertBefore", and "DLL_InsertAfter". +*/ + +TEST( dllist_test, DLL_GetTailPosition_null_list) { + std::cout << "NOTE: An error message is expected to follow." << std::endl; + DLLPOS result = DLL_GetTailPosition(nullptr); + EXPECT_EQ(result, nullptr); +} + +/* ========================================================================== +DLL_AddHead inserts an element at the head of the given list, and returns +a pointer to a new node. If the given list is NULL, an error message is printed +and the function returns NULL. + +PROTOTYPE: + DLLPOS DLL_AddHead(void* element, DLLIST* list); +*/ + +TEST( dllist_test, DLL_AddHead) { + + int A[] = {1,2,3,4,5}; + + /* Create a list. */ + DLLIST* list = DLL_Create(); + EXPECT_NE(list, nullptr); + + /* Add a node to the list. */ + DLLPOS pos_first = DLL_AddHead( &A[0], list); + + /* List State after call. + H [first] T + */ + + EXPECT_NE(pos_first, nullptr); + EXPECT_EQ(pos_first->info, &A[0]); + EXPECT_EQ(pos_first->prev, nullptr); + EXPECT_EQ(pos_first->next, nullptr); + EXPECT_EQ(pos_first, list->head); + EXPECT_EQ(pos_first, list->tail); + + /* Add a second node to the list. */ + DLLPOS pos_second = DLL_AddHead( &A[1], list); + + /* Expected List State after call. + H [second]=[first] T + */ + + EXPECT_NE(pos_second, nullptr); + EXPECT_EQ(pos_second->info, &A[1]); + + EXPECT_EQ(pos_first->prev, pos_second); + EXPECT_EQ(pos_first->next, nullptr); + EXPECT_EQ(pos_second->prev, nullptr); + EXPECT_EQ(pos_second->next, pos_first); + + EXPECT_EQ(pos_second, list->head); + EXPECT_EQ(pos_first, list->tail); + + /* Add a third node to the list. */ + DLLPOS pos_third = DLL_AddHead( &A[2], list); + + /* Expected List State after call. + H [third]=[second]=[first] T + */ + + EXPECT_NE(pos_third, nullptr); + EXPECT_EQ(pos_third->info, &A[2]); + EXPECT_EQ(pos_first->prev, pos_second); + EXPECT_EQ(pos_first->next, nullptr); + EXPECT_EQ(pos_second->prev, pos_third); + EXPECT_EQ(pos_second->next, pos_first); + EXPECT_EQ(pos_third->prev, nullptr); + EXPECT_EQ(pos_third->next, pos_second); + + EXPECT_EQ(pos_third, list->head); + EXPECT_EQ(pos_third, DLL_GetHeadPosition(list)); + EXPECT_EQ(pos_first, list->tail); + EXPECT_EQ(pos_first, DLL_GetTailPosition(list)); + + EXPECT_EQ(list->count, 3); + EXPECT_EQ( DLL_GetCount(list), 3); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_AddHead_null_list) { + int A[] = {1,2,3,4,5}; + std::cout << "NOTE: An error message is expected to follow." << std::endl; + DLLPOS result = DLL_AddHead( &A[0], nullptr); + EXPECT_EQ(result, nullptr); +} + +/* ========================================================================== +DLL_AddTail inserts an element at the tail of the given list, and returns +a pointer to a new node. If the given list is NULL, an error message is printed +and the functions returns NULL. + +PROTOTYPE: + DLLPOS DLL_AddTail(void* element, DLLIST* list); +*/ + +TEST( dllist_test, DLL_AddTail) { + + int A[] = {1,2,3,4,5}; // These elements will be added to a list. + DLLIST* list = DLL_Create(); // Create an empty list to add things to. + EXPECT_NE(list, nullptr); // It better not be null. + + /* Add a node to the list. */ + DLLPOS pos_first = DLL_AddTail( &A[0], list); + + /* List State after call. + H [first] T + */ + + EXPECT_NE(pos_first, nullptr); + EXPECT_EQ(pos_first->info, &A[0]); + + EXPECT_EQ(pos_first->prev, nullptr); + EXPECT_EQ(pos_first->next, nullptr); + + /* ===== Add a second node to the list. ===== */ + DLLPOS pos_second = DLL_AddTail( &A[1], list); + + /* Expected List State after call. + H [first]=[second] T + */ + + EXPECT_NE(pos_second, nullptr); + EXPECT_EQ(pos_second->info, &A[1]); + + EXPECT_EQ(pos_first->prev, nullptr); + EXPECT_EQ(pos_first->next, pos_second); + EXPECT_EQ(pos_second->prev, pos_first); + EXPECT_EQ(pos_second->next, nullptr); + + /* ===== CALL: Add a third node to the list. ===== */ + DLLPOS pos_third = DLL_AddTail( &A[2], list); + + /* Expected List State after call. + H [first]=[second]==[third] T + */ + + EXPECT_NE(pos_third, nullptr); + EXPECT_EQ(pos_third->info, &A[2]); + + EXPECT_EQ(pos_first->prev, nullptr); + EXPECT_EQ(pos_first->next, pos_second); + EXPECT_EQ(pos_second->prev, pos_first); + EXPECT_EQ(pos_second->next, pos_third); + EXPECT_EQ(pos_third->prev, pos_second); + EXPECT_EQ(pos_third->next, nullptr); + + EXPECT_EQ(pos_first, list->head); + EXPECT_EQ(pos_first, DLL_GetHeadPosition(list)); + EXPECT_EQ(pos_third, list->tail); + EXPECT_EQ(pos_third, DLL_GetTailPosition(list)); + + EXPECT_EQ(list->count, 3); + EXPECT_EQ( DLL_GetCount(list), 3); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_AddTail_null_list) { + int A[] = {1,2,3,4,5}; + std::cout << "NOTE: An error message is expected to follow." << std::endl; + DLLPOS result = DLL_AddTail( &A[0], nullptr); + EXPECT_EQ(result, nullptr); +} + +/* ========================================================================== +DLL_InsertBefore inserts the given data element before the given position, of +the given list. Returns the position of the inserted element node. + +PROTOTYPE: + DLLPOS DLL_InsertBefore(DLLPOS pos, void* element, DLLIST* list); +*/ + +TEST( dllist_test, DLL_InsertBefore) { + + int A[] = {1,2,3,4,5}; + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddHead( &A[0], list); + DLLPOS pos_second = DLL_AddHead( &A[1], list); + + /* Initial List State + H [second]=[first] T + */ + + /* ===== CALL: Add a third node to the list. ===== */ + DLLPOS pos_third = DLL_InsertBefore(pos_first, &A[2], list); + + /* Expected List State after the call: + H [second]=[third]=[first] T + */ + + EXPECT_NE(pos_third, nullptr); + EXPECT_EQ(pos_third->info, &A[2] ); + + EXPECT_EQ(pos_first->prev, pos_third ); + EXPECT_EQ(pos_first->next, nullptr ); + EXPECT_EQ(pos_second->prev, nullptr ); + EXPECT_EQ(pos_second->next, pos_third ); + EXPECT_EQ(pos_third->prev, pos_second ); + EXPECT_EQ(pos_third->next, pos_first ); + + /* ===== CALL: Add a fourth node to the beginning of the list. ===== */ + DLLPOS pos_fourth = DLL_InsertBefore(pos_second, &A[3], list); + + /* Expected List State after the call: + H [fourth]=[second]=[third]=[first] T + */ + + EXPECT_NE(pos_fourth, nullptr); + EXPECT_EQ(pos_fourth->info, &A[3] ); + + EXPECT_EQ(pos_first->prev, pos_third ); + EXPECT_EQ(pos_first->next, nullptr ); + EXPECT_EQ(pos_second->prev, pos_fourth ); + EXPECT_EQ(pos_second->next, pos_third ); + EXPECT_EQ(pos_third->prev, pos_second ); + EXPECT_EQ(pos_third->next, pos_first ); + EXPECT_EQ(pos_fourth->next, pos_second ); + EXPECT_EQ(pos_fourth->prev, nullptr ); + + EXPECT_EQ(pos_fourth, list->head); + EXPECT_EQ(pos_fourth, DLL_GetHeadPosition(list)); + EXPECT_EQ(pos_first, list->tail); + EXPECT_EQ(pos_first, DLL_GetTailPosition(list)); + + EXPECT_EQ(list->count, 4); + EXPECT_EQ( DLL_GetCount(list), 4); + + DLL_Delete(list); +} + +/* ========================================================================== +DLL_InsertAfter inserts the given data element after the given position, of +the given list. Returns the position of the inserted element node. + +PROTOTYPE: + DLLPOS DLL_InsertBefore(DLLPOS pos, void* element, DLLIST* list); +============================================================================= +*/ +TEST( dllist_test, DLL_InsertAfter) { + + int A[] = {1,2,3,4,5}; + + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddHead( &A[0], list); + DLLPOS pos_second = DLL_AddHead( &A[1], list); + + /* Initial List State + H [second]=[first] T + */ + + /* Add a third node. */ + DLLPOS pos_third = DLL_InsertAfter(pos_first, &A[2], list); + + /* Expected State of List after the call: + H [second]=[first]=[third] T + */ + + EXPECT_NE(pos_third, nullptr); + EXPECT_EQ(pos_third->info, &A[2] ); + + EXPECT_EQ(pos_first->prev, pos_second ); + EXPECT_EQ(pos_first->next, pos_third ); + EXPECT_EQ(pos_second->prev, nullptr ); + EXPECT_EQ(pos_second->next, pos_first ); + EXPECT_EQ(pos_third->prev, pos_first ); + EXPECT_EQ(pos_third->next, nullptr ); + + /* ===== CALL: Add a fourth node ===== */ + DLLPOS pos_fourth = DLL_InsertAfter(pos_second, &A[3], list); + + /* Expected State of List after the call: + H [second]=[fourth]=[first]=[third] T + */ + + EXPECT_NE(pos_fourth, nullptr); + EXPECT_EQ(pos_fourth->info, &A[3] ); + + EXPECT_EQ(pos_first->prev, pos_fourth ); + EXPECT_EQ(pos_first->next, pos_third ); + EXPECT_EQ(pos_second->prev, nullptr ); + EXPECT_EQ(pos_second->next, pos_fourth ); + EXPECT_EQ(pos_third->prev, pos_first ); + EXPECT_EQ(pos_third->next, nullptr ); + EXPECT_EQ(pos_fourth->next, pos_first ); + EXPECT_EQ(pos_fourth->prev, pos_second ); + + EXPECT_EQ(pos_second, list->head); + EXPECT_EQ(pos_second, DLL_GetHeadPosition(list)); + EXPECT_EQ(pos_third, list->tail); + EXPECT_EQ(pos_third, DLL_GetTailPosition(list)); + + EXPECT_EQ(list->count, 4); + EXPECT_EQ( DLL_GetCount(list), 4); + + DLL_Delete(list); +} + +/* ========================================================================== +DLL_GetNext returns a pointer to the data of the DLLPOS pointed +to by pos_p, and updates the DLLPOS referenced by pos_p to the +next DLLPOS in the linked list. + +PROTOTYPE: + void* DLL_GetNext(DLLPOS* pos_p ,DLLIST*); +=============================================================================*/ + +TEST( dllist_test, DLL_GetNext) { + + int A[] = {1,2,3,4,5}; + + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddTail( &(A[0]), list); + (void) DLL_AddTail( &(A[1]), list); + (void) DLL_AddTail( &(A[2]), list); + (void) DLL_AddTail( &(A[3]), list); + (void) DLL_AddTail( &(A[4]), list); + + /* Expected List State after call. + H [first]=[second]=[third]=[fourth]=[fifth] T + | | | | | + [1] [2] [3] [4] [5] + */ + + DLLPOS current_pos = pos_first; + + int *result; + result = (int*)DLL_GetNext(¤t_pos, list); + EXPECT_NE(current_pos, nullptr); + EXPECT_EQ(*result, 1); + result = (int*)DLL_GetNext(¤t_pos, list); + EXPECT_EQ(*result, 2); + EXPECT_NE(current_pos, nullptr); + result = (int*)DLL_GetNext(¤t_pos, list); + EXPECT_EQ(*result, 3); + EXPECT_NE(current_pos, nullptr); + result = (int*)DLL_GetNext(¤t_pos, list); + EXPECT_EQ(*result, 4); + EXPECT_NE(current_pos, nullptr); + result = (int*)DLL_GetNext(¤t_pos, list); + EXPECT_EQ(*result, 5); + EXPECT_EQ(current_pos, nullptr); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_GetNext_null_pos) { + int A[] = {1,2,3,4,5}; + DLLIST* list = DLL_Create(); + (void) DLL_AddTail( &(A[0]), list); + (void) DLL_AddTail( &(A[1]), list); + + std::cout << "NOTE: An error message is expected to follow." << std::endl; + void* result = DLL_GetNext(nullptr, list); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_GetNext_null_list) { + int A[] = {1,2,3,4,5}; + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddTail( &(A[0]), list); + (void) DLL_AddTail( &(A[1]), list); + DLLPOS current_pos = pos_first; + + std::cout << "NOTE: An error message is expected to follow." << std::endl; + void* result = DLL_GetNext(¤t_pos, nullptr); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + + +/* ========================================================================== +DLL_GetPrev returns a pointer to the node data of the DLLPOS pointed +to by pos_p, and updates the DLLPOS referenced by pos_p to the +previous DLLPOS in the linked list. +PROTOTYPE: + void* DLL_GetPrev(DLLPOS* pos_p ,DLLIST*); +=============================================================================*/ + +TEST( dllist_test, DLL_GetPrev) { + + int A[] = {1,2,3,4,5}; + + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddHead( &(A[0]), list); + (void) DLL_AddHead( &(A[1]), list); + (void) DLL_AddHead( &(A[2]), list); + (void) DLL_AddHead( &(A[3]), list); + (void) DLL_AddHead( &(A[4]), list); + + /* Expected List State. + H [fifth]=[fourth]=[third]=[second]=[first] T + | | | | | + [5] [4] [3] [2] [1] + */ + + DLLPOS current_pos = pos_first; + + int *result; + result = (int*)DLL_GetPrev(¤t_pos, list); + EXPECT_NE(current_pos, nullptr); + EXPECT_EQ(*result, 1); + result = (int*)DLL_GetPrev(¤t_pos, list); + EXPECT_EQ(*result, 2); + EXPECT_NE(current_pos, nullptr); + result = (int*)DLL_GetPrev(¤t_pos, list); + EXPECT_EQ(*result, 3); + EXPECT_NE(current_pos, nullptr); + result = (int*)DLL_GetPrev(¤t_pos, list); + EXPECT_EQ(*result, 4); + EXPECT_NE(current_pos, nullptr); + result = (int*)DLL_GetPrev(¤t_pos, list); + EXPECT_EQ(*result, 5); + EXPECT_EQ(current_pos, nullptr); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_GetPrev_null_pos) { + int A[] = {1,2,3,4,5}; + DLLIST* list = DLL_Create(); + (void) DLL_AddHead( &(A[0]), list); + (void) DLL_AddHead( &(A[1]), list); + + std::cout << "NOTE: An error message is expected to follow." << std::endl; + /* Call function under test with pos == NULL. */ + void* result = DLL_GetPrev(nullptr, list); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_GetPrev_null_list) { + int A[] = {1,2,3,4,5}; + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddHead( &(A[0]), list); + (void) DLL_AddHead( &(A[1]), list); + DLLPOS current_pos = pos_first; + + std::cout << "NOTE: An error message is expected to follow." << std::endl; + /* Call function under test with list == NULL. */ + void* result = DLL_GetPrev(¤t_pos, nullptr); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +/* ========================================================================== +DLL_Find returns a pointer to data stored in the list that matches the +specified data. Return NULL if the list is NULL, or if the specified data is +not found in the list. + +DLL_Find requires that a pointer to a compare function must be set in the +DLLIST structure. The prototype of a suitable compare function is: + int (*compare)(void* info1,void* info2); +The function should return 1 if the data match or 0 if they don't. + +The test below can serve as an example. + +PROTOTYPE: + void* DLL_Find(void* data, DLLIST* list); +=============================================================================*/ + +/* The following is a comparison function used in the DLL_Find test. */ +int IntCompare(void* a, void* b ) { + if ( *(int*)a == *(int*)b ) { + return 1; + } else { + return 0; + } +} + +TEST( dllist_test, DLL_Find) { + int A[] = {1,2,3,4,5}; + int waldo = 0; + void* result = nullptr; + + DLLIST* list = DLL_Create(); + (void) DLL_AddHead( &(A[0]), list); + (void) DLL_AddHead( &(A[1]), list); + (void) DLL_AddHead( &(A[2]), list); + (void) DLL_AddHead( &(A[3]), list); + (void) DLL_AddHead( &(A[4]), list); + + // DLL_Find requires the list to have a compare function. + list->compare = &IntCompare; + + waldo = 1; + result = DLL_Find( &waldo, list ); + EXPECT_EQ(result, &(A[0])); + waldo = 2; + result = DLL_Find( &waldo, list ); + EXPECT_EQ(result, &(A[1])); + waldo = 3; + result = DLL_Find( &waldo, list ); + EXPECT_EQ(result, &(A[2])); + waldo = 4; + result = DLL_Find( &waldo, list ); + EXPECT_EQ(result, &(A[3])); + waldo = 5; + result = DLL_Find( &waldo, list ); + EXPECT_EQ(result, &(A[4])); + waldo = 7; + result = DLL_Find( &waldo, list ); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_Find_null_list) { + int waldo = 1; + std::cout << "NOTE: An error message is expected to follow." << std::endl; + /* Call function under test with list == NULL. */ + void* result = DLL_Find(&waldo, nullptr); + EXPECT_EQ(result, nullptr); +} + +TEST( dllist_test, DLL_Find_null_compare_function) { + int A[] = {1,2,3,4,5}; + + DLLIST* list = DLL_Create(); + (void) DLL_AddHead( &(A[0]), list); + (void) DLL_AddHead( &(A[1]), list); + + int waldo = 1; + void* result = DLL_Find( &waldo, list ); + std::cout << "NOTE: An error message is expected to follow." << std::endl; + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +/* ========================================================================== +DLL_GetAt returns a pointer to the data of the node specified by pos. +Return NULL if list is NULL, pos is NULL, or if the node specified by pos is +not contained in the list. +PROTOTYPE: + void* DLL_GetAt(DLLPOS pos, DLLIST* list); +*/ + +TEST( dllist_test, DLL_GetAt) { + int A[] = {1,2,3,4,5}; + int* result; + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddHead( &(A[0]), list); + DLLPOS pos_second = DLL_AddHead( &(A[1]), list); + DLLPOS pos_third = DLL_AddHead( &(A[2]), list); + DLLPOS pos_fourth = DLL_AddHead( &(A[3]), list); + DLLPOS pos_fifth = DLL_AddHead( &(A[4]), list); + + result = (int*)DLL_GetAt( pos_first, list ); + EXPECT_EQ(*result, 1); + result = (int*)DLL_GetAt( pos_second, list ); + EXPECT_EQ(*result, 2); + result = (int*)DLL_GetAt( pos_third, list ); + EXPECT_EQ(*result, 3); + result = (int*)DLL_GetAt( pos_fourth, list ); + EXPECT_EQ(*result, 4); + result = (int*)DLL_GetAt( pos_fifth, list ); + EXPECT_EQ(*result, 5); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_GetAt_null_list) { + int A[] = {1,2,3,4,5}; + int* result; + + DLLIST* null_list = nullptr; + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddHead( &(A[0]), list); + (void) DLL_AddHead( &(A[1]), list); + + std::cout << "NOTE: An error message is expected to follow." << std::endl; + result = (int*)DLL_GetAt( pos_first, null_list ); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_GetAt_null_pos) { + int A[] = {1,2,3,4,5}; + int* result; + DLLPOS null_pos = nullptr; + DLLIST* list = DLL_Create(); + (void) DLL_AddHead( &(A[0]), list); + (void) DLL_AddHead( &(A[1]), list); + + std::cout << "NOTE: An error message is expected to follow." << std::endl; + result = (int*)DLL_GetAt( null_pos, list ); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_GetAt_list_doesnt_contain_node) { + int A[] = {1,2,3,4,5}; + int* result; + + DLLIST* list1 = DLL_Create(); + DLLPOS pos_in_list1 = DLL_AddHead( &(A[0]), list1); + DLLIST* list2 = DLL_Create(); + DLLPOS pos_in_list2 = DLL_AddHead( &(A[0]), list2); + + // These work. + result = (int*)DLL_GetAt( pos_in_list1, list1 ); + EXPECT_EQ(*result, 1); + result = (int*)DLL_GetAt( pos_in_list2, list2 ); + EXPECT_EQ(*result, 1); + + // These don't. + std::cout << "NOTE: An error message is expected to follow." << std::endl; + result = (int*)DLL_GetAt( pos_in_list1, list2 ); + EXPECT_EQ(result, nullptr); + std::cout << "NOTE: An error message is expected to follow." << std::endl; + result = (int*)DLL_GetAt( pos_in_list2, list1 ); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list1); + DLL_Delete(list2); +} + +/* ========================================================================== +DLL_SetAt sets the data of the node specified by pos to info, and return the +previous info. Return NULL if list is NULL, pos is NULL, or if the node +specified by pos is not contained in the list. +PROTOTYPE: + void *DLL_SetAt(DLLPOS pos, void *info, DLLIST * list) +*/ + +TEST( dllist_test, DLL_SetAt) { + int A[] = {1,2,3,4,5}; + int B[] = {6,7,8,9,10}; + int* result; + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddHead( &(A[0]), list); + DLLPOS pos_second = DLL_AddHead( &(A[1]), list); + DLLPOS pos_third = DLL_AddHead( &(A[2]), list); + DLLPOS pos_fourth = DLL_AddHead( &(A[3]), list); + DLLPOS pos_fifth = DLL_AddHead( &(A[4]), list); + + result = (int*)DLL_SetAt( pos_first, &(B[0]), list ); + EXPECT_EQ(*result, 1); + result = (int*)DLL_SetAt( pos_second, &(B[1]), list ); + EXPECT_EQ(*result, 2); + result = (int*)DLL_SetAt( pos_third, &(B[2]), list ); + EXPECT_EQ(*result, 3); + result = (int*)DLL_SetAt( pos_fourth, &(B[3]), list ); + EXPECT_EQ(*result, 4); + result = (int*)DLL_SetAt( pos_fifth, &(B[4]), list ); + EXPECT_EQ(*result, 5); + result = (int*)DLL_GetAt( pos_first, list ); + EXPECT_EQ(*result, 6); + result = (int*)DLL_GetAt( pos_second, list ); + EXPECT_EQ(*result, 7); + result = (int*)DLL_GetAt( pos_third, list ); + EXPECT_EQ(*result, 8); + result = (int*)DLL_GetAt( pos_fourth, list ); + EXPECT_EQ(*result, 9); + result = (int*)DLL_GetAt( pos_fifth, list ); + EXPECT_EQ(*result, 10); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_SetAt_null_list) { + int A[] = {1,2,3,4,5}; + int* result; + + DLLIST* null_list = nullptr; + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddHead( &(A[0]), list); + (void) DLL_AddHead( &(A[1]), list); + + std::cout << "NOTE: An error message is expected to follow." << std::endl; + result = (int*)DLL_SetAt( pos_first, &(A[0]), null_list ); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_SetAt_null_pos) { + int A[] = {1,2,3,4,5}; + int* result; + + DLLPOS null_pos = nullptr; + DLLIST* list = DLL_Create(); + (void) DLL_AddHead( &(A[0]), list); + (void) DLL_AddHead( &(A[1]), list); + + std::cout << "NOTE: An error message is expected to follow." << std::endl; + result = (int*)DLL_SetAt( null_pos, &(A[0]), list ); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_SetAt_list_doesnt_contain_node) { + int A[] = {1,2,3,4,5}; + int* result; + + DLLIST* list1 = DLL_Create(); + DLLPOS pos_in_list1 = DLL_AddHead( &(A[0]), list1); + DLLIST* list2 = DLL_Create(); + DLLPOS pos_in_list2 = DLL_AddHead( &(A[0]), list2); + + // These should work. + result = (int*)DLL_SetAt( pos_in_list1, &(A[1]), list1 ); + EXPECT_EQ(*result, 1); + result = (int*)DLL_SetAt( pos_in_list2, &(A[1]), list2 ); + EXPECT_EQ(*result, 1); + + // These shouldn't, because the specified nodes are not in the specified lists. + std::cout << "NOTE: An error message is expected to follow." << std::endl; + result = (int*)DLL_SetAt( pos_in_list1, &(A[1]), list2 ); + EXPECT_EQ(result, nullptr); + std::cout << "NOTE: An error message is expected to follow." << std::endl; + result = (int*)DLL_SetAt( pos_in_list2, &(A[1]), list1 ); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list1); + DLL_Delete(list2); +} + +/* ========================================================================== +DLL_FindPos +Return the position, in the specified list, that holds the specified data +address. If the list is NULL, or the data address isn't found, return NULL. +PROTOTYPE: + DLLPOS DLL_FindPos(void* data, DLLIST*); +*/ + +TEST( dllist_test, DLL_FindPos) { + int A[] = {1,2,3,4,5}; + int B = 7; + + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddHead( &(A[0]), list); + DLLPOS pos_second = DLL_AddHead( &(A[1]), list); + DLLPOS pos_third = DLL_AddHead( &(A[2]), list); + DLLPOS pos_fourth = DLL_AddHead( &(A[3]), list); + DLLPOS pos_fifth = DLL_AddHead( &(A[4]), list); + + DLLPOS result = nullptr; + result = DLL_FindPos( &(A[0]), list); + EXPECT_EQ(result, pos_first); + result = DLL_FindPos( &(A[1]), list); + EXPECT_EQ(result, pos_second); + result = DLL_FindPos( &(A[2]), list); + EXPECT_EQ(result, pos_third); + result = DLL_FindPos( &(A[3]), list); + EXPECT_EQ(result, pos_fourth); + result = DLL_FindPos( &(A[4]), list); + EXPECT_EQ(result, pos_fifth); + + /* B isn't in the list. */ + result = DLL_FindPos( &B, list); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_FindPos_null_list) { + int B = 7; + std::cout << "NOTE: An error message is expected to follow." << std::endl; + /* Call function under test with list == NULL. */ + DLLPOS result = DLL_FindPos(&B, nullptr); + EXPECT_EQ(result, nullptr); +} + +/* ========================================================================== +DLL_FindIndex +Return the node at the given index (n), where n ranges from 0 {the head node} +to (list->count - 1) {The tail node}. +PROTOTYPE: + DLLPOS DLL_FindIndex(int n, DLLIST * list) +*/ + +TEST( dllist_test, DLL_FindIndex) { + int A[] = {1,2,3,4,5}; + + DLLIST* list = DLL_Create(); + DLLPOS pos_first = DLL_AddTail( &(A[0]), list); + DLLPOS pos_second = DLL_AddTail( &(A[1]), list); + DLLPOS pos_third = DLL_AddTail( &(A[2]), list); + DLLPOS pos_fourth = DLL_AddTail( &(A[3]), list); + DLLPOS pos_fifth = DLL_AddTail( &(A[4]), list); + + DLLPOS result = nullptr; + result = DLL_FindIndex( 0, list); + EXPECT_EQ(result, pos_first); + result = DLL_FindIndex( 1, list); + EXPECT_EQ(result, pos_second); + result = DLL_FindIndex( 2, list); + EXPECT_EQ(result, pos_third); + result = DLL_FindIndex( 3, list); + EXPECT_EQ(result, pos_fourth); + result = DLL_FindIndex( 4, list); + EXPECT_EQ(result, pos_fifth); + + /* B isn't in the list. */ + std::cout << "NOTE: An error message is expected to follow." << std::endl; + result = DLL_FindIndex( 6, list); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_FindIndex_null_list) { + + std::cout << "NOTE: An error message is expected to follow." << std::endl; + DLLPOS result = DLL_FindIndex(0, nullptr); + + EXPECT_EQ(result, nullptr); +} + +/* ========================================================================== +DLL_RemoveAt +Remove the spcified node (pos) Node from the specified list. +Reurn the info at the position being removed, or NULL if it's not found in the +list. +PROTOTYPE: + void *DLL_RemoveAt(DLLPOS pos, DLLIST * list) +*/ + +TEST( dllist_test, DLL_RemoveAt_head) { + int A[] = {1,2,3,4,5}; + + DLLIST* list = DLL_Create(); + (void) DLL_AddTail( &(A[0]), list); + (void) DLL_AddTail( &(A[1]), list); + (void) DLL_AddTail( &(A[2]), list); + + DLLPOS nodeToRemove = DLL_GetHeadPosition(list); + int* result = nullptr; + + result = (int*)DLL_RemoveAt(nodeToRemove, list); + EXPECT_EQ(*result, 1); + EXPECT_EQ( DLL_GetCount(list), 2); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_RemoveAt_tail) { + int A[] = {1,2,3,4,5}; + + DLLIST* list = DLL_Create(); + (void) DLL_AddTail( &(A[0]), list); + (void) DLL_AddTail( &(A[1]), list); + (void) DLL_AddTail( &(A[2]), list); + + DLLPOS nodeToRemove = DLL_GetTailPosition(list); + int* result = nullptr; + + result = (int*)DLL_RemoveAt(nodeToRemove, list); + EXPECT_EQ(*result, 3); + EXPECT_EQ( DLL_GetCount(list), 2); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_RemoveAt_from_middle) { + int A[] = {1,2,3,4,5}; + + DLLIST* list = DLL_Create(); + (void) DLL_AddTail( &(A[0]), list); + DLLPOS nodeToRemove = DLL_AddTail( &(A[1]), list); + (void) DLL_AddTail( &(A[2]), list); + EXPECT_EQ( DLL_GetCount(list), 3); + + int* result = nullptr; + result = (int*)DLL_RemoveAt(nodeToRemove, list); + EXPECT_EQ(*result, 2); + EXPECT_EQ( DLL_GetCount(list), 2); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_RemoveAt_from_single_node_list) { + int A[] = {1,2,3,4,5}; + + DLLIST* list = DLL_Create(); + (void) DLL_AddTail( &(A[0]), list); + + DLLPOS nodeToRemove = DLL_GetTailPosition(list); + int* result = nullptr; + + result = (int*)DLL_RemoveAt(nodeToRemove, list); + EXPECT_EQ(*result, 1); + EXPECT_EQ( DLL_GetCount(list), 0); + + DLL_Delete(list); +} + +TEST( dllist_test, DLL_RemoveAt_null_list) { + + DLLIST* list = nullptr; + DLLPOS nodeToRemove = nullptr; + int* result = nullptr; + std::cout << "NOTE: An error message is expected to follow." << std::endl; + result = (int*)DLL_RemoveAt(nodeToRemove, list); + EXPECT_EQ(result, nullptr); + + DLL_Delete(list); +} + +/* ========================================================================== +DLL_RemoveAll +Removes all elements in the list. The list will then be empty. +Returns nothing. +PROTOTYPE: + void DLL_RemoveAll(DLLIST * list) +*/ + +TEST( dllist_test, DLL_RemoveAll) { + int A[] = {1,2,3,4,5}; + + DLLIST* list = DLL_Create(); + (void) DLL_AddTail( &(A[0]), list); + (void) DLL_AddTail( &(A[1]), list); + (void) DLL_AddTail( &(A[2]), list); + (void) DLL_AddTail( &(A[3]), list); + (void) DLL_AddTail( &(A[4]), list); + EXPECT_EQ( DLL_GetCount(list), 5); + + DLL_RemoveAll(list); + + EXPECT_EQ( DLL_GetCount(list), 0); + + DLL_Delete(list); + +} + +// END OF TEST SUITE diff --git a/trick_source/trick_utils/trick_adt/test_program/makefile b/trick_source/trick_utils/trick_adt/test_program/makefile deleted file mode 100644 index b2f875dd..00000000 --- a/trick_source/trick_utils/trick_adt/test_program/makefile +++ /dev/null @@ -1,236 +0,0 @@ -############################################################################# -# Makefile: -# This is a makefile for maintaining the -# '/stroke/users/trick_dev/trick_source/trick_adt/test_program' -# directory. This make file was automatically generated by the -# "make_build" program. -# -############################################################################# -# Creation: -# Author: Trick auto makefile program - "make_build", Version 1998.1.Beta -# Date: 13:46:16 on Monday 16 February 1998 -# -############################################################################# -# -# To get a desription of the arguments accepted by this makefile, -# type 'make help' -# -############################################################################# - - -############################################################################# -## DIRECTORY DEFINITIONS ## -############################################################################# -ifndef TRICK_HOST_CPU -TRICK_HOST_CPU := $(shell trick-gte TRICK_HOST_CPU) -endif - -ifndef TRICK_HOST_TYPE -TRICK_HOST_TYPE := $(shell trick-gte TRICK_HOST_TYPE) -endif - - -TRICK_VER = 1998.1.Beta -CWD_DIR = /stroke/users/trick_dev/trick_source/trick_adt/test_program -SRC_DIR = -OBJ_DIR = object_${TRICK_HOST_CPU} -MODEL_BIN_DIR = $(OBJ_DIR) - - -############################################################################# -## UTILITY DEFINITIONS ## -############################################################################# -SHELL = /bin/sh -AWK = awk -SED = sed -LEX = lex -YACC = yacc -CD = cd -MV = mv -RM = rm - - -# -# Make information -# -MAKEFILE = Makefile -AWKTEMPFILE = awk.temp -SEDTEMPFILE = sed.temp -MAKEDEPEND = makedepend -FTNDEPEND = ftn_depend - -# -# Awk program to filter out system include dependencies -# -AWK_PRGM = $(TRICK_HOME)/bin/depend.awk - - -############################################################################# -## COMPILER DEFINITIONS ## -############################################################################# - -# -# C Compilation Variables -# -CPP_PRE_DEFS = -CPP_POST_DEFS = -CPPFLAGS = $(CPP_PRE_DEFS) $(TRICK_CFLAGS) $(CPP_POST_DEFS) - -ifeq ($(TRICK_FORCE_32BIT), 1) - CPPFLAGS += -m32 -endif - -# -# FORTRAN Compilation Variables -# -FCFLAGS = $(TRICK_FTNFLAGS) - - - - -############################################################################# -## FILE NAME DEFINITIONS ## -############################################################################# - -MODEL_C_SRC = \ - $(SRC_DIR)test.c - -MODEL_IO_SRC = - -MODEL_FTN_SRC = - -MODEL_C_OBJS = \ - $(OBJ_DIR)/test.o - -MODEL_IO_OBJS = - -MODEL_FTN_OBJS = - -############################################################################# -## SPECIAL TARGETS ## -############################################################################# - -.PRECIOUS: $(MODEL_C_SRC) $(MODEL_FTN_SRC) - -############################################################################# -## MODEL TARGETS ## -############################################################################# - -default: verify_trick_version object_files - -verify_trick_version: - @if ( test `trick_version $(TRICK_VER)` != $(TRICK_VER) ) then \ - echo "Make ERROR:" ; \ - echo " The current Makefile was generated with version $(TRICK_VER) of the Trick" ; \ - echo " processors which is incompatible with the the current Trick version," ; \ - echo " `trick_version`. Run 'catalog -versions' to get a complete list of" ; \ - echo " potential incompatibility problems. You must delete this Makefile" ; \ - echo " before make_build will generate a new Makefile." ; \ - exit 1 ; \ - fi -object_files: $(OBJ_DIR) $(MODEL_IO_OBJS) $(MODEL_C_OBJS) $(MODEL_FTN_OBJS) - @ echo "$(CWD_DIR) object files up to date" - -help : - @ echo "\ -Source Directory Make Options:\n\ - make - Compiles are source files\n\ -\n\ - make ICG - Deletes the io_src directory and runs ICG\n\ - on all pertinent *.h files\n\ -\n\ - make catalog - Deletes the local catalog and builds a new one\n\ -\n\ - make depend - Adds file dependencies to Makefile\n\ -\n\ - make io_clean - Deletes the local io_src directory\n\ -\n\ - make catalog_clean - Deletes the local catalog directory\n\ -\n\ - make clean - Deletes the object code directory\n\ -\n\ - make real_clean - Deletes html/, io_src/, catalog/,\n\ - and object_${TRICK_HOST_CPU}/ directories\n" - -$(OBJ_DIR): - @ mkdir -p $(OBJ_DIR) - @ echo "Created $(OBJ_DIR)" - - -# -# MODEL_IO_OBJS -# - - -# -# MODEL_IO_SRC -# - - -# -# MODEL_C_OBJS -# -$(OBJ_DIR)/test.o : $(SRC_DIR)test.c - $(TRICK_CC) $(CPPFLAGS) -c test.c -o $(OBJ_DIR)/test.o - $(TRICK_CC) ${TRICK_CFLAGS} $(OBJ_DIR)/test.o -L${TRICK_HOME}/lib_${TRICK_HOST_CPU} -o test -ltrick_adt - - - -# -# LEX/YACC SOURCE -# - - -# -# MODEL_F_OBJS -# - - -# -# ICG Target -# -ICG: verify_trick_version io_clean $(OBJ_DIR) $(MODEL_IO_OBJS) - @ echo "IO files are up to date!" - -############################################################################# -## MAINTENANCE TARGETS ## -############################################################################# - -depend: - $(MAKEDEPEND) -f $(MAKEFILE) - @ touch $(AWKTEMPFILE) - @ $(MAKEDEPEND) -f $(AWKTEMPFILE) -Iinclude -- $(CPPFLAGS) -- $(MODEL_C_SRC) $(MODEL_IO_SRC) - @ $(FTNDEPEND) -- $(FCFLAGS) -- $(MODEL_FTN_SRC) >> $(AWKTEMPFILE) - @ $(AWK) -f $(AWK_PRGM) $(AWKTEMPFILE) >> $(SEDTEMPFILE) - @ $(RM) -f $(AWKTEMPFILE) - @ $(SED) -e 's:$(TRICK_HOME):$$(TRICK_HOME):' $(SEDTEMPFILE) >> $(AWKTEMPFILE) - @ $(SED) s:\$\(MODEL_BIN_DIR\)/src:\$\(MODEL_BIN_DIR\): $(AWKTEMPFILE) >> $(MAKEFILE) - @ $(RM) -f $(AWKTEMPFILE) $(AWKTEMPFILE).bak $(SEDTEMPFILE) - @ echo "Appended dependencies to $(MAKEFILE)" - -io_clean: verify_trick_version - $(RM) -rf io_src - -real_clean: verify_trick_version clean io_clean - $(RM) -rf html *~ *.bak core - @ echo "Directory is really clean!" - -clean: verify_trick_version - $(RM) -rf $(LIB) $(OBJ_DIR) - @ echo "Object files successfully removed" - -catalog_clean : verify_trick_version - $(RM) -rf catalog - @ echo "Catalog purged" - -catalog : verify_trick_version catalog_clean $(MODEL_IO_SRC) - MIS - @ echo "$(CWD_DIR) Catalog rebuilt" - -############################################################################# -#------------------------------------------------------------------------ -# Below this are the object module dependencies, built with makedepend. -#------------------------------------------------------------------------ -# DO NOT DELETE THIS LINE -- make depend depends on it. - -$(MODEL_BIN_DIR)/test.o: ../bst.h diff --git a/trick_source/trick_utils/trick_adt/test_program/test.c b/trick_source/trick_utils/trick_adt/test_program/test.c deleted file mode 100644 index 8bc3b4ba..00000000 --- a/trick_source/trick_utils/trick_adt/test_program/test.c +++ /dev/null @@ -1,103 +0,0 @@ - -#include -#include -#include "../bst.h" -#include - -typedef struct -{ - int key; - char* data; -}ITEM; - - -int compare(void* left, void* right) -{ - ITEM* pitem1=(ITEM*)left; - ITEM* pitem2=(ITEM*)right; - if(pitem1->key-pitem2->key < 0) - return -1; - else if(pitem1->key-pitem2->key > 0) - return 1; - else - return 0; -} - - -void main() -{ - short done=0; - int newnum; - char ch; - char buffer[256]; - ITEM* newitem; - BST bst; - bstNode* node; - ITEM tempitem; - bstInit(&bst); - bstSetCompareFunc(&bst,compare); - while(!done) - { - fprintf(stderr,"(1) Add Item\n(2) Lookup\n(3) Remove Item\n"); - ch=getchar(); - fflush(stdin); - switch(ch) - { - case '1': - newitem=(ITEM*)malloc(sizeof(ITEM)); - printf("\nEnter a string\n"); - scanf("%s",buffer); - newitem->data=strdup(buffer); - printf("Enter key\n"); - scanf("%d",&newnum); - newitem->key=newnum; - printf("inserting at %d\n",newnum); - bstInsert(newitem,&bst); - break; - case '2': - printf("Enter key\n"); - - scanf("%d",&newnum); - printf("Looking for %d\n",newnum); - tempitem.key=newnum; - node=bstFind(&tempitem,&bst); - if(node != NULL) - { - newitem=(ITEM*)bstGetInfo(node); - printf("found %s\n",newitem->data); - } - else - { - printf("Item not found\n"); - } - break; - case '3': - printf("Enter key\n"); - scanf("%d",&newnum); - tempitem.key=newnum; - node=bstFind(&tempitem,&bst); - if(node != NULL) - { - newitem=(ITEM*)bstGetInfo(node); - printf("removing %s\n",newitem->data); - bstDelete(node,&bst); - } - else - { - printf("Item not found\n"); - } - break; - default:done=1; - } - fflush(stdin); - } -} - - - - - - - - -