Implements upb_Message_DeepClone.

PiperOrigin-RevId: 514723111
pull/13171/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent a6ce73370f
commit 3286f948f8
  1. 38
      BUILD
  2. 6
      protos/protos.h
  3. 282
      upb/message/copy.c
  4. 63
      upb/message/copy.h
  5. 258
      upb/message/copy_test.cc

38
BUILD

@ -282,6 +282,26 @@ cc_library(
],
)
cc_library(
name = "message_copy",
srcs = [
"upb/message/copy.c",
],
hdrs = [
"upb/message/copy.h",
],
copts = UPB_DEFAULT_COPTS,
visibility = ["//visibility:public"],
deps = [
":collections_internal",
":message_accessors",
":message_internal",
":mini_table_internal",
":port",
":upb",
],
)
cc_test(
name = "mini_table_encode_test",
srcs = [
@ -317,6 +337,24 @@ cc_test(
],
)
cc_test(
name = "message_copy_test",
srcs = ["upb/message/copy_test.cc"],
deps = [
":collections",
":message_accessors",
":message_copy",
":mini_table_internal",
":upb",
"//upb/test:test_messages_proto2_upb_proto",
"//upb/test:test_messages_proto3_upb_proto",
"//upb/test:test_upb_proto",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_googletest//:gtest_main",
"@com_google_protobuf//:protobuf",
],
)
cc_library(
name = "fastdecode",
copts = UPB_DEFAULT_COPTS,

@ -116,6 +116,12 @@ typename T::Proxy CreateMessage(::protos::Arena& arena) {
arena.ptr());
}
template <typename T>
typename T::Proxy CloneMessage(Ptr<T> message, upb::Arena& arena) {
return typename T::Proxy(
upb_Message_DeepClone(message, T::minitable(), arena.ptr()), arena.ptr());
}
// begin:github_only
// This type exists to work around an absl type that has not yet been
// released.

@ -0,0 +1,282 @@
/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "upb/message/copy.h"
#include "upb/mem/arena.h"
#include "upb/message/accessors.h"
#include "upb/message/message.h"
// Must be last.
#include "upb/mini_table/common.h"
#include "upb/port/def.inc"
static bool upb_MessageField_IsMap(const upb_MiniTableField* field) {
return upb_FieldMode_Get(field) == kUpb_FieldMode_Map;
}
static upb_StringView upb_Clone_StringView(upb_StringView str,
upb_Arena* arena) {
if (str.size == 0) {
return upb_StringView_FromDataAndSize(NULL, 0);
}
void* cloned_data = upb_Arena_Malloc(arena, str.size);
upb_StringView cloned_str =
upb_StringView_FromDataAndSize(cloned_data, str.size);
memcpy(cloned_data, str.data, str.size);
return cloned_str;
}
static bool upb_Clone_MessageValue(void* value, upb_CType value_type,
const upb_MiniTable* sub, upb_Arena* arena) {
switch (value_type) {
case kUpb_CType_Bool:
case kUpb_CType_Float:
case kUpb_CType_Int32:
case kUpb_CType_UInt32:
case kUpb_CType_Enum:
case kUpb_CType_Double:
case kUpb_CType_Int64:
case kUpb_CType_UInt64:
return true;
case kUpb_CType_String:
case kUpb_CType_Bytes: {
upb_StringView source = *(upb_StringView*)value;
int size = source.size;
void* cloned_data = upb_Arena_Malloc(arena, size);
if (cloned_data == NULL) {
return false;
}
*(upb_StringView*)value =
upb_StringView_FromDataAndSize(cloned_data, size);
memcpy(cloned_data, source.data, size);
return true;
} break;
case kUpb_CType_Message: {
UPB_ASSERT(sub);
const upb_Message* source = *(upb_Message**)value;
UPB_ASSERT(source);
upb_Message* clone = upb_Message_DeepClone(source, sub, arena);
*(upb_Message**)value = clone;
return clone != NULL;
} break;
}
UPB_UNREACHABLE();
}
upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type,
upb_CType value_type,
const upb_MiniTable* map_entry_table,
upb_Arena* arena) {
upb_Map* cloned_map = _upb_Map_New(arena, map->key_size, map->val_size);
if (cloned_map == NULL) {
return NULL;
}
upb_MessageValue key, val;
size_t iter = kUpb_Map_Begin;
while (upb_Map_Next(map, &key, &val, &iter)) {
const upb_MiniTableField* value_field = &map_entry_table->fields[1];
const upb_MiniTable* value_sub =
(value_field->submsg_index != kUpb_NoSub)
? upb_MiniTable_GetSubMessageTable(map_entry_table, value_field)
: NULL;
upb_CType value_field_type = upb_MiniTableField_CType(value_field);
if (!upb_Clone_MessageValue(&val, value_field_type, value_sub, arena)) {
return NULL;
}
if (upb_Map_Insert(cloned_map, key, val, arena) ==
kUpb_MapInsertStatus_OutOfMemory) {
return NULL;
}
}
return cloned_map;
}
static upb_Map* upb_Message_Map_DeepClone(const upb_Map* map,
const upb_MiniTable* mini_table,
const upb_MiniTableField* field,
upb_Message* clone,
upb_Arena* arena) {
const upb_MiniTable* map_entry_table =
mini_table->subs[field->submsg_index].submsg;
UPB_ASSERT(map_entry_table);
const upb_MiniTableField* key_field = &map_entry_table->fields[0];
const upb_MiniTableField* value_field = &map_entry_table->fields[1];
upb_Map* cloned_map = upb_Map_DeepClone(
map, upb_MiniTableField_CType(key_field),
upb_MiniTableField_CType(value_field), map_entry_table, arena);
if (!cloned_map) {
return NULL;
}
_upb_Message_SetNonExtensionField(clone, field, &cloned_map);
return cloned_map;
}
upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type,
const upb_MiniTable* sub, upb_Arena* arena) {
size_t size = array->size;
upb_Array* cloned_array =
_upb_Array_New(arena, size, _upb_Array_CTypeSizeLg2(value_type));
if (!cloned_array) {
return NULL;
}
for (int i = 0; i < size; ++i) {
upb_MessageValue val = upb_Array_Get(array, i);
if (!upb_Clone_MessageValue(&val, value_type, sub, arena)) {
return false;
}
upb_Array_Set(cloned_array, i, val);
}
return cloned_array;
}
static bool upb_Message_Array_DeepClone(const upb_Array* array,
const upb_MiniTable* mini_table,
const upb_MiniTableField* field,
upb_Message* clone, upb_Arena* arena) {
_upb_MiniTableField_CheckIsArray(field);
upb_Array* cloned_array = upb_Array_DeepClone(
array, upb_MiniTableField_CType(field),
field->submsg_index != kUpb_NoSub
? upb_MiniTable_GetSubMessageTable(mini_table, field)
: NULL,
arena);
// Clear out upb_Array* due to parent memcpy.
_upb_Message_SetNonExtensionField(clone, field, &cloned_array);
return true;
}
static bool upb_Clone_ExtensionValue(
const upb_MiniTableExtension* mini_table_ext,
const upb_Message_Extension* source, upb_Message_Extension* dest,
upb_Arena* arena) {
dest->data = source->data;
return upb_Clone_MessageValue(
&dest->data, upb_MiniTableField_CType(&mini_table_ext->field),
mini_table_ext->sub.submsg, arena);
}
// Deep clones a message using the provided target arena.
//
// Returns NULL on failure.
upb_Message* upb_Message_DeepClone(const upb_Message* message,
const upb_MiniTable* mini_table,
upb_Arena* arena) {
upb_Message* clone = upb_Message_New(mini_table, arena);
upb_StringView empty_string = upb_StringView_FromDataAndSize(NULL, 0);
// Only copy message area skipping upb_Message_Internal.
memcpy(clone, message, mini_table->size);
for (size_t i = 0; i < mini_table->field_count; ++i) {
const upb_MiniTableField* field = &mini_table->fields[i];
if (!upb_IsRepeatedOrMap(field)) {
switch (field->descriptortype) {
case kUpb_FieldType_Group:
case kUpb_FieldType_Message: {
const upb_Message* sub_message =
upb_Message_GetMessage(message, field, NULL);
if (sub_message != NULL) {
const upb_MiniTable* sub_message_table =
upb_MiniTable_GetSubMessageTable(mini_table, field);
upb_Message* cloned_sub_message =
upb_Message_DeepClone(sub_message, sub_message_table, arena);
if (cloned_sub_message == NULL) {
return NULL;
}
upb_Message_SetMessage(clone, mini_table, field,
cloned_sub_message);
}
} break;
case kUpb_FieldType_String:
case kUpb_FieldType_Bytes: {
upb_StringView str =
upb_Message_GetString(message, field, empty_string);
if (str.size != 0) {
if (!upb_Message_SetString(
clone, field, upb_Clone_StringView(str, arena), arena)) {
return NULL;
}
}
} break;
default:
// Scalar, already copied.
break;
}
} else {
if (upb_MessageField_IsMap(field)) {
const upb_Map* map = upb_Message_GetMap(message, field);
if (map != NULL) {
if (!upb_Message_Map_DeepClone(map, mini_table, field, clone,
arena)) {
return NULL;
}
}
} else {
const upb_Array* array = upb_Message_GetArray(message, field);
if (array != NULL) {
if (!upb_Message_Array_DeepClone(array, mini_table, field, clone,
arena)) {
return NULL;
}
}
}
}
}
// Clone extensions.
size_t ext_count;
const upb_Message_Extension* ext = _upb_Message_Getexts(message, &ext_count);
for (size_t i = 0; i < ext_count; ++i) {
const upb_Message_Extension* msg_ext = &ext[i];
upb_Message_Extension* cloned_ext =
_upb_Message_GetOrCreateExtension(clone, msg_ext->ext, arena);
if (!cloned_ext) {
return NULL;
}
if (!upb_Clone_ExtensionValue(msg_ext->ext, msg_ext, cloned_ext, arena)) {
return NULL;
}
}
// Clone unknowns.
size_t unknown_size = 0;
const char* ptr = upb_Message_GetUnknown(message, &unknown_size);
if (unknown_size != 0) {
UPB_ASSERT(ptr);
// Make a copy into destination arena.
void* cloned_unknowns = upb_Arena_Malloc(arena, unknown_size);
if (cloned_unknowns == NULL) {
return NULL;
}
memcpy(cloned_unknowns, ptr, unknown_size);
if (!_upb_Message_AddUnknown(clone, cloned_unknowns, unknown_size, arena)) {
return NULL;
}
}
return clone;
}

