documenttest.cpp 18.5 KB
Newer Older
1 2 3
// 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.
4
//
5 6
// 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
7
//
8
// http://opensource.org/licenses/MIT
9
//
10 11 12 13
// 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.
14

15 16 17
#include "unittest.h"
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
18 19 20
#include "rapidjson/filereadstream.h"
#include "rapidjson/encodedstream.h"
#include "rapidjson/stringbuffer.h"
21
#include <sstream>
22
#include <algorithm>
23 24 25

using namespace rapidjson;

26 27
template <typename DocumentType>
void ParseCheck(DocumentType& doc) {
Milo Yip's avatar
Milo Yip committed
28
    typedef typename DocumentType::ValueType ValueType;
29

miloyip's avatar
miloyip committed
30
    EXPECT_FALSE(doc.HasParseError());
Milo Yip's avatar
Milo Yip committed
31
    EXPECT_TRUE(static_cast<ParseResult>(doc));
miloyip's avatar
miloyip committed
32

33
    EXPECT_TRUE(doc.IsObject());
34

35
    EXPECT_TRUE(doc.HasMember("hello"));
36
    const ValueType& hello = doc["hello"];
37 38
    EXPECT_TRUE(hello.IsString());
    EXPECT_STREQ("world", hello.GetString());
39

40
    EXPECT_TRUE(doc.HasMember("t"));
41
    const ValueType& t = doc["t"];
42
    EXPECT_TRUE(t.IsTrue());
43

44
    EXPECT_TRUE(doc.HasMember("f"));
45
    const ValueType& f = doc["f"];
46
    EXPECT_TRUE(f.IsFalse());
47

48
    EXPECT_TRUE(doc.HasMember("n"));
49
    const ValueType& n = doc["n"];
50
    EXPECT_TRUE(n.IsNull());
51

52
    EXPECT_TRUE(doc.HasMember("i"));
53
    const ValueType& i = doc["i"];
54 55
    EXPECT_TRUE(i.IsNumber());
    EXPECT_EQ(123, i.GetInt());
56

57
    EXPECT_TRUE(doc.HasMember("pi"));
58
    const ValueType& pi = doc["pi"];
59
    EXPECT_TRUE(pi.IsNumber());
60
    EXPECT_DOUBLE_EQ(3.1416, pi.GetDouble());
61

62
    EXPECT_TRUE(doc.HasMember("a"));
63
    const ValueType& a = doc["a"];
64 65
    EXPECT_TRUE(a.IsArray());
    EXPECT_EQ(4u, a.Size());
Milo Yip's avatar
Milo Yip committed
66 67
    for (SizeType j = 0; j < 4; j++)
        EXPECT_EQ(j + 1, a[j].GetUint());
68 69
}

70 71 72 73 74 75 76
template <typename Allocator, typename StackAllocator>
void ParseTest() {
    typedef GenericDocument<UTF8<>, Allocator, StackAllocator> DocumentType;
    DocumentType doc;

    const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";

miloyip's avatar
miloyip committed
77
    doc.Parse(json);
78 79 80 81
    ParseCheck(doc);

    doc.SetNull();
    StringStream s(json);
miloyip's avatar
miloyip committed
82
    doc.template ParseStream<0>(s);
83 84 85 86
    ParseCheck(doc);

    doc.SetNull();
    char *buffer = strdup(json);
miloyip's avatar
miloyip committed
87
    doc.ParseInsitu(buffer);
88 89 90 91
    ParseCheck(doc);
    free(buffer);
}

92 93 94 95 96 97 98
TEST(Document, Parse) {
    ParseTest<MemoryPoolAllocator<>, CrtAllocator>();
    ParseTest<MemoryPoolAllocator<>, MemoryPoolAllocator<> >();
    ParseTest<CrtAllocator, MemoryPoolAllocator<> >();
    ParseTest<CrtAllocator, CrtAllocator>();
}

