parent
a6ce73370f
commit
3286f948f8
5 changed files with 647 additions and 0 deletions
@ -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…
Reference in new issue