| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- #include "testBase.h"
- static void testKeyLookupEmptyString(void)
- {
- // 覆盖空 key 的解析与查询。
- RyanJson_t root = RyanJsonParse("{\"\":1,\"a\":2}");
- TEST_ASSERT_NOT_NULL(root);
- RyanJson_t node = RyanJsonGetObjectByKey(root, "");
- TEST_ASSERT_NOT_NULL(node);
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
- RyanJsonDelete(root);
- }
- static void testKeyLookupEscapedQuote(void)
- {
- // 覆盖 key 中包含引号 \" 的解析与查询。
- RyanJson_t root = RyanJsonParse("{\"\\\"\":1}");
- TEST_ASSERT_NOT_NULL(root);
- const char *key = "\"";
- RyanJson_t node = RyanJsonGetObjectByKey(root, key);
- TEST_ASSERT_NOT_NULL(node);
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
- RyanJsonDelete(root);
- }
- static void testKeyLookupEscapedBackslash(void)
- {
- // 覆盖 key 中包含反斜杠 \\ 的解析与查询。
- RyanJson_t root = RyanJsonParse("{\"\\\\\":1}");
- TEST_ASSERT_NOT_NULL(root);
- const char *key = "\\";
- RyanJson_t node = RyanJsonGetObjectByKey(root, key);
- TEST_ASSERT_NOT_NULL(node);
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
- RyanJsonDelete(root);
- }
- static void testKeyLookupEscapedSolidus(void)
- {
- // 覆盖 key 中包含转义斜杠 \\/ 的解析与查询。
- RyanJson_t root = RyanJsonParse("{\"\\/\":1}");
- TEST_ASSERT_NOT_NULL(root);
- const char *key = "/";
- RyanJson_t node = RyanJsonGetObjectByKey(root, key);
- TEST_ASSERT_NOT_NULL(node);
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
- RyanJsonDelete(root);
- }
- static void testKeyLookupEscapedTab(void)
- {
- // 覆盖 key 中包含 \t 的解析与查询。
- RyanJson_t root = RyanJsonParse("{\"\\t\":1}");
- TEST_ASSERT_NOT_NULL(root);
- const char *key = "\t";
- RyanJson_t node = RyanJsonGetObjectByKey(root, key);
- TEST_ASSERT_NOT_NULL(node);
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
- RyanJsonDelete(root);
- }
- static void testKeyLookupEscapedNewline(void)
- {
- // 覆盖 key 中包含 \n 的解析与查询。
- RyanJson_t root = RyanJsonParse("{\"\\n\":1}");
- TEST_ASSERT_NOT_NULL(root);
- const char *key = "\n";
- RyanJson_t node = RyanJsonGetObjectByKey(root, key);
- TEST_ASSERT_NOT_NULL(node);
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
- RyanJsonDelete(root);
- }
- static void testKeyLookupEscapedCarriageReturn(void)
- {
- // 覆盖 key 中包含 \r 的解析与查询。
- RyanJson_t root = RyanJsonParse("{\"\\r\":1}");
- TEST_ASSERT_NOT_NULL(root);
- const char *key = "\r";
- RyanJson_t node = RyanJsonGetObjectByKey(root, key);
- TEST_ASSERT_NOT_NULL(node);
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
- RyanJsonDelete(root);
- }
- static void testKeyLookupEscapedBackspace(void)
- {
- // 覆盖 key 中包含 \b 的解析与查询。
- RyanJson_t root = RyanJsonParse("{\"\\b\":1}");
- TEST_ASSERT_NOT_NULL(root);
- const char *key = "\b";
- RyanJson_t node = RyanJsonGetObjectByKey(root, key);
- TEST_ASSERT_NOT_NULL(node);
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
- RyanJsonDelete(root);
- }
- static void testKeyLookupEscapedUnicodeControl(void)
- {
- // 覆盖 key 中包含 \u0001 的解析与查询。
- RyanJson_t root = RyanJsonParse("{\"\\u0001\":1}");
- TEST_ASSERT_NOT_NULL(root);
- char key[2] = {1, 0};
- RyanJson_t node = RyanJsonGetObjectByKey(root, key);
- TEST_ASSERT_NOT_NULL(node);
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
- RyanJsonDelete(root);
- }
- static void testKeyChangeFromEscapeToPlain(void)
- {
- // 覆盖 key 从转义字符切换到普通 String 的路径可达性。
- RyanJson_t root = RyanJsonParse("{\"\\t\":1}");
- TEST_ASSERT_NOT_NULL(root);
- const char *tabKey = "\t";
- RyanJson_t node = RyanJsonGetObjectByKey(root, tabKey);
- TEST_ASSERT_NOT_NULL(node);
- TEST_ASSERT_TRUE(RyanJsonChangeKey(node, "tab"));
- TEST_ASSERT_NOT_NULL(RyanJsonGetObjectByKey(root, "tab"));
- TEST_ASSERT_NULL(RyanJsonGetObjectByKey(root, tabKey));
- RyanJsonDelete(root);
- }
- static void testKeyChangeFromEmptyToEscapedNewline(void)
- {
- // 覆盖 key 从空 String 切换到 \n 的路径可达性。
- RyanJson_t root = RyanJsonParse("{\"\":1}");
- TEST_ASSERT_NOT_NULL(root);
- RyanJson_t node = RyanJsonGetObjectByKey(root, "");
- TEST_ASSERT_NOT_NULL(node);
- TEST_ASSERT_TRUE(RyanJsonChangeKey(node, "\n"));
- TEST_ASSERT_NOT_NULL(RyanJsonGetObjectByKey(root, "\n"));
- TEST_ASSERT_NULL(RyanJsonGetObjectByKey(root, ""));
- RyanJsonDelete(root);
- }
- static void testUtf8KeyCreateLookupAndRoundtrip(void)
- {
- // 覆盖 UTF-8 key 的创建、查询与往返:
- // - Create/Add*ToObject 直接写入 UTF-8 key;
- // - GetObjectByKey 可定位多字节 key;
- // - Print/Parse 往返后语义保持一致。
- const char *keyCopyright = "\xC2\xA9";
- const char *keyCn = "\xE4\xB8\xAD";
- const char *keyOx = "\xF0\x9F\x90\x82";
- RyanJson_t root = RyanJsonCreateObject();
- TEST_ASSERT_NOT_NULL(root);
- TEST_ASSERT_TRUE(RyanJsonAddStringToObject(root, keyCopyright, "copy"));
- TEST_ASSERT_TRUE(RyanJsonAddIntToObject(root, keyCn, 7));
- TEST_ASSERT_TRUE(RyanJsonAddBoolToObject(root, keyOx, RyanJsonTrue));
- TEST_ASSERT_EQUAL_STRING("copy", RyanJsonGetStringValue(RyanJsonGetObjectByKey(root, keyCopyright)));
- TEST_ASSERT_EQUAL_INT(7, RyanJsonGetIntValue(RyanJsonGetObjectByKey(root, keyCn)));
- TEST_ASSERT_TRUE(RyanJsonGetBoolValue(RyanJsonGetObjectByKey(root, keyOx)));
- char *printed = RyanJsonPrint(root, 128, RyanJsonFalse, NULL);
- TEST_ASSERT_NOT_NULL(printed);
- RyanJson_t roundtrip = RyanJsonParse(printed);
- TEST_ASSERT_NOT_NULL(roundtrip);
- TEST_ASSERT_EQUAL_STRING("copy", RyanJsonGetStringValue(RyanJsonGetObjectByKey(roundtrip, keyCopyright)));
- TEST_ASSERT_EQUAL_INT(7, RyanJsonGetIntValue(RyanJsonGetObjectByKey(roundtrip, keyCn)));
- TEST_ASSERT_TRUE(RyanJsonGetBoolValue(RyanJsonGetObjectByKey(roundtrip, keyOx)));
- TEST_ASSERT_TRUE(RyanJsonCompare(root, roundtrip));
- RyanJsonDelete(roundtrip);
- RyanJsonFree(printed);
- RyanJsonDelete(root);
- }
- static void testAccessorPathLookupWithEscapedAndEmptyKeys(void)
- {
- // 覆盖“空 key + 特殊字符 key”的路径查询可达性:
- // - 空 key 作为 Object 字段名;
- // - 包含换行/斜杠的 key;
- // - ByKeys 与 HasObjectToKey 在该类路径上的一致性。
- const char *jsonText = "{\"\":{\"line\\nkey\":{\"slash/key\":123,\"quote\\\"k\":456}}}";
- RyanJson_t root = RyanJsonParse(jsonText);
- TEST_ASSERT_NOT_NULL_MESSAGE(root, "特殊 key 路径样本解析失败");
- RyanJson_t v1 = RyanJsonGetObjectByKeys(root, "", "line\nkey", "slash/key", NULL);
- RyanJson_t v2 = RyanJsonGetObjectByKeys(root, "", "line\nkey", "quote\"k", NULL);
- TEST_ASSERT_NOT_NULL(v1);
- TEST_ASSERT_NOT_NULL(v2);
- TEST_ASSERT_TRUE(RyanJsonIsInt(v1));
- TEST_ASSERT_TRUE(RyanJsonIsInt(v2));
- TEST_ASSERT_EQUAL_INT(123, RyanJsonGetIntValue(v1));
- TEST_ASSERT_EQUAL_INT(456, RyanJsonGetIntValue(v2));
- TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(root, "", "line\nkey", "slash/key"));
- TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(root, "", "line\nkey", "quote\"k"));
- TEST_ASSERT_FALSE(RyanJsonHasObjectToKey(root, "", "line\nkey", "missing"));
- RyanJsonDelete(root);
- }
- static void testAccessorUtf8PathLookupAndChangeKey(void)
- {
- // 覆盖 UTF-8 key 在路径 API 中的可达性与改 key 行为:
- // - GetObjectByKeys/HasObjectToKey 对多字节 key 可达;
- // - ChangeKey(UTF-8 -> ASCII) 后路径更新应一致。
- const char *keyCn = "\xE4\xB8\xAD";
- const char *keyOx = "\xF0\x9F\x90\x82";
- const char *keyCopy = "\xC2\xA9";
- RyanJson_t root = RyanJsonCreateObject();
- TEST_ASSERT_NOT_NULL(root);
- RyanJson_t child = RyanJsonCreateObject();
- TEST_ASSERT_NOT_NULL(child);
- TEST_ASSERT_TRUE(RyanJsonAddIntToObject(child, keyOx, 9));
- TEST_ASSERT_TRUE(RyanJsonAddItemToObject(root, keyCn, child));
- RyanJson_t arr = RyanJsonCreateArray();
- TEST_ASSERT_NOT_NULL(arr);
- TEST_ASSERT_TRUE(RyanJsonAddStringToArray(arr, "ok"));
- TEST_ASSERT_TRUE(RyanJsonAddItemToObject(root, keyCopy, arr));
- TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(root, keyCn, keyOx));
- TEST_ASSERT_EQUAL_INT(9, RyanJsonGetIntValue(RyanJsonGetObjectByKeys(root, keyCn, keyOx, NULL)));
- RyanJson_t cnNode = RyanJsonGetObjectByKey(root, keyCn);
- TEST_ASSERT_NOT_NULL(cnNode);
- TEST_ASSERT_TRUE(RyanJsonChangeKey(cnNode, "cn"));
- TEST_ASSERT_FALSE(RyanJsonHasObjectByKey(root, keyCn));
- TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(root, "cn", keyOx));
- TEST_ASSERT_EQUAL_INT(9, RyanJsonGetIntValue(RyanJsonGetObjectByKeys(root, "cn", keyOx, NULL)));
- TEST_ASSERT_NOT_NULL(RyanJsonGetObjectByKey(root, keyCopy));
- TEST_ASSERT_TRUE(RyanJsonIsArray(RyanJsonGetObjectByKey(root, keyCopy)));
- RyanJsonDelete(root);
- }
- static void testAccessorPathLookupUnicodeEscapedAndEmptyKey(void)
- {
- // 覆盖“空 key + Unicode 转义 key + 普通 key”的混合路径可达性。
- // 目标:验证转义 key 会被解码,且 ByKeys/HasObjectToKey 使用 UTF-8 key 可命中。
- const char *keyCn = "\xE4\xB8\xAD";
- RyanJson_t root = RyanJsonParse("{\"\":{\"\\u4E2D\":{\"\\u0061/b\":3}}}");
- TEST_ASSERT_NOT_NULL_MESSAGE(root, "Unicode 混合路径样本解析失败");
- RyanJson_t hit = RyanJsonGetObjectByKeys(root, "", keyCn, "a/b", NULL);
- TEST_ASSERT_NOT_NULL(hit);
- TEST_ASSERT_TRUE(RyanJsonIsInt(hit));
- TEST_ASSERT_EQUAL_INT(3, RyanJsonGetIntValue(hit));
- TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(root, "", keyCn, "a/b"));
- TEST_ASSERT_NULL_MESSAGE(RyanJsonGetObjectByKeys(root, "", "\\u4E2D", "a/b", NULL), "未解码 key 字面量不应命中");
- RyanJsonDelete(root);
- }
- static void testKeyLookupAfterDuplicatePreservesEscapedKeys(void)
- {
- // 覆盖 Duplicate 后转义 key 的查询仍使用解码语义。
- RyanJson_t root = RyanJsonParse("{\"\\t\":1,\"\\n\":2}");
- TEST_ASSERT_NOT_NULL(root);
- RyanJson_t dup = RyanJsonDuplicate(root);
- TEST_ASSERT_NOT_NULL(dup);
- TEST_ASSERT_NOT_NULL(RyanJsonGetObjectByKey(dup, "\t"));
- TEST_ASSERT_NOT_NULL(RyanJsonGetObjectByKey(dup, "\n"));
- TEST_ASSERT_TRUE(RyanJsonCompare(root, dup));
- RyanJsonDelete(dup);
- RyanJsonDelete(root);
- }
- void testKeyEscapeLookupRunner(void)
- {
- UnitySetTestFile(__FILE__);
- RUN_TEST(testKeyLookupEmptyString);
- RUN_TEST(testKeyLookupEscapedQuote);
- RUN_TEST(testKeyLookupEscapedBackslash);
- RUN_TEST(testKeyLookupEscapedSolidus);
- RUN_TEST(testKeyLookupEscapedTab);
- RUN_TEST(testKeyLookupEscapedNewline);
- RUN_TEST(testKeyLookupEscapedCarriageReturn);
- RUN_TEST(testKeyLookupEscapedBackspace);
- RUN_TEST(testKeyLookupEscapedUnicodeControl);
- RUN_TEST(testKeyChangeFromEscapeToPlain);
- RUN_TEST(testKeyChangeFromEmptyToEscapedNewline);
- RUN_TEST(testKeyLookupAfterDuplicatePreservesEscapedKeys);
- RUN_TEST(testUtf8KeyCreateLookupAndRoundtrip);
- RUN_TEST(testAccessorPathLookupWithEscapedAndEmptyKeys);
- RUN_TEST(testAccessorUtf8PathLookupAndChangeKey);
- RUN_TEST(testAccessorPathLookupUnicodeEscapedAndEmptyKey);
- }
|