testKeyDuplicateLookup.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #include "testBase.h"
  2. static void testKeyDuplicateCreatedByChangeKeyLookupDetach(void)
  3. {
  4. // 覆盖 ChangeKey 在 non-strict 下制造重复 key 后的查询/分离语义。
  5. #if true == RyanJsonStrictObjectKeyCheck
  6. // strict 模式下不允许制造重复 key,本用例只做控制组退出。
  7. RyanJson_t control = RyanJsonParse("{\"a\":1,\"b\":2}");
  8. TEST_ASSERT_NOT_NULL(control);
  9. RyanJsonDelete(control);
  10. return;
  11. #else
  12. RyanJson_t obj = RyanJsonParse("{\"a\":1,\"b\":2,\"c\":3}");
  13. TEST_ASSERT_NOT_NULL(obj);
  14. RyanJson_t bNode = RyanJsonGetObjectByKey(obj, "b");
  15. TEST_ASSERT_NOT_NULL(bNode);
  16. TEST_ASSERT_TRUE(RyanJsonChangeKey(bNode, "a"));
  17. TEST_ASSERT_EQUAL_UINT32(3U, RyanJsonGetSize(obj));
  18. RyanJson_t first = RyanJsonGetObjectByKey(obj, "a");
  19. TEST_ASSERT_NOT_NULL(first);
  20. int32_t firstVal = RyanJsonGetIntValue(first);
  21. TEST_ASSERT_TRUE_MESSAGE(firstVal == 1 || firstVal == 2, "重复 key 首次命中值不在预期集合");
  22. RyanJson_t removed = RyanJsonDetachByKey(obj, "a");
  23. TEST_ASSERT_NOT_NULL(removed);
  24. TEST_ASSERT_EQUAL_INT_MESSAGE(firstVal, RyanJsonGetIntValue(removed), "GetObjectByKey 与 DetachByKey 应命中同一节点");
  25. RyanJson_t next = RyanJsonGetObjectByKey(obj, "a");
  26. TEST_ASSERT_NOT_NULL(next);
  27. int32_t nextVal = RyanJsonGetIntValue(next);
  28. TEST_ASSERT_TRUE_MESSAGE((nextVal == 1 && firstVal == 2) || (nextVal == 2 && firstVal == 1),
  29. "分离首个重复 key 后,应命中另一个不同值节点");
  30. RyanJsonDelete(removed);
  31. RyanJsonDelete(obj);
  32. #endif
  33. }
  34. static void testKeyDuplicateEscapedVsUtf8LookupDetach(void)
  35. {
  36. // 覆盖转义 key 与 UTF-8 直写 key 的重复语义:
  37. // strict 模式下应拒绝;非 strict 下验证 GetObjectByKey/DetachByKey 命中一致。
  38. const char *utf8Key = "\xE4\xB8\xAD";
  39. #if true == RyanJsonStrictObjectKeyCheck
  40. RyanJson_t obj = RyanJsonParse("{\"\\u4E2D\":1,\"\xE4\xB8\xAD\":2}");
  41. TEST_ASSERT_NULL_MESSAGE(obj, "strict 模式下转义/UTF-8 等价 key 重复应解析失败");
  42. #else
  43. RyanJson_t obj = RyanJsonParse("{\"\\u4E2D\":1,\"\xE4\xB8\xAD\":2}");
  44. TEST_ASSERT_NOT_NULL_MESSAGE(obj, "non-strict 模式下转义/UTF-8 等价 key 重复应解析成功");
  45. RyanJson_t first = RyanJsonGetObjectByKey(obj, utf8Key);
  46. TEST_ASSERT_NOT_NULL(first);
  47. int32_t firstVal = RyanJsonGetIntValue(first);
  48. TEST_ASSERT_TRUE_MESSAGE(firstVal == 1 || firstVal == 2, "重复 key 首次命中值不在预期集合");
  49. RyanJson_t removed = RyanJsonDetachByKey(obj, utf8Key);
  50. TEST_ASSERT_NOT_NULL(removed);
  51. TEST_ASSERT_EQUAL_INT_MESSAGE(firstVal, RyanJsonGetIntValue(removed), "GetObjectByKey 与 DetachByKey 应命中同一节点");
  52. RyanJson_t next = RyanJsonGetObjectByKey(obj, utf8Key);
  53. TEST_ASSERT_NOT_NULL(next);
  54. int32_t nextVal = RyanJsonGetIntValue(next);
  55. TEST_ASSERT_TRUE_MESSAGE((nextVal == 1 && firstVal == 2) || (nextVal == 2 && firstVal == 1),
  56. "分离首个重复 key 后,应命中另一个不同值节点");
  57. TEST_ASSERT_EQUAL_UINT32(1U, RyanJsonGetSize(obj));
  58. RyanJsonDelete(removed);
  59. RyanJsonDelete(obj);
  60. #endif
  61. }
  62. static void testKeyDuplicateGetObjectByKeyAndDetachNext(void)
  63. {
  64. // 覆盖重复 key 下 GetObjectByKey 与 DetachByKey 的协同行为。
  65. RyanJson_t obj = RyanJsonParse("{\"a\":1,\"a\":2}");
  66. if (NULL == obj)
  67. {
  68. // strict 模式下重复 key 会解析失败,走控制组确保用例仍可执行。
  69. RyanJson_t control = RyanJsonParse("{\"a\":1,\"b\":2}");
  70. TEST_ASSERT_NOT_NULL(control);
  71. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(RyanJsonGetObjectByKey(control, "a")));
  72. RyanJsonDelete(control);
  73. return;
  74. }
  75. RyanJson_t first = RyanJsonGetObjectByKey(obj, "a");
  76. TEST_ASSERT_NOT_NULL(first);
  77. int32_t firstVal = RyanJsonGetIntValue(first);
  78. TEST_ASSERT_TRUE_MESSAGE(firstVal == 1 || firstVal == 2, "重复 key 首次命中值不在预期集合");
  79. RyanJson_t removed = RyanJsonDetachByKey(obj, "a");
  80. TEST_ASSERT_NOT_NULL(removed);
  81. int32_t removedVal = RyanJsonGetIntValue(removed);
  82. TEST_ASSERT_EQUAL_INT_MESSAGE(firstVal, removedVal, "GetObjectByKey 与 DetachByKey 应命中同一节点");
  83. RyanJson_t next = RyanJsonGetObjectByKey(obj, "a");
  84. TEST_ASSERT_NOT_NULL(next);
  85. int32_t nextVal = RyanJsonGetIntValue(next);
  86. TEST_ASSERT_TRUE_MESSAGE((nextVal == 1 && firstVal == 2) || (nextVal == 2 && firstVal == 1),
  87. "分离首个重复 key 后,应命中另一个不同值节点");
  88. TEST_ASSERT_EQUAL_UINT32(1U, RyanJsonGetSize(obj));
  89. RyanJsonDelete(removed);
  90. RyanJsonDelete(obj);
  91. }
  92. static void testKeyDuplicateDeleteByKeyTwiceRemovesAll(void)
  93. {
  94. // 覆盖重复 key 下连续 DeleteByKey 的清空路径。
  95. RyanJson_t obj = RyanJsonParse("{\"a\":1,\"a\":2}");
  96. if (NULL == obj)
  97. {
  98. // strict 控制组:无重复 key 时第二次删除应返回 False。
  99. RyanJson_t control = RyanJsonParse("{\"a\":1}");
  100. TEST_ASSERT_NOT_NULL(control);
  101. TEST_ASSERT_TRUE(RyanJsonDeleteByKey(control, "a"));
  102. TEST_ASSERT_FALSE(RyanJsonDeleteByKey(control, "a"));
  103. RyanJsonDelete(control);
  104. return;
  105. }
  106. TEST_ASSERT_TRUE(RyanJsonDeleteByKey(obj, "a"));
  107. TEST_ASSERT_TRUE(RyanJsonDeleteByKey(obj, "a"));
  108. TEST_ASSERT_EQUAL_UINT32(0U, RyanJsonGetSize(obj));
  109. TEST_ASSERT_FALSE(RyanJsonHasObjectByKey(obj, "a"));
  110. RyanJsonDelete(obj);
  111. }
  112. static void testKeyDuplicateDeleteByKeyReducesTraversalCount(void)
  113. {
  114. // 复杂链路:
  115. // Parse(重复 key) -> 统计 key 次数 -> DeleteByKey -> 再统计 -> Compare。
  116. // 目标:验证 DeleteByKey 在非严格模式下只删除一个重复 key,
  117. // 且删除后 Object 仍可继续稳定使用。
  118. RyanJson_t obj = RyanJsonParse("{\"a\":1,\"a\":2,\"b\":3}");
  119. if (NULL == obj)
  120. {
  121. // strict 模式降级:验证单 key 删除语义
  122. obj = RyanJsonParse("{\"a\":1,\"b\":3}");
  123. TEST_ASSERT_NOT_NULL(obj);
  124. TEST_ASSERT_TRUE(RyanJsonDeleteByKey(obj, "a"));
  125. TEST_ASSERT_EQUAL_UINT32(1U, RyanJsonGetSize(obj));
  126. TEST_ASSERT_FALSE(RyanJsonHasObjectByKey(obj, "a"));
  127. RyanJsonDelete(obj);
  128. return;
  129. }
  130. uint32_t aCount = 0;
  131. RyanJson_t item = RyanJsonGetObjectValue(obj);
  132. while (item)
  133. {
  134. if (RyanJsonIsKey(item) && 0 == strcmp(RyanJsonGetKey(item), "a")) { aCount++; }
  135. item = RyanJsonGetNext(item);
  136. }
  137. TEST_ASSERT_EQUAL_UINT32_MESSAGE(2U, aCount, "重复 key 计数应为 2");
  138. TEST_ASSERT_TRUE(RyanJsonDeleteByKey(obj, "a"));
  139. TEST_ASSERT_EQUAL_UINT32_MESSAGE(2U, RyanJsonGetSize(obj), "DeleteByKey 后 Object size 应减少 1");
  140. aCount = 0;
  141. item = RyanJsonGetObjectValue(obj);
  142. while (item)
  143. {
  144. if (RyanJsonIsKey(item) && 0 == strcmp(RyanJsonGetKey(item), "a")) { aCount++; }
  145. item = RyanJsonGetNext(item);
  146. }
  147. TEST_ASSERT_EQUAL_UINT32_MESSAGE(1U, aCount, "DeleteByKey 后重复 key 计数应减少 1");
  148. TEST_ASSERT_TRUE(RyanJsonHasObjectByKey(obj, "a"));
  149. int32_t remainVal = RyanJsonGetIntValue(RyanJsonGetObjectByKey(obj, "a"));
  150. TEST_ASSERT_TRUE_MESSAGE(remainVal == 1 || remainVal == 2, "DeleteByKey 后剩余值不在预期集合");
  151. RyanJson_t expect = RyanJsonParse("{\"a\":9,\"b\":3}");
  152. TEST_ASSERT_NOT_NULL(expect);
  153. TEST_ASSERT_FALSE_MESSAGE(RyanJsonCompare(obj, expect), "DeleteByKey 后值不应被固定假设");
  154. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompareOnlyKey(obj, expect), "DeleteByKey 后结构应与期望 Object 一致");
  155. RyanJsonDelete(expect);
  156. RyanJsonDelete(obj);
  157. }
  158. void testKeyDuplicateLookupRunner(void)
  159. {
  160. UnitySetTestFile(__FILE__);
  161. RUN_TEST(testKeyDuplicateCreatedByChangeKeyLookupDetach);
  162. RUN_TEST(testKeyDuplicateEscapedVsUtf8LookupDetach);
  163. RUN_TEST(testKeyDuplicateGetObjectByKeyAndDetachNext);
  164. RUN_TEST(testKeyDuplicateDeleteByKeyReducesTraversalCount);
  165. RUN_TEST(testKeyDuplicateDeleteByKeyTwiceRemovesAll);
  166. }