documenttest.cpp (rapidjson-1.0.2) | : | documenttest.cpp (rapidjson-1.1.0) | ||
---|---|---|---|---|
skipping to change at line 22 | skipping to change at line 22 | |||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the | // CONDITIONS OF ANY KIND, either express or implied. See the License for the | |||
// specific language governing permissions and limitations under the License. | // specific language governing permissions and limitations under the License. | |||
#include "unittest.h" | #include "unittest.h" | |||
#include "rapidjson/document.h" | #include "rapidjson/document.h" | |||
#include "rapidjson/writer.h" | #include "rapidjson/writer.h" | |||
#include "rapidjson/filereadstream.h" | #include "rapidjson/filereadstream.h" | |||
#include "rapidjson/encodedstream.h" | #include "rapidjson/encodedstream.h" | |||
#include "rapidjson/stringbuffer.h" | #include "rapidjson/stringbuffer.h" | |||
#include <sstream> | #include <sstream> | |||
#include <algorithm> | ||||
#ifdef __clang__ | ||||
RAPIDJSON_DIAG_PUSH | ||||
RAPIDJSON_DIAG_OFF(c++98-compat) | ||||
RAPIDJSON_DIAG_OFF(missing-variable-declarations) | ||||
#endif | ||||
using namespace rapidjson; | using namespace rapidjson; | |||
template <typename DocumentType> | template <typename DocumentType> | |||
void ParseCheck(DocumentType& doc) { | void ParseCheck(DocumentType& doc) { | |||
typedef typename DocumentType::ValueType ValueType; | typedef typename DocumentType::ValueType ValueType; | |||
EXPECT_FALSE(doc.HasParseError()); | EXPECT_FALSE(doc.HasParseError()); | |||
if (doc.HasParseError()) | ||||
printf("Error: %d at %zu\n", static_cast<int>(doc.GetParseError()), doc. | ||||
GetErrorOffset()); | ||||
EXPECT_TRUE(static_cast<ParseResult>(doc)); | ||||
EXPECT_TRUE(doc.IsObject()); | EXPECT_TRUE(doc.IsObject()); | |||
EXPECT_TRUE(doc.HasMember("hello")); | EXPECT_TRUE(doc.HasMember("hello")); | |||
const ValueType& hello = doc["hello"]; | const ValueType& hello = doc["hello"]; | |||
EXPECT_TRUE(hello.IsString()); | EXPECT_TRUE(hello.IsString()); | |||
EXPECT_STREQ("world", hello.GetString()); | EXPECT_STREQ("world", hello.GetString()); | |||
EXPECT_TRUE(doc.HasMember("t")); | EXPECT_TRUE(doc.HasMember("t")); | |||
const ValueType& t = doc["t"]; | const ValueType& t = doc["t"]; | |||
skipping to change at line 64 | skipping to change at line 74 | |||
EXPECT_TRUE(doc.HasMember("pi")); | EXPECT_TRUE(doc.HasMember("pi")); | |||
const ValueType& pi = doc["pi"]; | const ValueType& pi = doc["pi"]; | |||
EXPECT_TRUE(pi.IsNumber()); | EXPECT_TRUE(pi.IsNumber()); | |||
EXPECT_DOUBLE_EQ(3.1416, pi.GetDouble()); | EXPECT_DOUBLE_EQ(3.1416, pi.GetDouble()); | |||
EXPECT_TRUE(doc.HasMember("a")); | EXPECT_TRUE(doc.HasMember("a")); | |||
const ValueType& a = doc["a"]; | const ValueType& a = doc["a"]; | |||
EXPECT_TRUE(a.IsArray()); | EXPECT_TRUE(a.IsArray()); | |||
EXPECT_EQ(4u, a.Size()); | EXPECT_EQ(4u, a.Size()); | |||
for (SizeType i = 0; i < 4; i++) | for (SizeType j = 0; j < 4; j++) | |||
EXPECT_EQ(i + 1, a[i].GetUint()); | EXPECT_EQ(j + 1, a[j].GetUint()); | |||
} | } | |||
template <typename Allocator, typename StackAllocator> | template <typename Allocator, typename StackAllocator> | |||
void ParseTest() { | void ParseTest() { | |||
typedef GenericDocument<UTF8<>, Allocator, StackAllocator> DocumentType; | typedef GenericDocument<UTF8<>, Allocator, StackAllocator> DocumentType; | |||
DocumentType doc; | DocumentType doc; | |||
const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "; | const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "; | |||
doc.Parse(json); | doc.Parse(json); | |||
skipping to change at line 88 | skipping to change at line 98 | |||
doc.SetNull(); | doc.SetNull(); | |||
StringStream s(json); | StringStream s(json); | |||
doc.template ParseStream<0>(s); | doc.template ParseStream<0>(s); | |||
ParseCheck(doc); | ParseCheck(doc); | |||
doc.SetNull(); | doc.SetNull(); | |||
char *buffer = strdup(json); | char *buffer = strdup(json); | |||
doc.ParseInsitu(buffer); | doc.ParseInsitu(buffer); | |||
ParseCheck(doc); | ParseCheck(doc); | |||
free(buffer); | free(buffer); | |||
// Parse(const Ch*, size_t) | ||||
size_t length = strlen(json); | ||||
buffer = reinterpret_cast<char*>(malloc(length * 2)); | ||||
memcpy(buffer, json, length); | ||||
memset(buffer + length, 'X', length); | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
std::string s2(buffer, length); // backup buffer | ||||
#endif | ||||
doc.SetNull(); | ||||
doc.Parse(buffer, length); | ||||
free(buffer); | ||||
ParseCheck(doc); | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
// Parse(std::string) | ||||
doc.SetNull(); | ||||
doc.Parse(s2); | ||||
ParseCheck(doc); | ||||
#endif | ||||
} | } | |||
TEST(Document, Parse) { | TEST(Document, Parse) { | |||
ParseTest<MemoryPoolAllocator<>, CrtAllocator>(); | ParseTest<MemoryPoolAllocator<>, CrtAllocator>(); | |||
ParseTest<MemoryPoolAllocator<>, MemoryPoolAllocator<> >(); | ParseTest<MemoryPoolAllocator<>, MemoryPoolAllocator<> >(); | |||
ParseTest<CrtAllocator, MemoryPoolAllocator<> >(); | ParseTest<CrtAllocator, MemoryPoolAllocator<> >(); | |||
ParseTest<CrtAllocator, CrtAllocator>(); | ParseTest<CrtAllocator, CrtAllocator>(); | |||
} | } | |||
TEST(Document, UnchangedOnParseError) { | ||||
Document doc; | ||||
doc.SetArray().PushBack(0, doc.GetAllocator()); | ||||
ParseResult err = doc.Parse("{]"); | ||||
EXPECT_TRUE(doc.HasParseError()); | ||||
EXPECT_EQ(err.Code(), doc.GetParseError()); | ||||
EXPECT_EQ(err.Offset(), doc.GetErrorOffset()); | ||||
EXPECT_TRUE(doc.IsArray()); | ||||
EXPECT_EQ(doc.Size(), 1u); | ||||
err = doc.Parse("{}"); | ||||
EXPECT_FALSE(doc.HasParseError()); | ||||
EXPECT_FALSE(err.IsError()); | ||||
EXPECT_EQ(err.Code(), doc.GetParseError()); | ||||
EXPECT_EQ(err.Offset(), doc.GetErrorOffset()); | ||||
EXPECT_TRUE(doc.IsObject()); | ||||
EXPECT_EQ(doc.MemberCount(), 0u); | ||||
} | ||||
static FILE* OpenEncodedFile(const char* filename) { | static FILE* OpenEncodedFile(const char* filename) { | |||
const char *paths[] = { | const char *paths[] = { | |||
"encodings/%s", | "encodings", | |||
"bin/encodings/%s", | "bin/encodings", | |||
"../bin/encodings/%s", | "../bin/encodings", | |||
"../../bin/encodings/%s", | "../../bin/encodings", | |||
"../../../bin/encodings/%s" | "../../../bin/encodings" | |||
}; | }; | |||
char buffer[1024]; | char buffer[1024]; | |||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { | for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) { | |||
sprintf(buffer, paths[i], filename); | sprintf(buffer, "%s/%s", paths[i], filename); | |||
FILE *fp = fopen(buffer, "rb"); | FILE *fp = fopen(buffer, "rb"); | |||
if (fp) | if (fp) | |||
return fp; | return fp; | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
TEST(Document, Parse_Encoding) { | ||||
const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, | ||||
\"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "; | ||||
typedef GenericDocument<UTF16<> > DocumentType; | ||||
DocumentType doc; | ||||
// Parse<unsigned, SourceEncoding>(const SourceEncoding::Ch*) | ||||
// doc.Parse<kParseDefaultFlags, UTF8<> >(json); | ||||
// EXPECT_FALSE(doc.HasParseError()); | ||||
// EXPECT_EQ(0, StrCmp(doc[L"hello"].GetString(), L"world")); | ||||
// Parse<unsigned, SourceEncoding>(const SourceEncoding::Ch*, size_t) | ||||
size_t length = strlen(json); | ||||
char* buffer = reinterpret_cast<char*>(malloc(length * 2)); | ||||
memcpy(buffer, json, length); | ||||
memset(buffer + length, 'X', length); | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
std::string s2(buffer, length); // backup buffer | ||||
#endif | ||||
doc.SetNull(); | ||||
doc.Parse<kParseDefaultFlags, UTF8<> >(buffer, length); | ||||
free(buffer); | ||||
EXPECT_FALSE(doc.HasParseError()); | ||||
if (doc.HasParseError()) | ||||
printf("Error: %d at %zu\n", static_cast<int>(doc.GetParseError()), doc. | ||||
GetErrorOffset()); | ||||
EXPECT_EQ(0, StrCmp(doc[L"hello"].GetString(), L"world")); | ||||
#if RAPIDJSON_HAS_STDSTRING | ||||
// Parse<unsigned, SourceEncoding>(std::string) | ||||
doc.SetNull(); | ||||
#if defined(_MSC_VER) && _MSC_VER < 1800 | ||||
doc.Parse<kParseDefaultFlags, UTF8<> >(s2.c_str()); // VS2010 or below canno | ||||
t handle templated function overloading. Use const char* instead. | ||||
#else | ||||
doc.Parse<kParseDefaultFlags, UTF8<> >(s2); | ||||
#endif | ||||
EXPECT_FALSE(doc.HasParseError()); | ||||
EXPECT_EQ(0, StrCmp(doc[L"hello"].GetString(), L"world")); | ||||
#endif | ||||
} | ||||
TEST(Document, ParseStream_EncodedInputStream) { | TEST(Document, ParseStream_EncodedInputStream) { | |||
// UTF8 -> UTF16 | // UTF8 -> UTF16 | |||
FILE* fp = OpenEncodedFile("utf8.json"); | FILE* fp = OpenEncodedFile("utf8.json"); | |||
char buffer[256]; | char buffer[256]; | |||
FileReadStream bis(fp, buffer, sizeof(buffer)); | FileReadStream bis(fp, buffer, sizeof(buffer)); | |||
EncodedInputStream<UTF8<>, FileReadStream> eis(bis); | EncodedInputStream<UTF8<>, FileReadStream> eis(bis); | |||
GenericDocument<UTF16<> > d; | GenericDocument<UTF16<> > d; | |||
d.ParseStream<0, UTF8<> >(eis); | d.ParseStream<0, UTF8<> >(eis); | |||
EXPECT_FALSE(d.HasParseError()); | EXPECT_FALSE(d.HasParseError()); | |||
skipping to change at line 138 | skipping to change at line 229 | |||
wchar_t expected[] = L"I can eat glass and it doesn't hurt me."; | wchar_t expected[] = L"I can eat glass and it doesn't hurt me."; | |||
GenericValue<UTF16<> >& v = d[L"en"]; | GenericValue<UTF16<> >& v = d[L"en"]; | |||
EXPECT_TRUE(v.IsString()); | EXPECT_TRUE(v.IsString()); | |||
EXPECT_EQ(sizeof(expected) / sizeof(wchar_t) - 1, v.GetStringLength()); | EXPECT_EQ(sizeof(expected) / sizeof(wchar_t) - 1, v.GetStringLength()); | |||
EXPECT_EQ(0, StrCmp(expected, v.GetString())); | EXPECT_EQ(0, StrCmp(expected, v.GetString())); | |||
// UTF16 -> UTF8 in memory | // UTF16 -> UTF8 in memory | |||
StringBuffer bos; | StringBuffer bos; | |||
typedef EncodedOutputStream<UTF8<>, StringBuffer> OutputStream; | typedef EncodedOutputStream<UTF8<>, StringBuffer> OutputStream; | |||
OutputStream eos(bos, false); // Not writing BOM | OutputStream eos(bos, false); // Not writing BOM | |||
Writer<OutputStream, UTF16<>, UTF8<> > writer(eos); | ||||
d.Accept(writer); | ||||
{ | { | |||
// Condense the original file and compare. | Writer<OutputStream, UTF16<>, UTF8<> > writer(eos); | |||
FILE *fp = OpenEncodedFile("utf8.json"); | d.Accept(writer); | |||
FileReadStream is(fp, buffer, sizeof(buffer)); | ||||
Reader reader; | ||||
StringBuffer bos2; | ||||
Writer<StringBuffer> writer(bos2); | ||||
reader.Parse(is, writer); | ||||
fclose(fp); | ||||
EXPECT_EQ(bos.GetSize(), bos2.GetSize()); | ||||
EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); | ||||
} | } | |||
// 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())); | ||||
} | } | |||
TEST(Document, ParseStream_AutoUTFInputStream) { | TEST(Document, ParseStream_AutoUTFInputStream) { | |||
// Any -> UTF8 | // Any -> UTF8 | |||
FILE* fp = OpenEncodedFile("utf32be.json"); | FILE* fp = OpenEncodedFile("utf32be.json"); | |||
char buffer[256]; | char buffer[256]; | |||
FileReadStream bis(fp, buffer, sizeof(buffer)); | FileReadStream bis(fp, buffer, sizeof(buffer)); | |||
AutoUTFInputStream<unsigned, FileReadStream> eis(bis); | AutoUTFInputStream<unsigned, FileReadStream> eis(bis); | |||
Document d; | Document d; | |||
skipping to change at line 180 | skipping to change at line 271 | |||
Value& v = d["en"]; | Value& v = d["en"]; | |||
EXPECT_TRUE(v.IsString()); | EXPECT_TRUE(v.IsString()); | |||
EXPECT_EQ(sizeof(expected) - 1, v.GetStringLength()); | EXPECT_EQ(sizeof(expected) - 1, v.GetStringLength()); | |||
EXPECT_EQ(0, StrCmp(expected, v.GetString())); | EXPECT_EQ(0, StrCmp(expected, v.GetString())); | |||
// UTF8 -> UTF8 in memory | // UTF8 -> UTF8 in memory | |||
StringBuffer bos; | StringBuffer bos; | |||
Writer<StringBuffer> writer(bos); | Writer<StringBuffer> writer(bos); | |||
d.Accept(writer); | d.Accept(writer); | |||
{ | // Condense the original file and compare. | |||
// Condense the original file and compare. | fp = OpenEncodedFile("utf8.json"); | |||
FILE *fp = OpenEncodedFile("utf8.json"); | FileReadStream is(fp, buffer, sizeof(buffer)); | |||
FileReadStream is(fp, buffer, sizeof(buffer)); | Reader reader; | |||
Reader reader; | StringBuffer bos2; | |||
StringBuffer bos2; | Writer<StringBuffer> writer2(bos2); | |||
Writer<StringBuffer> writer(bos2); | reader.Parse(is, writer2); | |||
reader.Parse(is, writer); | fclose(fp); | |||
fclose(fp); | ||||
EXPECT_EQ(bos.GetSize(), bos2.GetSize()); | EXPECT_EQ(bos.GetSize(), bos2.GetSize()); | |||
EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); | EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); | |||
} | ||||
} | } | |||
TEST(Document, Swap) { | TEST(Document, Swap) { | |||
Document d1; | Document d1; | |||
Document::AllocatorType& a = d1.GetAllocator(); | Document::AllocatorType& a = d1.GetAllocator(); | |||
d1.SetArray().PushBack(1, a).PushBack(2, a); | d1.SetArray().PushBack(1, a).PushBack(2, a); | |||
Value o; | Value o; | |||
o.SetObject().AddMember("a", 1, a); | o.SetObject().AddMember("a", 1, a); | |||
// Swap between Document and Value | // Swap between Document and Value | |||
d1.Swap(o); | // d1.Swap(o); // doesn't compile | |||
o.Swap(d1); | ||||
EXPECT_TRUE(d1.IsObject()); | EXPECT_TRUE(d1.IsObject()); | |||
EXPECT_TRUE(o.IsArray()); | EXPECT_TRUE(o.IsArray()); | |||
// Swap between Document and Document | // Swap between Document and Document | |||
Document d2; | Document d2; | |||
d2.SetArray().PushBack(3, a); | d2.SetArray().PushBack(3, a); | |||
d1.Swap(d2); | d1.Swap(d2); | |||
EXPECT_TRUE(d1.IsArray()); | EXPECT_TRUE(d1.IsArray()); | |||
EXPECT_TRUE(d2.IsObject()); | EXPECT_TRUE(d2.IsObject()); | |||
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); | ||||
// 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()); | ||||
} | } | |||
// This should be slow due to assignment in inner-loop. | // This should be slow due to assignment in inner-loop. | |||
struct OutputStringStream : public std::ostringstream { | struct OutputStringStream : public std::ostringstream { | |||
typedef char Ch; | typedef char Ch; | |||
virtual ~OutputStringStream(); | ||||
void Put(char c) { | void Put(char c) { | |||
put(c); | put(c); | |||
} | } | |||
void Flush() {} | void Flush() {} | |||
}; | }; | |||
OutputStringStream::~OutputStringStream() {} | ||||
TEST(Document, AcceptWriter) { | TEST(Document, AcceptWriter) { | |||
Document doc; | Document doc; | |||
doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": nu ll, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); | doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": nu ll, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); | |||
OutputStringStream os; | OutputStringStream os; | |||
Writer<OutputStringStream> writer(os); | Writer<OutputStringStream> writer(os); | |||
doc.Accept(writer); | doc.Accept(writer); | |||
EXPECT_EQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123, \"pi\":3.1416,\"a\":[1,2,3,4]}", os.str()); | EXPECT_EQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123, \"pi\":3.1416,\"a\":[1,2,3,4]}", os.str()); | |||
} | } | |||
skipping to change at line 284 | skipping to change at line 399 | |||
ASSERT_TRUE(v.IsObject()); | ASSERT_TRUE(v.IsObject()); | |||
GenericValue< UTF16<> >& s = v[L"created_at"]; | GenericValue< UTF16<> >& s = v[L"created_at"]; | |||
ASSERT_TRUE(s.IsString()); | ASSERT_TRUE(s.IsString()); | |||
EXPECT_EQ(0, memcmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString(), (s.Get StringLength() + 1) * sizeof(wchar_t))); | EXPECT_EQ(0, memcmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString(), (s.Get StringLength() + 1) * sizeof(wchar_t))); | |||
} | } | |||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS | |||
#if 0 // Many old compiler does not support these. Turn it off temporaily. | ||||
#include <type_traits> | #include <type_traits> | |||
TEST(Document, Traits) { | TEST(Document, Traits) { | |||
static_assert(std::is_constructible<Document>::value, ""); | static_assert(std::is_constructible<Document>::value, ""); | |||
static_assert(std::is_default_constructible<Document>::value, ""); | static_assert(std::is_default_constructible<Document>::value, ""); | |||
#ifndef _MSC_VER | #ifndef _MSC_VER | |||
static_assert(!std::is_copy_constructible<Document>::value, ""); | static_assert(!std::is_copy_constructible<Document>::value, ""); | |||
#endif | #endif | |||
static_assert(std::is_move_constructible<Document>::value, ""); | static_assert(std::is_move_constructible<Document>::value, ""); | |||
skipping to change at line 321 | skipping to change at line 438 | |||
#ifndef _MSC_VER | #ifndef _MSC_VER | |||
static_assert(std::is_nothrow_move_assignable<Document>::value, ""); | static_assert(std::is_nothrow_move_assignable<Document>::value, ""); | |||
#endif | #endif | |||
static_assert( std::is_destructible<Document>::value, ""); | static_assert( std::is_destructible<Document>::value, ""); | |||
#ifndef _MSC_VER | #ifndef _MSC_VER | |||
static_assert(std::is_nothrow_destructible<Document>::value, ""); | static_assert(std::is_nothrow_destructible<Document>::value, ""); | |||
#endif | #endif | |||
} | } | |||
#endif | ||||
template <typename Allocator> | template <typename Allocator> | |||
struct DocumentMove: public ::testing::Test { | struct DocumentMove: public ::testing::Test { | |||
}; | }; | |||
typedef ::testing::Types< CrtAllocator, MemoryPoolAllocator<> > MoveAllocatorTyp es; | typedef ::testing::Types< CrtAllocator, MemoryPoolAllocator<> > MoveAllocatorTyp es; | |||
TYPED_TEST_CASE(DocumentMove, MoveAllocatorTypes); | TYPED_TEST_CASE(DocumentMove, MoveAllocatorTypes); | |||
TYPED_TEST(DocumentMove, MoveConstructor) { | TYPED_TEST(DocumentMove, MoveConstructor) { | |||
typedef TypeParam Allocator; | typedef TypeParam Allocator; | |||
typedef GenericDocument<UTF8<>, Allocator> Document; | typedef GenericDocument<UTF8<>, Allocator> D; | |||
Allocator allocator; | Allocator allocator; | |||
Document a(&allocator); | D a(&allocator); | |||
a.Parse("[\"one\", \"two\", \"three\"]"); | a.Parse("[\"one\", \"two\", \"three\"]"); | |||
EXPECT_FALSE(a.HasParseError()); | EXPECT_FALSE(a.HasParseError()); | |||
EXPECT_TRUE(a.IsArray()); | EXPECT_TRUE(a.IsArray()); | |||
EXPECT_EQ(3u, a.Size()); | EXPECT_EQ(3u, a.Size()); | |||
EXPECT_EQ(&a.GetAllocator(), &allocator); | EXPECT_EQ(&a.GetAllocator(), &allocator); | |||
// Document b(a); // does not compile (!is_copy_constructible) | // Document b(a); // does not compile (!is_copy_constructible) | |||
Document b(std::move(a)); | D b(std::move(a)); | |||
EXPECT_TRUE(a.IsNull()); | EXPECT_TRUE(a.IsNull()); | |||
EXPECT_TRUE(b.IsArray()); | EXPECT_TRUE(b.IsArray()); | |||
EXPECT_EQ(3u, b.Size()); | EXPECT_EQ(3u, b.Size()); | |||
EXPECT_EQ(&a.GetAllocator(), (void*)0); | EXPECT_THROW(a.GetAllocator(), AssertException); | |||
EXPECT_EQ(&b.GetAllocator(), &allocator); | EXPECT_EQ(&b.GetAllocator(), &allocator); | |||
b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}"); | b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}"); | |||
EXPECT_FALSE(b.HasParseError()); | EXPECT_FALSE(b.HasParseError()); | |||
EXPECT_TRUE(b.IsObject()); | EXPECT_TRUE(b.IsObject()); | |||
EXPECT_EQ(2u, b.MemberCount()); | EXPECT_EQ(2u, b.MemberCount()); | |||
// Document c = a; // does not compile (!is_copy_constructible) | // Document c = a; // does not compile (!is_copy_constructible) | |||
Document c = std::move(b); | D c = std::move(b); | |||
EXPECT_TRUE(b.IsNull()); | EXPECT_TRUE(b.IsNull()); | |||
EXPECT_TRUE(c.IsObject()); | EXPECT_TRUE(c.IsObject()); | |||
EXPECT_EQ(2u, c.MemberCount()); | EXPECT_EQ(2u, c.MemberCount()); | |||
EXPECT_EQ(&b.GetAllocator(), (void*)0); | EXPECT_THROW(b.GetAllocator(), AssertException); | |||
EXPECT_EQ(&c.GetAllocator(), &allocator); | EXPECT_EQ(&c.GetAllocator(), &allocator); | |||
} | } | |||
TYPED_TEST(DocumentMove, MoveConstructorParseError) { | TYPED_TEST(DocumentMove, MoveConstructorParseError) { | |||
typedef TypeParam Allocator; | typedef TypeParam Allocator; | |||
typedef GenericDocument<UTF8<>, Allocator> Document; | typedef GenericDocument<UTF8<>, Allocator> D; | |||
ParseResult noError; | ParseResult noError; | |||
Document a; | D a; | |||
a.Parse("{ 4 = 4]"); | a.Parse("{ 4 = 4]"); | |||
ParseResult error(a.GetParseError(), a.GetErrorOffset()); | ParseResult error(a.GetParseError(), a.GetErrorOffset()); | |||
EXPECT_TRUE(a.HasParseError()); | EXPECT_TRUE(a.HasParseError()); | |||
EXPECT_NE(error.Code(), noError.Code()); | EXPECT_NE(error.Code(), noError.Code()); | |||
EXPECT_NE(error.Offset(), noError.Offset()); | EXPECT_NE(error.Offset(), noError.Offset()); | |||
Document b(std::move(a)); | D b(std::move(a)); | |||
EXPECT_FALSE(a.HasParseError()); | EXPECT_FALSE(a.HasParseError()); | |||
EXPECT_TRUE(b.HasParseError()); | EXPECT_TRUE(b.HasParseError()); | |||
EXPECT_EQ(a.GetParseError(), noError.Code()); | EXPECT_EQ(a.GetParseError(), noError.Code()); | |||
EXPECT_EQ(b.GetParseError(), error.Code()); | EXPECT_EQ(b.GetParseError(), error.Code()); | |||
EXPECT_EQ(a.GetErrorOffset(), noError.Offset()); | EXPECT_EQ(a.GetErrorOffset(), noError.Offset()); | |||
EXPECT_EQ(b.GetErrorOffset(), error.Offset()); | EXPECT_EQ(b.GetErrorOffset(), error.Offset()); | |||
Document c(std::move(b)); | D c(std::move(b)); | |||
EXPECT_FALSE(b.HasParseError()); | EXPECT_FALSE(b.HasParseError()); | |||
EXPECT_TRUE(c.HasParseError()); | EXPECT_TRUE(c.HasParseError()); | |||
EXPECT_EQ(b.GetParseError(), noError.Code()); | EXPECT_EQ(b.GetParseError(), noError.Code()); | |||
EXPECT_EQ(c.GetParseError(), error.Code()); | EXPECT_EQ(c.GetParseError(), error.Code()); | |||
EXPECT_EQ(b.GetErrorOffset(), noError.Offset()); | EXPECT_EQ(b.GetErrorOffset(), noError.Offset()); | |||
EXPECT_EQ(c.GetErrorOffset(), error.Offset()); | EXPECT_EQ(c.GetErrorOffset(), error.Offset()); | |||
} | } | |||
// This test does not properly use parsing, just for testing. | // This test does not properly use parsing, just for testing. | |||
// It must call ClearStack() explicitly to prevent memory leak. | // It must call ClearStack() explicitly to prevent memory leak. | |||
skipping to change at line 423 | skipping to change at line 542 | |||
EXPECT_EQ(b.GetStackCapacity(), capacity); | EXPECT_EQ(b.GetStackCapacity(), capacity); | |||
Document c = std::move(b); | Document c = std::move(b); | |||
EXPECT_EQ(b.GetStackCapacity(), defaultCapacity); | EXPECT_EQ(b.GetStackCapacity(), defaultCapacity); | |||
EXPECT_EQ(c.GetStackCapacity(), capacity); | EXPECT_EQ(c.GetStackCapacity(), capacity); | |||
} | } | |||
#endif | #endif | |||
TYPED_TEST(DocumentMove, MoveAssignment) { | TYPED_TEST(DocumentMove, MoveAssignment) { | |||
typedef TypeParam Allocator; | typedef TypeParam Allocator; | |||
typedef GenericDocument<UTF8<>, Allocator> Document; | typedef GenericDocument<UTF8<>, Allocator> D; | |||
Allocator allocator; | Allocator allocator; | |||
Document a(&allocator); | D a(&allocator); | |||
a.Parse("[\"one\", \"two\", \"three\"]"); | a.Parse("[\"one\", \"two\", \"three\"]"); | |||
EXPECT_FALSE(a.HasParseError()); | EXPECT_FALSE(a.HasParseError()); | |||
EXPECT_TRUE(a.IsArray()); | EXPECT_TRUE(a.IsArray()); | |||
EXPECT_EQ(3u, a.Size()); | EXPECT_EQ(3u, a.Size()); | |||
EXPECT_EQ(&a.GetAllocator(), &allocator); | EXPECT_EQ(&a.GetAllocator(), &allocator); | |||
// Document b; b = a; // does not compile (!is_copy_assignable) | // Document b; b = a; // does not compile (!is_copy_assignable) | |||
Document b; | D b; | |||
b = std::move(a); | b = std::move(a); | |||
EXPECT_TRUE(a.IsNull()); | EXPECT_TRUE(a.IsNull()); | |||
EXPECT_TRUE(b.IsArray()); | EXPECT_TRUE(b.IsArray()); | |||
EXPECT_EQ(3u, b.Size()); | EXPECT_EQ(3u, b.Size()); | |||
EXPECT_EQ(&a.GetAllocator(), (void*)0); | EXPECT_THROW(a.GetAllocator(), AssertException); | |||
EXPECT_EQ(&b.GetAllocator(), &allocator); | EXPECT_EQ(&b.GetAllocator(), &allocator); | |||
b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}"); | b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}"); | |||
EXPECT_FALSE(b.HasParseError()); | EXPECT_FALSE(b.HasParseError()); | |||
EXPECT_TRUE(b.IsObject()); | EXPECT_TRUE(b.IsObject()); | |||
EXPECT_EQ(2u, b.MemberCount()); | EXPECT_EQ(2u, b.MemberCount()); | |||
// Document c; c = a; // does not compile (see static_assert) | // Document c; c = a; // does not compile (see static_assert) | |||
Document c; | D c; | |||
c = std::move(b); | c = std::move(b); | |||
EXPECT_TRUE(b.IsNull()); | EXPECT_TRUE(b.IsNull()); | |||
EXPECT_TRUE(c.IsObject()); | EXPECT_TRUE(c.IsObject()); | |||
EXPECT_EQ(2u, c.MemberCount()); | EXPECT_EQ(2u, c.MemberCount()); | |||
EXPECT_EQ(&b.GetAllocator(), (void*)0); | EXPECT_THROW(b.GetAllocator(), AssertException); | |||
EXPECT_EQ(&c.GetAllocator(), &allocator); | EXPECT_EQ(&c.GetAllocator(), &allocator); | |||
} | } | |||
TYPED_TEST(DocumentMove, MoveAssignmentParseError) { | TYPED_TEST(DocumentMove, MoveAssignmentParseError) { | |||
typedef TypeParam Allocator; | typedef TypeParam Allocator; | |||
typedef GenericDocument<UTF8<>, Allocator> Document; | typedef GenericDocument<UTF8<>, Allocator> D; | |||
ParseResult noError; | ParseResult noError; | |||
Document a; | D a; | |||
a.Parse("{ 4 = 4]"); | a.Parse("{ 4 = 4]"); | |||
ParseResult error(a.GetParseError(), a.GetErrorOffset()); | ParseResult error(a.GetParseError(), a.GetErrorOffset()); | |||
EXPECT_TRUE(a.HasParseError()); | EXPECT_TRUE(a.HasParseError()); | |||
EXPECT_NE(error.Code(), noError.Code()); | EXPECT_NE(error.Code(), noError.Code()); | |||
EXPECT_NE(error.Offset(), noError.Offset()); | EXPECT_NE(error.Offset(), noError.Offset()); | |||
Document b; | D b; | |||
b = std::move(a); | b = std::move(a); | |||
EXPECT_FALSE(a.HasParseError()); | EXPECT_FALSE(a.HasParseError()); | |||
EXPECT_TRUE(b.HasParseError()); | EXPECT_TRUE(b.HasParseError()); | |||
EXPECT_EQ(a.GetParseError(), noError.Code()); | EXPECT_EQ(a.GetParseError(), noError.Code()); | |||
EXPECT_EQ(b.GetParseError(), error.Code()); | EXPECT_EQ(b.GetParseError(), error.Code()); | |||
EXPECT_EQ(a.GetErrorOffset(), noError.Offset()); | EXPECT_EQ(a.GetErrorOffset(), noError.Offset()); | |||
EXPECT_EQ(b.GetErrorOffset(), error.Offset()); | EXPECT_EQ(b.GetErrorOffset(), error.Offset()); | |||
Document c; | D c; | |||
c = std::move(b); | c = std::move(b); | |||
EXPECT_FALSE(b.HasParseError()); | EXPECT_FALSE(b.HasParseError()); | |||
EXPECT_TRUE(c.HasParseError()); | EXPECT_TRUE(c.HasParseError()); | |||
EXPECT_EQ(b.GetParseError(), noError.Code()); | EXPECT_EQ(b.GetParseError(), noError.Code()); | |||
EXPECT_EQ(c.GetParseError(), error.Code()); | EXPECT_EQ(c.GetParseError(), error.Code()); | |||
EXPECT_EQ(b.GetErrorOffset(), noError.Offset()); | EXPECT_EQ(b.GetErrorOffset(), noError.Offset()); | |||
EXPECT_EQ(c.GetErrorOffset(), error.Offset()); | EXPECT_EQ(c.GetErrorOffset(), error.Offset()); | |||
} | } | |||
// This test does not properly use parsing, just for testing. | // This test does not properly use parsing, just for testing. | |||
// It must call ClearStack() explicitly to prevent memory leak. | // It must call ClearStack() explicitly to prevent memory leak. | |||
// But here we cannot as ClearStack() is private. | // But here we cannot as ClearStack() is private. | |||
#if 0 | #if 0 | |||
TYPED_TEST(DocumentMove, MoveAssignmentStack) { | TYPED_TEST(DocumentMove, MoveAssignmentStack) { | |||
typedef TypeParam Allocator; | typedef TypeParam Allocator; | |||
typedef UTF8<> Encoding; | typedef UTF8<> Encoding; | |||
typedef GenericDocument<Encoding, Allocator> Document; | typedef GenericDocument<Encoding, Allocator> D; | |||
Document a; | D a; | |||
size_t defaultCapacity = a.GetStackCapacity(); | size_t defaultCapacity = a.GetStackCapacity(); | |||
// Trick Document into getting GetStackCapacity() to return non-zero | // Trick Document into getting GetStackCapacity() to return non-zero | |||
typedef GenericReader<Encoding, Encoding, Allocator> Reader; | typedef GenericReader<Encoding, Encoding, Allocator> Reader; | |||
Reader reader(&a.GetAllocator()); | Reader reader(&a.GetAllocator()); | |||
GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]"); | GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]"); | |||
reader.template Parse<kParseDefaultFlags>(is, a); | reader.template Parse<kParseDefaultFlags>(is, a); | |||
size_t capacity = a.GetStackCapacity(); | size_t capacity = a.GetStackCapacity(); | |||
EXPECT_GT(capacity, 0u); | EXPECT_GT(capacity, 0u); | |||
Document b; | D b; | |||
b = std::move(a); | b = std::move(a); | |||
EXPECT_EQ(a.GetStackCapacity(), defaultCapacity); | EXPECT_EQ(a.GetStackCapacity(), defaultCapacity); | |||
EXPECT_EQ(b.GetStackCapacity(), capacity); | EXPECT_EQ(b.GetStackCapacity(), capacity); | |||
Document c; | D c; | |||
c = std::move(b); | c = std::move(b); | |||
EXPECT_EQ(b.GetStackCapacity(), defaultCapacity); | EXPECT_EQ(b.GetStackCapacity(), defaultCapacity); | |||
EXPECT_EQ(c.GetStackCapacity(), capacity); | EXPECT_EQ(c.GetStackCapacity(), capacity); | |||
} | } | |||
#endif | #endif | |||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS | #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS | |||
// Issue 22: Memory corruption via operator= | // Issue 22: Memory corruption via operator= | |||
// Fixed by making unimplemented assignment operator private. | // Fixed by making unimplemented assignment operator private. | |||
//TEST(Document, Assignment) { | //TEST(Document, Assignment) { | |||
// Document d1; | // Document d1; | |||
// Document d2; | // Document d2; | |||
// d1 = d2; | // d1 = d2; | |||
//} | //} | |||
#ifdef __clang__ | ||||
RAPIDJSON_DIAG_POP | ||||
#endif | ||||
End of changes. 44 change blocks. | ||||
59 lines changed or deleted | 182 lines changed or added |