diff --git a/ut_assert/inc/utlist.h b/ut_assert/inc/utlist.h index 1e1bef199..d38f08586 100644 --- a/ut_assert/inc/utlist.h +++ b/ut_assert/inc/utlist.h @@ -63,9 +63,8 @@ typedef struct UtListNodeTag { } UtListNode_t; typedef struct { - UtListNode_t *First; - UtListNode_t *Last; - uint32 NumberOfEntries; + UtListNode_t *Tags; + uint32 NumberOfTags; } UtListHead_t; /* @@ -75,54 +74,39 @@ typedef struct UtListNodeTag { /* Dynamically allocates a new list head. A list head could also just be declared, this function is useful * if you need to dynamically allocate memory for a new list head. Note always free list heads allocated by * this function by calling UtList_Destroy. */ -UtListHead_t *UtList_Create(void); +UtListHead_t *UtList_Create(uint32 NumTags); /* Frees a list head created by UtList_Create. */ void UtList_Destroy(UtListHead_t *ListHead); /* Deletes all nodes on the list. */ -void UtList_Reset(UtListHead_t *ListHead); +void UtList_Reset(UtListNode_t *TagHead); + +/* Merge two lists heads together */ +void UtList_Merge(UtListNode_t *TagHead1, UtListNode_t *TagHead2); /* Dynamically adds a new node to the list. Nodes are always added to the end of the list. Memory is dynamically * allocated for the new node and to hold the data pointed to by Data. A Tag field is also provided to be used to * store user defined information with the node. */ void UtList_Add(UtListHead_t *ListHead, void *Data, uint32 DataSize, uint32 Tag); -/* Deletes the first node from the list. */ -void UtList_DeleteFirst(UtListHead_t *ListHead); - -/* Deletes the last node from the list. */ -void UtList_DeleteLast(UtListHead_t *ListHead); - /* Deletes the specified node from the list, this will screw up if you do not pass in a valid DeleteNode. I do not * verify that DeleteNode is a member of the list. */ -void UtList_DeleteNode(UtListHead_t *ListHead, UtListNode_t *DeleteNode); - -/* Removes the first node from the list by first copying the data from the node to the memory buffer pointed to by the - * specified Data pointer and then the node is deleted from the list. Make sure the destination pointer points to a - * memory buffer large enough to hold the data. The size of the data on the node is available by referencing UtListNode->DataSize. */ -void UtList_RemoveFirst(UtListHead_t *ListHead, void *Data); +void UtList_DeleteNode(UtListNode_t *DeleteNode); -/* Removes the last node from the list by first copying the data from the node to the memory buffer pointed to by the - * specified Data pointer and then the node is deleted from the list. Make sure the destination pointer points to a - * memory buffer large enough to hold the data. The size of the data on the node is available by referencing UtListNode->DataSize. */ -void UtList_RemoveLast(UtListHead_t *ListHead, void *Data); - -/* Removes the speciified RemoveNode from the list by first copying the data from the node to the memory buffer pointed to by the - * specified Data pointer and then the node is deleted from the list. Make sure the destination pointer points to a - * memory buffer large enough to hold the data. The size of the data on the node is available by referencing UtListNode->DataSize. */ -void UtList_RemoveNode(UtListHead_t *ListHead, void *Data, UtListNode_t *RemoveNode); +/* Returns true if the list is empty. This is the same as (UtListHead->NumberOfEntries == 0). */ +bool UtList_IsEmpty(UtListNode_t *TagHead); -/* Returns a pointer to the first node on the list. This is the same as (UtListHead->First). */ -UtListNode_t *UtList_First(UtListHead_t *ListHead); +/* Returns the head node of a list for the given tag */ +UtListNode_t *UtList_GetHead(UtListHead_t *ListHead, uint32 Tag); -/* Returns a pointer to the last node on the list. This is the same as (UtListHead->Last). */ -UtListNode_t *UtList_Last(UtListHead_t *ListHead); +/* Returns the next node in the list, given the current node */ +UtListNode_t *UtList_GetNext(UtListNode_t *ListNode); -/* Returns true if the list is empty. This is the same as (UtListHead->NumberOfEntries == 0). */ -bool UtList_IsEmpty(UtListHead_t *ListHead); +/* Returns the data object associated with the current node */ +void *UtList_GetObject(UtListNode_t *ListNode); -/* Returns the number of nodes on the list. This is the same as (UtListHead->NumberOfEntries). */ -uint32 UtList_Depth(UtListHead_t *ListHead); +/* Check if the current node marks the end of the list */ +bool UtList_IsEnd(UtListNode_t *TagHead, UtListNode_t *ListNode); #endif diff --git a/ut_assert/inc/uttest.h b/ut_assert/inc/uttest.h index 05b387f3a..143c367b6 100644 --- a/ut_assert/inc/uttest.h +++ b/ut_assert/inc/uttest.h @@ -50,6 +50,29 @@ */ void UtTest_Add(void (*Test)(void), void (*Setup)(void), void (*Teardown)(void), const char *TestName); +/** + * \brief Registers a setup function + * + * This group of functions are invoked BEFORE normal test routines added with UtTest_Add. + * Within the group, functions are executed in the order registered. + * + * \param Setup Setup function, called before the test function + * \param TestName Name of function for logging purposes + */ +void UtTest_AddSetup(void (*Setup)(void), const char *SequenceName); + +/** + * \brief Registers a teardown function + * + * This group of functions is invoked AFTER normal test routines added with UtTest_Add. + * Within the group, functions are executed in the order registered. + * + * \param Teardown Teardown function, called before the test function + * \param TestName Name of function for logging purposes + */ +void UtTest_AddTeardown(void (*Teardown)(void), const char *SequenceName); + + /** * \brief Early initialization function * diff --git a/ut_assert/src/utbsp.c b/ut_assert/src/utbsp.c index f028455ef..ee68f3183 100644 --- a/ut_assert/src/utbsp.c +++ b/ut_assert/src/utbsp.c @@ -240,7 +240,7 @@ void OS_Application_Run(void) */ void OS_Application_Startup(void) { - + UtTest_EarlyInit(); UT_BSP_Setup(); /* diff --git a/ut_assert/src/utglobal.h b/ut_assert/src/utglobal.h index b23098ac4..dc8cbf4f3 100644 --- a/ut_assert/src/utglobal.h +++ b/ut_assert/src/utglobal.h @@ -55,7 +55,7 @@ typedef struct typedef struct { - UtListHead_t DataBase; + UtListHead_t *DataBasePtr; uint32 ExecutedCount; } UtAssert_Global_t; diff --git a/ut_assert/src/utlist.c b/ut_assert/src/utlist.c index 6942bc5ca..328503f37 100644 --- a/ut_assert/src/utlist.c +++ b/ut_assert/src/utlist.c @@ -37,138 +37,165 @@ * Function Definitions */ -UtListHead_t *UtList_Create(void) +UtListHead_t *UtList_Create(uint32 NumTags) { - UtListHead_t *NewList; + struct ListAllocator + { + UtListHead_t Head; + UtListNode_t Tags[]; + }; + struct ListAllocator *NewList; + UtListNode_t *TagHead; + size_t ActualSize; + uint32 i; + + ActualSize = sizeof(struct ListAllocator) + (sizeof(UtListNode_t) * NumTags); + NewList = (struct ListAllocator *)malloc(ActualSize); + + memset(NewList, 0, ActualSize); + + NewList->Head.Tags = NewList->Tags; + NewList->Head.NumberOfTags = NumTags; + + for (i=0; i < NumTags; ++i) + { + TagHead = &NewList->Head.Tags[i]; + TagHead->Tag = i; + TagHead->Next = TagHead; + TagHead->Prev = TagHead; + } - NewList = malloc(sizeof(UtListHead_t)); - NewList->First = NULL; - NewList->Last = NULL; - NewList->NumberOfEntries = 0; - return (NewList); + return (&NewList->Head); } void UtList_Destroy(UtListHead_t *ListHead) { - UtList_Reset(ListHead); + uint32 i; + + for (i=0; i < ListHead->NumberOfTags; ++i) + { + UtList_Reset(&ListHead->Tags[i]); + } free(ListHead); } -void UtList_Reset(UtListHead_t *ListHead) +void UtList_Reset(UtListNode_t *TagHead) { - while (!UtList_IsEmpty(ListHead)) { - UtList_DeleteFirst(ListHead); + while (!UtList_IsEmpty(TagHead)) + { + UtList_DeleteNode(TagHead->Next); } } -void UtList_Add(UtListHead_t *ListHead, void *Data, uint32 DataSize, uint32 Tag) +void UtList_Merge(UtListNode_t *TagHead1, UtListNode_t *TagHead2) { - UtListNode_t *NewNode = NULL; - - NewNode = malloc(sizeof(UtListNode_t)); - if (ListHead->NumberOfEntries == 0) { - - ListHead->First = NewNode; - ListHead->Last = NewNode; - ListHead->NumberOfEntries++; + UtListNode_t *Tail1 = TagHead1->Prev; + UtListNode_t *Tail2 = TagHead2->Prev; - NewNode->Next = NULL; - NewNode->Prev = NULL; - NewNode->Tag = Tag; - NewNode->DataSize = DataSize; - NewNode->Data = malloc(DataSize); - memcpy(NewNode->Data, Data, DataSize); - } - else { + Tail1->Next = TagHead2; + Tail2->Next = TagHead1; + TagHead1->Prev = Tail2; + TagHead2->Prev = Tail1; +} - NewNode->Next = NULL; - NewNode->Prev = ListHead->Last; - NewNode->Tag = Tag; - NewNode->DataSize = DataSize; - NewNode->Data = malloc(DataSize); - memcpy(NewNode->Data, Data, DataSize); +void UtList_Insert_After(UtListNode_t *ExistingNode, UtListNode_t *NewNode) +{ + NewNode->Next = ExistingNode->Next; + NewNode->Prev = ExistingNode; + NewNode->Prev->Next = NewNode; + NewNode->Next->Prev = NewNode; +} - ListHead->Last->Next = NewNode; - ListHead->Last = NewNode; - ListHead->NumberOfEntries++; - } +void UtList_Insert_Before(UtListNode_t *ExistingNode, UtListNode_t *NewNode) +{ + NewNode->Next = ExistingNode; + NewNode->Prev = ExistingNode->Prev; + NewNode->Prev->Next = NewNode; + NewNode->Next->Prev = NewNode; } -void UtList_DeleteFirst(UtListHead_t *ListHead) +void UtList_Extract(UtListNode_t *ExistingNode) { - UtList_DeleteNode(ListHead, ListHead->First); + ExistingNode->Next->Prev = ExistingNode->Prev; + ExistingNode->Prev->Next = ExistingNode->Next; + ExistingNode->Next = ExistingNode; + ExistingNode->Prev = ExistingNode; } -void UtList_DeleteLast(UtListHead_t *ListHead) +UtListNode_t *UtList_NewNode(void *Data, uint32 DataSize) { - UtList_DeleteNode(ListHead, ListHead->Last); + union NodeAllocator + { + UtListNode_t Node; + double AlignDbl; + void* AlignPtr; + long AlignLong; + } *AllocNode; + + AllocNode = malloc(sizeof(union NodeAllocator) + DataSize); + memset(AllocNode, 0, sizeof(union NodeAllocator)); + AllocNode->Node.Data = &AllocNode[1]; + AllocNode->Node.DataSize = DataSize; + memcpy(AllocNode->Node.Data, Data, DataSize); + + AllocNode->Node.Next = &AllocNode->Node; + AllocNode->Node.Prev = &AllocNode->Node; + + return &AllocNode->Node; } -void UtList_DeleteNode(UtListHead_t *ListHead, UtListNode_t *DeleteNode) + +void UtList_Add(UtListHead_t *ListHead, void *Data, uint32 DataSize, uint32 Tag) { - - if (!UtList_IsEmpty(ListHead)) { - - if (ListHead->NumberOfEntries == 1) { - ListHead->First = NULL; - ListHead->Last = NULL; - ListHead->NumberOfEntries = 0; - } - else if (DeleteNode == ListHead->First) { - ListHead->First = DeleteNode->Next; - ListHead->First->Prev = NULL; - ListHead->NumberOfEntries--; - } - else if (DeleteNode == ListHead->Last) { - ListHead->Last = DeleteNode->Prev; - ListHead->Last->Next = NULL; - ListHead->NumberOfEntries--; - } - else { - DeleteNode->Prev->Next = DeleteNode->Next; - DeleteNode->Next->Prev = DeleteNode->Prev; - ListHead->NumberOfEntries--; - } - - free(DeleteNode->Data); - free(DeleteNode); + UtListNode_t *TagHead; + UtListNode_t *NewNode; + + TagHead = UtList_GetHead(ListHead, Tag); + if (TagHead != NULL) + { + NewNode = UtList_NewNode(Data, DataSize); + NewNode->Tag = Tag; + UtList_Insert_Before(TagHead, NewNode); } } -void UtList_RemoveFirst(UtListHead_t *ListHead, void *Data) +void UtList_DeleteNode(UtListNode_t *DeleteNode) { - UtList_RemoveNode(ListHead, Data, ListHead->First); + UtList_Extract(DeleteNode); + + /* non-data/header nodes shouldn't be free()'ed */ + if (DeleteNode->Data != NULL) + { + free(DeleteNode); + } } -void UtList_RemoveLast(UtListHead_t *ListHead, void *Data) +bool UtList_IsEmpty(UtListNode_t *TagHead) { - UtList_RemoveNode(ListHead, Data, ListHead->Last); + return(TagHead->Next == TagHead); } -void UtList_RemoveNode(UtListHead_t *ListHead, void *Data, UtListNode_t *CurrentNode) +UtListNode_t *UtList_GetHead(UtListHead_t *ListHead, uint32 Tag) { - if (!UtList_IsEmpty(ListHead)) { - memcpy(Data, CurrentNode->Data, CurrentNode->DataSize); - UtList_DeleteNode(ListHead, CurrentNode); + if (Tag >= ListHead->NumberOfTags) + { + return NULL; } + return &ListHead->Tags[Tag]; } -UtListNode_t *UtList_First(UtListHead_t *ListHead) +UtListNode_t *UtList_GetNext(UtListNode_t *ListNode) { - return(ListHead->First); + return ListNode->Next; } -UtListNode_t *UtList_Last(UtListHead_t *ListHead) +void *UtList_GetObject(UtListNode_t *ListNode) { - return(ListHead->Last); + return ListNode->Data; } -bool UtList_IsEmpty(UtListHead_t *ListHead) +bool UtList_IsEnd(UtListNode_t *TagHead, UtListNode_t *ListNode) { - return(ListHead->NumberOfEntries == 0); + return(TagHead == ListNode); } -uint32 UtList_Depth(UtListHead_t *ListHead) -{ - return(ListHead->NumberOfEntries); -} diff --git a/ut_assert/src/uttest.c b/ut_assert/src/uttest.c index b1c15a420..f4d1ffce1 100644 --- a/ut_assert/src/uttest.c +++ b/ut_assert/src/uttest.c @@ -35,11 +35,20 @@ */ UtAssert_Global_t UtAssert_Global; +enum +{ + UTASSERT_GROUP_DEFAULT = 0, + UTASSERT_GROUP_SETUP, + UTASSERT_GROUP_TEST, + UTASSERT_GROUP_TEARDOWN, + UTASSERT_GROUP_MAX +}; + /* * Function Definitions */ -void UtTest_Add(void (*Test)(void), void (*Setup)(void), void (*Teardown)(void), const char *TestName) +void UtTest_AddCommon(void (*Test)(void), void (*Setup)(void), void (*Teardown)(void), const char *TestName, uint32 EntryType) { UtTestDataBaseEntry_t UtTestDataBaseEntry; @@ -47,23 +56,61 @@ void UtTest_Add(void (*Test)(void), void (*Setup)(void), void (*Teardown)(void), UtTestDataBaseEntry.Test = Test; UtTestDataBaseEntry.Setup = Setup; UtTestDataBaseEntry.Teardown = Teardown; - strncpy(UtTestDataBaseEntry.TestName, TestName, sizeof(UtTestDataBaseEntry.TestName)-1); - UtList_Add(&UtAssert_Global.DataBase, &UtTestDataBaseEntry, sizeof(UtTestDataBaseEntry_t), 0); + if (TestName != NULL) + { + strncpy(UtTestDataBaseEntry.TestName, TestName, sizeof(UtTestDataBaseEntry.TestName)-1); + } + + UtList_Add(UtAssert_Global.DataBasePtr, &UtTestDataBaseEntry, sizeof(UtTestDataBaseEntry_t), EntryType); +} + +void UtTest_Add(void (*Test)(void), void (*Setup)(void), void (*Teardown)(void), const char *SequenceName) +{ + UtTest_AddCommon(Test, Setup, Teardown, SequenceName, UTASSERT_GROUP_TEST); +} + +void UtTest_AddSetup(void (*Setup)(void), const char *SequenceName) +{ + UtTest_AddCommon(NULL, Setup, NULL, SequenceName, UTASSERT_GROUP_SETUP); +} + +void UtTest_AddTeardown(void (*Teardown)(void), const char *SequenceName) +{ + UtTest_AddCommon(NULL, NULL, Teardown, SequenceName, UTASSERT_GROUP_TEARDOWN); } + void UtTest_Run(void) { - uint32 i; + UtListNode_t *UtListMain; UtListNode_t *UtListNode; UtTestDataBaseEntry_t *UtTestDataBaseEntry; - if (UtAssert_Global.DataBase.NumberOfEntries > 0) { - - UtListNode = UtAssert_Global.DataBase.First; - for (i=0; i < UtAssert_Global.DataBase.NumberOfEntries; i++) { - - UtTestDataBaseEntry = UtListNode->Data; + /* + * The overall test sequence goes SETUP->TEST->TEARDOWN + * + * Combine all registered test groups into a merged group for execution. + * + * This could also (theoretically) randomize the order of the "TEST" group + * while assembling this list, if there was a portable source of entropy. + */ + UtListMain = UtList_GetHead(UtAssert_Global.DataBasePtr,UTASSERT_GROUP_DEFAULT); + UtList_Merge(UtListMain, UtList_GetHead(UtAssert_Global.DataBasePtr,UTASSERT_GROUP_SETUP)); + UtList_Merge(UtListMain, UtList_GetHead(UtAssert_Global.DataBasePtr,UTASSERT_GROUP_TEST)); + UtList_Merge(UtListMain, UtList_GetHead(UtAssert_Global.DataBasePtr,UTASSERT_GROUP_TEARDOWN)); + + /* + * Run through the merged list in order + */ + for (UtListNode = UtList_GetNext(UtListMain); + !UtList_IsEnd(UtListMain, UtListNode); + UtListNode = UtList_GetNext(UtListNode)) + { + UtTestDataBaseEntry = UtList_GetObject(UtListNode); + + if (UtTestDataBaseEntry != NULL) + { UtAssert_BeginTest(UtTestDataBaseEntry->TestName); UtAssert_SetContext(UTASSERT_CASETYPE_TSF); @@ -74,12 +121,10 @@ void UtTest_Run(void) if (UtTestDataBaseEntry->Teardown) { UtTestDataBaseEntry->Teardown(); } UtAssert_EndTest(); - - UtListNode = UtListNode->Next; } } - UtList_Reset(&UtAssert_Global.DataBase); + UtList_Destroy(UtAssert_Global.DataBasePtr); UT_BSP_EndTest(UtAssert_GetCounters()); } @@ -90,6 +135,7 @@ void UtTest_EarlyInit(void) * Reset the test global variables, just in case. */ memset(&UtAssert_Global, 0, sizeof(UtAssert_Global)); + UtAssert_Global.DataBasePtr = UtList_Create(UTASSERT_GROUP_MAX); }