/* * 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 #include #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/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, DeepCloneMessageArrayField) { upb_Arena* source_arena = upb_Arena_New(); protobuf_test_messages_proto2_TestAllTypesProto2* msg = protobuf_test_messages_proto2_TestAllTypesProto2_new(source_arena); std::vector array_test_values = {3, 4, 5}; for (int32_t value : array_test_values) { ASSERT_TRUE( protobuf_test_messages_proto2_TestAllTypesProto2_add_repeated_int32( msg, value, 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_clear_repeated_sint32(msg); upb_Arena_Free(source_arena); size_t cloned_size = 0; const int32_t* cloned_values = protobuf_test_messages_proto2_TestAllTypesProto2_repeated_int32( clone, &cloned_size); EXPECT_EQ(cloned_size, array_test_values.size()); int index = 0; for (int32_t value : array_test_values) { EXPECT_EQ(cloned_values[index++], value); } 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. 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. 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. 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