fuzzerDelete.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #include "RyanJson.h"
  2. #include "RyanJsonFuzzer.h"
  3. /**
  4. * @brief 节点删除测试
  5. *
  6. * 测试 RyanJson 的节点删除功能(DeleteByKey、DeleteByIndex)。
  7. * 覆盖场景:
  8. * 异常删除:测试无效 key、越界索引、空指针等错误。
  9. * 特殊位置删除:测试删除头部与尾部节点。
  10. * 递归删除:遍历 Json 树,随机删除子节点,验证树结构的完整性。
  11. *
  12. * @param state Fuzzer 状态上下文
  13. * @param pJson 当前正在操作的 Json 节点
  14. * @param size 输入数据大小
  15. */
  16. RyanJsonBool_e RyanJsonFuzzerTestDelete(RyanJson_t pJson, uint32_t size)
  17. {
  18. // 仅处理容器类型(Object/Array)
  19. if (RyanJsonFalse == RyanJsonIsArray(pJson) && RyanJsonFalse == RyanJsonIsObject(pJson)) { return RyanJsonTrue; }
  20. // 故障注入与异常参数测试
  21. if (RyanJsonFuzzerShouldFail(100))
  22. {
  23. // key 删除错误用例
  24. RyanJsonDeleteByKey(pJson, "non_exist_key");
  25. RyanJsonDeleteByKey(NULL, "some_key");
  26. RyanJsonDeleteByKey(pJson, NULL);
  27. RyanJsonDeleteByKey(NULL, NULL);
  28. // index 删除错误用例
  29. uint32_t currentSize = RyanJsonGetSize(pJson);
  30. RyanJsonDeleteByIndex(pJson,
  31. currentSize); // 越界:index 使用 0-based,size 位置必越界
  32. RyanJsonDeleteByIndex(NULL, size % (currentSize + 1));
  33. RyanJsonDeleteByIndex(pJson, (uint32_t)(-(int32_t)size)); // 负数强转
  34. RyanJsonDeleteByIndex(NULL, (uint32_t)(-(int32_t)size));
  35. }
  36. // 特殊位置删除测试(头部/尾部)
  37. // 在一定概率下尝试删除头部或尾部节点,测试链表操作的鲁棒性
  38. uint32_t jsonSize = RyanJsonGetSize(pJson);
  39. if (RyanJsonFuzzerShouldFail(10) && jsonSize > 2)
  40. {
  41. // 尝试按 key 删除尾部节点(仅 Object 有效)
  42. if (RyanJsonTrue == RyanJsonIsObject(pJson))
  43. {
  44. RyanJson_t tailNode = RyanJsonGetObjectByIndex(pJson, jsonSize - 1);
  45. if (NULL != tailNode) { RyanJsonDeleteByKey(pJson, RyanJsonGetKey(tailNode)); }
  46. // 重新获取 Size,因为刚删了一个
  47. if (RyanJsonGetSize(pJson) > 0)
  48. {
  49. RyanJson_t headNode = RyanJsonGetObjectByIndex(pJson, 0);
  50. if (NULL != headNode) { RyanJsonDeleteByKey(pJson, RyanJsonGetKey(headNode)); }
  51. }
  52. }
  53. }
  54. // 递归遍历
  55. // 先递归处理子节点,再删除当前层级的节点,避免由上而下的删除导致整个分支消失,减少测试覆盖率
  56. RyanJson_t item = NULL;
  57. RyanJson_t lastItem = NULL;
  58. RyanJsonObjectForEach(pJson, item)
  59. {
  60. // 递归调用
  61. RyanJsonFuzzerTestDelete(item, size);
  62. lastItem = item;
  63. }
  64. // 删除节点
  65. // 按 key 删除(仅 Object)
  66. if (RyanJsonTrue == RyanJsonIsObject(pJson))
  67. {
  68. // 删除最后一个遍历到的子节点
  69. // 注意:RyanJsonObjectForEach 遍历结束后,childNode 为 NULL,
  70. // 所以我们需要在循环中维护 lastChild。
  71. // 并且要确认 lastChild 仍然有效(递归处理的是它的子节点,不应影响它本身)
  72. // 不过,如果上面的 Head/Tail 删除逻辑把 lastChild 删了,这里就会出问题。
  73. // 考虑到 RyanJsonGetNodeBy... 的额外开销,以及 Fuzzer 的随机性,
  74. // 我们这里再次检查 lastChild 是否还存在于 pJson 中比较耗时。
  75. // 简化策略:若 lastChild 有 key,则直接尝试删除;找不到也允许返回。
  76. if (NULL != lastItem && RyanJsonTrue == RyanJsonIsKey(lastItem)) { RyanJsonDeleteByKey(pJson, RyanJsonGetKey(lastItem)); }
  77. }
  78. // 按 index 删除(Array/Object)
  79. {
  80. uint32_t idx = 0;
  81. uint32_t currentSize = RyanJsonGetSize(pJson);
  82. if (0 != currentSize)
  83. {
  84. idx = size % currentSize;
  85. RyanJsonDeleteByIndex(pJson, idx);
  86. }
  87. }
  88. return RyanJsonTrue;
  89. }