99 100 101 102
TEST(Document, UnchangedOnParseError) {
    Document doc;
    doc.SetArray().PushBack(0, doc.GetAllocator());

103
    ParseResult err = doc.Parse("{]");
104
    EXPECT_TRUE(doc.HasParseError());
105 106
    EXPECT_EQ(err.Code(), doc.GetParseError());
    EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
107 108 109
    EXPECT_TRUE(doc.IsArray());
    EXPECT_EQ(doc.Size(), 1u);

110
    err = doc.Parse("{}");
111
    EXPECT_FALSE(doc.HasParseError());
112 113 114
    EXPECT_FALSE(err.IsError());
    EXPECT_EQ(err.Code(), doc.GetParseError());
    EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
115 116 117 118
    EXPECT_TRUE(doc.IsObject());
    EXPECT_EQ(doc.MemberCount(), 0u);
}

119
static FILE* OpenEncodedFile(const char* filename) {
120
    const char *paths[] = {
Milo Yip's avatar
Milo Yip committed
121 122 123 124 125
        "encodings",
        "bin/encodings",
        "../bin/encodings",
        "../../bin/encodings",
        "../../../bin/encodings"
126
    };
127
    char buffer[1024];
128
    for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
Milo Yip's avatar
Milo Yip committed
129
        sprintf(buffer, "%s/%s", paths[i], filename);
130 131 132
        FILE *fp = fopen(buffer, "rb");
        if (fp)
            return fp;
133
    }
134
    return 0;
135 136 137
}

TEST(Document, ParseStream_EncodedInputStream) {
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
    // UTF8 -> UTF16
    FILE* fp = OpenEncodedFile("utf8.json");
    char buffer[256];
    FileReadStream bis(fp, buffer, sizeof(buffer));
    EncodedInputStream<UTF8<>, FileReadStream> eis(bis);

    GenericDocument<UTF16<> > d;
    d.ParseStream<0, UTF8<> >(eis);
    EXPECT_FALSE(d.HasParseError());

    fclose(fp);

    wchar_t expected[] = L"I can eat glass and it doesn't hurt me.";
    GenericValue<UTF16<> >& v = d[L"en"];
    EXPECT_TRUE(v.IsString());
    EXPECT_EQ(sizeof(expected) / sizeof(wchar_t) - 1, v.GetStringLength());
    EXPECT_EQ(0, StrCmp(expected, v.GetString()));

    // UTF16 -> UTF8 in memory
    StringBuffer bos;
    typedef EncodedOutputStream<UTF8<>, StringBuffer> OutputStream;
    OutputStream eos(bos, false);   // Not writing BOM
    {
Milo Yip's avatar
Milo Yip committed
161 162
        Writer<OutputStream, UTF16<>, UTF8<> > writer(eos);
        d.Accept(writer);
163
    }
Milo Yip's avatar
Milo Yip committed
164 165 166 167 168 169 170 171 172 173 174 175

    // Condense the original file and compare.
    fp = OpenEncodedFile("utf8.json");
    FileReadStream is(fp, buffer, sizeof(buffer));
    Reader reader;
    StringBuffer bos2;
    Writer<StringBuffer> writer2(bos2);
    reader.Parse(is, writer2);
    fclose(fp);

    EXPECT_EQ(bos.GetSize(), bos2.GetSize());
    EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
176 177 178
}

TEST(Document, ParseStream_AutoUTFInputStream) {
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    // Any -> UTF8
    FILE* fp = OpenEncodedFile("utf32be.json");
    char buffer[256];
    FileReadStream bis(fp, buffer, sizeof(buffer));
    AutoUTFInputStream<unsigned, FileReadStream> eis(bis);

    Document d;
    d.ParseStream<0, AutoUTF<unsigned> >(eis);
    EXPECT_FALSE(d.HasParseError());

    fclose(fp);

    char expected[] = "I can eat glass and it doesn't hurt me.";
    Value& v = d["en"];
    EXPECT_TRUE(v.IsString());
    EXPECT_EQ(sizeof(expected) - 1, v.GetStringLength());
    EXPECT_EQ(0, StrCmp(expected, v.GetString()));

    // UTF8 -> UTF8 in memory
    StringBuffer bos;
    Writer<StringBuffer> writer(bos);
    d.Accept(writer);

Milo Yip's avatar
Milo Yip committed
202 203 204 205 206 207 208 209 210 211 212
    // Condense the original file and compare.
    fp = OpenEncodedFile("utf8.json");
    FileReadStream is(fp, buffer, sizeof(buffer));
    Reader reader;
    StringBuffer bos2;
    Writer<StringBuffer> writer2(bos2);
    reader.Parse(is, writer2);
    fclose(fp);

    EXPECT_EQ(bos.GetSize(), bos2.GetSize());
    EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
213 214
}

