aboutsummaryrefslogtreecommitdiff
path: root/src/test_lib_json/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/test_lib_json/main.cpp')
-rw-r--r--src/test_lib_json/main.cpp2764
1 files changed, 2524 insertions, 240 deletions
diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp
index 13fc21d..991c247 100644
--- a/src/test_lib_json/main.cpp
+++ b/src/test_lib_json/main.cpp
@@ -1,12 +1,31 @@
-// Copyright 2007-2010 Baptiste Lepilleur
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(_MSC_VER)
+#pragma warning(disable : 4996)
+#endif
+
+#include "fuzz.h"
#include "jsontest.h"
+#include <cmath>
+#include <cstring>
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <iterator>
#include <json/config.h>
#include <json/json.h>
-#include <stdexcept>
+#include <limits>
+#include <memory>
+#include <sstream>
+#include <string>
+
+using CharReaderPtr = std::unique_ptr<Json::CharReader>;
// Make numeric limits more convenient to talk about.
// Assumes int type in 32 bits.
@@ -17,8 +36,8 @@
#define kint64min Json::Value::minInt64
#define kuint64max Json::Value::maxUInt64
-static const double kdint64max = double(kint64max);
-static const float kfint64max = float(kint64max);
+// static const double kdint64max = double(kint64max);
+// static const float kfint64max = float(kint64max);
static const float kfint32max = float(kint32max);
static const float kfuint32max = float(kuint32max);
@@ -35,33 +54,33 @@ static inline double uint64ToDouble(Json::UInt64 value) {
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
static inline double uint64ToDouble(Json::UInt64 value) {
return static_cast<double>(Json::Int64(value / 2)) * 2.0 +
- Json::Int64(value & 1);
+ static_cast<double>(Json::Int64(value & 1));
}
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+// local_ is the collection for the testcases in this code file.
+static std::deque<JsonTest::TestCaseFactory> local_;
+#define JSONTEST_FIXTURE_LOCAL(FixtureType, name) \
+ JSONTEST_FIXTURE_V2(FixtureType, name, local_)
+
struct ValueTest : JsonTest::TestCase {
Json::Value null_;
- Json::Value emptyArray_;
- Json::Value emptyObject_;
- Json::Value integer_;
- Json::Value unsignedInteger_;
- Json::Value smallUnsignedInteger_;
- Json::Value real_;
- Json::Value float_;
+ Json::Value emptyArray_{Json::arrayValue};
+ Json::Value emptyObject_{Json::objectValue};
+ Json::Value integer_{123456789};
+ Json::Value unsignedInteger_{34567890};
+ Json::Value smallUnsignedInteger_{Json::Value::UInt(Json::Value::maxInt)};
+ Json::Value real_{1234.56789};
+ Json::Value float_{0.00390625f};
Json::Value array1_;
Json::Value object1_;
- Json::Value emptyString_;
- Json::Value string1_;
- Json::Value string_;
- Json::Value true_;
- Json::Value false_;
-
- ValueTest()
- : emptyArray_(Json::arrayValue), emptyObject_(Json::objectValue),
- integer_(123456789), unsignedInteger_(34567890u),
- smallUnsignedInteger_(Json::Value::UInt(Json::Value::maxInt)),
- real_(1234.56789), float_(0.00390625f), emptyString_(""), string1_("a"),
- string_("sometext with space"), true_(true), false_(false) {
+ Json::Value emptyString_{""};
+ Json::Value string1_{"a"};
+ Json::Value string_{"sometext with space"};
+ Json::Value true_{true};
+ Json::Value false_{false};
+
+ ValueTest() {
array1_.append(1234);
object1_["id"] = 1234;
}
@@ -70,19 +89,19 @@ struct ValueTest : JsonTest::TestCase {
/// Initialize all checks to \c false by default.
IsCheck();
- bool isObject_;
- bool isArray_;
- bool isBool_;
- bool isString_;
- bool isNull_;
-
- bool isInt_;
- bool isInt64_;
- bool isUInt_;
- bool isUInt64_;
- bool isIntegral_;
- bool isDouble_;
- bool isNumeric_;
+ bool isObject_{false};
+ bool isArray_{false};
+ bool isBool_{false};
+ bool isString_{false};
+ bool isNull_{false};
+
+ bool isInt_{false};
+ bool isInt64_{false};
+ bool isUInt_{false};
+ bool isUInt64_{false};
+ bool isIntegral_{false};
+ bool isDouble_{false};
+ bool isNumeric_{false};
};
void checkConstMemberCount(const Json::Value& value,
@@ -98,54 +117,52 @@ struct ValueTest : JsonTest::TestCase {
/// Normalize the representation of floating-point number by stripped leading
/// 0 in exponent.
- static std::string normalizeFloatingPointStr(const std::string& s);
+ static Json::String normalizeFloatingPointStr(const Json::String& s);
};
-std::string ValueTest::normalizeFloatingPointStr(const std::string& s) {
- std::string::size_type index = s.find_last_of("eE");
- if (index != std::string::npos) {
- std::string::size_type hasSign =
- (s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
- std::string::size_type exponentStartIndex = index + 1 + hasSign;
- std::string normalized = s.substr(0, exponentStartIndex);
- std::string::size_type indexDigit =
- s.find_first_not_of('0', exponentStartIndex);
- std::string exponent = "0";
- if (indexDigit !=
- std::string::npos) // There is an exponent different from 0
- {
- exponent = s.substr(indexDigit);
- }
- return normalized + exponent;
- }
- return s;
-}
-
-JSONTEST_FIXTURE(ValueTest, checkNormalizeFloatingPointStr) {
- JSONTEST_ASSERT_STRING_EQUAL("0.0", normalizeFloatingPointStr("0.0"));
- JSONTEST_ASSERT_STRING_EQUAL("0e0", normalizeFloatingPointStr("0e0"));
- JSONTEST_ASSERT_STRING_EQUAL("1234.0", normalizeFloatingPointStr("1234.0"));
- JSONTEST_ASSERT_STRING_EQUAL("1234.0e0",
- normalizeFloatingPointStr("1234.0e0"));
- JSONTEST_ASSERT_STRING_EQUAL("1234.0e+0",
- normalizeFloatingPointStr("1234.0e+0"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e-1", normalizeFloatingPointStr("1234e-1"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e10", normalizeFloatingPointStr("1234e10"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e10",
- normalizeFloatingPointStr("1234e010"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e+10",
- normalizeFloatingPointStr("1234e+010"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e-10",
- normalizeFloatingPointStr("1234e-010"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e+100",
- normalizeFloatingPointStr("1234e+100"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e-100",
- normalizeFloatingPointStr("1234e-100"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e+1",
- normalizeFloatingPointStr("1234e+001"));
-}
-
-JSONTEST_FIXTURE(ValueTest, memberCount) {
+Json::String ValueTest::normalizeFloatingPointStr(const Json::String& s) {
+ auto index = s.find_last_of("eE");
+ if (index == s.npos)
+ return s;
+ std::size_t signWidth = (s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
+ auto exponentStartIndex = index + 1 + signWidth;
+ Json::String normalized = s.substr(0, exponentStartIndex);
+ auto indexDigit = s.find_first_not_of('0', exponentStartIndex);
+ Json::String exponent = "0";
+ if (indexDigit != s.npos) { // nonzero exponent
+ exponent = s.substr(indexDigit);
+ }
+ return normalized + exponent;
+}
+
+JSONTEST_FIXTURE_LOCAL(ValueTest, checkNormalizeFloatingPointStr) {
+ struct TestData {
+ std::string in;
+ std::string out;
+ } const testData[] = {
+ {"0.0", "0.0"},
+ {"0e0", "0e0"},
+ {"1234.0", "1234.0"},
+ {"1234.0e0", "1234.0e0"},
+ {"1234.0e-1", "1234.0e-1"},
+ {"1234.0e+0", "1234.0e+0"},
+ {"1234.0e+001", "1234.0e+1"},
+ {"1234e-1", "1234e-1"},
+ {"1234e+000", "1234e+0"},
+ {"1234e+001", "1234e+1"},
+ {"1234e10", "1234e10"},
+ {"1234e010", "1234e10"},
+ {"1234e+010", "1234e+10"},
+ {"1234e-010", "1234e-10"},
+ {"1234e+100", "1234e+100"},
+ {"1234e-100", "1234e-100"},
+ };
+ for (const auto& td : testData) {
+ JSONTEST_ASSERT_STRING_EQUAL(normalizeFloatingPointStr(td.in), td.out);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(ValueTest, memberCount) {
JSONTEST_ASSERT_PRED(checkMemberCount(emptyArray_, 0));
JSONTEST_ASSERT_PRED(checkMemberCount(emptyObject_, 0));
JSONTEST_ASSERT_PRED(checkMemberCount(array1_, 1));
@@ -158,9 +175,12 @@ JSONTEST_FIXTURE(ValueTest, memberCount) {
JSONTEST_ASSERT_PRED(checkMemberCount(emptyString_, 0));
JSONTEST_ASSERT_PRED(checkMemberCount(string_, 0));
JSONTEST_ASSERT_PRED(checkMemberCount(true_, 0));
+ JSONTEST_ASSERT_PRED(checkMemberCount(false_, 0));
+ JSONTEST_ASSERT_PRED(checkMemberCount(string1_, 0));
+ JSONTEST_ASSERT_PRED(checkMemberCount(float_, 0));
}
-JSONTEST_FIXTURE(ValueTest, objects) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, objects) {
// Types
IsCheck checks;
checks.isObject_ = true;
@@ -192,15 +212,71 @@ JSONTEST_FIXTURE(ValueTest, objects) {
JSONTEST_ASSERT_EQUAL(Json::Value(1234), constObject["id"]);
JSONTEST_ASSERT_EQUAL(Json::Value(), constObject["unknown id"]);
+ // Access through find()
+ const char idKey[] = "id";
+ const Json::Value* foundId = object1_.find(idKey, idKey + strlen(idKey));
+ JSONTEST_ASSERT(foundId != nullptr);
+ JSONTEST_ASSERT_EQUAL(Json::Value(1234), *foundId);
+
+ const char unknownIdKey[] = "unknown id";
+ const Json::Value* foundUnknownId =
+ object1_.find(unknownIdKey, unknownIdKey + strlen(unknownIdKey));
+ JSONTEST_ASSERT_EQUAL(nullptr, foundUnknownId);
+
+ // Access through demand()
+ const char yetAnotherIdKey[] = "yet another id";
+ const Json::Value* foundYetAnotherId =
+ object1_.find(yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey));
+ JSONTEST_ASSERT_EQUAL(nullptr, foundYetAnotherId);
+ Json::Value* demandedYetAnotherId = object1_.demand(
+ yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey));
+ JSONTEST_ASSERT(demandedYetAnotherId != nullptr);
+ *demandedYetAnotherId = "baz";
+
+ JSONTEST_ASSERT_EQUAL(Json::Value("baz"), object1_["yet another id"]);
+
// Access through non-const reference
JSONTEST_ASSERT_EQUAL(Json::Value(1234), object1_["id"]);
JSONTEST_ASSERT_EQUAL(Json::Value(), object1_["unknown id"]);
object1_["some other id"] = "foo";
JSONTEST_ASSERT_EQUAL(Json::Value("foo"), object1_["some other id"]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("foo"), object1_["some other id"]);
+
+ // Remove.
+ Json::Value got;
+ bool did;
+ did = object1_.removeMember("some other id", &got);
+ JSONTEST_ASSERT_EQUAL(Json::Value("foo"), got);
+ JSONTEST_ASSERT_EQUAL(true, did);
+ got = Json::Value("bar");
+ did = object1_.removeMember("some other id", &got);
+ JSONTEST_ASSERT_EQUAL(Json::Value("bar"), got);
+ JSONTEST_ASSERT_EQUAL(false, did);
+
+ object1_["some other id"] = "foo";
+ Json::Value* gotPtr = nullptr;
+ did = object1_.removeMember("some other id", gotPtr);
+ JSONTEST_ASSERT_EQUAL(nullptr, gotPtr);
+ JSONTEST_ASSERT_EQUAL(true, did);
+
+ // Using other removeMember interfaces, the test idea is the same as above.
+ object1_["some other id"] = "foo";
+ const Json::String key("some other id");
+ did = object1_.removeMember(key, &got);
+ JSONTEST_ASSERT_EQUAL(Json::Value("foo"), got);
+ JSONTEST_ASSERT_EQUAL(true, did);
+ got = Json::Value("bar");
+ did = object1_.removeMember(key, &got);
+ JSONTEST_ASSERT_EQUAL(Json::Value("bar"), got);
+ JSONTEST_ASSERT_EQUAL(false, did);
+
+ object1_["some other id"] = "foo";
+ object1_.removeMember(key);
+ JSONTEST_ASSERT_EQUAL(Json::nullValue, object1_[key]);
}
-JSONTEST_FIXTURE(ValueTest, arrays) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, arrays) {
const unsigned int index0 = 0;
// Types
@@ -240,9 +316,125 @@ JSONTEST_FIXTURE(ValueTest, arrays) {
array1_[2] = Json::Value(17);
JSONTEST_ASSERT_EQUAL(Json::Value(), array1_[1]);
JSONTEST_ASSERT_EQUAL(Json::Value(17), array1_[2]);
+ Json::Value got;
+ JSONTEST_ASSERT_EQUAL(true, array1_.removeIndex(2, &got));
+ JSONTEST_ASSERT_EQUAL(Json::Value(17), got);
+ JSONTEST_ASSERT_EQUAL(false, array1_.removeIndex(2, &got)); // gone now
+}
+JSONTEST_FIXTURE_LOCAL(ValueTest, resizeArray) {
+ Json::Value array;
+ {
+ for (Json::ArrayIndex i = 0; i < 10; i++)
+ array[i] = i;
+ JSONTEST_ASSERT_EQUAL(array.size(), 10);
+ // The length set is greater than the length of the array.
+ array.resize(15);
+ JSONTEST_ASSERT_EQUAL(array.size(), 15);
+
+ // The length set is less than the length of the array.
+ array.resize(5);
+ JSONTEST_ASSERT_EQUAL(array.size(), 5);
+
+ // The length of the array is set to 0.
+ array.resize(0);
+ JSONTEST_ASSERT_EQUAL(array.size(), 0);
+ }
+ {
+ for (Json::ArrayIndex i = 0; i < 10; i++)
+ array[i] = i;
+ JSONTEST_ASSERT_EQUAL(array.size(), 10);
+ array.clear();
+ JSONTEST_ASSERT_EQUAL(array.size(), 0);
+ }
+}
+JSONTEST_FIXTURE_LOCAL(ValueTest, getArrayValue) {
+ Json::Value array;
+ for (Json::ArrayIndex i = 0; i < 5; i++)
+ array[i] = i;
+
+ JSONTEST_ASSERT_EQUAL(array.size(), 5);
+ const Json::Value defaultValue(10);
+ Json::ArrayIndex index = 0;
+ for (; index <= 4; index++)
+ JSONTEST_ASSERT_EQUAL(index, array.get(index, defaultValue).asInt());
+
+ index = 4;
+ JSONTEST_ASSERT_EQUAL(array.isValidIndex(index), true);
+ index = 5;
+ JSONTEST_ASSERT_EQUAL(array.isValidIndex(index), false);
+ JSONTEST_ASSERT_EQUAL(defaultValue, array.get(index, defaultValue));
+ JSONTEST_ASSERT_EQUAL(array.isValidIndex(index), false);
+}
+JSONTEST_FIXTURE_LOCAL(ValueTest, arrayIssue252) {
+ int count = 5;
+ Json::Value root;
+ Json::Value item;
+ root["array"] = Json::Value::nullSingleton();
+ for (int i = 0; i < count; i++) {
+ item["a"] = i;
+ item["b"] = i;
+ root["array"][i] = item;
+ }
+ // JSONTEST_ASSERT_EQUAL(5, root["array"].size());
}
-JSONTEST_FIXTURE(ValueTest, null) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, arrayInsertAtRandomIndex) {
+ Json::Value array;
+ const Json::Value str0("index2");
+ const Json::Value str1("index3");
+ array.append("index0"); // append rvalue
+ array.append("index1");
+ array.append(str0); // append lvalue
+
+ std::vector<Json::Value*> vec; // storage value address for checking
+ for (Json::ArrayIndex i = 0; i < 3; i++) {
+ vec.push_back(&array[i]);
+ }
+ JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[0]); // check append
+ JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[1]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[2]);
+
+ // insert lvalue at the head
+ JSONTEST_ASSERT(array.insert(0, str1));
+ JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array[0]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[1]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[2]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[3]);
+ // checking address
+ for (Json::ArrayIndex i = 0; i < 3; i++) {
+ JSONTEST_ASSERT_EQUAL(vec[i], &array[i]);
+ }
+ vec.push_back(&array[3]);
+ // insert rvalue at middle
+ JSONTEST_ASSERT(array.insert(2, "index4"));
+ JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array[0]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[1]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index4"), array[2]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[3]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[4]);
+ // checking address
+ for (Json::ArrayIndex i = 0; i < 4; i++) {
+ JSONTEST_ASSERT_EQUAL(vec[i], &array[i]);
+ }
+ vec.push_back(&array[4]);
+ // insert rvalue at the tail
+ JSONTEST_ASSERT(array.insert(5, "index5"));
+ JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array[0]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[1]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index4"), array[2]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[3]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[4]);
+ JSONTEST_ASSERT_EQUAL(Json::Value("index5"), array[5]);
+ // checking address
+ for (Json::ArrayIndex i = 0; i < 5; i++) {
+ JSONTEST_ASSERT_EQUAL(vec[i], &array[i]);
+ }
+ vec.push_back(&array[5]);
+ // beyond max array size, it should not be allowed to insert into its tail
+ JSONTEST_ASSERT(!array.insert(10, "index10"));
+}
+
+JSONTEST_FIXTURE_LOCAL(ValueTest, null) {
JSONTEST_ASSERT_EQUAL(Json::nullValue, null_.type());
IsCheck checks;
@@ -265,9 +457,17 @@ JSONTEST_FIXTURE(ValueTest, null) {
JSONTEST_ASSERT_EQUAL(0.0, null_.asDouble());
JSONTEST_ASSERT_EQUAL(0.0, null_.asFloat());
JSONTEST_ASSERT_STRING_EQUAL("", null_.asString());
+
+ JSONTEST_ASSERT_EQUAL(Json::Value::nullSingleton(), null_);
+
+ // Test using a Value in a boolean context (false iff null)
+ JSONTEST_ASSERT_EQUAL(null_, false);
+ JSONTEST_ASSERT_EQUAL(object1_, true);
+ JSONTEST_ASSERT_EQUAL(!null_, true);
+ JSONTEST_ASSERT_EQUAL(!object1_, false);
}
-JSONTEST_FIXTURE(ValueTest, strings) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, strings) {
JSONTEST_ASSERT_EQUAL(Json::stringValue, string1_.type());
IsCheck checks;
@@ -296,7 +496,7 @@ JSONTEST_FIXTURE(ValueTest, strings) {
JSONTEST_ASSERT_STRING_EQUAL("a", string1_.asCString());
}
-JSONTEST_FIXTURE(ValueTest, bools) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, bools) {
JSONTEST_ASSERT_EQUAL(Json::booleanValue, false_.type());
IsCheck checks;
@@ -338,7 +538,7 @@ JSONTEST_FIXTURE(ValueTest, bools) {
JSONTEST_ASSERT_EQUAL(0.0, false_.asFloat());
}
-JSONTEST_FIXTURE(ValueTest, integers) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, integers) {
IsCheck checks;
Json::Value val;
@@ -443,7 +643,7 @@ JSONTEST_FIXTURE(ValueTest, integers) {
JSONTEST_ASSERT_EQUAL(0.0, val.asDouble());
JSONTEST_ASSERT_EQUAL(0.0, val.asFloat());
JSONTEST_ASSERT_EQUAL(false, val.asBool());
- JSONTEST_ASSERT_STRING_EQUAL("0", val.asString());
+ JSONTEST_ASSERT_STRING_EQUAL("0.0", val.asString());
// Zero (signed constructor arg)
val = Json::Value(0);
@@ -527,7 +727,7 @@ JSONTEST_FIXTURE(ValueTest, integers) {
JSONTEST_ASSERT_EQUAL(0.0, val.asDouble());
JSONTEST_ASSERT_EQUAL(0.0, val.asFloat());
JSONTEST_ASSERT_EQUAL(false, val.asBool());
- JSONTEST_ASSERT_STRING_EQUAL("0", val.asString());
+ JSONTEST_ASSERT_STRING_EQUAL("0.0", val.asString());
// 2^20 (signed constructor arg)
val = Json::Value(1 << 20);
@@ -610,8 +810,9 @@ JSONTEST_FIXTURE(ValueTest, integers) {
JSONTEST_ASSERT_EQUAL((1 << 20), val.asDouble());
JSONTEST_ASSERT_EQUAL((1 << 20), val.asFloat());
JSONTEST_ASSERT_EQUAL(true, val.asBool());
- JSONTEST_ASSERT_STRING_EQUAL("1048576",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "1048576.0",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// -2^20
val = Json::Value(-(1 << 20));
@@ -851,8 +1052,9 @@ JSONTEST_FIXTURE(ValueTest, integers) {
JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asDouble());
JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asFloat());
JSONTEST_ASSERT_EQUAL(true, val.asBool());
- JSONTEST_ASSERT_STRING_EQUAL("1099511627776",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "1099511627776.0",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// -2^40
val = Json::Value(-(Json::Int64(1) << 40));
@@ -923,11 +1125,12 @@ JSONTEST_FIXTURE(ValueTest, integers) {
JSONTEST_ASSERT_EQUAL(Json::UInt64(1) << 63, val.asUInt64());
JSONTEST_ASSERT_EQUAL(Json::UInt64(1) << 63, val.asLargestUInt());
JSONTEST_ASSERT_EQUAL(uint64ToDouble(Json::UInt64(1) << 63), val.asDouble());
- JSONTEST_ASSERT_EQUAL(float(uint64ToDouble(Json::UInt64(1) << 63)),
- val.asFloat());
+ JSONTEST_ASSERT_EQUAL(float(Json::UInt64(1) << 63), val.asFloat());
+
JSONTEST_ASSERT_EQUAL(true, val.asBool());
- JSONTEST_ASSERT_STRING_EQUAL("9.223372036854776e+18",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "9.2233720368547758e+18",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// int64 min
val = Json::Value(Json::Int64(kint64min));
@@ -974,11 +1177,12 @@ JSONTEST_FIXTURE(ValueTest, integers) {
JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asDouble());
JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asFloat());
JSONTEST_ASSERT_EQUAL(true, val.asBool());
- JSONTEST_ASSERT_STRING_EQUAL("-9.223372036854776e+18",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "-9.2233720368547758e+18",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// 10^19
- const Json::UInt64 ten_to_19 = static_cast<Json::UInt64>(1e19);
+ const auto ten_to_19 = static_cast<Json::UInt64>(1e19);
val = Json::Value(Json::UInt64(ten_to_19));
JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type());
@@ -1021,8 +1225,9 @@ JSONTEST_FIXTURE(ValueTest, integers) {
JSONTEST_ASSERT_EQUAL(1e19, val.asDouble());
JSONTEST_ASSERT_EQUAL(1e19, val.asFloat());
JSONTEST_ASSERT_EQUAL(true, val.asBool());
- JSONTEST_ASSERT_STRING_EQUAL("1e+19",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "1e+19",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// uint64 max
val = Json::Value(Json::UInt64(kuint64max));
@@ -1065,12 +1270,13 @@ JSONTEST_FIXTURE(ValueTest, integers) {
JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asDouble());
JSONTEST_ASSERT_EQUAL(18446744073709551616.0, val.asFloat());
JSONTEST_ASSERT_EQUAL(true, val.asBool());
- JSONTEST_ASSERT_STRING_EQUAL("1.844674407370955e+19",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "1.8446744073709552e+19",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
#endif
}
-JSONTEST_FIXTURE(ValueTest, nonIntegers) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, nonIntegers) {
IsCheck checks;
Json::Value val;
@@ -1155,8 +1361,9 @@ JSONTEST_FIXTURE(ValueTest, nonIntegers) {
JSONTEST_ASSERT_EQUAL(2147483647U, val.asLargestUInt());
#endif
JSONTEST_ASSERT_EQUAL(true, val.asBool());
- JSONTEST_ASSERT_EQUAL("2147483647.5",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_EQUAL(
+ "2147483647.5",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// A bit under int32 min
val = Json::Value(kint32min - 0.5);
@@ -1180,11 +1387,12 @@ JSONTEST_FIXTURE(ValueTest, nonIntegers) {
JSONTEST_ASSERT_EQUAL(-2147483648.5, val.asDouble());
JSONTEST_ASSERT_EQUAL(float(-2147483648.5), val.asFloat());
#ifdef JSON_HAS_INT64
- JSONTEST_ASSERT_EQUAL(-Json::Int64(1) << 31, val.asLargestInt());
+ JSONTEST_ASSERT_EQUAL(-(Json::Int64(1) << 31), val.asLargestInt());
#endif
JSONTEST_ASSERT_EQUAL(true, val.asBool());
- JSONTEST_ASSERT_EQUAL("-2147483648.5",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_EQUAL(
+ "-2147483648.5",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// A bit over uint32 max
val = Json::Value(kuint32max + 0.5);
@@ -1213,30 +1421,35 @@ JSONTEST_FIXTURE(ValueTest, nonIntegers) {
val.asLargestUInt());
#endif
JSONTEST_ASSERT_EQUAL(true, val.asBool());
- JSONTEST_ASSERT_EQUAL("4294967295.5",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_EQUAL(
+ "4294967295.5",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
val = Json::Value(1.2345678901234);
- JSONTEST_ASSERT_STRING_EQUAL("1.2345678901234",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "1.2345678901234001",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// A 16-digit floating point number.
val = Json::Value(2199023255552000.0f);
- JSONTEST_ASSERT_EQUAL(float(2199023255552000), val.asFloat());
- JSONTEST_ASSERT_STRING_EQUAL("2199023255552000",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_EQUAL(float(2199023255552000.0f), val.asFloat());
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "2199023255552000.0",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// A very large floating point number.
val = Json::Value(3.402823466385289e38);
JSONTEST_ASSERT_EQUAL(float(3.402823466385289e38), val.asFloat());
- JSONTEST_ASSERT_STRING_EQUAL("3.402823466385289e+38",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "3.402823466385289e+38",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// An even larger floating point number.
val = Json::Value(1.2345678e300);
JSONTEST_ASSERT_EQUAL(double(1.2345678e300), val.asDouble());
- JSONTEST_ASSERT_STRING_EQUAL("1.2345678e+300",
- normalizeFloatingPointStr(val.asString()));
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "1.2345678e+300",
+ normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
}
void ValueTest::checkConstMemberCount(const Json::Value& value,
@@ -1263,11 +1476,7 @@ void ValueTest::checkMemberCount(Json::Value& value,
JSONTEST_ASSERT_PRED(checkConstMemberCount(value, expectedCount));
}
-ValueTest::IsCheck::IsCheck()
- : isObject_(false), isArray_(false), isBool_(false), isString_(false),
- isNull_(false), isInt_(false), isInt64_(false), isUInt_(false),
- isUInt64_(false), isIntegral_(false), isDouble_(false),
- isNumeric_(false) {}
+ValueTest::IsCheck::IsCheck() = default;
void ValueTest::checkIs(const Json::Value& value, const IsCheck& check) {
JSONTEST_ASSERT_EQUAL(check.isObject_, value.isObject());
@@ -1290,31 +1499,35 @@ void ValueTest::checkIs(const Json::Value& value, const IsCheck& check) {
#endif
}
-JSONTEST_FIXTURE(ValueTest, compareNull) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, compareNull) {
JSONTEST_ASSERT_PRED(checkIsEqual(Json::Value(), Json::Value()));
+ JSONTEST_ASSERT_PRED(
+ checkIsEqual(Json::Value::nullSingleton(), Json::Value()));
+ JSONTEST_ASSERT_PRED(
+ checkIsEqual(Json::Value::nullSingleton(), Json::Value::nullSingleton()));
}
-JSONTEST_FIXTURE(ValueTest, compareInt) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, compareInt) {
JSONTEST_ASSERT_PRED(checkIsLess(0, 10));
JSONTEST_ASSERT_PRED(checkIsEqual(10, 10));
JSONTEST_ASSERT_PRED(checkIsEqual(-10, -10));
JSONTEST_ASSERT_PRED(checkIsLess(-10, 0));
}
-JSONTEST_FIXTURE(ValueTest, compareUInt) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, compareUInt) {
JSONTEST_ASSERT_PRED(checkIsLess(0u, 10u));
JSONTEST_ASSERT_PRED(checkIsLess(0u, Json::Value::maxUInt));
JSONTEST_ASSERT_PRED(checkIsEqual(10u, 10u));
}
-JSONTEST_FIXTURE(ValueTest, compareDouble) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, compareDouble) {
JSONTEST_ASSERT_PRED(checkIsLess(0.0, 10.0));
JSONTEST_ASSERT_PRED(checkIsEqual(10.0, 10.0));
JSONTEST_ASSERT_PRED(checkIsEqual(-10.0, -10.0));
JSONTEST_ASSERT_PRED(checkIsLess(-10.0, 0.0));
}
-JSONTEST_FIXTURE(ValueTest, compareString) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, compareString) {
JSONTEST_ASSERT_PRED(checkIsLess("", " "));
JSONTEST_ASSERT_PRED(checkIsLess("", "a"));
JSONTEST_ASSERT_PRED(checkIsLess("abcd", "zyui"));
@@ -1325,13 +1538,13 @@ JSONTEST_FIXTURE(ValueTest, compareString) {
JSONTEST_ASSERT_PRED(checkIsEqual("ABCD", "ABCD"));
}
-JSONTEST_FIXTURE(ValueTest, compareBoolean) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, compareBoolean) {
JSONTEST_ASSERT_PRED(checkIsLess(false, true));
JSONTEST_ASSERT_PRED(checkIsEqual(false, false));
JSONTEST_ASSERT_PRED(checkIsEqual(true, true));
}
-JSONTEST_FIXTURE(ValueTest, compareArray) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, compareArray) {
// array compare size then content
Json::Value emptyArray(Json::arrayValue);
Json::Value l1aArray;
@@ -1346,32 +1559,60 @@ JSONTEST_FIXTURE(ValueTest, compareArray) {
l2bArray.append(10);
JSONTEST_ASSERT_PRED(checkIsLess(emptyArray, l1aArray));
JSONTEST_ASSERT_PRED(checkIsLess(emptyArray, l2aArray));
- JSONTEST_ASSERT_PRED(checkIsLess(l1aArray, l2aArray));
+ JSONTEST_ASSERT_PRED(checkIsLess(l1aArray, l1bArray));
+ JSONTEST_ASSERT_PRED(checkIsLess(l1bArray, l2aArray));
JSONTEST_ASSERT_PRED(checkIsLess(l2aArray, l2bArray));
JSONTEST_ASSERT_PRED(checkIsEqual(emptyArray, Json::Value(emptyArray)));
JSONTEST_ASSERT_PRED(checkIsEqual(l1aArray, Json::Value(l1aArray)));
+ JSONTEST_ASSERT_PRED(checkIsEqual(l1bArray, Json::Value(l1bArray)));
+ JSONTEST_ASSERT_PRED(checkIsEqual(l2aArray, Json::Value(l2aArray)));
JSONTEST_ASSERT_PRED(checkIsEqual(l2bArray, Json::Value(l2bArray)));
}
-JSONTEST_FIXTURE(ValueTest, compareObject) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, compareObject) {
// object compare size then content
Json::Value emptyObject(Json::objectValue);
Json::Value l1aObject;
l1aObject["key1"] = 0;
Json::Value l1bObject;
- l1aObject["key1"] = 10;
+ l1bObject["key1"] = 10;
Json::Value l2aObject;
l2aObject["key1"] = 0;
l2aObject["key2"] = 0;
+ Json::Value l2bObject;
+ l2bObject["key1"] = 10;
+ l2bObject["key2"] = 0;
JSONTEST_ASSERT_PRED(checkIsLess(emptyObject, l1aObject));
- JSONTEST_ASSERT_PRED(checkIsLess(emptyObject, l2aObject));
- JSONTEST_ASSERT_PRED(checkIsLess(l1aObject, l2aObject));
+ JSONTEST_ASSERT_PRED(checkIsLess(l1aObject, l1bObject));
+ JSONTEST_ASSERT_PRED(checkIsLess(l1bObject, l2aObject));
+ JSONTEST_ASSERT_PRED(checkIsLess(l2aObject, l2bObject));
JSONTEST_ASSERT_PRED(checkIsEqual(emptyObject, Json::Value(emptyObject)));
JSONTEST_ASSERT_PRED(checkIsEqual(l1aObject, Json::Value(l1aObject)));
+ JSONTEST_ASSERT_PRED(checkIsEqual(l1bObject, Json::Value(l1bObject)));
JSONTEST_ASSERT_PRED(checkIsEqual(l2aObject, Json::Value(l2aObject)));
+ JSONTEST_ASSERT_PRED(checkIsEqual(l2bObject, Json::Value(l2bObject)));
+ {
+ Json::Value aObject;
+ aObject["a"] = 10;
+ Json::Value bObject;
+ bObject["b"] = 0;
+ Json::Value cObject;
+ cObject["c"] = 20;
+ cObject["f"] = 15;
+ Json::Value dObject;
+ dObject["d"] = -2;
+ dObject["e"] = 10;
+ JSONTEST_ASSERT_PRED(checkIsLess(aObject, bObject));
+ JSONTEST_ASSERT_PRED(checkIsLess(bObject, cObject));
+ JSONTEST_ASSERT_PRED(checkIsLess(cObject, dObject));
+ JSONTEST_ASSERT_PRED(checkIsEqual(aObject, Json::Value(aObject)));
+ JSONTEST_ASSERT_PRED(checkIsEqual(bObject, Json::Value(bObject)));
+ JSONTEST_ASSERT_PRED(checkIsEqual(cObject, Json::Value(cObject)));
+ JSONTEST_ASSERT_PRED(checkIsEqual(dObject, Json::Value(dObject)));
+ }
}
-JSONTEST_FIXTURE(ValueTest, compareType) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, compareType) {
// object of different type are ordered according to their type
JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(), Json::Value(1)));
JSONTEST_ASSERT_PRED(checkIsLess(Json::Value(1), Json::Value(1u)));
@@ -1384,6 +1625,58 @@ JSONTEST_FIXTURE(ValueTest, compareType) {
Json::Value(Json::objectValue)));
}
+JSONTEST_FIXTURE_LOCAL(ValueTest, CopyObject) {
+ Json::Value arrayVal;
+ arrayVal.append("val1");
+ arrayVal.append("val2");
+ arrayVal.append("val3");
+ Json::Value stringVal("string value");
+ Json::Value copy1, copy2;
+ {
+ Json::Value arrayCopy, stringCopy;
+ arrayCopy.copy(arrayVal);
+ stringCopy.copy(stringVal);
+ JSONTEST_ASSERT_PRED(checkIsEqual(arrayCopy, arrayVal));
+ JSONTEST_ASSERT_PRED(checkIsEqual(stringCopy, stringVal));
+ arrayCopy.append("val4");
+ JSONTEST_ASSERT(arrayCopy.size() == 4);
+ arrayVal.append("new4");
+ arrayVal.append("new5");
+ JSONTEST_ASSERT(arrayVal.size() == 5);
+ JSONTEST_ASSERT(!(arrayCopy == arrayVal));
+ stringCopy = "another string";
+ JSONTEST_ASSERT(!(stringCopy == stringVal));
+ copy1.copy(arrayCopy);
+ copy2.copy(stringCopy);
+ }
+ JSONTEST_ASSERT(arrayVal.size() == 5);
+ JSONTEST_ASSERT(stringVal == "string value");
+ JSONTEST_ASSERT(copy1.size() == 4);
+ JSONTEST_ASSERT(copy2 == "another string");
+ copy1.copy(stringVal);
+ JSONTEST_ASSERT(copy1 == "string value");
+ copy2.copy(arrayVal);
+ JSONTEST_ASSERT(copy2.size() == 5);
+ {
+ Json::Value srcObject, objectCopy, otherObject;
+ srcObject["key0"] = 10;
+ objectCopy.copy(srcObject);
+ JSONTEST_ASSERT(srcObject["key0"] == 10);
+ JSONTEST_ASSERT(objectCopy["key0"] == 10);
+ JSONTEST_ASSERT(srcObject.getMemberNames().size() == 1);
+ JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 1);
+ otherObject["key1"] = 15;
+ otherObject["key2"] = 16;
+ JSONTEST_ASSERT(otherObject.getMemberNames().size() == 2);
+ objectCopy.copy(otherObject);
+ JSONTEST_ASSERT(objectCopy["key1"] == 15);
+ JSONTEST_ASSERT(objectCopy["key2"] == 16);
+ JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 2);
+ otherObject["key1"] = 20;
+ JSONTEST_ASSERT(objectCopy["key1"] == 15);
+ }
+}
+
void ValueTest::checkIsLess(const Json::Value& x, const Json::Value& y) {
JSONTEST_ASSERT(x < y);
JSONTEST_ASSERT(y > x);
@@ -1414,7 +1707,7 @@ void ValueTest::checkIsEqual(const Json::Value& x, const Json::Value& y) {
JSONTEST_ASSERT(y.compare(x) == 0);
}
-JSONTEST_FIXTURE(ValueTest, typeChecksThrowExceptions) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, typeChecksThrowExceptions) {
#if JSON_USE_EXCEPTION
Json::Value intVal(1);
@@ -1480,7 +1773,7 @@ JSONTEST_FIXTURE(ValueTest, typeChecksThrowExceptions) {
#endif
}
-JSONTEST_FIXTURE(ValueTest, offsetAccessors) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, offsetAccessors) {
Json::Value x;
JSONTEST_ASSERT(x.getOffsetStart() == 0);
JSONTEST_ASSERT(x.getOffsetLimit() == 0);
@@ -1499,9 +1792,312 @@ JSONTEST_FIXTURE(ValueTest, offsetAccessors) {
JSONTEST_ASSERT(y.getOffsetLimit() == 0);
}
-struct WriterTest : JsonTest::TestCase {};
+JSONTEST_FIXTURE_LOCAL(ValueTest, StaticString) {
+ char mutant[] = "hello";
+ Json::StaticString ss(mutant);
+ Json::String regular(mutant);
+ mutant[1] = 'a';
+ JSONTEST_ASSERT_STRING_EQUAL("hallo", ss.c_str());
+ JSONTEST_ASSERT_STRING_EQUAL("hello", regular.c_str());
+ {
+ Json::Value root;
+ root["top"] = ss;
+ JSONTEST_ASSERT_STRING_EQUAL("hallo", root["top"].asString());
+ mutant[1] = 'u';
+ JSONTEST_ASSERT_STRING_EQUAL("hullo", root["top"].asString());
+ }
+ {
+ Json::Value root;
+ root["top"] = regular;
+ JSONTEST_ASSERT_STRING_EQUAL("hello", root["top"].asString());
+ mutant[1] = 'u';
+ JSONTEST_ASSERT_STRING_EQUAL("hello", root["top"].asString());
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(ValueTest, WideString) {
+ // https://github.com/open-source-parsers/jsoncpp/issues/756
+ const std::string uni = u8"\u5f0f\uff0c\u8fdb"; // "式,进"
+ std::string styled;
+ {
+ Json::Value v;
+ v["abc"] = uni;
+ styled = v.toStyledString();
+ }
+ Json::Value root;
+ {
+ JSONCPP_STRING errs;
+ std::istringstream iss(styled);
+ bool ok = parseFromStream(Json::CharReaderBuilder(), iss, &root, &errs);
+ JSONTEST_ASSERT(ok);
+ if (!ok) {
+ std::cerr << "errs: " << errs << std::endl;
+ }
+ }
+ JSONTEST_ASSERT_STRING_EQUAL(root["abc"].asString(), uni);
+}
+
+JSONTEST_FIXTURE_LOCAL(ValueTest, CommentBefore) {
+ Json::Value val; // fill val
+ val.setComment(Json::String("// this comment should appear before"),
+ Json::commentBefore);
+ Json::StreamWriterBuilder wbuilder;
+ wbuilder.settings_["commentStyle"] = "All";
+ {
+ char const expected[] = "// this comment should appear before\nnull";
+ Json::String result = Json::writeString(wbuilder, val);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ Json::String res2 = val.toStyledString();
+ Json::String exp2 = "\n";
+ exp2 += expected;
+ exp2 += "\n";
+ JSONTEST_ASSERT_STRING_EQUAL(exp2, res2);
+ }
+ Json::Value other = "hello";
+ val.swapPayload(other);
+ {
+ char const expected[] = "// this comment should appear before\n\"hello\"";
+ Json::String result = Json::writeString(wbuilder, val);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ Json::String res2 = val.toStyledString();
+ Json::String exp2 = "\n";
+ exp2 += expected;
+ exp2 += "\n";
+ JSONTEST_ASSERT_STRING_EQUAL(exp2, res2);
+ JSONTEST_ASSERT_STRING_EQUAL("null\n", other.toStyledString());
+ }
+ val = "hello";
+ // val.setComment("// this comment should appear before",
+ // Json::CommentPlacement::commentBefore); Assignment over-writes comments.
+ {
+ char const expected[] = "\"hello\"";
+ Json::String result = Json::writeString(wbuilder, val);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ Json::String res2 = val.toStyledString();
+ Json::String exp2;
+ exp2 += expected;
+ exp2 += "\n";
+ JSONTEST_ASSERT_STRING_EQUAL(exp2, res2);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(ValueTest, zeroes) {
+ char const cstr[] = "h\0i";
+ Json::String binary(cstr, sizeof(cstr)); // include trailing 0
+ JSONTEST_ASSERT_EQUAL(4U, binary.length());
+ Json::StreamWriterBuilder b;
+ {
+ Json::Value root;
+ root = binary;
+ JSONTEST_ASSERT_STRING_EQUAL(binary, root.asString());
+ }
+ {
+ char const top[] = "top";
+ Json::Value root;
+ root[top] = binary;
+ JSONTEST_ASSERT_STRING_EQUAL(binary, root[top].asString());
+ Json::Value removed;
+ bool did;
+ did = root.removeMember(top, top + sizeof(top) - 1U, &removed);
+ JSONTEST_ASSERT(did);
+ JSONTEST_ASSERT_STRING_EQUAL(binary, removed.asString());
+ did = root.removeMember(top, top + sizeof(top) - 1U, &removed);
+ JSONTEST_ASSERT(!did);
+ JSONTEST_ASSERT_STRING_EQUAL(binary, removed.asString()); // still
+ }
+}
-JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) {
+JSONTEST_FIXTURE_LOCAL(ValueTest, zeroesInKeys) {
+ char const cstr[] = "h\0i";
+ Json::String binary(cstr, sizeof(cstr)); // include trailing 0
+ JSONTEST_ASSERT_EQUAL(4U, binary.length());
+ {
+ Json::Value root;
+ root[binary] = "there";
+ JSONTEST_ASSERT_STRING_EQUAL("there", root[binary].asString());
+ JSONTEST_ASSERT(!root.isMember("h"));
+ JSONTEST_ASSERT(root.isMember(binary));
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "there", root.get(binary, Json::Value::nullSingleton()).asString());
+ Json::Value removed;
+ bool did;
+ did = root.removeMember(binary.data(), binary.data() + binary.length(),
+ &removed);
+ JSONTEST_ASSERT(did);
+ JSONTEST_ASSERT_STRING_EQUAL("there", removed.asString());
+ did = root.removeMember(binary.data(), binary.data() + binary.length(),
+ &removed);
+ JSONTEST_ASSERT(!did);
+ JSONTEST_ASSERT_STRING_EQUAL("there", removed.asString()); // still
+ JSONTEST_ASSERT(!root.isMember(binary));
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "", root.get(binary, Json::Value::nullSingleton()).asString());
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(ValueTest, specialFloats) {
+ Json::StreamWriterBuilder b;
+ b.settings_["useSpecialFloats"] = true;
+
+ Json::Value v = std::numeric_limits<double>::quiet_NaN();
+ Json::String expected = "NaN";
+ Json::String result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+
+ v = std::numeric_limits<double>::infinity();
+ expected = "Infinity";
+ result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+
+ v = -std::numeric_limits<double>::infinity();
+ expected = "-Infinity";
+ result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(ValueTest, precision) {
+ Json::StreamWriterBuilder b;
+ b.settings_["precision"] = 5;
+
+ Json::Value v = 100.0 / 3;
+ Json::String expected = "33.333";
+ Json::String result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+
+ v = 0.25000000;
+ expected = "0.25";
+ result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+
+ v = 0.2563456;
+ expected = "0.25635";
+ result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+
+ b.settings_["precision"] = 1;
+ expected = "0.3";
+ result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+
+ b.settings_["precision"] = 17;
+ v = 1234857476305.256345694873740545068;
+ expected = "1234857476305.2563";
+ result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+
+ b.settings_["precision"] = 24;
+ v = 0.256345694873740545068;
+ expected = "0.25634569487374054";
+ result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+
+ b.settings_["precision"] = 5;
+ b.settings_["precisionType"] = "decimal";
+ v = 0.256345694873740545068;
+ expected = "0.25635";
+ result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+
+ b.settings_["precision"] = 1;
+ b.settings_["precisionType"] = "decimal";
+ v = 0.256345694873740545068;
+ expected = "0.3";
+ result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+
+ b.settings_["precision"] = 10;
+ b.settings_["precisionType"] = "decimal";
+ v = 0.23300000;
+ expected = "0.233";
+ result = Json::writeString(b, v);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+JSONTEST_FIXTURE_LOCAL(ValueTest, searchValueByPath) {
+ Json::Value root, subroot;
+ root["property1"][0] = 0;
+ root["property1"][1] = 1;
+ subroot["object"] = "object";
+ root["property2"] = subroot;
+
+ const Json::Value defaultValue("error");
+ Json::FastWriter writer;
+
+ {
+ const Json::String expected("{"
+ "\"property1\":[0,1],"
+ "\"property2\":{\"object\":\"object\"}"
+ "}\n");
+ Json::String outcome = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, outcome);
+
+ // Array member exists.
+ const Json::Path path1(".property1.[%]", 1);
+ Json::Value result = path1.resolve(root);
+ JSONTEST_ASSERT_EQUAL(Json::Value(1), result);
+ result = path1.resolve(root, defaultValue);
+ JSONTEST_ASSERT_EQUAL(Json::Value(1), result);
+
+ // Array member does not exist.
+ const Json::Path path2(".property1.[2]");
+ result = path2.resolve(root);
+ JSONTEST_ASSERT_EQUAL(Json::nullValue, result);
+ result = path2.resolve(root, defaultValue);
+ JSONTEST_ASSERT_EQUAL(defaultValue, result);
+
+ // Access array path form error
+ const Json::Path path3(".property1.0");
+ result = path3.resolve(root);
+ JSONTEST_ASSERT_EQUAL(Json::nullValue, result);
+ result = path3.resolve(root, defaultValue);
+ JSONTEST_ASSERT_EQUAL(defaultValue, result);
+
+ // Object member exists.
+ const Json::Path path4(".property2.%", "object");
+ result = path4.resolve(root);
+ JSONTEST_ASSERT_EQUAL(Json::Value("object"), result);
+ result = path4.resolve(root, defaultValue);
+ JSONTEST_ASSERT_EQUAL(Json::Value("object"), result);
+
+ // Object member does not exist.
+ const Json::Path path5(".property2.hello");
+ result = path5.resolve(root);
+ JSONTEST_ASSERT_EQUAL(Json::nullValue, result);
+ result = path5.resolve(root, defaultValue);
+ JSONTEST_ASSERT_EQUAL(defaultValue, result);
+
+ // Access object path form error
+ const Json::Path path6(".property2.[0]");
+ result = path5.resolve(root);
+ JSONTEST_ASSERT_EQUAL(Json::nullValue, result);
+ result = path6.resolve(root, defaultValue);
+ JSONTEST_ASSERT_EQUAL(defaultValue, result);
+
+ // resolve will not change the value
+ outcome = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, outcome);
+ }
+ {
+ const Json::String expected("{"
+ "\"property1\":[0,1,null],"
+ "\"property2\":{"
+ "\"hello\":null,"
+ "\"object\":\"object\"}}\n");
+ Json::Path path1(".property1.[%]", 2);
+ Json::Value& value1 = path1.make(root);
+ JSONTEST_ASSERT_EQUAL(Json::nullValue, value1);
+
+ Json::Path path2(".property2.%", "hello");
+ Json::Value& value2 = path2.make(root);
+ JSONTEST_ASSERT_EQUAL(Json::nullValue, value2);
+
+ // make will change the value
+ const Json::String outcome = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, outcome);
+ }
+}
+struct FastWriterTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(FastWriterTest, dropNullPlaceholders) {
Json::FastWriter writer;
Json::Value nullValue;
JSONTEST_ASSERT(writer.write(nullValue) == "null\n");
@@ -1510,128 +2106,1816 @@ JSONTEST_FIXTURE(WriterTest, dropNullPlaceholders) {
JSONTEST_ASSERT(writer.write(nullValue) == "\n");
}
-struct ReaderTest : JsonTest::TestCase {};
+JSONTEST_FIXTURE_LOCAL(FastWriterTest, enableYAMLCompatibility) {
+ Json::FastWriter writer;
+ Json::Value root;
+ root["hello"] = "world";
-JSONTEST_FIXTURE(ReaderTest, parseWithNoErrors) {
- Json::Reader reader;
+ JSONTEST_ASSERT(writer.write(root) == "{\"hello\":\"world\"}\n");
+
+ writer.enableYAMLCompatibility();
+ JSONTEST_ASSERT(writer.write(root) == "{\"hello\": \"world\"}\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(FastWriterTest, omitEndingLineFeed) {
+ Json::FastWriter writer;
+ Json::Value nullValue;
+
+ JSONTEST_ASSERT(writer.write(nullValue) == "null\n");
+
+ writer.omitEndingLineFeed();
+ JSONTEST_ASSERT(writer.write(nullValue) == "null");
+}
+
+JSONTEST_FIXTURE_LOCAL(FastWriterTest, writeNumericValue) {
+ Json::FastWriter writer;
+ const Json::String expected("{"
+ "\"emptyValue\":null,"
+ "\"false\":false,"
+ "\"null\":\"null\","
+ "\"number\":-6200000000000000.0,"
+ "\"real\":1.256,"
+ "\"uintValue\":17"
+ "}\n");
+ Json::Value root;
+ root["emptyValue"] = Json::nullValue;
+ root["false"] = false;
+ root["null"] = "null";
+ root["number"] = -6.2e+15;
+ root["real"] = 1.256;
+ root["uintValue"] = Json::Value(17U);
+
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(FastWriterTest, writeArrays) {
+ Json::FastWriter writer;
+ const Json::String expected("{"
+ "\"property1\":[\"value1\",\"value2\"],"
+ "\"property2\":[]"
+ "}\n");
+ Json::Value root;
+ root["property1"][0] = "value1";
+ root["property1"][1] = "value2";
+ root["property2"] = Json::arrayValue;
+
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(FastWriterTest, writeNestedObjects) {
+ Json::FastWriter writer;
+ const Json::String expected("{"
+ "\"object1\":{"
+ "\"bool\":true,"
+ "\"nested\":123"
+ "},"
+ "\"object2\":{}"
+ "}\n");
+ Json::Value root, child;
+ child["nested"] = 123;
+ child["bool"] = true;
+ root["object1"] = child;
+ root["object2"] = Json::objectValue;
+
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+struct StyledWriterTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(StyledWriterTest, writeNumericValue) {
+ Json::StyledWriter writer;
+ const Json::String expected("{\n"
+ " \"emptyValue\" : null,\n"
+ " \"false\" : false,\n"
+ " \"null\" : \"null\",\n"
+ " \"number\" : -6200000000000000.0,\n"
+ " \"real\" : 1.256,\n"
+ " \"uintValue\" : 17\n"
+ "}\n");
+ Json::Value root;
+ root["emptyValue"] = Json::nullValue;
+ root["false"] = false;
+ root["null"] = "null";
+ root["number"] = -6.2e+15;
+ root["real"] = 1.256;
+ root["uintValue"] = Json::Value(17U);
+
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(StyledWriterTest, writeArrays) {
+ Json::StyledWriter writer;
+ const Json::String expected("{\n"
+ " \"property1\" : [ \"value1\", \"value2\" ],\n"
+ " \"property2\" : []\n"
+ "}\n");
+ Json::Value root;
+ root["property1"][0] = "value1";
+ root["property1"][1] = "value2";
+ root["property2"] = Json::arrayValue;
+
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(StyledWriterTest, writeNestedObjects) {
+ Json::StyledWriter writer;
+ const Json::String expected("{\n"
+ " \"object1\" : {\n"
+ " \"bool\" : true,\n"
+ " \"nested\" : 123\n"
+ " },\n"
+ " \"object2\" : {}\n"
+ "}\n");
+ Json::Value root, child;
+ child["nested"] = 123;
+ child["bool"] = true;
+ root["object1"] = child;
+ root["object2"] = Json::objectValue;
+
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(StyledWriterTest, multiLineArray) {
+ Json::StyledWriter writer;
+ {
+ // Array member has more than 20 print effect rendering lines
+ const Json::String expected("[\n "
+ "0,\n 1,\n 2,\n "
+ "3,\n 4,\n 5,\n "
+ "6,\n 7,\n 8,\n "
+ "9,\n 10,\n 11,\n "
+ "12,\n 13,\n 14,\n "
+ "15,\n 16,\n 17,\n "
+ "18,\n 19,\n 20\n]\n");
+ Json::Value root;
+ for (Json::ArrayIndex i = 0; i < 21; i++)
+ root[i] = i;
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+ {
+ // Array members do not exceed 21 print effects to render a single line
+ const Json::String expected("[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]\n");
+ Json::Value root;
+ for (Json::ArrayIndex i = 0; i < 10; i++)
+ root[i] = i;
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(StyledWriterTest, writeValueWithComment) {
+ Json::StyledWriter writer;
+ {
+ const Json::String expected("\n//commentBeforeValue\n\"hello\"\n");
+ Json::Value root = "hello";
+ root.setComment(Json::String("//commentBeforeValue"), Json::commentBefore);
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+ {
+ const Json::String expected("\"hello\" //commentAfterValueOnSameLine\n");
+ Json::Value root = "hello";
+ root.setComment(Json::String("//commentAfterValueOnSameLine"),
+ Json::commentAfterOnSameLine);
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+ {
+ const Json::String expected("\"hello\"\n//commentAfter\n\n");
+ Json::Value root = "hello";
+ root.setComment(Json::String("//commentAfter"), Json::commentAfter);
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+}
+
+struct StyledStreamWriterTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(StyledStreamWriterTest, writeNumericValue) {
+ Json::StyledStreamWriter writer;
+ const Json::String expected("{\n"
+ "\t\"emptyValue\" : null,\n"
+ "\t\"false\" : false,\n"
+ "\t\"null\" : \"null\",\n"
+ "\t\"number\" : -6200000000000000.0,\n"
+ "\t\"real\" : 1.256,\n"
+ "\t\"uintValue\" : 17\n"
+ "}\n");
+
+ Json::Value root;
+ root["emptyValue"] = Json::nullValue;
+ root["false"] = false;
+ root["null"] = "null";
+ root["number"] = -6.2e+15; // big float number
+ root["real"] = 1.256; // float number
+ root["uintValue"] = Json::Value(17U);
+
+ Json::OStringStream sout;
+ writer.write(sout, root);
+ const Json::String result = sout.str();
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(StyledStreamWriterTest, writeArrays) {
+ Json::StyledStreamWriter writer;
+ const Json::String expected("{\n"
+ "\t\"property1\" : [ \"value1\", \"value2\" ],\n"
+ "\t\"property2\" : []\n"
+ "}\n");
+ Json::Value root;
+ root["property1"][0] = "value1";
+ root["property1"][1] = "value2";
+ root["property2"] = Json::arrayValue;
+
+ Json::OStringStream sout;
+ writer.write(sout, root);
+ const Json::String result = sout.str();
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(StyledStreamWriterTest, writeNestedObjects) {
+ Json::StyledStreamWriter writer;
+ const Json::String expected("{\n"
+ "\t\"object1\" : \n"
+ "\t"
+ "{\n"
+ "\t\t\"bool\" : true,\n"
+ "\t\t\"nested\" : 123\n"
+ "\t},\n"
+ "\t\"object2\" : {}\n"
+ "}\n");
+ Json::Value root, child;
+ child["nested"] = 123;
+ child["bool"] = true;
+ root["object1"] = child;
+ root["object2"] = Json::objectValue;
+
+ Json::OStringStream sout;
+ writer.write(sout, root);
+ const Json::String result = sout.str();
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(StyledStreamWriterTest, multiLineArray) {
+ {
+ // Array member has more than 20 print effect rendering lines
+ const Json::String expected("[\n\t0,"
+ "\n\t1,"
+ "\n\t2,"
+ "\n\t3,"
+ "\n\t4,"
+ "\n\t5,"
+ "\n\t6,"
+ "\n\t7,"
+ "\n\t8,"
+ "\n\t9,"
+ "\n\t10,"
+ "\n\t11,"
+ "\n\t12,"
+ "\n\t13,"
+ "\n\t14,"
+ "\n\t15,"
+ "\n\t16,"
+ "\n\t17,"
+ "\n\t18,"
+ "\n\t19,"
+ "\n\t20\n]\n");
+ Json::StyledStreamWriter writer;
+ Json::Value root;
+ for (Json::ArrayIndex i = 0; i < 21; i++)
+ root[i] = i;
+ Json::OStringStream sout;
+ writer.write(sout, root);
+ const Json::String result = sout.str();
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+ {
+ Json::StyledStreamWriter writer;
+ // Array members do not exceed 21 print effects to render a single line
+ const Json::String expected("[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]\n");
+ Json::Value root;
+ for (Json::ArrayIndex i = 0; i < 10; i++)
+ root[i] = i;
+ Json::OStringStream sout;
+ writer.write(sout, root);
+ const Json::String result = sout.str();
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(StyledStreamWriterTest, writeValueWithComment) {
+ Json::StyledStreamWriter writer("\t");
+ {
+ const Json::String expected("//commentBeforeValue\n\"hello\"\n");
+ Json::Value root = "hello";
+ Json::OStringStream sout;
+ root.setComment(Json::String("//commentBeforeValue"), Json::commentBefore);
+ writer.write(sout, root);
+ const Json::String result = sout.str();
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+ {
+ const Json::String expected("\"hello\" //commentAfterValueOnSameLine\n");
+ Json::Value root = "hello";
+ Json::OStringStream sout;
+ root.setComment(Json::String("//commentAfterValueOnSameLine"),
+ Json::commentAfterOnSameLine);
+ writer.write(sout, root);
+ const Json::String result = sout.str();
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+ {
+ const Json::String expected("\"hello\"\n//commentAfter\n");
+ Json::Value root = "hello";
+ Json::OStringStream sout;
+ root.setComment(Json::String("//commentAfter"), Json::commentAfter);
+ writer.write(sout, root);
+ const Json::String result = sout.str();
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+}
+
+struct StreamWriterTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, writeNumericValue) {
+ Json::StreamWriterBuilder writer;
+ const Json::String expected("{\n"
+ "\t\"emptyValue\" : null,\n"
+ "\t\"false\" : false,\n"
+ "\t\"null\" : \"null\",\n"
+ "\t\"number\" : -6200000000000000.0,\n"
+ "\t\"real\" : 1.256,\n"
+ "\t\"uintValue\" : 17\n"
+ "}");
+ Json::Value root;
+ root["emptyValue"] = Json::nullValue;
+ root["false"] = false;
+ root["null"] = "null";
+ root["number"] = -6.2e+15;
+ root["real"] = 1.256;
+ root["uintValue"] = Json::Value(17U);
+
+ const Json::String result = Json::writeString(writer, root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, writeArrays) {
+ Json::StreamWriterBuilder writer;
+ const Json::String expected("{\n"
+ "\t\"property1\" : \n"
+ "\t[\n"
+ "\t\t\"value1\",\n"
+ "\t\t\"value2\"\n"
+ "\t],\n"
+ "\t\"property2\" : []\n"
+ "}");
+
+ Json::Value root;
+ root["property1"][0] = "value1";
+ root["property1"][1] = "value2";
+ root["property2"] = Json::arrayValue;
+
+ const Json::String result = Json::writeString(writer, root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, writeNestedObjects) {
+ Json::StreamWriterBuilder writer;
+ const Json::String expected("{\n"
+ "\t\"object1\" : \n"
+ "\t{\n"
+ "\t\t\"bool\" : true,\n"
+ "\t\t\"nested\" : 123\n"
+ "\t},\n"
+ "\t\"object2\" : {}\n"
+ "}");
+
+ Json::Value root, child;
+ child["nested"] = 123;
+ child["bool"] = true;
+ root["object1"] = child;
+ root["object2"] = Json::objectValue;
+
+ const Json::String result = Json::writeString(writer, root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, multiLineArray) {
+ Json::StreamWriterBuilder wb;
+ wb.settings_["commentStyle"] = "None";
+ {
+ // When wb.settings_["commentStyle"] = "None", the effect of
+ // printing multiple lines will be displayed when there are
+ // more than 20 array members.
+ const Json::String expected("[\n\t0,"
+ "\n\t1,"
+ "\n\t2,"
+ "\n\t3,"
+ "\n\t4,"
+ "\n\t5,"
+ "\n\t6,"
+ "\n\t7,"
+ "\n\t8,"
+ "\n\t9,"
+ "\n\t10,"
+ "\n\t11,"
+ "\n\t12,"
+ "\n\t13,"
+ "\n\t14,"
+ "\n\t15,"
+ "\n\t16,"
+ "\n\t17,"
+ "\n\t18,"
+ "\n\t19,"
+ "\n\t20\n]");
+ Json::Value root;
+ for (Json::ArrayIndex i = 0; i < 21; i++)
+ root[i] = i;
+ const Json::String result = Json::writeString(wb, root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+ {
+ // Array members do not exceed 21 print effects to render a single line
+ const Json::String expected("[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]");
+ Json::Value root;
+ for (Json::ArrayIndex i = 0; i < 10; i++)
+ root[i] = i;
+ const Json::String result = Json::writeString(wb, root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, dropNullPlaceholders) {
+ Json::StreamWriterBuilder b;
+ Json::Value nullValue;
+ b.settings_["dropNullPlaceholders"] = false;
+ JSONTEST_ASSERT(Json::writeString(b, nullValue) == "null");
+ b.settings_["dropNullPlaceholders"] = true;
+ JSONTEST_ASSERT(Json::writeString(b, nullValue).empty());
+}
+
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, enableYAMLCompatibility) {
+ Json::StreamWriterBuilder b;
+ Json::Value root;
+ root["hello"] = "world";
+
+ b.settings_["indentation"] = "";
+ JSONTEST_ASSERT(Json::writeString(b, root) == "{\"hello\":\"world\"}");
+
+ b.settings_["enableYAMLCompatibility"] = true;
+ JSONTEST_ASSERT(Json::writeString(b, root) == "{\"hello\": \"world\"}");
+
+ b.settings_["enableYAMLCompatibility"] = false;
+ JSONTEST_ASSERT(Json::writeString(b, root) == "{\"hello\":\"world\"}");
+}
+
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, indentation) {
+ Json::StreamWriterBuilder b;
+ Json::Value root;
+ root["hello"] = "world";
+
+ b.settings_["indentation"] = "";
+ JSONTEST_ASSERT(Json::writeString(b, root) == "{\"hello\":\"world\"}");
+
+ b.settings_["indentation"] = "\t";
+ JSONTEST_ASSERT(Json::writeString(b, root) ==
+ "{\n\t\"hello\" : \"world\"\n}");
+}
+
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, writeZeroes) {
+ Json::String binary("hi", 3); // include trailing 0
+ JSONTEST_ASSERT_EQUAL(3, binary.length());
+ Json::String expected(R"("hi\u0000")"); // unicoded zero
+ Json::StreamWriterBuilder b;
+ {
+ Json::Value root;
+ root = binary;
+ JSONTEST_ASSERT_STRING_EQUAL(binary, root.asString());
+ Json::String out = Json::writeString(b, root);
+ JSONTEST_ASSERT_EQUAL(expected.size(), out.size());
+ JSONTEST_ASSERT_STRING_EQUAL(expected, out);
+ }
+ {
+ Json::Value root;
+ root["top"] = binary;
+ JSONTEST_ASSERT_STRING_EQUAL(binary, root["top"].asString());
+ Json::String out = Json::writeString(b, root["top"]);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, out);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, unicode) {
+ // Create a Json value containing UTF-8 string with some chars that need
+ // escape (tab,newline).
+ Json::Value root;
+ root["test"] = "\t\n\xF0\x91\xA2\xA1\x3D\xC4\xB3\xF0\x9B\x84\x9B\xEF\xBD\xA7";
+
+ Json::StreamWriterBuilder b;
+
+ // Default settings - should be unicode escaped.
+ JSONTEST_ASSERT(Json::writeString(b, root) ==
+ "{\n\t\"test\" : "
+ "\"\\t\\n\\ud806\\udca1=\\u0133\\ud82c\\udd1b\\uff67\"\n}");
+
+ b.settings_["emitUTF8"] = true;
+
+ // Should not be unicode escaped.
+ JSONTEST_ASSERT(
+ Json::writeString(b, root) ==
+ "{\n\t\"test\" : "
+ "\"\\t\\n\xF0\x91\xA2\xA1=\xC4\xB3\xF0\x9B\x84\x9B\xEF\xBD\xA7\"\n}");
+
+ b.settings_["emitUTF8"] = false;
+
+ // Should be unicode escaped.
+ JSONTEST_ASSERT(Json::writeString(b, root) ==
+ "{\n\t\"test\" : "
+ "\"\\t\\n\\ud806\\udca1=\\u0133\\ud82c\\udd1b\\uff67\"\n}");
+}
+
+// Control chars should be escaped regardless of UTF-8 input encoding.
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, escapeControlCharacters) {
+ auto uEscape = [](unsigned ch) {
+ static const char h[] = "0123456789abcdef";
+ std::string r = "\\u";
+ r += h[(ch >> (3 * 4)) & 0xf];
+ r += h[(ch >> (2 * 4)) & 0xf];
+ r += h[(ch >> (1 * 4)) & 0xf];
+ r += h[(ch >> (0 * 4)) & 0xf];
+ return r;
+ };
+ auto shortEscape = [](unsigned ch) -> const char* {
+ switch (ch) {
+ case '\"':
+ return "\\\"";
+ case '\\':
+ return "\\\\";
+ case '\b':
+ return "\\b";
+ case '\f':
+ return "\\f";
+ case '\n':
+ return "\\n";
+ case '\r':
+ return "\\r";
+ case '\t':
+ return "\\t";
+ default:
+ return nullptr;
+ }
+ };
+
+ Json::StreamWriterBuilder b;
+
+ for (bool emitUTF8 : {true, false}) {
+ b.settings_["emitUTF8"] = emitUTF8;
+
+ for (unsigned i = 0; i != 0x100; ++i) {
+ if (!emitUTF8 && i >= 0x80)
+ break; // The algorithm would try to parse UTF-8, so stop here.
+
+ std::string raw({static_cast<char>(i)});
+ std::string esc = raw;
+ if (i < 0x20)
+ esc = uEscape(i);
+ if (const char* shEsc = shortEscape(i))
+ esc = shEsc;
+
+ // std::cout << "emit=" << emitUTF8 << ", i=" << std::hex << i << std::dec
+ // << std::endl;
+
+ Json::Value root;
+ root["test"] = raw;
+ JSONTEST_ASSERT_STRING_EQUAL(
+ std::string("{\n\t\"test\" : \"").append(esc).append("\"\n}"),
+ Json::writeString(b, root))
+ << ", emit=" << emitUTF8 << ", i=" << i << ", raw=\"" << raw << "\""
+ << ", esc=\"" << esc << "\"";
+ }
+ }
+}
+
+#ifdef _WIN32
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, escapeTabCharacterWindows) {
+ // Get the current locale before changing it
+ std::string currentLocale = setlocale(LC_ALL, NULL);
+ setlocale(LC_ALL, "English_United States.1252");
+
+ Json::Value root;
+ root["test"] = "\tTabTesting\t";
+
+ Json::StreamWriterBuilder b;
+
+ JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : "
+ "\"\\tTabTesting\\t\"\n}");
+
+ b.settings_["emitUTF8"] = true;
+ JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : "
+ "\"\\tTabTesting\\t\"\n}");
+
+ b.settings_["emitUTF8"] = false;
+ JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : "
+ "\"\\tTabTesting\\t\"\n}");
+
+ // Restore the locale
+ if (!currentLocale.empty())
+ setlocale(LC_ALL, currentLocale.c_str());
+}
+#endif
+
+struct ReaderTest : JsonTest::TestCase {
+ void setStrictMode() {
+ reader = std::unique_ptr<Json::Reader>(
+ new Json::Reader(Json::Features{}.strictMode()));
+ }
+
+ void setFeatures(Json::Features& features) {
+ reader = std::unique_ptr<Json::Reader>(new Json::Reader(features));
+ }
+
+ void checkStructuredErrors(
+ const std::vector<Json::Reader::StructuredError>& actual,
+ const std::vector<Json::Reader::StructuredError>& expected) {
+ JSONTEST_ASSERT_EQUAL(expected.size(), actual.size());
+ for (size_t i = 0; i < actual.size(); ++i) {
+ const auto& a = actual[i];
+ const auto& e = expected[i];
+ JSONTEST_ASSERT_EQUAL(e.offset_start, a.offset_start) << i;
+ JSONTEST_ASSERT_EQUAL(e.offset_limit, a.offset_limit) << i;
+ JSONTEST_ASSERT_EQUAL(e.message, a.message) << i;
+ }
+ }
+
+ template <typename Input> void checkParse(Input&& input) {
+ JSONTEST_ASSERT(reader->parse(input, root));
+ }
+
+ template <typename Input>
+ void
+ checkParse(Input&& input,
+ const std::vector<Json::Reader::StructuredError>& structured) {
+ JSONTEST_ASSERT(!reader->parse(input, root));
+ checkStructuredErrors(reader->getStructuredErrors(), structured);
+ }
+
+ template <typename Input>
+ void checkParse(Input&& input,
+ const std::vector<Json::Reader::StructuredError>& structured,
+ const std::string& formatted) {
+ checkParse(input, structured);
+ JSONTEST_ASSERT_EQUAL(formatted, reader->getFormattedErrorMessages());
+ }
+
+ std::unique_ptr<Json::Reader> reader{new Json::Reader()};
+ Json::Value root;
+};
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrors) {
+ checkParse(R"({ "property" : "value" })");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseObject) {
+ checkParse(R"({"property"})",
+ {{11, 12, "Missing ':' after object member name"}},
+ "* Line 1, Column 12\n Missing ':' after object member name\n");
+ checkParse(
+ R"({"property" : "value" )",
+ {{22, 22, "Missing ',' or '}' in object declaration"}},
+ "* Line 1, Column 23\n Missing ',' or '}' in object declaration\n");
+ checkParse(R"({"property" : "value", )",
+ {{23, 23, "Missing '}' or object member name"}},
+ "* Line 1, Column 24\n Missing '}' or object member name\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseArray) {
+ checkParse(
+ R"([ "value" )", {{10, 10, "Missing ',' or ']' in array declaration"}},
+ "* Line 1, Column 11\n Missing ',' or ']' in array declaration\n");
+ checkParse(
+ R"([ "value1" "value2" ] )",
+ {{11, 19, "Missing ',' or ']' in array declaration"}},
+ "* Line 1, Column 12\n Missing ',' or ']' in array declaration\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) {
+ checkParse(R"([ "\u8a2a" ])");
+ checkParse(
+ R"([ "\ud801" ])",
+ {{2, 10,
+ "additional six characters expected to parse unicode surrogate "
+ "pair."}},
+ "* Line 1, Column 3\n"
+ " additional six characters expected to parse unicode surrogate pair.\n"
+ "See Line 1, Column 10 for detail.\n");
+ checkParse(R"([ "\ud801\d1234" ])",
+ {{2, 16,
+ "expecting another \\u token to begin the "
+ "second half of a unicode surrogate pair"}},
+ "* Line 1, Column 3\n"
+ " expecting another \\u token to begin the "
+ "second half of a unicode surrogate pair\n"
+ "See Line 1, Column 12 for detail.\n");
+ checkParse(R"([ "\ua3t@" ])",
+ {{2, 10,
+ "Bad unicode escape sequence in string: "
+ "hexadecimal digit expected."}},
+ "* Line 1, Column 3\n"
+ " Bad unicode escape sequence in string: "
+ "hexadecimal digit expected.\n"
+ "See Line 1, Column 9 for detail.\n");
+ checkParse(
+ R"([ "\ua3t" ])",
+ {{2, 9, "Bad unicode escape sequence in string: four digits expected."}},
+ "* Line 1, Column 3\n"
+ " Bad unicode escape sequence in string: four digits expected.\n"
+ "See Line 1, Column 6 for detail.\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseComment) {
+ checkParse(
+ R"({ /*commentBeforeValue*/ "property" : "value" }//commentAfterValue)"
+ "\n");
+ checkParse(" true //comment1\n//comment2\r//comment3\r\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, streamParseWithNoErrors) {
+ std::string styled = R"({ "property" : "value" })";
+ std::istringstream iss(styled);
+ checkParse(iss);
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrorsTestingOffsets) {
+ checkParse(R"({)"
+ R"( "property" : ["value", "value2"],)"
+ R"( "obj" : { "nested" : -6.2e+15, "bool" : true},)"
+ R"( "null" : null,)"
+ R"( "false" : false)"
+ R"( })");
+ auto checkOffsets = [&](const Json::Value& v, int start, int limit) {
+ JSONTEST_ASSERT_EQUAL(start, v.getOffsetStart());
+ JSONTEST_ASSERT_EQUAL(limit, v.getOffsetLimit());
+ };
+ checkOffsets(root, 0, 115);
+ checkOffsets(root["property"], 15, 34);
+ checkOffsets(root["property"][0], 16, 23);
+ checkOffsets(root["property"][1], 25, 33);
+ checkOffsets(root["obj"], 44, 81);
+ checkOffsets(root["obj"]["nested"], 57, 65);
+ checkOffsets(root["obj"]["bool"], 76, 80);
+ checkOffsets(root["null"], 92, 96);
+ checkOffsets(root["false"], 108, 113);
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithOneError) {
+ checkParse(R"({ "property" :: "value" })",
+ {{14, 15, "Syntax error: value, object or array expected."}},
+ "* Line 1, Column 15\n Syntax error: value, object or array "
+ "expected.\n");
+ checkParse("s", {{0, 1, "Syntax error: value, object or array expected."}},
+ "* Line 1, Column 1\n Syntax error: value, object or array "
+ "expected.\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseSpecialFloat) {
+ checkParse(R"({ "a" : Infi })",
+ {{8, 9, "Syntax error: value, object or array expected."}},
+ "* Line 1, Column 9\n Syntax error: value, object or array "
+ "expected.\n");
+ checkParse(R"({ "a" : Infiniaa })",
+ {{8, 9, "Syntax error: value, object or array expected."}},
+ "* Line 1, Column 9\n Syntax error: value, object or array "
+ "expected.\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, strictModeParseNumber) {
+ setStrictMode();
+ checkParse(
+ "123",
+ {{0, 3,
+ "A valid JSON document must be either an array or an object value."}},
+ "* Line 1, Column 1\n"
+ " A valid JSON document must be either an array or an object value.\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseChineseWithOneError) {
+ checkParse(R"({ "pr)"
+ u8"\u4f50\u85e4" // 佐藤
+ R"(erty" :: "value" })",
+ {{18, 19, "Syntax error: value, object or array expected."}},
+ "* Line 1, Column 19\n Syntax error: value, object or array "
+ "expected.\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithDetailError) {
+ checkParse(R"({ "property" : "v\alue" })",
+ {{15, 23, "Bad escape sequence in string"}},
+ "* Line 1, Column 16\n"
+ " Bad escape sequence in string\n"
+ "See Line 1, Column 20 for detail.\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, pushErrorTest) {
+ checkParse(R"({ "AUTHOR" : 123 })");
+ if (!root["AUTHOR"].isString()) {
+ JSONTEST_ASSERT(
+ reader->pushError(root["AUTHOR"], "AUTHOR must be a string"));
+ }
+ JSONTEST_ASSERT_STRING_EQUAL(reader->getFormattedErrorMessages(),
+ "* Line 1, Column 14\n"
+ " AUTHOR must be a string\n");
+
+ checkParse(R"({ "AUTHOR" : 123 })");
+ if (!root["AUTHOR"].isString()) {
+ JSONTEST_ASSERT(reader->pushError(root["AUTHOR"], "AUTHOR must be a string",
+ root["AUTHOR"]));
+ }
+ JSONTEST_ASSERT_STRING_EQUAL(reader->getFormattedErrorMessages(),
+ "* Line 1, Column 14\n"
+ " AUTHOR must be a string\n"
+ "See Line 1, Column 14 for detail.\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, allowNumericKeysTest) {
+ Json::Features features;
+ features.allowNumericKeys_ = true;
+ setFeatures(features);
+ checkParse(R"({ 123 : "abc" })");
+}
+
+struct CharReaderTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
Json::Value root;
- bool ok = reader.parse("{ \"property\" : \"value\" }", root);
+ char const doc[] = R"({ "property" : "value" })";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
- JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0);
+ JSONTEST_ASSERT(errs.empty());
}
-JSONTEST_FIXTURE(ReaderTest, parseWithNoErrorsTestingOffsets) {
- Json::Reader reader;
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrorsTestingOffsets) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
Json::Value root;
- bool ok = reader.parse("{ \"property\" : [\"value\", \"value2\"], \"obj\" : "
- "{ \"nested\" : 123, \"bool\" : true}, \"null\" : "
- "null, \"false\" : false }",
- root);
+ char const doc[] = "{ \"property\" : [\"value\", \"value2\"], \"obj\" : "
+ "{ \"nested\" : -6.2e+15, \"num\" : +123, \"bool\" : "
+ "true}, \"null\" : null, \"false\" : false }";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages().size() == 0);
- JSONTEST_ASSERT(reader.getStructuredErrors().size() == 0);
- JSONTEST_ASSERT(root["property"].getOffsetStart() == 15);
- JSONTEST_ASSERT(root["property"].getOffsetLimit() == 34);
- JSONTEST_ASSERT(root["property"][0].getOffsetStart() == 16);
- JSONTEST_ASSERT(root["property"][0].getOffsetLimit() == 23);
- JSONTEST_ASSERT(root["property"][1].getOffsetStart() == 25);
- JSONTEST_ASSERT(root["property"][1].getOffsetLimit() == 33);
- JSONTEST_ASSERT(root["obj"].getOffsetStart() == 44);
- JSONTEST_ASSERT(root["obj"].getOffsetLimit() == 76);
- JSONTEST_ASSERT(root["obj"]["nested"].getOffsetStart() == 57);
- JSONTEST_ASSERT(root["obj"]["nested"].getOffsetLimit() == 60);
- JSONTEST_ASSERT(root["obj"]["bool"].getOffsetStart() == 71);
- JSONTEST_ASSERT(root["obj"]["bool"].getOffsetLimit() == 75);
- JSONTEST_ASSERT(root["null"].getOffsetStart() == 87);
- JSONTEST_ASSERT(root["null"].getOffsetLimit() == 91);
- JSONTEST_ASSERT(root["false"].getOffsetStart() == 103);
- JSONTEST_ASSERT(root["false"].getOffsetLimit() == 108);
- JSONTEST_ASSERT(root.getOffsetStart() == 0);
- JSONTEST_ASSERT(root.getOffsetLimit() == 110);
-}
-
-JSONTEST_FIXTURE(ReaderTest, parseWithOneError) {
- Json::Reader reader;
+ JSONTEST_ASSERT(errs.empty());
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseNumber) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ Json::Value root;
+ {
+ // if intvalue > threshold, treat the number as a double.
+ // 21 digits
+ char const doc[] = "[111111111111111111111]";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL(1.1111111111111111e+020, root[0]);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ Json::String errs;
+ {
+ char const doc[] = "[\"\"]";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL("", root[0]);
+ }
+ {
+ char const doc[] = R"(["\u8A2a"])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL(u8"\u8A2a", root[0].asString()); // "訪"
+ }
+ {
+ char const doc[] = R"([ "\uD801" ])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
+ " additional six characters expected to "
+ "parse unicode surrogate pair.\n"
+ "See Line 1, Column 10 for detail.\n");
+ }
+ {
+ char const doc[] = R"([ "\uD801\d1234" ])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
+ " expecting another \\u token to begin the "
+ "second half of a unicode surrogate pair\n"
+ "See Line 1, Column 12 for detail.\n");
+ }
+ {
+ char const doc[] = R"([ "\ua3t@" ])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
+ " Bad unicode escape sequence in string: "
+ "hexadecimal digit expected.\n"
+ "See Line 1, Column 9 for detail.\n");
+ }
+ {
+ char const doc[] = R"([ "\ua3t" ])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(
+ errs ==
+ "* Line 1, Column 3\n"
+ " Bad unicode escape sequence in string: four digits expected.\n"
+ "See Line 1, Column 6 for detail.\n");
+ }
+ {
+ b.settings_["allowSingleQuotes"] = true;
+ CharReaderPtr charreader(b.newCharReader());
+ char const doc[] = R"({'a': 'x\ty', "b":'x\\y'})";
+ bool ok = charreader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(2u, root.size());
+ JSONTEST_ASSERT_STRING_EQUAL("x\ty", root["a"].asString());
+ JSONTEST_ASSERT_STRING_EQUAL("x\\y", root["b"].asString());
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseComment) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ Json::String errs;
+ {
+ char const doc[] = "//comment1\n { //comment2\n \"property\" :"
+ " \"value\" //comment3\n } //comment4\n";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL("value", root["property"]);
+ }
+ {
+ char const doc[] = "{ \"property\" //comment\n : \"value\" }";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 14\n"
+ " Missing ':' after object member name\n");
+ }
+ {
+ char const doc[] = "//comment1\n [ //comment2\n \"value\" //comment3\n,"
+ " //comment4\n true //comment5\n ] //comment6\n";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL("value", root[0]);
+ JSONTEST_ASSERT_EQUAL(true, root[1]);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ Json::String errs;
+ {
+ char const doc[] = R"({ "property" : "value" )";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 24\n"
+ " Missing ',' or '}' in object declaration\n");
+ JSONTEST_ASSERT_EQUAL("value", root["property"]);
+ }
+ {
+ char const doc[] = R"({ "property" : "value" ,)";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 25\n"
+ " Missing '}' or object member name\n");
+ JSONTEST_ASSERT_EQUAL("value", root["property"]);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseArrayWithErrors) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
Json::Value root;
- bool ok = reader.parse("{ \"property\" :: \"value\" }", root);
+ Json::String errs;
+ {
+ char const doc[] = "[ \"value\" ";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 11\n"
+ " Missing ',' or ']' in array declaration\n");
+ JSONTEST_ASSERT_EQUAL("value", root[0]);
+ }
+ {
+ char const doc[] = R"([ "value1" "value2" ])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 12\n"
+ " Missing ',' or ']' in array declaration\n");
+ JSONTEST_ASSERT_EQUAL("value1", root[0]);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithOneError) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ Json::Value root;
+ char const doc[] = R"({ "property" :: "value" })";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
+ JSONTEST_ASSERT(errs ==
"* Line 1, Column 15\n Syntax error: value, object or array "
"expected.\n");
- std::vector<Json::Reader::StructuredError> errors =
- reader.getStructuredErrors();
- JSONTEST_ASSERT(errors.size() == 1);
- JSONTEST_ASSERT(errors.at(0).offset_start == 14);
- JSONTEST_ASSERT(errors.at(0).offset_limit == 15);
- JSONTEST_ASSERT(errors.at(0).message ==
- "Syntax error: value, object or array expected.");
}
-JSONTEST_FIXTURE(ReaderTest, parseChineseWithOneError) {
- Json::Reader reader;
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseChineseWithOneError) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
Json::Value root;
- bool ok = reader.parse("{ \"pr佐藤erty\" :: \"value\" }", root);
+ char const doc[] = "{ \"pr佐藤erty\" :: \"value\" }";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
+ JSONTEST_ASSERT(errs ==
"* Line 1, Column 19\n Syntax error: value, object or array "
"expected.\n");
- std::vector<Json::Reader::StructuredError> errors =
- reader.getStructuredErrors();
- JSONTEST_ASSERT(errors.size() == 1);
- JSONTEST_ASSERT(errors.at(0).offset_start == 18);
- JSONTEST_ASSERT(errors.at(0).offset_limit == 19);
- JSONTEST_ASSERT(errors.at(0).message ==
- "Syntax error: value, object or array expected.");
}
-JSONTEST_FIXTURE(ReaderTest, parseWithDetailError) {
- Json::Reader reader;
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
Json::Value root;
- bool ok = reader.parse("{ \"property\" : \"v\\alue\" }", root);
+ char const doc[] = R"({ "property" : "v\alue" })";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
+ JSONTEST_ASSERT(errs ==
"* Line 1, Column 16\n Bad escape sequence in string\nSee "
"Line 1, Column 20 for detail.\n");
- std::vector<Json::Reader::StructuredError> errors =
- reader.getStructuredErrors();
- JSONTEST_ASSERT(errors.size() == 1);
- JSONTEST_ASSERT(errors.at(0).offset_start == 15);
- JSONTEST_ASSERT(errors.at(0).offset_limit == 23);
- JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string");
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) {
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ char const doc[] = R"({ "property" : "value" })";
+ {
+ b.settings_["stackLimit"] = 2;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL("value", root["property"]);
+ }
+ {
+ b.settings_["stackLimit"] = 1;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ JSONTEST_ASSERT_THROWS(
+ reader->parse(doc, doc + std::strlen(doc), &root, &errs));
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, testOperator) {
+ const std::string styled = R"({ "property" : "value" })";
+ std::istringstream iss(styled);
+ Json::Value root;
+ iss >> root;
+ JSONTEST_ASSERT_EQUAL("value", root["property"]);
+}
+
+struct CharReaderStrictModeTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(CharReaderStrictModeTest, dupKeys) {
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ char const doc[] =
+ R"({ "property" : "value", "key" : "val1", "key" : "val2" })";
+ {
+ b.strictMode(&b.settings_);
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL("* Line 1, Column 41\n"
+ " Duplicate key: 'key'\n",
+ errs);
+ JSONTEST_ASSERT_EQUAL("val1", root["key"]); // so far
+ }
+}
+struct CharReaderFailIfExtraTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) {
+ // This is interpreted as a string value followed by a colon.
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ char const doc[] = R"( "property" : "value" })";
+ {
+ b.settings_["failIfExtra"] = false;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL("property", root);
+ }
+ {
+ b.settings_["failIfExtra"] = true;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL("* Line 1, Column 13\n"
+ " Extra non-whitespace after JSON value.\n",
+ errs);
+ JSONTEST_ASSERT_EQUAL("property", root);
+ }
+ {
+ b.strictMode(&b.settings_);
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL("* Line 1, Column 13\n"
+ " Extra non-whitespace after JSON value.\n",
+ errs);
+ JSONTEST_ASSERT_EQUAL("property", root);
+ }
+ {
+ b.strictMode(&b.settings_);
+ b.settings_["failIfExtra"] = false;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "* Line 1, Column 1\n"
+ " A valid JSON document must be either an array or an object value.\n",
+ errs);
+ JSONTEST_ASSERT_EQUAL("property", root);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue107) {
+ // This is interpreted as an int value followed by a colon.
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ char const doc[] = "1:2:3";
+ b.settings_["failIfExtra"] = true;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL("* Line 1, Column 2\n"
+ " Extra non-whitespace after JSON value.\n",
+ errs);
+ JSONTEST_ASSERT_EQUAL(1, root.asInt());
+}
+JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterObject) {
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ {
+ char const doc[] = "{ \"property\" : \"value\" } //trailing\n//comment\n";
+ b.settings_["failIfExtra"] = true;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL("value", root["property"]);
+ }
+}
+JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterArray) {
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ char const doc[] = "[ \"property\" , \"value\" ] //trailing\n//comment\n";
+ b.settings_["failIfExtra"] = true;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL("value", root[1u]);
+}
+JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterBool) {
+ Json::CharReaderBuilder b;
+ Json::Value root;
+ char const doc[] = " true /*trailing\ncomment*/";
+ b.settings_["failIfExtra"] = true;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(true, root.asBool());
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, parseComment) {
+ Json::CharReaderBuilder b;
+ b.settings_["failIfExtra"] = true;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ Json::String errs;
+ {
+ char const doc[] = " true //comment1\n//comment2\r//comment3\r\n";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(true, root.asBool());
+ }
+ {
+ char const doc[] = " true //com\rment";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL("* Line 2, Column 1\n"
+ " Extra non-whitespace after JSON value.\n",
+ errs);
+ JSONTEST_ASSERT_EQUAL(true, root.asBool());
+ }
+ {
+ char const doc[] = " true //com\nment";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL("* Line 2, Column 1\n"
+ " Extra non-whitespace after JSON value.\n",
+ errs);
+ JSONTEST_ASSERT_EQUAL(true, root.asBool());
+ }
+}
+
+struct CharReaderAllowDropNullTest : JsonTest::TestCase {
+ using Value = Json::Value;
+ using ValueCheck = std::function<void(const Value&)>;
+
+ Value nullValue = Value{Json::nullValue};
+ Value emptyArray = Value{Json::arrayValue};
+
+ ValueCheck checkEq(const Value& v) {
+ return [=](const Value& root) { JSONTEST_ASSERT_EQUAL(root, v); };
+ }
+
+ static ValueCheck objGetAnd(std::string idx, ValueCheck f) {
+ return [=](const Value& root) { f(root.get(idx, true)); };
+ }
+
+ static ValueCheck arrGetAnd(int idx, ValueCheck f) {
+ return [=](const Value& root) { f(root[idx]); };
+ }
+};
+
+JSONTEST_FIXTURE_LOCAL(CharReaderAllowDropNullTest, issue178) {
+ struct TestSpec {
+ int line;
+ std::string doc;
+ size_t rootSize;
+ ValueCheck onRoot;
+ };
+ const TestSpec specs[] = {
+ {__LINE__, R"({"a":,"b":true})", 2, objGetAnd("a", checkEq(nullValue))},
+ {__LINE__, R"({"a":,"b":true})", 2, objGetAnd("a", checkEq(nullValue))},
+ {__LINE__, R"({"a":})", 1, objGetAnd("a", checkEq(nullValue))},
+ {__LINE__, "[]", 0, checkEq(emptyArray)},
+ {__LINE__, "[null]", 1, nullptr},
+ {__LINE__, "[,]", 2, nullptr},
+ {__LINE__, "[,,,]", 4, nullptr},
+ {__LINE__, "[null,]", 2, nullptr},
+ {__LINE__, "[,null]", 2, nullptr},
+ {__LINE__, "[,,]", 3, nullptr},
+ {__LINE__, "[null,,]", 3, nullptr},
+ {__LINE__, "[,null,]", 3, nullptr},
+ {__LINE__, "[,,null]", 3, nullptr},
+ {__LINE__, "[[],,,]", 4, arrGetAnd(0, checkEq(emptyArray))},
+ {__LINE__, "[,[],,]", 4, arrGetAnd(1, checkEq(emptyArray))},
+ {__LINE__, "[,,,[]]", 4, arrGetAnd(3, checkEq(emptyArray))},
+ };
+ for (const auto& spec : specs) {
+ Json::CharReaderBuilder b;
+ b.settings_["allowDroppedNullPlaceholders"] = true;
+ std::unique_ptr<Json::CharReader> reader(b.newCharReader());
+
+ Json::Value root;
+ Json::String errs;
+ bool ok = reader->parse(spec.doc.data(), spec.doc.data() + spec.doc.size(),
+ &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL(errs, "");
+ if (spec.onRoot) {
+ spec.onRoot(root);
+ }
+ }
+}
+
+struct CharReaderAllowNumericKeysTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(CharReaderAllowNumericKeysTest, allowNumericKeys) {
+ Json::CharReaderBuilder b;
+ b.settings_["allowNumericKeys"] = true;
+ Json::Value root;
+ Json::String errs;
+ CharReaderPtr reader(b.newCharReader());
+ char const doc[] = "{15:true,-16:true,12.01:true}";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(3u, root.size());
+ JSONTEST_ASSERT_EQUAL(true, root.get("15", false));
+ JSONTEST_ASSERT_EQUAL(true, root.get("-16", false));
+ JSONTEST_ASSERT_EQUAL(true, root.get("12.01", false));
+}
+
+struct CharReaderAllowSingleQuotesTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(CharReaderAllowSingleQuotesTest, issue182) {
+ Json::CharReaderBuilder b;
+ b.settings_["allowSingleQuotes"] = true;
+ Json::Value root;
+ Json::String errs;
+ CharReaderPtr reader(b.newCharReader());
+ {
+ char const doc[] = "{'a':true,\"b\":true}";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(2u, root.size());
+ JSONTEST_ASSERT_EQUAL(true, root.get("a", false));
+ JSONTEST_ASSERT_EQUAL(true, root.get("b", false));
+ }
+ {
+ char const doc[] = "{'a': 'x', \"b\":'y'}";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(2u, root.size());
+ JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString());
+ JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString());
+ }
+}
+
+struct CharReaderAllowZeroesTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(CharReaderAllowZeroesTest, issue176) {
+ Json::CharReaderBuilder b;
+ b.settings_["allowSingleQuotes"] = true;
+ Json::Value root;
+ Json::String errs;
+ CharReaderPtr reader(b.newCharReader());
+ {
+ char const doc[] = "{'a':true,\"b\":true}";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(2u, root.size());
+ JSONTEST_ASSERT_EQUAL(true, root.get("a", false));
+ JSONTEST_ASSERT_EQUAL(true, root.get("b", false));
+ }
+ {
+ char const doc[] = "{'a': 'x', \"b\":'y'}";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(2u, root.size());
+ JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString());
+ JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString());
+ }
+}
+
+struct CharReaderAllowSpecialFloatsTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, specialFloat) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ Json::String errs;
+ {
+ char const doc[] = "{\"a\": NaN}";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "* Line 1, Column 7\n"
+ " Syntax error: value, object or array expected.\n",
+ errs);
+ }
+ {
+ char const doc[] = "{\"a\": Infinity}";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "* Line 1, Column 7\n"
+ " Syntax error: value, object or array expected.\n",
+ errs);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
+ Json::CharReaderBuilder b;
+ b.settings_["allowSpecialFloats"] = true;
+ Json::Value root;
+ Json::String errs;
+ CharReaderPtr reader(b.newCharReader());
+ {
+ char const doc[] = R"({"a":NaN,"b":Infinity,"c":-Infinity,"d":+Infinity})";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(4u, root.size());
+ double n = root["a"].asDouble();
+ JSONTEST_ASSERT(std::isnan(n));
+ JSONTEST_ASSERT_EQUAL(std::numeric_limits<double>::infinity(),
+ root.get("b", 0.0));
+ JSONTEST_ASSERT_EQUAL(-std::numeric_limits<double>::infinity(),
+ root.get("c", 0.0));
+ JSONTEST_ASSERT_EQUAL(std::numeric_limits<double>::infinity(),
+ root.get("d", 0.0));
+ }
+
+ struct TestData {
+ int line;
+ bool ok;
+ Json::String in;
+ };
+ const TestData test_data[] = {
+ {__LINE__, true, "{\"a\":9}"}, //
+ {__LINE__, false, "{\"a\":0Infinity}"}, //
+ {__LINE__, false, "{\"a\":1Infinity}"}, //
+ {__LINE__, false, "{\"a\":9Infinity}"}, //
+ {__LINE__, false, "{\"a\":0nfinity}"}, //
+ {__LINE__, false, "{\"a\":1nfinity}"}, //
+ {__LINE__, false, "{\"a\":9nfinity}"}, //
+ {__LINE__, false, "{\"a\":nfinity}"}, //
+ {__LINE__, false, "{\"a\":.nfinity}"}, //
+ {__LINE__, false, "{\"a\":9nfinity}"}, //
+ {__LINE__, false, "{\"a\":-nfinity}"}, //
+ {__LINE__, true, "{\"a\":Infinity}"}, //
+ {__LINE__, false, "{\"a\":.Infinity}"}, //
+ {__LINE__, false, "{\"a\":_Infinity}"}, //
+ {__LINE__, false, "{\"a\":_nfinity}"}, //
+ {__LINE__, true, "{\"a\":-Infinity}"}, //
+ {__LINE__, true, "{\"a\":+Infinity}"} //
+ };
+ for (const auto& td : test_data) {
+ bool ok = reader->parse(&*td.in.begin(), &*td.in.begin() + td.in.size(),
+ &root, &errs);
+ JSONTEST_ASSERT(td.ok == ok) << "line:" << td.line << "\n"
+ << " expected: {"
+ << "ok:" << td.ok << ", in:\'" << td.in << "\'"
+ << "}\n"
+ << " actual: {"
+ << "ok:" << ok << "}\n";
+ }
+
+ {
+ char const doc[] = R"({"posInf": +Infinity, "NegInf": -Infinity})";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(2u, root.size());
+ JSONTEST_ASSERT_EQUAL(std::numeric_limits<double>::infinity(),
+ root["posInf"].asDouble());
+ JSONTEST_ASSERT_EQUAL(-std::numeric_limits<double>::infinity(),
+ root["NegInf"].asDouble());
+ }
+}
+
+struct EscapeSequenceTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, readerParseEscapeSequence) {
+ Json::Reader reader;
+ Json::Value root;
+ bool ok = reader.parse("[\"\\\"\",\"\\/\",\"\\\\\",\"\\b\","
+ "\"\\f\",\"\\n\",\"\\r\",\"\\t\","
+ "\"\\u0278\",\"\\ud852\\udf62\"]\n",
+ root);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(reader.getFormattedErrorMessages().empty());
+ JSONTEST_ASSERT(reader.getStructuredErrors().empty());
+}
+
+JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, charReaderParseEscapeSequence) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ Json::String errs;
+ char const doc[] = "[\"\\\"\",\"\\/\",\"\\\\\",\"\\b\","
+ "\"\\f\",\"\\n\",\"\\r\",\"\\t\","
+ "\"\\u0278\",\"\\ud852\\udf62\"]";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+}
+
+JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, writeEscapeSequence) {
+ Json::FastWriter writer;
+ const Json::String expected("[\"\\\"\",\"\\\\\",\"\\b\","
+ "\"\\f\",\"\\n\",\"\\r\",\"\\t\","
+ "\"\\u0278\",\"\\ud852\\udf62\"]\n");
+ Json::Value root;
+ root[0] = "\"";
+ root[1] = "\\";
+ root[2] = "\b";
+ root[3] = "\f";
+ root[4] = "\n";
+ root[5] = "\r";
+ root[6] = "\t";
+ root[7] = "ɸ";
+ root[8] = "𤭢";
+ const Json::String result = writer.write(root);
+ JSONTEST_ASSERT_STRING_EQUAL(expected, result);
+}
+
+struct BuilderTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(BuilderTest, settings) {
+ {
+ Json::Value errs;
+ Json::CharReaderBuilder rb;
+ JSONTEST_ASSERT_EQUAL(false, rb.settings_.isMember("foo"));
+ JSONTEST_ASSERT_EQUAL(true, rb.validate(&errs));
+ rb["foo"] = "bar";
+ JSONTEST_ASSERT_EQUAL(true, rb.settings_.isMember("foo"));
+ JSONTEST_ASSERT_EQUAL(false, rb.validate(&errs));
+ }
+ {
+ Json::Value errs;
+ Json::StreamWriterBuilder wb;
+ JSONTEST_ASSERT_EQUAL(false, wb.settings_.isMember("foo"));
+ JSONTEST_ASSERT_EQUAL(true, wb.validate(&errs));
+ wb["foo"] = "bar";
+ JSONTEST_ASSERT_EQUAL(true, wb.settings_.isMember("foo"));
+ JSONTEST_ASSERT_EQUAL(false, wb.validate(&errs));
+ }
+}
+
+struct BomTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(BomTest, skipBom) {
+ const std::string with_bom = "\xEF\xBB\xBF{\"key\" : \"value\"}";
+ Json::Value root;
+ JSONCPP_STRING errs;
+ std::istringstream iss(with_bom);
+ bool ok = parseFromStream(Json::CharReaderBuilder(), iss, &root, &errs);
+ // The default behavior is to skip the BOM, so we can parse it normally.
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_STRING_EQUAL(root["key"].asString(), "value");
+}
+JSONTEST_FIXTURE_LOCAL(BomTest, notSkipBom) {
+ const std::string with_bom = "\xEF\xBB\xBF{\"key\" : \"value\"}";
+ Json::Value root;
+ JSONCPP_STRING errs;
+ std::istringstream iss(with_bom);
+ Json::CharReaderBuilder b;
+ b.settings_["skipBom"] = false;
+ bool ok = parseFromStream(b, iss, &root, &errs);
+ // Detect the BOM, and failed on it.
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(!errs.empty());
+}
+
+struct IteratorTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(IteratorTest, convert) {
+ Json::Value j;
+ const Json::Value& cj = j;
+ auto it = j.begin();
+ Json::Value::const_iterator cit;
+ cit = it;
+ JSONTEST_ASSERT(cit == cj.begin());
+}
+
+JSONTEST_FIXTURE_LOCAL(IteratorTest, decrement) {
+ Json::Value json;
+ json["k1"] = "a";
+ json["k2"] = "b";
+ std::vector<std::string> values;
+ for (auto it = json.end(); it != json.begin();) {
+ --it;
+ values.push_back(it->asString());
+ }
+ JSONTEST_ASSERT((values == std::vector<std::string>{"b", "a"}));
+}
+
+JSONTEST_FIXTURE_LOCAL(IteratorTest, reverseIterator) {
+ Json::Value json;
+ json["k1"] = "a";
+ json["k2"] = "b";
+ std::vector<std::string> values;
+ using Iter = decltype(json.begin());
+ auto re = std::reverse_iterator<Iter>(json.begin());
+ for (auto it = std::reverse_iterator<Iter>(json.end()); it != re; ++it) {
+ values.push_back(it->asString());
+ }
+ JSONTEST_ASSERT((values == std::vector<std::string>{"b", "a"}));
+}
+
+JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) {
+ {
+ Json::Value json;
+ json["k1"] = "a";
+ json["k2"] = "b";
+ int i = 0;
+ auto it = json.begin();
+ for (;; ++it, ++i) {
+ auto dist = it - json.begin();
+ JSONTEST_ASSERT_EQUAL(i, dist);
+ if (it == json.end())
+ break;
+ }
+ }
+ {
+ Json::Value empty;
+ JSONTEST_ASSERT_EQUAL(0, empty.end() - empty.end());
+ JSONTEST_ASSERT_EQUAL(0, empty.end() - empty.begin());
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(IteratorTest, nullValues) {
+ {
+ Json::Value json;
+ auto end = json.end();
+ auto endCopy = end;
+ JSONTEST_ASSERT(endCopy == end);
+ endCopy = end;
+ JSONTEST_ASSERT(endCopy == end);
+ }
+ {
+ // Same test, now with const Value.
+ const Json::Value json;
+ auto end = json.end();
+ auto endCopy = end;
+ JSONTEST_ASSERT(endCopy == end);
+ endCopy = end;
+ JSONTEST_ASSERT(endCopy == end);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(IteratorTest, staticStringKey) {
+ Json::Value json;
+ json[Json::StaticString("k1")] = "a";
+ JSONTEST_ASSERT_EQUAL(Json::Value("k1"), json.begin().key());
+}
+
+JSONTEST_FIXTURE_LOCAL(IteratorTest, names) {
+ Json::Value json;
+ json["k1"] = "a";
+ json["k2"] = "b";
+ Json::ValueIterator it = json.begin();
+ JSONTEST_ASSERT(it != json.end());
+ JSONTEST_ASSERT_EQUAL(Json::Value("k1"), it.key());
+ JSONTEST_ASSERT_STRING_EQUAL("k1", it.name());
+ JSONTEST_ASSERT_STRING_EQUAL("k1", it.memberName());
+ JSONTEST_ASSERT_EQUAL(-1, it.index());
+ ++it;
+ JSONTEST_ASSERT(it != json.end());
+ JSONTEST_ASSERT_EQUAL(Json::Value("k2"), it.key());
+ JSONTEST_ASSERT_STRING_EQUAL("k2", it.name());
+ JSONTEST_ASSERT_STRING_EQUAL("k2", it.memberName());
+ JSONTEST_ASSERT_EQUAL(-1, it.index());
+ ++it;
+ JSONTEST_ASSERT(it == json.end());
+}
+
+JSONTEST_FIXTURE_LOCAL(IteratorTest, indexes) {
+ Json::Value json;
+ json[0] = "a";
+ json[1] = "b";
+ Json::ValueIterator it = json.begin();
+ JSONTEST_ASSERT(it != json.end());
+ JSONTEST_ASSERT_EQUAL(Json::Value(Json::ArrayIndex(0)), it.key());
+ JSONTEST_ASSERT_STRING_EQUAL("", it.name());
+ JSONTEST_ASSERT_EQUAL(0, it.index());
+ ++it;
+ JSONTEST_ASSERT(it != json.end());
+ JSONTEST_ASSERT_EQUAL(Json::Value(Json::ArrayIndex(1)), it.key());
+ JSONTEST_ASSERT_STRING_EQUAL("", it.name());
+ JSONTEST_ASSERT_EQUAL(1, it.index());
+ ++it;
+ JSONTEST_ASSERT(it == json.end());
+}
+
+JSONTEST_FIXTURE_LOCAL(IteratorTest, constness) {
+ Json::Value const v;
+ JSONTEST_ASSERT_THROWS(
+ Json::Value::iterator it(v.begin())); // Compile, but throw.
+
+ Json::Value value;
+
+ for (int i = 9; i < 12; ++i) {
+ Json::OStringStream out;
+ out << std::setw(2) << i;
+ Json::String str = out.str();
+ value[str] = str;
+ }
+
+ Json::OStringStream out;
+ // in old code, this will get a compile error
+ Json::Value::const_iterator iter = value.begin();
+ for (; iter != value.end(); ++iter) {
+ out << *iter << ',';
+ }
+ Json::String expected = R"(" 9","10","11",)";
+ JSONTEST_ASSERT_STRING_EQUAL(expected, out.str());
+}
+
+struct RValueTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(RValueTest, moveConstruction) {
+ Json::Value json;
+ json["key"] = "value";
+ Json::Value moved = std::move(json);
+ JSONTEST_ASSERT(moved != json); // Possibly not nullValue; definitely not
+ // equal.
+ JSONTEST_ASSERT_EQUAL(Json::objectValue, moved.type());
+ JSONTEST_ASSERT_EQUAL(Json::stringValue, moved["key"].type());
+}
+
+struct FuzzTest : JsonTest::TestCase {};
+
+// Build and run the fuzz test without any fuzzer, so that it's guaranteed not
+// go out of date, even if it's never run as an actual fuzz test.
+JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) {
+ const std::string example = "{}";
+ JSONTEST_ASSERT_EQUAL(
+ 0,
+ LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t*>(example.c_str()),
+ example.size()));
}
int main(int argc, const char* argv[]) {
JsonTest::Runner runner;
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, memberCount);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, objects);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, arrays);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, null);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, strings);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, bools);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, integers);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, nonIntegers);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareNull);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareInt);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareUInt);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareDouble);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareString);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareBoolean);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareArray);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareObject);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, compareType);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, offsetAccessors);
- JSONTEST_REGISTER_FIXTURE(runner, ValueTest, typeChecksThrowExceptions);
-
- JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithNoErrors);
- JSONTEST_REGISTER_FIXTURE(
- runner, ReaderTest, parseWithNoErrorsTestingOffsets);
- JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithOneError);
- JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseChineseWithOneError);
- JSONTEST_REGISTER_FIXTURE(runner, ReaderTest, parseWithDetailError);
-
- JSONTEST_REGISTER_FIXTURE(runner, WriterTest, dropNullPlaceholders);
+
+ for (auto& local : local_) {
+ runner.add(local);
+ }
return runner.runCommandLine(argc, argv);
}
+
+struct MemberTemplateAs : JsonTest::TestCase {
+ template <typename T, typename F>
+ JsonTest::TestResult& EqEval(T v, F f) const {
+ const Json::Value j = v;
+ return JSONTEST_ASSERT_EQUAL(j.as<T>(), f(j));
+ }
+};
+
+JSONTEST_FIXTURE_LOCAL(MemberTemplateAs, BehavesSameAsNamedAs) {
+ const Json::Value jstr = "hello world";
+ JSONTEST_ASSERT_STRING_EQUAL(jstr.as<const char*>(), jstr.asCString());
+ JSONTEST_ASSERT_STRING_EQUAL(jstr.as<Json::String>(), jstr.asString());
+ EqEval(Json::Int(64), [](const Json::Value& j) { return j.asInt(); });
+ EqEval(Json::UInt(64), [](const Json::Value& j) { return j.asUInt(); });
+#if defined(JSON_HAS_INT64)
+ EqEval(Json::Int64(64), [](const Json::Value& j) { return j.asInt64(); });
+ EqEval(Json::UInt64(64), [](const Json::Value& j) { return j.asUInt64(); });
+#endif // if defined(JSON_HAS_INT64)
+ EqEval(Json::LargestInt(64),
+ [](const Json::Value& j) { return j.asLargestInt(); });
+ EqEval(Json::LargestUInt(64),
+ [](const Json::Value& j) { return j.asLargestUInt(); });
+
+ EqEval(69.69f, [](const Json::Value& j) { return j.asFloat(); });
+ EqEval(69.69, [](const Json::Value& j) { return j.asDouble(); });
+ EqEval(false, [](const Json::Value& j) { return j.asBool(); });
+ EqEval(true, [](const Json::Value& j) { return j.asBool(); });
+}
+
+class MemberTemplateIs : public JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(MemberTemplateIs, BehavesSameAsNamedIs) {
+ const Json::Value values[] = {true, 142, 40.63, "hello world"};
+ for (const Json::Value& j : values) {
+ JSONTEST_ASSERT_EQUAL(j.is<bool>(), j.isBool());
+ JSONTEST_ASSERT_EQUAL(j.is<Json::Int>(), j.isInt());
+ JSONTEST_ASSERT_EQUAL(j.is<Json::Int64>(), j.isInt64());
+ JSONTEST_ASSERT_EQUAL(j.is<Json::UInt>(), j.isUInt());
+ JSONTEST_ASSERT_EQUAL(j.is<Json::UInt64>(), j.isUInt64());
+ JSONTEST_ASSERT_EQUAL(j.is<double>(), j.isDouble());
+ JSONTEST_ASSERT_EQUAL(j.is<Json::String>(), j.isString());
+ }
+}
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif