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 using namespace rapidjson;
25 
26 template <typename DocumentType>
ParseCheck(DocumentType & doc)27 void ParseCheck(DocumentType& doc) {
28     typedef typename DocumentType::ValueType ValueType;
29 
30     EXPECT_FALSE(doc.HasParseError());
31 
32     EXPECT_TRUE(doc.IsObject());
33 
34     EXPECT_TRUE(doc.HasMember("hello"));
35     const ValueType& hello = doc["hello"];
36     EXPECT_TRUE(hello.IsString());
37     EXPECT_STREQ("world", hello.GetString());
38 
39     EXPECT_TRUE(doc.HasMember("t"));
40     const ValueType& t = doc["t"];
41     EXPECT_TRUE(t.IsTrue());
42 
43     EXPECT_TRUE(doc.HasMember("f"));
44     const ValueType& f = doc["f"];
45     EXPECT_TRUE(f.IsFalse());
46 
47     EXPECT_TRUE(doc.HasMember("n"));
48     const ValueType& n = doc["n"];
49     EXPECT_TRUE(n.IsNull());
50 
51     EXPECT_TRUE(doc.HasMember("i"));
52     const ValueType& i = doc["i"];
53     EXPECT_TRUE(i.IsNumber());
54     EXPECT_EQ(123, i.GetInt());
55 
56     EXPECT_TRUE(doc.HasMember("pi"));
57     const ValueType& pi = doc["pi"];
58     EXPECT_TRUE(pi.IsNumber());
59     EXPECT_DOUBLE_EQ(3.1416, pi.GetDouble());
60 
61     EXPECT_TRUE(doc.HasMember("a"));
62     const ValueType& a = doc["a"];
63     EXPECT_TRUE(a.IsArray());
64     EXPECT_EQ(4u, a.Size());
65     for (SizeType i = 0; i < 4; i++)
66         EXPECT_EQ(i + 1, a[i].GetUint());
67 }
68 
69 template <typename Allocator, typename StackAllocator>
ParseTest()70 void ParseTest() {
71     typedef GenericDocument<UTF8<>, Allocator, StackAllocator> DocumentType;
72     DocumentType doc;
73 
74     const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
75 
76     doc.Parse(json);
77     ParseCheck(doc);
78 
79     doc.SetNull();
80     StringStream s(json);
81     doc.template ParseStream<0>(s);
82     ParseCheck(doc);
83 
84     doc.SetNull();
85     char *buffer = strdup(json);
86     doc.ParseInsitu(buffer);
87     ParseCheck(doc);
88     free(buffer);
89 }
90 
TEST(Document,Parse)91 TEST(Document, Parse) {
92     ParseTest<MemoryPoolAllocator<>, CrtAllocator>();
93     ParseTest<MemoryPoolAllocator<>, MemoryPoolAllocator<> >();
94     ParseTest<CrtAllocator, MemoryPoolAllocator<> >();
95     ParseTest<CrtAllocator, CrtAllocator>();
96 }
97 
OpenEncodedFile(const char * filename)98 static FILE* OpenEncodedFile(const char* filename) {
99     const char *paths[] = {
100         "encodings/%s",
101         "bin/encodings/%s",
102         "../bin/encodings/%s",
103         "../../bin/encodings/%s",
104         "../../../bin/encodings/%s"
105     };
106     char buffer[1024];
107     for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
108         sprintf(buffer, paths[i], filename);
109         FILE *fp = fopen(buffer, "rb");
110         if (fp)
111             return fp;
112     }
113     return 0;
114 }
115 
TEST(Document,ParseStream_EncodedInputStream)116 TEST(Document, ParseStream_EncodedInputStream) {
117     // UTF8 -> UTF16
118     FILE* fp = OpenEncodedFile("utf8.json");
119     char buffer[256];
120     FileReadStream bis(fp, buffer, sizeof(buffer));
121     EncodedInputStream<UTF8<>, FileReadStream> eis(bis);
122 
123     GenericDocument<UTF16<> > d;
124     d.ParseStream<0, UTF8<> >(eis);
125     EXPECT_FALSE(d.HasParseError());
126 
127     fclose(fp);
128 
129     wchar_t expected[] = L"I can eat glass and it doesn't hurt me.";
130     GenericValue<UTF16<> >& v = d[L"en"];
131     EXPECT_TRUE(v.IsString());
132     EXPECT_EQ(sizeof(expected) / sizeof(wchar_t) - 1, v.GetStringLength());
133     EXPECT_EQ(0, StrCmp(expected, v.GetString()));
134 
135     // UTF16 -> UTF8 in memory
136     StringBuffer bos;
137     typedef EncodedOutputStream<UTF8<>, StringBuffer> OutputStream;
138     OutputStream eos(bos, false);   // Not writing BOM
139     Writer<OutputStream, UTF16<>, UTF8<> > writer(eos);
140     d.Accept(writer);
141 
142     {
143         // Condense the original file and compare.
144         FILE *fp = OpenEncodedFile("utf8.json");
145         FileReadStream is(fp, buffer, sizeof(buffer));
146         Reader reader;
147         StringBuffer bos2;
148         Writer<StringBuffer> writer(bos2);
149         reader.Parse(is, writer);
150         fclose(fp);
151 
152         EXPECT_EQ(bos.GetSize(), bos2.GetSize());
153         EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
154     }
155 }
156 
TEST(Document,ParseStream_AutoUTFInputStream)157 TEST(Document, ParseStream_AutoUTFInputStream) {
158     // Any -> UTF8
159     FILE* fp = OpenEncodedFile("utf32be.json");
160     char buffer[256];
161     FileReadStream bis(fp, buffer, sizeof(buffer));
162     AutoUTFInputStream<unsigned, FileReadStream> eis(bis);
163 
164     Document d;
165     d.ParseStream<0, AutoUTF<unsigned> >(eis);
166     EXPECT_FALSE(d.HasParseError());
167 
168     fclose(fp);
169 
170     char expected[] = "I can eat glass and it doesn't hurt me.";
171     Value& v = d["en"];
172     EXPECT_TRUE(v.IsString());
173     EXPECT_EQ(sizeof(expected) - 1, v.GetStringLength());
174     EXPECT_EQ(0, StrCmp(expected, v.GetString()));
175 
176     // UTF8 -> UTF8 in memory
177     StringBuffer bos;
178     Writer<StringBuffer> writer(bos);
179     d.Accept(writer);
180 
181     {
182         // Condense the original file and compare.
183         FILE *fp = OpenEncodedFile("utf8.json");
184         FileReadStream is(fp, buffer, sizeof(buffer));
185         Reader reader;
186         StringBuffer bos2;
187         Writer<StringBuffer> writer(bos2);
188         reader.Parse(is, writer);
189         fclose(fp);
190 
191         EXPECT_EQ(bos.GetSize(), bos2.GetSize());
192         EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
193     }
194 }
195 
TEST(Document,Swap)196 TEST(Document, Swap) {
197     Document d1;
198     Document::AllocatorType& a = d1.GetAllocator();
199 
200     d1.SetArray().PushBack(1, a).PushBack(2, a);
201 
202     Value o;
203     o.SetObject().AddMember("a", 1, a);
204 
205     // Swap between Document and Value
206     // d1.Swap(o); // doesn't compile
207     o.Swap(d1);
208     EXPECT_TRUE(d1.IsObject());
209     EXPECT_TRUE(o.IsArray());
210 
211     // Swap between Document and Document
212     Document d2;
213     d2.SetArray().PushBack(3, a);
214     d1.Swap(d2);
215     EXPECT_TRUE(d1.IsArray());
216     EXPECT_TRUE(d2.IsObject());
217     EXPECT_EQ(&d2.GetAllocator(), &a);
218 
219     // reset value
220     Value().Swap(d1);
221     EXPECT_TRUE(d1.IsNull());
222 
223     // reset document, including allocator
224     Document().Swap(d2);
225     EXPECT_TRUE(d2.IsNull());
226     EXPECT_NE(&d2.GetAllocator(), &a);
227 
228     // testing std::swap compatibility
229     d1.SetBool(true);
230     using std::swap;
231     swap(d1, d2);
232     EXPECT_TRUE(d1.IsNull());
233     EXPECT_TRUE(d2.IsTrue());
234 
235     swap(o, d2);
236     EXPECT_TRUE(o.IsTrue());
237     EXPECT_TRUE(d2.IsArray());
238 }
239 
240 
241 // This should be slow due to assignment in inner-loop.
242 struct OutputStringStream : public std::ostringstream {
243     typedef char Ch;
244 
PutOutputStringStream245     void Put(char c) {
246         put(c);
247     }
FlushOutputStringStream248     void Flush() {}
249 };
250 
TEST(Document,AcceptWriter)251 TEST(Document, AcceptWriter) {
252     Document doc;
253     doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
254 
255     OutputStringStream os;
256     Writer<OutputStringStream> writer(os);
257     doc.Accept(writer);
258 
259     EXPECT_EQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,4]}", os.str());
260 }
261 
TEST(Document,UserBuffer)262 TEST(Document, UserBuffer) {
263     typedef GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > DocumentType;
264     char valueBuffer[4096];
265     char parseBuffer[1024];
266     MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer));
267     MemoryPoolAllocator<> parseAllocator(parseBuffer, sizeof(parseBuffer));
268     DocumentType doc(&valueAllocator, sizeof(parseBuffer) / 2, &parseAllocator);
269     doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
270     EXPECT_FALSE(doc.HasParseError());
271     EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer));
272     EXPECT_LE(parseAllocator.Size(), sizeof(parseBuffer));
273 
274     // Cover MemoryPoolAllocator::Capacity()
275     EXPECT_LE(valueAllocator.Size(), valueAllocator.Capacity());
276     EXPECT_LE(parseAllocator.Size(), parseAllocator.Capacity());
277 }
278 
279 // Issue 226: Value of string type should not point to NULL
TEST(Document,AssertAcceptInvalidNameType)280 TEST(Document, AssertAcceptInvalidNameType) {
281     Document doc;
282     doc.SetObject();
283     doc.AddMember("a", 0, doc.GetAllocator());
284     doc.FindMember("a")->name.SetNull(); // Change name to non-string type.
285 
286     OutputStringStream os;
287     Writer<OutputStringStream> writer(os);
288     ASSERT_THROW(doc.Accept(writer), AssertException);
289 }
290 
291 // Issue 44:    SetStringRaw doesn't work with wchar_t
TEST(Document,UTF16_Document)292 TEST(Document, UTF16_Document) {
293     GenericDocument< UTF16<> > json;
294     json.Parse<kParseValidateEncodingFlag>(L"[{\"created_at\":\"Wed Oct 30 17:13:20 +0000 2012\"}]");
295 
296     ASSERT_TRUE(json.IsArray());
297     GenericValue< UTF16<> >& v = json[0];
298     ASSERT_TRUE(v.IsObject());
299 
300     GenericValue< UTF16<> >& s = v[L"created_at"];
301     ASSERT_TRUE(s.IsString());
302 
303     EXPECT_EQ(0, memcmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString(), (s.GetStringLength() + 1) * sizeof(wchar_t)));
304 }
305 
306 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
307 
308 #include <type_traits>
309 
TEST(Document,Traits)310 TEST(Document, Traits) {
311     static_assert(std::is_constructible<Document>::value, "");
312     static_assert(std::is_default_constructible<Document>::value, "");
313 #ifndef _MSC_VER
314     static_assert(!std::is_copy_constructible<Document>::value, "");
315 #endif
316     static_assert(std::is_move_constructible<Document>::value, "");
317 
318     static_assert(!std::is_nothrow_constructible<Document>::value, "");
319     static_assert(!std::is_nothrow_default_constructible<Document>::value, "");
320 #ifndef _MSC_VER
321     static_assert(!std::is_nothrow_copy_constructible<Document>::value, "");
322     static_assert(std::is_nothrow_move_constructible<Document>::value, "");
323 #endif
324 
325     static_assert(std::is_assignable<Document,Document>::value, "");
326 #ifndef _MSC_VER
327   static_assert(!std::is_copy_assignable<Document>::value, "");
328 #endif
329     static_assert(std::is_move_assignable<Document>::value, "");
330 
331 #ifndef _MSC_VER
332     static_assert(std::is_nothrow_assignable<Document, Document>::value, "");
333 #endif
334     static_assert(!std::is_nothrow_copy_assignable<Document>::value, "");
335 #ifndef _MSC_VER
336     static_assert(std::is_nothrow_move_assignable<Document>::value, "");
337 #endif
338 
339     static_assert( std::is_destructible<Document>::value, "");
340 #ifndef _MSC_VER
341     static_assert(std::is_nothrow_destructible<Document>::value, "");
342 #endif
343 }
344 
345 template <typename Allocator>
346 struct DocumentMove: public ::testing::Test {
347 };
348 
349 typedef ::testing::Types< CrtAllocator, MemoryPoolAllocator<> > MoveAllocatorTypes;
350 TYPED_TEST_CASE(DocumentMove, MoveAllocatorTypes);
351 
TYPED_TEST(DocumentMove,MoveConstructor)352 TYPED_TEST(DocumentMove, MoveConstructor) {
353     typedef TypeParam Allocator;
354     typedef GenericDocument<UTF8<>, Allocator> Document;
355     Allocator allocator;
356 
357     Document a(&allocator);
358     a.Parse("[\"one\", \"two\", \"three\"]");
359     EXPECT_FALSE(a.HasParseError());
360     EXPECT_TRUE(a.IsArray());
361     EXPECT_EQ(3u, a.Size());
362     EXPECT_EQ(&a.GetAllocator(), &allocator);
363 
364     // Document b(a); // does not compile (!is_copy_constructible)
365     Document b(std::move(a));
366     EXPECT_TRUE(a.IsNull());
367     EXPECT_TRUE(b.IsArray());
368     EXPECT_EQ(3u, b.Size());
369     EXPECT_EQ(&a.GetAllocator(), (void*)0);
370     EXPECT_EQ(&b.GetAllocator(), &allocator);
371 
372     b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
373     EXPECT_FALSE(b.HasParseError());
374     EXPECT_TRUE(b.IsObject());
375     EXPECT_EQ(2u, b.MemberCount());
376 
377     // Document c = a; // does not compile (!is_copy_constructible)
378     Document c = std::move(b);
379     EXPECT_TRUE(b.IsNull());
380     EXPECT_TRUE(c.IsObject());
381     EXPECT_EQ(2u, c.MemberCount());
382     EXPECT_EQ(&b.GetAllocator(), (void*)0);
383     EXPECT_EQ(&c.GetAllocator(), &allocator);
384 }
385 
TYPED_TEST(DocumentMove,MoveConstructorParseError)386 TYPED_TEST(DocumentMove, MoveConstructorParseError) {
387     typedef TypeParam Allocator;
388     typedef GenericDocument<UTF8<>, Allocator> Document;
389 
390     ParseResult noError;
391     Document a;
392     a.Parse("{ 4 = 4]");
393     ParseResult error(a.GetParseError(), a.GetErrorOffset());
394     EXPECT_TRUE(a.HasParseError());
395     EXPECT_NE(error.Code(), noError.Code());
396     EXPECT_NE(error.Offset(), noError.Offset());
397 
398     Document b(std::move(a));
399     EXPECT_FALSE(a.HasParseError());
400     EXPECT_TRUE(b.HasParseError());
401     EXPECT_EQ(a.GetParseError(), noError.Code());
402     EXPECT_EQ(b.GetParseError(), error.Code());
403     EXPECT_EQ(a.GetErrorOffset(), noError.Offset());
404     EXPECT_EQ(b.GetErrorOffset(), error.Offset());
405 
406     Document c(std::move(b));
407     EXPECT_FALSE(b.HasParseError());
408     EXPECT_TRUE(c.HasParseError());
409     EXPECT_EQ(b.GetParseError(), noError.Code());
410     EXPECT_EQ(c.GetParseError(), error.Code());
411     EXPECT_EQ(b.GetErrorOffset(), noError.Offset());
412     EXPECT_EQ(c.GetErrorOffset(), error.Offset());
413 }
414 
415 // This test does not properly use parsing, just for testing.
416 // It must call ClearStack() explicitly to prevent memory leak.
417 // But here we cannot as ClearStack() is private.
418 #if 0
419 TYPED_TEST(DocumentMove, MoveConstructorStack) {
420     typedef TypeParam Allocator;
421     typedef UTF8<> Encoding;
422     typedef GenericDocument<Encoding, Allocator> Document;
423 
424     Document a;
425     size_t defaultCapacity = a.GetStackCapacity();
426 
427     // Trick Document into getting GetStackCapacity() to return non-zero
428     typedef GenericReader<Encoding, Encoding, Allocator> Reader;
429     Reader reader(&a.GetAllocator());
430     GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]");
431     reader.template Parse<kParseDefaultFlags>(is, a);
432     size_t capacity = a.GetStackCapacity();
433     EXPECT_GT(capacity, 0u);
434 
435     Document b(std::move(a));
436     EXPECT_EQ(a.GetStackCapacity(), defaultCapacity);
437     EXPECT_EQ(b.GetStackCapacity(), capacity);
438 
439     Document c = std::move(b);
440     EXPECT_EQ(b.GetStackCapacity(), defaultCapacity);
441     EXPECT_EQ(c.GetStackCapacity(), capacity);
442 }
443 #endif
444 
TYPED_TEST(DocumentMove,MoveAssignment)445 TYPED_TEST(DocumentMove, MoveAssignment) {
446     typedef TypeParam Allocator;
447     typedef GenericDocument<UTF8<>, Allocator> Document;
448     Allocator allocator;
449 
450     Document a(&allocator);
451     a.Parse("[\"one\", \"two\", \"three\"]");
452     EXPECT_FALSE(a.HasParseError());
453     EXPECT_TRUE(a.IsArray());
454     EXPECT_EQ(3u, a.Size());
455     EXPECT_EQ(&a.GetAllocator(), &allocator);
456 
457     // Document b; b = a; // does not compile (!is_copy_assignable)
458     Document b;
459     b = std::move(a);
460     EXPECT_TRUE(a.IsNull());
461     EXPECT_TRUE(b.IsArray());
462     EXPECT_EQ(3u, b.Size());
463     EXPECT_EQ(&a.GetAllocator(), (void*)0);
464     EXPECT_EQ(&b.GetAllocator(), &allocator);
465 
466     b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
467     EXPECT_FALSE(b.HasParseError());
468     EXPECT_TRUE(b.IsObject());
469     EXPECT_EQ(2u, b.MemberCount());
470 
471     // Document c; c = a; // does not compile (see static_assert)
472     Document c;
473     c = std::move(b);
474     EXPECT_TRUE(b.IsNull());
475     EXPECT_TRUE(c.IsObject());
476     EXPECT_EQ(2u, c.MemberCount());
477     EXPECT_EQ(&b.GetAllocator(), (void*)0);
478     EXPECT_EQ(&c.GetAllocator(), &allocator);
479 }
480 
TYPED_TEST(DocumentMove,MoveAssignmentParseError)481 TYPED_TEST(DocumentMove, MoveAssignmentParseError) {
482     typedef TypeParam Allocator;
483     typedef GenericDocument<UTF8<>, Allocator> Document;
484 
485     ParseResult noError;
486     Document a;
487     a.Parse("{ 4 = 4]");
488     ParseResult error(a.GetParseError(), a.GetErrorOffset());
489     EXPECT_TRUE(a.HasParseError());
490     EXPECT_NE(error.Code(), noError.Code());
491     EXPECT_NE(error.Offset(), noError.Offset());
492 
493     Document b;
494     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     Document c;
503     c = std::move(b);
504     EXPECT_FALSE(b.HasParseError());
505     EXPECT_TRUE(c.HasParseError());
506     EXPECT_EQ(b.GetParseError(), noError.Code());
507     EXPECT_EQ(c.GetParseError(), error.Code());
508     EXPECT_EQ(b.GetErrorOffset(), noError.Offset());
509     EXPECT_EQ(c.GetErrorOffset(), error.Offset());
510 }
511 
512 // This test does not properly use parsing, just for testing.
513 // It must call ClearStack() explicitly to prevent memory leak.
514 // But here we cannot as ClearStack() is private.
515 #if 0
516 TYPED_TEST(DocumentMove, MoveAssignmentStack) {
517     typedef TypeParam Allocator;
518     typedef UTF8<> Encoding;
519     typedef GenericDocument<Encoding, Allocator> Document;
520 
521     Document a;
522     size_t defaultCapacity = a.GetStackCapacity();
523 
524     // Trick Document into getting GetStackCapacity() to return non-zero
525     typedef GenericReader<Encoding, Encoding, Allocator> Reader;
526     Reader reader(&a.GetAllocator());
527     GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]");
528     reader.template Parse<kParseDefaultFlags>(is, a);
529     size_t capacity = a.GetStackCapacity();
530     EXPECT_GT(capacity, 0u);
531 
532     Document b;
533     b = std::move(a);
534     EXPECT_EQ(a.GetStackCapacity(), defaultCapacity);
535     EXPECT_EQ(b.GetStackCapacity(), capacity);
536 
537     Document c;
538     c = std::move(b);
539     EXPECT_EQ(b.GetStackCapacity(), defaultCapacity);
540     EXPECT_EQ(c.GetStackCapacity(), capacity);
541 }
542 #endif
543 
544 #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
545 
546 // Issue 22: Memory corruption via operator=
547 // Fixed by making unimplemented assignment operator private.
548 //TEST(Document, Assignment) {
549 //  Document d1;
550 //  Document d2;
551 //  d1 = d2;
552 //}
553