testChange.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. #include "testBase.h"
  2. static void testChangeEdgeCases(void)
  3. {
  4. // 测试 NULL 输入处理
  5. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeBoolValue(NULL, true), "ChangeBoolValue(NULL) 应返回 False");
  6. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeIntValue(NULL, 1), "ChangeIntValue(NULL) 应返回 False");
  7. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeDoubleValue(NULL, 1.0), "ChangeDoubleValue(NULL) 应返回 False");
  8. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeStringValue(NULL, "test"), "ChangeStringValue(NULL) 应返回 False");
  9. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeKey(NULL, "key"), "ChangeKey(NULL) 应返回 False");
  10. // 测试类型不匹配处理
  11. RyanJson_t intNode = RyanJsonCreateInt(NULL, 1);
  12. RyanJson_t doubleNode = RyanJsonCreateDouble(NULL, 1.0);
  13. RyanJson_t boolNode = RyanJsonCreateBool(NULL, RyanJsonTrue);
  14. RyanJson_t strNode = RyanJsonCreateString(NULL, "s");
  15. RyanJson_t keyedStrNode = RyanJsonCreateString("k", "v");
  16. RyanJson_t keyedBoolNode = RyanJsonCreateBool("flag", RyanJsonTrue);
  17. TEST_ASSERT_NOT_NULL(intNode);
  18. TEST_ASSERT_NOT_NULL(doubleNode);
  19. TEST_ASSERT_NOT_NULL(boolNode);
  20. TEST_ASSERT_NOT_NULL(strNode);
  21. TEST_ASSERT_NOT_NULL(keyedStrNode);
  22. TEST_ASSERT_NOT_NULL(keyedBoolNode);
  23. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeIntValue(doubleNode, 3), "ChangeIntValue(非 Int 节点) 应返回 False");
  24. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeDoubleValue(intNode, 3.14), "ChangeDoubleValue(非 Double 节点) 应返回 False");
  25. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeBoolValue(intNode, RyanJsonTrue), "ChangeBoolValue(非 Bool 节点) 应返回 False");
  26. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeStringValue(intNode, "x"), "ChangeStringValue(非 String 节点) 应返回 False");
  27. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeKey(strNode, "k2"), "ChangeKey(无Key的 String 节点) 应返回 False");
  28. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeKey(keyedStrNode, NULL), "ChangeKey(key!=NULL 前置条件) 应返回 False");
  29. // 失败后原值应保持不变
  30. TEST_ASSERT_TRUE_MESSAGE(RyanJsonGetBoolValue(boolNode), "bool 初始值错误");
  31. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeIntValue(boolNode, 9), "ChangeIntValue(Bool 节点) 应返回 False");
  32. TEST_ASSERT_TRUE_MESSAGE(RyanJsonGetBoolValue(boolNode), "失败后 bool 值不应变化");
  33. TEST_ASSERT_EQUAL_INT_MESSAGE(1, RyanJsonGetIntValue(intNode), "int 初始值错误");
  34. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeDoubleValue(intNode, 8.8), "ChangeDoubleValue(Int 节点) 应返回 False");
  35. TEST_ASSERT_EQUAL_INT_MESSAGE(1, RyanJsonGetIntValue(intNode), "失败后 int 值不应变化");
  36. TEST_ASSERT_EQUAL_STRING_MESSAGE("v", RyanJsonGetStringValue(keyedStrNode), "string 初始值错误");
  37. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeBoolValue(keyedStrNode, RyanJsonFalse), "ChangeBoolValue(String 节点) 应返回 False");
  38. TEST_ASSERT_EQUAL_STRING_MESSAGE("v", RyanJsonGetStringValue(keyedStrNode), "失败后 string 值不应变化");
  39. TEST_ASSERT_EQUAL_STRING_MESSAGE("k", RyanJsonGetKey(keyedStrNode), "失败后 key 不应变化");
  40. // 有 key 的非 String 节点允许改 key,且值不应改变
  41. TEST_ASSERT_TRUE_MESSAGE(RyanJsonChangeKey(keyedBoolNode, "flag2"), "ChangeKey(Bool+Key 节点) 应成功");
  42. TEST_ASSERT_EQUAL_STRING_MESSAGE("flag2", RyanJsonGetKey(keyedBoolNode), "Bool 节点改 key 失败");
  43. TEST_ASSERT_TRUE_MESSAGE(RyanJsonGetBoolValue(keyedBoolNode), "Bool 节点改 key 后 value 不应变化");
  44. RyanJsonDelete(intNode);
  45. RyanJsonDelete(doubleNode);
  46. RyanJsonDelete(boolNode);
  47. RyanJsonDelete(strNode);
  48. RyanJsonDelete(keyedStrNode);
  49. RyanJsonDelete(keyedBoolNode);
  50. }
  51. static void testChangeKeyDuplicatePolicy(void)
  52. {
  53. // 这个用例只证明“改成已存在 key”时的策略差异:
  54. // strict 必须拒绝,non-strict 可以成功;不重复覆盖后续查询/roundtrip 语义。
  55. RyanJson_t obj = RyanJsonCreateObject();
  56. TEST_ASSERT_NOT_NULL(obj);
  57. TEST_ASSERT_TRUE(RyanJsonAddIntToObject(obj, "a", 1));
  58. TEST_ASSERT_TRUE(RyanJsonAddIntToObject(obj, "b", 2));
  59. RyanJson_t bNode = RyanJsonGetObjectByKey(obj, "b");
  60. TEST_ASSERT_NOT_NULL_MESSAGE(bNode, "前置条件失败:缺少 key=b");
  61. #if true == RyanJsonStrictObjectKeyCheck
  62. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeKey(bNode, "a"), "严格模式下 ChangeKey 重复 key 应失败");
  63. TEST_ASSERT_NOT_NULL_MESSAGE(RyanJsonGetObjectByKey(obj, "b"), "严格模式失败后原 key 应保持不变");
  64. TEST_ASSERT_EQUAL_INT_MESSAGE(2, RyanJsonGetIntValue(RyanJsonGetObjectByKey(obj, "b")), "严格模式失败后节点值不应变化");
  65. #else
  66. TEST_ASSERT_TRUE_MESSAGE(RyanJsonChangeKey(bNode, "a"), "非严格模式下 ChangeKey 重复 key 应成功");
  67. TEST_ASSERT_NULL_MESSAGE(RyanJsonGetObjectByKey(obj, "b"), "非严格模式成功后旧 key 应不存在");
  68. TEST_ASSERT_EQUAL_UINT32_MESSAGE(2U, RyanJsonGetSize(obj), "非严格模式成功后 Object 元素数量应保持不变");
  69. #endif
  70. RyanJsonDelete(obj);
  71. }
  72. static void testChangeKeySameTextNoOp(void)
  73. {
  74. // 同文本改 key 应视为 no-op:
  75. // 既不能被 strict 重复 key 检查误伤,也不能替换节点身份或污染兄弟节点。
  76. RyanJson_t obj = RyanJsonCreateObject();
  77. TEST_ASSERT_NOT_NULL(obj);
  78. TEST_ASSERT_TRUE(RyanJsonAddIntToObject(obj, "a", 1));
  79. TEST_ASSERT_TRUE(RyanJsonAddStringToObject(obj, "b", "keep"));
  80. RyanJson_t aNode = RyanJsonGetObjectToKey(obj, "a");
  81. RyanJson_t bNode = RyanJsonGetObjectToKey(obj, "b");
  82. TEST_ASSERT_NOT_NULL(aNode);
  83. TEST_ASSERT_NOT_NULL(bNode);
  84. TEST_ASSERT_TRUE_MESSAGE(RyanJsonChangeKey(aNode, "a"), "ChangeKey(同文本 key) 应成功");
  85. TEST_ASSERT_EQUAL_PTR_MESSAGE(aNode, RyanJsonGetObjectToKey(obj, "a"), "同文本 ChangeKey 不应替换节点身份");
  86. TEST_ASSERT_EQUAL_INT_MESSAGE(1, RyanJsonGetIntValue(RyanJsonGetObjectToKey(obj, "a")), "同文本 ChangeKey 后值不应变化");
  87. TEST_ASSERT_EQUAL_STRING_MESSAGE("keep", RyanJsonGetStringValue(RyanJsonGetObjectToKey(obj, "b")),
  88. "同文本 ChangeKey 不应影响其他兄弟节点");
  89. TEST_ASSERT_EQUAL_UINT32_MESSAGE(2U, RyanJsonGetSize(obj), "同文本 ChangeKey 不应改变 Object 元素数量");
  90. RyanJsonDelete(obj);
  91. }
  92. static void testChangeValueStress(void)
  93. {
  94. RyanJson_t root = RyanJsonCreateObject();
  95. RyanJsonAddStringToObject(root, "k", "v");
  96. // 高频修改 strValue
  97. // 变为超长
  98. char *longStr = (char *)malloc(1000);
  99. memset(longStr, 'A', 999);
  100. longStr[999] = '\0';
  101. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(RyanJsonGetObjectByKey(root, "k"), longStr));
  102. TEST_ASSERT_EQUAL_STRING(longStr, RyanJsonGetStringValue(RyanJsonGetObjectByKey(root, "k")));
  103. // 变为特殊字符
  104. const char *specials = "\t\n\r\b\f\"\\/";
  105. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(RyanJsonGetObjectByKey(root, "k"), specials));
  106. TEST_ASSERT_EQUAL_STRING(specials, RyanJsonGetStringValue(RyanJsonGetObjectByKey(root, "k")));
  107. // 变为空串
  108. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(RyanJsonGetObjectByKey(root, "k"), ""));
  109. TEST_ASSERT_EQUAL_STRING("", RyanJsonGetStringValue(RyanJsonGetObjectByKey(root, "k")));
  110. // 高频修改 key
  111. // 变为超长
  112. TEST_ASSERT_TRUE(RyanJsonChangeKey(RyanJsonGetObjectByKey(root, "k"), longStr));
  113. TEST_ASSERT_TRUE(RyanJsonHasObjectByKey(root, longStr));
  114. // 变为空 key
  115. TEST_ASSERT_TRUE(RyanJsonChangeKey(RyanJsonGetObjectByKey(root, longStr), ""));
  116. TEST_ASSERT_TRUE(RyanJsonHasObjectByKey(root, ""));
  117. free(longStr);
  118. RyanJsonDelete(root);
  119. }
  120. static void testChangeScalarAndStorageMode(void)
  121. {
  122. char jsonstr[] =
  123. "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,"
  124. "\"item\":{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},"
  125. "\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,16.89,16.89,16.89],"
  126. "\"arrayString\":[\"hello\",\"hello\",\"hello\",\"hello\",\"hello\"],"
  127. "\"array\":[16,16.89,\"hello\",true,false,null],"
  128. "\"arrayItem\":[{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null},"
  129. "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null}],"
  130. "\"string2222\":\"hello\",\"0\":\"1\",\"nameaaaaaaaaaaaaaaaaaaaaaaaaaaaa\":\"Mash\",\"2\":\"3\",\"name\":"
  131. "\"Mashaaaaaaaaaaaaaaaaaaaaaaaa\"}";
  132. RyanJson_t jsonRoot = RyanJsonParse(jsonstr);
  133. TEST_ASSERT_NOT_NULL_MESSAGE(jsonRoot, "解析基础 Json 失败");
  134. /**
  135. * @brief 修改基本类型
  136. */
  137. // 修改 Int
  138. RyanJsonChangeIntValue(RyanJsonGetObjectToKey(jsonRoot, "inter"), 20);
  139. TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsInt(RyanJsonGetObjectToKey(jsonRoot, "inter")), "字段 'inter' 修改后不是 Int");
  140. TEST_ASSERT_EQUAL_INT_MESSAGE(20, RyanJsonGetIntValue(RyanJsonGetObjectToKey(jsonRoot, "inter")), "字段 'inter' 值不匹配");
  141. // 修改 Double
  142. RyanJsonChangeDoubleValue(RyanJsonGetObjectToKey(jsonRoot, "double"), 20.89);
  143. TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsDouble(RyanJsonGetObjectToKey(jsonRoot, "double")), "字段 'double' 修改后不是 Double");
  144. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompareDouble(RyanJsonGetDoubleValue(RyanJsonGetObjectToKey(jsonRoot, "double")), 20.89),
  145. "字段 'double' 值不匹配");
  146. // 修改 Key (inline 模式,不超过长度)
  147. RyanJsonChangeKey(RyanJsonGetObjectByKey(jsonRoot, "0"), "type");
  148. TEST_ASSERT_EQUAL_STRING_MESSAGE("type", RyanJsonGetKey(RyanJsonGetObjectToKey(jsonRoot, "type")), "字段 'type' 的 Key 不匹配");
  149. TEST_ASSERT_EQUAL_STRING_MESSAGE("1", RyanJsonGetStringValue(RyanJsonGetObjectToKey(jsonRoot, "type")), "字段 'type' 的内容不匹配");
  150. // 修改 Key (从 inline 转 ptr 模式)
  151. RyanJsonChangeKey(RyanJsonGetObjectByKey(jsonRoot, "type"), "type000000000000000");
  152. TEST_ASSERT_EQUAL_STRING_MESSAGE("type000000000000000", RyanJsonGetKey(RyanJsonGetObjectToKey(jsonRoot, "type000000000000000")),
  153. "长 Key 模式下的 Key 不匹配");
  154. TEST_ASSERT_EQUAL_STRING_MESSAGE("1", RyanJsonGetStringValue(RyanJsonGetObjectToKey(jsonRoot, "type000000000000000")),
  155. "长 Key 模式下的内容不匹配");
  156. // 修改 Key (从 ptr 转 inline 模式)
  157. RyanJsonChangeKey(RyanJsonGetObjectByKey(jsonRoot, "nameaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), "na");
  158. TEST_ASSERT_EQUAL_STRING_MESSAGE("na", RyanJsonGetKey(RyanJsonGetObjectToKey(jsonRoot, "na")), "回退到 inline 模式的 Key 不匹配");
  159. TEST_ASSERT_EQUAL_STRING_MESSAGE("Mash", RyanJsonGetStringValue(RyanJsonGetObjectToKey(jsonRoot, "na")),
  160. "回退到 inline 模式的内容不匹配");
  161. // 修改 Value (inline 模式,不超过长度)
  162. RyanJsonChangeStringValue(RyanJsonGetObjectByKey(jsonRoot, "2"), "type");
  163. TEST_ASSERT_EQUAL_STRING_MESSAGE("2", RyanJsonGetKey(RyanJsonGetObjectToKey(jsonRoot, "2")), "字段 '2' 的 Key 不匹配");
  164. TEST_ASSERT_EQUAL_STRING_MESSAGE("type", RyanJsonGetStringValue(RyanJsonGetObjectToKey(jsonRoot, "2")), "字段 '2' 的新内容不匹配");
  165. // 修改 Value (从 ptr 转 inline 模式)
  166. RyanJsonChangeStringValue(RyanJsonGetObjectByKey(jsonRoot, "name"), "Ma");
  167. TEST_ASSERT_EQUAL_STRING_MESSAGE("name", RyanJsonGetKey(RyanJsonGetObjectToKey(jsonRoot, "name")), "字段 'name' 的 Key 不匹配");
  168. TEST_ASSERT_EQUAL_STRING_MESSAGE("Ma", RyanJsonGetStringValue(RyanJsonGetObjectToKey(jsonRoot, "name")),
  169. "回退到 inline 模式的 Value 不匹配");
  170. // 修改 Value (从 ptr 转 ptr 模式)
  171. RyanJsonChangeStringValue(RyanJsonGetObjectByKey(jsonRoot, "name"), "Mashaaaaaaaaaaaaaaaaaaaaaaaa");
  172. TEST_ASSERT_EQUAL_STRING_MESSAGE("name", RyanJsonGetKey(RyanJsonGetObjectToKey(jsonRoot, "name")), "字段 'name' 的 Key 不匹配");
  173. TEST_ASSERT_EQUAL_STRING_MESSAGE("Mashaaaaaaaaaaaaaaaaaaaaaaaa", RyanJsonGetStringValue(RyanJsonGetObjectToKey(jsonRoot, "name")),
  174. "长 Value 模式下的内容不匹配");
  175. // 修改 String
  176. RyanJsonChangeStringValue(RyanJsonGetObjectToKey(jsonRoot, "string"), "world");
  177. TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsString(RyanJsonGetObjectToKey(jsonRoot, "string")), "字段 'string' 修改后不是 String");
  178. TEST_ASSERT_EQUAL_STRING_MESSAGE("world", RyanJsonGetStringValue(RyanJsonGetObjectToKey(jsonRoot, "string")),
  179. "字段 'string' 内容不匹配");
  180. // 修改 boolValue (true -> false)
  181. RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(jsonRoot, "boolTrue"), RyanJsonFalse);
  182. TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsBool(RyanJsonGetObjectToKey(jsonRoot, "boolTrue")), "字段 'boolTrue' 类型错误");
  183. TEST_ASSERT_EQUAL_INT_MESSAGE(RyanJsonFalse, RyanJsonGetBoolValue(RyanJsonGetObjectToKey(jsonRoot, "boolTrue")),
  184. "字段 'boolTrue' 值错误");
  185. // 修改 boolValue (false -> true)
  186. RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(jsonRoot, "boolFalse"), RyanJsonTrue);
  187. TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsBool(RyanJsonGetObjectToKey(jsonRoot, "boolFalse")), "字段 'boolFalse' 类型错误");
  188. TEST_ASSERT_EQUAL_INT_MESSAGE(RyanJsonTrue, RyanJsonGetBoolValue(RyanJsonGetObjectToKey(jsonRoot, "boolFalse")),
  189. "字段 'boolFalse' 值错误");
  190. /**
  191. * @brief 修改 Array 元素 (arrayInt)
  192. */
  193. RyanJsonChangeIntValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(jsonRoot, "arrayInt"), 0), 99);
  194. TEST_ASSERT_EQUAL_INT_MESSAGE(99, RyanJsonGetIntValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(jsonRoot, "arrayInt"), 0)),
  195. "Array 元素修改失败");
  196. /**
  197. * @brief 修改 Array 元素 (arrayDouble)
  198. */
  199. RyanJsonChangeDoubleValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(jsonRoot, "arrayDouble"), 1), 99.99);
  200. TEST_ASSERT_TRUE_MESSAGE(
  201. RyanJsonCompareDouble(RyanJsonGetDoubleValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(jsonRoot, "arrayDouble"), 1)),
  202. 99.99),
  203. "Array 浮点元素修改失败");
  204. /**
  205. * @brief 修改 Array 元素 (arrayString)
  206. */
  207. RyanJsonChangeStringValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(jsonRoot, "arrayString"), 2), "changedString");
  208. TEST_ASSERT_EQUAL_STRING_MESSAGE(
  209. "changedString", RyanJsonGetStringValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(jsonRoot, "arrayString"), 2)),
  210. "ArrayString 元素修改失败");
  211. /**
  212. * @brief 修改嵌套 Object
  213. */
  214. RyanJson_t nestedObj = RyanJsonGetObjectToKey(jsonRoot, "item");
  215. RyanJsonChangeStringValue(RyanJsonGetObjectToKey(nestedObj, "string"), "nestedWorld");
  216. TEST_ASSERT_EQUAL_STRING_MESSAGE("nestedWorld", RyanJsonGetStringValue(RyanJsonGetObjectToKey(nestedObj, "string")),
  217. "嵌套 Object 修改失败");
  218. /**
  219. * @brief 修改 Array 中 Object 的字段 (arrayItem[0].inter -> 123)
  220. */
  221. RyanJson_t arrayItem0 = RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(jsonRoot, "arrayItem"), 0);
  222. RyanJsonChangeIntValue(RyanJsonGetObjectToKey(arrayItem0, "inter"), 123);
  223. TEST_ASSERT_EQUAL_INT_MESSAGE(123, RyanJsonGetIntValue(RyanJsonGetObjectToKey(arrayItem0, "inter")), "Array 中 Object 的字段修改失败");
  224. char *str = RyanJsonPrint(jsonRoot, 1024, RyanJsonTrue, NULL);
  225. RyanJsonFree(str);
  226. RyanJsonDelete(jsonRoot);
  227. /**
  228. * @brief 验证创建后的内存模式库切换 (Create -> Change)
  229. */
  230. RyanJson_t json = RyanJsonCreateString("key", "val");
  231. TEST_ASSERT_NOT_NULL(json);
  232. TEST_ASSERT_EQUAL_STRING_MESSAGE("val", RyanJsonGetStringValue(json), "Inline 模式初次设置失败");
  233. // 修改为长 String (触发自动切换到 ptr 模式)
  234. const char *longVal = "This is a very long string that definitely exceeds the inline threshold of RyanJson structure.";
  235. RyanJsonChangeStringValue(json, longVal);
  236. TEST_ASSERT_EQUAL_STRING_MESSAGE(longVal, RyanJsonGetStringValue(json), "切换到 Ptr 模式后值错误");
  237. // 修改回短 String
  238. RyanJsonChangeStringValue(json, "new");
  239. TEST_ASSERT_EQUAL_STRING_MESSAGE("new", RyanJsonGetStringValue(json), "切回短 String 后值错误");
  240. // 修改 Key 为长 Key
  241. const char *longKey = "a_very_long_key_name_to_trigger_ptr_mode_for_key_storage_in_ryanjson";
  242. RyanJsonChangeKey(json, longKey);
  243. TEST_ASSERT_EQUAL_STRING_MESSAGE(longKey, RyanJsonGetKey(json), "Key 切换到 Ptr 模式后错误");
  244. RyanJsonDelete(json);
  245. }
  246. static void testChangeInlineCalcBoundary(void)
  247. {
  248. /**
  249. * @brief 这个测试的目标:
  250. * @details
  251. * 验证 RyanJsonInternalChangeString 的容量判断在“临界长度”处是否正确;
  252. * 验证 value 和 key 两条路径都会发生 inline <-> ptr 的双向切换;
  253. * 不依赖固定常量(例如 keyLen=255),而是基于当前编译配置动态计算边界。
  254. *
  255. * 背景:
  256. * RyanJsonInternalChangeString 的判定核心是:
  257. * if ((mallocSize + keyLenFieldBytes) <= RyanJsonInlineStringSize) => inline
  258. * else => ptr
  259. *
  260. * 因此这里分别构造:
  261. * - 恰好满足 <= 的输入(应保持/切回 inline)
  262. * - 超过 1 字节的输入(应切到 ptr)
  263. */
  264. uint32_t inlineSize = RyanJsonInlineStringSize;
  265. uint32_t fixedKeyLen = 1;
  266. uint32_t fixedValueLen = 1;
  267. /**
  268. * @brief value 边界计算(固定 key="k")。
  269. * @details
  270. * 需要占用的总 inline 空间 = keyFieldLen + keyLen + '\0' + valueLen + '\0'
  271. * 先算出不含 value 内容本体时的固定开销 baseNeedForValue,
  272. * 再反推出 value 能放进 inline 的最大长度 maxInlineValueLen。
  273. */
  274. uint32_t keyFieldLenForValue = RyanJsonInternalDecodeKeyLenField(RyanJsonInternalCalcLenBytes(fixedKeyLen));
  275. uint32_t baseNeedForValue = keyFieldLenForValue + fixedKeyLen + 1 + 1; // keyField + key + '\0' + value '\0'
  276. TEST_ASSERT_TRUE_MESSAGE(inlineSize >= baseNeedForValue, "inline 大小异常,无法完成边界测试");
  277. uint32_t maxInlineValueLen = inlineSize - baseNeedForValue;
  278. // valueInline: 恰好命中 inline 临界;valuePtr: 比临界多 1 字节,必须走 ptr
  279. char *valueInline = (char *)malloc((size_t)maxInlineValueLen + 1U);
  280. char *valuePtr = (char *)malloc((size_t)maxInlineValueLen + 2U);
  281. TEST_ASSERT_NOT_NULL(valueInline);
  282. TEST_ASSERT_NOT_NULL(valuePtr);
  283. memset(valueInline, 'v', maxInlineValueLen);
  284. valueInline[maxInlineValueLen] = '\0';
  285. memset(valuePtr, 'p', maxInlineValueLen + 1U);
  286. valuePtr[maxInlineValueLen + 1U] = '\0';
  287. RyanJson_t valueNode = RyanJsonCreateString("k", "");
  288. TEST_ASSERT_NOT_NULL(valueNode);
  289. // 临界长度:应为 inline
  290. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(valueNode, valueInline));
  291. TEST_ASSERT_FALSE_MESSAGE(RyanJsonGetPayloadStrIsPtrByFlag(valueNode), "value 临界长度应为 inline");
  292. // 超临界:应切到 ptr
  293. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(valueNode, valuePtr));
  294. TEST_ASSERT_TRUE_MESSAGE(RyanJsonGetPayloadStrIsPtrByFlag(valueNode), "value 超过临界长度应切到 ptr");
  295. // 回退到临界:应能从 ptr 回到 inline(覆盖回切逻辑)
  296. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(valueNode, valueInline));
  297. TEST_ASSERT_FALSE_MESSAGE(RyanJsonGetPayloadStrIsPtrByFlag(valueNode), "value 回退到临界长度应切回 inline");
  298. /**
  299. * @brief key 边界计算(固定 value="v")。
  300. * @details
  301. * keyLen 变化时,keyLenField 可能从 1/2/4 字节变化,
  302. * 所以不能硬编码某个 keyLen,必须遍历找到“当前配置下最大可 inline 的 key 长度”。
  303. */
  304. uint32_t maxInlineKeyLen = 0;
  305. for (uint32_t keyLen = 0; keyLen <= inlineSize; keyLen++)
  306. {
  307. uint32_t keyFieldLen = RyanJsonInternalDecodeKeyLenField(RyanJsonInternalCalcLenBytes(keyLen));
  308. uint32_t need = keyFieldLen + keyLen + 1 + fixedValueLen + 1;
  309. if (need <= inlineSize) { maxInlineKeyLen = keyLen; }
  310. }
  311. // 交叉校验:maxInlineKeyLen 应满足 inline;maxInlineKeyLen+1 应超过 inline
  312. uint32_t inlineNeed =
  313. RyanJsonInternalDecodeKeyLenField(RyanJsonInternalCalcLenBytes(maxInlineKeyLen)) + maxInlineKeyLen + 1 + fixedValueLen + 1;
  314. uint32_t ptrNeed = RyanJsonInternalDecodeKeyLenField(RyanJsonInternalCalcLenBytes(maxInlineKeyLen + 1U)) + (maxInlineKeyLen + 1U) +
  315. 1 + fixedValueLen + 1;
  316. TEST_ASSERT_TRUE_MESSAGE(inlineNeed <= inlineSize, "inline key 临界值计算错误");
  317. TEST_ASSERT_TRUE_MESSAGE(ptrNeed > inlineSize, "ptr key 临界值计算错误");
  318. // keyInline: 恰好临界;keyPtr: 超临界 1 字节
  319. char *keyInline = (char *)malloc((size_t)maxInlineKeyLen + 1U);
  320. char *keyPtr = (char *)malloc((size_t)maxInlineKeyLen + 2U);
  321. TEST_ASSERT_NOT_NULL(keyInline);
  322. TEST_ASSERT_NOT_NULL(keyPtr);
  323. memset(keyInline, 'k', maxInlineKeyLen);
  324. keyInline[maxInlineKeyLen] = '\0';
  325. memset(keyPtr, 'K', maxInlineKeyLen + 1U);
  326. keyPtr[maxInlineKeyLen + 1U] = '\0';
  327. RyanJson_t keyNode = RyanJsonCreateString("", "v");
  328. TEST_ASSERT_NOT_NULL(keyNode);
  329. // key 临界长度:应为 inline
  330. TEST_ASSERT_TRUE(RyanJsonChangeKey(keyNode, keyInline));
  331. TEST_ASSERT_FALSE_MESSAGE(RyanJsonGetPayloadStrIsPtrByFlag(keyNode), "key 临界长度应为 inline");
  332. // key 超临界:应切到 ptr
  333. TEST_ASSERT_TRUE(RyanJsonChangeKey(keyNode, keyPtr));
  334. TEST_ASSERT_TRUE_MESSAGE(RyanJsonGetPayloadStrIsPtrByFlag(keyNode), "key 超过临界长度应切到 ptr");
  335. // key 回退临界:应切回 inline
  336. TEST_ASSERT_TRUE(RyanJsonChangeKey(keyNode, keyInline));
  337. TEST_ASSERT_FALSE_MESSAGE(RyanJsonGetPayloadStrIsPtrByFlag(keyNode), "key 回退到临界长度应切回 inline");
  338. // 释放临时资源,避免单测内存泄漏
  339. RyanJsonDelete(valueNode);
  340. RyanJsonDelete(keyNode);
  341. free(valueInline);
  342. free(valuePtr);
  343. free(keyInline);
  344. free(keyPtr);
  345. }
  346. static void testChangeNumericStringIdFidelity(void)
  347. {
  348. // 覆盖“NumberString ID”保真:
  349. // - 解析后仍为 String 类型,且保留前导零与大 Int 文本;
  350. // - Print/Parse 往返不数值化;
  351. // - ChangeStringValue 不会触发数值化或去零。
  352. const char *text = "{\"id\":\"00123\",\"big\":\"9007199254740993\",\"arr\":[\"00123\",\"9007199254740993\"]}";
  353. RyanJson_t root = RyanJsonParse(text);
  354. TEST_ASSERT_NOT_NULL_MESSAGE(root, "Number String 样本解析失败");
  355. RyanJson_t idNode = RyanJsonGetObjectByKey(root, "id");
  356. RyanJson_t bigNode = RyanJsonGetObjectByKey(root, "big");
  357. RyanJson_t arr = RyanJsonGetObjectByKey(root, "arr");
  358. TEST_ASSERT_NOT_NULL(idNode);
  359. TEST_ASSERT_NOT_NULL(bigNode);
  360. TEST_ASSERT_NOT_NULL(arr);
  361. TEST_ASSERT_TRUE(RyanJsonIsArray(arr));
  362. TEST_ASSERT_TRUE(RyanJsonIsString(idNode));
  363. TEST_ASSERT_TRUE(RyanJsonIsString(bigNode));
  364. TEST_ASSERT_EQUAL_STRING("00123", RyanJsonGetStringValue(idNode));
  365. TEST_ASSERT_EQUAL_STRING("9007199254740993", RyanJsonGetStringValue(bigNode));
  366. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByIndex(arr, 0)));
  367. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByIndex(arr, 1)));
  368. TEST_ASSERT_EQUAL_STRING("00123", RyanJsonGetStringValue(RyanJsonGetObjectByIndex(arr, 0)));
  369. TEST_ASSERT_EQUAL_STRING("9007199254740993", RyanJsonGetStringValue(RyanJsonGetObjectByIndex(arr, 1)));
  370. char *printed = RyanJsonPrint(root, 160, RyanJsonFalse, NULL);
  371. TEST_ASSERT_NOT_NULL(printed);
  372. RyanJson_t roundtrip = RyanJsonParse(printed);
  373. TEST_ASSERT_NOT_NULL(roundtrip);
  374. TEST_ASSERT_EQUAL_STRING("00123", RyanJsonGetStringValue(RyanJsonGetObjectByKey(roundtrip, "id")));
  375. TEST_ASSERT_EQUAL_STRING("9007199254740993", RyanJsonGetStringValue(RyanJsonGetObjectByKey(roundtrip, "big")));
  376. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByKey(roundtrip, "id")));
  377. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByKey(roundtrip, "big")));
  378. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByIndex(RyanJsonGetObjectByKey(roundtrip, "arr"), 0)));
  379. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByIndex(RyanJsonGetObjectByKey(roundtrip, "arr"), 1)));
  380. TEST_ASSERT_EQUAL_STRING("00123", RyanJsonGetStringValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectByKey(roundtrip, "arr"), 0)));
  381. TEST_ASSERT_EQUAL_STRING("9007199254740993",
  382. RyanJsonGetStringValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectByKey(roundtrip, "arr"), 1)));
  383. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(idNode, "00001"));
  384. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(bigNode, "90071992547409930"));
  385. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(RyanJsonGetObjectByIndex(arr, 0), "00001"));
  386. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(RyanJsonGetObjectByIndex(arr, 1), "90071992547409930"));
  387. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByKey(root, "id")));
  388. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByKey(root, "big")));
  389. TEST_ASSERT_EQUAL_STRING("00001", RyanJsonGetStringValue(RyanJsonGetObjectByKey(root, "id")));
  390. TEST_ASSERT_EQUAL_STRING("90071992547409930", RyanJsonGetStringValue(RyanJsonGetObjectByKey(root, "big")));
  391. TEST_ASSERT_EQUAL_STRING("00001", RyanJsonGetStringValue(RyanJsonGetObjectByIndex(arr, 0)));
  392. TEST_ASSERT_EQUAL_STRING("90071992547409930", RyanJsonGetStringValue(RyanJsonGetObjectByIndex(arr, 1)));
  393. char *printed2 = RyanJsonPrint(root, 160, RyanJsonFalse, NULL);
  394. TEST_ASSERT_NOT_NULL(printed2);
  395. RyanJson_t roundtrip2 = RyanJsonParse(printed2);
  396. TEST_ASSERT_NOT_NULL(roundtrip2);
  397. TEST_ASSERT_EQUAL_STRING("00001", RyanJsonGetStringValue(RyanJsonGetObjectByKey(roundtrip2, "id")));
  398. TEST_ASSERT_EQUAL_STRING("90071992547409930", RyanJsonGetStringValue(RyanJsonGetObjectByKey(roundtrip2, "big")));
  399. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByKey(roundtrip2, "id")));
  400. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByKey(roundtrip2, "big")));
  401. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByIndex(RyanJsonGetObjectByKey(roundtrip2, "arr"), 0)));
  402. TEST_ASSERT_TRUE(RyanJsonIsString(RyanJsonGetObjectByIndex(RyanJsonGetObjectByKey(roundtrip2, "arr"), 1)));
  403. TEST_ASSERT_EQUAL_STRING("00001", RyanJsonGetStringValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectByKey(roundtrip2, "arr"), 0)));
  404. TEST_ASSERT_EQUAL_STRING("90071992547409930",
  405. RyanJsonGetStringValue(RyanJsonGetObjectByIndex(RyanJsonGetObjectByKey(roundtrip2, "arr"), 1)));
  406. RyanJsonDelete(roundtrip2);
  407. RyanJsonFree(printed2);
  408. RyanJsonDelete(roundtrip);
  409. RyanJsonFree(printed);
  410. RyanJsonDelete(root);
  411. }
  412. static void testChangeFailureThenSuccessChainAgainstExpected(void)
  413. {
  414. // 复杂链路:
  415. // Parse -> Duplicate(snapshot) -> 连续失败 Change -> Compare(snapshot)
  416. // -> 连续成功 Change(含 ChangeKey) -> CompareOnlyKey 差异 -> 对齐期望文档 -> Roundtrip。
  417. // 目标:
  418. // - 验证失败 Change 不会污染原树;
  419. // - 验证失败与成功交错后,结构和值仍可稳定收敛到期望语义;
  420. // - 覆盖 ChangeKey 引起的 key 结构变化对 CompareOnlyKey 的影响。
  421. const char *source = "{\"cfg\":{\"mode\":\"a\",\"retry\":1},\"arr\":[{\"k\":\"x\"},{\"k\":\"y\"}],\"flag\":true}";
  422. const char *expectText = "{\"cfg\":{\"mode\":\"b\",\"retry2\":9},\"arr\":[{\"k\":\"x\"},{\"k\":\"z\"}],\"flag\":false}";
  423. RyanJson_t root = RyanJsonParse(source);
  424. TEST_ASSERT_NOT_NULL_MESSAGE(root, "Change 链路样本解析失败");
  425. RyanJson_t snapshot = RyanJsonDuplicate(root);
  426. TEST_ASSERT_NOT_NULL_MESSAGE(snapshot, "Change 链路快照构造失败");
  427. RyanJson_t cfg = RyanJsonGetObjectToKey(root, "cfg");
  428. RyanJson_t arr = RyanJsonGetObjectToKey(root, "arr");
  429. RyanJson_t arr0 = RyanJsonGetObjectToIndex(arr, 0);
  430. RyanJson_t arr1 = RyanJsonGetObjectToIndex(arr, 1);
  431. TEST_ASSERT_NOT_NULL(cfg);
  432. TEST_ASSERT_NOT_NULL(arr);
  433. TEST_ASSERT_NOT_NULL(arr0);
  434. TEST_ASSERT_NOT_NULL(arr1);
  435. // 失败路径:类型不匹配 + Array 元素无 key,不应改变文档语义。
  436. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(cfg, "mode"), 1), "String 节点 ChangeIntValue 应失败");
  437. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(arr0, "k"), RyanJsonTrue),
  438. "String 节点 ChangeBoolValue 应失败");
  439. TEST_ASSERT_FALSE_MESSAGE(RyanJsonChangeKey(arr0, "arr0"), "Array 元素无 key,ChangeKey 应失败");
  440. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(root, snapshot), "仅发生失败 Change 时,文档语义应与 snapshot 完全一致");
  441. // 成功路径:值修改 + key 修改。
  442. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(RyanJsonGetObjectToKey(cfg, "mode"), "b"));
  443. TEST_ASSERT_TRUE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(cfg, "retry"), 9));
  444. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(RyanJsonGetObjectToKey(arr1, "k"), "z"));
  445. TEST_ASSERT_TRUE(RyanJsonChangeBoolValue(RyanJsonGetObjectToKey(root, "flag"), RyanJsonFalse));
  446. TEST_ASSERT_TRUE_MESSAGE(RyanJsonChangeKey(RyanJsonGetObjectToKey(cfg, "retry"), "retry2"), "将 cfg.retry 重命名为 retry2 失败");
  447. TEST_ASSERT_FALSE(RyanJsonHasObjectToKey(cfg, "retry"));
  448. TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(cfg, "retry2"));
  449. TEST_ASSERT_FALSE_MESSAGE(RyanJsonCompareOnlyKey(root, snapshot), "发生 key 结构变化后 CompareOnlyKey 应返回 False");
  450. RyanJson_t expect = RyanJsonParse(expectText);
  451. TEST_ASSERT_NOT_NULL(expect);
  452. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(root, expect), "Change 链路最终结果与期望文档不一致");
  453. char *printed = RyanJsonPrint(root, 160, RyanJsonFalse, NULL);
  454. TEST_ASSERT_NOT_NULL(printed);
  455. RyanJson_t roundtrip = RyanJsonParse(printed);
  456. TEST_ASSERT_NOT_NULL(roundtrip);
  457. TEST_ASSERT_TRUE(RyanJsonCompare(root, roundtrip));
  458. RyanJsonDelete(roundtrip);
  459. RyanJsonFree(printed);
  460. RyanJsonDelete(expect);
  461. RyanJsonDelete(snapshot);
  462. RyanJsonDelete(root);
  463. }
  464. void testChangeRunner(void)
  465. {
  466. UnitySetTestFile(__FILE__);
  467. RUN_TEST(testChangeEdgeCases);
  468. RUN_TEST(testChangeKeyDuplicatePolicy);
  469. RUN_TEST(testChangeKeySameTextNoOp);
  470. RUN_TEST(testChangeValueStress);
  471. RUN_TEST(testChangeScalarAndStorageMode);
  472. RUN_TEST(testChangeInlineCalcBoundary);
  473. RUN_TEST(testChangeNumericStringIdFidelity);
  474. RUN_TEST(testChangeFailureThenSuccessChainAgainstExpected);
  475. }