| /* Copyright (c) 2010 James Grenning and Contributed to Unity Project |
| * ========================================== |
| * Unity Project - A Test Framework for C |
| * Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams |
| * [Released under MIT License. Please refer to license.txt for details] |
| * ========================================== */ |
| |
| #include "unity_fixture.h" |
| #include "unity_internals.h" |
| #include <string.h> |
| #if USE_RTOS |
| #include "FreeRTOS.h" |
| #include "task.h" |
| #endif |
| |
| struct UNITY_FIXTURE_T UnityFixture; |
| |
| /* If you decide to use the function pointer approach. |
| * Build with -D UNITY_OUTPUT_CHAR=outputChar and include <stdio.h> |
| * int (*outputChar)(int) = putchar; */ |
| |
| #if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA) |
| void setUp(void) { /*does nothing*/ } |
| void tearDown(void) { /*does nothing*/ } |
| #endif |
| |
| static void announceTestRun(unsigned int runNumber) |
| { |
| UnityPrint("Unity test run "); |
| UnityPrintNumberUnsigned(runNumber+1); |
| UnityPrint(" of "); |
| UnityPrintNumberUnsigned(UnityFixture.RepeatCount); |
| UNITY_PRINT_EOL(); |
| } |
| |
| #if USE_RTOS |
| void UnityMainRTOSTask(unityParams *parms) |
| { |
| int result = UnityGetCommandLineOptions(parms->argc, parms->argv); |
| unsigned int r = 0; |
| if (result != 0) |
| vTaskDelete(NULL);; |
| |
| UnityAddin_AnnounceFilters(); |
| |
| for (r = 0; r < UnityFixture.RepeatCount; r++) |
| { |
| UnityBegin(parms->argv[0]); |
| announceTestRun(r); |
| parms->runAllTests(); |
| if (!UnityFixture.Verbose) UNITY_PRINT_EOL(); |
| UnityEnd(); |
| } |
| |
| UnityAddin_AnnounceFilters(); |
| vTaskDelete(NULL); |
| } |
| #endif |
| |
| int UnityMain(int argc, const char* argv[], void (*runAllTests)(void)) |
| { |
| int result = UnityGetCommandLineOptions(argc, argv); |
| unsigned int r = 0; |
| if (result != 0) |
| return result; |
| |
| UnityAddin_AnnounceFilters(); |
| |
| for (r = 0; r < UnityFixture.RepeatCount; r++) |
| { |
| UnityBegin(argv[0]); |
| announceTestRun(r); |
| runAllTests(); |
| if (!UnityFixture.Verbose) UNITY_PRINT_EOL(); |
| UnityEnd(); |
| } |
| |
| UnityAddin_AnnounceFilters(); |
| |
| return (int)Unity.TestFailures; |
| } |
| |
| static int selected(const char* filter, const char* name) |
| { |
| if (filter == 0) |
| return 1; |
| return strstr(name, filter) ? 1 : 0; |
| } |
| |
| static int testSelected(const char* test) |
| { |
| return selected(UnityFixture.NameFilter, test); |
| } |
| |
| static int groupSelected(const char* group) |
| { |
| return selected(UnityFixture.GroupFilter, group); |
| } |
| |
| void UnityTestRunner(unityfunction* setup, |
| unityfunction* testBody, |
| unityfunction* teardown, |
| const char* printableName, |
| const char* group, |
| const char* name, |
| const char* file, |
| unsigned int line) |
| { |
| if (testSelected(name) && groupSelected(group)) |
| { |
| Unity.TestFile = file; |
| Unity.CurrentTestName = printableName; |
| Unity.CurrentTestLineNumber = line; |
| if (!UnityFixture.Verbose) |
| UNITY_OUTPUT_CHAR('.'); |
| else |
| { |
| UnityPrint(printableName); |
| #ifndef UNITY_REPEAT_TEST_NAME |
| Unity.CurrentTestName = NULL; |
| #endif |
| } |
| |
| Unity.NumberOfTests++; |
| UnityMalloc_StartTest(); |
| UnityPointer_Init(); |
| UnityAddin_SetMessage(NULL, 0); |
| |
| if (TEST_PROTECT()) |
| { |
| setup(); |
| testBody(); |
| } |
| if (TEST_PROTECT()) |
| { |
| teardown(); |
| } |
| if (TEST_PROTECT()) |
| { |
| UnityPointer_UndoAllSets(); |
| if (!Unity.CurrentTestFailed) |
| UnityMalloc_EndTest(); |
| } |
| UnityAddin_ConcludeFixture(printableName, group, name, file, line); //+TB |
| UnityConcludeFixtureTest(); |
| } |
| } |
| |
| void UnityIgnoreTest(const char* printableName, const char* group, const char* name) |
| { |
| if (testSelected(name) && groupSelected(group)) |
| { |
| Unity.NumberOfTests++; |
| Unity.TestIgnores++; |
| if (!UnityFixture.Verbose) |
| UNITY_OUTPUT_CHAR('!'); |
| else |
| { |
| UnityPrint(printableName); |
| UNITY_PRINT_EOL(); |
| } |
| } |
| } |
| |
| |
| /*------------------------------------------------- */ |
| /* Malloc and free stuff */ |
| #define MALLOC_DONT_FAIL -1 |
| static int malloc_count; |
| static int malloc_fail_countdown = MALLOC_DONT_FAIL; |
| |
| void UnityMalloc_StartTest(void) |
| { |
| malloc_count = 0; |
| malloc_fail_countdown = MALLOC_DONT_FAIL; |
| } |
| |
| void UnityMalloc_EndTest(void) |
| { |
| malloc_fail_countdown = MALLOC_DONT_FAIL; |
| if (malloc_count != 0) |
| { |
| UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "This test leaks!"); |
| } |
| } |
| |
| void UnityMalloc_MakeMallocFailAfterCount(int countdown) |
| { |
| malloc_fail_countdown = countdown; |
| } |
| |
| /* These definitions are always included from unity_fixture_malloc_overrides.h */ |
| /* We undef to use them or avoid conflict with <stdlib.h> per the C standard */ |
| #undef malloc |
| #undef free |
| #undef calloc |
| #undef realloc |
| |
| #ifdef UNITY_EXCLUDE_STDLIB_MALLOC |
| static unsigned char unity_heap[UNITY_INTERNAL_HEAP_SIZE_BYTES]; |
| static size_t heap_index; |
| #else |
| #include <stdlib.h> |
| #endif |
| |
| typedef struct GuardBytes |
| { |
| size_t size; |
| size_t guard_space; |
| } Guard; |
| |
| |
| static const char end[] = "END"; |
| |
| void* unity_malloc(size_t size) |
| { |
| char* mem; |
| Guard* guard; |
| size_t total_size = size + sizeof(Guard) + sizeof(end); |
| |
| if (malloc_fail_countdown != MALLOC_DONT_FAIL) |
| { |
| if (malloc_fail_countdown == 0) |
| return NULL; |
| malloc_fail_countdown--; |
| } |
| |
| if (size == 0) return NULL; |
| #ifdef UNITY_EXCLUDE_STDLIB_MALLOC |
| if (heap_index + total_size > UNITY_INTERNAL_HEAP_SIZE_BYTES) |
| { |
| guard = NULL; |
| } |
| else |
| { |
| guard = (Guard*)&unity_heap[heap_index]; |
| heap_index += total_size; |
| } |
| #else |
| guard = (Guard*)UNITY_FIXTURE_MALLOC(total_size); |
| #endif |
| if (guard == NULL) return NULL; |
| malloc_count++; |
| guard->size = size; |
| guard->guard_space = 0; |
| mem = (char*)&(guard[1]); |
| memcpy(&mem[size], end, sizeof(end)); |
| |
| return (void*)mem; |
| } |
| |
| static int isOverrun(void* mem) |
| { |
| Guard* guard = (Guard*)mem; |
| char* memAsChar = (char*)mem; |
| guard--; |
| |
| return guard->guard_space != 0 || strcmp(&memAsChar[guard->size], end) != 0; |
| } |
| |
| static void release_memory(void* mem) |
| { |
| Guard* guard = (Guard*)mem; |
| guard--; |
| |
| malloc_count--; |
| #ifdef UNITY_EXCLUDE_STDLIB_MALLOC |
| if (mem == unity_heap + heap_index - guard->size - sizeof(end)) |
| { |
| heap_index -= (guard->size + sizeof(Guard) + sizeof(end)); |
| } |
| #else |
| UNITY_FIXTURE_FREE(guard); |
| #endif |
| } |
| |
| void unity_free(void* mem) |
| { |
| int overrun; |
| |
| if (mem == NULL) |
| { |
| return; |
| } |
| |
| overrun = isOverrun(mem); |
| release_memory(mem); |
| if (overrun) |
| { |
| UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during free()"); |
| } |
| } |
| |
| void* unity_calloc(size_t num, size_t size) |
| { |
| void* mem = unity_malloc(num * size); |
| if (mem == NULL) return NULL; |
| memset(mem, 0, num * size); |
| return mem; |
| } |
| |
| void* unity_realloc(void* oldMem, size_t size) |
| { |
| Guard* guard = (Guard*)oldMem; |
| void* newMem; |
| |
| if (oldMem == NULL) return unity_malloc(size); |
| |
| guard--; |
| if (isOverrun(oldMem)) |
| { |
| release_memory(oldMem); |
| UNITY_TEST_FAIL(Unity.CurrentTestLineNumber, "Buffer overrun detected during realloc()"); |
| } |
| |
| if (size == 0) |
| { |
| release_memory(oldMem); |
| return NULL; |
| } |
| |
| if (guard->size >= size) return oldMem; |
| |
| #ifdef UNITY_EXCLUDE_STDLIB_MALLOC /* Optimization if memory is expandable */ |
| if (oldMem == unity_heap + heap_index - guard->size - sizeof(end) && |
| heap_index + size - guard->size <= UNITY_INTERNAL_HEAP_SIZE_BYTES) |
| { |
| release_memory(oldMem); /* Not thread-safe, like unity_heap generally */ |
| return unity_malloc(size); /* No memcpy since data is in place */ |
| } |
| #endif |
| newMem = unity_malloc(size); |
| if (newMem == NULL) return NULL; /* Do not release old memory */ |
| memcpy(newMem, oldMem, guard->size); |
| release_memory(oldMem); |
| return newMem; |
| } |
| |
| |
| /*-------------------------------------------------------- */ |
| /*Automatic pointer restoration functions */ |
| struct PointerPair |
| { |
| void** pointer; |
| void* old_value; |
| }; |
| |
| static struct PointerPair pointer_store[UNITY_MAX_POINTERS]; |
| static int pointer_index = 0; |
| |
| void UnityPointer_Init(void) |
| { |
| pointer_index = 0; |
| } |
| |
| void UnityPointer_Set(void** pointer, void* newValue, UNITY_LINE_TYPE line) |
| { |
| if (pointer_index >= UNITY_MAX_POINTERS) |
| { |
| UNITY_TEST_FAIL(line, "Too many pointers set"); |
| } |
| else |
| { |
| pointer_store[pointer_index].pointer = pointer; |
| pointer_store[pointer_index].old_value = *pointer; |
| *pointer = newValue; |
| pointer_index++; |
| } |
| } |
| |
| void UnityPointer_UndoAllSets(void) |
| { |
| while (pointer_index > 0) |
| { |
| pointer_index--; |
| *(pointer_store[pointer_index].pointer) = |
| pointer_store[pointer_index].old_value; |
| } |
| } |
| |
| int UnityGetCommandLineOptions(int argc, const char* argv[]) |
| { |
| int i; |
| UnityFixture.Verbose = 1; |
| UnityFixture.GroupFilter = 0; |
| UnityFixture.NameFilter = 0; |
| UnityFixture.RepeatCount = 1; |
| |
| if (argc == 1) |
| return 0; |
| |
| for (i = 1; i < argc; ) |
| { |
| if (strcmp(argv[i], "-v") == 0) |
| { |
| UnityFixture.Verbose = 1; |
| i++; |
| } |
| else if (strcmp(argv[i], "-g") == 0) |
| { |
| i++; |
| if (i >= argc) |
| return 1; |
| UnityFixture.GroupFilter = argv[i]; |
| i++; |
| } |
| else if (strcmp(argv[i], "-n") == 0) |
| { |
| i++; |
| if (i >= argc) |
| return 1; |
| UnityFixture.NameFilter = argv[i]; |
| i++; |
| } |
| else if (strcmp(argv[i], "-r") == 0) |
| { |
| UnityFixture.RepeatCount = 2; |
| i++; |
| if (i < argc) |
| { |
| if (*(argv[i]) >= '0' && *(argv[i]) <= '9') |
| { |
| unsigned int digit = 0; |
| UnityFixture.RepeatCount = 0; |
| while (argv[i][digit] >= '0' && argv[i][digit] <= '9') |
| { |
| UnityFixture.RepeatCount *= 10; |
| UnityFixture.RepeatCount += (unsigned int)argv[i][digit++] - '0'; |
| } |
| i++; |
| } |
| } |
| } |
| else |
| { |
| /* ignore unknown parameter */ |
| i++; |
| } |
| } |
| return 0; |
| } |
| |
| |
| #ifdef UNITY_OUTPUT_COLOR |
| static const char *szPASS = "\033[42mOK\033[00m"; |
| #else |
| static const char *szPASS = "PASS"; |
| #endif |
| |
| void UnityConcludeFixtureTest(void) |
| { |
| if (Unity.CurrentTestIgnored) |
| { |
| Unity.TestIgnores++; |
| UNITY_PRINT_EOL(); |
| } |
| else if (!Unity.CurrentTestFailed) |
| { |
| if (UnityFixture.Verbose) |
| { |
| UnityPrint(" "); |
| UnityPrint(szPASS); |
| UNITY_PRINT_EOL(); |
| } |
| } |
| else /* Unity.CurrentTestFailed */ |
| { |
| Unity.TestFailures++; |
| UNITY_PRINT_EOL(); |
| } |
| |
| Unity.CurrentTestFailed = 0; |
| Unity.CurrentTestIgnored = 0; |
| } |