Files
rippled/src/test/json/json_value_test.cpp
2020-04-23 10:02:04 -07:00

1400 lines
56 KiB
C++

//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/beast/core/LexicalCast.h>
#include <ripple/beast/type_name.h>
#include <ripple/beast/unit_test.h>
#include <ripple/json/json_reader.h>
#include <ripple/json/json_value.h>
#include <ripple/json/json_writer.h>
#include <algorithm>
#include <regex>
namespace ripple {
struct json_value_test : beast::unit_test::suite
{
void
test_StaticString()
{
static constexpr char sample[]{"Contents of a Json::StaticString"};
static constexpr Json::StaticString test1(sample);
char const* addrTest1{test1};
BEAST_EXPECT(addrTest1 == &sample[0]);
BEAST_EXPECT(test1.c_str() == &sample[0]);
static constexpr Json::StaticString test2{
"Contents of a Json::StaticString"};
static constexpr Json::StaticString test3{"Another StaticString"};
BEAST_EXPECT(test1 == test2);
BEAST_EXPECT(test1 != test3);
std::string str{sample};
BEAST_EXPECT(str == test2);
BEAST_EXPECT(str != test3);
BEAST_EXPECT(test2 == str);
BEAST_EXPECT(test3 != str);
}
void
test_types()
{
// Exercise ValueType constructor
static constexpr Json::StaticString staticStr{"staticStr"};
auto testCopy = [this](Json::ValueType typ) {
Json::Value val{typ};
Json::Value cpy{val};
BEAST_EXPECT(val.type() == typ);
BEAST_EXPECT(cpy.type() == typ);
return val;
};
{
Json::Value const nullV{testCopy(Json::nullValue)};
BEAST_EXPECT(nullV.isNull());
BEAST_EXPECT(!nullV.isBool());
BEAST_EXPECT(!nullV.isInt());
BEAST_EXPECT(!nullV.isUInt());
BEAST_EXPECT(!nullV.isIntegral());
BEAST_EXPECT(!nullV.isDouble());
BEAST_EXPECT(!nullV.isNumeric());
BEAST_EXPECT(!nullV.isString());
BEAST_EXPECT(!nullV.isArray());
BEAST_EXPECT(nullV.isArrayOrNull());
BEAST_EXPECT(!nullV.isObject());
BEAST_EXPECT(nullV.isObjectOrNull());
}
{
Json::Value const intV{testCopy(Json::intValue)};
BEAST_EXPECT(!intV.isNull());
BEAST_EXPECT(!intV.isBool());
BEAST_EXPECT(intV.isInt());
BEAST_EXPECT(!intV.isUInt());
BEAST_EXPECT(intV.isIntegral());
BEAST_EXPECT(!intV.isDouble());
BEAST_EXPECT(intV.isNumeric());
BEAST_EXPECT(!intV.isString());
BEAST_EXPECT(!intV.isArray());
BEAST_EXPECT(!intV.isArrayOrNull());
BEAST_EXPECT(!intV.isObject());
BEAST_EXPECT(!intV.isObjectOrNull());
}
{
Json::Value const uintV{testCopy(Json::uintValue)};
BEAST_EXPECT(!uintV.isNull());
BEAST_EXPECT(!uintV.isBool());
BEAST_EXPECT(!uintV.isInt());
BEAST_EXPECT(uintV.isUInt());
BEAST_EXPECT(uintV.isIntegral());
BEAST_EXPECT(!uintV.isDouble());
BEAST_EXPECT(uintV.isNumeric());
BEAST_EXPECT(!uintV.isString());
BEAST_EXPECT(!uintV.isArray());
BEAST_EXPECT(!uintV.isArrayOrNull());
BEAST_EXPECT(!uintV.isObject());
BEAST_EXPECT(!uintV.isObjectOrNull());
}
{
Json::Value const realV{testCopy(Json::realValue)};
BEAST_EXPECT(!realV.isNull());
BEAST_EXPECT(!realV.isBool());
BEAST_EXPECT(!realV.isInt());
BEAST_EXPECT(!realV.isUInt());
BEAST_EXPECT(!realV.isIntegral());
BEAST_EXPECT(realV.isDouble());
BEAST_EXPECT(realV.isNumeric());
BEAST_EXPECT(!realV.isString());
BEAST_EXPECT(!realV.isArray());
BEAST_EXPECT(!realV.isArrayOrNull());
BEAST_EXPECT(!realV.isObject());
BEAST_EXPECT(!realV.isObjectOrNull());
}
{
Json::Value const stringV{testCopy(Json::stringValue)};
BEAST_EXPECT(!stringV.isNull());
BEAST_EXPECT(!stringV.isBool());
BEAST_EXPECT(!stringV.isInt());
BEAST_EXPECT(!stringV.isUInt());
BEAST_EXPECT(!stringV.isIntegral());
BEAST_EXPECT(!stringV.isDouble());
BEAST_EXPECT(!stringV.isNumeric());
BEAST_EXPECT(stringV.isString());
BEAST_EXPECT(!stringV.isArray());
BEAST_EXPECT(!stringV.isArrayOrNull());
BEAST_EXPECT(!stringV.isObject());
BEAST_EXPECT(!stringV.isObjectOrNull());
}
{
Json::Value const staticStrV{staticStr};
{
Json::Value cpy{staticStrV};
BEAST_EXPECT(staticStrV.type() == Json::stringValue);
BEAST_EXPECT(cpy.type() == Json::stringValue);
}
BEAST_EXPECT(!staticStrV.isNull());
BEAST_EXPECT(!staticStrV.isBool());
BEAST_EXPECT(!staticStrV.isInt());
BEAST_EXPECT(!staticStrV.isUInt());
BEAST_EXPECT(!staticStrV.isIntegral());
BEAST_EXPECT(!staticStrV.isDouble());
BEAST_EXPECT(!staticStrV.isNumeric());
BEAST_EXPECT(staticStrV.isString());
BEAST_EXPECT(!staticStrV.isArray());
BEAST_EXPECT(!staticStrV.isArrayOrNull());
BEAST_EXPECT(!staticStrV.isObject());
BEAST_EXPECT(!staticStrV.isObjectOrNull());
}
{
Json::Value const boolV{testCopy(Json::booleanValue)};
BEAST_EXPECT(!boolV.isNull());
BEAST_EXPECT(boolV.isBool());
BEAST_EXPECT(!boolV.isInt());
BEAST_EXPECT(!boolV.isUInt());
BEAST_EXPECT(boolV.isIntegral());
BEAST_EXPECT(!boolV.isDouble());
BEAST_EXPECT(boolV.isNumeric());
BEAST_EXPECT(!boolV.isString());
BEAST_EXPECT(!boolV.isArray());
BEAST_EXPECT(!boolV.isArrayOrNull());
BEAST_EXPECT(!boolV.isObject());
BEAST_EXPECT(!boolV.isObjectOrNull());
}
{
Json::Value const arrayV{testCopy(Json::arrayValue)};
BEAST_EXPECT(!arrayV.isNull());
BEAST_EXPECT(!arrayV.isBool());
BEAST_EXPECT(!arrayV.isInt());
BEAST_EXPECT(!arrayV.isUInt());
BEAST_EXPECT(!arrayV.isIntegral());
BEAST_EXPECT(!arrayV.isDouble());
BEAST_EXPECT(!arrayV.isNumeric());
BEAST_EXPECT(!arrayV.isString());
BEAST_EXPECT(arrayV.isArray());
BEAST_EXPECT(arrayV.isArrayOrNull());
BEAST_EXPECT(!arrayV.isObject());
BEAST_EXPECT(!arrayV.isObjectOrNull());
}
{
Json::Value const objectV{testCopy(Json::objectValue)};
BEAST_EXPECT(!objectV.isNull());
BEAST_EXPECT(!objectV.isBool());
BEAST_EXPECT(!objectV.isInt());
BEAST_EXPECT(!objectV.isUInt());
BEAST_EXPECT(!objectV.isIntegral());
BEAST_EXPECT(!objectV.isDouble());
BEAST_EXPECT(!objectV.isNumeric());
BEAST_EXPECT(!objectV.isString());
BEAST_EXPECT(!objectV.isArray());
BEAST_EXPECT(!objectV.isArrayOrNull());
BEAST_EXPECT(objectV.isObject());
BEAST_EXPECT(objectV.isObjectOrNull());
}
}
void
test_compare()
{
auto doCompare = [this](
Json::Value const& lhs,
Json::Value const& rhs,
bool lhsEqRhs,
bool lhsLtRhs,
int line) {
auto fmt = [this](bool cond, char const* text, int line) {
if (cond)
this->pass();
else
this->fail(text, __FILE__, line);
};
fmt((lhs == rhs) == lhsEqRhs, "Value ==", line);
fmt((lhs != rhs) != lhsEqRhs, "Value !=", line);
fmt((lhs < rhs) == (!(lhsEqRhs | !lhsLtRhs)), "Value <", line);
fmt((lhs <= rhs) == (lhsEqRhs | lhsLtRhs), "Value <=", line);
fmt((lhs >= rhs) == (lhsEqRhs | !lhsLtRhs), "Value >=", line);
fmt((lhs > rhs) == (!(lhsEqRhs | lhsLtRhs)), "Value >", line);
};
Json::Value const null0;
Json::Value const intNeg1{-1};
Json::Value const int0{Json::intValue};
Json::Value const intPos1{1};
Json::Value const uint0{Json::uintValue};
Json::Value const uint1{1u};
Json::Value const realNeg1{-1.0};
Json::Value const real0{Json::realValue};
Json::Value const realPos1{1.0};
Json::Value const str0{Json::stringValue};
Json::Value const str1{"1"};
Json::Value const boolF{false};
Json::Value const boolT{true};
Json::Value const array0{Json::arrayValue};
Json::Value const array1{[]() {
Json::Value array1;
array1[0u] = 1;
return array1;
}()};
Json::Value const obj0{Json::objectValue};
Json::Value const obj1{[]() {
Json::Value obj1;
obj1["one"] = 1;
return obj1;
}()};
// lhs == rhs lhs < rhs
doCompare(null0, Json::Value{}, true, false, __LINE__);
doCompare(null0, intNeg1, false, true, __LINE__);
doCompare(null0, int0, false, true, __LINE__);
doCompare(null0, intPos1, false, true, __LINE__);
doCompare(null0, uint0, false, true, __LINE__);
doCompare(null0, uint1, false, true, __LINE__);
doCompare(null0, realNeg1, false, true, __LINE__);
doCompare(null0, real0, false, true, __LINE__);
doCompare(null0, realPos1, false, true, __LINE__);
doCompare(null0, str0, false, true, __LINE__);
doCompare(null0, str1, false, true, __LINE__);
doCompare(null0, boolF, false, true, __LINE__);
doCompare(null0, boolT, false, true, __LINE__);
doCompare(null0, array0, false, true, __LINE__);
doCompare(null0, array1, false, true, __LINE__);
doCompare(null0, obj0, false, true, __LINE__);
doCompare(null0, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(intNeg1, null0, false, false, __LINE__);
doCompare(intNeg1, intNeg1, true, false, __LINE__);
doCompare(intNeg1, int0, false, true, __LINE__);
doCompare(intNeg1, intPos1, false, true, __LINE__);
doCompare(intNeg1, uint0, false, true, __LINE__);
doCompare(intNeg1, uint1, false, true, __LINE__);
doCompare(intNeg1, realNeg1, false, true, __LINE__);
doCompare(intNeg1, real0, false, true, __LINE__);
doCompare(intNeg1, realPos1, false, true, __LINE__);
doCompare(intNeg1, str0, false, true, __LINE__);
doCompare(intNeg1, str1, false, true, __LINE__);
doCompare(intNeg1, boolF, false, true, __LINE__);
doCompare(intNeg1, boolT, false, true, __LINE__);
doCompare(intNeg1, array0, false, true, __LINE__);
doCompare(intNeg1, array1, false, true, __LINE__);
doCompare(intNeg1, obj0, false, true, __LINE__);
doCompare(intNeg1, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(int0, null0, false, false, __LINE__);
doCompare(int0, intNeg1, false, false, __LINE__);
doCompare(int0, int0, true, false, __LINE__);
doCompare(int0, intPos1, false, true, __LINE__);
doCompare(int0, uint0, true, false, __LINE__);
doCompare(int0, uint1, false, true, __LINE__);
doCompare(int0, realNeg1, false, true, __LINE__);
doCompare(int0, real0, false, true, __LINE__);
doCompare(int0, realPos1, false, true, __LINE__);
doCompare(int0, str0, false, true, __LINE__);
doCompare(int0, str1, false, true, __LINE__);
doCompare(int0, boolF, false, true, __LINE__);
doCompare(int0, boolT, false, true, __LINE__);
doCompare(int0, array0, false, true, __LINE__);
doCompare(int0, array1, false, true, __LINE__);
doCompare(int0, obj0, false, true, __LINE__);
doCompare(int0, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(intPos1, null0, false, false, __LINE__);
doCompare(intPos1, intNeg1, false, false, __LINE__);
doCompare(intPos1, int0, false, false, __LINE__);
doCompare(intPos1, intPos1, true, false, __LINE__);
doCompare(intPos1, uint0, false, false, __LINE__);
doCompare(intPos1, uint1, true, false, __LINE__);
doCompare(intPos1, realNeg1, false, true, __LINE__);
doCompare(intPos1, real0, false, true, __LINE__);
doCompare(intPos1, realPos1, false, true, __LINE__);
doCompare(intPos1, str0, false, true, __LINE__);
doCompare(intPos1, str1, false, true, __LINE__);
doCompare(intPos1, boolF, false, true, __LINE__);
doCompare(intPos1, boolT, false, true, __LINE__);
doCompare(intPos1, array0, false, true, __LINE__);
doCompare(intPos1, array1, false, true, __LINE__);
doCompare(intPos1, obj0, false, true, __LINE__);
doCompare(intPos1, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(uint0, null0, false, false, __LINE__);
doCompare(uint0, intNeg1, false, false, __LINE__);
doCompare(uint0, int0, true, false, __LINE__);
doCompare(uint0, intPos1, false, true, __LINE__);
doCompare(uint0, uint0, true, false, __LINE__);
doCompare(uint0, uint1, false, true, __LINE__);
doCompare(uint0, realNeg1, false, true, __LINE__);
doCompare(uint0, real0, false, true, __LINE__);
doCompare(uint0, realPos1, false, true, __LINE__);
doCompare(uint0, str0, false, true, __LINE__);
doCompare(uint0, str1, false, true, __LINE__);
doCompare(uint0, boolF, false, true, __LINE__);
doCompare(uint0, boolT, false, true, __LINE__);
doCompare(uint0, array0, false, true, __LINE__);
doCompare(uint0, array1, false, true, __LINE__);
doCompare(uint0, obj0, false, true, __LINE__);
doCompare(uint0, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(uint1, null0, false, false, __LINE__);
doCompare(uint1, intNeg1, false, false, __LINE__);
doCompare(uint1, int0, false, false, __LINE__);
doCompare(uint1, intPos1, true, false, __LINE__);
doCompare(uint1, uint0, false, false, __LINE__);
doCompare(uint1, uint1, true, false, __LINE__);
doCompare(uint1, realNeg1, false, true, __LINE__);
doCompare(uint1, real0, false, true, __LINE__);
doCompare(uint1, realPos1, false, true, __LINE__);
doCompare(uint1, str0, false, true, __LINE__);
doCompare(uint1, str1, false, true, __LINE__);
doCompare(uint1, boolF, false, true, __LINE__);
doCompare(uint1, boolT, false, true, __LINE__);
doCompare(uint1, array0, false, true, __LINE__);
doCompare(uint1, array1, false, true, __LINE__);
doCompare(uint1, obj0, false, true, __LINE__);
doCompare(uint1, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(realNeg1, null0, false, false, __LINE__);
doCompare(realNeg1, intNeg1, false, false, __LINE__);
doCompare(realNeg1, int0, false, false, __LINE__);
doCompare(realNeg1, intPos1, false, false, __LINE__);
doCompare(realNeg1, uint0, false, false, __LINE__);
doCompare(realNeg1, uint1, false, false, __LINE__);
doCompare(realNeg1, realNeg1, true, false, __LINE__);
doCompare(realNeg1, real0, false, true, __LINE__);
doCompare(realNeg1, realPos1, false, true, __LINE__);
doCompare(realNeg1, str0, false, true, __LINE__);
doCompare(realNeg1, str1, false, true, __LINE__);
doCompare(realNeg1, boolF, false, true, __LINE__);
doCompare(realNeg1, boolT, false, true, __LINE__);
doCompare(realNeg1, array0, false, true, __LINE__);
doCompare(realNeg1, array1, false, true, __LINE__);
doCompare(realNeg1, obj0, false, true, __LINE__);
doCompare(realNeg1, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(real0, null0, false, false, __LINE__);
doCompare(real0, intNeg1, false, false, __LINE__);
doCompare(real0, int0, false, false, __LINE__);
doCompare(real0, intPos1, false, false, __LINE__);
doCompare(real0, uint0, false, false, __LINE__);
doCompare(real0, uint1, false, false, __LINE__);
doCompare(real0, realNeg1, false, false, __LINE__);
doCompare(real0, real0, true, false, __LINE__);
doCompare(real0, realPos1, false, true, __LINE__);
doCompare(real0, str0, false, true, __LINE__);
doCompare(real0, str1, false, true, __LINE__);
doCompare(real0, boolF, false, true, __LINE__);
doCompare(real0, boolT, false, true, __LINE__);
doCompare(real0, array0, false, true, __LINE__);
doCompare(real0, array1, false, true, __LINE__);
doCompare(real0, obj0, false, true, __LINE__);
doCompare(real0, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(realPos1, null0, false, false, __LINE__);
doCompare(realPos1, intNeg1, false, false, __LINE__);
doCompare(realPos1, int0, false, false, __LINE__);
doCompare(realPos1, intPos1, false, false, __LINE__);
doCompare(realPos1, uint0, false, false, __LINE__);
doCompare(realPos1, uint1, false, false, __LINE__);
doCompare(realPos1, realNeg1, false, false, __LINE__);
doCompare(realPos1, real0, false, false, __LINE__);
doCompare(realPos1, realPos1, true, false, __LINE__);
doCompare(realPos1, str0, false, true, __LINE__);
doCompare(realPos1, str1, false, true, __LINE__);
doCompare(realPos1, boolF, false, true, __LINE__);
doCompare(realPos1, boolT, false, true, __LINE__);
doCompare(realPos1, array0, false, true, __LINE__);
doCompare(realPos1, array1, false, true, __LINE__);
doCompare(realPos1, obj0, false, true, __LINE__);
doCompare(realPos1, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(str0, null0, false, false, __LINE__);
doCompare(str0, intNeg1, false, false, __LINE__);
doCompare(str0, int0, false, false, __LINE__);
doCompare(str0, intPos1, false, false, __LINE__);
doCompare(str0, uint0, false, false, __LINE__);
doCompare(str0, uint1, false, false, __LINE__);
doCompare(str0, realNeg1, false, false, __LINE__);
doCompare(str0, real0, false, false, __LINE__);
doCompare(str0, realPos1, false, false, __LINE__);
doCompare(str0, str0, true, false, __LINE__);
doCompare(str0, str1, false, true, __LINE__);
doCompare(str0, boolF, false, true, __LINE__);
doCompare(str0, boolT, false, true, __LINE__);
doCompare(str0, array0, false, true, __LINE__);
doCompare(str0, array1, false, true, __LINE__);
doCompare(str0, obj0, false, true, __LINE__);
doCompare(str0, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(str1, null0, false, false, __LINE__);
doCompare(str1, intNeg1, false, false, __LINE__);
doCompare(str1, int0, false, false, __LINE__);
doCompare(str1, intPos1, false, false, __LINE__);
doCompare(str1, uint0, false, false, __LINE__);
doCompare(str1, uint1, false, false, __LINE__);
doCompare(str1, realNeg1, false, false, __LINE__);
doCompare(str1, real0, false, false, __LINE__);
doCompare(str1, realPos1, false, false, __LINE__);
doCompare(str1, str0, false, false, __LINE__);
doCompare(str1, str1, true, false, __LINE__);
doCompare(str1, boolF, false, true, __LINE__);
doCompare(str1, boolT, false, true, __LINE__);
doCompare(str1, array0, false, true, __LINE__);
doCompare(str1, array1, false, true, __LINE__);
doCompare(str1, obj0, false, true, __LINE__);
doCompare(str1, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(boolF, null0, false, false, __LINE__);
doCompare(boolF, intNeg1, false, false, __LINE__);
doCompare(boolF, int0, false, false, __LINE__);
doCompare(boolF, intPos1, false, false, __LINE__);
doCompare(boolF, uint0, false, false, __LINE__);
doCompare(boolF, uint1, false, false, __LINE__);
doCompare(boolF, realNeg1, false, false, __LINE__);
doCompare(boolF, real0, false, false, __LINE__);
doCompare(boolF, realPos1, false, false, __LINE__);
doCompare(boolF, str0, false, false, __LINE__);
doCompare(boolF, str1, false, false, __LINE__);
doCompare(boolF, boolF, true, false, __LINE__);
doCompare(boolF, boolT, false, true, __LINE__);
doCompare(boolF, array0, false, true, __LINE__);
doCompare(boolF, array1, false, true, __LINE__);
doCompare(boolF, obj0, false, true, __LINE__);
doCompare(boolF, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(boolT, null0, false, false, __LINE__);
doCompare(boolT, intNeg1, false, false, __LINE__);
doCompare(boolT, int0, false, false, __LINE__);
doCompare(boolT, intPos1, false, false, __LINE__);
doCompare(boolT, uint0, false, false, __LINE__);
doCompare(boolT, uint1, false, false, __LINE__);
doCompare(boolT, realNeg1, false, false, __LINE__);
doCompare(boolT, real0, false, false, __LINE__);
doCompare(boolT, realPos1, false, false, __LINE__);
doCompare(boolT, str0, false, false, __LINE__);
doCompare(boolT, str1, false, false, __LINE__);
doCompare(boolT, boolF, false, false, __LINE__);
doCompare(boolT, boolT, true, false, __LINE__);
doCompare(boolT, array0, false, true, __LINE__);
doCompare(boolT, array1, false, true, __LINE__);
doCompare(boolT, obj0, false, true, __LINE__);
doCompare(boolT, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(array0, null0, false, false, __LINE__);
doCompare(array0, intNeg1, false, false, __LINE__);
doCompare(array0, int0, false, false, __LINE__);
doCompare(array0, intPos1, false, false, __LINE__);
doCompare(array0, uint0, false, false, __LINE__);
doCompare(array0, uint1, false, false, __LINE__);
doCompare(array0, realNeg1, false, false, __LINE__);
doCompare(array0, real0, false, false, __LINE__);
doCompare(array0, realPos1, false, false, __LINE__);
doCompare(array0, str0, false, false, __LINE__);
doCompare(array0, str1, false, false, __LINE__);
doCompare(array0, boolF, false, false, __LINE__);
doCompare(array0, boolT, false, false, __LINE__);
doCompare(array0, array0, true, false, __LINE__);
doCompare(array0, array1, false, true, __LINE__);
doCompare(array0, obj0, false, true, __LINE__);
doCompare(array0, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(array1, null0, false, false, __LINE__);
doCompare(array1, intNeg1, false, false, __LINE__);
doCompare(array1, int0, false, false, __LINE__);
doCompare(array1, intPos1, false, false, __LINE__);
doCompare(array1, uint0, false, false, __LINE__);
doCompare(array1, uint1, false, false, __LINE__);
doCompare(array1, realNeg1, false, false, __LINE__);
doCompare(array1, real0, false, false, __LINE__);
doCompare(array1, realPos1, false, false, __LINE__);
doCompare(array1, str0, false, false, __LINE__);
doCompare(array1, str1, false, false, __LINE__);
doCompare(array1, boolF, false, false, __LINE__);
doCompare(array1, boolT, false, false, __LINE__);
doCompare(array1, array0, false, false, __LINE__);
doCompare(array1, array1, true, false, __LINE__);
doCompare(array1, obj0, false, true, __LINE__);
doCompare(array1, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(obj0, null0, false, false, __LINE__);
doCompare(obj0, intNeg1, false, false, __LINE__);
doCompare(obj0, int0, false, false, __LINE__);
doCompare(obj0, intPos1, false, false, __LINE__);
doCompare(obj0, uint0, false, false, __LINE__);
doCompare(obj0, uint1, false, false, __LINE__);
doCompare(obj0, realNeg1, false, false, __LINE__);
doCompare(obj0, real0, false, false, __LINE__);
doCompare(obj0, realPos1, false, false, __LINE__);
doCompare(obj0, str0, false, false, __LINE__);
doCompare(obj0, str1, false, false, __LINE__);
doCompare(obj0, boolF, false, false, __LINE__);
doCompare(obj0, boolT, false, false, __LINE__);
doCompare(obj0, array0, false, false, __LINE__);
doCompare(obj0, array1, false, false, __LINE__);
doCompare(obj0, obj0, true, false, __LINE__);
doCompare(obj0, obj1, false, true, __LINE__);
// lhs == rhs lhs < rhs
doCompare(obj1, null0, false, false, __LINE__);
doCompare(obj1, intNeg1, false, false, __LINE__);
doCompare(obj1, int0, false, false, __LINE__);
doCompare(obj1, intPos1, false, false, __LINE__);
doCompare(obj1, uint0, false, false, __LINE__);
doCompare(obj1, uint1, false, false, __LINE__);
doCompare(obj1, realNeg1, false, false, __LINE__);
doCompare(obj1, real0, false, false, __LINE__);
doCompare(obj1, realPos1, false, false, __LINE__);
doCompare(obj1, str0, false, false, __LINE__);
doCompare(obj1, str1, false, false, __LINE__);
doCompare(obj1, boolF, false, false, __LINE__);
doCompare(obj1, boolT, false, false, __LINE__);
doCompare(obj1, array0, false, false, __LINE__);
doCompare(obj1, array1, false, false, __LINE__);
doCompare(obj1, obj0, false, false, __LINE__);
doCompare(obj1, obj1, true, false, __LINE__);
}
void
test_bool()
{
BEAST_EXPECT(!Json::Value());
BEAST_EXPECT(!Json::Value(""));
BEAST_EXPECT(bool(Json::Value("empty")));
BEAST_EXPECT(bool(Json::Value(false)));
BEAST_EXPECT(bool(Json::Value(true)));
BEAST_EXPECT(bool(Json::Value(0)));
BEAST_EXPECT(bool(Json::Value(1)));
Json::Value array(Json::arrayValue);
BEAST_EXPECT(!array);
array.append(0);
BEAST_EXPECT(bool(array));
Json::Value object(Json::objectValue);
BEAST_EXPECT(!object);
object[""] = false;
BEAST_EXPECT(bool(object));
}
void
test_bad_json()
{
char const* s(
"{\"method\":\"ledger\",\"params\":[{\"ledger_index\":1e300}]}");
Json::Value j;
Json::Reader r;
r.parse(s, j);
pass();
}
void
test_edge_cases()
{
std::string json;
std::uint32_t max_uint = std::numeric_limits<std::uint32_t>::max();
std::int32_t max_int = std::numeric_limits<std::int32_t>::max();
std::int32_t min_int = std::numeric_limits<std::int32_t>::min();
std::uint32_t a_uint = max_uint - 1978;
std::int32_t a_large_int = max_int - 1978;
std::int32_t a_small_int = min_int + 1978;
json = "{\"max_uint\":" + std::to_string(max_uint);
json += ",\"max_int\":" + std::to_string(max_int);
json += ",\"min_int\":" + std::to_string(min_int);
json += ",\"a_uint\":" + std::to_string(a_uint);
json += ",\"a_large_int\":" + std::to_string(a_large_int);
json += ",\"a_small_int\":" + std::to_string(a_small_int);
json += "}";
Json::Value j1;
Json::Reader r1;
BEAST_EXPECT(r1.parse(json, j1));
BEAST_EXPECT(j1["max_uint"].asUInt() == max_uint);
BEAST_EXPECT(j1["max_int"].asInt() == max_int);
BEAST_EXPECT(j1["min_int"].asInt() == min_int);
BEAST_EXPECT(j1["a_uint"].asUInt() == a_uint);
BEAST_EXPECT(j1["a_uint"] > a_large_int);
BEAST_EXPECT(j1["a_uint"] > a_small_int);
BEAST_EXPECT(j1["a_large_int"].asInt() == a_large_int);
BEAST_EXPECT(j1["a_large_int"].asUInt() == a_large_int);
BEAST_EXPECT(j1["a_large_int"] < a_uint);
BEAST_EXPECT(j1["a_small_int"].asInt() == a_small_int);
BEAST_EXPECT(j1["a_small_int"] < a_uint);
json = "{\"overflow\":";
json += std::to_string(std::uint64_t(max_uint) + 1);
json += "}";
Json::Value j2;
Json::Reader r2;
BEAST_EXPECT(!r2.parse(json, j2));
json = "{\"underflow\":";
json += std::to_string(std::int64_t(min_int) - 1);
json += "}";
Json::Value j3;
Json::Reader r3;
BEAST_EXPECT(!r3.parse(json, j3));
Json::Value intString{"4294967296"};
try
{
[[maybe_unused]] std::uint32_t const uTooBig{intString.asUInt()};
fail("4294967296", __FILE__, __LINE__);
}
catch (beast::BadLexicalCast const&)
{
pass();
}
intString = "4294967295";
BEAST_EXPECT(intString.asUInt() == 4294967295u);
intString = "0";
BEAST_EXPECT(intString.asUInt() == 0);
intString = "-1";
try
{
[[maybe_unused]] std::uint32_t const uTooSmall{intString.asUInt()};
fail("-1", __FILE__, __LINE__);
}
catch (beast::BadLexicalCast const&)
{
pass();
}
intString = "2147483648";
try
{
[[maybe_unused]] std::int32_t tooPos{intString.asInt()};
fail("2147483648", __FILE__, __LINE__);
}
catch (beast::BadLexicalCast const&)
{
pass();
}
intString = "2147483647";
BEAST_EXPECT(intString.asInt() == 2147483647);
intString = "-2147483648";
BEAST_EXPECT(intString.asInt() == -2147483648LL); // MSVC wants the LL
intString = "-2147483649";
try
{
[[maybe_unused]] std::int32_t tooNeg{intString.asInt()};
fail("-2147483649", __FILE__, __LINE__);
}
catch (beast::BadLexicalCast const&)
{
pass();
}
}
void
test_copy()
{
Json::Value v1{2.5};
BEAST_EXPECT(v1.isDouble());
BEAST_EXPECT(v1.asDouble() == 2.5);
Json::Value v2 = v1;
BEAST_EXPECT(v1.isDouble());
BEAST_EXPECT(v1.asDouble() == 2.5);
BEAST_EXPECT(v2.isDouble());
BEAST_EXPECT(v2.asDouble() == 2.5);
BEAST_EXPECT(v1 == v2);
v1 = v2;
BEAST_EXPECT(v1.isDouble());
BEAST_EXPECT(v1.asDouble() == 2.5);
BEAST_EXPECT(v2.isDouble());
BEAST_EXPECT(v2.asDouble() == 2.5);
BEAST_EXPECT(v1 == v2);
pass();
}
void
test_move()
{
Json::Value v1{2.5};
BEAST_EXPECT(v1.isDouble());
BEAST_EXPECT(v1.asDouble() == 2.5);
Json::Value v2 = std::move(v1);
BEAST_EXPECT(!v1);
BEAST_EXPECT(v2.isDouble());
BEAST_EXPECT(v2.asDouble() == 2.5);
BEAST_EXPECT(v1 != v2);
v1 = std::move(v2);
BEAST_EXPECT(v1.isDouble());
BEAST_EXPECT(v1.asDouble() == 2.5);
BEAST_EXPECT(!v2);
BEAST_EXPECT(v1 != v2);
pass();
}
void
test_comparisons()
{
Json::Value a, b;
auto testEquals = [&](std::string const& name) {
BEAST_EXPECT(a == b);
BEAST_EXPECT(a <= b);
BEAST_EXPECT(a >= b);
BEAST_EXPECT(!(a != b));
BEAST_EXPECT(!(a < b));
BEAST_EXPECT(!(a > b));
BEAST_EXPECT(b == a);
BEAST_EXPECT(b <= a);
BEAST_EXPECT(b >= a);
BEAST_EXPECT(!(b != a));
BEAST_EXPECT(!(b < a));
BEAST_EXPECT(!(b > a));
};
auto testGreaterThan = [&](std::string const& name) {
BEAST_EXPECT(!(a == b));
BEAST_EXPECT(!(a <= b));
BEAST_EXPECT(a >= b);
BEAST_EXPECT(a != b);
BEAST_EXPECT(!(a < b));
BEAST_EXPECT(a > b);
BEAST_EXPECT(!(b == a));
BEAST_EXPECT(b <= a);
BEAST_EXPECT(!(b >= a));
BEAST_EXPECT(b != a);
BEAST_EXPECT(b < a);
BEAST_EXPECT(!(b > a));
};
a["a"] = Json::UInt(0);
b["a"] = Json::Int(0);
testEquals("zero");
b["a"] = Json::Int(-1);
testGreaterThan("negative");
Json::Int big = std::numeric_limits<int>::max();
Json::UInt bigger = big;
bigger++;
a["a"] = bigger;
b["a"] = big;
testGreaterThan("big");
}
void
test_compact()
{
Json::Value j;
Json::Reader r;
char const* s("{\"array\":[{\"12\":23},{},null,false,0.5]}");
auto countLines = [](std::string const& str) {
return 1 + std::count_if(str.begin(), str.end(), [](char c) {
return c == '\n';
});
};
BEAST_EXPECT(r.parse(s, j));
{
std::stringstream ss;
ss << j;
BEAST_EXPECT(countLines(ss.str()) > 1);
}
{
std::stringstream ss;
ss << Json::Compact(std::move(j));
BEAST_EXPECT(countLines(ss.str()) == 1);
}
}
void
test_conversions()
{
// We have Json::Int, but not Json::Double or Json::Real.
// We have Json::Int, Json::Value::Int, and Json::ValueType::intValue.
// We have Json::ValueType::realValue but Json::Value::asDouble.
// TODO: What's the thinking here?
{
// null
Json::Value val;
BEAST_EXPECT(val.isNull());
// BEAST_EXPECT(strcmp (val.asCString(), ?) == 0); //
// asserts
BEAST_EXPECT(val.asString() == "");
BEAST_EXPECT(val.asInt() == 0);
BEAST_EXPECT(val.asUInt() == 0);
BEAST_EXPECT(val.asDouble() == 0.0);
BEAST_EXPECT(val.asBool() == false);
BEAST_EXPECT(val.isConvertibleTo(Json::nullValue));
BEAST_EXPECT(val.isConvertibleTo(Json::intValue));
BEAST_EXPECT(val.isConvertibleTo(Json::uintValue));
BEAST_EXPECT(val.isConvertibleTo(Json::realValue));
BEAST_EXPECT(val.isConvertibleTo(Json::stringValue));
BEAST_EXPECT(val.isConvertibleTo(Json::booleanValue));
BEAST_EXPECT(val.isConvertibleTo(Json::arrayValue));
BEAST_EXPECT(val.isConvertibleTo(Json::objectValue));
}
{
// int
Json::Value val = -1234;
BEAST_EXPECT(val.isInt());
// BEAST_EXPECT(strcmp (val.asCString(), ?) == 0); //
// asserts
BEAST_EXPECT(val.asString() == "-1234");
BEAST_EXPECT(val.asInt() == -1234);
// BEAST_EXPECT(val.asUInt() == ?); //
// asserts or throws
BEAST_EXPECT(val.asDouble() == -1234.0);
BEAST_EXPECT(val.asBool() == true);
BEAST_EXPECT(!val.isConvertibleTo(Json::nullValue));
BEAST_EXPECT(val.isConvertibleTo(Json::intValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::uintValue));
BEAST_EXPECT(val.isConvertibleTo(Json::realValue));
BEAST_EXPECT(val.isConvertibleTo(Json::stringValue));
BEAST_EXPECT(val.isConvertibleTo(Json::booleanValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::arrayValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::objectValue));
}
{
// uint
Json::Value val = 1234U;
BEAST_EXPECT(val.isUInt());
// BEAST_EXPECT(strcmp (val.asCString(), ?) == 0); //
// asserts
BEAST_EXPECT(val.asString() == "1234");
BEAST_EXPECT(val.asInt() == 1234);
BEAST_EXPECT(val.asUInt() == 1234u);
BEAST_EXPECT(val.asDouble() == 1234.0);
BEAST_EXPECT(val.asBool() == true);
BEAST_EXPECT(!val.isConvertibleTo(Json::nullValue));
BEAST_EXPECT(val.isConvertibleTo(Json::intValue));
BEAST_EXPECT(val.isConvertibleTo(Json::uintValue));
BEAST_EXPECT(val.isConvertibleTo(Json::realValue));
BEAST_EXPECT(val.isConvertibleTo(Json::stringValue));
BEAST_EXPECT(val.isConvertibleTo(Json::booleanValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::arrayValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::objectValue));
}
{
// real
Json::Value val = 2.0;
BEAST_EXPECT(val.isDouble());
// BEAST_EXPECT(strcmp (val.asCString(), ?) == 0); //
// asserts
BEAST_EXPECT(
std::regex_match(val.asString(), std::regex("^2\\.0*$")));
BEAST_EXPECT(val.asInt() == 2);
BEAST_EXPECT(val.asUInt() == 2u);
BEAST_EXPECT(val.asDouble() == 2.0);
BEAST_EXPECT(val.asBool() == true);
BEAST_EXPECT(!val.isConvertibleTo(Json::nullValue));
BEAST_EXPECT(val.isConvertibleTo(Json::intValue));
BEAST_EXPECT(val.isConvertibleTo(Json::uintValue));
BEAST_EXPECT(val.isConvertibleTo(Json::realValue));
BEAST_EXPECT(val.isConvertibleTo(Json::stringValue));
BEAST_EXPECT(val.isConvertibleTo(Json::booleanValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::arrayValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::objectValue));
}
{
// numeric string
Json::Value val = "54321";
BEAST_EXPECT(val.isString());
BEAST_EXPECT(strcmp(val.asCString(), "54321") == 0);
BEAST_EXPECT(val.asString() == "54321");
BEAST_EXPECT(val.asInt() == 54321);
BEAST_EXPECT(val.asUInt() == 54321u);
// BEAST_EXPECT(val.asDouble() == 54321.0); //
// asserts or throws
BEAST_EXPECT(val.asBool() == true);
BEAST_EXPECT(!val.isConvertibleTo(Json::nullValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::intValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::uintValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::realValue));
BEAST_EXPECT(val.isConvertibleTo(Json::stringValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::booleanValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::arrayValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::objectValue));
}
{
// non-numeric string
Json::Value val(Json::stringValue);
BEAST_EXPECT(val.isString());
BEAST_EXPECT(val.asCString() == nullptr);
BEAST_EXPECT(val.asString() == "");
try
{
BEAST_EXPECT(val.asInt() == 0);
fail("expected exception", __FILE__, __LINE__);
}
catch (std::exception const&)
{
pass();
}
try
{
BEAST_EXPECT(val.asUInt() == 0);
fail("expected exception", __FILE__, __LINE__);
}
catch (std::exception const&)
{
pass();
}
// BEAST_EXPECT(val.asDouble() == ?); //
// asserts or throws
BEAST_EXPECT(val.asBool() == false);
BEAST_EXPECT(val.isConvertibleTo(Json::nullValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::intValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::uintValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::realValue));
BEAST_EXPECT(val.isConvertibleTo(Json::stringValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::booleanValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::arrayValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::objectValue));
}
{
// bool false
Json::Value val = false;
BEAST_EXPECT(val.isBool());
// BEAST_EXPECT(strcmp (val.asCString(), ?) == 0); //
// asserts
BEAST_EXPECT(val.asString() == "false");
BEAST_EXPECT(val.asInt() == 0);
BEAST_EXPECT(val.asUInt() == 0);
BEAST_EXPECT(val.asDouble() == 0.0);
BEAST_EXPECT(val.asBool() == false);
BEAST_EXPECT(val.isConvertibleTo(Json::nullValue));
BEAST_EXPECT(val.isConvertibleTo(Json::intValue));
BEAST_EXPECT(val.isConvertibleTo(Json::uintValue));
BEAST_EXPECT(val.isConvertibleTo(Json::realValue));
BEAST_EXPECT(val.isConvertibleTo(Json::stringValue));
BEAST_EXPECT(val.isConvertibleTo(Json::booleanValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::arrayValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::objectValue));
}
{
// bool true
Json::Value val = true;
BEAST_EXPECT(val.isBool());
// BEAST_EXPECT(strcmp (val.asCString(), ?) == 0); //
// asserts
BEAST_EXPECT(val.asString() == "true");
BEAST_EXPECT(val.asInt() == 1);
BEAST_EXPECT(val.asUInt() == 1);
BEAST_EXPECT(val.asDouble() == 1.0);
BEAST_EXPECT(val.asBool() == true);
BEAST_EXPECT(!val.isConvertibleTo(Json::nullValue));
BEAST_EXPECT(val.isConvertibleTo(Json::intValue));
BEAST_EXPECT(val.isConvertibleTo(Json::uintValue));
BEAST_EXPECT(val.isConvertibleTo(Json::realValue));
BEAST_EXPECT(val.isConvertibleTo(Json::stringValue));
BEAST_EXPECT(val.isConvertibleTo(Json::booleanValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::arrayValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::objectValue));
}
{
// array type
Json::Value val(Json::arrayValue);
BEAST_EXPECT(val.isArray());
// BEAST_EXPECT(strcmp (val.asCString(), ?) == 0); //
// asserts BEAST_EXPECT(val.asString() == ?); // asserts or
// throws BEAST_EXPECT(val.asInt() == ?); // asserts or
// throws BEAST_EXPECT(val.asUInt() == ?); // asserts or
// throws BEAST_EXPECT(val.asDouble() == ?); // asserts or
// throws
BEAST_EXPECT(val.asBool() == false); // empty or not
BEAST_EXPECT(val.isConvertibleTo(Json::nullValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::intValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::uintValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::realValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::stringValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::booleanValue));
BEAST_EXPECT(val.isConvertibleTo(Json::arrayValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::objectValue));
}
{
// object type
Json::Value val(Json::objectValue);
BEAST_EXPECT(val.isObject());
// BEAST_EXPECT(strcmp (val.asCString(), ?) == 0); //
// asserts BEAST_EXPECT(strcmp (val.asCString(), ?) == 0);
// // asserts BEAST_EXPECT(val.asString() == ?); // asserts
// or throws BEAST_EXPECT(val.asInt() == ?); // asserts or
// throws BEAST_EXPECT(val.asUInt() == ?); // asserts or
// throws
BEAST_EXPECT(val.asBool() == false); // empty or not
BEAST_EXPECT(val.isConvertibleTo(Json::nullValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::intValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::uintValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::realValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::stringValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::booleanValue));
BEAST_EXPECT(!val.isConvertibleTo(Json::arrayValue));
BEAST_EXPECT(val.isConvertibleTo(Json::objectValue));
}
}
void
test_access()
{
Json::Value val;
BEAST_EXPECT(val.type() == Json::nullValue);
BEAST_EXPECT(val.size() == 0);
BEAST_EXPECT(!val.isValidIndex(0));
BEAST_EXPECT(!val.isMember("key"));
{
Json::Value const constVal = val;
BEAST_EXPECT(constVal[7u].type() == Json::nullValue);
BEAST_EXPECT(!constVal.isMember("key"));
BEAST_EXPECT(constVal["key"].type() == Json::nullValue);
BEAST_EXPECT(constVal.getMemberNames().empty());
BEAST_EXPECT(constVal.get(1u, "default0") == "default0");
BEAST_EXPECT(constVal.get(std::string("not"), "oh") == "oh");
BEAST_EXPECT(constVal.get("missing", "default2") == "default2");
}
val = -7;
BEAST_EXPECT(val.type() == Json::intValue);
BEAST_EXPECT(val.size() == 0);
BEAST_EXPECT(!val.isValidIndex(0));
BEAST_EXPECT(!val.isMember("key"));
val = 42u;
BEAST_EXPECT(val.type() == Json::uintValue);
BEAST_EXPECT(val.size() == 0);
BEAST_EXPECT(!val.isValidIndex(0));
BEAST_EXPECT(!val.isMember("key"));
val = 3.14159;
BEAST_EXPECT(val.type() == Json::realValue);
BEAST_EXPECT(val.size() == 0);
BEAST_EXPECT(!val.isValidIndex(0));
BEAST_EXPECT(!val.isMember("key"));
val = true;
BEAST_EXPECT(val.type() == Json::booleanValue);
BEAST_EXPECT(val.size() == 0);
BEAST_EXPECT(!val.isValidIndex(0));
BEAST_EXPECT(!val.isMember("key"));
val = "string";
BEAST_EXPECT(val.type() == Json::stringValue);
BEAST_EXPECT(val.size() == 0);
BEAST_EXPECT(!val.isValidIndex(0));
BEAST_EXPECT(!val.isMember("key"));
val = Json::Value(Json::objectValue);
BEAST_EXPECT(val.type() == Json::objectValue);
BEAST_EXPECT(val.size() == 0);
static Json::StaticString const staticThree("three");
val[staticThree] = 3;
val["two"] = 2;
BEAST_EXPECT(val.size() == 2);
BEAST_EXPECT(val.isValidIndex(1));
BEAST_EXPECT(!val.isValidIndex(2));
BEAST_EXPECT(val[staticThree] == 3);
BEAST_EXPECT(val.isMember("two"));
BEAST_EXPECT(val.isMember(staticThree));
BEAST_EXPECT(!val.isMember("key"));
{
Json::Value const constVal = val;
BEAST_EXPECT(constVal["two"] == 2);
BEAST_EXPECT(constVal["four"].type() == Json::nullValue);
BEAST_EXPECT(constVal[staticThree] == 3);
BEAST_EXPECT(constVal.isMember("two"));
BEAST_EXPECT(constVal.isMember(staticThree));
BEAST_EXPECT(!constVal.isMember("key"));
BEAST_EXPECT(val.get(std::string("two"), "backup") == 2);
BEAST_EXPECT(val.get("missing", "default2") == "default2");
}
val = Json::Value(Json::arrayValue);
BEAST_EXPECT(val.type() == Json::arrayValue);
BEAST_EXPECT(val.size() == 0);
val[0u] = "zero";
val[1u] = "one";
BEAST_EXPECT(val.size() == 2);
BEAST_EXPECT(val.isValidIndex(1));
BEAST_EXPECT(!val.isValidIndex(2));
BEAST_EXPECT(val[20u].type() == Json::nullValue);
BEAST_EXPECT(!val.isMember("key"));
{
Json::Value const constVal = val;
BEAST_EXPECT(constVal[0u] == "zero");
BEAST_EXPECT(constVal[2u].type() == Json::nullValue);
BEAST_EXPECT(!constVal.isMember("key"));
BEAST_EXPECT(val.get(1u, "default0") == "one");
BEAST_EXPECT(val.get(3u, "default1") == "default1");
}
}
void
test_removeMember()
{
Json::Value val;
BEAST_EXPECT(
val.removeMember(std::string("member")).type() == Json::nullValue);
val = Json::Value(Json::objectValue);
static Json::StaticString const staticThree("three");
val[staticThree] = 3;
val["two"] = 2;
BEAST_EXPECT(val.size() == 2);
BEAST_EXPECT(
val.removeMember(std::string("six")).type() == Json::nullValue);
BEAST_EXPECT(val.size() == 2);
BEAST_EXPECT(val.removeMember(staticThree) == 3);
BEAST_EXPECT(val.size() == 1);
BEAST_EXPECT(val.removeMember(staticThree).type() == Json::nullValue);
BEAST_EXPECT(val.size() == 1);
BEAST_EXPECT(val.removeMember(std::string("two")) == 2);
BEAST_EXPECT(val.size() == 0);
BEAST_EXPECT(
val.removeMember(std::string("two")).type() == Json::nullValue);
BEAST_EXPECT(val.size() == 0);
}
void
test_iterator()
{
{
// Iterating an array.
Json::Value arr{Json::arrayValue};
arr[0u] = "zero";
arr[1u] = "one";
arr[2u] = "two";
arr[3u] = "three";
Json::ValueIterator const b{arr.begin()};
Json::ValueIterator const e{arr.end()};
Json::ValueIterator i1 = b;
Json::ValueIterator i2 = e;
--i2;
// key(), index(), and memberName() on an object iterator.
BEAST_EXPECT(b != e);
BEAST_EXPECT(!(b == e));
BEAST_EXPECT(i1.key() == 0);
BEAST_EXPECT(i2.key() == 3);
BEAST_EXPECT(i1.index() == 0);
BEAST_EXPECT(i2.index() == 3);
BEAST_EXPECT(std::strcmp(i1.memberName(), "") == 0);
BEAST_EXPECT(std::strcmp(i2.memberName(), "") == 0);
// Pre and post increment and decrement.
*i1++ = "0";
BEAST_EXPECT(*i1 == "one");
*i1 = "1";
++i1;
*i2-- = "3";
BEAST_EXPECT(*i2 == "two");
BEAST_EXPECT(i1 == i2);
*i2 = "2";
BEAST_EXPECT(*i1 == "2");
}
{
// Iterating a const object.
Json::Value const obj{[]() {
Json::Value obj{Json::objectValue};
obj["0"] = 0;
obj["1"] = 1;
obj["2"] = 2;
obj["3"] = 3;
return obj;
}()};
Json::ValueConstIterator i1{obj.begin()};
Json::ValueConstIterator i2{obj.end()};
--i2;
// key(), index(), and memberName() on an object iterator.
BEAST_EXPECT(i1 != i2);
BEAST_EXPECT(!(i1 == i2));
BEAST_EXPECT(i1.key() == "0");
BEAST_EXPECT(i2.key() == "3");
BEAST_EXPECT(i1.index() == -1);
BEAST_EXPECT(i2.index() == -1);
BEAST_EXPECT(std::strcmp(i1.memberName(), "0") == 0);
BEAST_EXPECT(std::strcmp(i2.memberName(), "3") == 0);
// Pre and post increment and decrement.
BEAST_EXPECT(*i1++ == 0);
BEAST_EXPECT(*i1 == 1);
++i1;
BEAST_EXPECT(*i2-- == 3);
BEAST_EXPECT(*i2 == 2);
BEAST_EXPECT(i1 == i2);
BEAST_EXPECT(*i1 == 2);
}
{
// Iterating a non-const null object.
Json::Value nul{};
BEAST_EXPECT(nul.begin() == nul.end());
}
{
// Iterating a const Int.
Json::Value const i{-3};
BEAST_EXPECT(i.begin() == i.end());
}
}
void
test_nest_limits()
{
Json::Reader r;
{
auto nest = [](std::uint32_t depth) -> std::string {
std::string s = "{";
for (std::uint32_t i{1}; i <= depth; ++i)
s += "\"obj\":{";
for (std::uint32_t i{1}; i <= depth; ++i)
s += "}";
s += "}";
return s;
};
{
// Within object nest limit
auto json{nest(std::min(10u, Json::Reader::nest_limit))};
Json::Value j;
BEAST_EXPECT(r.parse(json, j));
}
{
// Exceed object nest limit
auto json{nest(Json::Reader::nest_limit + 1)};
Json::Value j;
BEAST_EXPECT(!r.parse(json, j));
}
}
auto nest = [](std::uint32_t depth) -> std::string {
std::string s = "{";
for (std::uint32_t i{1}; i <= depth; ++i)
s += "\"array\":[{";
for (std::uint32_t i{1}; i <= depth; ++i)
s += "]}";
s += "}";
return s;
};
{
// Exceed array nest limit
auto json{nest(Json::Reader::nest_limit + 1)};
Json::Value j;
BEAST_EXPECT(!r.parse(json, j));
}
}
void
test_leak()
{
// When run with the address sanitizer, this test confirms there is no
// memory leak with the scenarios below.
{
Json::Value a;
a[0u] = 1;
BEAST_EXPECT(a.type() == Json::arrayValue);
BEAST_EXPECT(a[0u].type() == Json::intValue);
a = std::move(a[0u]);
BEAST_EXPECT(a.type() == Json::intValue);
}
{
Json::Value b;
Json::Value temp;
temp["a"] = "Probably avoids the small string optimization";
temp["b"] = "Also probably avoids the small string optimization";
BEAST_EXPECT(temp.type() == Json::objectValue);
b.append(temp);
BEAST_EXPECT(temp.type() == Json::objectValue);
BEAST_EXPECT(b.size() == 1);
b.append(std::move(temp));
BEAST_EXPECT(b.size() == 2);
// Note that the type() == nullValue check is implementation
// specific and not guaranteed to be valid in the future.
BEAST_EXPECT(temp.type() == Json::nullValue);
}
}
void
run() override
{
test_StaticString();
test_types();
test_compare();
test_bool();
test_bad_json();
test_edge_cases();
test_copy();
test_move();
test_comparisons();
test_compact();
test_conversions();
test_access();
test_removeMember();
test_iterator();
test_nest_limits();
test_leak();
}
};
BEAST_DEFINE_TESTSUITE(json_value, json, ripple);
} // namespace ripple