| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- #include "testBase.h"
- static int32_t gFailAfter = -1;
- static int32_t gAllocCount = 0;
- static void *failingMalloc(size_t size)
- {
- if (gFailAfter >= 0 && gAllocCount++ >= gFailAfter) { return NULL; }
- return unityTestMalloc(size);
- }
- static void *failingRealloc(void *block, size_t size)
- {
- if (gFailAfter >= 0 && gAllocCount++ >= gFailAfter) { return NULL; }
- return unityTestRealloc(block, size);
- }
- static void setFailAfter(int32_t n)
- {
- gFailAfter = n;
- gAllocCount = 0;
- RyanJsonInitHooks(failingMalloc, unityTestFree, failingRealloc);
- }
- static void setFailAfterNoRealloc(int32_t n)
- {
- gFailAfter = n;
- gAllocCount = 0;
- RyanJsonInitHooks(failingMalloc, unityTestFree, NULL);
- }
- static void restoreHooks(void)
- {
- RyanJsonInitHooks(unityTestMalloc, unityTestFree, unityTestRealloc);
- gFailAfter = -1;
- gAllocCount = 0;
- }
- static void assertMinifyEq(char *buffer, int32_t textLen, const char *expected)
- {
- uint32_t len = RyanJsonMinify(buffer, textLen);
- TEST_ASSERT_EQUAL_STRING(expected, buffer);
- TEST_ASSERT_EQUAL_UINT32((uint32_t)strlen(expected), len);
- }
- #define expectCreateNullUnderOom(failAfter, expr, msg) \
- do \
- { \
- setFailAfter((failAfter)); \
- RyanJson_t _node = (expr); \
- restoreHooks(); \
- if (_node) { RyanJsonDelete(_node); } \
- TEST_ASSERT_NULL_MESSAGE(_node, (msg)); \
- } while (0)
- static void testParseOptionsTerminator(void)
- {
- const char *end = NULL;
- // 允许尾部内容:requireNullTerminator = false
- const char *text = " {\"a\":1} trailing";
- RyanJson_t json = RyanJsonParseOptions(text, (uint32_t)strlen(text), RyanJsonFalse, &end);
- TEST_ASSERT_NOT_NULL_MESSAGE(json, "ParseOptions(允许尾部) 失败");
- TEST_ASSERT_NOT_NULL_MESSAGE(end, "parseEndPtr 不应为 NULL");
- TEST_ASSERT_EQUAL_STRING_MESSAGE(" trailing", end, "parseEndPtr 位置错误");
- RyanJsonDelete(json);
- // 禁止尾部内容:requireNullTerminator = true
- json = RyanJsonParseOptions(text, (uint32_t)strlen(text), RyanJsonTrue, NULL);
- TEST_ASSERT_NULL_MESSAGE(json, "ParseOptions(强制结尾) 应失败");
- // 仅包含空白尾部:应成功,parseEndPtr 应指向末尾
- text = "{\"a\":1} \t\r\n";
- json = RyanJsonParseOptions(text, (uint32_t)strlen(text), RyanJsonTrue, &end);
- TEST_ASSERT_NOT_NULL_MESSAGE(json, "ParseOptions(空白尾部) 失败");
- TEST_ASSERT_NOT_NULL(end);
- TEST_ASSERT_EQUAL_CHAR('\0', *end);
- RyanJsonDelete(json);
- // 限长解析:仅解析前半段
- const char *concat = "{\"a\":1}{\"b\":2}";
- uint32_t firstLen = (uint32_t)strlen("{\"a\":1}");
- end = NULL;
- json = RyanJsonParseOptions(concat, firstLen, RyanJsonTrue, &end);
- TEST_ASSERT_NOT_NULL_MESSAGE(json, "ParseOptions(限长解析) 失败");
- TEST_ASSERT_NOT_NULL(end);
- TEST_ASSERT_EQUAL_STRING_MESSAGE("{\"b\":2}", end, "size-limited parseEndPtr 错误");
- RyanJsonDelete(json);
- }
- static void testMinifyComplexEscapesAndComments(void)
- {
- // 注释应被剔除,但字符串里的注释片段必须保留
- char buf[] = " { \"url\" : \"http://x//y\" , /* block */ \"path\" : \"C:\\\\tmp\\\\/*file*/\" , // line\n \"ok\" : true } ";
- assertMinifyEq(buf, (int32_t)strlen(buf), "{\"url\":\"http://x//y\",\"path\":\"C:\\\\tmp\\\\/*file*/\",\"ok\":true}");
- // 转义引号与字符串内 // 也应保持原样
- char buf2[] = "{\"msg\":\"he said: \\\"/*no*/\\\" //keep\" , \"v\" : 1} ";
- assertMinifyEq(buf2, (int32_t)strlen(buf2), "{\"msg\":\"he said: \\\"/*no*/\\\" //keep\",\"v\":1}");
- }
- static void testMinifyNoTerminatorOverflow(void)
- {
- // textLen 不包含额外 '\0' 空间时,不应越界写终止符
- uint8_t rawBuf[8] = {'{', '\"', 'a', '\"', ':', '1', '}', '#'};
- uint32_t len = RyanJsonMinify((char *)rawBuf, 7);
- TEST_ASSERT_EQUAL_UINT32(7, len);
- TEST_ASSERT_EQUAL_UINT8('#', rawBuf[7]);
- TEST_ASSERT_EQUAL_UINT8('{', rawBuf[0]);
- TEST_ASSERT_EQUAL_UINT8('\"', rawBuf[1]);
- TEST_ASSERT_EQUAL_UINT8('a', rawBuf[2]);
- TEST_ASSERT_EQUAL_UINT8('\"', rawBuf[3]);
- TEST_ASSERT_EQUAL_UINT8(':', rawBuf[4]);
- TEST_ASSERT_EQUAL_UINT8('1', rawBuf[5]);
- TEST_ASSERT_EQUAL_UINT8('}', rawBuf[6]);
- }
- static void testMinifyCommentBoundaryCases(void)
- {
- // 行注释直到输入结束(无换行)
- char lineTail[] = "{\"a\":1}//tail";
- assertMinifyEq(lineTail, (int32_t)strlen(lineTail), "{\"a\":1}");
- // 块注释未闭合:应安全走到 end,不越界
- char blockTail[] = "{\"a\":1}/*tail";
- assertMinifyEq(blockTail, (int32_t)strlen(blockTail), "{\"a\":1}");
- // 末尾孤立 '/' 不是注释起始,应保留
- char loneSlash[] = "{\"a\":1}/";
- assertMinifyEq(loneSlash, (int32_t)strlen(loneSlash), "{\"a\":1}/");
- // 字符串内末尾反斜杠且 textLen 截断,覆盖 text + 1 < end 为 false 的路径
- char rawTruncated[3] = {'\"', 'a', '\\'};
- uint32_t len = RyanJsonMinify(rawTruncated, 3);
- TEST_ASSERT_EQUAL_UINT32(3U, len);
- TEST_ASSERT_EQUAL_UINT8('\"', (uint8_t)rawTruncated[0]);
- TEST_ASSERT_EQUAL_UINT8('a', (uint8_t)rawTruncated[1]);
- TEST_ASSERT_EQUAL_UINT8('\\', (uint8_t)rawTruncated[2]);
- }
- static void testMinifyWhitespaceAndNonCommentSlashPaths(void)
- {
- char tabLeading[] = "\t{\"a\":1}";
- assertMinifyEq(tabLeading, (int32_t)strlen(tabLeading), "{\"a\":1}");
- char crLeading[] = "\r{\"b\":2}";
- assertMinifyEq(crLeading, (int32_t)strlen(crLeading), "{\"b\":2}");
- // "/x" 不是注释,应完整保留
- char slashNonComment[] = "/x";
- assertMinifyEq(slashNonComment, (int32_t)strlen(slashNonComment), "/x");
- // 块注释内出现 '*' 但后续不是 '/',应继续扫描直到真正闭合
- char blockWithStar[] = "/*a*b*/{\"k\":1}";
- assertMinifyEq(blockWithStar, (int32_t)strlen(blockWithStar), "{\"k\":1}");
- // 未闭合块注释且最后一个字符是 '*'
- char blockEndWithStar[] = "/*abc*";
- assertMinifyEq(blockEndWithStar, (int32_t)strlen(blockEndWithStar), "");
- }
- static void testParseAllocatedKeyCleanupOnValueError(void)
- {
- const char *bad = "{\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\":}";
- RyanJson_t json = RyanJsonParse(bad);
- TEST_ASSERT_NULL_MESSAGE(json, "长 key 后 value 非法时应解析失败");
- }
- static void testPrintPreallocatedArgGuards(void)
- {
- RyanJson_t obj = RyanJsonCreateObject();
- TEST_ASSERT_NOT_NULL(obj);
- RyanJsonAddStringToObject(obj, "k", "v");
- char buf[16] = {0};
- TEST_ASSERT_NULL(RyanJsonPrintPreallocated(NULL, buf, sizeof(buf), RyanJsonFalse, NULL));
- TEST_ASSERT_NULL(RyanJsonPrintPreallocated(obj, NULL, sizeof(buf), RyanJsonFalse, NULL));
- TEST_ASSERT_NULL(RyanJsonPrintPreallocated(obj, buf, 0, RyanJsonFalse, NULL));
- uint32_t len = 0;
- char *out = RyanJsonPrintPreallocated(obj, buf, sizeof(buf), RyanJsonFalse, &len);
- TEST_ASSERT_NOT_NULL(out);
- TEST_ASSERT_EQUAL_STRING("{\"k\":\"v\"}", out);
- TEST_ASSERT_EQUAL_UINT32((uint32_t)strlen(out), len);
- RyanJsonDelete(obj);
- }
- static void testInitHooksAndCreateApiGuards(void)
- {
- TEST_ASSERT_FALSE_MESSAGE(RyanJsonInitHooks(NULL, unityTestFree, unityTestRealloc), "InitHooks(NULL malloc) 应失败");
- TEST_ASSERT_FALSE_MESSAGE(RyanJsonInitHooks(unityTestMalloc, NULL, unityTestRealloc), "InitHooks(NULL free) 应失败");
- TEST_ASSERT_TRUE_MESSAGE(RyanJsonInitHooks(unityTestMalloc, unityTestFree, unityTestRealloc), "恢复默认 hooks 应成功");
- TEST_ASSERT_NULL_MESSAGE(RyanJsonCreateString("k", NULL), "CreateString(NULL value) 应返回 NULL");
- TEST_ASSERT_NULL_MESSAGE(RyanJsonCreateIntArray(NULL, 1), "CreateIntArray(NULL,1) 应返回 NULL");
- TEST_ASSERT_NULL_MESSAGE(RyanJsonCreateDoubleArray(NULL, 1), "CreateDoubleArray(NULL,1) 应返回 NULL");
- TEST_ASSERT_NULL_MESSAGE(RyanJsonCreateStringArray(NULL, 1), "CreateStringArray(NULL,1) 应返回 NULL");
- }
- static void testNumberBoundaries(void)
- {
- RyanJson_t json = RyanJsonParse("{\"i\":2147483647,\"i2\":-2147483648,\"i3\":2147483648,\"n\":-0}");
- TEST_ASSERT_NOT_NULL(json);
- RyanJson_t i = RyanJsonGetObjectToKey(json, "i");
- RyanJson_t i2 = RyanJsonGetObjectToKey(json, "i2");
- RyanJson_t i3 = RyanJsonGetObjectToKey(json, "i3");
- RyanJson_t n = RyanJsonGetObjectToKey(json, "n");
- TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsInt(i), "2147483647 应解析为 int32_t");
- TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsInt(i2), "-2147483648 应解析为 int32_t");
- TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsDouble(i3), "2147483648 应解析为 double");
- TEST_ASSERT_TRUE_MESSAGE(RyanJsonIsInt(n), "-0 应解析为 int32_t");
- TEST_ASSERT_EQUAL_INT_MESSAGE(0, RyanJsonGetIntValue(n), "-0 值错误");
- RyanJsonDelete(json);
- }
- static void testVarargsPathTypeMismatchAndNullInput(void)
- {
- RyanJson_t root = RyanJsonCreateObject();
- TEST_ASSERT_NOT_NULL(root);
- RyanJson_t arr = RyanJsonCreateArray();
- TEST_ASSERT_NOT_NULL(arr);
- TEST_ASSERT_TRUE(RyanJsonAddIntToArray(arr, 7));
- RyanJsonAddItemToObject(root, "arr", arr);
- TEST_ASSERT_TRUE(RyanJsonAddIntToObject(root, "n", 42));
- TEST_ASSERT_NULL_MESSAGE(RyanJsonGetObjectToKey(NULL, "a"), "NULL 根节点应返回 NULL");
- TEST_ASSERT_NULL_MESSAGE(RyanJsonGetObjectToIndex(NULL, 0), "NULL 根节点应返回 NULL");
- // 根节点是 object,也支持按索引获取直接子节点
- TEST_ASSERT_NOT_NULL_MESSAGE(RyanJsonGetObjectToIndex(root, 0), "object 根节点按 index=0 获取应成功");
- TEST_ASSERT_NULL_MESSAGE(RyanJsonGetObjectToIndex(root, 100), "object 根节点 index 越界应返回 NULL");
- // 标量节点继续向下取 key/index 都应失败
- TEST_ASSERT_NULL_MESSAGE(RyanJsonGetObjectToKey(root, "n", "x"), "标量节点不应继续按 key 深入");
- TEST_ASSERT_NULL_MESSAGE(RyanJsonGetObjectToIndex(arr, 0, 0), "标量节点不应继续按 index 深入");
- TEST_ASSERT_FALSE(RyanJsonHasObjectToKey(root, "n", "x"));
- TEST_ASSERT_FALSE(RyanJsonHasObjectToIndex(arr, 0, 0));
- // 首层查找失败路径(不进入可变参数迭代)
- TEST_ASSERT_NULL_MESSAGE(RyanJsonGetObjectByKeys(root, "missing", NULL), "首层 key 缺失应返回 NULL");
- TEST_ASSERT_NULL_MESSAGE(RyanJsonGetObjectByIndexs(arr, 1, UINT32_MAX), "首层 index 越界应返回 NULL");
- RyanJsonDelete(root);
- }
- static void testDuplicateKeyDetach(void)
- {
- RyanJson_t obj = RyanJsonCreateObject();
- TEST_ASSERT_TRUE(RyanJsonAddIntToObject(obj, "dup", 1));
- #if true == RyanJsonStrictObjectKeyCheck
- TEST_ASSERT_FALSE_MESSAGE(RyanJsonAddIntToObject(obj, "dup", 2), "严格模式下对象不应允许重复 key");
- #else
- TEST_ASSERT_TRUE_MESSAGE(RyanJsonAddIntToObject(obj, "dup", 2), "非严格模式下对象应允许重复 key");
- #endif
- RyanJson_t only = RyanJsonGetObjectByKey(obj, "dup");
- TEST_ASSERT_NOT_NULL(only);
- #if true == RyanJsonDefaultAddAtHead && false == RyanJsonStrictObjectKeyCheck
- TEST_ASSERT_EQUAL_INT(2, RyanJsonGetIntValue(only));
- #else
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(only));
- #endif
- RyanJson_t detached = RyanJsonDetachByKey(obj, "dup");
- TEST_ASSERT_NOT_NULL(detached);
- #if true == RyanJsonDefaultAddAtHead && false == RyanJsonStrictObjectKeyCheck
- TEST_ASSERT_EQUAL_INT(2, RyanJsonGetIntValue(detached));
- #else
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(detached));
- #endif
- RyanJsonDelete(detached);
- #if true == RyanJsonStrictObjectKeyCheck
- TEST_ASSERT_NULL(RyanJsonGetObjectByKey(obj, "dup"));
- #else
- RyanJson_t second = RyanJsonGetObjectByKey(obj, "dup");
- TEST_ASSERT_NOT_NULL(second);
- #if true == RyanJsonDefaultAddAtHead
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(second));
- #else
- TEST_ASSERT_EQUAL_INT(2, RyanJsonGetIntValue(second));
- #endif
- RyanJson_t detached2 = RyanJsonDetachByKey(obj, "dup");
- TEST_ASSERT_NOT_NULL(detached2);
- #if true == RyanJsonDefaultAddAtHead
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(detached2));
- #else
- TEST_ASSERT_EQUAL_INT(2, RyanJsonGetIntValue(detached2));
- #endif
- RyanJsonDelete(detached2);
- TEST_ASSERT_NULL(RyanJsonGetObjectByKey(obj, "dup"));
- #endif
- RyanJsonDelete(obj);
- }
- static void testInsertOutOfRangeAndKeyValidation(void)
- {
- // Array:index 超出范围应追加到尾部
- RyanJson_t arr = RyanJsonCreateArray();
- RyanJsonAddIntToArray(arr, 1);
- RyanJsonAddIntToArray(arr, 2);
- TEST_ASSERT_TRUE(RyanJsonInsert(arr, 100, RyanJsonCreateInt(NULL, 3)));
- TEST_ASSERT_EQUAL_INT(3, RyanJsonGetSize(arr));
- TEST_ASSERT_EQUAL_INT(3, RyanJsonGetIntValue(RyanJsonGetObjectByIndex(arr, 2)));
- RyanJsonDelete(arr);
- // Object:item 无 key 应失败
- RyanJson_t obj = RyanJsonCreateObject();
- RyanJsonAddIntToObject(obj, "a", 1);
- RyanJson_t noKey = RyanJsonCreateInt(NULL, 2);
- TEST_ASSERT_FALSE_MESSAGE(RyanJsonInsert(obj, 0, noKey), "Object 插入无 key item 应失败");
- TEST_ASSERT_EQUAL_INT(1, RyanJsonGetSize(obj));
- RyanJsonDelete(obj);
- }
- static void testGetSizeNullAndContainer(void)
- {
- TEST_ASSERT_EQUAL_UINT32_MESSAGE(0, RyanJsonGetSize(NULL), "NULL GetSize 应返回 0");
- RyanJson_t num = RyanJsonParse("1");
- TEST_ASSERT_NOT_NULL(num);
- TEST_ASSERT_EQUAL_INT_MESSAGE(1, RyanJsonGetSize(num), "标量 GetSize 应返回 1");
- RyanJsonDelete(num);
- RyanJson_t obj = RyanJsonCreateObject();
- TEST_ASSERT_NOT_NULL(obj);
- TEST_ASSERT_TRUE(RyanJsonAddIntToObject(obj, "a", 1));
- TEST_ASSERT_TRUE(RyanJsonAddItemToObject(obj, "b", RyanJsonCreateObject()));
- TEST_ASSERT_EQUAL_UINT32_MESSAGE(2, RyanJsonGetSize(obj), "对象 GetSize 应返回直接子节点数量");
- TEST_ASSERT_EQUAL_UINT32_MESSAGE(0, RyanJsonGetSize(RyanJsonGetObjectToKey(obj, "b")), "空对象 GetSize 应为 0");
- RyanJsonDelete(obj);
- RyanJson_t arr = RyanJsonCreateArray();
- TEST_ASSERT_NOT_NULL(arr);
- TEST_ASSERT_TRUE(RyanJsonAddIntToArray(arr, 1));
- TEST_ASSERT_TRUE(RyanJsonAddIntToArray(arr, 2));
- TEST_ASSERT_EQUAL_UINT32_MESSAGE(2, RyanJsonGetSize(arr), "数组 GetSize 应返回元素数量");
- RyanJsonDelete(arr);
- }
- static void testInternalUtilsBranchCoverage(void)
- {
- const char *same = "same";
- TEST_ASSERT_TRUE(RyanJsonInternalStrEq(same, same));
- TEST_ASSERT_FALSE(RyanJsonInternalStrEq("abc", "abd"));
- TEST_ASSERT_EQUAL_UINT8(4, RyanJsonInternalDecodeKeyLenField(3));
- TEST_ASSERT_EQUAL_UINT8(2, RyanJsonInternalDecodeKeyLenField(2));
- TEST_ASSERT_EQUAL_UINT8(1, RyanJsonInternalCalcLenBytes(UINT8_MAX));
- TEST_ASSERT_EQUAL_UINT8(2, RyanJsonInternalCalcLenBytes((uint32_t)UINT8_MAX + 1U));
- TEST_ASSERT_EQUAL_UINT8(3, RyanJsonInternalCalcLenBytes((uint32_t)UINT16_MAX + 1U));
- RyanJson_t arr = RyanJsonCreateArray();
- TEST_ASSERT_NOT_NULL(arr);
- TEST_ASSERT_TRUE(RyanJsonAddIntToArray(arr, 7));
- RyanJson_t v = RyanJsonGetObjectByIndexs(arr, 0, UINT32_MAX);
- TEST_ASSERT_NOT_NULL(v);
- TEST_ASSERT_EQUAL_INT(7, RyanJsonGetIntValue(v));
- RyanJsonDelete(arr);
- }
- static void testTypedArrayCreationZeroCount(void)
- {
- int32_t intOne[1] = {1};
- double doubleOne[1] = {1.5};
- const char *strOne[1] = {"x"};
- RyanJson_t iArr = RyanJsonCreateIntArray(intOne, 0);
- RyanJson_t dArr = RyanJsonCreateDoubleArray(doubleOne, 0);
- RyanJson_t sArr = RyanJsonCreateStringArray(strOne, 0);
- TEST_ASSERT_NOT_NULL(iArr);
- TEST_ASSERT_NOT_NULL(dArr);
- TEST_ASSERT_NOT_NULL(sArr);
- TEST_ASSERT_EQUAL_UINT32(0, RyanJsonGetSize(iArr));
- TEST_ASSERT_EQUAL_UINT32(0, RyanJsonGetSize(dArr));
- TEST_ASSERT_EQUAL_UINT32(0, RyanJsonGetSize(sArr));
- RyanJsonDelete(iArr);
- RyanJsonDelete(dArr);
- RyanJsonDelete(sArr);
- }
- static void testTypedArrayCreationOomPaths(void)
- {
- int32_t ints[2] = {1, 2};
- double doubles[2] = {1.1, 2.2};
- const char *strs[2] = {"a", "b"};
- expectCreateNullUnderOom(1, RyanJsonCreateIntArray(ints, 2), "CreateIntArray OOM 路径应返回 NULL");
- expectCreateNullUnderOom(1, RyanJsonCreateDoubleArray(doubles, 2), "CreateDoubleArray OOM 路径应返回 NULL");
- expectCreateNullUnderOom(1, RyanJsonCreateStringArray(strs, 2), "CreateStringArray OOM 路径应返回 NULL");
- }
- static void testCreateScalarOomAndTypeGuards(void)
- {
- // CreateInt/CreateDouble 失败分支
- expectCreateNullUnderOom(0, RyanJsonCreateInt(NULL, 1), "CreateInt OOM 应返回 NULL");
- expectCreateNullUnderOom(0, RyanJsonCreateDouble(NULL, 1.5), "CreateDouble OOM 应返回 NULL");
- // 类型判定与 GetObjectByKey 空参分支
- RyanJson_t nullNode = RyanJsonCreateNull(NULL);
- RyanJson_t intNode = RyanJsonCreateInt(NULL, 7);
- TEST_ASSERT_NOT_NULL(nullNode);
- TEST_ASSERT_NOT_NULL(intNode);
- TEST_ASSERT_TRUE(RyanJsonIsNull(nullNode));
- TEST_ASSERT_FALSE(RyanJsonIsNull(intNode));
- TEST_ASSERT_FALSE(RyanJsonIsNull(NULL));
- RyanJson_t obj = RyanJsonCreateObject();
- TEST_ASSERT_NOT_NULL(obj);
- TEST_ASSERT_TRUE(RyanJsonAddIntToObject(obj, "a", 1));
- TEST_ASSERT_NULL(RyanJsonGetObjectByKey(obj, NULL));
- TEST_ASSERT_NULL(RyanJsonGetObjectByKey(NULL, "a"));
- RyanJsonDelete(obj);
- RyanJsonDelete(nullNode);
- RyanJsonDelete(intNode);
- }
- static void testPrintExpandFallbackWithoutRealloc(void)
- {
- char longValue[600] = {0};
- memset(longValue, 'x', sizeof(longValue) - 1U);
- RyanJson_t obj = RyanJsonCreateObject();
- TEST_ASSERT_NOT_NULL(obj);
- TEST_ASSERT_TRUE(RyanJsonAddStringToObject(obj, "k", longValue));
- // PrintWithStyle 至少会分配 RyanJsonPrintfPreAlloSize;长字符串可稳定触发扩容
- // 先成功分配初始缓冲,再在扩容时失败,覆盖 jsonRealloc=NULL 的 fallback 路径
- setFailAfterNoRealloc(1);
- char *printed = RyanJsonPrint(obj, RyanJsonPrintfPreAlloSize, RyanJsonFalse, NULL);
- restoreHooks();
- if (printed) { RyanJsonFree(printed); }
- TEST_ASSERT_NULL_MESSAGE(printed, "Print 扩容 fallback(malloc) 失败应返回 NULL");
- RyanJsonDelete(obj);
- }
- static void testDuplicateEmptyContainerAndOomPaths(void)
- {
- RyanJson_t root = RyanJsonCreateObject();
- TEST_ASSERT_NOT_NULL(root);
- RyanJson_t emptyObj = RyanJsonCreateObject();
- TEST_ASSERT_NOT_NULL(emptyObj);
- TEST_ASSERT_TRUE(RyanJsonAddItemToObject(root, "e", emptyObj));
- RyanJson_t dup = RyanJsonDuplicate(root);
- TEST_ASSERT_NOT_NULL_MESSAGE(dup, "Duplicate(含空容器) 应成功");
- RyanJson_t dupE = RyanJsonGetObjectToKey(dup, "e");
- TEST_ASSERT_NOT_NULL(dupE);
- TEST_ASSERT_TRUE(RyanJsonIsObject(dupE));
- TEST_ASSERT_EQUAL_UINT32(0U, RyanJsonGetSize(dupE));
- RyanJsonDelete(dup);
- RyanJsonDelete(root);
- root = RyanJsonCreateObject();
- TEST_ASSERT_NOT_NULL(root);
- TEST_ASSERT_TRUE(RyanJsonAddIntToObject(root, "a", 1));
- // 根节点复制成功,首个子节点复制失败,覆盖 Duplicate error__ 路径
- expectCreateNullUnderOom(1, RyanJsonDuplicate(root), "Duplicate OOM 路径应返回 NULL");
- RyanJsonDelete(root);
- }
- static void testOomCreateParsePrint(void)
- {
- // 创建对象:首次分配失败
- setFailAfter(0);
- RyanJson_t obj = RyanJsonCreateObject();
- restoreHooks();
- if (obj) { RyanJsonDelete(obj); }
- TEST_ASSERT_NULL_MESSAGE(obj, "CreateObject OOM 应返回 NULL");
- // 解析流程:中途分配失败(长 key 触发 key buffer 分配)
- const char *longKeyJson =
- "{\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\":1}";
- setFailAfter(1); // root 成功,key buffer 失败
- RyanJson_t json = RyanJsonParse(longKeyJson);
- restoreHooks();
- if (json) { RyanJsonDelete(json); }
- TEST_ASSERT_NULL_MESSAGE(json, "Parse OOM 应返回 NULL");
- // 打印流程:分配打印缓冲失败
- obj = RyanJsonCreateObject();
- RyanJsonAddIntToObject(obj, "a", 1);
- setFailAfter(0);
- char *printed = RyanJsonPrint(obj, 32, RyanJsonFalse, NULL);
- restoreHooks();
- TEST_ASSERT_NULL_MESSAGE(printed, "Print OOM 应返回 NULL");
- RyanJsonDelete(obj);
- }
- void testRobustRunner(void)
- {
- UnitySetTestFile(__FILE__);
- RUN_TEST(testParseOptionsTerminator);
- RUN_TEST(testMinifyComplexEscapesAndComments);
- RUN_TEST(testMinifyNoTerminatorOverflow);
- RUN_TEST(testMinifyCommentBoundaryCases);
- RUN_TEST(testMinifyWhitespaceAndNonCommentSlashPaths);
- RUN_TEST(testParseAllocatedKeyCleanupOnValueError);
- RUN_TEST(testPrintPreallocatedArgGuards);
- RUN_TEST(testInitHooksAndCreateApiGuards);
- RUN_TEST(testNumberBoundaries);
- RUN_TEST(testVarargsPathTypeMismatchAndNullInput);
- RUN_TEST(testDuplicateKeyDetach);
- RUN_TEST(testInsertOutOfRangeAndKeyValidation);
- RUN_TEST(testGetSizeNullAndContainer);
- RUN_TEST(testInternalUtilsBranchCoverage);
- RUN_TEST(testTypedArrayCreationZeroCount);
- RUN_TEST(testTypedArrayCreationOomPaths);
- RUN_TEST(testCreateScalarOomAndTypeGuards);
- RUN_TEST(testPrintExpandFallbackWithoutRealloc);
- RUN_TEST(testDuplicateEmptyContainerAndOomPaths);
- RUN_TEST(testOomCreateParsePrint);
- }
|