documenttest.cpp 20 KB

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