From c2b364a77a5bd147cca0dffdb7d8555cc615b5c8 Mon Sep 17 00:00:00 2001 From: pulimsr Date: Tue, 9 Jun 2026 14:40:15 -0400 Subject: [PATCH] adding the JsonShapeSerializer --- src/aws-cpp-sdk-core/CMakeLists.txt | 10 +- .../include/smithy/client/schema/Schema.h | 2 + .../client/schema/JsonShapeSerializer.cpp | 209 ++++++++++ tests/aws-cpp-sdk-core-tests/CMakeLists.txt | 1 + .../client/schema/JsonShapeSerializerTest.cpp | 364 ++++++++++++++++++ 5 files changed, 585 insertions(+), 1 deletion(-) create mode 100644 src/aws-cpp-sdk-core/source/smithy/client/schema/JsonShapeSerializer.cpp create mode 100644 tests/aws-cpp-sdk-core-tests/smithy/client/schema/JsonShapeSerializerTest.cpp diff --git a/src/aws-cpp-sdk-core/CMakeLists.txt b/src/aws-cpp-sdk-core/CMakeLists.txt index 14ae520433e3..007d30752407 100644 --- a/src/aws-cpp-sdk-core/CMakeLists.txt +++ b/src/aws-cpp-sdk-core/CMakeLists.txt @@ -543,7 +543,15 @@ check_cxx_source_compiles(" return 0; }" AWS_HAS_ALIGNED_ALLOC) -add_library(${PROJECT_NAME} ${AWS_NATIVE_SDK_SRC}) +add_library(${PROJECT_NAME} ${AWS_NATIVE_SDK_SRC} + include/smithy/client/schema/ShapeSerializer.h + include/smithy/client/schema/CborShapeSerializer.h + include/smithy/client/schema/Schema.h + include/smithy/client/schema/JsonShapeSerializer.h + include/smithy/client/schema/QueryShapeSerializer.h + include/smithy/client/schema/XmlShapeSerializer.h + source/smithy/client/schema/JsonShapeSerializer.cpp +) add_library(AWS::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) target_compile_definitions(${PROJECT_NAME} PUBLIC "AWS_SDK_VERSION_MAJOR=${AWSSDK_VERSION_MAJOR}") diff --git a/src/aws-cpp-sdk-core/include/smithy/client/schema/Schema.h b/src/aws-cpp-sdk-core/include/smithy/client/schema/Schema.h index a8a8cacb3a61..4cbe8e366ae7 100644 --- a/src/aws-cpp-sdk-core/include/smithy/client/schema/Schema.h +++ b/src/aws-cpp-sdk-core/include/smithy/client/schema/Schema.h @@ -35,6 +35,8 @@ enum class ShapeType : uint8_t { class Schema { public: Schema() = default; + Schema(const char* memberName, ShapeType type) + : m_type(type), m_memberName(memberName) {} ShapeType GetType() const { return m_type; } const char* GetId() const { return m_id; } diff --git a/src/aws-cpp-sdk-core/source/smithy/client/schema/JsonShapeSerializer.cpp b/src/aws-cpp-sdk-core/source/smithy/client/schema/JsonShapeSerializer.cpp new file mode 100644 index 000000000000..f1368900dcdc --- /dev/null +++ b/src/aws-cpp-sdk-core/source/smithy/client/schema/JsonShapeSerializer.cpp @@ -0,0 +1,209 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include +#include +#include + +using namespace smithy::schema; +using namespace Aws::Utils; +using namespace Aws::Utils::Json; + +struct JsonShapeSerializer::Impl { + JsonValue m_root; + + struct StackEntry { + JsonValue object; + const char* fieldName = nullptr; + bool isList = false; + bool isMap = false; + Aws::Vector listItems; + }; + + Aws::Vector m_stack; + Aws::String m_currentMapKey; + + JsonValue& CurrentObject() { + if (m_stack.empty()) return m_root; + return m_stack.back().object; + } + + const char* CurrentKey(const Schema& schema) { + if (!m_stack.empty() && m_stack.back().isMap) return m_currentMapKey.c_str(); + return schema.GetMemberName(); + } + + void BeginStructure(const Schema&) {} + void EndStructure() {} + + void WriteBoolean(const Schema& schema, bool value) { + if (!m_stack.empty() && m_stack.back().isList) { + JsonValue v; + v.AsBool(value); + m_stack.back().listItems.push_back(std::move(v)); + } else { + CurrentObject().WithBool(CurrentKey(schema), value); + } + } + + void WriteInteger(const Schema& schema, int value) { + if (!m_stack.empty() && m_stack.back().isList) { + JsonValue v; + v.AsInteger(value); + m_stack.back().listItems.push_back(std::move(v)); + } else { + CurrentObject().WithInteger(CurrentKey(schema), value); + } + } + + void WriteLong(const Schema& schema, int64_t value) { + if (!m_stack.empty() && m_stack.back().isList) { + JsonValue v; + v.AsInt64(value); + m_stack.back().listItems.push_back(std::move(v)); + } else { + CurrentObject().WithInt64(CurrentKey(schema), value); + } + } + + void WriteDouble(const Schema& schema, double value) { + if (!m_stack.empty() && m_stack.back().isList) { + JsonValue v; + v.AsDouble(value); + m_stack.back().listItems.push_back(std::move(v)); + } else { + CurrentObject().WithDouble(CurrentKey(schema), value); + } + } + + void WriteString(const Schema& schema, const Aws::String& value) { + if (!m_stack.empty() && m_stack.back().isList) { + JsonValue v; + v.AsString(value); + m_stack.back().listItems.push_back(std::move(v)); + } else { + CurrentObject().WithString(CurrentKey(schema), value); + } + } + + void WriteTimestamp(const Schema& schema, const DateTime& value) { + if (!m_stack.empty() && m_stack.back().isList) { + JsonValue v; + v.AsDouble(value.SecondsWithMSPrecision()); + m_stack.back().listItems.push_back(std::move(v)); + } else { + CurrentObject().WithDouble(CurrentKey(schema), value.SecondsWithMSPrecision()); + } + } + + void WriteBlob(const Schema& schema, const ByteBuffer& value) { + Aws::String encoded = HashingUtils::Base64Encode(value); + if (!m_stack.empty() && m_stack.back().isList) { + JsonValue v; + v.AsString(encoded); + m_stack.back().listItems.push_back(std::move(v)); + } else { + CurrentObject().WithString(CurrentKey(schema), encoded); + } + } + + void WriteEnum(const Schema& schema, int value) { WriteInteger(schema, value); } + + void WriteNull(const Schema& schema) { + if (!m_stack.empty() && m_stack.back().isList) { + JsonValue v; + v.AsNull(); + m_stack.back().listItems.push_back(std::move(v)); + } else { + CurrentObject().WithNull(CurrentKey(schema)); + } + } + + void BeginList(const Schema& schema, size_t) { + StackEntry entry; + entry.fieldName = CurrentKey(schema); + entry.isList = true; + m_stack.push_back(std::move(entry)); + } + + void EndList() { + auto entry = std::move(m_stack.back()); + m_stack.pop_back(); + + Array arr(entry.listItems.size()); + for (size_t i = 0; i < entry.listItems.size(); ++i) { + arr[i] = std::move(entry.listItems[i]); + } + + if (!m_stack.empty() && m_stack.back().isList) { + JsonValue listVal; + listVal.WithArray("", std::move(arr)); + m_stack.back().listItems.push_back(std::move(listVal)); + } else { + CurrentObject().WithArray(entry.fieldName, std::move(arr)); + } + } + + void BeginMap(const Schema& schema, size_t) { + StackEntry entry; + entry.fieldName = CurrentKey(schema); + entry.isMap = true; + m_stack.push_back(std::move(entry)); + } + + void WriteMapKey(const Aws::String& key) { m_currentMapKey = key; } + + void EndMap() { + auto entry = std::move(m_stack.back()); + m_stack.pop_back(); + + if (!m_stack.empty() && m_stack.back().isList) { + m_stack.back().listItems.push_back(std::move(entry.object)); + } else { + CurrentObject().WithObject(entry.fieldName, std::move(entry.object)); + } + } + + void BeginNestedStructure(const Schema& schema) { + StackEntry entry; + entry.fieldName = CurrentKey(schema); + m_stack.push_back(std::move(entry)); + } + + void EndNestedStructure() { + auto entry = std::move(m_stack.back()); + m_stack.pop_back(); + + if (!m_stack.empty() && m_stack.back().isList) { + m_stack.back().listItems.push_back(std::move(entry.object)); + } else { + CurrentObject().WithObject(entry.fieldName, std::move(entry.object)); + } + } + + Aws::String GetPayload() const { return m_root.View().WriteCompact(); } +}; + +JsonShapeSerializer::JsonShapeSerializer() : m_impl(new Impl) {} +JsonShapeSerializer::~JsonShapeSerializer() = default; + +void JsonShapeSerializer::BeginStructure(const Schema& schema) { m_impl->BeginStructure(schema); } +void JsonShapeSerializer::EndStructure() { m_impl->EndStructure(); } +void JsonShapeSerializer::WriteBoolean(const Schema& schema, bool value) { m_impl->WriteBoolean(schema, value); } +void JsonShapeSerializer::WriteInteger(const Schema& schema, int value) { m_impl->WriteInteger(schema, value); } +void JsonShapeSerializer::WriteLong(const Schema& schema, int64_t value) { m_impl->WriteLong(schema, value); } +void JsonShapeSerializer::WriteDouble(const Schema& schema, double value) { m_impl->WriteDouble(schema, value); } +void JsonShapeSerializer::WriteString(const Schema& schema, const Aws::String& value) { m_impl->WriteString(schema, value); } +void JsonShapeSerializer::WriteTimestamp(const Schema& schema, const DateTime& value) { m_impl->WriteTimestamp(schema, value); } +void JsonShapeSerializer::WriteBlob(const Schema& schema, const ByteBuffer& value) { m_impl->WriteBlob(schema, value); } +void JsonShapeSerializer::WriteEnum(const Schema& schema, int value) { m_impl->WriteEnum(schema, value); } +void JsonShapeSerializer::WriteNull(const Schema& schema) { m_impl->WriteNull(schema); } +void JsonShapeSerializer::BeginList(const Schema& schema, size_t count) { m_impl->BeginList(schema, count); } +void JsonShapeSerializer::EndList() { m_impl->EndList(); } +void JsonShapeSerializer::BeginMap(const Schema& schema, size_t count) { m_impl->BeginMap(schema, count); } +void JsonShapeSerializer::WriteMapKey(const Aws::String& key) { m_impl->WriteMapKey(key); } +void JsonShapeSerializer::EndMap() { m_impl->EndMap(); } +void JsonShapeSerializer::BeginNestedStructure(const Schema& schema) { m_impl->BeginNestedStructure(schema); } +void JsonShapeSerializer::EndNestedStructure() { m_impl->EndNestedStructure(); } +Aws::String JsonShapeSerializer::GetPayload() const { return m_impl->GetPayload(); } diff --git a/tests/aws-cpp-sdk-core-tests/CMakeLists.txt b/tests/aws-cpp-sdk-core-tests/CMakeLists.txt index 36cdad1290c5..4ce72d351177 100644 --- a/tests/aws-cpp-sdk-core-tests/CMakeLists.txt +++ b/tests/aws-cpp-sdk-core-tests/CMakeLists.txt @@ -27,6 +27,7 @@ file(GLOB UTILS_COMPONENT_REGISTRY_SRC "${CMAKE_CURRENT_SOURCE_DIR}/utils/compon file(GLOB MONITORING_SRC "${CMAKE_CURRENT_SOURCE_DIR}/monitoring/*.cpp") file(GLOB SMITHY_TRACING_SRC "${CMAKE_CURRENT_SOURCE_DIR}/smithy/tracing/*.cpp") file(GLOB SMITHY_CLIENT_SRC "${CMAKE_CURRENT_SOURCE_DIR}/smithy/client/*.cpp") +file(GLOB SMITHY_CLIENT_SRC "${CMAKE_CURRENT_SOURCE_DIR}/smithy/client/schema/*.cpp") file(GLOB SMITHY_CLIENT_SERIALIZER_SRC "${CMAKE_CURRENT_SOURCE_DIR}/smithy/client/serializer/*.cpp") file(GLOB SMITHY_CLIENT_FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/smithy/client/feature/*.cpp") file(GLOB ENDPOINT_SRC "${CMAKE_CURRENT_SOURCE_DIR}/endpoint/*.cpp") diff --git a/tests/aws-cpp-sdk-core-tests/smithy/client/schema/JsonShapeSerializerTest.cpp b/tests/aws-cpp-sdk-core-tests/smithy/client/schema/JsonShapeSerializerTest.cpp new file mode 100644 index 000000000000..bd9ba79ac926 --- /dev/null +++ b/tests/aws-cpp-sdk-core-tests/smithy/client/schema/JsonShapeSerializerTest.cpp @@ -0,0 +1,364 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include +#include +#include + +using namespace smithy::schema; + +class JsonShapeSerializerTest : public Aws::Testing::AwsCppSdkGTestSuite {}; + +// --- Scalars --- + +TEST_F(JsonShapeSerializerTest, EmptyStructure) { + JsonShapeSerializer s; + Schema root; + s.BeginStructure(root); + s.EndStructure(); + EXPECT_EQ(s.GetPayload(), "{}"); +} + +TEST_F(JsonShapeSerializerTest, BooleanTrue) { + JsonShapeSerializer s; + Schema root; + Schema member("enabled", ShapeType::Boolean); + s.BeginStructure(root); + s.WriteBoolean(member, true); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"enabled\":true"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, BooleanFalse) { + JsonShapeSerializer s; + Schema root; + Schema member("enabled", ShapeType::Boolean); + s.BeginStructure(root); + s.WriteBoolean(member, false); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"enabled\":false"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, Integer) { + JsonShapeSerializer s; + Schema root; + Schema member("count", ShapeType::Integer); + s.BeginStructure(root); + s.WriteInteger(member, 42); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"count\":42"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, Long) { + JsonShapeSerializer s; + Schema root; + Schema member("bigNum", ShapeType::Long); + s.BeginStructure(root); + s.WriteLong(member, 9876543210LL); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"bigNum\":9876543210"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, Double) { + JsonShapeSerializer s; + Schema root; + Schema member("ratio", ShapeType::Double); + s.BeginStructure(root); + s.WriteDouble(member, 3.14); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"ratio\":3.14"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, String) { + JsonShapeSerializer s; + Schema root; + Schema member("name", ShapeType::String); + s.BeginStructure(root); + s.WriteString(member, "hello"); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"name\":\"hello\""), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, EmptyString) { + JsonShapeSerializer s; + Schema root; + Schema member("name", ShapeType::String); + s.BeginStructure(root); + s.WriteString(member, ""); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"name\":\"\""), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, Timestamp) { + JsonShapeSerializer s; + Schema root; + Schema member("created", ShapeType::Timestamp); + s.BeginStructure(root); + Aws::Utils::DateTime dt(1234567890.0); + s.WriteTimestamp(member, dt); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"created\":"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, Blob) { + JsonShapeSerializer s; + Schema root; + Schema member("data", ShapeType::Blob); + s.BeginStructure(root); + unsigned char raw[] = {0x66, 0x6f, 0x6f}; + Aws::Utils::ByteBuffer buf(raw, 3); + s.WriteBlob(member, buf); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"data\":\"Zm9v\""), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, NullValue) { + JsonShapeSerializer s; + Schema root; + Schema member("item", ShapeType::String); + s.BeginStructure(root); + s.WriteNull(member); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"item\":null"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, MultipleScalars) { + JsonShapeSerializer s; + Schema root; + Schema m1("a", ShapeType::Boolean); + Schema m2("b", ShapeType::Integer); + Schema m3("c", ShapeType::String); + s.BeginStructure(root); + s.WriteBoolean(m1, true); + s.WriteInteger(m2, 7); + s.WriteString(m3, "x"); + s.EndStructure(); + auto payload = s.GetPayload(); + EXPECT_NE(payload.find("\"a\":true"), Aws::String::npos); + EXPECT_NE(payload.find("\"b\":7"), Aws::String::npos); + EXPECT_NE(payload.find("\"c\":\"x\""), Aws::String::npos); +} + +// --- Nested structures --- + +TEST_F(JsonShapeSerializerTest, NestedStructure) { + JsonShapeSerializer s; + Schema root; + Schema nested("metadata", ShapeType::Structure); + Schema inner("key", ShapeType::String); + s.BeginStructure(root); + s.BeginNestedStructure(nested); + s.WriteString(inner, "val"); + s.EndNestedStructure(); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"metadata\":{\"key\":\"val\"}"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, DeeplyNestedStructure) { + JsonShapeSerializer s; + Schema root; + Schema level1("l1", ShapeType::Structure); + Schema level2("l2", ShapeType::Structure); + Schema leaf("val", ShapeType::Integer); + s.BeginStructure(root); + s.BeginNestedStructure(level1); + s.BeginNestedStructure(level2); + s.WriteInteger(leaf, 99); + s.EndNestedStructure(); + s.EndNestedStructure(); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"l1\":{\"l2\":{\"val\":99}}"), Aws::String::npos); +} + +// --- Lists --- + +TEST_F(JsonShapeSerializerTest, ListOfStrings) { + JsonShapeSerializer s; + Schema root; + Schema listMember("tags", ShapeType::List); + Schema elem("member", ShapeType::String); + s.BeginStructure(root); + s.BeginList(listMember, 3); + s.WriteString(elem, "a"); + s.WriteString(elem, "b"); + s.WriteString(elem, "c"); + s.EndList(); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"tags\":[\"a\",\"b\",\"c\"]"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, ListOfIntegers) { + JsonShapeSerializer s; + Schema root; + Schema listMember("nums", ShapeType::List); + Schema elem("member", ShapeType::Integer); + s.BeginStructure(root); + s.BeginList(listMember, 3); + s.WriteInteger(elem, 1); + s.WriteInteger(elem, 2); + s.WriteInteger(elem, 3); + s.EndList(); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"nums\":[1,2,3]"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, EmptyList) { + JsonShapeSerializer s; + Schema root; + Schema listMember("items", ShapeType::List); + s.BeginStructure(root); + s.BeginList(listMember, 0); + s.EndList(); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"items\":[]"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, ListOfStructures) { + JsonShapeSerializer s; + Schema root; + Schema listMember("items", ShapeType::List); + Schema structElem("member", ShapeType::Structure); + Schema field("id", ShapeType::Integer); + s.BeginStructure(root); + s.BeginList(listMember, 2); + s.BeginNestedStructure(structElem); + s.WriteInteger(field, 1); + s.EndNestedStructure(); + s.BeginNestedStructure(structElem); + s.WriteInteger(field, 2); + s.EndNestedStructure(); + s.EndList(); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"items\":[{\"id\":1},{\"id\":2}]"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, SparseList) { + JsonShapeSerializer s; + Schema root; + Schema listMember("items", ShapeType::List); + Schema elem("member", ShapeType::String); + s.BeginStructure(root); + s.BeginList(listMember, 3); + s.WriteString(elem, "a"); + s.WriteNull(elem); + s.WriteString(elem, "b"); + s.EndList(); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"items\":[\"a\",null,\"b\"]"), Aws::String::npos); +} + +// --- Maps --- + +TEST_F(JsonShapeSerializerTest, MapOfStrings) { + JsonShapeSerializer s; + Schema root; + Schema mapMember("headers", ShapeType::Map); + Schema valSchema("value", ShapeType::String); + s.BeginStructure(root); + s.BeginMap(mapMember, 2); + s.WriteMapKey("x-foo"); + s.WriteString(valSchema, "bar"); + s.WriteMapKey("x-baz"); + s.WriteString(valSchema, "qux"); + s.EndMap(); + s.EndStructure(); + auto payload = s.GetPayload(); + EXPECT_NE(payload.find("\"x-foo\":\"bar\""), Aws::String::npos); + EXPECT_NE(payload.find("\"x-baz\":\"qux\""), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, EmptyMap) { + JsonShapeSerializer s; + Schema root; + Schema mapMember("tags", ShapeType::Map); + s.BeginStructure(root); + s.BeginMap(mapMember, 0); + s.EndMap(); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"tags\":{}"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, MapOfStructures) { + JsonShapeSerializer s; + Schema root; + Schema mapMember("nodes", ShapeType::Map); + Schema valSchema("value", ShapeType::Structure); + Schema field("val", ShapeType::Integer); + s.BeginStructure(root); + s.BeginMap(mapMember, 1); + s.WriteMapKey("a"); + s.BeginNestedStructure(valSchema); + s.WriteInteger(field, 1); + s.EndNestedStructure(); + s.EndMap(); + s.EndStructure(); + EXPECT_NE(s.GetPayload().find("\"nodes\":{\"a\":{\"val\":1}}"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, SparseMap) { + JsonShapeSerializer s; + Schema root; + Schema mapMember("data", ShapeType::Map); + Schema valSchema("value", ShapeType::String); + s.BeginStructure(root); + s.BeginMap(mapMember, 2); + s.WriteMapKey("present"); + s.WriteString(valSchema, "yes"); + s.WriteMapKey("absent"); + s.WriteNull(valSchema); + s.EndMap(); + s.EndStructure(); + auto payload = s.GetPayload(); + EXPECT_NE(payload.find("\"present\":\"yes\""), Aws::String::npos); + EXPECT_NE(payload.find("\"absent\":null"), Aws::String::npos); +} + +// --- Combinations --- + +TEST_F(JsonShapeSerializerTest, StructureWithListAndMap) { + JsonShapeSerializer s; + Schema root; + Schema strMember("name", ShapeType::String); + Schema listMember("tags", ShapeType::List); + Schema listElem("member", ShapeType::String); + Schema mapMember("meta", ShapeType::Map); + Schema mapVal("value", ShapeType::String); + + s.BeginStructure(root); + s.WriteString(strMember, "test"); + s.BeginList(listMember, 2); + s.WriteString(listElem, "t1"); + s.WriteString(listElem, "t2"); + s.EndList(); + s.BeginMap(mapMember, 1); + s.WriteMapKey("k"); + s.WriteString(mapVal, "v"); + s.EndMap(); + s.EndStructure(); + + auto payload = s.GetPayload(); + EXPECT_NE(payload.find("\"name\":\"test\""), Aws::String::npos); + EXPECT_NE(payload.find("\"tags\":[\"t1\",\"t2\"]"), Aws::String::npos); + EXPECT_NE(payload.find("\"meta\":{\"k\":\"v\"}"), Aws::String::npos); +} + +TEST_F(JsonShapeSerializerTest, MapContainingList) { + JsonShapeSerializer s; + Schema root; + Schema mapMember("data", ShapeType::Map); + Schema listSchema("value", ShapeType::List); + Schema elem("member", ShapeType::Integer); + + s.BeginStructure(root); + s.BeginMap(mapMember, 1); + s.WriteMapKey("nums"); + s.BeginList(listSchema, 2); + s.WriteInteger(elem, 1); + s.WriteInteger(elem, 2); + s.EndList(); + s.EndMap(); + s.EndStructure(); + + EXPECT_NE(s.GetPayload().find("\"data\":{\"nums\":[1,2]}"), Aws::String::npos); +}