testStress.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #include "testBase.h"
  2. /**
  3. * @brief 压力与边界测试
  4. *
  5. * @note 验证 RyanJson 处理大数据量(长字符串、大数组)的能力。
  6. */
  7. static RyanJson_t createSequentialIntArray(uint32_t arraySize)
  8. {
  9. RyanJson_t array = RyanJsonCreateArray();
  10. TEST_ASSERT_NOT_NULL(array);
  11. for (uint32_t i = 0; i < arraySize; i++)
  12. {
  13. TEST_ASSERT_TRUE_MESSAGE(RyanJsonAddIntToArray(array, (int32_t)i), "向大数组添加整数失败");
  14. }
  15. return array;
  16. }
  17. static int32_t gStressFailAfter = -1;
  18. static int32_t gStressAllocCount = 0;
  19. static void *stressFailMalloc(size_t size)
  20. {
  21. if (gStressFailAfter >= 0 && gStressAllocCount++ >= gStressFailAfter) { return NULL; }
  22. return unityTestMalloc(size);
  23. }
  24. static void *stressFailRealloc(void *block, size_t size)
  25. {
  26. if (gStressFailAfter >= 0 && gStressAllocCount++ >= gStressFailAfter) { return NULL; }
  27. return unityTestRealloc(block, size);
  28. }
  29. static void stressSetFailAfter(int32_t failAfter)
  30. {
  31. gStressFailAfter = failAfter;
  32. gStressAllocCount = 0;
  33. RyanJsonInitHooks(stressFailMalloc, unityTestFree, stressFailRealloc);
  34. }
  35. static void stressRestoreHooks(void)
  36. {
  37. RyanJsonInitHooks(unityTestMalloc, unityTestFree, unityTestRealloc);
  38. gStressFailAfter = -1;
  39. gStressAllocCount = 0;
  40. }
  41. static void testStressLongString(void)
  42. {
  43. // 测试超长字符串 (10KB)
  44. const int32_t longStrLen = 10 * 1024;
  45. char *longStrVal = (char *)malloc(longStrLen + 1);
  46. TEST_ASSERT_NOT_NULL(longStrVal);
  47. memset(longStrVal, 'A', longStrLen);
  48. longStrVal[longStrLen] = '\0';
  49. RyanJson_t jsonStr = RyanJsonCreateString("longStr", longStrVal);
  50. TEST_ASSERT_NOT_NULL(jsonStr);
  51. TEST_ASSERT_EQUAL_STRING_MESSAGE(longStrVal, RyanJsonGetStringValue(jsonStr), "超长字符串读取不匹配");
  52. RyanJsonDelete(jsonStr);
  53. free(longStrVal);
  54. }
  55. static void testStressLargeArray(void)
  56. {
  57. // 测试大数组 (1000 个整数)
  58. const uint32_t arraySize = 1000;
  59. RyanJson_t array = createSequentialIntArray(arraySize);
  60. TEST_ASSERT_EQUAL_UINT32_MESSAGE(arraySize, (uint32_t)RyanJsonGetArraySize(array), "大数组长度错误");
  61. // 校验最后一个元素
  62. RyanJson_t lastItem = RyanJsonGetObjectByIndex(array, (int32_t)(arraySize - 1U));
  63. #if true == RyanJsonDefaultAddAtHead
  64. TEST_ASSERT_EQUAL_INT32_MESSAGE(0, RyanJsonGetIntValue(lastItem), "大数组末尾元素错误");
  65. #else
  66. TEST_ASSERT_EQUAL_INT32_MESSAGE((int32_t)(arraySize - 1U), RyanJsonGetIntValue(lastItem), "大数组末尾元素错误");
  67. #endif
  68. RyanJsonDelete(array);
  69. }
  70. static void testStressPrint(void)
  71. {
  72. // 序列化压力测试 (无格式)
  73. const uint32_t arraySize = 1000;
  74. RyanJson_t array = createSequentialIntArray(arraySize);
  75. char *printed = RyanJsonPrint(array, 8192, RyanJsonFalse, NULL);
  76. TEST_ASSERT_NOT_NULL_MESSAGE(printed, "大数组序列化失败");
  77. RyanJsonFree(printed);
  78. RyanJsonDelete(array);
  79. }
  80. static void testStressLargeArrayRoundtrip(void)
  81. {
  82. const uint32_t arraySize = 2048;
  83. RyanJson_t array = createSequentialIntArray(arraySize);
  84. // 关键位置抽样检查,避免仅检查尾节点导致漏检
  85. const uint32_t sampleIndex[] = {0U, 1U, 2U, 127U, 1023U, 1536U, 2047U};
  86. for (uint32_t i = 0; i < sizeof(sampleIndex) / sizeof(sampleIndex[0]); i++)
  87. {
  88. uint32_t idx = sampleIndex[i];
  89. RyanJson_t item = RyanJsonGetObjectByIndex(array, (int32_t)idx);
  90. TEST_ASSERT_NOT_NULL_MESSAGE(item, "大数组抽样索引越界");
  91. TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsInt(item), "大数组抽样元素类型错误");
  92. #if true == RyanJsonDefaultAddAtHead
  93. TEST_ASSERT_EQUAL_INT32_MESSAGE((int32_t)(arraySize - 1U - idx), RyanJsonGetIntValue(item), "大数组抽样元素值错误");
  94. #else
  95. TEST_ASSERT_EQUAL_INT32_MESSAGE((int32_t)idx, RyanJsonGetIntValue(item), "大数组抽样元素值错误");
  96. #endif
  97. }
  98. uint32_t printLen = 0;
  99. char *printed = RyanJsonPrint(array, 0, RyanJsonFalse, &printLen);
  100. TEST_ASSERT_NOT_NULL_MESSAGE(printed, "大数组往返测试:序列化失败");
  101. TEST_ASSERT_TRUE_MESSAGE(printLen > arraySize, "大数组序列化长度异常");
  102. RyanJson_t parsed = RyanJsonParse(printed);
  103. TEST_ASSERT_NOT_NULL_MESSAGE(parsed, "大数组往返测试:反序列化失败");
  104. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(array, parsed), "大数组往返测试:前后 Compare 不一致");
  105. RyanJsonDelete(parsed);
  106. RyanJsonFree(printed);
  107. RyanJsonDelete(array);
  108. }
  109. static void testStressLargeStringArrayPreallocated(void)
  110. {
  111. const uint32_t arraySize = 1200;
  112. RyanJson_t array = RyanJsonCreateArray();
  113. TEST_ASSERT_NOT_NULL(array);
  114. for (uint32_t i = 0; i < arraySize; i++)
  115. {
  116. TEST_ASSERT_TRUE_MESSAGE(RyanJsonAddStringToArray(array, "v"), "向字符串大数组添加元素失败");
  117. }
  118. uint32_t expectLen = 0;
  119. char *expect = RyanJsonPrint(array, 0, RyanJsonFalse, &expectLen);
  120. TEST_ASSERT_NOT_NULL_MESSAGE(expect, "字符串大数组序列化失败");
  121. char *buf = (char *)malloc((size_t)expectLen + 1U);
  122. TEST_ASSERT_NOT_NULL(buf);
  123. char *out = RyanJsonPrintPreallocated(array, buf, expectLen + 1U, RyanJsonFalse, NULL);
  124. TEST_ASSERT_NOT_NULL_MESSAGE(out, "字符串大数组预分配刚好够用应成功");
  125. TEST_ASSERT_EQUAL_STRING_MESSAGE(expect, out, "字符串大数组预分配输出不一致");
  126. RyanJson_t parsed = RyanJsonParse(out);
  127. TEST_ASSERT_NOT_NULL_MESSAGE(parsed, "字符串大数组预分配结果解析失败");
  128. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(array, parsed), "字符串大数组预分配结果前后 Compare 不一致");
  129. RyanJsonDelete(parsed);
  130. free(buf);
  131. RyanJsonFree(expect);
  132. RyanJsonDelete(array);
  133. }
  134. static void testStressLargeStringArrayPreallocatedNoTerminator(void)
  135. {
  136. const uint32_t arraySize = 800;
  137. RyanJson_t array = RyanJsonCreateArray();
  138. TEST_ASSERT_NOT_NULL(array);
  139. for (uint32_t i = 0; i < arraySize; i++)
  140. {
  141. TEST_ASSERT_TRUE_MESSAGE(RyanJsonAddStringToArray(array, "value"), "向字符串大数组添加元素失败");
  142. }
  143. uint32_t expectLen = 0;
  144. char *expect = RyanJsonPrint(array, 0, RyanJsonFalse, &expectLen);
  145. TEST_ASSERT_NOT_NULL(expect);
  146. char *buf = (char *)malloc((size_t)expectLen);
  147. TEST_ASSERT_NOT_NULL(buf);
  148. // 少 1 字节 '\0' 空间,预分配打印应失败
  149. char *out = RyanJsonPrintPreallocated(array, buf, expectLen, RyanJsonFalse, NULL);
  150. TEST_ASSERT_NULL_MESSAGE(out, "预分配缺少 '\\0' 空间应失败");
  151. free(buf);
  152. RyanJsonFree(expect);
  153. RyanJsonDelete(array);
  154. }
  155. static void testStressPrintOomLargeArray(void)
  156. {
  157. RyanJson_t array = createSequentialIntArray(2000);
  158. // 首次分配失败
  159. stressSetFailAfter(0);
  160. char *printed = RyanJsonPrint(array, 0, RyanJsonFalse, NULL);
  161. stressRestoreHooks();
  162. if (printed) { RyanJsonFree(printed); }
  163. TEST_ASSERT_NULL_MESSAGE(printed, "Print OOM(首次分配失败) 应返回 NULL");
  164. // 首次分配成功,扩容失败
  165. stressSetFailAfter(1);
  166. printed = RyanJsonPrint(array, 1, RyanJsonFalse, NULL);
  167. stressRestoreHooks();
  168. if (printed) { RyanJsonFree(printed); }
  169. TEST_ASSERT_NULL_MESSAGE(printed, "Print OOM(扩容失败) 应返回 NULL");
  170. RyanJsonDelete(array);
  171. }
  172. static void testStressLargeObjectKeyLookup(void)
  173. {
  174. const uint32_t keyCount = 1500;
  175. RyanJson_t obj = RyanJsonCreateObject();
  176. TEST_ASSERT_NOT_NULL(obj);
  177. for (uint32_t i = 0; i < keyCount; i++)
  178. {
  179. char key[24];
  180. RyanJsonSnprintf(key, sizeof(key), "k%04u", (unsigned)i);
  181. TEST_ASSERT_TRUE_MESSAGE(RyanJsonAddIntToObject(obj, key, (int32_t)i), "大对象添加 key 失败");
  182. }
  183. TEST_ASSERT_EQUAL_UINT32_MESSAGE(keyCount, (uint32_t)RyanJsonGetSize(obj), "大对象大小错误");
  184. // 热点索引查找:头/中/尾
  185. const uint32_t lookupIndex[] = {0U, keyCount / 2U, keyCount - 1U};
  186. for (uint32_t i = 0; i < sizeof(lookupIndex) / sizeof(lookupIndex[0]); i++)
  187. {
  188. char key[24];
  189. uint32_t idx = lookupIndex[i];
  190. RyanJsonSnprintf(key, sizeof(key), "k%04u", (unsigned)idx);
  191. RyanJson_t item = RyanJsonGetObjectByKey(obj, key);
  192. TEST_ASSERT_NOT_NULL_MESSAGE(item, "大对象 key 查找失败");
  193. TEST_ASSERT_EQUAL_INT32_MESSAGE((int32_t)idx, RyanJsonGetIntValue(item), "大对象 key 查找值错误");
  194. }
  195. // 替换中间节点并验证
  196. {
  197. char midKey[24];
  198. uint32_t mid = keyCount / 2U;
  199. RyanJsonSnprintf(midKey, sizeof(midKey), "k%04u", (unsigned)mid);
  200. RyanJson_t replaceItem = RyanJsonCreateInt(midKey, -12345);
  201. TEST_ASSERT_NOT_NULL(replaceItem);
  202. TEST_ASSERT_TRUE_MESSAGE(RyanJsonReplaceByKey(obj, midKey, replaceItem), "大对象中间节点替换失败");
  203. TEST_ASSERT_EQUAL_INT32_MESSAGE(-12345, RyanJsonGetIntValue(RyanJsonGetObjectByKey(obj, midKey)),
  204. "大对象中间节点替换值错误");
  205. }
  206. uint32_t len = 0;
  207. char *printed = RyanJsonPrint(obj, 0, RyanJsonFalse, &len);
  208. TEST_ASSERT_NOT_NULL_MESSAGE(printed, "大对象序列化失败");
  209. TEST_ASSERT_TRUE_MESSAGE(len > keyCount * 6U, "大对象序列化长度异常");
  210. RyanJson_t roundtrip = RyanJsonParse(printed);
  211. TEST_ASSERT_NOT_NULL_MESSAGE(roundtrip, "大对象往返测试:解析失败");
  212. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(obj, roundtrip), "大对象往返测试:前后 Compare 不一致");
  213. RyanJsonDelete(roundtrip);
  214. RyanJsonFree(printed);
  215. RyanJsonDelete(obj);
  216. }
  217. void testStressRunner(void)
  218. {
  219. UnitySetTestFile(__FILE__);
  220. RUN_TEST(testStressLongString);
  221. RUN_TEST(testStressLargeArray);
  222. RUN_TEST(testStressPrint);
  223. RUN_TEST(testStressLargeArrayRoundtrip);
  224. RUN_TEST(testStressLargeStringArrayPreallocated);
  225. RUN_TEST(testStressLargeStringArrayPreallocatedNoTerminator);
  226. RUN_TEST(testStressPrintOomLargeArray);
  227. RUN_TEST(testStressLargeObjectKeyLookup);
  228. }