@ -0,0 +1,63 @@
/*
* Copyright (c) 2009-2022, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UPB_MESSAGE_COPY_H_
#define UPB_MESSAGE_COPY_H_
#include "upb/collections/message_value.h"
#include "upb/message/internal.h"
#include "upb/mini_table/common.h"
// Must be last.
#include "upb/port/def.inc"
#ifdef __cplusplus
extern "C" {
#endif
// Deep clones a message using the provided target arena.
upb_Message* upb_Message_DeepClone(const upb_Message* message,
const upb_MiniTable* mini_table,
upb_Arena* arena);
// Deep clones array contents.
upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type,
const upb_MiniTable* sub, upb_Arena* arena);
// Deep clones map contents.
upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type,
upb_CType value_type,
const upb_MiniTable* map_entry_table,
upb_Arena* arena);
#ifdef __cplusplus
} /* extern "C" */
#endif
#include "upb/port/undef.inc"
#endif // UPB_MESSAGE_COPY_H_

@ -0,0 +1,258 @@
/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Test of mini table accessors.
*
* Messages are created and mutated using generated code, and then
* accessed through reflective APIs exposed through mini table accessors.
*/
#include "upb/message/copy.h"
#include "gtest/gtest.h"
#include "google/protobuf/test_messages_proto2.upb.h"
#include "google/protobuf/test_messages_proto3.upb.h"
#include "upb/base/string_view.h"
#include "upb/collections/array.h"
#include "upb/collections/map.h"
#include "upb/mem/arena.h"
#include "upb/message/accessors.h"
#include "upb/mini_table/common.h"
#include "upb/mini_table/encode_internal.hpp"
#include "upb/mini_table/field_internal.h"
#include "upb/test/test.upb.h"
#include "upb/upb.h"
namespace {
// Proto2 test messages field numbers used for reflective access.
const uint32_t kFieldOptionalInt32 = 1;
const uint32_t kFieldOptionalString = 14;
const uint32_t kFieldOptionalNestedMessage = 18;
const char kTestStr1[] = "Hello1";
const char kTestStr2[] = "HelloWorld2";
const int32_t kTestInt32 = 567;
const int32_t kTestNestedInt32 = 123;
const upb_MiniTableField* find_proto2_field(int field_number) {
return upb_MiniTable_FindFieldByNumber(
&protobuf_test_messages_proto2_TestAllTypesProto2_msg_init, field_number);
}
TEST(GeneratedCode, DeepCloneMessageScalarAndString) {
upb_Arena* source_arena = upb_Arena_New();
protobuf_test_messages_proto2_TestAllTypesProto2* msg =
protobuf_test_messages_proto2_TestAllTypesProto2_new(source_arena);
const upb_MiniTableField* optional_int32_field =
find_proto2_field(kFieldOptionalInt32);
const upb_MiniTableField* optional_string_field =
find_proto2_field(kFieldOptionalString);
upb_Message_SetInt32(msg, optional_int32_field, kTestInt32, nullptr);
char* string_in_arena =
(char*)upb_Arena_Malloc(source_arena, sizeof(kTestStr1));
memcpy(string_in_arena, kTestStr1, sizeof(kTestStr1));
upb_Message_SetString(
msg, optional_string_field,
upb_StringView_FromDataAndSize(string_in_arena, sizeof(kTestStr1) - 1),
source_arena);
upb_Arena* arena = upb_Arena_New();
protobuf_test_messages_proto2_TestAllTypesProto2* clone =
(protobuf_test_messages_proto2_TestAllTypesProto2*)upb_Message_DeepClone(
msg, &protobuf_test_messages_proto2_TestAllTypesProto2_msg_init,
arena);
// After cloning overwrite values and destroy source arena for MSAN.
memset(string_in_arena, 0, sizeof(kTestStr1));
upb_Arena_Free(source_arena);
EXPECT_TRUE(upb_Message_HasField(clone, optional_int32_field));
EXPECT_EQ(upb_Message_GetInt32(clone, optional_int32_field, 0), kTestInt32);
EXPECT_TRUE(upb_Message_HasField(clone, optional_string_field));
EXPECT_EQ(upb_Message_GetString(clone, optional_string_field,
upb_StringView_FromDataAndSize(nullptr, 0))
.size,
sizeof(kTestStr1) - 1);
EXPECT_TRUE(upb_StringView_IsEqual(
upb_Message_GetString(clone, optional_string_field,
upb_StringView_FromDataAndSize(nullptr, 0)),
upb_StringView_FromString(kTestStr1)));
upb_Arena_Free(arena);
}
TEST(GeneratedCode, DeepCloneMessageSubMessage) {
upb_Arena* source_arena = upb_Arena_New();
protobuf_test_messages_proto2_TestAllTypesProto2* msg =
protobuf_test_messages_proto2_TestAllTypesProto2_new(source_arena);
const upb_MiniTableField* nested_message_field =
find_proto2_field(kFieldOptionalNestedMessage);
protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage* nested =
protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_new(
source_arena);
protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_set_a(
nested, kTestNestedInt32);
upb_Message_SetMessage(
msg, &protobuf_test_messages_proto2_TestAllTypesProto2_msg_init,
nested_message_field, nested);
upb_Arena* arena = upb_Arena_New();
protobuf_test_messages_proto2_TestAllTypesProto2* clone =
(protobuf_test_messages_proto2_TestAllTypesProto2*)upb_Message_DeepClone(
msg, &protobuf_test_messages_proto2_TestAllTypesProto2_msg_init,
arena);
// After cloning overwrite values and destroy source arena for MSAN.
protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_set_a(nested,
0);
upb_Arena_Free(source_arena);
EXPECT_TRUE(upb_Message_HasField(clone, nested_message_field));
protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage*
cloned_nested =
(protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage*)
upb_Message_GetMessage(clone, nested_message_field, nullptr);
EXPECT_EQ(protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_a(
cloned_nested),
kTestNestedInt32);
upb_Arena_Free(arena);
}
TEST(GeneratedCode, DeepCloneMessageMapField) {
upb_Arena* source_arena = upb_Arena_New();
protobuf_test_messages_proto2_TestAllTypesProto2* msg =
protobuf_test_messages_proto2_TestAllTypesProto2_new(source_arena);
ASSERT_TRUE(
protobuf_test_messages_proto2_TestAllTypesProto2_map_int32_double_set(
msg, 12, 1200.5, source_arena));
ASSERT_TRUE(
protobuf_test_messages_proto2_TestAllTypesProto2_map_string_string_set(
msg, upb_StringView_FromString("key1"),
upb_StringView_FromString("value1"), source_arena));
protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage* nested =
protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_new(
source_arena);
protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_set_a(
nested, kTestNestedInt32);
ASSERT_TRUE(
protobuf_test_messages_proto2_TestAllTypesProto2_map_string_nested_message_set(
msg, upb_StringView_FromString("nestedkey1"), nested, source_arena));
upb_Arena* arena = upb_Arena_New();
protobuf_test_messages_proto2_TestAllTypesProto2* clone =
(protobuf_test_messages_proto2_TestAllTypesProto2*)upb_Message_DeepClone(
msg, &protobuf_test_messages_proto2_TestAllTypesProto2_msg_init,
arena);
protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_set_a(nested,
0);
upb_Arena_Free(source_arena);
size_t iter = kUpb_Map_Begin;
// Test map<int32, int32>.
const protobuf_test_messages_proto2_TestAllTypesProto2_MapInt32DoubleEntry*
int32_double_entry =
protobuf_test_messages_proto2_TestAllTypesProto2_map_int32_double_next(
clone, &iter);
ASSERT_NE(int32_double_entry, nullptr);
EXPECT_EQ(
protobuf_test_messages_proto2_TestAllTypesProto2_MapInt32DoubleEntry_key(
int32_double_entry),
12);
EXPECT_EQ(
protobuf_test_messages_proto2_TestAllTypesProto2_MapInt32DoubleEntry_value(
int32_double_entry),
1200.5);
// Test map<string, string>.
iter = kUpb_Map_Begin;
const protobuf_test_messages_proto2_TestAllTypesProto2_MapStringStringEntry*
string_string_entry =
protobuf_test_messages_proto2_TestAllTypesProto2_map_string_string_next(
clone, &iter);
ASSERT_NE(string_string_entry, nullptr);
EXPECT_TRUE(upb_StringView_IsEqual(
protobuf_test_messages_proto2_TestAllTypesProto2_MapStringStringEntry_key(
string_string_entry),
upb_StringView_FromString("key1")));
EXPECT_TRUE(upb_StringView_IsEqual(
protobuf_test_messages_proto2_TestAllTypesProto2_MapStringStringEntry_value(
string_string_entry),
upb_StringView_FromString("value1")));
// Test map<string, NestedMessage>.
iter = kUpb_Map_Begin;
const protobuf_test_messages_proto2_TestAllTypesProto2_MapStringNestedMessageEntry*
nested_message_entry =
protobuf_test_messages_proto2_TestAllTypesProto2_map_string_nested_message_next(
clone, &iter);
ASSERT_NE(nested_message_entry, nullptr);
EXPECT_TRUE(upb_StringView_IsEqual(
protobuf_test_messages_proto2_TestAllTypesProto2_MapStringNestedMessageEntry_key(
nested_message_entry),
upb_StringView_FromString("nestedkey1")));
const protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage*
cloned_nested =
protobuf_test_messages_proto2_TestAllTypesProto2_MapStringNestedMessageEntry_value(
nested_message_entry);
ASSERT_NE(cloned_nested, nullptr);
EXPECT_EQ(protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_a(
cloned_nested),
kTestNestedInt32);
upb_Arena_Free(arena);
}
TEST(GeneratedCode, DeepCloneMessageExtensions) {
// Alloc and fill in test message with extension.
upb_Arena* source_arena = upb_Arena_New();
protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrect* msg =
protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrect_new(
source_arena);
protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrectExtension1*
ext1 =
protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrectExtension1_new(
source_arena);
protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrectExtension1_set_str(
ext1, upb_StringView_FromString(kTestStr1));
protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrectExtension1_set_message_set_extension(
msg, ext1, source_arena);
// Create clone.
upb_Arena* arena = upb_Arena_New();
protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrect* clone =
(protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrect*)
upb_Message_DeepClone(
msg,
&protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrect_msg_init,
arena);
// Mutate original extension.
protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrectExtension1_set_str(
ext1, upb_StringView_FromString(kTestStr2));
upb_Arena_Free(source_arena);
const protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrectExtension1*
cloned_ext =
protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrectExtension1_message_set_extension(
clone);
ASSERT_NE(cloned_ext, nullptr);
EXPECT_TRUE(upb_StringView_IsEqual(
protobuf_test_messages_proto2_TestAllTypesProto2_MessageSetCorrectExtension1_str(
cloned_ext),
upb_StringView_FromString(kTestStr1)));
upb_Arena_Free(arena);
}
} // namespace
Loading…
Cancel
Save