| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- #include "testBase.h"
- static void testKeyDuplicateCreatedByChangeKeyLookupDetach(void)
- {
- // 覆盖 ChangeKey 在 non-strict 下制造重复 key 后的查询/分离语义。
- #if true == RyanJsonStrictObjectKeyCheck
- // strict 模式下不允许制造重复 key,本用例只做控制组退出。
- RyanJson_t control = RyanJsonParse("{\"a\":1,\"b\":2}");
- TEST_ASSERT_NOT_NULL(control);
- RyanJsonDelete(control);
- return;
- #else
- RyanJson_t obj = RyanJsonParse("{\"a\":1,\"b\":2,\"c\":3}");
- TEST_ASSERT_NOT_NULL(obj);
- RyanJson_t bNode = RyanJsonGetObjectByKey(obj, "b");
- TEST_ASSERT_NOT_NULL(bNode);
- TEST_ASSERT_TRUE(RyanJsonChangeKey(bNode, "a"));
- TEST_ASSERT_EQUAL_UINT32(3U, RyanJsonGetSize(obj));
- RyanJson_t first = RyanJsonGetObjectByKey(obj, "a");
- TEST_ASSERT_NOT_NULL(first);
- int32_t firstVal = RyanJsonGetIntValue(first);
- TEST_ASSERT_TRUE_MESSAGE(firstVal == 1 || firstVal == 2, "重复 key 首次命中值不在预期集合");
- RyanJson_t removed = RyanJsonDetachByKey(obj, "a");
- TEST_ASSERT_NOT_NULL(removed);
- TEST_ASSERT_EQUAL_INT_MESSAGE(firstVal, RyanJsonGetIntValue(removed), "GetObjectByKey 与 DetachByKey 应命中同一节点");
- RyanJson_t next = RyanJsonGetObjectByKey(obj, "a");
- TEST_ASSERT_NOT_NULL(next);
- int32_t nextVal = RyanJsonGetIntValue(next);
- TEST_ASSERT_TRUE_MESSAGE((nextVal == 1 && firstVal == 2) || (nextVal == 2 && firstVal == 1),
- "分离首个重复 key 后,应命中另一个不同值节点");
- RyanJsonDelete(removed);
- RyanJsonDelete(obj);
- #endif
- }
- static void testKeyDuplicateEscapedVsUtf8LookupDetach(void)
- {
- // 覆盖转义 key 与 UTF-8 直写 key 的重复语义:
- // strict 模式下应拒绝;非 strict 下验证 GetObjectByKey/DetachByKey 命中一致。
- const char *utf8Key = "\xE4\xB8\xAD";
- #if true == RyanJsonStrictObjectKeyCheck
- RyanJson_t obj = RyanJsonParse("{\"\\u4E2D\":1,\"\xE4\xB8\xAD\":2}");
- TEST_ASSERT_NULL_MESSAGE(obj, "strict 模式下转义/UTF-8 等价 key 重复应解析失败");
- #else
- RyanJson_t obj = RyanJsonParse("{\"\\u4E2D\":1,\"\xE4\xB8\xAD\":2}");
- TEST_ASSERT_NOT_NULL_MESSAGE(obj, "non-strict 模式下转义/UTF-8 等价 key 重复应解析成功");
- RyanJson_t first = RyanJsonGetObjectByKey(obj, utf8Key);
- TEST_ASSERT_NOT_NULL(first);
- int32_t firstVal = RyanJsonGetIntValue(first);
- TEST_ASSERT_TRUE_MESSAGE(firstVal == 1 || firstVal == 2, "重复 key 首次命中值不在预期集合");
- RyanJson_t removed = RyanJsonDetachByKey(obj, utf8Key);
- TEST_ASSERT_NOT_NULL(removed);
- TEST_ASSERT_EQUAL_INT_MESSAGE(firstVal, RyanJsonGetIntValue(removed), "GetObjectByKey 与 DetachByKey 应命中同一节点");
- RyanJson_t next = RyanJsonGetObjectByKey(obj, utf8Key);
- TEST_ASSERT_NOT_NULL(next);
- int32_t nextVal = RyanJsonGetIntValue(next);
- TEST_ASSERT_TRUE_MESSAGE((nextVal == 1 && firstVal == 2) || (nextVal == 2 && firstVal == 1),
- "分离首个重复 key 后,应命中另一个不同值节点");
- TEST_ASSERT_EQUAL_UINT32(1U, RyanJsonGetSize(obj));
- RyanJsonDelete(removed);
- RyanJsonDelete(obj);
- #endif
- }
- static void testKeyDuplicateGetObjectByKeyAndDetachNext(void)
- {
- // 覆盖重复 key 下 GetObjectByKey 与 DetachByKey 的协同行为。
- RyanJson_t obj = RyanJsonParse("{\"a\":1,\"a\":2}");
- if (NULL == obj)
- {
- // strict 模式下重复 key 会解析失败,走控制组确保用例仍可执行。
- RyanJson_t control = RyanJsonParse("{\"a\":1,\"b\":2}");
- TEST_ASSERT_NOT_NULL(control);
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(RyanJsonGetObjectByKey(control, "a")));
- RyanJsonDelete(control);
- return;
- }
- RyanJson_t first = RyanJsonGetObjectByKey(obj, "a");
- TEST_ASSERT_NOT_NULL(first);
- int32_t firstVal = RyanJsonGetIntValue(first);
- TEST_ASSERT_TRUE_MESSAGE(firstVal == 1 || firstVal == 2, "重复 key 首次命中值不在预期集合");
- RyanJson_t removed = RyanJsonDetachByKey(obj, "a");
- TEST_ASSERT_NOT_NULL(removed);
- int32_t removedVal = RyanJsonGetIntValue(removed);
- TEST_ASSERT_EQUAL_INT_MESSAGE(firstVal, removedVal, "GetObjectByKey 与 DetachByKey 应命中同一节点");
- RyanJson_t next = RyanJsonGetObjectByKey(obj, "a");
- TEST_ASSERT_NOT_NULL(next);
- int32_t nextVal = RyanJsonGetIntValue(next);
- TEST_ASSERT_TRUE_MESSAGE((nextVal == 1 && firstVal == 2) || (nextVal == 2 && firstVal == 1),
- "分离首个重复 key 后,应命中另一个不同值节点");
- TEST_ASSERT_EQUAL_UINT32(1U, RyanJsonGetSize(obj));
- RyanJsonDelete(removed);
- RyanJsonDelete(obj);
- }
- static void testKeyDuplicateDeleteByKeyTwiceRemovesAll(void)
- {
- // 覆盖重复 key 下连续 DeleteByKey 的清空路径。
- RyanJson_t obj = RyanJsonParse("{\"a\":1,\"a\":2}");
- if (NULL == obj)
- {
- // strict 控制组:无重复 key 时第二次删除应返回 False。
- RyanJson_t control = RyanJsonParse("{\"a\":1}");
- TEST_ASSERT_NOT_NULL(control);
- TEST_ASSERT_TRUE(RyanJsonDeleteByKey(control, "a"));
- TEST_ASSERT_FALSE(RyanJsonDeleteByKey(control, "a"));
- RyanJsonDelete(control);
- return;
- }
- TEST_ASSERT_TRUE(RyanJsonDeleteByKey(obj, "a"));
- TEST_ASSERT_TRUE(RyanJsonDeleteByKey(obj, "a"));
- TEST_ASSERT_EQUAL_UINT32(0U, RyanJsonGetSize(obj));
- TEST_ASSERT_FALSE(RyanJsonHasObjectByKey(obj, "a"));
- RyanJsonDelete(obj);
- }
- static void testKeyDuplicateDeleteByKeyReducesTraversalCount(void)
- {
- // 复杂链路:
- // Parse(重复 key) -> 统计 key 次数 -> DeleteByKey -> 再统计 -> Compare。
- // 目标:验证 DeleteByKey 在非严格模式下只删除一个重复 key,
- // 且删除后 Object 仍可继续稳定使用。
- RyanJson_t obj = RyanJsonParse("{\"a\":1,\"a\":2,\"b\":3}");
- if (NULL == obj)
- {
- // strict 模式降级:验证单 key 删除语义
- obj = RyanJsonParse("{\"a\":1,\"b\":3}");
- TEST_ASSERT_NOT_NULL(obj);
- TEST_ASSERT_TRUE(RyanJsonDeleteByKey(obj, "a"));
- TEST_ASSERT_EQUAL_UINT32(1U, RyanJsonGetSize(obj));
- TEST_ASSERT_FALSE(RyanJsonHasObjectByKey(obj, "a"));
- RyanJsonDelete(obj);
- return;
- }
- uint32_t aCount = 0;
- RyanJson_t item = RyanJsonGetObjectValue(obj);
- while (item)
- {
- if (RyanJsonIsKey(item) && 0 == strcmp(RyanJsonGetKey(item), "a")) { aCount++; }
- item = RyanJsonGetNext(item);
- }
- TEST_ASSERT_EQUAL_UINT32_MESSAGE(2U, aCount, "重复 key 计数应为 2");
- TEST_ASSERT_TRUE(RyanJsonDeleteByKey(obj, "a"));
- TEST_ASSERT_EQUAL_UINT32_MESSAGE(2U, RyanJsonGetSize(obj), "DeleteByKey 后 Object size 应减少 1");
- aCount = 0;
- item = RyanJsonGetObjectValue(obj);
- while (item)
- {
- if (RyanJsonIsKey(item) && 0 == strcmp(RyanJsonGetKey(item), "a")) { aCount++; }
- item = RyanJsonGetNext(item);
- }
- TEST_ASSERT_EQUAL_UINT32_MESSAGE(1U, aCount, "DeleteByKey 后重复 key 计数应减少 1");
- TEST_ASSERT_TRUE(RyanJsonHasObjectByKey(obj, "a"));
- int32_t remainVal = RyanJsonGetIntValue(RyanJsonGetObjectByKey(obj, "a"));
- TEST_ASSERT_TRUE_MESSAGE(remainVal == 1 || remainVal == 2, "DeleteByKey 后剩余值不在预期集合");
- RyanJson_t expect = RyanJsonParse("{\"a\":9,\"b\":3}");
- TEST_ASSERT_NOT_NULL(expect);
- TEST_ASSERT_FALSE_MESSAGE(RyanJsonCompare(obj, expect), "DeleteByKey 后值不应被固定假设");
- TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompareOnlyKey(obj, expect), "DeleteByKey 后结构应与期望 Object 一致");
- RyanJsonDelete(expect);
- RyanJsonDelete(obj);
- }
- void testKeyDuplicateLookupRunner(void)
- {
- UnitySetTestFile(__FILE__);
- RUN_TEST(testKeyDuplicateCreatedByChangeKeyLookupDetach);
- RUN_TEST(testKeyDuplicateEscapedVsUtf8LookupDetach);
- RUN_TEST(testKeyDuplicateGetObjectByKeyAndDetachNext);
- RUN_TEST(testKeyDuplicateDeleteByKeyReducesTraversalCount);
- RUN_TEST(testKeyDuplicateDeleteByKeyTwiceRemovesAll);
- }
|