/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #include #include #include #include #include #include #include #include namespace AZ::Dom::Tests { class DomJsonTests : public DomTestFixture { public: void SetUp() override { DomTestFixture::SetUp(); m_document = AZStd::make_unique(); } void TearDown() override { m_document.reset(); DomTestFixture::TearDown(); } rapidjson::Value CreateString(const AZStd::string& text) { rapidjson::Value key; key.SetString(text.c_str(), static_cast(text.length()), m_document->GetAllocator()); return key; } template void AddValue(const AZStd::string& key, T value) { m_document->AddMember(CreateString(key), rapidjson::Value(value), m_document->GetAllocator()); } // Validate round-trip serialization to and from rapidjson::Document and a UTF-8 encoded string void PerformSerializationChecks() { // Generate a canonical serializaed representation of this document using rapidjson // This will be pretty-printed using the same rapidjson pretty printer we use, so should be binary identical // to any output generated by the visitor API AZStd::string canonicalSerializedDocument; AZ::JsonSerializationUtils::WriteJsonString(*m_document, canonicalSerializedDocument); auto visitDocumentFn = [this](AZ::Dom::Visitor& visitor) { return Json::VisitRapidJsonValue(*m_document, visitor, Lifetime::Temporary); }; // Document -> Document { auto result = Json::WriteToRapidJsonDocument(visitDocumentFn); EXPECT_TRUE(result.IsSuccess()); EXPECT_EQ(AZ::JsonSerialization::Compare(*m_document, result.GetValue()), AZ::JsonSerializerCompareResult::Equal); } // Document -> string { AZStd::string serializedDocument; JsonBackend backend; auto result = backend.WriteToBuffer(serializedDocument, visitDocumentFn); EXPECT_TRUE(result.IsSuccess()); EXPECT_EQ(canonicalSerializedDocument, serializedDocument); } // string -> Document { auto result = Json::WriteToRapidJsonDocument( [&canonicalSerializedDocument](AZ::Dom::Visitor& visitor) { JsonBackend backend; return Dom::Utils::ReadFromString(backend, canonicalSerializedDocument, Lifetime::Temporary, visitor); }); EXPECT_TRUE(result.IsSuccess()); EXPECT_EQ(AZ::JsonSerialization::Compare(*m_document, result.GetValue()), JsonSerializerCompareResult::Equal); } // string -> string { AZStd::string serializedDocument; JsonBackend backend; auto result = backend.WriteToBuffer( serializedDocument, [&backend, &canonicalSerializedDocument](AZ::Dom::Visitor& visitor) { return Dom::Utils::ReadFromString(backend, canonicalSerializedDocument, Lifetime::Temporary, visitor); }); EXPECT_TRUE(result.IsSuccess()); EXPECT_EQ(canonicalSerializedDocument, serializedDocument); } } AZStd::unique_ptr m_document; }; TEST_F(DomJsonTests, EmptyArray) { m_document->SetArray(); PerformSerializationChecks(); } TEST_F(DomJsonTests, SimpleArray) { m_document->SetArray(); for (int i = 0; i < 5; ++i) { m_document->PushBack(i, m_document->GetAllocator()); } PerformSerializationChecks(); } TEST_F(DomJsonTests, NestedArrays) { m_document->SetArray(); for (int j = 0; j < 7; ++j) { rapidjson::Value nestedArray(rapidjson::kArrayType); for (int i = 0; i < 5; ++i) { nestedArray.PushBack(i, m_document->GetAllocator()); } m_document->PushBack(nestedArray.Move(), m_document->GetAllocator()); } PerformSerializationChecks(); } TEST_F(DomJsonTests, EmptyObject) { m_document->SetObject(); PerformSerializationChecks(); } TEST_F(DomJsonTests, SimpleObject) { m_document->SetObject(); for (int i = 0; i < 5; ++i) { m_document->AddMember(CreateString(AZStd::string::format("Key%i", i)), rapidjson::Value(i), m_document->GetAllocator()); } PerformSerializationChecks(); } TEST_F(DomJsonTests, NestedObjects) { m_document->SetObject(); for (int j = 0; j < 7; ++j) { rapidjson::Value nestedObject(rapidjson::kObjectType); for (int i = 0; i < 5; ++i) { nestedObject.AddMember(CreateString(AZStd::string::format("Key%i", i)), rapidjson::Value(i), m_document->GetAllocator()); } m_document->AddMember(CreateString(AZStd::string::format("Obj%i", j)), nestedObject.Move(), m_document->GetAllocator()); } PerformSerializationChecks(); } TEST_F(DomJsonTests, Int64) { m_document->SetObject(); AddValue("int64_min", AZStd::numeric_limits::min()); AddValue("int64_max", AZStd::numeric_limits::max()); PerformSerializationChecks(); } TEST_F(DomJsonTests, Uint64) { m_document->SetObject(); AddValue("uint64_min", AZStd::numeric_limits::min()); AddValue("uint64_max", AZStd::numeric_limits::max()); PerformSerializationChecks(); } TEST_F(DomJsonTests, Double) { m_document->SetObject(); AddValue("double_min", AZStd::numeric_limits::min()); AddValue("double_max", AZStd::numeric_limits::max()); PerformSerializationChecks(); } TEST_F(DomJsonTests, Null) { m_document->SetObject(); m_document->AddMember(CreateString("null_value"), rapidjson::Value(rapidjson::kNullType), m_document->GetAllocator()); PerformSerializationChecks(); } TEST_F(DomJsonTests, Bool) { m_document->SetObject(); AddValue("true_value", true); AddValue("false_value", false); PerformSerializationChecks(); } TEST_F(DomJsonTests, String) { m_document->SetObject(); m_document->AddMember(CreateString("empty_string"), CreateString(""), m_document->GetAllocator()); m_document->AddMember(CreateString("short_string"), CreateString("test"), m_document->GetAllocator()); m_document->AddMember( CreateString("long_string"), CreateString("abcdefghijklmnopqrstuvwxyz0123456789"), m_document->GetAllocator()); PerformSerializationChecks(); } } // namespace AZ::Dom::Tests