| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- #include "RyanJson.h"
- #include "RyanJsonFuzzer.h"
- /**
- * @brief 修改与访问测试
- *
- * 测试 RyanJson 的节点修改能力(Change 值/key)以及数据访问安全性。
- * 覆盖场景:
- * 异常参数修改:测试空指针、类型不匹配时的修改行为。
- * 递归修改:遍历 Json 树,随机修改子节点的值或 key。
- * 类型安全访问:测试类型不匹配时调用 Get 接口的安全性(例如对 Int 调用 GetString)。
- * 访问正确性验证:验证 Get 接口返回值与 Set 结果一致。
- *
- * @param state Fuzzer 状态上下文
- * @param pJson 当前正在操作的 Json 节点
- * @param size 输入数据大小
- */
- RyanJsonBool_e RyanJsonFuzzerTestModify(RyanJson_t pJson, uint32_t size)
- {
- // 一次性覆盖 Change 参数/类型防御分支,并验证失败不改值
- static RyanJsonBool_e changeGuardCovered = RyanJsonFalse;
- if (RyanJsonFalse == changeGuardCovered)
- {
- RyanJsonBool_e lastIsEnableMemFail = g_fuzzerState.isEnableMemFail;
- g_fuzzerState.isEnableMemFail = false;
- RyanJson_t intNode = RyanJsonCreateInt(NULL, 123);
- RyanJson_t doubleNode = RyanJsonCreateDouble(NULL, 1.25);
- RyanJson_t boolNode = RyanJsonCreateBool("flag", RyanJsonTrue);
- RyanJson_t strNode = RyanJsonCreateString("k", "v");
- if (intNode)
- {
- assert(RyanJsonFalse == RyanJsonChangeDoubleValue(intNode, 9.9));
- assert(123 == RyanJsonGetIntValue(intNode));
- }
- if (doubleNode)
- {
- assert(RyanJsonFalse == RyanJsonChangeIntValue(doubleNode, 7));
- assert(RyanJsonTrue == RyanJsonCompareDouble(1.25, RyanJsonGetDoubleValue(doubleNode)));
- }
- if (boolNode)
- {
- assert(RyanJsonFalse == RyanJsonChangeIntValue(boolNode, 1));
- assert(RyanJsonTrue == RyanJsonGetBoolValue(boolNode));
- assert(RyanJsonTrue == RyanJsonChangeKey(boolNode, "flag2"));
- assert(0 == strcmp(RyanJsonGetKey(boolNode), "flag2"));
- }
- if (strNode)
- {
- // 命中 RyanJsonChangeStringValue 中 RyanJsonIsKey(pJson)==true 的分支
- assert(RyanJsonTrue == RyanJsonChangeStringValue(strNode, "v2"));
- assert(0 == strcmp(RyanJsonGetStringValue(strNode), "v2"));
- assert(0 == strcmp(RyanJsonGetKey(strNode), "k"));
- assert(RyanJsonFalse == RyanJsonChangeBoolValue(strNode, RyanJsonFalse));
- assert(0 == strcmp(RyanJsonGetStringValue(strNode), "v2"));
- assert(RyanJsonFalse == RyanJsonChangeKey(strNode, NULL));
- assert(0 == strcmp(RyanJsonGetKey(strNode), "k"));
- }
- RyanJsonDelete(intNode);
- RyanJsonDelete(doubleNode);
- RyanJsonDelete(boolNode);
- RyanJsonDelete(strNode);
- g_fuzzerState.isEnableMemFail = lastIsEnableMemFail;
- changeGuardCovered = RyanJsonTrue;
- }
- // 修改 key 测试
- if (RyanJsonIsKey(pJson))
- {
- const char *oldKey = RyanJsonGetKey(pJson);
- if (oldKey)
- {
- // 备份原始 key
- size_t keyLen = strlen(oldKey);
- char *backupKey = (char *)malloc(keyLen + 1);
- if (backupKey)
- {
- memcpy(backupKey, oldKey, keyLen);
- backupKey[keyLen] = 0;
- // 修改为临时 key
- if (RyanJsonTrue == RyanJsonChangeKey(pJson, "temp_modified_key"))
- {
- fuzzTestWithMemFail({ assert(0 == strcmp(RyanJsonGetKey(pJson), "temp_modified_key")); });
- }
- // 恢复原始 key(确保结构一致,避免影响后续测试)
- if (RyanJsonTrue == RyanJsonChangeKey(pJson, backupKey))
- {
- fuzzTestWithMemFail({ assert(0 == strcmp(RyanJsonGetKey(pJson), backupKey)); });
- }
- free(backupKey);
- }
- }
- }
- // 布尔节点
- if (RyanJsonIsBool(pJson))
- {
- RyanJsonBool_e oldBool = RyanJsonGetBoolValue(pJson);
- if (RyanJsonTrue == RyanJsonChangeBoolValue(pJson, !oldBool))
- {
- fuzzTestWithMemFail({ assert(RyanJsonGetBoolValue(pJson) == !oldBool); });
- }
- if (RyanJsonTrue == RyanJsonChangeBoolValue(pJson, oldBool)) // 恢复
- {
- fuzzTestWithMemFail({ assert(RyanJsonGetBoolValue(pJson) == oldBool); });
- }
- }
- // 数值节点(Int/Double)
- if (RyanJsonIsNumber(pJson))
- {
- if (RyanJsonIsInt(pJson))
- {
- int32_t oldInt = RyanJsonGetIntValue(pJson);
- if (RyanJsonTrue == RyanJsonChangeIntValue(pJson, (int32_t)size))
- {
- fuzzTestWithMemFail({ assert(RyanJsonGetIntValue(pJson) == (int32_t)size); });
- }
- if (RyanJsonTrue == RyanJsonChangeIntValue(pJson, oldInt)) // 恢复
- {
- fuzzTestWithMemFail({ assert(RyanJsonGetIntValue(pJson) == oldInt); });
- }
- }
- if (RyanJsonIsDouble(pJson))
- {
- double oldDouble = RyanJsonGetDoubleValue(pJson);
- if (RyanJsonTrue == RyanJsonChangeDoubleValue(pJson, size * 1.123456789))
- {
- fuzzTestWithMemFail({ assert(RyanJsonCompareDouble(RyanJsonGetDoubleValue(pJson), size * 1.123456789)); });
- }
- if (RyanJsonTrue == RyanJsonChangeDoubleValue(pJson, oldDouble)) // 恢复
- {
- fuzzTestWithMemFail({ assert(RyanJsonCompareDouble(RyanJsonGetDoubleValue(pJson), oldDouble)); });
- }
- }
- }
- // 字符串节点
- if (RyanJsonIsString(pJson))
- {
- const char *oldStr = RyanJsonGetStringValue(pJson);
- if (oldStr)
- {
- size_t strLen = strlen(oldStr);
- char *backupStr = (char *)malloc(strLen + 1);
- if (backupStr)
- {
- memcpy(backupStr, oldStr, strLen);
- backupStr[strLen] = 0;
- if (RyanJsonTrue == RyanJsonChangeStringValue(pJson, "modified_string_value"))
- {
- fuzzTestWithMemFail(
- { assert(0 == strcmp(RyanJsonGetStringValue(pJson), "modified_string_value")); });
- }
- if (RyanJsonTrue == RyanJsonChangeStringValue(pJson, "short"))
- {
- fuzzTestWithMemFail({ assert(0 == strcmp(RyanJsonGetStringValue(pJson), "short")); });
- }
- if (RyanJsonTrue == RyanJsonChangeStringValue(pJson, backupStr)) // 恢复
- {
- fuzzTestWithMemFail({ assert(0 == strcmp(RyanJsonGetStringValue(pJson), backupStr)); });
- }
- free(backupStr);
- }
- }
- }
- // 递归遍历
- if (RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))
- {
- RyanJson_t item;
- RyanJsonArrayForEach(pJson, item)
- {
- RyanJsonCheckReturnFalse(RyanJsonTrue == RyanJsonFuzzerTestModify(item, size));
- }
- }
- return RyanJsonTrue;
- }
- RyanJsonBool_e RyanJsonFuzzerVerifyGet(RyanJson_t parent, RyanJson_t current, uint32_t index, uint32_t size)
- {
- (void)size; // 未使用
- RyanJsonIsNull(current);
- // Get 接口前置条件:调用方需保证 pJson 非 NULL 且类型匹配。
- // 这里只保留可明确约定返回值的 GetObjectByKey 参数防御验证。
- // 验证 GetObjectByKey 异常参数
- assert(NULL == RyanJsonGetObjectByKey(NULL, NULL));
- assert(NULL == RyanJsonGetObjectByKey(current, NULL));
- assert(NULL == RyanJsonGetObjectByKey(NULL, "NULL"));
- assert(NULL == RyanJsonGetObjectToKey(NULL, NULL));
- assert(NULL == RyanJsonGetObjectToKey(current, NULL));
- assert(NULL == RyanJsonGetObjectToKey(NULL, "NULL"));
- // 验证 GetObjectByIndex 异常参数
- assert(NULL == RyanJsonGetObjectByIndex(NULL, 10));
- // 验证错误类型调用
- if (!RyanJsonIsObject(current)) { assert(NULL == RyanJsonGetObjectByKey(current, "NULL")); }
- // 验证 GetObjectByIndex 错误类型调用
- if (!RyanJsonIsArray(current) && !RyanJsonIsObject(current)) { assert(NULL == RyanJsonGetObjectByIndex(current, 0)); }
- // 验证父子关系查找
- // 确认当前节点 current 可以通过 parent + key/index 找回
- if (RyanJsonIsKey(current))
- {
- // 如果是 key 类型,应能通过 parent + key 找回(或找回其对应值)
- // 注意:RyanJsonGetObjectByKey 通常返回值节点,而非 key 节点本身
- // 但在 RyanJson 实现中,key 节点与 value 节点关系较紧密,返回语义由实现细节决定
- // 这里只调用 API 增加覆盖率,不做强一致性断言,因为实现细节可能复杂
- RyanJsonGetObjectToKey(parent, RyanJsonGetKey(current));
- }
- else
- {
- // 否则尝试通过 index 访问
- RyanJsonGetObjectToIndex(parent, index);
- }
- // 递归验证
- if (RyanJsonIsArray(current) || RyanJsonIsObject(current))
- {
- RyanJson_t item;
- // 这里的 index 是相对于 current 的子索引
- uint32_t childIndex = 0;
- RyanJsonObjectForEach(current, item)
- {
- RyanJsonFuzzerVerifyGet(current, item, childIndex, size);
- childIndex++;
- }
- }
- return RyanJsonTrue;
- }
- RyanJsonBool_e RyanJsonFuzzerTestGet(RyanJson_t pJson, uint32_t size)
- {
- // 全局异常测试
- assert(RyanJsonFalse == RyanJsonIsKey(NULL));
- assert(RyanJsonFalse == RyanJsonIsNull(NULL));
- assert(RyanJsonFalse == RyanJsonIsBool(NULL));
- assert(RyanJsonFalse == RyanJsonIsNumber(NULL));
- assert(RyanJsonFalse == RyanJsonIsString(NULL));
- assert(RyanJsonFalse == RyanJsonIsArray(NULL));
- assert(RyanJsonFalse == RyanJsonIsObject(NULL));
- assert(RyanJsonFalse == RyanJsonIsInt(NULL));
- assert(RyanJsonFalse == RyanJsonIsDouble(NULL));
- // 遍历测试
- if (RyanJsonIsArray(pJson) || RyanJsonIsObject(pJson))
- {
- RyanJson_t item;
- uint32_t index = 0;
- RyanJsonObjectForEach(pJson, item)
- {
- RyanJsonFuzzerVerifyGet(pJson, item, index, size);
- index++;
- }
- }
- return RyanJsonTrue;
- }
|