/* Copyright 2015 the SumatraPDF project authors (see AUTHORS file). License: Simplified BSD (see COPYING.BSD) */ #include "BaseUtil.h" #include "JsonParser.h" // must be last due to assert() over-write #include "UtAssert.h" struct JsonValue { const char *path; json::DataType type; const char *value; JsonValue() : path(nullptr), value(nullptr) { } JsonValue(const char *path, const char *value, json::DataType type=json::Type_String) : path(path), type(type), value(value) { } }; class JsonVerifier : public json::ValueVisitor { const JsonValue *data; size_t dataLen; size_t idx; public: JsonVerifier(const JsonValue *data, size_t dataLen) : data(data), dataLen(dataLen), idx(0) { } ~JsonVerifier() { utassert(dataLen == idx); } virtual bool Visit(const char *path, const char *value, json::DataType type) { utassert(idx < dataLen); utassert(type == data[idx].type); utassert(str::Eq(path, data[idx].path)); utassert(str::Eq(value, data[idx].value)); idx++; return true; } }; void JsonTest() { static const struct { const char *json; JsonValue value; } validJsonData[] = { // strings { "\"test\"", JsonValue("", "test") }, { "\"\\\\\\n\\t\\u01234\"", JsonValue("", "\\\n\t\xC4\xA3""4") }, // numbers { "123", JsonValue("", "123", json::Type_Number) }, { "-99.99", JsonValue("", "-99.99", json::Type_Number) }, { "1.2E+15", JsonValue("", "1.2E+15", json::Type_Number) }, { "0e-7", JsonValue("", "0e-7", json::Type_Number) }, // keywords { "true", JsonValue("", "true", json::Type_Bool) }, { "false", JsonValue("", "false", json::Type_Bool) }, { "null", JsonValue("", "null", json::Type_Null) }, // dictionaries { "{\"key\":\"test\"}", JsonValue("/key", "test") }, { "{ \"no\" : 123 }", JsonValue("/no", "123", json::Type_Number) }, { "{ \"bool\": true }", JsonValue("/bool", "true", json::Type_Bool) }, { "{}", JsonValue() }, // arrays { "[\"test\"]", JsonValue("[0]", "test") }, { "[123]", JsonValue("[0]", "123", json::Type_Number) }, { "[ null ]", JsonValue("[0]", "null", json::Type_Null) }, { "[]", JsonValue() }, // combination { "{\"key\":[{\"name\":-987}]}", JsonValue("/key[0]/name", "-987", json::Type_Number) }, }; for (size_t i = 0; i < dimof(validJsonData); i++) { JsonVerifier verifier(&validJsonData[i].value, validJsonData[i].value.value ? 1 : 0); utassert(json::Parse(validJsonData[i].json, &verifier)); } static const struct { const char *json; JsonValue value; } invalidJsonData[] = { // dictionaries { "{\"key\":\"test\"", JsonValue("/key", "test") }, { "{ \"no\" : 123, }", JsonValue("/no", "123", json::Type_Number) }, { "{\"key\":\"test\"]", JsonValue("/key", "test") }, // arrays { "[\"test\"", JsonValue("[0]", "test") }, { "[123,]", JsonValue("[0]", "123", json::Type_Number) }, { "[\"test\"}", JsonValue("[0]", "test") }, }; for (size_t i = 0; i < dimof(invalidJsonData); i++) { JsonVerifier verifier(&invalidJsonData[i].value, 1); utassert(!json::Parse(invalidJsonData[i].json, &verifier)); } static const char *invalidJson[] = { "", "string", "nada", "\"open", "\"\\xC4\"", "\"\\u123h\"", "'string'", "01", ".1", "12.", "1e", "-", "-01", "{", "{,}", "{\"key\": }", "{\"key: 123 }", "{ 'key': 123 }", "[", "[,]" }; JsonVerifier verifyError(nullptr, 0); for (size_t i = 0; i < dimof(invalidJson); i++) { utassert(!json::Parse(invalidJson[i], &verifyError)); } const JsonValue testData[] = { JsonValue("/ComicBookInfo/1.0/title", "Meta data demo"), JsonValue("/ComicBookInfo/1.0/publicationMonth", "4", json::Type_Number), JsonValue("/ComicBookInfo/1.0/publicationYear", "2010", json::Type_Number), JsonValue("/ComicBookInfo/1.0/credits[0]/primary", "true", json::Type_Bool), JsonValue("/ComicBookInfo/1.0/credits[0]/role", "Writer"), JsonValue("/ComicBookInfo/1.0/credits[1]/primary", "false", json::Type_Bool), JsonValue("/ComicBookInfo/1.0/credits[1]/role", "Publisher"), JsonValue("/ComicBookInfo/1.0/credits[2]", "null", json::Type_Null), JsonValue("/appID", "Test/123"), }; const char *jsonSample = "{\n\ \"ComicBookInfo/1.0\": {\n\ \"title\": \"Meta data demo\",\n\ \"publicationMonth\": 4,\n\ \"publicationYear\": 2010,\n\ \"credits\": [\n\ { \"primary\": true, \"role\": \"Writer\" },\n\ { \"primary\": false, \"role\": \"Publisher\" },\n\ null\n\ ]\n\ },\n\ \"appID\": \"Test/123\"\n\ }"; JsonVerifier sampleVerifier(testData, dimof(testData)); utassert(json::Parse(jsonSample, &sampleVerifier)); }