215
TEST(Document, Swap) {
216 217
    Document d1;
    Document::AllocatorType& a = d1.GetAllocator();
218

219
    d1.SetArray().PushBack(1, a).PushBack(2, a);
220

221 222
    Value o;
    o.SetObject().AddMember("a", 1, a);
223

224
    // Swap between Document and Value
225 226
    // d1.Swap(o); // doesn't compile
    o.Swap(d1);
227 228
    EXPECT_TRUE(d1.IsObject());
    EXPECT_TRUE(o.IsArray());
229

230 231 232 233 234 235
    // Swap between Document and Document
    Document d2;
    d2.SetArray().PushBack(3, a);
    d1.Swap(d2);
    EXPECT_TRUE(d1.IsArray());
    EXPECT_TRUE(d2.IsObject());
236 237 238 239 240 241 242 243 244 245
    EXPECT_EQ(&d2.GetAllocator(), &a);

    // reset value
    Value().Swap(d1);
    EXPECT_TRUE(d1.IsNull());

    // reset document, including allocator
    Document().Swap(d2);
    EXPECT_TRUE(d2.IsNull());
    EXPECT_NE(&d2.GetAllocator(), &a);
246 247 248 249 250 251 252 253 254 255 256

    // testing std::swap compatibility
    d1.SetBool(true);
    using std::swap;
    swap(d1, d2);
    EXPECT_TRUE(d1.IsNull());
    EXPECT_TRUE(d2.IsTrue());

    swap(o, d2);
    EXPECT_TRUE(o.IsTrue());
    EXPECT_TRUE(d2.IsArray());
257 258
}

259

260
// This should be slow due to assignment in inner-loop.
261
struct OutputStringStream : public std::ostringstream {
262
    typedef char Ch;
263

Milo Yip's avatar
Milo Yip committed
264 265
    virtual ~OutputStringStream();

266 267 268 269
    void Put(char c) {
        put(c);
    }
    void Flush() {}
270 271
};

Milo Yip's avatar
Milo Yip committed
272 273
OutputStringStream::~OutputStringStream() {}

274
TEST(Document, AcceptWriter) {
275 276
    Document doc;
    doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
277

278 279 280
    OutputStringStream os;
    Writer<OutputStringStream> writer(os);
    doc.Accept(writer);
281

282
    EXPECT_EQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,4]}", os.str());
283
}
284

Milo Yip's avatar
Milo Yip committed
285
TEST(Document, UserBuffer) {
286
    typedef GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > DocumentType;
Milo Yip's avatar
Milo Yip committed
287 288 289 290
    char valueBuffer[4096];
    char parseBuffer[1024];
    MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer));
    MemoryPoolAllocator<> parseAllocator(parseBuffer, sizeof(parseBuffer));
291
    DocumentType doc(&valueAllocator, sizeof(parseBuffer) / 2, &parseAllocator);
Milo Yip's avatar
Milo Yip committed
292 293 294 295
    doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
    EXPECT_FALSE(doc.HasParseError());
    EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer));
    EXPECT_LE(parseAllocator.Size(), sizeof(parseBuffer));
296

miloyip's avatar
miloyip committed
297
    // Cover MemoryPoolAllocator::Capacity()
298 299
    EXPECT_LE(valueAllocator.Size(), valueAllocator.Capacity());
    EXPECT_LE(parseAllocator.Size(), parseAllocator.Capacity());
Milo Yip's avatar
Milo Yip committed
300 301
}

