blob: af0c4a96b15f7a4705ae1622497eda23f4ae037b [file] [log] [blame] [edit]
// Protocol Buffers - Google's data interchange format
// Copyright 2023 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
/* 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 <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "google/protobuf/test_messages_proto2.upb.h"
#include "google/protobuf/test_messages_proto2.upb_minitable.h"
#include "upb/base/string_view.h"
#include "upb/base/upcast.h"
#include "upb/mem/arena.h"
#include "upb/message/accessors.h"
#include "upb/message/internal/message.h"
#include "upb/message/map.h"
#include "upb/message/message.h"
#include "upb/mini_table/field.h"
#include "upb/mini_table/message.h"
#include "upb/wire/encode.h"
// Must be last.
#include "upb/port/def.inc"
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_0test_0messages__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(UPB_UPCAST(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(
UPB_UPCAST(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(
UPB_UPCAST(msg),
&protobuf_0test_0messages__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_HasBaseField(UPB_UPCAST(clone), optional_int32_field));
EXPECT_EQ(upb_Message_GetInt32(UPB_UPCAST(clone), optional_int32_field, 0),
kTestInt32);
EXPECT_TRUE(
upb_Message_HasBaseField(UPB_UPCAST(clone), optional_string_field));
EXPECT_EQ(upb_Message_GetString(UPB_UPCAST(clone), optional_string_field,
upb_StringView_FromDataAndSize(nullptr, 0))
.size,
sizeof(kTestStr1) - 1);
EXPECT_TRUE(upb_StringView_IsEqual(
upb_Message_GetString(UPB_UPCAST(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(UPB_UPCAST(msg), nested_message_field,
UPB_UPCAST(nested));
upb_Arena* arena = upb_Arena_New();
protobuf_test_messages_proto2_TestAllTypesProto2* clone =
(protobuf_test_messages_proto2_TestAllTypesProto2*)upb_Message_DeepClone(
UPB_UPCAST(msg),
&protobuf_0test_0messages__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_HasBaseField(UPB_UPCAST(clone), nested_message_field));
protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage*
cloned_nested =
(protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage*)
upb_Message_GetMessage(UPB_UPCAST(clone), nested_message_field);
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<int32_t> 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(
UPB_UPCAST(msg),
&protobuf_0test_0messages__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(
UPB_UPCAST(msg),
&protobuf_0test_0messages__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(
UPB_UPCAST(msg),
&protobuf_0test_0messages__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);
}
TEST(GeneratedCode, DeepCloneMessageWithUnknowns) {
upb_Arena* source_arena = upb_Arena_New();
upb_Arena* unknown_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));
// Create unknown data.
protobuf_test_messages_proto2_UnknownToTestAllTypes* unknown_source =
protobuf_test_messages_proto2_UnknownToTestAllTypes_new(unknown_arena);
protobuf_test_messages_proto2_UnknownToTestAllTypes_set_optional_bool(
unknown_source, true);
protobuf_test_messages_proto2_UnknownToTestAllTypes_set_optional_int32(
unknown_source, 123);
// Encode unknown message to bytes.
size_t len;
char* data;
upb_Arena* encode_arena = upb_Arena_New();
upb_EncodeStatus status = upb_Encode(
UPB_UPCAST(unknown_source),
&protobuf_0test_0messages__proto2__UnknownToTestAllTypes_msg_init,
kUpb_EncodeOption_CheckRequired, encode_arena, &data, &len);
ASSERT_EQ(status, kUpb_EncodeStatus_Ok);
std::string unknown_data(data, len);
// Add unknown data.
UPB_PRIVATE(_upb_Message_AddUnknown)
(UPB_UPCAST(msg), data, len, source_arena);
// Create clone.
upb_Arena* clone_arena = upb_Arena_New();
protobuf_test_messages_proto2_TestAllTypesProto2* clone =
(protobuf_test_messages_proto2_TestAllTypesProto2*)upb_Message_DeepClone(
UPB_UPCAST(msg),
&protobuf_0test_0messages__proto2__TestAllTypesProto2_msg_init,
clone_arena);
upb_Arena_Free(source_arena);
upb_Arena_Free(unknown_arena);
upb_Arena_Free(encode_arena);
// Read unknown data from clone and verify.
std::string cloned_unknown_data;
upb_StringView unknown;
uintptr_t iter = kUpb_Message_UnknownBegin;
while (upb_Message_NextUnknown(UPB_UPCAST(clone), &unknown, &iter)) {
cloned_unknown_data.append(unknown.data, unknown.size);
}
EXPECT_EQ(unknown_data, cloned_unknown_data);
upb_Arena_Free(clone_arena);
}
} // namespace