documenttest.cpp 21 KB

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