* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "gtest/gtest.h"
#include "mockcpp/mockcpp.hpp"
#include "errno/error_code.h"
#include "json/json_parser.h"
#include "json/json_generator.h"
#include "securec.h"
#include "osal/osal_mem.h"
#include "logger/logger.h"
class JsonParserUtest : public testing::Test {
protected:
void SetUp()
{}
void TearDown()
{}
};
TEST_F(JsonParserUtest, JsonParseCaseBasicNull)
{
const char *json = "null";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsNull(jsonObj));
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicTrue)
{
const char *json = "true";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsBool(jsonObj));
ASSERT_TRUE(GetJsonBool(jsonObj));
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicFalse)
{
const char *json = "false";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsBool(jsonObj));
ASSERT_FALSE(GetJsonBool(jsonObj));
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicNumber)
{
const char *json = "123";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsInt(jsonObj));
EXPECT_EQ(GetJsonInt(jsonObj), 123);
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicNumber1)
{
const char *json = "-123";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsInt(jsonObj));
EXPECT_EQ(GetJsonInt(jsonObj), -123);
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicNumber2)
{
const char *json = "+123";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsInt(jsonObj));
EXPECT_EQ(GetJsonInt(jsonObj), 123);
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicNumber3)
{
const char *json = "1.23";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsDouble(jsonObj));
EXPECT_EQ(GetJsonDouble(jsonObj), 1.23);
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicString)
{
const char *json = "\"123\"";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsString(jsonObj));
ASSERT_STREQ(GetJsonString(jsonObj), "123");
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicString2)
{
const char *json = "\"\\123\"";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj == NULL));
}
TEST_F(JsonParserUtest, JsonParseCaseBasicString3)
{
const char *json = "\"\\\"123\"";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsString(jsonObj));
ASSERT_STREQ(GetJsonString(jsonObj), "\"123");
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicInvalid0)
{
const char *json = "123\"";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj == NULL));
}
TEST_F(JsonParserUtest, JsonParseCaseBasicInvalid1)
{
const char *json = "[123";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj == NULL));
}
TEST_F(JsonParserUtest, JsonParseCaseBasicInvalid2)
{
const char *json = "{123";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj == NULL));
}
TEST_F(JsonParserUtest, JsonParseCaseBasicInvalid3)
{
const char *json = "\\123";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj == NULL));
}
TEST_F(JsonParserUtest, JsonParseCaseBasicObj)
{
const char *json = "{\"a\" : true, \"b\" : false, \"c\" : 123, \"d\" : \"123\"}";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsObj(jsonObj));
JsonObj *jsonObjValue = GetJsonSubObj(jsonObj, "a");
ASSERT_TRUE((jsonObjValue != NULL));
ASSERT_TRUE(JsonIsBool(jsonObjValue));
ASSERT_TRUE(GetJsonBool(jsonObjValue));
jsonObjValue = GetJsonSubObj(jsonObj, "b");
ASSERT_TRUE((jsonObjValue != NULL));
ASSERT_TRUE(JsonIsBool(jsonObjValue));
ASSERT_FALSE(GetJsonBool(jsonObjValue));
jsonObjValue = GetJsonSubObj(jsonObj, "c");
ASSERT_TRUE((jsonObjValue != NULL));
ASSERT_TRUE(JsonIsInt(jsonObjValue));
ASSERT_EQ(GetJsonInt(jsonObjValue), 123);
jsonObjValue = GetJsonSubObj(jsonObj, "d");
ASSERT_TRUE((jsonObjValue != NULL));
ASSERT_TRUE(JsonIsString(jsonObjValue));
ASSERT_STREQ(GetJsonString(jsonObjValue), "123");
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicObjInvalid)
{
const char *json = "{\"a\" : true; \"b\" : false, \"c\" : 123, \"d\" : \"123\"}";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj == NULL));
}
TEST_F(JsonParserUtest, JsonParseCaseBasicObjInvalid1)
{
const char *json = "{\"a\" : true, \"b\" : false, \"c\" : 123, \"d\" : \"123\",}";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj == NULL));
}
TEST_F(JsonParserUtest, JsonParseCaseBasicArray)
{
const char *json = "[0, 1, 2]";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsArray(jsonObj));
ASSERT_EQ(GetJsonArraySize(jsonObj), 3);
for (int i = 0; i < 3; i++) {
JsonObj *jsonObjValue = JsonArrayAt(jsonObj, i);
ASSERT_TRUE((jsonObjValue != NULL));
ASSERT_TRUE(JsonIsInt(jsonObjValue));
ASSERT_EQ(GetJsonInt(jsonObjValue), i);
}
JsonObj *jsonObjValue = JsonArrayAt(jsonObj, 4);
ASSERT_TRUE((jsonObjValue == NULL));
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicArrayObj)
{
const char *json = "[{\"a\" : true, \"b\" : false, \"c\" : 123, \"d\" : \"123\"}, "
"{\"a\" : true, \"b\" : false, \"c\" : 123, \"d\" : \"123\"}, "
"{\"a\" : true, \"b\" : false, \"c\" : 123, \"d\" : \"123\"}]";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsArray(jsonObj));
ASSERT_EQ(GetJsonArraySize(jsonObj), 3);
for (int i = 0; i < 3; i++) {
JsonObj *jsonObjIt = JsonArrayAt(jsonObj, i);
JsonObj *jsonObjValue = GetJsonSubObj(jsonObjIt, "a");
ASSERT_TRUE((jsonObjValue != NULL));
ASSERT_TRUE(JsonIsBool(jsonObjValue));
ASSERT_TRUE(GetJsonBool(jsonObjValue));
jsonObjValue = GetJsonSubObj(jsonObjIt, "b");
ASSERT_TRUE((jsonObjValue != NULL));
ASSERT_TRUE(JsonIsBool(jsonObjValue));
ASSERT_FALSE(GetJsonBool(jsonObjValue));
jsonObjValue = GetJsonSubObj(jsonObjIt, "c");
ASSERT_TRUE((jsonObjValue != NULL));
ASSERT_TRUE(JsonIsInt(jsonObjValue));
ASSERT_EQ(GetJsonInt(jsonObjValue), 123);
jsonObjValue = GetJsonSubObj(jsonObjIt, "d");
ASSERT_TRUE((jsonObjValue != NULL));
ASSERT_TRUE(JsonIsString(jsonObjValue));
ASSERT_STREQ(GetJsonString(jsonObjValue), "123");
}
JsonObj *jsonObjValue = JsonArrayAt(jsonObj, 4);
ASSERT_TRUE((jsonObjValue == NULL));
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, JsonParseCaseBasicObjArray)
{
const char *json = "{\"a\" : [0, 1, 2]}";
JsonObj *jsonObj = JsonParse(json);
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsObj(jsonObj));
JsonObj *jsonObjValue = GetJsonSubObj(jsonObj, "a");
ASSERT_TRUE((jsonObjValue != NULL));
ASSERT_TRUE(JsonIsArray(jsonObjValue));
ASSERT_EQ(GetJsonArraySize(jsonObjValue), 3);
for (int i = 0; i < 3; i++) {
JsonObj *jsonObjIt = JsonArrayAt(jsonObjValue, i);
ASSERT_TRUE((jsonObjIt != NULL));
ASSERT_TRUE(JsonIsInt(jsonObjIt));
ASSERT_EQ(GetJsonInt(jsonObjIt), i);
}
JsonFree(jsonObj);
}
void TestNumber(double expect, char *json)
{
JsonObj *jsonObj = JsonParse(json);
EXPECT_EQ(true, jsonObj != NULL);
EXPECT_EQ(true, JsonIsDouble(jsonObj));
EXPECT_EQ(expect, GetJsonDouble(jsonObj));
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, TestJsonDouble)
{
TestNumber(0.0, "0.0");
TestNumber(1.5, "1.5");
TestNumber(-1.5, "-1.5");
TestNumber(3.1416, "3.1416");
TestNumber(999999999999999.0, "999999999999999.0");
TestNumber(1.0000000000000002, "1.0000000000000002");
}
void TestString(char *expect, char *json)
{
JsonObj *jsonObj = JsonParse(json);
EXPECT_EQ(true, jsonObj != NULL);
EXPECT_EQ(true, JsonIsString(jsonObj));
EXPECT_EQ(0, strcmp(expect, GetJsonString(jsonObj)));
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, TestJsonParseString)
{
TestString("", "\"\"");
TestString("Hello", "\"Hello\"");
TestString("Hello\nWorld", "\"Hello\\nWorld\"");
TestString("\" \\ / \b \f \n \r \t", "\"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\"");
}
TEST_F(JsonParserUtest, TestJsonParseObject)
{
JsonObj *obj = JsonParse(" { } ");
ASSERT_TRUE((obj != NULL));
ASSERT_TRUE(JsonIsObj(obj));
JsonFree(obj);
JsonObj *jsonObj = JsonParse(" { "
"\"n\" : null , "
"\"f\" : false , "
"\"t\" : true , "
"\"i\" : 123 , "
"\"s\" : \"abc\", "
"\"a\" : [ 1, 2, 3 ],"
"\"o\" : { \"1\" : 1, \"2\" : 2, \"3\" : 3 }"
" } ");
ASSERT_TRUE((jsonObj != NULL));
ASSERT_TRUE(JsonIsObj(jsonObj));
JsonFree(jsonObj);
}
void TestInvalid(char *json)
{
JsonObj *jsonObj = JsonParse(json);
EXPECT_EQ(NULL, jsonObj);
}
TEST_F(JsonParserUtest, TestInvalid)
{
TestInvalid("nul");
TestInvalid("");
TestInvalid(" ");
TestInvalid("?");
TestInvalid("null x");
}
void TestRoundTrip(char *json)
{
JsonObj *jsonObj = JsonParse(json);
EXPECT_EQ(true, jsonObj != NULL);
char *newString = JsonToString(jsonObj);
EXPECT_EQ(0, strcmp(json, newString));
free(newString);
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, TestJsonToString)
{
TestRoundTrip("null");
TestRoundTrip("false");
TestRoundTrip("true");
TestRoundTrip("0");
TestRoundTrip("1");
TestRoundTrip("-1");
TestRoundTrip("1.5");
TestRoundTrip("1.1");
TestRoundTrip("3.25");
TestRoundTrip("-3.25");
TestRoundTrip("34234233425.25");
TestRoundTrip("-34234233425.25");
TestRoundTrip("1.00000000000001");
TestRoundTrip("\"\"");
TestRoundTrip("\"Hello\\nWorld\"");
TestRoundTrip("\"\\\" \\\\ / \\b \\f \\n \\r \\t\"");
TestRoundTrip("[]");
TestRoundTrip("[null,false,true,123,\"abc\",[1,2,3]]");
TestRoundTrip("{}");
TestRoundTrip(
"{\"a\":[1,2,3],\"f\":false,\"i\":123,\"n\":null,\"o\":{\"1\":1,\"2\":2,\"3\":3},\"s\":\"abc\",\"t\":true}");
TestRoundTrip("-9223372036854775808");
TestRoundTrip("9223372036854775807");
TestRoundTrip("9223372036854775808");
TestRoundTrip("18446744073709551615");
}
void TestInt(int64_t expect, char *json)
{
JsonObj *jsonObj = JsonParse(json);
EXPECT_EQ(true, jsonObj != NULL);
EXPECT_EQ(true, JsonIsInt(jsonObj));
EXPECT_EQ(expect, GetJsonInt(jsonObj));
JsonFree(jsonObj);
}
void TestUint(uint64_t expect, char *json)
{
JsonObj *jsonObj = JsonParse(json);
EXPECT_EQ(true, jsonObj != NULL);
EXPECT_EQ(true, JsonIsUint(jsonObj));
EXPECT_EQ(expect, GetJsonUint(jsonObj));
JsonFree(jsonObj);
}
TEST_F(JsonParserUtest, TestUint64)
{
TestInt(0, "0");
TestInt(-1, "-1");
TestInt(-9223372036854775808, "-9223372036854775808");
TestInt(9223372036854775807, "9223372036854775807");
TestUint(9223372036854775808, "9223372036854775808");
TestUint(18446744073709551615, "18446744073709551615");
}
TEST_F(JsonParserUtest, TestJsonMakeString)
{
JsonObj *emptyObj = JsonInit();
char *emptyStr = JsonToString(emptyObj);
EXPECT_EQ(0, strcmp("null", emptyStr));
JsonFree(emptyObj);
free(emptyStr);
JsonObj *subObj = JsonInit();
subObj->SetValueByKey(subObj, "1", {"1", CJSON_STRING})
->SetValueByKey(subObj, "2", {"2", CJSON_STRING})
->SetValueByKey(subObj, "3", {"3", CJSON_STRING});
JsonObj *arr = JsonInit();
arr->AddArrayItem(arr, {{.intValue = 1}, .type = CJSON_INT})
->AddArrayItem(arr, {{.intValue = 2}, .type = CJSON_INT})
->AddArrayItem(arr, {{.intValue = 3}, .type = CJSON_INT});
JsonObj *obj = JsonInit();
obj->SetValueByKey(obj, "s", {"abc", CJSON_STRING})
->SetValueByKey(obj, "t", {{.boolValue = true}, .type = CJSON_BOOL})
->SetValueByKey(obj, "f", {{.boolValue = false}, .type = CJSON_BOOL})
->SetValueByKey(obj, "i", {{.intValue = 123}, .type = CJSON_INT})
->SetValueByKey(obj, "d", {{.doubleValue = 1.5}, .type = CJSON_DOUBLE})
->SetValueByKey(obj, "a", *arr)
->SetValueByKey(obj, "o", *subObj);
JsonObj *objPtr = obj;
objPtr->TravelByKey(&objPtr, "o")->SetValueByKey(objPtr, "1", {{.intValue = 111}, .type = CJSON_INT});
EXPECT_EQ(CJSON_OBJ, objPtr->type);
char *json3 = JsonToString(obj);
char *expectJson = "{\"a\":[1,2,3],\"d\":1.5,\"f\":false,\"i\":123,\"o\":{\"1\":111,\"2\":\"2\",\"3\":\"3\"},\"s\":"
"\"abc\",\"t\":true}";
EXPECT_EQ(0, strcmp(expectJson, json3));
EXPECT_EQ(true, obj->Contains(obj, "s"));
EXPECT_EQ(false, obj->Contains(obj, "not_exist"));
void *notExist = obj->GetValueByKey(obj, "not_exist");
EXPECT_EQ(NULL, notExist);
const char *gotStr = obj->GetValueByKey(obj, "s")->stringValue;
EXPECT_EQ(0, strcmp("abc", gotStr));
int64_t gotInt = obj->GetValueByKey(obj, "i")->intValue;
EXPECT_EQ(123, gotInt);
bool gotTrue = obj->GetValueByKey(obj, "t")->boolValue;
EXPECT_EQ(true, gotTrue);
double gotDouble = obj->GetValueByKey(obj, "d")->doubleValue;
EXPECT_EQ(1.5, gotDouble);
free(json3);
JsonFree(subObj);
JsonFree(arr);
JsonFree(obj);
}
void EXPECT_JsonMake()
{
JsonObj *subObj = JsonInit();
if (subObj == NULL) {
return;
}
subObj->SetValueByKey(subObj, "1", {"1", CJSON_STRING})
->SetValueByKey(subObj, "2", {"2", CJSON_STRING})
->SetValueByKey(subObj, "3", {"3", CJSON_STRING})
->SetValueByKey(subObj, "3", {"30", CJSON_STRING});
JsonObj *arr = JsonInit();
if (arr == NULL) {
JsonFree(subObj);
return;
}
arr->AddArrayItem(arr, {{.intValue = 1}, .type = CJSON_INT})
->AddArrayItem(arr, {{.intValue = 2}, .type = CJSON_INT})
->AddArrayItem(arr, {{.intValue = 3}, .type = CJSON_INT});
JsonObj *obj = JsonInit();
if (obj == NULL) {
JsonFree(subObj);
JsonFree(arr);
return;
}
obj
->SetValueByKey(obj, "a", *arr)
->SetValueByKey(obj, "o", *subObj)
->SetValueByKey(obj, "s", {"abc", CJSON_STRING})
->SetValueByKey(obj, "t", {{.boolValue = true}, .type = CJSON_BOOL})
->SetValueByKey(obj, "f", {{.boolValue = false}, .type = CJSON_BOOL})
->SetValueByKey(obj, "i", {{.intValue = 123}, .type = CJSON_INT})
->SetValueByKey(obj, "d", {{.doubleValue = 1.5}, .type = CJSON_DOUBLE});
char *newString = JsonToString(obj);
if (newString != NULL) {
MSPROF_LOGI("%s", newString);
}
free(newString);
JsonFree(subObj);
JsonFree(arr);
JsonFree(obj);
}
TEST_F(JsonParserUtest, ToHeapStrMemoryLeakTest)
{
testing::internal::CaptureStdout();
JsonObj *dstObj = JsonInit();
JsonObj *obj = JsonInit();
obj->SetValueByKey(obj, "s", {"abc", CJSON_STRING});
MOCKER(memcpy_s)
.stubs()
.will(returnValue(-1));
JsonCopy(dstObj, obj);
JsonFree(obj);
JsonFree(dstObj);
std::string outputLog = testing::internal::GetCapturedStdout();
EXPECT_NE(outputLog.find("memcpy_s failed"), std::string::npos);
}
void *JsonMallocStub(int32_t size)
{
return malloc(size);
}
int32_t g_jsonMallocSuccessCnt = 0;
void *JsonMallocTest(int32_t size)
{
void *ret = nullptr;
if (g_jsonMallocSuccessCnt > 0) {
ret = JsonMallocStub(size);
}
g_jsonMallocSuccessCnt--;
return ret;
}
TEST_F(JsonParserUtest, TestJsonGeneratorMallocFailed)
{
MOCKER(OsalMalloc).stubs().will(invoke(JsonMallocTest));
for (int32_t i = 0; i < 31; i++) {
g_jsonMallocSuccessCnt = i;
EXPECT_JsonMake();
}
}
TEST_F(JsonParserUtest, TestJsonParserMallocFailed)
{
MOCKER(OsalMalloc).stubs().will(invoke(JsonMallocTest));
for (int32_t i = 0; i < 17; i++) {
g_jsonMallocSuccessCnt = i;
JsonObj *jsonObj = JsonParse(" { "
"\"n\" : null , "
"\"f\" : false , "
"\"t\" : true , "
"\"i\" : 123 , "
"\"s\" : \"abc\", "
"\"a\" : [ 1, 2, 3 ],"
"\"o\" : { \"1\" : 1, \"2\" : 2, \"3\" : 3 }"
" } ");
JsonFree(jsonObj);
EXPECT_EQ(jsonObj, nullptr);
}
}