main.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include "FreeRTOS.h"
  2. #include "RyanJson.h"
  3. #include "task.h"
  4. #include "../../common/testCommon.h"
  5. #include "testBase.h"
  6. #include <errno.h>
  7. #include <stdlib.h>
  8. #include <time.h>
  9. #if defined(RyanJsonTestPlatformQemu)
  10. #include "qemuPlatform.h"
  11. #endif
  12. #if defined(RyanJsonFreeRtosHeap4)
  13. void vApplicationGetRandomHeapCanary(portPOINTER_SIZE_TYPE *heapCanary)
  14. {
  15. portPOINTER_SIZE_TYPE seed = (portPOINTER_SIZE_TYPE)(uintptr_t)&vApplicationGetRandomHeapCanary;
  16. if (NULL == heapCanary) { return; }
  17. #if defined(RyanJsonTestPlatformQemu)
  18. seed ^= (portPOINTER_SIZE_TYPE)xTaskGetTickCount();
  19. #else
  20. struct timespec ts = {0};
  21. if (0 == clock_gettime(CLOCK_MONOTONIC, &ts))
  22. {
  23. seed ^= (portPOINTER_SIZE_TYPE)(uintptr_t)ts.tv_sec;
  24. seed ^= (portPOINTER_SIZE_TYPE)(uintptr_t)ts.tv_nsec;
  25. }
  26. #endif
  27. seed ^= (portPOINTER_SIZE_TYPE)(uintptr_t)heapCanary;
  28. if (0U == seed) { seed = (portPOINTER_SIZE_TYPE)0xA5A5A5A5U; }
  29. *heapCanary = seed;
  30. }
  31. #endif
  32. static int32_t defaultTestPlatformLogV(const char *fmt, va_list args)
  33. {
  34. if (NULL == fmt) { return -1; }
  35. #if defined(RyanJsonTestPlatformQemu)
  36. char logBuffer[1024];
  37. int32_t logLen = (int32_t)vsnprintf(logBuffer, sizeof(logBuffer), fmt, args);
  38. if (logLen > 0) { qemuUartWrite(logBuffer); }
  39. return logLen;
  40. #else
  41. return vprintf(fmt, args);
  42. #endif
  43. }
  44. static uint64_t defaultTestPlatformGetUptimeMs(void)
  45. {
  46. return (uint64_t)xTaskGetTickCount() * (uint64_t)portTICK_PERIOD_MS;
  47. }
  48. static void defaultTestPlatformSleepMs(uint32_t ms)
  49. {
  50. if (0U == ms) { return; }
  51. vTaskDelay(pdMS_TO_TICKS(ms));
  52. }
  53. typedef struct
  54. {
  55. testPlatformThreadEntry_t threadEntry;
  56. void *threadArg;
  57. TaskHandle_t waitTask;
  58. } testPlatformThreadCtx_t;
  59. static void defaultTestPlatformThreadTask(void *arg)
  60. {
  61. testPlatformThreadCtx_t *threadCtx = (testPlatformThreadCtx_t *)arg;
  62. if (NULL != threadCtx && NULL != threadCtx->threadEntry) { threadCtx->threadEntry(threadCtx->threadArg); }
  63. if (NULL != threadCtx && NULL != threadCtx->waitTask) { xTaskNotifyGive(threadCtx->waitTask); }
  64. vTaskDelete(NULL);
  65. }
  66. static int32_t defaultTestPlatformRunThreadWithStackSize(testPlatformThreadEntry_t entry, void *arg, size_t stackDepthWords)
  67. {
  68. BaseType_t createRet = pdFAIL;
  69. TaskHandle_t waitTask = xTaskGetCurrentTaskHandle();
  70. configSTACK_DEPTH_TYPE taskStackDepth = 0U;
  71. testPlatformThreadCtx_t threadCtx = {0};
  72. if (NULL == entry || NULL == waitTask) { return EINVAL; }
  73. if (0U == stackDepthWords) { taskStackDepth = (configSTACK_DEPTH_TYPE)configMINIMAL_STACK_SIZE; }
  74. else
  75. {
  76. if (stackDepthWords < (size_t)configMINIMAL_STACK_SIZE) { stackDepthWords = (size_t)configMINIMAL_STACK_SIZE; }
  77. if (stackDepthWords > (size_t)(~(configSTACK_DEPTH_TYPE)0U)) { stackDepthWords = (size_t)(~(configSTACK_DEPTH_TYPE)0U); }
  78. taskStackDepth = (configSTACK_DEPTH_TYPE)stackDepthWords;
  79. }
  80. threadCtx.threadEntry = entry;
  81. threadCtx.threadArg = arg;
  82. threadCtx.waitTask = waitTask;
  83. createRet = xTaskCreate(defaultTestPlatformThreadTask, "unitCase", taskStackDepth, &threadCtx,
  84. (UBaseType_t)(configMAX_PRIORITIES - 3U), NULL);
  85. if (pdPASS != createRet) { return ENOMEM; }
  86. (void)ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
  87. return 0;
  88. }
  89. static int32_t gUnitTestResult = 1;
  90. #if defined(RyanJsonTestPlatformQemu)
  91. static uint32_t qemuLoadWordViaAsm(const void *address)
  92. {
  93. uint32_t value = 0U;
  94. __asm volatile("ldr %0, [%1]" : "=r"(value) : "r"(address));
  95. return value;
  96. }
  97. static void qemuForceUnalignedFaultViaAsm(const void *address)
  98. {
  99. /* LDRD on unaligned address should trap on Cortex-M models that implement it. */
  100. __asm volatile("ldrd r2, r3, [%0]" : : "r"(address) : "r2", "r3", "memory");
  101. }
  102. static void qemuRunPostUnitAlignmentCheck(void) __attribute__((noreturn));
  103. static void qemuRunPostUnitAlignmentCheck(void)
  104. {
  105. uint32_t alignedWords[2] = {0x12345678UL, 0xAABBCCDDUL};
  106. uint32_t readBack = qemuLoadWordViaAsm((const void *)&alignedWords[1]);
  107. uint8_t raw[8] __attribute__((aligned(4))) = {0x11U, 0x22U, 0x33U, 0x44U, 0x55U, 0x66U, 0x77U, 0x88U};
  108. void const *unalignedAddr = (void const *)(raw + 1U);
  109. if (readBack != alignedWords[1])
  110. {
  111. testLog("[QEMU][ALIGN] aligned_access FAIL read=0x%08lx expected=0x%08lx\n", (unsigned long)readBack,
  112. (unsigned long)alignedWords[1]);
  113. qemuRequestExit(1);
  114. }
  115. testLog("[QEMU][ALIGN] aligned_access PASS read=0x%08lx\n", (unsigned long)readBack);
  116. qemuSetExpectUnalignedFault(true);
  117. testLog("[QEMU][ALIGN] unaligned_access TRIGGER addr=0x%08lx\n", (unsigned long)(uintptr_t)unalignedAddr);
  118. qemuForceUnalignedFaultViaAsm(unalignedAddr);
  119. #if defined(RyanJsonQemuSoftUnalignedTrap)
  120. if ((((uintptr_t)unalignedAddr) & 0x3U) != 0U)
  121. {
  122. testLog("[QEMU][ALIGN] fallback_soft_trap\n");
  123. testLog("[QEMU][HARDFAULT] fallback_soft_trap_no_hw_fault addr=0x%08lx\n", (unsigned long)(uintptr_t)unalignedAddr);
  124. testLog("[QEMU][RESULT] EXPECTED_UNALIGNED_FAULT fallbackAddr=0x%08lx\n", (unsigned long)(uintptr_t)unalignedAddr);
  125. qemuRequestExit(0);
  126. }
  127. #endif
  128. qemuSetExpectUnalignedFault(false);
  129. testLog("[QEMU][ALIGN] unaligned_access did not fault\n");
  130. testLog("[QEMU][RESULT] UNIT_FAIL code=%ld\n", (long)1L);
  131. qemuRequestExit(1);
  132. }
  133. #endif
  134. void vAssertCalled(const char *file, int32_t line)
  135. {
  136. testLog("\n[FreeRTOS ASSERT] %s:%ld\n", (NULL != file) ? file : "<null>", (long)line);
  137. abort();
  138. }
  139. void vApplicationMallocFailedHook(void)
  140. {
  141. testLog("\n[FreeRTOS] Malloc Failed Hook\n");
  142. vAssertCalled(__FILE__, (int32_t)__LINE__);
  143. }
  144. void vApplicationStackOverflowHook(TaskHandle_t task, char *taskName)
  145. {
  146. (void)task;
  147. testLog("\n[FreeRTOS] Stack Overflow Hook: %s\n", (NULL != taskName) ? taskName : "<null>");
  148. vAssertCalled(__FILE__, (int32_t)__LINE__);
  149. }
  150. testPlatformOps_t gTestPlatformOps = {
  151. .logV = defaultTestPlatformLogV,
  152. .getUptimeMs = defaultTestPlatformGetUptimeMs,
  153. .sleepMs = defaultTestPlatformSleepMs,
  154. .runThreadWithStackSize = defaultTestPlatformRunThreadWithStackSize,
  155. };
  156. static int32_t baselineUsed = 0;
  157. void setUp(void)
  158. {
  159. ryanJsonTestSetup();
  160. baselineUsed = unityTestGetUse();
  161. }
  162. void tearDown(void)
  163. {
  164. int32_t used = unityTestGetUse();
  165. if (used != baselineUsed)
  166. {
  167. testLog("\n\033[1;31m[MEMORY LEAK] Test '%s' leaked %d bytes!\033[0m\n", Unity.CurrentTestName, used - baselineUsed);
  168. showMemoryInfo();
  169. }
  170. TEST_ASSERT_EQUAL_INT_MESSAGE(baselineUsed, used, "Memory Leak Detected");
  171. ryanJsonTestTeardown();
  172. }
  173. void testRyanJsonExample(void)
  174. {
  175. TEST_ASSERT_EQUAL(RyanJsonTrue, RyanJsonExample());
  176. RyanJsonInitHooks(unityTestMalloc, unityTestFree, unityTestRealloc);
  177. }
  178. static int32_t runAllUnitTests(void)
  179. {
  180. UnityBegin(__FILE__);
  181. RUN_TEST(testRyanJsonExample);
  182. testChangeRunner();
  183. testCompareRunner();
  184. testCreateRunner();
  185. testDeleteRunner();
  186. testDetachRunner();
  187. testDuplicateRunner();
  188. testForEachRunner();
  189. testLoadSuccessRunner();
  190. testLoadFailureRunner();
  191. testReplaceRunner();
  192. testEqualityBoolRunner();
  193. testEqualityDoubleRunner();
  194. testEqualityIntRunner();
  195. testEqualityStringRunner();
  196. testUtilsRunner();
  197. testRobustRunner();
  198. testPrintRunner();
  199. testStressRunner();
  200. #if !defined(RyanJsonTestPlatformQemu)
  201. testRfc8259Runner();
  202. #endif
  203. testMemoryRunner();
  204. testDeepRecursionRunner();
  205. return UnityEnd();
  206. }
  207. static void logUnitTaskRuntimeInfo(void)
  208. {
  209. TaskHandle_t currentTask = xTaskGetCurrentTaskHandle();
  210. logTaskStackRuntimeInfoByHandle("unitMain", NULL, currentTask);
  211. }
  212. static void unitTestTask(void *arg)
  213. {
  214. (void)arg;
  215. gUnitTestResult = runAllUnitTests();
  216. logUnitTaskRuntimeInfo();
  217. #if defined(RyanJsonTestPlatformQemu)
  218. if (0 == gUnitTestResult)
  219. {
  220. testLog("[QEMU][RESULT] UNIT_PASS code=%ld tick=%lu\n", (long)gUnitTestResult, (unsigned long)xTaskGetTickCount());
  221. qemuRunPostUnitAlignmentCheck();
  222. }
  223. testLog("[QEMU][RESULT] UNIT_FAIL code=%ld\n", (long)gUnitTestResult);
  224. qemuRequestExit((0 == gUnitTestResult) ? 1 : gUnitTestResult);
  225. #else
  226. vTaskEndScheduler();
  227. vTaskDelete(NULL);
  228. #endif
  229. }
  230. #ifndef isEnableFuzzer
  231. int32_t main(void)
  232. {
  233. BaseType_t createRet = xTaskCreate(unitTestTask, // 任务入口函数
  234. "unitMain", // 任务名称
  235. 4096, // 任务栈大小
  236. NULL, // 任务参数
  237. (UBaseType_t)(configMAX_PRIORITIES - 2), // 任务优先级
  238. NULL // 不需要任务句柄
  239. );
  240. if (pdPASS != createRet)
  241. {
  242. testLog("[FreeRTOS] xTaskCreate(unitMain) failed\n");
  243. return 1;
  244. }
  245. vTaskStartScheduler();
  246. return gUnitTestResult;
  247. }
  248. #endif