302 303 304 305 306 307 308 309 310 311 312 313
// Issue 226: Value of string type should not point to NULL
TEST(Document, AssertAcceptInvalidNameType) {
    Document doc;
    doc.SetObject();
    doc.AddMember("a", 0, doc.GetAllocator());
    doc.FindMember("a")->name.SetNull(); // Change name to non-string type.

    OutputStringStream os;
    Writer<OutputStringStream> writer(os);
    ASSERT_THROW(doc.Accept(writer), AssertException);
}

314
// Issue 44:    SetStringRaw doesn't work with wchar_t
315
TEST(Document, UTF16_Document) {
316 317
    GenericDocument< UTF16<> > json;
    json.Parse<kParseValidateEncodingFlag>(L"[{\"created_at\":\"Wed Oct 30 17:13:20 +0000 2012\"}]");
318

319
    ASSERT_TRUE(json.IsArray());
320
    GenericValue< UTF16<> >& v = json[0];
321
    ASSERT_TRUE(v.IsObject());
322

323 324
    GenericValue< UTF16<> >& s = v[L"created_at"];
    ASSERT_TRUE(s.IsString());
325

326
    EXPECT_EQ(0, memcmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString(), (s.GetStringLength() + 1) * sizeof(wchar_t)));
327
}
328

329 330
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS

331 332 333
#include <type_traits>

TEST(Document, Traits) {
334 335 336 337 338 339 340 341 342 343
    static_assert(std::is_constructible<Document>::value, "");
    static_assert(std::is_default_constructible<Document>::value, "");
#ifndef _MSC_VER
    static_assert(!std::is_copy_constructible<Document>::value, "");
#endif
    static_assert(std::is_move_constructible<Document>::value, "");

    static_assert(!std::is_nothrow_constructible<Document>::value, "");
    static_assert(!std::is_nothrow_default_constructible<Document>::value, "");
#ifndef _MSC_VER
344
    static_assert(!std::is_nothrow_copy_constructible<Document>::value, "");
345 346 347 348 349
    static_assert(std::is_nothrow_move_constructible<Document>::value, "");
#endif

    static_assert(std::is_assignable<Document,Document>::value, "");
#ifndef _MSC_VER
350
  static_assert(!std::is_copy_assignable<Document>::value, "");
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
#endif
    static_assert(std::is_move_assignable<Document>::value, "");

#ifndef _MSC_VER
    static_assert(std::is_nothrow_assignable<Document, Document>::value, "");
#endif
    static_assert(!std::is_nothrow_copy_assignable<Document>::value, "");
#ifndef _MSC_VER
    static_assert(std::is_nothrow_move_assignable<Document>::value, "");
#endif

    static_assert( std::is_destructible<Document>::value, "");
#ifndef _MSC_VER
    static_assert(std::is_nothrow_destructible<Document>::value, "");
#endif
366 367
}

368 369 370 371 372 373 374 375 376 377 378
template <typename Allocator>
struct DocumentMove: public ::testing::Test {
};

typedef ::testing::Types< CrtAllocator, MemoryPoolAllocator<> > MoveAllocatorTypes;
TYPED_TEST_CASE(DocumentMove, MoveAllocatorTypes);

TYPED_TEST(DocumentMove, MoveConstructor) {
    typedef TypeParam Allocator;
    typedef GenericDocument<UTF8<>, Allocator> Document;
    Allocator allocator;
379 380 381 382 383 384 385 386

    Document a(&allocator);
    a.Parse("[\"one\", \"two\", \"three\"]");
    EXPECT_FALSE(a.HasParseError());
    EXPECT_TRUE(a.IsArray());
    EXPECT_EQ(3u, a.Size());
    EXPECT_EQ(&a.GetAllocator(), &allocator);

387
    // Document b(a); // does not compile (!is_copy_constructible)
388 389 390 391
    Document b(std::move(a));
    EXPECT_TRUE(a.IsNull());
    EXPECT_TRUE(b.IsArray());
    EXPECT_EQ(3u, b.Size());
392
    EXPECT_THROW(a.GetAllocator(), AssertException);
393 394 395 396 397 398 399
    EXPECT_EQ(&b.GetAllocator(), &allocator);

    b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
    EXPECT_FALSE(b.HasParseError());
    EXPECT_TRUE(b.IsObject());
    EXPECT_EQ(2u, b.MemberCount());

400
    // Document c = a; // does not compile (!is_copy_constructible)
401 402 403 404
    Document c = std::move(b);
    EXPECT_TRUE(b.IsNull());
    EXPECT_TRUE(c.IsObject());
    EXPECT_EQ(2u, c.MemberCount());
405
    EXPECT_THROW(b.GetAllocator(), AssertException);
406 407 408
    EXPECT_EQ(&c.GetAllocator(), &allocator);
}

