rapidjson/test/unittest/pointertest.cpp
ylavic eb6ee17d2d Speed up Pointer::operator<().
Speed is more important than alphabetical order (which makes few sense in
JSON in general, and with pointers especially). The use case is indexing
in std containers, i.e. O(log n) with rbtree, so the faster comparison
the better.
2018-12-12 22:32:56 +01:00

1605 lines
57 KiB
C++

// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#include "unittest.h"
#include "rapidjson/pointer.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/ostreamwrapper.h"
#include <sstream>
#include <map>
using namespace rapidjson;
static const char kJson[] = "{\n"
" \"foo\":[\"bar\", \"baz\"],\n"
" \"\" : 0,\n"
" \"a/b\" : 1,\n"
" \"c%d\" : 2,\n"
" \"e^f\" : 3,\n"
" \"g|h\" : 4,\n"
" \"i\\\\j\" : 5,\n"
" \"k\\\"l\" : 6,\n"
" \" \" : 7,\n"
" \"m~n\" : 8\n"
"}";
TEST(Pointer, DefaultConstructor) {
Pointer p;
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(0u, p.GetTokenCount());
}
TEST(Pointer, Parse) {
{
Pointer p("");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(0u, p.GetTokenCount());
}
{
Pointer p("/");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(0u, p.GetTokens()[0].length);
EXPECT_STREQ("", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
}
{
Pointer p("/foo");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
}
#if RAPIDJSON_HAS_STDSTRING
{
Pointer p(std::string("/foo"));
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
}
#endif
{
Pointer p("/foo/0");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(2u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
EXPECT_EQ(1u, p.GetTokens()[1].length);
EXPECT_STREQ("0", p.GetTokens()[1].name);
EXPECT_EQ(0u, p.GetTokens()[1].index);
}
{
// Unescape ~1
Pointer p("/a~1b");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("a/b", p.GetTokens()[0].name);
}
{
// Unescape ~0
Pointer p("/m~0n");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("m~n", p.GetTokens()[0].name);
}
{
// empty name
Pointer p("/");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(0u, p.GetTokens()[0].length);
EXPECT_STREQ("", p.GetTokens()[0].name);
}
{
// empty and non-empty name
Pointer p("//a");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(2u, p.GetTokenCount());
EXPECT_EQ(0u, p.GetTokens()[0].length);
EXPECT_STREQ("", p.GetTokens()[0].name);
EXPECT_EQ(1u, p.GetTokens()[1].length);
EXPECT_STREQ("a", p.GetTokens()[1].name);
}
{
// Null characters
Pointer p("/\0\0", 3);
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(2u, p.GetTokens()[0].length);
EXPECT_EQ('\0', p.GetTokens()[0].name[0]);
EXPECT_EQ('\0', p.GetTokens()[0].name[1]);
EXPECT_EQ('\0', p.GetTokens()[0].name[2]);
}
{
// Valid index
Pointer p("/123");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_STREQ("123", p.GetTokens()[0].name);
EXPECT_EQ(123u, p.GetTokens()[0].index);
}
{
// Invalid index (with leading zero)
Pointer p("/01");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_STREQ("01", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
}
if (sizeof(SizeType) == 4) {
// Invalid index (overflow)
Pointer p("/4294967296");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_STREQ("4294967296", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
}
{
// kPointerParseErrorTokenMustBeginWithSolidus
Pointer p(" ");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorTokenMustBeginWithSolidus, p.GetParseErrorCode());
EXPECT_EQ(0u, p.GetParseErrorOffset());
}
{
// kPointerParseErrorInvalidEscape
Pointer p("/~");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode());
EXPECT_EQ(2u, p.GetParseErrorOffset());
}
{
// kPointerParseErrorInvalidEscape
Pointer p("/~2");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode());
EXPECT_EQ(2u, p.GetParseErrorOffset());
}
}
TEST(Pointer, Parse_URIFragment) {
{
Pointer p("#");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(0u, p.GetTokenCount());
}
{
Pointer p("#/foo");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name);
}
{
Pointer p("#/foo/0");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(2u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name);
EXPECT_EQ(1u, p.GetTokens()[1].length);
EXPECT_STREQ("0", p.GetTokens()[1].name);
EXPECT_EQ(0u, p.GetTokens()[1].index);
}
{
// Unescape ~1
Pointer p("#/a~1b");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("a/b", p.GetTokens()[0].name);
}
{
// Unescape ~0
Pointer p("#/m~0n");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("m~n", p.GetTokens()[0].name);
}
{
// empty name
Pointer p("#/");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(0u, p.GetTokens()[0].length);
EXPECT_STREQ("", p.GetTokens()[0].name);
}
{
// empty and non-empty name
Pointer p("#//a");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(2u, p.GetTokenCount());
EXPECT_EQ(0u, p.GetTokens()[0].length);
EXPECT_STREQ("", p.GetTokens()[0].name);
EXPECT_EQ(1u, p.GetTokens()[1].length);
EXPECT_STREQ("a", p.GetTokens()[1].name);
}
{
// Null characters
Pointer p("#/%00%00");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(2u, p.GetTokens()[0].length);
EXPECT_EQ('\0', p.GetTokens()[0].name[0]);
EXPECT_EQ('\0', p.GetTokens()[0].name[1]);
EXPECT_EQ('\0', p.GetTokens()[0].name[2]);
}
{
// Percentage Escapes
EXPECT_STREQ("c%d", Pointer("#/c%25d").GetTokens()[0].name);
EXPECT_STREQ("e^f", Pointer("#/e%5Ef").GetTokens()[0].name);
EXPECT_STREQ("g|h", Pointer("#/g%7Ch").GetTokens()[0].name);
EXPECT_STREQ("i\\j", Pointer("#/i%5Cj").GetTokens()[0].name);
EXPECT_STREQ("k\"l", Pointer("#/k%22l").GetTokens()[0].name);
EXPECT_STREQ(" ", Pointer("#/%20").GetTokens()[0].name);
}
{
// Valid index
Pointer p("#/123");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_STREQ("123", p.GetTokens()[0].name);
EXPECT_EQ(123u, p.GetTokens()[0].index);
}
{
// Invalid index (with leading zero)
Pointer p("#/01");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_STREQ("01", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
}
if (sizeof(SizeType) == 4) {
// Invalid index (overflow)
Pointer p("#/4294967296");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_STREQ("4294967296", p.GetTokens()[0].name);
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
}
{
// Decode UTF-8 perecent encoding to UTF-8
Pointer p("#/%C2%A2");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_STREQ("\xC2\xA2", p.GetTokens()[0].name);
}
{
// Decode UTF-8 perecent encoding to UTF-16
GenericPointer<GenericValue<UTF16<> > > p(L"#/%C2%A2");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(static_cast<UTF16<>::Ch>(0x00A2), p.GetTokens()[0].name[0]);
EXPECT_EQ(1u, p.GetTokens()[0].length);
}
{
// Decode UTF-8 perecent encoding to UTF-16
GenericPointer<GenericValue<UTF16<> > > p(L"#/%E2%82%AC");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
EXPECT_EQ(static_cast<UTF16<>::Ch>(0x20AC), p.GetTokens()[0].name[0]);
EXPECT_EQ(1u, p.GetTokens()[0].length);
}
{
// kPointerParseErrorTokenMustBeginWithSolidus
Pointer p("# ");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorTokenMustBeginWithSolidus, p.GetParseErrorCode());
EXPECT_EQ(1u, p.GetParseErrorOffset());
}
{
// kPointerParseErrorInvalidEscape
Pointer p("#/~");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode());
EXPECT_EQ(3u, p.GetParseErrorOffset());
}
{
// kPointerParseErrorInvalidEscape
Pointer p("#/~2");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode());
EXPECT_EQ(3u, p.GetParseErrorOffset());
}
{
// kPointerParseErrorInvalidPercentEncoding
Pointer p("#/%");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode());
EXPECT_EQ(2u, p.GetParseErrorOffset());
}
{
// kPointerParseErrorInvalidPercentEncoding (invalid hex)
Pointer p("#/%g0");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode());
EXPECT_EQ(2u, p.GetParseErrorOffset());
}
{
// kPointerParseErrorInvalidPercentEncoding (invalid hex)
Pointer p("#/%0g");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode());
EXPECT_EQ(2u, p.GetParseErrorOffset());
}
{
// kPointerParseErrorInvalidPercentEncoding (incomplete UTF-8 sequence)
Pointer p("#/%C2");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode());
EXPECT_EQ(2u, p.GetParseErrorOffset());
}
{
// kPointerParseErrorCharacterMustPercentEncode
Pointer p("#/ ");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorCharacterMustPercentEncode, p.GetParseErrorCode());
EXPECT_EQ(2u, p.GetParseErrorOffset());
}
{
// kPointerParseErrorCharacterMustPercentEncode
Pointer p("#/\n");
EXPECT_FALSE(p.IsValid());
EXPECT_EQ(kPointerParseErrorCharacterMustPercentEncode, p.GetParseErrorCode());
EXPECT_EQ(2u, p.GetParseErrorOffset());
}
}
TEST(Pointer, Stringify) {
// Test by roundtrip
const char* sources[] = {
"",
"/foo",
"/foo/0",
"/",
"/a~1b",
"/c%d",
"/e^f",
"/g|h",
"/i\\j",
"/k\"l",
"/ ",
"/m~0n",
"/\xC2\xA2",
"/\xE2\x82\xAC",
"/\xF0\x9D\x84\x9E"
};
for (size_t i = 0; i < sizeof(sources) / sizeof(sources[0]); i++) {
Pointer p(sources[i]);
StringBuffer s;
EXPECT_TRUE(p.Stringify(s));
EXPECT_STREQ(sources[i], s.GetString());
// Stringify to URI fragment
StringBuffer s2;
EXPECT_TRUE(p.StringifyUriFragment(s2));
Pointer p2(s2.GetString(), s2.GetSize());
EXPECT_TRUE(p2.IsValid());
EXPECT_TRUE(p == p2);
}
{
// Strigify to URI fragment with an invalid UTF-8 sequence
Pointer p("/\xC2");
StringBuffer s;
EXPECT_FALSE(p.StringifyUriFragment(s));
}
}
// Construct a Pointer with static tokens, no dynamic allocation involved.
#define NAME(s) { s, static_cast<SizeType>(sizeof(s) / sizeof(s[0]) - 1), kPointerInvalidIndex }
#define INDEX(i) { #i, static_cast<SizeType>(sizeof(#i) - 1), i }
static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(0) }; // equivalent to "/foo/0"
#undef NAME
#undef INDEX
TEST(Pointer, ConstructorWithToken) {
Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(2u, p.GetTokenCount());
EXPECT_EQ(3u, p.GetTokens()[0].length);
EXPECT_STREQ("foo", p.GetTokens()[0].name);
EXPECT_EQ(1u, p.GetTokens()[1].length);
EXPECT_STREQ("0", p.GetTokens()[1].name);
EXPECT_EQ(0u, p.GetTokens()[1].index);
}
TEST(Pointer, CopyConstructor) {
{
CrtAllocator allocator;
Pointer p("/foo/0", &allocator);
Pointer q(p);
EXPECT_TRUE(q.IsValid());
EXPECT_EQ(2u, q.GetTokenCount());
EXPECT_EQ(3u, q.GetTokens()[0].length);
EXPECT_STREQ("foo", q.GetTokens()[0].name);
EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index);
EXPECT_EQ(&p.GetAllocator(), &q.GetAllocator());
}
// Static tokens
{
Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
Pointer q(p);
EXPECT_TRUE(q.IsValid());
EXPECT_EQ(2u, q.GetTokenCount());
EXPECT_EQ(3u, q.GetTokens()[0].length);
EXPECT_STREQ("foo", q.GetTokens()[0].name);
EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index);
}
}
TEST(Pointer, Assignment) {
{
CrtAllocator allocator;
Pointer p("/foo/0", &allocator);
Pointer q;
q = p;
EXPECT_TRUE(q.IsValid());
EXPECT_EQ(2u, q.GetTokenCount());
EXPECT_EQ(3u, q.GetTokens()[0].length);
EXPECT_STREQ("foo", q.GetTokens()[0].name);
EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index);
EXPECT_NE(&p.GetAllocator(), &q.GetAllocator());
q = static_cast<const Pointer &>(q);
EXPECT_TRUE(q.IsValid());
EXPECT_EQ(2u, q.GetTokenCount());
EXPECT_EQ(3u, q.GetTokens()[0].length);
EXPECT_STREQ("foo", q.GetTokens()[0].name);
EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index);
EXPECT_NE(&p.GetAllocator(), &q.GetAllocator());
}
// Static tokens
{
Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
Pointer q;
q = p;
EXPECT_TRUE(q.IsValid());
EXPECT_EQ(2u, q.GetTokenCount());
EXPECT_EQ(3u, q.GetTokens()[0].length);
EXPECT_STREQ("foo", q.GetTokens()[0].name);
EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index);
}
}
TEST(Pointer, Append) {
{
Pointer p;
Pointer q = p.Append("foo");
EXPECT_TRUE(Pointer("/foo") == q);
q = q.Append(1234);
EXPECT_TRUE(Pointer("/foo/1234") == q);
q = q.Append("");
EXPECT_TRUE(Pointer("/foo/1234/") == q);
}
{
Pointer p;
Pointer q = p.Append(Value("foo").Move());
EXPECT_TRUE(Pointer("/foo") == q);
q = q.Append(Value(1234).Move());
EXPECT_TRUE(Pointer("/foo/1234") == q);
q = q.Append(Value(kStringType).Move());
EXPECT_TRUE(Pointer("/foo/1234/") == q);
}
#if RAPIDJSON_HAS_STDSTRING
{
Pointer p;
Pointer q = p.Append(std::string("foo"));
EXPECT_TRUE(Pointer("/foo") == q);
}
#endif
}
TEST(Pointer, Equality) {
EXPECT_TRUE(Pointer("/foo/0") == Pointer("/foo/0"));
EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/1"));
EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/0/1"));
EXPECT_FALSE(Pointer("/foo/0") == Pointer("a"));
EXPECT_FALSE(Pointer("a") == Pointer("a")); // Invalid always not equal
}
TEST(Pointer, Inequality) {
EXPECT_FALSE(Pointer("/foo/0") != Pointer("/foo/0"));
EXPECT_TRUE(Pointer("/foo/0") != Pointer("/foo/1"));
EXPECT_TRUE(Pointer("/foo/0") != Pointer("/foo/0/1"));
EXPECT_TRUE(Pointer("/foo/0") != Pointer("a"));
EXPECT_TRUE(Pointer("a") != Pointer("a")); // Invalid always not equal
}
TEST(Pointer, Create) {
Document d;
{
Value* v = &Pointer("").Create(d, d.GetAllocator());
EXPECT_EQ(&d, v);
}
{
Value* v = &Pointer("/foo").Create(d, d.GetAllocator());
EXPECT_EQ(&d["foo"], v);
}
{
Value* v = &Pointer("/foo/0").Create(d, d.GetAllocator());
EXPECT_EQ(&d["foo"][0], v);
}
{
Value* v = &Pointer("/foo/-").Create(d, d.GetAllocator());
EXPECT_EQ(&d["foo"][1], v);
}
{
Value* v = &Pointer("/foo/-/-").Create(d, d.GetAllocator());
// "foo/-" is a newly created null value x.
// "foo/-/-" finds that x is not an array, it converts x to empty object
// and treats - as "-" member name
EXPECT_EQ(&d["foo"][2]["-"], v);
}
{
// Document with no allocator
Value* v = &Pointer("/foo/-").Create(d);
EXPECT_EQ(&d["foo"][3], v);
}
{
// Value (not document) must give allocator
Value* v = &Pointer("/-").Create(d["foo"], d.GetAllocator());
EXPECT_EQ(&d["foo"][4], v);
}
}
TEST(Pointer, Get) {
Document d;
d.Parse(kJson);
EXPECT_EQ(&d, Pointer("").Get(d));
EXPECT_EQ(&d["foo"], Pointer("/foo").Get(d));
EXPECT_EQ(&d["foo"][0], Pointer("/foo/0").Get(d));
EXPECT_EQ(&d[""], Pointer("/").Get(d));
EXPECT_EQ(&d["a/b"], Pointer("/a~1b").Get(d));
EXPECT_EQ(&d["c%d"], Pointer("/c%d").Get(d));
EXPECT_EQ(&d["e^f"], Pointer("/e^f").Get(d));
EXPECT_EQ(&d["g|h"], Pointer("/g|h").Get(d));
EXPECT_EQ(&d["i\\j"], Pointer("/i\\j").Get(d));
EXPECT_EQ(&d["k\"l"], Pointer("/k\"l").Get(d));
EXPECT_EQ(&d[" "], Pointer("/ ").Get(d));
EXPECT_EQ(&d["m~n"], Pointer("/m~0n").Get(d));
EXPECT_TRUE(Pointer("/abc").Get(d) == 0);
size_t unresolvedTokenIndex;
EXPECT_TRUE(Pointer("/foo/2").Get(d, &unresolvedTokenIndex) == 0); // Out of boundary
EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(Pointer("/foo/a").Get(d, &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a"
EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(Pointer("/foo/0/0").Get(d, &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
EXPECT_EQ(2u, unresolvedTokenIndex);
EXPECT_TRUE(Pointer("/foo/0/a").Get(d, &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
EXPECT_EQ(2u, unresolvedTokenIndex);
}
TEST(Pointer, GetWithDefault) {
Document d;
d.Parse(kJson);
// Value version
Document::AllocatorType& a = d.GetAllocator();
const Value v("qux");
EXPECT_TRUE(Value("bar") == Pointer("/foo/0").GetWithDefault(d, v, a));
EXPECT_TRUE(Value("baz") == Pointer("/foo/1").GetWithDefault(d, v, a));
EXPECT_TRUE(Value("qux") == Pointer("/foo/2").GetWithDefault(d, v, a));
EXPECT_TRUE(Value("last") == Pointer("/foo/-").GetWithDefault(d, Value("last").Move(), a));
EXPECT_STREQ("last", d["foo"][3].GetString());
EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, Value().Move(), a).IsNull());
EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, "x", a).IsNull());
// Generic version
EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -1, a).GetInt());
EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -2, a).GetInt());
EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x87654321, a).GetUint());
EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x12345678, a).GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64, a).GetInt64());
EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64 + 1, a).GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64, a).GetUint64());
EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64 - 1, a).GetUint64());
EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, true, a).IsTrue());
EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, false, a).IsTrue());
EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, false, a).IsFalse());
EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, true, a).IsFalse());
// StringRef version
EXPECT_STREQ("Hello", Pointer("/foo/hello").GetWithDefault(d, "Hello", a).GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
EXPECT_STREQ("World", Pointer("/foo/world").GetWithDefault(d, buffer, a).GetString());
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
#if RAPIDJSON_HAS_STDSTRING
EXPECT_STREQ("C++", Pointer("/foo/C++").GetWithDefault(d, std::string("C++"), a).GetString());
#endif
}
TEST(Pointer, GetWithDefault_NoAllocator) {
Document d;
d.Parse(kJson);
// Value version
const Value v("qux");
EXPECT_TRUE(Value("bar") == Pointer("/foo/0").GetWithDefault(d, v));
EXPECT_TRUE(Value("baz") == Pointer("/foo/1").GetWithDefault(d, v));
EXPECT_TRUE(Value("qux") == Pointer("/foo/2").GetWithDefault(d, v));
EXPECT_TRUE(Value("last") == Pointer("/foo/-").GetWithDefault(d, Value("last").Move()));
EXPECT_STREQ("last", d["foo"][3].GetString());
EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, Value().Move()).IsNull());
EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, "x").IsNull());
// Generic version
EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -1).GetInt());
EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -2).GetInt());
EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x87654321).GetUint());
EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x12345678).GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64).GetInt64());
EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64 + 1).GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64).GetUint64());
EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64 - 1).GetUint64());
EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, true).IsTrue());
EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, false).IsTrue());
EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, false).IsFalse());
EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, true).IsFalse());
// StringRef version
EXPECT_STREQ("Hello", Pointer("/foo/hello").GetWithDefault(d, "Hello").GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
EXPECT_STREQ("World", Pointer("/foo/world").GetWithDefault(d, buffer).GetString());
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
#if RAPIDJSON_HAS_STDSTRING
EXPECT_STREQ("C++", Pointer("/foo/C++").GetWithDefault(d, std::string("C++")).GetString());
#endif
}
TEST(Pointer, Set) {
Document d;
d.Parse(kJson);
Document::AllocatorType& a = d.GetAllocator();
// Value version
Pointer("/foo/0").Set(d, Value(123).Move(), a);
EXPECT_EQ(123, d["foo"][0].GetInt());
Pointer("/foo/-").Set(d, Value(456).Move(), a);
EXPECT_EQ(456, d["foo"][2].GetInt());
Pointer("/foo/null").Set(d, Value().Move(), a);
EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
// Const Value version
const Value foo(d["foo"], a);
Pointer("/clone").Set(d, foo, a);
EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
// Generic version
Pointer("/foo/int").Set(d, -1, a);
EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
Pointer("/foo/uint").Set(d, 0x87654321, a);
EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
Pointer("/foo/int64").Set(d, i64, a);
EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
Pointer("/foo/uint64").Set(d, u64, a);
EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
Pointer("/foo/true").Set(d, true, a);
EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
Pointer("/foo/false").Set(d, false, a);
EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
// StringRef version
Pointer("/foo/hello").Set(d, "Hello", a);
EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
Pointer("/foo/world").Set(d, buffer, a);
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
#if RAPIDJSON_HAS_STDSTRING
Pointer("/foo/c++").Set(d, std::string("C++"), a);
EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
#endif
}
TEST(Pointer, Set_NoAllocator) {
Document d;
d.Parse(kJson);
// Value version
Pointer("/foo/0").Set(d, Value(123).Move());
EXPECT_EQ(123, d["foo"][0].GetInt());
Pointer("/foo/-").Set(d, Value(456).Move());
EXPECT_EQ(456, d["foo"][2].GetInt());
Pointer("/foo/null").Set(d, Value().Move());
EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
// Const Value version
const Value foo(d["foo"], d.GetAllocator());
Pointer("/clone").Set(d, foo);
EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
// Generic version
Pointer("/foo/int").Set(d, -1);
EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
Pointer("/foo/uint").Set(d, 0x87654321);
EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
Pointer("/foo/int64").Set(d, i64);
EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
Pointer("/foo/uint64").Set(d, u64);
EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
Pointer("/foo/true").Set(d, true);
EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
Pointer("/foo/false").Set(d, false);
EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
// StringRef version
Pointer("/foo/hello").Set(d, "Hello");
EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
Pointer("/foo/world").Set(d, buffer);
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
#if RAPIDJSON_HAS_STDSTRING
Pointer("/foo/c++").Set(d, std::string("C++"));
EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
#endif
}
TEST(Pointer, Swap) {
Document d;
d.Parse(kJson);
Document::AllocatorType& a = d.GetAllocator();
Pointer("/foo/0").Swap(d, *Pointer("/foo/1").Get(d), a);
EXPECT_STREQ("baz", d["foo"][0].GetString());
EXPECT_STREQ("bar", d["foo"][1].GetString());
}
TEST(Pointer, Swap_NoAllocator) {
Document d;
d.Parse(kJson);
Pointer("/foo/0").Swap(d, *Pointer("/foo/1").Get(d));
EXPECT_STREQ("baz", d["foo"][0].GetString());
EXPECT_STREQ("bar", d["foo"][1].GetString());
}
TEST(Pointer, Erase) {
Document d;
d.Parse(kJson);
EXPECT_FALSE(Pointer("").Erase(d));
EXPECT_FALSE(Pointer("/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/nonexist/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/foo/nonexist/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/foo/0/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/foo/0/nonexist/nonexist").Erase(d));
EXPECT_FALSE(Pointer("/foo/2/nonexist").Erase(d));
EXPECT_TRUE(Pointer("/foo/0").Erase(d));
EXPECT_EQ(1u, d["foo"].Size());
EXPECT_STREQ("baz", d["foo"][0].GetString());
EXPECT_TRUE(Pointer("/foo/0").Erase(d));
EXPECT_TRUE(d["foo"].Empty());
EXPECT_TRUE(Pointer("/foo").Erase(d));
EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
Pointer("/a/0/b/0").Create(d);
EXPECT_TRUE(Pointer("/a/0/b/0").Get(d) != 0);
EXPECT_TRUE(Pointer("/a/0/b/0").Erase(d));
EXPECT_TRUE(Pointer("/a/0/b/0").Get(d) == 0);
EXPECT_TRUE(Pointer("/a/0/b").Get(d) != 0);
EXPECT_TRUE(Pointer("/a/0/b").Erase(d));
EXPECT_TRUE(Pointer("/a/0/b").Get(d) == 0);
EXPECT_TRUE(Pointer("/a/0").Get(d) != 0);
EXPECT_TRUE(Pointer("/a/0").Erase(d));
EXPECT_TRUE(Pointer("/a/0").Get(d) == 0);
EXPECT_TRUE(Pointer("/a").Get(d) != 0);
EXPECT_TRUE(Pointer("/a").Erase(d));
EXPECT_TRUE(Pointer("/a").Get(d) == 0);
}
TEST(Pointer, CreateValueByPointer) {
Document d;
Document::AllocatorType& a = d.GetAllocator();
{
Value& v = CreateValueByPointer(d, Pointer("/foo/0"), a);
EXPECT_EQ(&d["foo"][0], &v);
}
{
Value& v = CreateValueByPointer(d, "/foo/1", a);
EXPECT_EQ(&d["foo"][1], &v);
}
}
TEST(Pointer, CreateValueByPointer_NoAllocator) {
Document d;
{
Value& v = CreateValueByPointer(d, Pointer("/foo/0"));
EXPECT_EQ(&d["foo"][0], &v);
}
{
Value& v = CreateValueByPointer(d, "/foo/1");
EXPECT_EQ(&d["foo"][1], &v);
}
}
TEST(Pointer, GetValueByPointer) {
Document d;
d.Parse(kJson);
EXPECT_EQ(&d["foo"][0], GetValueByPointer(d, Pointer("/foo/0")));
EXPECT_EQ(&d["foo"][0], GetValueByPointer(d, "/foo/0"));
size_t unresolvedTokenIndex;
EXPECT_TRUE(GetValueByPointer(d, "/foo/2", &unresolvedTokenIndex) == 0); // Out of boundary
EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(d, "/foo/a", &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a"
EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(d, "/foo/0/0", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
EXPECT_EQ(2u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(d, "/foo/0/a", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
EXPECT_EQ(2u, unresolvedTokenIndex);
// const version
const Value& v = d;
EXPECT_EQ(&d["foo"][0], GetValueByPointer(v, Pointer("/foo/0")));
EXPECT_EQ(&d["foo"][0], GetValueByPointer(v, "/foo/0"));
EXPECT_TRUE(GetValueByPointer(v, "/foo/2", &unresolvedTokenIndex) == 0); // Out of boundary
EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(v, "/foo/a", &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a"
EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(v, "/foo/0/0", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
EXPECT_EQ(2u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(v, "/foo/0/a", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
EXPECT_EQ(2u, unresolvedTokenIndex);
}
TEST(Pointer, GetValueByPointerWithDefault_Pointer) {
Document d;
d.Parse(kJson);
Document::AllocatorType& a = d.GetAllocator();
const Value v("qux");
EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v, a));
EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v, a));
EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, Pointer("/foo/1"), v, a));
EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, Pointer("/foo/2"), v, a));
EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, Pointer("/foo/-"), Value("last").Move(), a));
EXPECT_STREQ("last", d["foo"][3].GetString());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), Value().Move(), a).IsNull());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), "x", a).IsNull());
// Generic version
EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -1, a).GetInt());
EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -2, a).GetInt());
EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x87654321, a).GetUint());
EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x12345678, a).GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64, a).GetInt64());
EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64 + 1, a).GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64, a).GetUint64());
EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64 - 1, a).GetUint64());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), true, a).IsTrue());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), false, a).IsTrue());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), false, a).IsFalse());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), true, a).IsFalse());
// StringRef version
EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, Pointer("/foo/hello"), "Hello", a).GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
EXPECT_STREQ("World", GetValueByPointerWithDefault(d, Pointer("/foo/world"), buffer, a).GetString());
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, Pointer("/foo/world"))->GetString());
#if RAPIDJSON_HAS_STDSTRING
EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, Pointer("/foo/C++"), std::string("C++"), a).GetString());
#endif
}
TEST(Pointer, GetValueByPointerWithDefault_String) {
Document d;
d.Parse(kJson);
Document::AllocatorType& a = d.GetAllocator();
const Value v("qux");
EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v, a));
EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v, a));
EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, "/foo/1", v, a));
EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, "/foo/2", v, a));
EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, "/foo/-", Value("last").Move(), a));
EXPECT_STREQ("last", d["foo"][3].GetString());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", Value().Move(), a).IsNull());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", "x", a).IsNull());
// Generic version
EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -1, a).GetInt());
EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -2, a).GetInt());
EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x87654321, a).GetUint());
EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x12345678, a).GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64, a).GetInt64());
EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64 + 1, a).GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64, a).GetUint64());
EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64 - 1, a).GetUint64());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", true, a).IsTrue());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", false, a).IsTrue());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", false, a).IsFalse());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", true, a).IsFalse());
// StringRef version
EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, "/foo/hello", "Hello", a).GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
EXPECT_STREQ("World", GetValueByPointerWithDefault(d, "/foo/world", buffer, a).GetString());
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
#if RAPIDJSON_HAS_STDSTRING
EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, "/foo/C++", std::string("C++"), a).GetString());
#endif
}
TEST(Pointer, GetValueByPointerWithDefault_Pointer_NoAllocator) {
Document d;
d.Parse(kJson);
const Value v("qux");
EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v));
EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v));
EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, Pointer("/foo/1"), v));
EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, Pointer("/foo/2"), v));
EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, Pointer("/foo/-"), Value("last").Move()));
EXPECT_STREQ("last", d["foo"][3].GetString());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), Value().Move()).IsNull());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), "x").IsNull());
// Generic version
EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -1).GetInt());
EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -2).GetInt());
EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x87654321).GetUint());
EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x12345678).GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64).GetInt64());
EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64 + 1).GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64).GetUint64());
EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64 - 1).GetUint64());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), true).IsTrue());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), false).IsTrue());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), false).IsFalse());
EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), true).IsFalse());
// StringRef version
EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, Pointer("/foo/hello"), "Hello").GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
EXPECT_STREQ("World", GetValueByPointerWithDefault(d, Pointer("/foo/world"), buffer).GetString());
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, Pointer("/foo/world"))->GetString());
#if RAPIDJSON_HAS_STDSTRING
EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, Pointer("/foo/C++"), std::string("C++")).GetString());
#endif
}
TEST(Pointer, GetValueByPointerWithDefault_String_NoAllocator) {
Document d;
d.Parse(kJson);
const Value v("qux");
EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v));
EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v));
EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, "/foo/1", v));
EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, "/foo/2", v));
EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, "/foo/-", Value("last").Move()));
EXPECT_STREQ("last", d["foo"][3].GetString());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", Value().Move()).IsNull());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", "x").IsNull());
// Generic version
EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -1).GetInt());
EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -2).GetInt());
EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x87654321).GetUint());
EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x12345678).GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64).GetInt64());
EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64 + 1).GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64).GetUint64());
EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64 - 1).GetUint64());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", true).IsTrue());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", false).IsTrue());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", false).IsFalse());
EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", true).IsFalse());
// StringRef version
EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, "/foo/hello", "Hello").GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
EXPECT_STREQ("World", GetValueByPointerWithDefault(d, "/foo/world", buffer).GetString());
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
#if RAPIDJSON_HAS_STDSTRING
EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, Pointer("/foo/C++"), std::string("C++")).GetString());
#endif
}
TEST(Pointer, SetValueByPointer_Pointer) {
Document d;
d.Parse(kJson);
Document::AllocatorType& a = d.GetAllocator();
// Value version
SetValueByPointer(d, Pointer("/foo/0"), Value(123).Move(), a);
EXPECT_EQ(123, d["foo"][0].GetInt());
SetValueByPointer(d, Pointer("/foo/null"), Value().Move(), a);
EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
// Const Value version
const Value foo(d["foo"], d.GetAllocator());
SetValueByPointer(d, Pointer("/clone"), foo, a);
EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
// Generic version
SetValueByPointer(d, Pointer("/foo/int"), -1, a);
EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
SetValueByPointer(d, Pointer("/foo/uint"), 0x87654321, a);
EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
SetValueByPointer(d, Pointer("/foo/int64"), i64, a);
EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
SetValueByPointer(d, Pointer("/foo/uint64"), u64, a);
EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
SetValueByPointer(d, Pointer("/foo/true"), true, a);
EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
SetValueByPointer(d, Pointer("/foo/false"), false, a);
EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
// StringRef version
SetValueByPointer(d, Pointer("/foo/hello"), "Hello", a);
EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
SetValueByPointer(d, Pointer("/foo/world"), buffer, a);
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
#if RAPIDJSON_HAS_STDSTRING
SetValueByPointer(d, Pointer("/foo/c++"), std::string("C++"), a);
EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
#endif
}
TEST(Pointer, SetValueByPointer_String) {
Document d;
d.Parse(kJson);
Document::AllocatorType& a = d.GetAllocator();
// Value version
SetValueByPointer(d, "/foo/0", Value(123).Move(), a);
EXPECT_EQ(123, d["foo"][0].GetInt());
SetValueByPointer(d, "/foo/null", Value().Move(), a);
EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
// Const Value version
const Value foo(d["foo"], d.GetAllocator());
SetValueByPointer(d, "/clone", foo, a);
EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
// Generic version
SetValueByPointer(d, "/foo/int", -1, a);
EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
SetValueByPointer(d, "/foo/uint", 0x87654321, a);
EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
SetValueByPointer(d, "/foo/int64", i64, a);
EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
SetValueByPointer(d, "/foo/uint64", u64, a);
EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
SetValueByPointer(d, "/foo/true", true, a);
EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
SetValueByPointer(d, "/foo/false", false, a);
EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
// StringRef version
SetValueByPointer(d, "/foo/hello", "Hello", a);
EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
SetValueByPointer(d, "/foo/world", buffer, a);
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
#if RAPIDJSON_HAS_STDSTRING
SetValueByPointer(d, "/foo/c++", std::string("C++"), a);
EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
#endif
}
TEST(Pointer, SetValueByPointer_Pointer_NoAllocator) {
Document d;
d.Parse(kJson);
// Value version
SetValueByPointer(d, Pointer("/foo/0"), Value(123).Move());
EXPECT_EQ(123, d["foo"][0].GetInt());
SetValueByPointer(d, Pointer("/foo/null"), Value().Move());
EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
// Const Value version
const Value foo(d["foo"], d.GetAllocator());
SetValueByPointer(d, Pointer("/clone"), foo);
EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
// Generic version
SetValueByPointer(d, Pointer("/foo/int"), -1);
EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
SetValueByPointer(d, Pointer("/foo/uint"), 0x87654321);
EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
SetValueByPointer(d, Pointer("/foo/int64"), i64);
EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
SetValueByPointer(d, Pointer("/foo/uint64"), u64);
EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
SetValueByPointer(d, Pointer("/foo/true"), true);
EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
SetValueByPointer(d, Pointer("/foo/false"), false);
EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
// StringRef version
SetValueByPointer(d, Pointer("/foo/hello"), "Hello");
EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
SetValueByPointer(d, Pointer("/foo/world"), buffer);
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
#if RAPIDJSON_HAS_STDSTRING
SetValueByPointer(d, Pointer("/foo/c++"), std::string("C++"));
EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
#endif
}
TEST(Pointer, SetValueByPointer_String_NoAllocator) {
Document d;
d.Parse(kJson);
// Value version
SetValueByPointer(d, "/foo/0", Value(123).Move());
EXPECT_EQ(123, d["foo"][0].GetInt());
SetValueByPointer(d, "/foo/null", Value().Move());
EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
// Const Value version
const Value foo(d["foo"], d.GetAllocator());
SetValueByPointer(d, "/clone", foo);
EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
// Generic version
SetValueByPointer(d, "/foo/int", -1);
EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
SetValueByPointer(d, "/foo/uint", 0x87654321);
EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
SetValueByPointer(d, "/foo/int64", i64);
EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
SetValueByPointer(d, "/foo/uint64", u64);
EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
SetValueByPointer(d, "/foo/true", true);
EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
SetValueByPointer(d, "/foo/false", false);
EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
// StringRef version
SetValueByPointer(d, "/foo/hello", "Hello");
EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
// Copy string version
{
char buffer[256];
strcpy(buffer, "World");
SetValueByPointer(d, "/foo/world", buffer);
memset(buffer, 0, sizeof(buffer));
}
EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
#if RAPIDJSON_HAS_STDSTRING
SetValueByPointer(d, "/foo/c++", std::string("C++"));
EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
#endif
}
TEST(Pointer, SwapValueByPointer) {
Document d;
d.Parse(kJson);
Document::AllocatorType& a = d.GetAllocator();
SwapValueByPointer(d, Pointer("/foo/0"), *GetValueByPointer(d, "/foo/1"), a);
EXPECT_STREQ("baz", d["foo"][0].GetString());
EXPECT_STREQ("bar", d["foo"][1].GetString());
SwapValueByPointer(d, "/foo/0", *GetValueByPointer(d, "/foo/1"), a);
EXPECT_STREQ("bar", d["foo"][0].GetString());
EXPECT_STREQ("baz", d["foo"][1].GetString());
}
TEST(Pointer, SwapValueByPointer_NoAllocator) {
Document d;
d.Parse(kJson);
SwapValueByPointer(d, Pointer("/foo/0"), *GetValueByPointer(d, "/foo/1"));
EXPECT_STREQ("baz", d["foo"][0].GetString());
EXPECT_STREQ("bar", d["foo"][1].GetString());
SwapValueByPointer(d, "/foo/0", *GetValueByPointer(d, "/foo/1"));
EXPECT_STREQ("bar", d["foo"][0].GetString());
EXPECT_STREQ("baz", d["foo"][1].GetString());
}
TEST(Pointer, EraseValueByPointer_Pointer) {
Document d;
d.Parse(kJson);
EXPECT_FALSE(EraseValueByPointer(d, Pointer("")));
EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo/0")));
EXPECT_EQ(1u, d["foo"].Size());
EXPECT_STREQ("baz", d["foo"][0].GetString());
EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo/0")));
EXPECT_TRUE(d["foo"].Empty());
EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo")));
EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
}
TEST(Pointer, EraseValueByPointer_String) {
Document d;
d.Parse(kJson);
EXPECT_FALSE(EraseValueByPointer(d, ""));
EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
EXPECT_TRUE(EraseValueByPointer(d, "/foo/0"));
EXPECT_EQ(1u, d["foo"].Size());
EXPECT_STREQ("baz", d["foo"][0].GetString());
EXPECT_TRUE(EraseValueByPointer(d, "/foo/0"));
EXPECT_TRUE(d["foo"].Empty());
EXPECT_TRUE(EraseValueByPointer(d, "/foo"));
EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
}
TEST(Pointer, Ambiguity) {
{
Document d;
d.Parse("{\"0\" : [123]}");
EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt());
Pointer("/0/a").Set(d, 456); // Change array [123] to object {456}
EXPECT_EQ(456, Pointer("/0/a").Get(d)->GetInt());
}
{
Document d;
EXPECT_FALSE(d.Parse("[{\"0\": 123}]").HasParseError());
EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt());
Pointer("/0/1").Set(d, 456); // 1 is treated as "1" to index object
EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt());
EXPECT_EQ(456, Pointer("/0/1").Get(d)->GetInt());
}
}
TEST(Pointer, LessThan) {
static const struct {
const char *str;
bool valid;
} pointers[] = {
{ "/a/b", true },
{ "/a", true },
{ "/d/1", true },
{ "/d/2/z", true },
{ "/d/2/3", true },
{ "/d/2", true },
{ "/a/c", true },
{ "/e/f~g", false },
{ "/d/2/zz", true },
{ "/d/1", true },
{ "/d/2/z", true },
{ "/e/f~~g", false },
{ "/e/f~0g", true },
{ "/e/f~1g", true },
{ "/e/f.g", true },
{ "", true }
};
static const char *ordered_pointers[] = {
"",
"/a",
"/a/b",
"/a/c",
"/d/1",
"/d/1",
"/d/2",
"/e/f.g",
"/e/f~1g",
"/e/f~0g",
"/d/2/3",
"/d/2/z",
"/d/2/z",
"/d/2/zz",
NULL, // was invalid "/e/f~g"
NULL // was invalid "/e/f~~g"
};
typedef MemoryPoolAllocator<> AllocatorType;
typedef GenericPointer<Value, AllocatorType> PointerType;
typedef std::multimap<PointerType, size_t> PointerMap;
PointerMap map;
PointerMap::iterator it;
AllocatorType allocator;
size_t i;
EXPECT_EQ(sizeof(pointers) / sizeof(pointers[0]),
sizeof(ordered_pointers) / sizeof(ordered_pointers[0]));
for (i = 0; i < sizeof(pointers) / sizeof(pointers[0]); ++i) {
it = map.insert(PointerMap::value_type(PointerType(pointers[i].str, &allocator), i));
if (!it->first.IsValid()) {
EXPECT_EQ(++it, map.end());
}
}
for (i = 0, it = map.begin(); it != map.end(); ++it, ++i) {
EXPECT_TRUE(it->second < sizeof(pointers) / sizeof(pointers[0]));
EXPECT_EQ(it->first.IsValid(), pointers[it->second].valid);
EXPECT_TRUE(i < sizeof(ordered_pointers) / sizeof(ordered_pointers[0]));
EXPECT_EQ(it->first.IsValid(), !!ordered_pointers[i]);
if (it->first.IsValid()) {
std::stringstream ss;
OStreamWrapper os(ss);
EXPECT_TRUE(it->first.Stringify(os));
EXPECT_EQ(ss.str(), pointers[it->second].str);
EXPECT_EQ(ss.str(), ordered_pointers[i]);
}
}
}
// https://github.com/Tencent/rapidjson/issues/483
namespace myjson {
class MyAllocator
{
public:
static const bool kNeedFree = true;
void * Malloc(size_t _size) { return malloc(_size); }
void * Realloc(void *_org_p, size_t _org_size, size_t _new_size) { (void)_org_size; return realloc(_org_p, _new_size); }
static void Free(void *_p) { return free(_p); }
};
typedef rapidjson::GenericDocument<
rapidjson::UTF8<>,
rapidjson::MemoryPoolAllocator< MyAllocator >,
MyAllocator
> Document;
typedef rapidjson::GenericPointer<
::myjson::Document::ValueType,
MyAllocator
> Pointer;
typedef ::myjson::Document::ValueType Value;
}
TEST(Pointer, Issue483) {
std::string mystr, path;
myjson::Document document;
myjson::Value value(rapidjson::kStringType);
value.SetString(mystr.c_str(), static_cast<SizeType>(mystr.length()), document.GetAllocator());
myjson::Pointer(path.c_str()).Set(document, value, document.GetAllocator());
}