fuzzerCreate.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. #include "RyanJson.h"
  2. #include "RyanJsonFuzzer.h"
  3. /**
  4. * @brief 在运行期 fuzz 中主动覆盖 CreateXArray builder 成功路径
  5. *
  6. * 这类 API 不再放进 SelfTestOnce,而是在 create 用例里按当前输入触发。
  7. * 这里只覆盖成功构建路径;OOM 路径仍交给运行期内存故障注入。
  8. */
  9. static void RyanJsonFuzzerExerciseCreateArrayBuilderCases(uint32_t size)
  10. {
  11. static const char *const stringPool[] = {"alpha", "beta", "gamma", "delta"};
  12. int32_t intValues[] = {(int32_t)size, -((int32_t)size + 1)};
  13. double doubleValues[] = {(double)size * 0.25 + 1.25, -((double)size * 0.5 + 2.5)};
  14. const char *stringValues[] = {stringPool[size % (sizeof(stringPool) / sizeof(stringPool[0]))],
  15. stringPool[(size + 1U) % (sizeof(stringPool) / sizeof(stringPool[0]))]};
  16. fuzzTestWithMemFail({
  17. RyanJson_t emptyIntArray = RyanJsonCreateIntArray(intValues, 0);
  18. RyanJson_t intArray = RyanJsonCreateIntArray(intValues, sizeof(intValues) / sizeof(intValues[0]));
  19. assert(NULL != emptyIntArray && NULL != intArray);
  20. assert(0 == RyanJsonGetArraySize(emptyIntArray));
  21. assert(2 == RyanJsonGetArraySize(intArray));
  22. #if true == RyanJsonDefaultAddAtHead
  23. assert(intValues[1] == RyanJsonGetIntValue(RyanJsonGetObjectByIndex(intArray, 0)));
  24. assert(intValues[0] == RyanJsonGetIntValue(RyanJsonGetObjectByIndex(intArray, 1)));
  25. #else
  26. assert(intValues[0] == RyanJsonGetIntValue(RyanJsonGetObjectByIndex(intArray, 0)));
  27. assert(intValues[1] == RyanJsonGetIntValue(RyanJsonGetObjectByIndex(intArray, 1)));
  28. #endif
  29. RyanJsonDelete(emptyIntArray);
  30. RyanJsonDelete(intArray);
  31. RyanJson_t emptyDoubleArray = RyanJsonCreateDoubleArray(doubleValues, 0);
  32. RyanJson_t doubleArray = RyanJsonCreateDoubleArray(doubleValues, sizeof(doubleValues) / sizeof(doubleValues[0]));
  33. assert(NULL != emptyDoubleArray && NULL != doubleArray);
  34. assert(0 == RyanJsonGetArraySize(emptyDoubleArray));
  35. assert(2 == RyanJsonGetArraySize(doubleArray));
  36. #if true == RyanJsonDefaultAddAtHead
  37. assert(RyanJsonCompareDouble(doubleValues[1], RyanJsonGetDoubleValue(RyanJsonGetObjectByIndex(doubleArray, 0))));
  38. assert(RyanJsonCompareDouble(doubleValues[0], RyanJsonGetDoubleValue(RyanJsonGetObjectByIndex(doubleArray, 1))));
  39. #else
  40. assert(RyanJsonCompareDouble(doubleValues[0], RyanJsonGetDoubleValue(RyanJsonGetObjectByIndex(doubleArray, 0))));
  41. assert(RyanJsonCompareDouble(doubleValues[1], RyanJsonGetDoubleValue(RyanJsonGetObjectByIndex(doubleArray, 1))));
  42. #endif
  43. RyanJsonDelete(emptyDoubleArray);
  44. RyanJsonDelete(doubleArray);
  45. RyanJson_t emptyStringArray = RyanJsonCreateStringArray(stringValues, 0);
  46. RyanJson_t stringArray = RyanJsonCreateStringArray(stringValues, sizeof(stringValues) / sizeof(stringValues[0]));
  47. assert(NULL != emptyStringArray && NULL != stringArray);
  48. assert(0 == RyanJsonGetArraySize(emptyStringArray));
  49. assert(2 == RyanJsonGetArraySize(stringArray));
  50. #if true == RyanJsonDefaultAddAtHead
  51. assert(0 == strcmp(stringValues[1], RyanJsonGetStringValue(RyanJsonGetObjectByIndex(stringArray, 0))));
  52. assert(0 == strcmp(stringValues[0], RyanJsonGetStringValue(RyanJsonGetObjectByIndex(stringArray, 1))));
  53. #else
  54. assert(0 == strcmp(stringValues[0], RyanJsonGetStringValue(RyanJsonGetObjectByIndex(stringArray, 0))));
  55. assert(0 == strcmp(stringValues[1], RyanJsonGetStringValue(RyanJsonGetObjectByIndex(stringArray, 1))));
  56. #endif
  57. RyanJsonDelete(emptyStringArray);
  58. RyanJsonDelete(stringArray);
  59. });
  60. }
  61. /**
  62. * @brief 补齐“非空容器包装后挂树”路径
  63. *
  64. * 运行期 generator 只会生成空 Object/Array,无法自然到达 RyanJsonCreateItem
  65. * 中 children!=NULL 的分支。
  66. */
  67. static void RyanJsonFuzzerSelfTestCreateWrappedContainerCases(void)
  68. {
  69. RyanJson_t parent = RyanJsonCreateObject();
  70. RyanJson_t childArray = RyanJsonCreateArray();
  71. assert(NULL != parent && NULL != childArray);
  72. assert(RyanJsonTrue == RyanJsonAddIntToArray(childArray, 1));
  73. assert(RyanJsonTrue == RyanJsonAddIntToArray(childArray, 2));
  74. assert(RyanJsonTrue == RyanJsonAddItemToObject(parent, "arr", childArray));
  75. RyanJson_t wrappedArray = RyanJsonGetObjectByKey(parent, "arr");
  76. assert(NULL != wrappedArray && RyanJsonTrue == RyanJsonIsArray(wrappedArray));
  77. assert(2 == RyanJsonGetArraySize(wrappedArray));
  78. #if true == RyanJsonDefaultAddAtHead
  79. assert(2 == RyanJsonGetIntValue(RyanJsonGetObjectByIndex(wrappedArray, 0)));
  80. assert(1 == RyanJsonGetIntValue(RyanJsonGetObjectByIndex(wrappedArray, 1)));
  81. #else
  82. assert(1 == RyanJsonGetIntValue(RyanJsonGetObjectByIndex(wrappedArray, 0)));
  83. assert(2 == RyanJsonGetIntValue(RyanJsonGetObjectByIndex(wrappedArray, 1)));
  84. #endif
  85. RyanJsonDelete(parent);
  86. parent = RyanJsonCreateObject();
  87. RyanJson_t childObject = RyanJsonCreateObject();
  88. assert(NULL != parent && NULL != childObject);
  89. assert(RyanJsonTrue == RyanJsonAddIntToObject(childObject, "a", 1));
  90. assert(RyanJsonTrue == RyanJsonAddIntToObject(childObject, "b", 2));
  91. assert(RyanJsonTrue == RyanJsonAddItemToObject(parent, "obj", childObject));
  92. RyanJson_t wrappedObject = RyanJsonGetObjectByKey(parent, "obj");
  93. assert(NULL != wrappedObject && RyanJsonTrue == RyanJsonIsObject(wrappedObject));
  94. assert(2 == RyanJsonGetSize(wrappedObject));
  95. assert(1 == RyanJsonGetIntValue(RyanJsonGetObjectByKey(wrappedObject, "a")));
  96. assert(2 == RyanJsonGetIntValue(RyanJsonGetObjectByKey(wrappedObject, "b")));
  97. RyanJsonDelete(parent);
  98. }
  99. /**
  100. * @brief create 模块的一次性确定性自检
  101. *
  102. * 这里只保留运行期 fuzz 无法主动构造的非法内部状态和非空容器包装路径。
  103. */
  104. void RyanJsonFuzzerSelfTestCreateCases(void)
  105. {
  106. RyanJsonBool_e lastIsEnableMemFail;
  107. RyanJsonFuzzerMemFailPush(lastIsEnableMemFail, RyanJsonFalse);
  108. RyanJson_t malformedDetached = RyanJsonCreateInt(NULL, 1);
  109. assert(NULL != malformedDetached);
  110. assert(RyanJsonTrue == RyanJsonIsDetachedItem(malformedDetached));
  111. RyanJsonSetPayloadIsLastByFlag(malformedDetached, RyanJsonTrue);
  112. assert(RyanJsonFalse == RyanJsonIsDetachedItem(malformedDetached));
  113. RyanJsonSetPayloadIsLastByFlag(malformedDetached, RyanJsonFalse);
  114. RyanJsonDelete(malformedDetached);
  115. RyanJsonFuzzerSelfTestCreateWrappedContainerCases();
  116. RyanJsonFuzzerMemFailPop(lastIsEnableMemFail);
  117. }
  118. /**
  119. * @brief 创建与插入测试
  120. *
  121. * 测试 RyanJson 的节点创建、数据类型设置以及 Object/Array 的插入操作。
  122. * 覆盖场景:
  123. * 异常参数注入:测试空指针、无效 key、类型不匹配等错误处理。
  124. * 基础类型创建:测试 Bool/Int/Double/String 及其 Array 的创建与添加。
  125. * 递归结构构建:递归地向 Object/Array 中添加随机生成的子节点。
  126. * 边界插入测试:覆盖 Array 头部与中间位置插入。
  127. *
  128. * @param state Fuzzer 状态上下文
  129. * @param pJson 当前正在操作的 Json 节点
  130. * @param size 输入数据大小,用于控制递归深度和随机决策
  131. */
  132. RyanJsonBool_e RyanJsonFuzzerTestCreate(RyanJson_t pJson, uint32_t size)
  133. {
  134. static RyanJsonBool_e duplicateKeyGuardCovered = RyanJsonFalse;
  135. // duplicate key 守卫与当前输入无关,只需确定性命中一次,避免每轮重复造 Object。
  136. if (RyanJsonFalse == duplicateKeyGuardCovered)
  137. {
  138. RyanJsonBool_e lastIsEnableMemFail;
  139. RyanJsonFuzzerMemFailPush(lastIsEnableMemFail, RyanJsonFalse);
  140. RyanJson_t obj = RyanJsonCreateObject();
  141. assert(NULL != obj);
  142. assert(RyanJsonTrue == RyanJsonAddIntToObject(obj, "dup", 1));
  143. #if true == RyanJsonStrictObjectKeyCheck
  144. assert(RyanJsonFalse == RyanJsonAddIntToObject(obj, "dup", 2));
  145. assert(RyanJsonFalse == RyanJsonInsert(obj, UINT32_MAX, RyanJsonCreateInt("dup", 3)));
  146. assert(1 == RyanJsonGetIntValue(RyanJsonGetObjectByKey(obj, "dup")));
  147. #else
  148. assert(RyanJsonTrue == RyanJsonAddIntToObject(obj, "dup", 2));
  149. assert(RyanJsonTrue == RyanJsonInsert(obj, UINT32_MAX, RyanJsonCreateInt("dup", 3)));
  150. assert(3 == RyanJsonGetSize(obj));
  151. #if true == RyanJsonDefaultAddAtHead
  152. assert(2 == RyanJsonGetIntValue(RyanJsonGetObjectByKey(obj, "dup")));
  153. #else
  154. assert(1 == RyanJsonGetIntValue(RyanJsonGetObjectByKey(obj, "dup")));
  155. #endif
  156. #endif
  157. RyanJsonDelete(obj);
  158. RyanJsonFuzzerMemFailPop(lastIsEnableMemFail);
  159. duplicateKeyGuardCovered = RyanJsonTrue;
  160. }
  161. // RyanJsonInsert 特殊路径:模拟内存分配失败或无效参数输入
  162. uint32_t index = 6;
  163. // 仅在根节点触发 builder 成功路径,避免递归遍历整棵树时指数级放大成本。
  164. if (NULL == RyanJsonInternalGetParent(pJson) && RyanJsonFuzzerShouldFail(100))
  165. {
  166. RyanJsonFuzzerExerciseCreateArrayBuilderCases(size);
  167. }
  168. // 这批合同检查覆盖面广,但与当前输入关联较弱,因此降频执行,控制热路径成本。
  169. if (RyanJsonFuzzerShouldFail(100))
  170. {
  171. // 第一层:纯参数守卫和类型守卫。
  172. // 这些断言的共同点是“即使不依赖当前输入的具体值,也能验证接口合同是否稳固”。
  173. assert(RyanJsonFalse == RyanJsonInsert(NULL, UINT32_MAX, RyanJsonCreateString("key", "string")));
  174. assert(RyanJsonFalse == RyanJsonInsert(pJson, UINT32_MAX, NULL));
  175. assert(RyanJsonFalse == RyanJsonInsert(NULL, 0, NULL));
  176. assert(NULL == RyanJsonCreateString(NULL, NULL));
  177. assert(NULL == RyanJsonCreateString("NULL", NULL));
  178. assert(RyanJsonFalse == RyanJsonChangeStringValue(NULL, NULL));
  179. assert(RyanJsonFalse == RyanJsonChangeStringValue(pJson, NULL));
  180. assert(RyanJsonFalse == RyanJsonChangeStringValue(NULL, "NULL"));
  181. if (RyanJsonFalse == RyanJsonIsKey(pJson) && RyanJsonFalse == RyanJsonIsString(pJson)) // pJson 类型错误
  182. {
  183. assert(RyanJsonFalse == RyanJsonChangeStringValue(pJson, "NULL"));
  184. }
  185. assert(RyanJsonFalse == RyanJsonChangeKey(NULL, NULL));
  186. assert(RyanJsonFalse == RyanJsonChangeKey(pJson, NULL));
  187. assert(RyanJsonFalse == RyanJsonChangeKey(NULL, "NULL"));
  188. if (RyanJsonFalse == RyanJsonIsKey(pJson) && RyanJsonFalse == RyanJsonIsString(pJson)) // pJson 类型错误
  189. {
  190. RyanJsonBool_e lastIsEnableMemFail;
  191. RyanJsonFuzzerMemFailPush(lastIsEnableMemFail, RyanJsonFalse);
  192. assert(RyanJsonFalse == RyanJsonChangeKey(pJson, "NULL"));
  193. RyanJsonFuzzerMemFailPop(lastIsEnableMemFail);
  194. }
  195. // 测试“无 key 但有 strValue”的分支
  196. if (RyanJsonFalse == RyanJsonIsKey(pJson) && RyanJsonTrue == RyanJsonIsString(pJson))
  197. {
  198. RyanJsonBool_e lastIsEnableMemFail;
  199. RyanJsonFuzzerMemFailPush(lastIsEnableMemFail, RyanJsonFalse);
  200. assert(RyanJsonFalse == RyanJsonChangeKey(pJson, "NULL"));
  201. RyanJsonFuzzerMemFailPop(lastIsEnableMemFail);
  202. }
  203. assert(RyanJsonFalse == RyanJsonChangeIntValue(NULL, 0));
  204. assert(RyanJsonFalse == RyanJsonChangeDoubleValue(NULL, 0));
  205. assert(RyanJsonFalse == RyanJsonChangeBoolValue(NULL, 0));
  206. RyanJson_t mismatchNode = RyanJsonCreateDouble(NULL, 1.0);
  207. assert(RyanJsonFalse == RyanJsonChangeIntValue(mismatchNode, 7));
  208. if (NULL != mismatchNode) { RyanJsonDelete(mismatchNode); }
  209. mismatchNode = RyanJsonCreateInt(NULL, 1);
  210. assert(RyanJsonFalse == RyanJsonChangeDoubleValue(mismatchNode, 7.0));
  211. if (NULL != mismatchNode) { RyanJsonDelete(mismatchNode); }
  212. mismatchNode = RyanJsonCreateInt(NULL, 1);
  213. assert(RyanJsonFalse == RyanJsonChangeBoolValue(mismatchNode, RyanJsonTrue));
  214. if (NULL != mismatchNode) { RyanJsonDelete(mismatchNode); }
  215. mismatchNode = RyanJsonCreateString(NULL, "v");
  216. assert(RyanJsonFalse == RyanJsonChangeKey(mismatchNode, "k2"));
  217. if (NULL != mismatchNode) { RyanJsonDelete(mismatchNode); }
  218. mismatchNode = RyanJsonCreateBool(NULL, RyanJsonTrue);
  219. assert(RyanJsonFalse == RyanJsonChangeStringValue(mismatchNode, "x"));
  220. if (NULL != mismatchNode) { RyanJsonDelete(mismatchNode); }
  221. assert(RyanJsonFalse == RyanJsonAddItemToObject(NULL, NULL, NULL));
  222. assert(RyanJsonFalse == RyanJsonAddItemToObject(pJson, NULL, NULL));
  223. assert(NULL == RyanJsonCreateIntArray(NULL, 0));
  224. assert(NULL == RyanJsonCreateDoubleArray(NULL, 0));
  225. assert(NULL == RyanJsonCreateStringArray(NULL, 0));
  226. // 仅调用,不判断返回值,因为有可能会成功的
  227. RyanJsonHasObjectToKey(NULL, "0", "1", "2", "3");
  228. RyanJsonHasObjectToIndex(NULL, 0, 1, 2, 3);
  229. RyanJsonHasObjectToKey(pJson, "0", "1", "2", "3");
  230. RyanJsonHasObjectToIndex(pJson, 0, 1, 2, 3);
  231. RyanJsonHasObjectToIndex(pJson, 0);
  232. // 第二层:已挂树 item 的复用/二次插入守卫。
  233. // 这类路径在随机 generator 下不够稳定,集中在这里以确定性方式补齐。
  234. {
  235. RyanJsonBool_e lastIsEnableMemFail;
  236. RyanJsonFuzzerMemFailPush(lastIsEnableMemFail, RyanJsonFalse);
  237. RyanJson_t arr1 = RyanJsonCreateArray();
  238. RyanJson_t arr2 = RyanJsonCreateArray();
  239. RyanJson_t attachedArr = RyanJsonCreateArray();
  240. assert(RyanJsonFalse == RyanJsonIsDetachedItem(NULL));
  241. assert(NULL != arr1 && NULL != arr2 && NULL != attachedArr);
  242. assert(RyanJsonTrue == RyanJsonIsDetachedItem(attachedArr));
  243. assert(RyanJsonTrue == RyanJsonInsert(arr1, 0, attachedArr));
  244. assert(RyanJsonFalse == RyanJsonIsDetachedItem(attachedArr));
  245. assert(RyanJsonFalse == RyanJsonInsert(arr2, 0, attachedArr));
  246. assert(RyanJsonFalse == RyanJsonAddItemToArray(arr2, attachedArr));
  247. RyanJson_t detachedArr = RyanJsonDetachByIndex(arr1, 0);
  248. assert(detachedArr == attachedArr);
  249. assert(RyanJsonTrue == RyanJsonIsDetachedItem(detachedArr));
  250. RyanJsonDelete(detachedArr);
  251. RyanJson_t obj1 = RyanJsonCreateObject();
  252. RyanJson_t obj2 = RyanJsonCreateObject();
  253. RyanJson_t attachedObj = RyanJsonInternalCreateObjectAndKey("k");
  254. assert(NULL != obj1 && NULL != obj2 && NULL != attachedObj);
  255. assert(RyanJsonTrue == RyanJsonIsDetachedItem(attachedObj));
  256. assert(RyanJsonTrue == RyanJsonInsert(obj1, 0, attachedObj));
  257. assert(RyanJsonFalse == RyanJsonIsDetachedItem(attachedObj));
  258. assert(RyanJsonFalse == RyanJsonInsert(obj2, 0, attachedObj));
  259. assert(RyanJsonFalse == RyanJsonAddItemToObject(obj2, "dup", attachedObj));
  260. RyanJson_t detachedObj = RyanJsonDetachByIndex(obj1, 0);
  261. assert(detachedObj == attachedObj);
  262. assert(RyanJsonTrue == RyanJsonIsDetachedItem(detachedObj));
  263. RyanJsonDelete(detachedObj);
  264. RyanJsonDelete(arr2);
  265. RyanJsonDelete(obj2);
  266. RyanJsonDelete(arr1);
  267. RyanJsonDelete(obj1);
  268. RyanJsonFuzzerMemFailPop(lastIsEnableMemFail);
  269. }
  270. }
  271. char *key = "keyaaa";
  272. // 对容器这是正常 append;对标量则是刻意保留的误用合同覆盖。
  273. RyanJsonAddNullToObject(pJson, key);
  274. // 如果当前节点是 key 类型,尝试获取其 key String 作为后续操作 key
  275. if (RyanJsonTrue == RyanJsonIsKey(pJson))
  276. {
  277. // Change 系列测试已在 modify 用例覆盖
  278. key = RyanJsonGetKey(pJson);
  279. }
  280. if (RyanJsonTrue == RyanJsonIsBool(pJson) && RyanJsonFuzzerShouldFail(index))
  281. {
  282. // 标量追加测试仍保留在运行期:这里需要当前节点值参与断言,不能挪到 SelfTestOnce。
  283. if (RyanJsonTrue == RyanJsonAddBoolToObject(pJson, key, RyanJsonGetBoolValue(pJson)))
  284. {
  285. fuzzTestWithMemFail(
  286. assert(RyanJsonGetBoolValue(RyanJsonGetObjectByKey(pJson, key)) == RyanJsonGetBoolValue(pJson)));
  287. }
  288. }
  289. if (RyanJsonTrue == RyanJsonIsNumber(pJson) && RyanJsonFuzzerShouldFail(index))
  290. {
  291. // Number 路径既覆盖 AddInt/AddDouble,也顺带覆盖 typed Array builder 的运行期成功路径。
  292. // 这正是“数学上可由 fuzz 命中,所以不应塞进 self-test”的典型例子。
  293. if (RyanJsonTrue == RyanJsonIsInt(pJson))
  294. {
  295. if (RyanJsonTrue == RyanJsonAddIntToObject(pJson, key, RyanJsonGetIntValue(pJson)))
  296. {
  297. fuzzTestWithMemFail(
  298. assert(RyanJsonGetIntValue(RyanJsonGetObjectByKey(pJson, key)) == RyanJsonGetIntValue(pJson)));
  299. }
  300. int32_t val = RyanJsonGetIntValue(pJson);
  301. int32_t testIntArray[] = {val, val, val, val, val};
  302. RyanJsonBool_e jsonAddResult = RyanJsonAddItemToObject(
  303. pJson, (0 != size % 2) ? key : "arrayString",
  304. RyanJsonCreateIntArray(testIntArray, sizeof(testIntArray) / sizeof(testIntArray[0])));
  305. if (RyanJsonTrue == jsonAddResult)
  306. {
  307. fuzzTestWithMemFail({
  308. RyanJson_t itemIntArr = RyanJsonGetObjectByKey(pJson, key);
  309. assert(RyanJsonIsArray(itemIntArr));
  310. assert(RyanJsonGetArraySize(itemIntArr) == sizeof(testIntArray) / sizeof(testIntArray[0]));
  311. RyanJson_t item;
  312. RyanJsonArrayForEach(itemIntArr, item)
  313. {
  314. assert(RyanJsonGetIntValue(item) == val);
  315. }
  316. });
  317. }
  318. }
  319. else if (RyanJsonTrue == RyanJsonIsDouble(pJson))
  320. {
  321. if (RyanJsonTrue == RyanJsonAddDoubleToObject(pJson, key, RyanJsonGetDoubleValue(pJson)))
  322. {
  323. fuzzTestWithMemFail(assert(RyanJsonCompareDouble(RyanJsonGetDoubleValue(RyanJsonGetObjectByKey(pJson, key)),
  324. RyanJsonGetDoubleValue(pJson))));
  325. }
  326. double val = RyanJsonGetDoubleValue(pJson);
  327. double testDoubleArray[] = {val, val, val, val, val};
  328. RyanJsonBool_e jsonAddResult = RyanJsonAddItemToObject(
  329. pJson, (0 != size % 2) ? key : "arrayString",
  330. RyanJsonCreateDoubleArray(testDoubleArray, sizeof(testDoubleArray) / sizeof(testDoubleArray[0])));
  331. if (RyanJsonTrue == jsonAddResult)
  332. {
  333. fuzzTestWithMemFail({
  334. RyanJson_t itemIntArr = RyanJsonGetObjectByKey(pJson, key);
  335. assert(RyanJsonIsArray(itemIntArr));
  336. assert(RyanJsonGetArraySize(itemIntArr) == sizeof(testDoubleArray) / sizeof(testDoubleArray[0]));
  337. RyanJson_t item;
  338. RyanJsonArrayForEach(itemIntArr, item)
  339. {
  340. assert(RyanJsonCompareDouble(RyanJsonGetDoubleValue(item), val));
  341. }
  342. });
  343. }
  344. }
  345. }
  346. if (RyanJsonTrue == RyanJsonIsString(pJson) && RyanJsonFuzzerShouldFail(index))
  347. {
  348. // String 路径与 Number 路径保持相同结构,方便后续维护时按类型成组审阅覆盖缺口。
  349. if (RyanJsonTrue == RyanJsonAddStringToObject(pJson, key, RyanJsonGetStringValue(pJson)))
  350. {
  351. fuzzTestWithMemFail(assert(
  352. 0 == strcmp(RyanJsonGetStringValue(RyanJsonGetObjectByKey(pJson, key)), RyanJsonGetStringValue(pJson))));
  353. }
  354. const char *val = RyanJsonGetStringValue(pJson);
  355. const char *testStringArray[] = {val, val, val, val, val};
  356. RyanJsonBool_e jsonAddResult = RyanJsonAddItemToObject(
  357. pJson, (0 != size % 2) ? key : "arrayString",
  358. RyanJsonCreateStringArray(testStringArray, sizeof(testStringArray) / sizeof(testStringArray[0])));
  359. if (RyanJsonTrue == jsonAddResult)
  360. {
  361. fuzzTestWithMemFail({
  362. RyanJson_t itemIntArr = RyanJsonGetObjectByKey(pJson, key);
  363. assert(RyanJsonIsArray(itemIntArr));
  364. assert(RyanJsonGetArraySize(itemIntArr) == sizeof(testStringArray) / sizeof(testStringArray[0]));
  365. RyanJson_t item;
  366. RyanJsonArrayForEach(itemIntArr, item)
  367. {
  368. assert(0 == strcmp(RyanJsonGetStringValue(item), val));
  369. }
  370. });
  371. }
  372. }
  373. // 复合类型递归与插入测试
  374. if (RyanJsonTrue == RyanJsonIsArray(pJson) || RyanJsonTrue == RyanJsonIsObject(pJson))
  375. {
  376. RyanJson_t item;
  377. // 先递归已有子节点,再追加新节点,避免本轮新增节点在同一轮里被继续放大递归成本。
  378. // 递归处理子节点
  379. if (RyanJsonTrue == RyanJsonIsArray(pJson))
  380. {
  381. RyanJsonArrayForEach(pJson, item)
  382. {
  383. RyanJsonFuzzerTestCreate(item, size);
  384. }
  385. }
  386. else
  387. {
  388. // 对 Object 必须保留 key 语义,不能偷懒统一走 ArrayForEach。
  389. RyanJsonObjectForEach(pJson, item)
  390. {
  391. RyanJsonFuzzerTestCreate(item, size);
  392. }
  393. }
  394. // 添加随机生成的节点 (AddItem 方案A: 仅允许 Array/Object,成功后会消费原 item)
  395. uint32_t oldSize = RyanJsonGetSize(pJson);
  396. RyanJson_t newItem = RyanJsonFuzzerCreateRandomNode(pJson);
  397. RyanJson_t newItemDup = NULL;
  398. // 只给容器节点做 duplicate 快照,避免为标量白白增加复制和删除成本。
  399. if (newItem && (RyanJsonIsArray(newItem) || RyanJsonIsObject(newItem))) { newItemDup = RyanJsonDuplicate(newItem); }
  400. RyanJsonBool_e jsonAddResult = RyanJsonAddItemToObject(pJson, key, newItem);
  401. if (RyanJsonTrue == jsonAddResult)
  402. {
  403. fuzzTestWithMemFail({
  404. assert(RyanJsonGetSize(pJson) == oldSize + 1);
  405. #if true == RyanJsonDefaultAddAtHead
  406. RyanJson_t itemJson = RyanJsonGetObjectByIndex(pJson, 0);
  407. #else
  408. RyanJson_t itemJson = RyanJsonGetObjectByIndex(pJson, oldSize);
  409. #endif
  410. assert(NULL != itemJson);
  411. assert(RyanJsonIsArray(itemJson) || RyanJsonIsObject(itemJson));
  412. if (RyanJsonTrue == RyanJsonIsObject(pJson))
  413. {
  414. assert(RyanJsonIsKey(itemJson));
  415. assert(0 == strcmp(RyanJsonGetKey(itemJson), key));
  416. }
  417. if (newItemDup) { assert(RyanJsonCompare(itemJson, newItemDup)); }
  418. });
  419. }
  420. if (newItemDup) { RyanJsonDelete(newItemDup); }
  421. if (RyanJsonTrue == RyanJsonIsArray(pJson))
  422. {
  423. // 以下分支只在 Array 下执行,集中覆盖 Array 专属 append/insert 语义。
  424. // Object 的 key 语义更强,相关路径已在前面的 Add*ToObject / AddItemToObject 中单独验证。
  425. if (RyanJsonFuzzerShouldFail(index / 8) && RyanJsonTrue == RyanJsonAddNullToArray(pJson))
  426. {
  427. fuzzTestWithMemFail({
  428. assert(RyanJsonIsArray(pJson));
  429. #if true == RyanJsonDefaultAddAtHead
  430. assert(RyanJsonIsNull(RyanJsonGetObjectByIndex(pJson, 0)));
  431. #else
  432. assert(RyanJsonIsNull(RyanJsonGetObjectByIndex(pJson, RyanJsonGetSize(pJson) - 1)));
  433. #endif
  434. });
  435. }
  436. if (RyanJsonFuzzerShouldFail(index / 8) &&
  437. RyanJsonTrue == RyanJsonAddBoolToArray(pJson, 0 != size % 2 ? RyanJsonTrue : RyanJsonFalse))
  438. {
  439. fuzzTestWithMemFail({
  440. assert(RyanJsonIsArray(pJson));
  441. #if true == RyanJsonDefaultAddAtHead
  442. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, 0);
  443. #else
  444. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, RyanJsonGetSize(pJson) - 1);
  445. #endif
  446. assert(RyanJsonIsBool(item));
  447. assert(RyanJsonGetBoolValue(item) == (0 != size % 2 ? RyanJsonTrue : RyanJsonFalse));
  448. });
  449. }
  450. if (RyanJsonFuzzerShouldFail(index / 8) && RyanJsonTrue == RyanJsonAddIntToArray(pJson, size))
  451. {
  452. fuzzTestWithMemFail({
  453. assert(RyanJsonIsArray(pJson));
  454. #if true == RyanJsonDefaultAddAtHead
  455. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, 0);
  456. #else
  457. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, RyanJsonGetSize(pJson) - 1);
  458. #endif
  459. assert(RyanJsonIsInt(item));
  460. assert(RyanJsonGetIntValue(item) == size);
  461. });
  462. }
  463. if (RyanJsonFuzzerShouldFail(index / 8) && RyanJsonTrue == RyanJsonAddDoubleToArray(pJson, size * 0.123456))
  464. {
  465. fuzzTestWithMemFail({
  466. assert(RyanJsonIsArray(pJson));
  467. #if true == RyanJsonDefaultAddAtHead
  468. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, 0);
  469. #else
  470. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, RyanJsonGetSize(pJson) - 1);
  471. #endif
  472. assert(RyanJsonIsDouble(item));
  473. assert(RyanJsonCompareDouble(RyanJsonGetDoubleValue(item), size * 0.123456));
  474. });
  475. }
  476. if (RyanJsonFuzzerShouldFail(index / 8) && RyanJsonTrue == RyanJsonAddStringToArray(pJson, "NULL"))
  477. {
  478. fuzzTestWithMemFail({
  479. assert(RyanJsonIsArray(pJson));
  480. #if true == RyanJsonDefaultAddAtHead
  481. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, 0);
  482. #else
  483. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, RyanJsonGetSize(pJson) - 1);
  484. #endif
  485. assert(RyanJsonIsString(item));
  486. assert(0 == strcmp(RyanJsonGetStringValue(item), "NULL"));
  487. });
  488. }
  489. if (RyanJsonFuzzerShouldFail(index / 8) && RyanJsonTrue == RyanJsonAddItemToArray(pJson, RyanJsonCreateArray()))
  490. {
  491. fuzzTestWithMemFail({
  492. assert(RyanJsonIsArray(pJson));
  493. #if true == RyanJsonDefaultAddAtHead
  494. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, 0);
  495. #else
  496. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, RyanJsonGetSize(pJson) - 1);
  497. #endif
  498. assert(RyanJsonIsArray(item));
  499. });
  500. }
  501. if (RyanJsonFuzzerShouldFail(index / 8) && RyanJsonTrue == RyanJsonAddItemToArray(pJson, RyanJsonCreateObject()))
  502. {
  503. fuzzTestWithMemFail({
  504. assert(RyanJsonIsArray(pJson));
  505. #if true == RyanJsonDefaultAddAtHead
  506. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, 0);
  507. #else
  508. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, RyanJsonGetSize(pJson) - 1);
  509. #endif
  510. assert(RyanJsonIsObject(item));
  511. });
  512. }
  513. if (RyanJsonFuzzerShouldFail(index / 8))
  514. {
  515. RyanJson_t randomNode = RyanJsonFuzzerCreateRandomNode(RyanJsonGetArrayValue(pJson));
  516. RyanJson_t randomNodeDup = NULL;
  517. if (randomNode && (RyanJsonIsArray(randomNode) || RyanJsonIsObject(randomNode)))
  518. {
  519. randomNodeDup = RyanJsonDuplicate(randomNode);
  520. }
  521. uint32_t oldLen = RyanJsonGetSize(pJson);
  522. if (RyanJsonTrue == RyanJsonAddItemToArray(pJson, randomNode))
  523. {
  524. fuzzTestWithMemFail({
  525. assert(RyanJsonIsArray(pJson));
  526. assert(RyanJsonGetSize(pJson) == oldLen + 1);
  527. #if true == RyanJsonDefaultAddAtHead
  528. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, 0);
  529. #else
  530. RyanJson_t item = RyanJsonGetObjectByIndex(pJson, oldLen);
  531. #endif
  532. assert(NULL != item);
  533. if (randomNodeDup) { assert(RyanJsonCompare(item, randomNodeDup)); }
  534. });
  535. }
  536. if (randomNodeDup) { RyanJsonDelete(randomNodeDup); }
  537. }
  538. // 获取当前大小,避免重复调用 RyanJsonGetSize(其复杂度为 O(N))
  539. // 在嵌入式场景下应尽量规避 O(N^2) 路径
  540. if (RyanJsonFuzzerShouldFail(index / 8))
  541. {
  542. uint32_t len = RyanJsonGetSize(pJson);
  543. uint32_t idx = len / 2;
  544. // 测试中间位置插入
  545. // 注意:每次插入后,Array 长度增加,idx 相对位置其实在变动,
  546. // 这里为简化逻辑保持 index 不变,覆盖随机位置插入行为
  547. RyanJsonInsert(pJson, idx, RyanJsonCreateBool(key, 0 != size % 2 ? RyanJsonTrue : RyanJsonFalse));
  548. RyanJsonInsert(pJson, idx, RyanJsonCreateString(key, "NULL"));
  549. RyanJsonInsert(pJson, idx, RyanJsonCreateInt(key, 0));
  550. RyanJsonInsert(pJson, idx, RyanJsonCreateDouble(key, 0));
  551. RyanJsonInsert(pJson, idx, RyanJsonCreateArray());
  552. RyanJsonInsert(pJson, idx, RyanJsonCreateObject());
  553. // 测试头部插入
  554. RyanJsonInsert(pJson, 0, RyanJsonCreateBool(key, 0 != size % 2 ? RyanJsonTrue : RyanJsonFalse));
  555. RyanJsonInsert(pJson, 0, RyanJsonCreateString(key, "NULL"));
  556. RyanJsonInsert(pJson, 0, RyanJsonCreateInt(key, 0));
  557. RyanJsonInsert(pJson, 0, RyanJsonCreateDouble(key, 0));
  558. RyanJsonInsert(pJson, 0, RyanJsonCreateArray());
  559. RyanJsonInsert(pJson, 0, RyanJsonCreateObject());
  560. }
  561. }
  562. }
  563. return RyanJsonTrue;
  564. }