409 410 411
TYPED_TEST(DocumentMove, MoveConstructorParseError) {
    typedef TypeParam Allocator;
    typedef GenericDocument<UTF8<>, Allocator> Document;
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437

    ParseResult noError;
    Document a;
    a.Parse("{ 4 = 4]");
    ParseResult error(a.GetParseError(), a.GetErrorOffset());
    EXPECT_TRUE(a.HasParseError());
    EXPECT_NE(error.Code(), noError.Code());
    EXPECT_NE(error.Offset(), noError.Offset());

    Document b(std::move(a));
    EXPECT_FALSE(a.HasParseError());
    EXPECT_TRUE(b.HasParseError());
    EXPECT_EQ(a.GetParseError(), noError.Code());
    EXPECT_EQ(b.GetParseError(), error.Code());
    EXPECT_EQ(a.GetErrorOffset(), noError.Offset());
    EXPECT_EQ(b.GetErrorOffset(), error.Offset());

    Document c(std::move(b));
    EXPECT_FALSE(b.HasParseError());
    EXPECT_TRUE(c.HasParseError());
    EXPECT_EQ(b.GetParseError(), noError.Code());
    EXPECT_EQ(c.GetParseError(), error.Code());
    EXPECT_EQ(b.GetErrorOffset(), noError.Offset());
    EXPECT_EQ(c.GetErrorOffset(), error.Offset());
}

438 439 440 441
// This test does not properly use parsing, just for testing.
// It must call ClearStack() explicitly to prevent memory leak.
// But here we cannot as ClearStack() is private.
#if 0
442 443
TYPED_TEST(DocumentMove, MoveConstructorStack) {
    typedef TypeParam Allocator;
444
    typedef UTF8<> Encoding;
445
    typedef GenericDocument<Encoding, Allocator> Document;
446 447 448 449 450

    Document a;
    size_t defaultCapacity = a.GetStackCapacity();

    // Trick Document into getting GetStackCapacity() to return non-zero
451
    typedef GenericReader<Encoding, Encoding, Allocator> Reader;
452 453
    Reader reader(&a.GetAllocator());
    GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]");
454
    reader.template Parse<kParseDefaultFlags>(is, a);
455
    size_t capacity = a.GetStackCapacity();
456
    EXPECT_GT(capacity, 0u);
457 458 459 460 461 462 463 464 465

    Document b(std::move(a));
    EXPECT_EQ(a.GetStackCapacity(), defaultCapacity);
    EXPECT_EQ(b.GetStackCapacity(), capacity);

    Document c = std::move(b);
    EXPECT_EQ(b.GetStackCapacity(), defaultCapacity);
    EXPECT_EQ(c.GetStackCapacity(), capacity);
}
466
#endif
467

