]> git.proxmox.com Git - ceph.git/blob - ceph/src/rapidjson/test/unittest/documenttest.cpp
update sources to v12.1.0
[ceph.git] / ceph / src / rapidjson / test / unittest / documenttest.cpp
1 // Tencent is pleased to support the open source community by making RapidJSON available.
2 //
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 //
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // http://opensource.org/licenses/MIT
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
14
15 #include "unittest.h"
16 #include "rapidjson/document.h"
17 #include "rapidjson/writer.h"
18 #include "rapidjson/filereadstream.h"
19 #include "rapidjson/encodedstream.h"
20 #include "rapidjson/stringbuffer.h"
21 #include <sstream>
22 #include <algorithm>
23
24 #ifdef __clang__
25 RAPIDJSON_DIAG_PUSH
26 RAPIDJSON_DIAG_OFF(c++98-compat)
27 RAPIDJSON_DIAG_OFF(missing-variable-declarations)
28 #endif
29
30 using namespace rapidjson;
31
32 template <typename DocumentType>
33 void ParseCheck(DocumentType& doc) {
34 typedef typename DocumentType::ValueType ValueType;
35
36 EXPECT_FALSE(doc.HasParseError());
37 if (doc.HasParseError())
38 printf("Error: %d at %zu\n", static_cast<int>(doc.GetParseError()), doc.GetErrorOffset());
39 EXPECT_TRUE(static_cast<ParseResult>(doc));
40
41 EXPECT_TRUE(doc.IsObject());
42
43 EXPECT_TRUE(doc.HasMember("hello"));
44 const ValueType& hello = doc["hello"];
45 EXPECT_TRUE(hello.IsString());
46 EXPECT_STREQ("world", hello.GetString());
47
48 EXPECT_TRUE(doc.HasMember("t"));
49 const ValueType& t = doc["t"];
50 EXPECT_TRUE(t.IsTrue());
51
52 EXPECT_TRUE(doc.HasMember("f"));
53 const ValueType& f = doc["f"];
54 EXPECT_TRUE(f.IsFalse());
55
56 EXPECT_TRUE(doc.HasMember("n"));
57 const ValueType& n = doc["n"];
58 EXPECT_TRUE(n.IsNull());
59
60 EXPECT_TRUE(doc.HasMember("i"));
61 const ValueType& i = doc["i"];
62 EXPECT_TRUE(i.IsNumber());
63 EXPECT_EQ(123, i.GetInt());
64
65 EXPECT_TRUE(doc.HasMember("pi"));
66 const ValueType& pi = doc["pi"];
67 EXPECT_TRUE(pi.IsNumber());
68 EXPECT_DOUBLE_EQ(3.1416, pi.GetDouble());
69
70 EXPECT_TRUE(doc.HasMember("a"));
71 const ValueType& a = doc["a"];
72 EXPECT_TRUE(a.IsArray());
73 EXPECT_EQ(4u, a.Size());
74 for (SizeType j = 0; j < 4; j++)
75 EXPECT_EQ(j + 1, a[j].GetUint());
76 }
77
78 template <typename Allocator, typename StackAllocator>
79 void ParseTest() {
80 typedef GenericDocument<UTF8<>, Allocator, StackAllocator> DocumentType;
81 DocumentType doc;
82
83 const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
84
85 doc.Parse(json);
86 ParseCheck(doc);
87
88 doc.SetNull();
89 StringStream s(json);
90 doc.template ParseStream<0>(s);
91 ParseCheck(doc);
92
93 doc.SetNull();
94 char *buffer = strdup(json);
95 doc.ParseInsitu(buffer);
96 ParseCheck(doc);
97 free(buffer);
98
99 // Parse(const Ch*, size_t)
100 size_t length = strlen(json);
101 buffer = reinterpret_cast<char*>(malloc(length * 2));
102 memcpy(buffer, json, length);
103 memset(buffer + length, 'X', length);
104 #if RAPIDJSON_HAS_STDSTRING
105 std::string s2(buffer, length); // backup buffer
106 #endif
107 doc.SetNull();
108 doc.Parse(buffer, length);
109 free(buffer);
110 ParseCheck(doc);
111
112 #if RAPIDJSON_HAS_STDSTRING
113 // Parse(std::string)
114 doc.SetNull();
115 doc.Parse(s2);
116 ParseCheck(doc);
117 #endif
118 }
119
120 TEST(Document, Parse) {
121 ParseTest<MemoryPoolAllocator<>, CrtAllocator>();
122 ParseTest<MemoryPoolAllocator<>, MemoryPoolAllocator<> >();
123 ParseTest<CrtAllocator, MemoryPoolAllocator<> >();
124 ParseTest<CrtAllocator, CrtAllocator>();
125 }
126
127 TEST(Document, UnchangedOnParseError) {
128 Document doc;
129 doc.SetArray().PushBack(0, doc.GetAllocator());
130
131 ParseResult err = doc.Parse("{]");
132 EXPECT_TRUE(doc.HasParseError());
133 EXPECT_EQ(err.Code(), doc.GetParseError());
134 EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
135 EXPECT_TRUE(doc.IsArray());
136 EXPECT_EQ(doc.Size(), 1u);
137
138 err = doc.Parse("{}");
139 EXPECT_FALSE(doc.HasParseError());
140 EXPECT_FALSE(err.IsError());
141 EXPECT_EQ(err.Code(), doc.GetParseError());
142 EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
143 EXPECT_TRUE(doc.IsObject());
144 EXPECT_EQ(doc.MemberCount(), 0u);
145 }
146
147 static FILE* OpenEncodedFile(const char* filename) {
148 const char *paths[] = {
149 "encodings",
150 "bin/encodings",
151 "../bin/encodings",
152 "../../bin/encodings",
153 "../../../bin/encodings"
154 };
155 char buffer[1024];
156 for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
157 sprintf(buffer, "%s/%s", paths[i], filename);
158 FILE *fp = fopen(buffer, "rb");
159 if (fp)
160 return fp;
161 }
162 return 0;
163 }
164
165 TEST(Document, Parse_Encoding) {
166 const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
167
168 typedef GenericDocument<UTF16<> > DocumentType;
169 DocumentType doc;
170
171 // Parse<unsigned, SourceEncoding>(const SourceEncoding::Ch*)
172 // doc.Parse<kParseDefaultFlags, UTF8<> >(json);
173 // EXPECT_FALSE(doc.HasParseError());
174 // EXPECT_EQ(0, StrCmp(doc[L"hello"].GetString(), L"world"));
175
176 // Parse<unsigned, SourceEncoding>(const SourceEncoding::Ch*, size_t)
177 size_t length = strlen(json);
178 char* buffer = reinterpret_cast<char*>(malloc(length * 2));
179 memcpy(buffer, json, length);
180 memset(buffer + length, 'X', length);
181 #if RAPIDJSON_HAS_STDSTRING
182 std::string s2(buffer, length); // backup buffer
183 #endif
184 doc.SetNull();
185 doc.Parse<kParseDefaultFlags, UTF8<> >(buffer, length);
186 free(buffer);
187 EXPECT_FALSE(doc.HasParseError());
188 if (doc.HasParseError())
189 printf("Error: %d at %zu\n", static_cast<int>(doc.GetParseError()), doc.GetErrorOffset());
190 EXPECT_EQ(0, StrCmp(doc[L"hello"].GetString(), L"world"));
191
192 #if RAPIDJSON_HAS_STDSTRING
193 // Parse<unsigned, SourceEncoding>(std::string)
194 doc.SetNull();
195
196 #if defined(_MSC_VER) && _MSC_VER < 1800
197 doc.Parse<kParseDefaultFlags, UTF8<> >(s2.c_str()); // VS2010 or below cannot handle templated function overloading. Use const char* instead.
198 #else
199 doc.Parse<kParseDefaultFlags, UTF8<> >(s2);
200 #endif
201 EXPECT_FALSE(doc.HasParseError());
202 EXPECT_EQ(0, StrCmp(doc[L"hello"].GetString(), L"world"));
203 #endif
204 }
205
206 TEST(Document, ParseStream_EncodedInputStream) {
207 // UTF8 -> UTF16
208 FILE* fp = OpenEncodedFile("utf8.json");
209 char buffer[256];
210 FileReadStream bis(fp, buffer, sizeof(buffer));
211 EncodedInputStream<UTF8<>, FileReadStream> eis(bis);
212
213 GenericDocument<UTF16<> > d;
214 d.ParseStream<0, UTF8<> >(eis);
215 EXPECT_FALSE(d.HasParseError());
216
217 fclose(fp);
218
219 wchar_t expected[] = L"I can eat glass and it doesn't hurt me.";
220 GenericValue<UTF16<> >& v = d[L"en"];
221 EXPECT_TRUE(v.IsString());
222 EXPECT_EQ(sizeof(expected) / sizeof(wchar_t) - 1, v.GetStringLength());
223 EXPECT_EQ(0, StrCmp(expected, v.GetString()));
224
225 // UTF16 -> UTF8 in memory
226 StringBuffer bos;
227 typedef EncodedOutputStream<UTF8<>, StringBuffer> OutputStream;
228 OutputStream eos(bos, false); // Not writing BOM
229 {
230 Writer<OutputStream, UTF16<>, UTF8<> > writer(eos);
231 d.Accept(writer);
232 }
233
234 // Condense the original file and compare.
235 fp = OpenEncodedFile("utf8.json");
236 FileReadStream is(fp, buffer, sizeof(buffer));
237 Reader reader;
238 StringBuffer bos2;
239 Writer<StringBuffer> writer2(bos2);
240 reader.Parse(is, writer2);
241 fclose(fp);
242
243 EXPECT_EQ(bos.GetSize(), bos2.GetSize());
244 EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
245 }
246
247 TEST(Document, ParseStream_AutoUTFInputStream) {
248 // Any -> UTF8
249 FILE* fp = OpenEncodedFile("utf32be.json");
250 char buffer[256];
251 FileReadStream bis(fp, buffer, sizeof(buffer));
252 AutoUTFInputStream<unsigned, FileReadStream> eis(bis);
253
254 Document d;
255 d.ParseStream<0, AutoUTF<unsigned> >(eis);
256 EXPECT_FALSE(d.HasParseError());
257
258 fclose(fp);
259
260 char expected[] = "I can eat glass and it doesn't hurt me.";
261 Value& v = d["en"];
262 EXPECT_TRUE(v.IsString());
263 EXPECT_EQ(sizeof(expected) - 1, v.GetStringLength());
264 EXPECT_EQ(0, StrCmp(expected, v.GetString()));
265
266 // UTF8 -> UTF8 in memory
267 StringBuffer bos;
268 Writer<StringBuffer> writer(bos);
269 d.Accept(writer);
270
271 // Condense the original file and compare.
272 fp = OpenEncodedFile("utf8.json");
273 FileReadStream is(fp, buffer, sizeof(buffer));
274 Reader reader;
275 StringBuffer bos2;
276 Writer<StringBuffer> writer2(bos2);
277 reader.Parse(is, writer2);
278 fclose(fp);
279
280 EXPECT_EQ(bos.GetSize(), bos2.GetSize());
281 EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
282 }
283
284 TEST(Document, Swap) {
285 Document d1;
286 Document::AllocatorType& a = d1.GetAllocator();
287
288 d1.SetArray().PushBack(1, a).PushBack(2, a);
289
290 Value o;
291 o.SetObject().AddMember("a", 1, a);
292
293 // Swap between Document and Value
294 // d1.Swap(o); // doesn't compile
295 o.Swap(d1);
296 EXPECT_TRUE(d1.IsObject());
297 EXPECT_TRUE(o.IsArray());
298
299 // Swap between Document and Document
300 Document d2;
301 d2.SetArray().PushBack(3, a);
302 d1.Swap(d2);
303 EXPECT_TRUE(d1.IsArray());
304 EXPECT_TRUE(d2.IsObject());
305 EXPECT_EQ(&d2.GetAllocator(), &a);
306
307 // reset value
308 Value().Swap(d1);
309 EXPECT_TRUE(d1.IsNull());
310
311 // reset document, including allocator
312 Document().Swap(d2);
313 EXPECT_TRUE(d2.IsNull());
314 EXPECT_NE(&d2.GetAllocator(), &a);
315
316 // testing std::swap compatibility
317 d1.SetBool(true);
318 using std::swap;
319 swap(d1, d2);
320 EXPECT_TRUE(d1.IsNull());
321 EXPECT_TRUE(d2.IsTrue());
322
323 swap(o, d2);
324 EXPECT_TRUE(o.IsTrue());
325 EXPECT_TRUE(d2.IsArray());
326 }
327
328
329 // This should be slow due to assignment in inner-loop.
330 struct OutputStringStream : public std::ostringstream {
331 typedef char Ch;
332
333 virtual ~OutputStringStream();
334
335 void Put(char c) {
336 put(c);
337 }
338 void Flush() {}
339 };
340
341 OutputStringStream::~OutputStringStream() {}
342
343 TEST(Document, AcceptWriter) {
344 Document doc;
345 doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
346
347 OutputStringStream os;
348 Writer<OutputStringStream> writer(os);
349 doc.Accept(writer);
350
351 EXPECT_EQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,4]}", os.str());
352 }
353
354 TEST(Document, UserBuffer) {
355 typedef GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > DocumentType;
356 char valueBuffer[4096];
357 char parseBuffer[1024];
358 MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer));
359 MemoryPoolAllocator<> parseAllocator(parseBuffer, sizeof(parseBuffer));
360 DocumentType doc(&valueAllocator, sizeof(parseBuffer) / 2, &parseAllocator);
361 doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
362 EXPECT_FALSE(doc.HasParseError());
363 EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer));
364 EXPECT_LE(parseAllocator.Size(), sizeof(parseBuffer));
365
366 // Cover MemoryPoolAllocator::Capacity()
367 EXPECT_LE(valueAllocator.Size(), valueAllocator.Capacity());
368 EXPECT_LE(parseAllocator.Size(), parseAllocator.Capacity());
369 }
370
371 // Issue 226: Value of string type should not point to NULL
372 TEST(Document, AssertAcceptInvalidNameType) {
373 Document doc;
374 doc.SetObject();
375 doc.AddMember("a", 0, doc.GetAllocator());
376 doc.FindMember("a")->name.SetNull(); // Change name to non-string type.
377
378 OutputStringStream os;
379 Writer<OutputStringStream> writer(os);
380 ASSERT_THROW(doc.Accept(writer), AssertException);
381 }
382
383 // Issue 44: SetStringRaw doesn't work with wchar_t
384 TEST(Document, UTF16_Document) {
385 GenericDocument< UTF16<> > json;
386 json.Parse<kParseValidateEncodingFlag>(L"[{\"created_at\":\"Wed Oct 30 17:13:20 +0000 2012\"}]");
387
388 ASSERT_TRUE(json.IsArray());
389 GenericValue< UTF16<> >& v = json[0];
390 ASSERT_TRUE(v.IsObject());
391
392 GenericValue< UTF16<> >& s = v[L"created_at"];
393 ASSERT_TRUE(s.IsString());
394
395 EXPECT_EQ(0, memcmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString(), (s.GetStringLength() + 1) * sizeof(wchar_t)));
396 }
397
398 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
399
400 #if 0 // Many old compiler does not support these. Turn it off temporaily.
401
402 #include <type_traits>
403
404 TEST(Document, Traits) {
405 static_assert(std::is_constructible<Document>::value, "");
406 static_assert(std::is_default_constructible<Document>::value, "");
407 #ifndef _MSC_VER
408 static_assert(!std::is_copy_constructible<Document>::value, "");
409 #endif
410 static_assert(std::is_move_constructible<Document>::value, "");
411
412 static_assert(!std::is_nothrow_constructible<Document>::value, "");
413 static_assert(!std::is_nothrow_default_constructible<Document>::value, "");
414 #ifndef _MSC_VER
415 static_assert(!std::is_nothrow_copy_constructible<Document>::value, "");
416 static_assert(std::is_nothrow_move_constructible<Document>::value, "");
417 #endif
418
419 static_assert(std::is_assignable<Document,Document>::value, "");
420 #ifndef _MSC_VER
421 static_assert(!std::is_copy_assignable<Document>::value, "");
422 #endif
423 static_assert(std::is_move_assignable<Document>::value, "");
424
425 #ifndef _MSC_VER
426 static_assert(std::is_nothrow_assignable<Document, Document>::value, "");
427 #endif
428 static_assert(!std::is_nothrow_copy_assignable<Document>::value, "");
429 #ifndef _MSC_VER
430 static_assert(std::is_nothrow_move_assignable<Document>::value, "");
431 #endif
432
433 static_assert( std::is_destructible<Document>::value, "");
434 #ifndef _MSC_VER
435 static_assert(std::is_nothrow_destructible<Document>::value, "");
436 #endif
437 }
438
439 #endif
440
441 template <typename Allocator>
442 struct DocumentMove: public ::testing::Test {
443 };
444
445 typedef ::testing::Types< CrtAllocator, MemoryPoolAllocator<> > MoveAllocatorTypes;
446 TYPED_TEST_CASE(DocumentMove, MoveAllocatorTypes);
447
448 TYPED_TEST(DocumentMove, MoveConstructor) {
449 typedef TypeParam Allocator;
450 typedef GenericDocument<UTF8<>, Allocator> D;
451 Allocator allocator;
452
453 D a(&allocator);
454 a.Parse("[\"one\", \"two\", \"three\"]");
455 EXPECT_FALSE(a.HasParseError());
456 EXPECT_TRUE(a.IsArray());
457 EXPECT_EQ(3u, a.Size());
458 EXPECT_EQ(&a.GetAllocator(), &allocator);
459
460 // Document b(a); // does not compile (!is_copy_constructible)
461 D b(std::move(a));
462 EXPECT_TRUE(a.IsNull());
463 EXPECT_TRUE(b.IsArray());
464 EXPECT_EQ(3u, b.Size());
465 EXPECT_THROW(a.GetAllocator(), AssertException);
466 EXPECT_EQ(&b.GetAllocator(), &allocator);
467
468 b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
469 EXPECT_FALSE(b.HasParseError());
470 EXPECT_TRUE(b.IsObject());
471 EXPECT_EQ(2u, b.MemberCount());
472
473 // Document c = a; // does not compile (!is_copy_constructible)
474 D c = std::move(b);
475 EXPECT_TRUE(b.IsNull());
476 EXPECT_TRUE(c.IsObject());
477 EXPECT_EQ(2u, c.MemberCount());
478 EXPECT_THROW(b.GetAllocator(), AssertException);
479 EXPECT_EQ(&c.GetAllocator(), &allocator);
480 }
481
482 TYPED_TEST(DocumentMove, MoveConstructorParseError) {
483 typedef TypeParam Allocator;
484 typedef GenericDocument<UTF8<>, Allocator> D;
485
486 ParseResult noError;
487 D a;
488 a.Parse("{ 4 = 4]");
489 ParseResult error(a.GetParseError(), a.GetErrorOffset());
490 EXPECT_TRUE(a.HasParseError());
491 EXPECT_NE(error.Code(), noError.Code());
492 EXPECT_NE(error.Offset(), noError.Offset());
493
494 D b(std::move(a));
495 EXPECT_FALSE(a.HasParseError());
496 EXPECT_TRUE(b.HasParseError());
497 EXPECT_EQ(a.GetParseError(), noError.Code());
498 EXPECT_EQ(b.GetParseError(), error.Code());
499 EXPECT_EQ(a.GetErrorOffset(), noError.Offset());
500 EXPECT_EQ(b.GetErrorOffset(), error.Offset());
501
502 D c(std::move(b));
503 EXPECT_FALSE(b.HasParseError());
504 EXPECT_TRUE(c.HasParseError());
505 EXPECT_EQ(b.GetParseError(), noError.Code());
506 EXPECT_EQ(c.GetParseError(), error.Code());
507 EXPECT_EQ(b.GetErrorOffset(), noError.Offset());
508 EXPECT_EQ(c.GetErrorOffset(), error.Offset());
509 }
510
511 // This test does not properly use parsing, just for testing.
512 // It must call ClearStack() explicitly to prevent memory leak.
513 // But here we cannot as ClearStack() is private.
514 #if 0
515 TYPED_TEST(DocumentMove, MoveConstructorStack) {
516 typedef TypeParam Allocator;
517 typedef UTF8<> Encoding;
518 typedef GenericDocument<Encoding, Allocator> Document;
519
520 Document a;
521 size_t defaultCapacity = a.GetStackCapacity();
522
523 // Trick Document into getting GetStackCapacity() to return non-zero
524 typedef GenericReader<Encoding, Encoding, Allocator> Reader;
525 Reader reader(&a.GetAllocator());
526 GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]");
527 reader.template Parse<kParseDefaultFlags>(is, a);
528 size_t capacity = a.GetStackCapacity();
529 EXPECT_GT(capacity, 0u);
530
531 Document b(std::move(a));
532 EXPECT_EQ(a.GetStackCapacity(), defaultCapacity);
533 EXPECT_EQ(b.GetStackCapacity(), capacity);
534
535 Document c = std::move(b);
536 EXPECT_EQ(b.GetStackCapacity(), defaultCapacity);
537 EXPECT_EQ(c.GetStackCapacity(), capacity);
538 }
539 #endif
540
541 TYPED_TEST(DocumentMove, MoveAssignment) {
542 typedef TypeParam Allocator;
543 typedef GenericDocument<UTF8<>, Allocator> D;
544 Allocator allocator;
545
546 D a(&allocator);
547 a.Parse("[\"one\", \"two\", \"three\"]");
548 EXPECT_FALSE(a.HasParseError());
549 EXPECT_TRUE(a.IsArray());
550 EXPECT_EQ(3u, a.Size());
551 EXPECT_EQ(&a.GetAllocator(), &allocator);
552
553 // Document b; b = a; // does not compile (!is_copy_assignable)
554 D b;
555 b = std::move(a);
556 EXPECT_TRUE(a.IsNull());
557 EXPECT_TRUE(b.IsArray());
558 EXPECT_EQ(3u, b.Size());
559 EXPECT_THROW(a.GetAllocator(), AssertException);
560 EXPECT_EQ(&b.GetAllocator(), &allocator);
561
562 b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
563 EXPECT_FALSE(b.HasParseError());
564 EXPECT_TRUE(b.IsObject());
565 EXPECT_EQ(2u, b.MemberCount());
566
567 // Document c; c = a; // does not compile (see static_assert)
568 D c;
569 c = std::move(b);
570 EXPECT_TRUE(b.IsNull());
571 EXPECT_TRUE(c.IsObject());
572 EXPECT_EQ(2u, c.MemberCount());
573 EXPECT_THROW(b.GetAllocator(), AssertException);
574 EXPECT_EQ(&c.GetAllocator(), &allocator);
575 }
576
577 TYPED_TEST(DocumentMove, MoveAssignmentParseError) {
578 typedef TypeParam Allocator;
579 typedef GenericDocument<UTF8<>, Allocator> D;
580
581 ParseResult noError;
582 D a;
583 a.Parse("{ 4 = 4]");
584 ParseResult error(a.GetParseError(), a.GetErrorOffset());
585 EXPECT_TRUE(a.HasParseError());
586 EXPECT_NE(error.Code(), noError.Code());
587 EXPECT_NE(error.Offset(), noError.Offset());
588
589 D b;
590 b = std::move(a);
591 EXPECT_FALSE(a.HasParseError());
592 EXPECT_TRUE(b.HasParseError());
593 EXPECT_EQ(a.GetParseError(), noError.Code());
594 EXPECT_EQ(b.GetParseError(), error.Code());
595 EXPECT_EQ(a.GetErrorOffset(), noError.Offset());
596 EXPECT_EQ(b.GetErrorOffset(), error.Offset());
597
598 D c;
599 c = std::move(b);
600 EXPECT_FALSE(b.HasParseError());
601 EXPECT_TRUE(c.HasParseError());
602 EXPECT_EQ(b.GetParseError(), noError.Code());
603 EXPECT_EQ(c.GetParseError(), error.Code());
604 EXPECT_EQ(b.GetErrorOffset(), noError.Offset());
605 EXPECT_EQ(c.GetErrorOffset(), error.Offset());
606 }
607
608 // This test does not properly use parsing, just for testing.
609 // It must call ClearStack() explicitly to prevent memory leak.
610 // But here we cannot as ClearStack() is private.
611 #if 0
612 TYPED_TEST(DocumentMove, MoveAssignmentStack) {
613 typedef TypeParam Allocator;
614 typedef UTF8<> Encoding;
615 typedef GenericDocument<Encoding, Allocator> D;
616
617 D a;
618 size_t defaultCapacity = a.GetStackCapacity();
619
620 // Trick Document into getting GetStackCapacity() to return non-zero
621 typedef GenericReader<Encoding, Encoding, Allocator> Reader;
622 Reader reader(&a.GetAllocator());
623 GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]");
624 reader.template Parse<kParseDefaultFlags>(is, a);
625 size_t capacity = a.GetStackCapacity();
626 EXPECT_GT(capacity, 0u);
627
628 D b;
629 b = std::move(a);
630 EXPECT_EQ(a.GetStackCapacity(), defaultCapacity);
631 EXPECT_EQ(b.GetStackCapacity(), capacity);
632
633 D c;
634 c = std::move(b);
635 EXPECT_EQ(b.GetStackCapacity(), defaultCapacity);
636 EXPECT_EQ(c.GetStackCapacity(), capacity);
637 }
638 #endif
639
640 #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
641
642 // Issue 22: Memory corruption via operator=
643 // Fixed by making unimplemented assignment operator private.
644 //TEST(Document, Assignment) {
645 // Document d1;
646 // Document d2;
647 // d1 = d2;
648 //}
649
650 #ifdef __clang__
651 RAPIDJSON_DIAG_POP
652 #endif