testKeyEscapeLookup.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. #include "testBase.h"
  2. static void testKeyLookupEmptyString(void)
  3. {
  4. // 覆盖空 key 的解析与查询。
  5. RyanJson_t root = RyanJsonParse("{\"\":1,\"a\":2}");
  6. TEST_ASSERT_NOT_NULL(root);
  7. RyanJson_t node = RyanJsonGetObjectByKey(root, "");
  8. TEST_ASSERT_NOT_NULL(node);
  9. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
  10. RyanJsonDelete(root);
  11. }
  12. static void testKeyLookupEscapedQuote(void)
  13. {
  14. // 覆盖 key 中包含引号 \" 的解析与查询。
  15. RyanJson_t root = RyanJsonParse("{\"\\\"\":1}");
  16. TEST_ASSERT_NOT_NULL(root);
  17. const char *key = "\"";
  18. RyanJson_t node = RyanJsonGetObjectByKey(root, key);
  19. TEST_ASSERT_NOT_NULL(node);
  20. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
  21. RyanJsonDelete(root);
  22. }
  23. static void testKeyLookupEscapedBackslash(void)
  24. {
  25. // 覆盖 key 中包含反斜杠 \\ 的解析与查询。
  26. RyanJson_t root = RyanJsonParse("{\"\\\\\":1}");
  27. TEST_ASSERT_NOT_NULL(root);
  28. const char *key = "\\";
  29. RyanJson_t node = RyanJsonGetObjectByKey(root, key);
  30. TEST_ASSERT_NOT_NULL(node);
  31. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
  32. RyanJsonDelete(root);
  33. }
  34. static void testKeyLookupEscapedSolidus(void)
  35. {
  36. // 覆盖 key 中包含转义斜杠 \\/ 的解析与查询。
  37. RyanJson_t root = RyanJsonParse("{\"\\/\":1}");
  38. TEST_ASSERT_NOT_NULL(root);
  39. const char *key = "/";
  40. RyanJson_t node = RyanJsonGetObjectByKey(root, key);
  41. TEST_ASSERT_NOT_NULL(node);
  42. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
  43. RyanJsonDelete(root);
  44. }
  45. static void testKeyLookupEscapedTab(void)
  46. {
  47. // 覆盖 key 中包含 \t 的解析与查询。
  48. RyanJson_t root = RyanJsonParse("{\"\\t\":1}");
  49. TEST_ASSERT_NOT_NULL(root);
  50. const char *key = "\t";
  51. RyanJson_t node = RyanJsonGetObjectByKey(root, key);
  52. TEST_ASSERT_NOT_NULL(node);
  53. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
  54. RyanJsonDelete(root);
  55. }
  56. static void testKeyLookupEscapedNewline(void)
  57. {
  58. // 覆盖 key 中包含 \n 的解析与查询。
  59. RyanJson_t root = RyanJsonParse("{\"\\n\":1}");
  60. TEST_ASSERT_NOT_NULL(root);
  61. const char *key = "\n";
  62. RyanJson_t node = RyanJsonGetObjectByKey(root, key);
  63. TEST_ASSERT_NOT_NULL(node);
  64. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
  65. RyanJsonDelete(root);
  66. }
  67. static void testKeyLookupEscapedCarriageReturn(void)
  68. {
  69. // 覆盖 key 中包含 \r 的解析与查询。
  70. RyanJson_t root = RyanJsonParse("{\"\\r\":1}");
  71. TEST_ASSERT_NOT_NULL(root);
  72. const char *key = "\r";
  73. RyanJson_t node = RyanJsonGetObjectByKey(root, key);
  74. TEST_ASSERT_NOT_NULL(node);
  75. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
  76. RyanJsonDelete(root);
  77. }
  78. static void testKeyLookupEscapedBackspace(void)
  79. {
  80. // 覆盖 key 中包含 \b 的解析与查询。
  81. RyanJson_t root = RyanJsonParse("{\"\\b\":1}");
  82. TEST_ASSERT_NOT_NULL(root);
  83. const char *key = "\b";
  84. RyanJson_t node = RyanJsonGetObjectByKey(root, key);
  85. TEST_ASSERT_NOT_NULL(node);
  86. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
  87. RyanJsonDelete(root);
  88. }
  89. static void testKeyLookupEscapedUnicodeControl(void)
  90. {
  91. // 覆盖 key 中包含 \u0001 的解析与查询。
  92. RyanJson_t root = RyanJsonParse("{\"\\u0001\":1}");
  93. TEST_ASSERT_NOT_NULL(root);
  94. char key[2] = {1, 0};
  95. RyanJson_t node = RyanJsonGetObjectByKey(root, key);
  96. TEST_ASSERT_NOT_NULL(node);
  97. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(node));
  98. RyanJsonDelete(root);
  99. }
  100. static void testKeyChangeFromEscapeToPlain(void)
  101. {
  102. // 覆盖 key 从转义字符切换到普通 String 的路径可达性。
  103. RyanJson_t root = RyanJsonParse("{\"\\t\":1}");
  104. TEST_ASSERT_NOT_NULL(root);
  105. const char *tabKey = "\t";
  106. RyanJson_t node = RyanJsonGetObjectByKey(root, tabKey);
  107. TEST_ASSERT_NOT_NULL(node);
  108. TEST_ASSERT_TRUE(RyanJsonChangeKey(node, "tab"));
  109. TEST_ASSERT_NOT_NULL(RyanJsonGetObjectByKey(root, "tab"));
  110. TEST_ASSERT_NULL(RyanJsonGetObjectByKey(root, tabKey));
  111. RyanJsonDelete(root);
  112. }
  113. static void testKeyChangeFromEmptyToEscapedNewline(void)
  114. {
  115. // 覆盖 key 从空 String 切换到 \n 的路径可达性。
  116. RyanJson_t root = RyanJsonParse("{\"\":1}");
  117. TEST_ASSERT_NOT_NULL(root);
  118. RyanJson_t node = RyanJsonGetObjectByKey(root, "");
  119. TEST_ASSERT_NOT_NULL(node);
  120. TEST_ASSERT_TRUE(RyanJsonChangeKey(node, "\n"));
  121. TEST_ASSERT_NOT_NULL(RyanJsonGetObjectByKey(root, "\n"));
  122. TEST_ASSERT_NULL(RyanJsonGetObjectByKey(root, ""));
  123. RyanJsonDelete(root);
  124. }
  125. static void testUtf8KeyCreateLookupAndRoundtrip(void)
  126. {
  127. // 覆盖 UTF-8 key 的创建、查询与往返:
  128. // - Create/Add*ToObject 直接写入 UTF-8 key;
  129. // - GetObjectByKey 可定位多字节 key;
  130. // - Print/Parse 往返后语义保持一致。
  131. const char *keyCopyright = "\xC2\xA9";
  132. const char *keyCn = "\xE4\xB8\xAD";
  133. const char *keyOx = "\xF0\x9F\x90\x82";
  134. RyanJson_t root = RyanJsonCreateObject();
  135. TEST_ASSERT_NOT_NULL(root);
  136. TEST_ASSERT_TRUE(RyanJsonAddStringToObject(root, keyCopyright, "copy"));
  137. TEST_ASSERT_TRUE(RyanJsonAddIntToObject(root, keyCn, 7));
  138. TEST_ASSERT_TRUE(RyanJsonAddBoolToObject(root, keyOx, RyanJsonTrue));
  139. TEST_ASSERT_EQUAL_STRING("copy", RyanJsonGetStringValue(RyanJsonGetObjectByKey(root, keyCopyright)));
  140. TEST_ASSERT_EQUAL_INT(7, RyanJsonGetIntValue(RyanJsonGetObjectByKey(root, keyCn)));
  141. TEST_ASSERT_TRUE(RyanJsonGetBoolValue(RyanJsonGetObjectByKey(root, keyOx)));
  142. char *printed = RyanJsonPrint(root, 128, RyanJsonFalse, NULL);
  143. TEST_ASSERT_NOT_NULL(printed);
  144. RyanJson_t roundtrip = RyanJsonParse(printed);
  145. TEST_ASSERT_NOT_NULL(roundtrip);
  146. TEST_ASSERT_EQUAL_STRING("copy", RyanJsonGetStringValue(RyanJsonGetObjectByKey(roundtrip, keyCopyright)));
  147. TEST_ASSERT_EQUAL_INT(7, RyanJsonGetIntValue(RyanJsonGetObjectByKey(roundtrip, keyCn)));
  148. TEST_ASSERT_TRUE(RyanJsonGetBoolValue(RyanJsonGetObjectByKey(roundtrip, keyOx)));
  149. TEST_ASSERT_TRUE(RyanJsonCompare(root, roundtrip));
  150. RyanJsonDelete(roundtrip);
  151. RyanJsonFree(printed);
  152. RyanJsonDelete(root);
  153. }
  154. static void testAccessorPathLookupWithEscapedAndEmptyKeys(void)
  155. {
  156. // 覆盖“空 key + 特殊字符 key”的路径查询可达性:
  157. // - 空 key 作为 Object 字段名;
  158. // - 包含换行/斜杠的 key;
  159. // - ByKeys 与 HasObjectToKey 在该类路径上的一致性。
  160. const char *jsonText = "{\"\":{\"line\\nkey\":{\"slash/key\":123,\"quote\\\"k\":456}}}";
  161. RyanJson_t root = RyanJsonParse(jsonText);
  162. TEST_ASSERT_NOT_NULL_MESSAGE(root, "特殊 key 路径样本解析失败");
  163. RyanJson_t v1 = RyanJsonGetObjectByKeys(root, "", "line\nkey", "slash/key", NULL);
  164. RyanJson_t v2 = RyanJsonGetObjectByKeys(root, "", "line\nkey", "quote\"k", NULL);
  165. TEST_ASSERT_NOT_NULL(v1);
  166. TEST_ASSERT_NOT_NULL(v2);
  167. TEST_ASSERT_TRUE(RyanJsonIsInt(v1));
  168. TEST_ASSERT_TRUE(RyanJsonIsInt(v2));
  169. TEST_ASSERT_EQUAL_INT(123, RyanJsonGetIntValue(v1));
  170. TEST_ASSERT_EQUAL_INT(456, RyanJsonGetIntValue(v2));
  171. TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(root, "", "line\nkey", "slash/key"));
  172. TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(root, "", "line\nkey", "quote\"k"));
  173. TEST_ASSERT_FALSE(RyanJsonHasObjectToKey(root, "", "line\nkey", "missing"));
  174. RyanJsonDelete(root);
  175. }
  176. static void testAccessorUtf8PathLookupAndChangeKey(void)
  177. {
  178. // 覆盖 UTF-8 key 在路径 API 中的可达性与改 key 行为:
  179. // - GetObjectByKeys/HasObjectToKey 对多字节 key 可达;
  180. // - ChangeKey(UTF-8 -> ASCII) 后路径更新应一致。
  181. const char *keyCn = "\xE4\xB8\xAD";
  182. const char *keyOx = "\xF0\x9F\x90\x82";
  183. const char *keyCopy = "\xC2\xA9";
  184. RyanJson_t root = RyanJsonCreateObject();
  185. TEST_ASSERT_NOT_NULL(root);
  186. RyanJson_t child = RyanJsonCreateObject();
  187. TEST_ASSERT_NOT_NULL(child);
  188. TEST_ASSERT_TRUE(RyanJsonAddIntToObject(child, keyOx, 9));
  189. TEST_ASSERT_TRUE(RyanJsonAddItemToObject(root, keyCn, child));
  190. RyanJson_t arr = RyanJsonCreateArray();
  191. TEST_ASSERT_NOT_NULL(arr);
  192. TEST_ASSERT_TRUE(RyanJsonAddStringToArray(arr, "ok"));
  193. TEST_ASSERT_TRUE(RyanJsonAddItemToObject(root, keyCopy, arr));
  194. TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(root, keyCn, keyOx));
  195. TEST_ASSERT_EQUAL_INT(9, RyanJsonGetIntValue(RyanJsonGetObjectByKeys(root, keyCn, keyOx, NULL)));
  196. RyanJson_t cnNode = RyanJsonGetObjectByKey(root, keyCn);
  197. TEST_ASSERT_NOT_NULL(cnNode);
  198. TEST_ASSERT_TRUE(RyanJsonChangeKey(cnNode, "cn"));
  199. TEST_ASSERT_FALSE(RyanJsonHasObjectByKey(root, keyCn));
  200. TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(root, "cn", keyOx));
  201. TEST_ASSERT_EQUAL_INT(9, RyanJsonGetIntValue(RyanJsonGetObjectByKeys(root, "cn", keyOx, NULL)));
  202. TEST_ASSERT_NOT_NULL(RyanJsonGetObjectByKey(root, keyCopy));
  203. TEST_ASSERT_TRUE(RyanJsonIsArray(RyanJsonGetObjectByKey(root, keyCopy)));
  204. RyanJsonDelete(root);
  205. }
  206. static void testAccessorPathLookupUnicodeEscapedAndEmptyKey(void)
  207. {
  208. // 覆盖“空 key + Unicode 转义 key + 普通 key”的混合路径可达性。
  209. // 目标:验证转义 key 会被解码,且 ByKeys/HasObjectToKey 使用 UTF-8 key 可命中。
  210. const char *keyCn = "\xE4\xB8\xAD";
  211. RyanJson_t root = RyanJsonParse("{\"\":{\"\\u4E2D\":{\"\\u0061/b\":3}}}");
  212. TEST_ASSERT_NOT_NULL_MESSAGE(root, "Unicode 混合路径样本解析失败");
  213. RyanJson_t hit = RyanJsonGetObjectByKeys(root, "", keyCn, "a/b", NULL);
  214. TEST_ASSERT_NOT_NULL(hit);
  215. TEST_ASSERT_TRUE(RyanJsonIsInt(hit));
  216. TEST_ASSERT_EQUAL_INT(3, RyanJsonGetIntValue(hit));
  217. TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(root, "", keyCn, "a/b"));
  218. TEST_ASSERT_NULL_MESSAGE(RyanJsonGetObjectByKeys(root, "", "\\u4E2D", "a/b", NULL), "未解码 key 字面量不应命中");
  219. RyanJsonDelete(root);
  220. }
  221. static void testKeyLookupAfterDuplicatePreservesEscapedKeys(void)
  222. {
  223. // 覆盖 Duplicate 后转义 key 的查询仍使用解码语义。
  224. RyanJson_t root = RyanJsonParse("{\"\\t\":1,\"\\n\":2}");
  225. TEST_ASSERT_NOT_NULL(root);
  226. RyanJson_t dup = RyanJsonDuplicate(root);
  227. TEST_ASSERT_NOT_NULL(dup);
  228. TEST_ASSERT_NOT_NULL(RyanJsonGetObjectByKey(dup, "\t"));
  229. TEST_ASSERT_NOT_NULL(RyanJsonGetObjectByKey(dup, "\n"));
  230. TEST_ASSERT_TRUE(RyanJsonCompare(root, dup));
  231. RyanJsonDelete(dup);
  232. RyanJsonDelete(root);
  233. }
  234. void testKeyEscapeLookupRunner(void)
  235. {
  236. UnitySetTestFile(__FILE__);
  237. RUN_TEST(testKeyLookupEmptyString);
  238. RUN_TEST(testKeyLookupEscapedQuote);
  239. RUN_TEST(testKeyLookupEscapedBackslash);
  240. RUN_TEST(testKeyLookupEscapedSolidus);
  241. RUN_TEST(testKeyLookupEscapedTab);
  242. RUN_TEST(testKeyLookupEscapedNewline);
  243. RUN_TEST(testKeyLookupEscapedCarriageReturn);
  244. RUN_TEST(testKeyLookupEscapedBackspace);
  245. RUN_TEST(testKeyLookupEscapedUnicodeControl);
  246. RUN_TEST(testKeyChangeFromEscapeToPlain);
  247. RUN_TEST(testKeyChangeFromEmptyToEscapedNewline);
  248. RUN_TEST(testKeyLookupAfterDuplicatePreservesEscapedKeys);
  249. RUN_TEST(testUtf8KeyCreateLookupAndRoundtrip);
  250. RUN_TEST(testAccessorPathLookupWithEscapedAndEmptyKeys);
  251. RUN_TEST(testAccessorUtf8PathLookupAndChangeKey);
  252. RUN_TEST(testAccessorPathLookupUnicodeEscapedAndEmptyKey);
  253. }