468 469 470 471
TYPED_TEST(DocumentMove, MoveAssignment) {
    typedef TypeParam Allocator;
    typedef GenericDocument<UTF8<>, Allocator> Document;
    Allocator allocator;
472 473 474 475 476 477 478 479

    Document a(&allocator);
    a.Parse("[\"one\", \"two\", \"three\"]");
    EXPECT_FALSE(a.HasParseError());
    EXPECT_TRUE(a.IsArray());
    EXPECT_EQ(3u, a.Size());
    EXPECT_EQ(&a.GetAllocator(), &allocator);

480
    // Document b; b = a; // does not compile (!is_copy_assignable)
481 482 483 484 485
    Document b;
    b = std::move(a);
    EXPECT_TRUE(a.IsNull());
    EXPECT_TRUE(b.IsArray());
    EXPECT_EQ(3u, b.Size());
486
    EXPECT_THROW(a.GetAllocator(), AssertException);
487 488 489 490 491 492 493
    EXPECT_EQ(&b.GetAllocator(), &allocator);

    b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
    EXPECT_FALSE(b.HasParseError());
    EXPECT_TRUE(b.IsObject());
    EXPECT_EQ(2u, b.MemberCount());

494
    // Document c; c = a; // does not compile (see static_assert)
495 496 497 498 499
    Document c;
    c = std::move(b);
    EXPECT_TRUE(b.IsNull());
    EXPECT_TRUE(c.IsObject());
    EXPECT_EQ(2u, c.MemberCount());
500
    EXPECT_THROW(b.GetAllocator(), AssertException);
501 502 503
    EXPECT_EQ(&c.GetAllocator(), &allocator);
}

504 505 506
TYPED_TEST(DocumentMove, MoveAssignmentParseError) {
    typedef TypeParam Allocator;
    typedef GenericDocument<UTF8<>, Allocator> Document;
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534

    ParseResult noError;
    Document a;
    a.Parse("{ 4 = 4]");
    ParseResult error(a.GetParseError(), a.GetErrorOffset());
    EXPECT_TRUE(a.HasParseError());
    EXPECT_NE(error.Code(), noError.Code());
    EXPECT_NE(error.Offset(), noError.Offset());

    Document b;
    b = std::move(a);
    EXPECT_FALSE(a.HasParseError());
    EXPECT_TRUE(b.HasParseError());
    EXPECT_EQ(a.GetParseError(), noError.Code());
    EXPECT_EQ(b.GetParseError(), error.Code());
    EXPECT_EQ(a.GetErrorOffset(), noError.Offset());
    EXPECT_EQ(b.GetErrorOffset(), error.Offset());

    Document c;
    c = std::move(b);
    EXPECT_FALSE(b.HasParseError());
    EXPECT_TRUE(c.HasParseError());
    EXPECT_EQ(b.GetParseError(), noError.Code());
    EXPECT_EQ(c.GetParseError(), error.Code());
    EXPECT_EQ(b.GetErrorOffset(), noError.Offset());
    EXPECT_EQ(c.GetErrorOffset(), error.Offset());
}

535 536 537 538
// This test does not properly use parsing, just for testing.
// It must call ClearStack() explicitly to prevent memory leak.
// But here we cannot as ClearStack() is private.
#if 0
539 540
TYPED_TEST(DocumentMove, MoveAssignmentStack) {
    typedef TypeParam Allocator;
541
    typedef UTF8<> Encoding;
542
    typedef GenericDocument<Encoding, Allocator> Document;
543 544 545 546 547

    Document a;
    size_t defaultCapacity = a.GetStackCapacity();

    // Trick Document into getting GetStackCapacity() to return non-zero
548
    typedef GenericReader<Encoding, Encoding, Allocator> Reader;
549 550
    Reader reader(&a.GetAllocator());
    GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]");
551
    reader.template Parse<kParseDefaultFlags>(is, a);
552
    size_t capacity = a.GetStackCapacity();
553
    EXPECT_GT(capacity, 0u);
554 555 556 557 558 559 560 561 562 563 564

    Document b;
    b = std::move(a);
    EXPECT_EQ(a.GetStackCapacity(), defaultCapacity);
    EXPECT_EQ(b.GetStackCapacity(), capacity);

    Document c;
    c = std::move(b);
    EXPECT_EQ(b.GetStackCapacity(), defaultCapacity);
    EXPECT_EQ(c.GetStackCapacity(), capacity);
}
565
#endif
566 567 568

#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS

569 570 571
// Issue 22: Memory corruption via operator=
// Fixed by making unimplemented assignment operator private.
//TEST(Document, Assignment) {
572 573 574
//  Document d1;
//  Document d2;
//  d1 = d2;
575
//}