testForEach.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. #include "testBase.h"
  2. static void testForEachEdgeCases(void)
  3. {
  4. RyanJson_t item = NULL;
  5. // 遍历 NULL Object (应该安全跳过循环)
  6. int32_t count = 0;
  7. RyanJsonArrayForEach(NULL, item)
  8. {
  9. count++;
  10. }
  11. TEST_ASSERT_EQUAL_INT_MESSAGE(0, count, "遍历 NULL Array 应不执行循环");
  12. count = 0;
  13. RyanJsonObjectForEach(NULL, item)
  14. {
  15. count++;
  16. }
  17. TEST_ASSERT_EQUAL_INT_MESSAGE(0, count, "遍历 NULL Object 应不执行循环");
  18. // 遍历非容器 Object (应该同上)
  19. RyanJson_t num = RyanJsonCreateInt("num", 1);
  20. count = 0;
  21. RyanJsonArrayForEach(num, item)
  22. {
  23. count++;
  24. }
  25. TEST_ASSERT_EQUAL_INT_MESSAGE(0, count, "遍历非容器 Array 应不执行循环");
  26. count = 0;
  27. RyanJsonObjectForEach(num, item)
  28. {
  29. count++;
  30. }
  31. TEST_ASSERT_EQUAL_INT_MESSAGE(0, count, "遍历非容器 Object 应不执行循环");
  32. RyanJsonDelete(num);
  33. // 循环中断测试 (break)
  34. RyanJson_t arr = RyanJsonCreateArray();
  35. TEST_ASSERT_NOT_NULL(arr);
  36. RyanJsonAddIntToArray(arr, 1);
  37. RyanJsonAddIntToArray(arr, 2);
  38. RyanJsonAddIntToArray(arr, 3);
  39. count = 0;
  40. RyanJsonArrayForEach(arr, item)
  41. {
  42. count++;
  43. if (RyanJsonGetIntValue(item) == 2) { break; }
  44. }
  45. TEST_ASSERT_EQUAL_INT_MESSAGE(2, count, "循环 break 测试失败");
  46. RyanJsonDelete(arr);
  47. }
  48. static void testForEachIterativeTraversals(void)
  49. {
  50. char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":"
  51. "{\"inter\":16,\"double\":16."
  52. "89,\"string\":\"hello\","
  53. "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,"
  54. "16.89,16.89,16.89],"
  55. "\"arrayString\":[\"hello\",\"hello\","
  56. "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
  57. "\"double\":16.89,\"string\":"
  58. "\"hello\",\"boolTrue\":true,"
  59. "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
  60. "\"boolFalse\":false,\"null\":null}]}";
  61. RyanJson_t json = RyanJsonParse(jsonstr);
  62. TEST_ASSERT_NOT_NULL_MESSAGE(json, "解析 Json 失败");
  63. RyanJson_t item = NULL;
  64. // 遍历 arrayDouble Array 测试
  65. RyanJsonArrayForEach(RyanJsonGetObjectToKey(json, "arrayDouble"), item)
  66. {
  67. TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsDouble(item), "Array 元素不是 Double 类型");
  68. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompareDouble(16.89, RyanJsonGetDoubleValue(item)), "Array 元素值不正确");
  69. }
  70. // 遍历 arrayInt Array 测试
  71. RyanJsonArrayForEach(RyanJsonGetObjectToKey(json, "arrayInt"), item)
  72. {
  73. TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsInt(item), "Array 元素不是 Int 类型");
  74. TEST_ASSERT_EQUAL_INT_MESSAGE(16, RyanJsonGetIntValue(item), "Array 元素值不正确");
  75. }
  76. // 遍历 item Object 测试
  77. RyanJsonObjectForEach(RyanJsonGetObjectToKey(json, "item"), item)
  78. {
  79. TEST_ASSERT_NOT_NULL_MESSAGE(RyanJsonGetKey(item), "Object 键值为空");
  80. char *str = RyanJsonPrint(item, 128, RyanJsonTrue, NULL);
  81. TEST_ASSERT_NOT_NULL_MESSAGE(str, "遍历项打印失败");
  82. RyanJsonFree(str);
  83. }
  84. RyanJsonDelete(json);
  85. }
  86. static void testForEachComplexSummaryWithMixedArrayMacros(void)
  87. {
  88. // 复杂链路:
  89. // Create(root/events/summary) -> Add*ToArray(混合类型) -> ArrayForEach(统计+改写)
  90. // -> ObjectForEach(汇总校验) -> Print/Parse Roundtrip。
  91. // 目标:
  92. // - 覆盖 AddNull/Bool/Double/StringToArray 与 AddItemToArray 的协同路径;
  93. // - 覆盖遍历过程中“按类型分支修改节点”是否会引发连锁结构破坏;
  94. // - 覆盖 ObjectForEach 在汇总 Object 上的稳定遍历语义。
  95. RyanJson_t root = RyanJsonCreateObject();
  96. RyanJson_t events = RyanJsonCreateArray();
  97. RyanJson_t summary = RyanJsonCreateObject();
  98. TEST_ASSERT_NOT_NULL(root);
  99. TEST_ASSERT_NOT_NULL(events);
  100. TEST_ASSERT_NOT_NULL(summary);
  101. // 构造混合类型 Array:Null / Bool / Double / String / Object
  102. TEST_ASSERT_TRUE(RyanJsonAddNullToArray(events));
  103. TEST_ASSERT_TRUE(RyanJsonAddBoolToArray(events, RyanJsonTrue));
  104. TEST_ASSERT_TRUE(RyanJsonAddDoubleToArray(events, 12.5));
  105. TEST_ASSERT_TRUE(RyanJsonAddStringToArray(events, "evt"));
  106. RyanJson_t payloadObj = RyanJsonCreateObject();
  107. TEST_ASSERT_NOT_NULL(payloadObj);
  108. TEST_ASSERT_TRUE(RyanJsonAddStringToObject(payloadObj, "type", "obj"));
  109. TEST_ASSERT_TRUE(RyanJsonAddIntToObject(payloadObj, "score", 7));
  110. TEST_ASSERT_TRUE(RyanJsonAddItemToArray(events, payloadObj));
  111. TEST_ASSERT_TRUE(RyanJsonAddIntToObject(summary, "nullCnt", 0));
  112. TEST_ASSERT_TRUE(RyanJsonAddIntToObject(summary, "boolCnt", 0));
  113. TEST_ASSERT_TRUE(RyanJsonAddIntToObject(summary, "doubleCnt", 0));
  114. TEST_ASSERT_TRUE(RyanJsonAddIntToObject(summary, "stringCnt", 0));
  115. TEST_ASSERT_TRUE(RyanJsonAddIntToObject(summary, "objectCnt", 0));
  116. TEST_ASSERT_TRUE(RyanJsonAddItemToObject(root, "events", events));
  117. TEST_ASSERT_TRUE(RyanJsonAddItemToObject(root, "summary", summary));
  118. // 挂载完成后重新取回容器,避免后续误用旧缓存指针。
  119. events = RyanJsonGetObjectToKey(root, "events");
  120. summary = RyanJsonGetObjectToKey(root, "summary");
  121. TEST_ASSERT_NOT_NULL(events);
  122. TEST_ASSERT_NOT_NULL(summary);
  123. TEST_ASSERT_EQUAL_UINT32(5U, RyanJsonGetArraySize(events));
  124. uint32_t idx = 0;
  125. int32_t nullIndex = -1;
  126. RyanJson_t item = NULL;
  127. RyanJsonArrayForEach(events, item)
  128. {
  129. if (RyanJsonIsNull(item))
  130. {
  131. TEST_ASSERT_TRUE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(summary, "nullCnt"),
  132. RyanJsonGetIntValue(RyanJsonGetObjectToKey(summary, "nullCnt")) + 1));
  133. // 记录待替换位置。不要在 ArrayForEach 内直接替换当前节点,避免破坏迭代指针。
  134. nullIndex = (int32_t)idx;
  135. }
  136. else if (RyanJsonIsBool(item))
  137. {
  138. TEST_ASSERT_TRUE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(summary, "boolCnt"),
  139. RyanJsonGetIntValue(RyanJsonGetObjectToKey(summary, "boolCnt")) + 1));
  140. }
  141. else if (RyanJsonIsDouble(item))
  142. {
  143. TEST_ASSERT_TRUE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(summary, "doubleCnt"),
  144. RyanJsonGetIntValue(RyanJsonGetObjectToKey(summary, "doubleCnt")) + 1));
  145. TEST_ASSERT_TRUE(RyanJsonChangeDoubleValue(item, 25.0));
  146. }
  147. else if (RyanJsonIsString(item))
  148. {
  149. TEST_ASSERT_TRUE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(summary, "stringCnt"),
  150. RyanJsonGetIntValue(RyanJsonGetObjectToKey(summary, "stringCnt")) + 1));
  151. }
  152. else if (RyanJsonIsObject(item))
  153. {
  154. TEST_ASSERT_TRUE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(summary, "objectCnt"),
  155. RyanJsonGetIntValue(RyanJsonGetObjectToKey(summary, "objectCnt")) + 1));
  156. TEST_ASSERT_TRUE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(item, "score"), 9));
  157. }
  158. else
  159. {
  160. TEST_FAIL_MESSAGE("events 中出现未预期类型");
  161. }
  162. idx++;
  163. }
  164. TEST_ASSERT_TRUE_MESSAGE(nullIndex >= 0, "应至少命中一个 null 元素");
  165. TEST_ASSERT_TRUE(RyanJsonReplaceByIndex(events, (uint32_t)nullIndex, RyanJsonCreateString(NULL, "null->string")));
  166. // 不能依赖索引顺序:
  167. // 在 RyanJsonDefaultAddAtHead=true/false 两种模式下,Add*ToArray 的相对位置不同。
  168. // 这里改为顺序无关的语义校验,确保“类型/值/数量”正确即可。
  169. uint32_t boolCnt = 0;
  170. uint32_t doubleCnt = 0;
  171. uint32_t stringCnt = 0;
  172. uint32_t objectCnt = 0;
  173. uint32_t hitEvt = 0;
  174. uint32_t hitNullToString = 0;
  175. RyanJsonArrayForEach(events, item)
  176. {
  177. if (RyanJsonIsBool(item))
  178. {
  179. boolCnt++;
  180. TEST_ASSERT_TRUE(RyanJsonGetBoolValue(item));
  181. }
  182. else if (RyanJsonIsDouble(item))
  183. {
  184. doubleCnt++;
  185. TEST_ASSERT_TRUE(RyanJsonCompareDouble(25.0, RyanJsonGetDoubleValue(item)));
  186. }
  187. else if (RyanJsonIsString(item))
  188. {
  189. const char *s = RyanJsonGetStringValue(item);
  190. TEST_ASSERT_NOT_NULL(s);
  191. stringCnt++;
  192. if (strcmp(s, "evt") == 0) { hitEvt++; }
  193. else if (strcmp(s, "null->string") == 0) { hitNullToString++; }
  194. else
  195. {
  196. TEST_FAIL_MESSAGE("events 中 String 值不在预期集合");
  197. }
  198. }
  199. else if (RyanJsonIsObject(item))
  200. {
  201. objectCnt++;
  202. TEST_ASSERT_EQUAL_INT(9, RyanJsonGetIntValue(RyanJsonGetObjectToKey(item, "score")));
  203. }
  204. else
  205. {
  206. TEST_FAIL_MESSAGE("events 中出现未预期类型");
  207. }
  208. }
  209. TEST_ASSERT_EQUAL_UINT32(1U, boolCnt);
  210. TEST_ASSERT_EQUAL_UINT32(1U, doubleCnt);
  211. TEST_ASSERT_EQUAL_UINT32(2U, stringCnt);
  212. TEST_ASSERT_EQUAL_UINT32(1U, objectCnt);
  213. TEST_ASSERT_EQUAL_UINT32(1U, hitEvt);
  214. TEST_ASSERT_EQUAL_UINT32(1U, hitNullToString);
  215. int32_t summaryTotal = 0;
  216. RyanJsonObjectForEach(summary, item)
  217. {
  218. TEST_ASSERT_TRUE(RyanJsonIsInt(item));
  219. summaryTotal += RyanJsonGetIntValue(item);
  220. }
  221. TEST_ASSERT_EQUAL_INT(5, summaryTotal);
  222. char *printed = RyanJsonPrint(root, 192, RyanJsonFalse, NULL);
  223. TEST_ASSERT_NOT_NULL(printed);
  224. RyanJson_t roundtrip = RyanJsonParse(printed);
  225. TEST_ASSERT_NOT_NULL(roundtrip);
  226. TEST_ASSERT_TRUE(RyanJsonCompare(root, roundtrip));
  227. RyanJsonDelete(roundtrip);
  228. RyanJsonFree(printed);
  229. RyanJsonDelete(root);
  230. }
  231. static void testForEachObjectTraversalWithCrossContainerMove(void)
  232. {
  233. // 复杂链路:
  234. // Parse(wait/done) -> ObjectForEach(wait) 收集条件 -> 复制挂载到 done
  235. // -> 按收集 key 回删 wait -> ArrayForEach(done) 二次校验。
  236. // 目标:
  237. // - 验证 Object 遍历驱动的“条件迁移”不会造成容器链表损坏;
  238. // - 验证迁移后再删除源节点,目标容器数据保持稳定;
  239. // - 验证复杂链路下 key/index 查询语义一致。
  240. const char *source = "{\"wait\":{\"a\":{\"done\":false},\"b\":{\"done\":true},\"c\":{\"done\":true}},\"done\":[]}";
  241. RyanJson_t root = RyanJsonParse(source);
  242. TEST_ASSERT_NOT_NULL(root);
  243. RyanJson_t wait = RyanJsonGetObjectToKey(root, "wait");
  244. RyanJson_t done = RyanJsonGetObjectToKey(root, "done");
  245. TEST_ASSERT_NOT_NULL(wait);
  246. TEST_ASSERT_NOT_NULL(done);
  247. TEST_ASSERT_TRUE(RyanJsonIsObject(wait));
  248. TEST_ASSERT_TRUE(RyanJsonIsArray(done));
  249. char movedKeys[3][8] = {{0}};
  250. uint32_t movedCount = 0;
  251. RyanJson_t item = NULL;
  252. RyanJsonObjectForEach(wait, item)
  253. {
  254. RyanJson_t doneNode = RyanJsonGetObjectToKey(item, "done");
  255. TEST_ASSERT_NOT_NULL(doneNode);
  256. if (RyanJsonGetBoolValue(doneNode))
  257. {
  258. TEST_ASSERT_TRUE_MESSAGE(movedCount < 3U, "movedKeys 缓冲区不足");
  259. RyanJsonSnprintf(movedKeys[movedCount], sizeof(movedKeys[movedCount]), "%s", RyanJsonGetKey(item));
  260. movedCount++;
  261. TEST_ASSERT_TRUE(RyanJsonAddItemToArray(done, RyanJsonDuplicate(item)));
  262. }
  263. }
  264. TEST_ASSERT_EQUAL_UINT32(2U, movedCount);
  265. TEST_ASSERT_EQUAL_UINT32(2U, RyanJsonGetArraySize(done));
  266. for (uint32_t i = 0; i < movedCount; i++)
  267. {
  268. TEST_ASSERT_TRUE_MESSAGE(RyanJsonDeleteByKey(wait, movedKeys[i]), "按收集 key 回删 wait 失败");
  269. }
  270. TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(wait, "a"));
  271. TEST_ASSERT_FALSE(RyanJsonHasObjectToKey(wait, "b"));
  272. TEST_ASSERT_FALSE(RyanJsonHasObjectToKey(wait, "c"));
  273. TEST_ASSERT_EQUAL_UINT32(1U, RyanJsonGetSize(wait));
  274. uint32_t doneTraverseCount = 0;
  275. RyanJsonArrayForEach(done, item)
  276. {
  277. doneTraverseCount++;
  278. TEST_ASSERT_TRUE(RyanJsonGetBoolValue(RyanJsonGetObjectToKey(item, "done")));
  279. }
  280. TEST_ASSERT_EQUAL_UINT32(2U, doneTraverseCount);
  281. char *printed = RyanJsonPrint(root, 128, RyanJsonFalse, NULL);
  282. TEST_ASSERT_NOT_NULL(printed);
  283. RyanJson_t roundtrip = RyanJsonParse(printed);
  284. TEST_ASSERT_NOT_NULL(roundtrip);
  285. TEST_ASSERT_TRUE(RyanJsonCompare(root, roundtrip));
  286. RyanJsonDelete(roundtrip);
  287. RyanJsonFree(printed);
  288. RyanJsonDelete(root);
  289. }
  290. void testForEachRunner(void)
  291. {
  292. UnitySetTestFile(__FILE__);
  293. RUN_TEST(testForEachEdgeCases);
  294. RUN_TEST(testForEachIterativeTraversals);
  295. RUN_TEST(testForEachComplexSummaryWithMixedArrayMacros);
  296. RUN_TEST(testForEachObjectTraversalWithCrossContainerMove);
  297. }