// 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 #include #include #include #include #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "hpb_generator/tests/child_model.hpb.h" #include "hpb_generator/tests/no_package.hpb.h" #include "hpb_generator/tests/null_enum.hpb.h" #include "hpb_generator/tests/set_alias.hpb.h" #include "hpb_generator/tests/test_enum.hpb.h" #include "hpb_generator/tests/test_extension.hpb.h" #include "hpb_generator/tests/test_model.hpb.h" #include "hpb/arena.h" #include "hpb/backend/upb/interop.h" #include "hpb/hpb.h" #include "hpb/options.h" #include "hpb/ptr.h" #include "hpb/requires.h" #include "hpb/status.h" namespace { using ::hpb::internal::Requires; using ::hpb_unittest::protos::Child; using ::hpb_unittest::protos::ChildModel1; using ::hpb_unittest::protos::Parent; using ::hpb_unittest::protos::ParentWithMap; using ::hpb_unittest::protos::ParentWithRepeated; using ::hpb_unittest::protos::RED; using ::hpb_unittest::protos::TestEnum; using ::hpb_unittest::protos::TestModel; using ::hpb_unittest::protos::TestModel_Category; using ::hpb_unittest::protos::TestModel_Category_IMAGES; using ::hpb_unittest::protos::TestModel_Category_NEWS; using ::hpb_unittest::protos::TestModel_Category_VIDEO; TEST(CppGeneratedCode, Constructor) { TestModel test_model; } TEST(CppGeneratedCode, MessageEnum) { EXPECT_EQ(5, TestModel_Category_IMAGES); } TEST(CppGeneratedCode, ImportedEnum) { EXPECT_EQ(3, TestEnum::DEVICE_MONITOR); } TEST(CppGeneratedCode, Enum) { EXPECT_EQ(1, RED); } TEST(CppGeneratedCode, NullEnum) { EXPECT_EQ(1, hpb_test::protos::NULL_); } TEST(CppGeneratedCode, EnumNoPackage) { EXPECT_EQ(1, ::hpb_CELSIUS); } TEST(CppGeneratedCode, EnumContainingMessage) { EXPECT_EQ( 1, ::hpb_unittest::protos::ContainingMessage_OtherMessage_NestedTestEnum:: ContainingMessage_OtherMessage_NestedTestEnum_DEVICE_KEYBOARD); } TEST(CppGeneratedCode, MessageEnumType) { TestModel_Category category1 = TestModel_Category_IMAGES; TestModel::Category category2 = TestModel::IMAGES; EXPECT_EQ(category1, category2); } TEST(CppGeneratedCode, MessageEnumValue) { EXPECT_EQ(TestModel_Category_IMAGES, TestModel::IMAGES); } TEST(CppGeneratedCode, ArenaConstructor) { ::hpb::Arena arena; auto testModel = ::hpb::CreateMessage(arena); EXPECT_EQ(false, testModel.has_b1()); } TEST(CppGeneratedCode, Booleans) { ::hpb::Arena arena; auto testModel = ::hpb::CreateMessage(arena); EXPECT_FALSE(testModel.b1()); testModel.set_b1(true); EXPECT_TRUE(testModel.b1()); testModel.set_b1(false); EXPECT_FALSE(testModel.b1()); testModel.set_b1(true); EXPECT_TRUE(testModel.b1()); testModel.clear_b1(); EXPECT_FALSE(testModel.has_b1()); } TEST(CppGeneratedCode, ScalarInt32) { ::hpb::Arena arena; auto testModel = ::hpb::CreateMessage(arena); // Test int32 defaults. EXPECT_EQ(testModel.value(), 0); EXPECT_FALSE(testModel.has_value()); // Floating point defaults. EXPECT_EQ(std::numeric_limits::infinity(), testModel.float_value_with_default()); EXPECT_EQ(-std::numeric_limits::infinity(), testModel.double_value_with_default()); // Set value. testModel.set_value(5); EXPECT_TRUE(testModel.has_value()); EXPECT_EQ(testModel.value(), 5); // Change value. testModel.set_value(10); EXPECT_TRUE(testModel.has_value()); EXPECT_EQ(testModel.value(), 10); // Clear value. testModel.clear_value(); EXPECT_FALSE(testModel.has_value()); EXPECT_EQ(testModel.value(), 0); } const char kTestStr1[] = "abcdefg"; const char kTestStr2[] = "just another test string"; TEST(CppGeneratedCode, Strings) { TestModel testModel; testModel.set_str1(kTestStr1); testModel.set_str2(kTestStr2); EXPECT_EQ(testModel.str1(), kTestStr1); EXPECT_EQ(testModel.str2(), kTestStr2); EXPECT_TRUE(testModel.has_str1()); EXPECT_TRUE(testModel.has_str2()); testModel.clear_str1(); EXPECT_FALSE(testModel.has_str1()); EXPECT_TRUE(testModel.has_str2()); } TEST(CppGeneratedCode, ScalarUInt32) { ::hpb::Arena arena; auto testModel = ::hpb::CreateMessage(arena); // Test defaults. EXPECT_EQ(testModel.optional_uint32(), 0); EXPECT_FALSE(testModel.has_optional_uint32()); // Set value. testModel.set_optional_uint32(0xA0001000); EXPECT_TRUE(testModel.has_optional_uint32()); EXPECT_EQ(testModel.optional_uint32(), 0xA0001000); // Change value. testModel.set_optional_uint32(0x70002000); EXPECT_TRUE(testModel.has_optional_uint32()); EXPECT_EQ(testModel.optional_uint32(), 0x70002000); // Clear value. testModel.clear_optional_uint32(); EXPECT_FALSE(testModel.has_optional_uint32()); EXPECT_EQ(testModel.optional_uint32(), 0); } TEST(CppGeneratedCode, ScalarInt64) { ::hpb::Arena arena; auto testModel = ::hpb::CreateMessage(arena); // Test defaults. EXPECT_EQ(testModel.optional_int64(), 0); EXPECT_FALSE(testModel.has_optional_int64()); // Set value. testModel.set_optional_int64(static_cast(0xFF00CCDDA0001000)); EXPECT_TRUE(testModel.has_optional_int64()); EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDDA0001000); // Change value. testModel.set_optional_int64(static_cast(0xFF00CCDD70002000)); EXPECT_TRUE(testModel.has_optional_int64()); EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDD70002000); // Clear value. testModel.clear_optional_int64(); EXPECT_FALSE(testModel.has_optional_int64()); EXPECT_EQ(testModel.optional_int64(), 0); // Set after clear. testModel.set_optional_int64(static_cast(0xFF00CCDDA0001000)); EXPECT_TRUE(testModel.has_optional_int64()); EXPECT_EQ(testModel.optional_int64(), 0xFF00CCDDA0001000); } TEST(CppGeneratedCode, ScalarFloat) { ::hpb::Arena arena; auto testModel = ::hpb::CreateMessage(arena); // Test defaults. EXPECT_EQ(testModel.optional_float(), 0.0f); EXPECT_FALSE(testModel.has_optional_float()); EXPECT_EQ(std::numeric_limits::infinity(), testModel.float_value_with_default()); EXPECT_EQ(-std::numeric_limits::infinity(), testModel.double_value_with_default()); // Set value. testModel.set_optional_float(3.14159265f); EXPECT_TRUE(testModel.has_optional_float()); EXPECT_NEAR(testModel.optional_float(), 3.14159265f, 1e-9f); // Change value. testModel.set_optional_float(-2.0f); EXPECT_TRUE(testModel.has_optional_float()); EXPECT_NEAR(testModel.optional_float(), -2, 1e-9f); // Clear value. testModel.clear_optional_float(); EXPECT_FALSE(testModel.has_optional_float()); EXPECT_EQ(testModel.optional_float(), 0.0f); // Set after clear. testModel.set_optional_float(3.14159265f); EXPECT_TRUE(testModel.has_optional_float()); EXPECT_NEAR(testModel.optional_float(), 3.14159265f, 1e-9f); } TEST(CppGeneratedCode, ScalarDouble) { ::hpb::Arena arena; auto testModel = ::hpb::CreateMessage(arena); // Test defaults. EXPECT_EQ(testModel.optional_double(), 0.0); EXPECT_FALSE(testModel.has_optional_double()); // Set value. testModel.set_optional_double(3.141592653589793); EXPECT_TRUE(testModel.has_optional_double()); EXPECT_NEAR(testModel.optional_double(), 3.141592653589793, 1e-16f); // Change value. testModel.set_optional_double(-1.0); EXPECT_TRUE(testModel.has_optional_double()); EXPECT_NEAR(testModel.optional_double(), -1.0, 1e-16f); // Clear value. testModel.clear_optional_double(); EXPECT_FALSE(testModel.has_optional_double()); EXPECT_EQ(testModel.optional_double(), 0.0f); // Set after clear. testModel.set_optional_double(3.141592653589793); EXPECT_TRUE(testModel.has_optional_double()); EXPECT_NEAR(testModel.optional_double(), 3.141592653589793, 1e-16f); } TEST(CppGeneratedCode, Enums) { ::hpb::Arena arena; auto testModel = ::hpb::CreateMessage(arena); // Check enum default value. EXPECT_EQ(TestModel_Category_IMAGES, 5); // Test defaults. EXPECT_FALSE(testModel.has_category()); EXPECT_EQ(testModel.category(), TestModel_Category_IMAGES); // Set value. testModel.set_category(TestModel_Category_NEWS); EXPECT_TRUE(testModel.has_category()); EXPECT_EQ(testModel.category(), TestModel_Category_NEWS); // Change value. testModel.set_category(TestModel_Category_VIDEO); EXPECT_TRUE(testModel.has_category()); EXPECT_EQ(testModel.category(), TestModel_Category_VIDEO); // Clear value. testModel.clear_category(); EXPECT_FALSE(testModel.has_category()); EXPECT_EQ(testModel.category(), TestModel_Category_IMAGES); // Set after clear. testModel.set_category(TestModel_Category_VIDEO); EXPECT_TRUE(testModel.has_category()); EXPECT_EQ(testModel.category(), TestModel_Category_VIDEO); } TEST(CppGeneratedCode, FieldWithDefaultValue) { ::hpb::Arena arena; auto testModel = ::hpb::CreateMessage(arena); EXPECT_FALSE(testModel.has_int_value_with_default()); EXPECT_EQ(testModel.int_value_with_default(), 65); testModel.set_int_value_with_default(10); EXPECT_EQ(testModel.int_value_with_default(), 10); EXPECT_FALSE(testModel.has_string_value_with_default()); EXPECT_EQ(testModel.string_value_with_default(), "hello"); testModel.set_string_value_with_default("new string"); EXPECT_EQ(testModel.string_value_with_default(), "new string"); } TEST(CppGeneratedCode, OneOfFields) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_FALSE(test_model.has_oneof_member1()); EXPECT_FALSE(test_model.has_oneof_member2()); EXPECT_EQ(TestModel::CHILD_ONEOF1_NOT_SET, test_model.child_oneof1_case()); test_model.set_oneof_member1("one of string"); EXPECT_TRUE(test_model.has_oneof_member1()); EXPECT_FALSE(test_model.has_oneof_member2()); EXPECT_EQ(test_model.oneof_member1(), "one of string"); EXPECT_EQ(TestModel::kOneofMember1, test_model.child_oneof1_case()); test_model.set_oneof_member2(true); EXPECT_FALSE(test_model.has_oneof_member1()); EXPECT_TRUE(test_model.has_oneof_member2()); EXPECT_EQ(test_model.oneof_member2(), true); EXPECT_EQ(TestModel::kOneofMember2, test_model.child_oneof1_case()); test_model.clear_oneof_member2(); EXPECT_FALSE(test_model.has_oneof_member1()); EXPECT_FALSE(test_model.has_oneof_member2()); EXPECT_EQ(test_model.oneof_member1(), ""); EXPECT_EQ(test_model.oneof_member2(), false); EXPECT_EQ(TestModel::CHILD_ONEOF1_NOT_SET, test_model.child_oneof1_case()); } TEST(CppGeneratedCode, Messages) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(false, test_model.has_child_model_1()); auto child_model = test_model.child_model_1(); EXPECT_EQ(false, child_model->has_child_b1()); EXPECT_EQ(false, child_model->child_b1()); auto mutable_child = test_model.mutable_child_model_1(); mutable_child->set_child_b1(true); EXPECT_EQ(true, mutable_child->has_child_b1()); EXPECT_EQ(true, mutable_child->child_b1()); // The View should not change due to mutation since it // is default_instance. EXPECT_EQ(false, child_model->has_child_b1()); // Readonly View should now show change. child_model = test_model.child_model_1(); EXPECT_EQ(true, child_model->has_child_b1()); EXPECT_EQ(true, child_model->child_b1()); // Clear message field. EXPECT_EQ(true, test_model.has_child_model_1()); test_model.clear_child_model_1(); EXPECT_EQ(false, test_model.has_child_model_1()); } TEST(CppGeneratedCode, NestedMessages) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); auto nested_child = test_model.nested_child_1(); EXPECT_EQ(0, nested_child->nested_child_name().size()); auto mutable_nested_child = test_model.mutable_nested_child_1(); EXPECT_EQ(false, mutable_nested_child->has_nested_child_name()); mutable_nested_child->set_nested_child_name(kTestStr1); EXPECT_EQ(true, mutable_nested_child->has_nested_child_name()); } TEST(CppGeneratedCode, MessageMapInt32KeyMessageValue) { const int key_test_value = 3; ::hpb::Arena arena; ::hpb::Arena child_arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(0, test_model.child_map_size()); test_model.clear_child_map(); EXPECT_EQ(0, test_model.child_map_size()); auto child_model1 = ::hpb::CreateMessage(child_arena); child_model1.set_child_str1("abc"); test_model.set_child_map(key_test_value, child_model1); auto map_result = test_model.get_child_map(key_test_value); EXPECT_EQ(true, map_result.ok()); EXPECT_EQ("abc", map_result.value()->child_str1()); // Now mutate original child model to verify that value semantics are // preserved. child_model1.set_child_str1("abc V2"); EXPECT_EQ("abc", map_result.value()->child_str1()); test_model.delete_child_map(key_test_value); auto map_result_after_delete = test_model.get_child_map(key_test_value); EXPECT_EQ(false, map_result_after_delete.ok()); } TEST(CppGeneratedCode, MapMutableValue) { constexpr int key = 1; hpb::Arena arena; auto msg = hpb::CreateMessage(arena); auto child = hpb::CreateMessage(arena); child.set_peeps(12); msg.set_child_map(key, child); auto const_map_result = msg.get_child_map(key); EXPECT_EQ(true, const_map_result.ok()); EXPECT_EQ(12, const_map_result.value()->peeps()); auto mut_map_result = msg.get_mutable_child_map(key); EXPECT_EQ(true, mut_map_result.ok()); mut_map_result.value()->set_peeps(9001); EXPECT_EQ(9001, mut_map_result.value()->peeps()); } TEST(CppGeneratedCode, MessageMapStringKeyAndStringValue) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(0, test_model.str_to_str_map_size()); test_model.clear_str_to_str_map(); EXPECT_EQ(0, test_model.str_to_str_map_size()); test_model.set_str_to_str_map("first", "abc"); test_model.set_str_to_str_map("second", "def"); auto result = test_model.get_str_to_str_map("second"); EXPECT_EQ(true, result.ok()); EXPECT_EQ("def", result.value()); test_model.delete_str_to_str_map("first"); auto result_after_delete = test_model.get_str_to_str_map("first"); EXPECT_EQ(false, result_after_delete.ok()); } TEST(CppGeneratedCode, MessageMapStringKeyAndInt32Value) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(0, test_model.str_to_int_map_size()); test_model.clear_str_to_int_map(); EXPECT_EQ(0, test_model.str_to_int_map_size()); test_model.set_str_to_int_map("first", 10); EXPECT_EQ(1, test_model.str_to_int_map_size()); test_model.set_str_to_int_map("second", 20); EXPECT_EQ(2, test_model.str_to_int_map_size()); auto result = test_model.get_str_to_int_map("second"); EXPECT_EQ(true, result.ok()); EXPECT_EQ(20, result.value()); test_model.delete_str_to_int_map("first"); auto result_after_delete = test_model.get_str_to_int_map("first"); EXPECT_EQ(false, result_after_delete.ok()); } TEST(CppGeneratedCode, HpbStatus) { TestModel model; model.set_str1("lightweight status"); hpb::Arena arena; absl::StatusOr bytes = ::hpb::Serialize(&model, arena); EXPECT_EQ(true, bytes.ok()); hpb::StatusOr parsed_model = ::hpb::Parse( bytes.value(), hpb::ParseOptionsWithEmptyRegistry()); EXPECT_EQ(true, parsed_model.ok()); EXPECT_EQ("lightweight status", parsed_model.value().str1()); } TEST(CppGeneratedCode, HpbStatusFail) { hpb::StatusOr status = ::hpb::Parse( "definitely not a proto", hpb::ParseOptionsWithEmptyRegistry()); EXPECT_EQ(false, status.ok()); EXPECT_EQ(status.error(), "Wire format was corrupt"); absl::StatusOr to_absl_status = status.ToAbslStatusOr(); EXPECT_EQ(false, to_absl_status.ok()); EXPECT_EQ(to_absl_status.status().message(), "Wire format was corrupt"); } TEST(CppGeneratedCode, SerializeUsingArena) { TestModel model; model.set_str1("Hello World"); hpb::Arena arena; absl::StatusOr bytes = ::hpb::Serialize(&model, arena); EXPECT_EQ(true, bytes.ok()); TestModel parsed_model = ::hpb::Parse(bytes.value(), hpb::DefaultParseOptions()) .value(); EXPECT_EQ("Hello World", parsed_model.str1()); } TEST(CppGeneratedCode, SerializeProxyUsingArena) { hpb::Arena message_arena; TestModel::Proxy model_proxy = ::hpb::CreateMessage(message_arena); model_proxy.set_str1("Hello World"); hpb::Arena arena; absl::StatusOr bytes = ::hpb::Serialize(&model_proxy, arena); EXPECT_EQ(true, bytes.ok()); TestModel parsed_model = ::hpb::Parse(bytes.value(), hpb::DefaultParseOptions()) .value(); EXPECT_EQ("Hello World", parsed_model.str1()); } TEST(CppGeneratedCode, SerializeNestedMessageUsingArena) { TestModel model; model.mutable_recursive_child()->set_str1("Hello World"); hpb::Arena arena; hpb::Ptr child = model.recursive_child(); absl::StatusOr bytes = ::hpb::Serialize(child, arena); EXPECT_EQ(true, bytes.ok()); TestModel parsed_model = ::hpb::Parse(bytes.value(), hpb::DefaultParseOptions()) .value(); EXPECT_EQ("Hello World", parsed_model.str1()); } TEST(CppGeneratedCode, NameCollisions) { TestModel model; model.set_template_("test"); EXPECT_EQ("test", model.template_()); model.set_arena__("test"); EXPECT_EQ("test", model.arena__()); } TEST(CppGeneratedCode, SharedPointer) { std::shared_ptr model = std::make_shared(); hpb::Arena arena; auto bytes = ::hpb::Serialize(model.get(), arena); EXPECT_TRUE(::hpb::Parse(model.get(), bytes.value())); } TEST(CppGeneratedCode, UniquePointer) { auto model = std::make_unique(); hpb::Arena arena; auto bytes = ::hpb::Serialize(model.get(), arena); EXPECT_TRUE(::hpb::Parse(model.get(), bytes.value())); } TEST(CppGeneratedCode, Assignment) { TestModel model; model.set_category(5); model.mutable_child_model_1()->set_child_str1("text in child"); TestModel model2 = model; EXPECT_EQ(5, model2.category()); EXPECT_EQ(model2.child_model_1()->child_str1(), "text in child"); } TEST(CppGeneratedCode, PtrAssignment) { TestModel model; model.mutable_child_model_1()->set_child_str1("text in child"); ChildModel1 child_from_const_ptr = *model.child_model_1(); EXPECT_EQ(child_from_const_ptr.child_str1(), "text in child"); ChildModel1 child_from_ptr = *model.mutable_child_model_1(); EXPECT_EQ(child_from_ptr.child_str1(), "text in child"); } TEST(CppGeneratedCode, CopyConstructor) { TestModel model; model.set_category(6); TestModel model2(model); EXPECT_EQ(6, model2.category()); } TEST(CppGeneratedCode, PtrConstructor) { TestModel model; model.mutable_child_model_1()->set_child_str1("text in child"); ChildModel1 child_from_ptr(*model.mutable_child_model_1()); EXPECT_EQ(child_from_ptr.child_str1(), "text in child"); ChildModel1 child_from_const_ptr(*model.child_model_1()); EXPECT_EQ(child_from_const_ptr.child_str1(), "text in child"); } TEST(CppGeneratedCode, MutableToProxy) { TestModel model; ::hpb::Ptr child = model.mutable_child_model_1(); (void)child; } TEST(CppGeneratedCode, ProxyToCProxy) { TestModel model; ::hpb::Ptr child = model.mutable_child_model_1(); ::hpb::Ptr child2 = child; (void)child2; } TEST(CppGeneratedCode, MutableAccessorsAreHiddenInCProxy) { TestModel model; ::hpb::Ptr proxy = &model; ::hpb::Ptr cproxy = proxy; const auto test_const_accessors = [](auto p) { // We don't want to run it, just check it compiles. if (false) { (void)p->has_str1(); (void)p->str1(); (void)p->has_value(); (void)p->value(); (void)p->has_oneof_member1(); (void)p->oneof_member1(); (void)p->value_array(); (void)p->value_array_size(); (void)p->value_array(1); (void)p->has_nested_child_1(); (void)p->nested_child_1(); (void)p->child_models(); (void)p->child_models_size(); (void)p->child_models(1); (void)p->child_map_size(); (void)p->get_child_map(1); } }; test_const_accessors(proxy); test_const_accessors(cproxy); const auto test_mutable_accessors = [](auto p, bool expected) { const auto r = [&](auto l) { return Requires(l) == expected; }; EXPECT_TRUE(r([](auto p) -> decltype(p->set_str1("")) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->clear_str1()) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->set_value(1)) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->clear_value()) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->set_oneof_member1("")) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->clear_oneof_member1()) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->mutable_nested_child_1()) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->clear_nested_child_1()) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->add_value_array(1)) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->mutable_value_array()) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->resize_value_array(1)) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->set_value_array(1, 1)) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->add_child_models()) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->mutable_child_models(1)) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->clear_child_map()) {})); EXPECT_TRUE(r([](auto p) -> decltype(p->delete_child_map(1)) {})); EXPECT_TRUE(r( [](auto p) -> decltype(p->set_child_map(1, *p->get_child_map(1))) {})); }; test_mutable_accessors(proxy, true); test_mutable_accessors(cproxy, false); } bool ProxyToCProxyMethod(::hpb::Ptr child) { return child->child_str1() == "text in child"; } TEST(CppGeneratedCode, PassProxyToCProxy) { TestModel model; model.mutable_child_model_1()->set_child_str1("text in child"); EXPECT_TRUE(ProxyToCProxyMethod(model.mutable_child_model_1())); } TEST(CppGeneratedCode, PtrImplicitConversion) { TestModel model; model.set_int64(5); ::hpb::Ptr model_ptr = &model; EXPECT_EQ(model_ptr->int64(), 5); } TEST(CppGeneratedCode, CanInvokeClearMessageWithPtr) { // Fill model. TestModel model; model.set_int64(5); auto new_child = model.add_child_models(); // Clear using Ptr auto ptr = ::hpb::Ptr(&model); ::hpb::ClearMessage(ptr); // Successful clear EXPECT_FALSE(model.has_int64()); } TEST(CppGeneratedCode, CanInvokeClearMessageWithRawPtr) { // Fill model. TestModel model; model.set_int64(5); auto new_child = model.add_child_models(); // Clear using T* ::hpb::ClearMessage(&model); // Successful clear EXPECT_FALSE(model.has_int64()); } template bool CanCallClearMessage() { return Requires([](auto x) -> decltype(::hpb::ClearMessage(x)) {}); } TEST(CppGeneratedCode, CannotInvokeClearMessageWithConstPtr) { EXPECT_TRUE(CanCallClearMessage<::hpb::Ptr>()); EXPECT_FALSE(CanCallClearMessage<::hpb::Ptr>()); } TEST(CppGeneratedCode, CannotInvokeClearMessageWithConstRawPtr) { EXPECT_TRUE(CanCallClearMessage()); EXPECT_FALSE(CanCallClearMessage()); } TEST(CppGeneratedCode, FieldNumberConstants) { static_assert(TestModel::kChildMapFieldNumber == 225); EXPECT_EQ(225, TestModel::kChildMapFieldNumber); } TEST(CppGeneratedCode, ClearConstMessageShouldFailForConstChild) { TestModel model; EXPECT_FALSE(CanCallClearMessage()); EXPECT_TRUE(CanCallClearMessage()); } TEST(CppGeneratedCode, CloneMessage) { hpb::Arena arena; TestModel model; model.set_str1("Hello World"); auto ptr = hpb::Ptr(&model); hpb::Ptr cloned_model = hpb::CloneMessage(ptr, arena); EXPECT_EQ(cloned_model->str1(), "Hello World"); } TEST(CppGeneratedCode, SetAlias) { hpb::Arena arena; auto child = hpb::CreateMessage(arena); child.set_peeps(12); auto parent1 = hpb::CreateMessage(arena); auto parent2 = hpb::CreateMessage(arena); parent1.set_alias_child(child); parent2.set_alias_child(child); ASSERT_EQ(parent1.child()->peeps(), parent2.child()->peeps()); ASSERT_EQ(hpb::interop::upb::GetMessage(parent1.child()), hpb::interop::upb::GetMessage(parent2.child())); auto childPtr = hpb::Ptr(child); ASSERT_EQ(hpb::interop::upb::GetMessage(childPtr), hpb::interop::upb::GetMessage(parent1.child())); } TEST(CppGeneratedCode, SetAliasFieldsOutofOrder) { hpb::Arena arena; auto child = hpb::CreateMessage(arena); child.set_peeps(12); auto parent1 = hpb::CreateMessage(arena); auto parent2 = hpb::CreateMessage(arena); parent1.set_alias_child(child); parent2.set_alias_child(child); ASSERT_EQ(parent1.child()->peeps(), parent2.child()->peeps()); ASSERT_EQ(parent1.child()->peeps(), 12); } #ifndef NDEBUG TEST(CppGeneratedCode, SetAliasFailsForDifferentArena) { hpb::Arena arena; auto child = hpb::CreateMessage(arena); hpb::Arena different_arena; auto parent = hpb::CreateMessage(different_arena); EXPECT_DEATH(parent.set_alias_child(child), "hpb::interop::upb::GetArena"); } #endif TEST(CppGeneratedCode, SetAliasSucceedsForDifferentArenaFused) { hpb::Arena arena; auto parent1 = hpb::CreateMessage(arena); auto child = parent1.mutable_child(); child->set_peeps(12); hpb::Arena other_arena; auto parent2 = hpb::CreateMessage(other_arena); arena.Fuse(other_arena); parent2.set_alias_child(child); ASSERT_EQ(parent1.child()->peeps(), parent2.child()->peeps()); ASSERT_EQ(hpb::interop::upb::GetMessage(parent1.child()), hpb::interop::upb::GetMessage(parent2.child())); auto childPtr = hpb::Ptr(child); ASSERT_EQ(hpb::interop::upb::GetMessage(childPtr), hpb::interop::upb::GetMessage(parent1.child())); } TEST(CppGeneratedCode, SetAliasRepeated) { hpb::Arena arena; auto child = hpb::CreateMessage(arena); child.set_peeps(1611); auto parent1 = hpb::CreateMessage(arena); auto parent2 = hpb::CreateMessage(arena); parent1.add_alias_children(child); parent2.add_alias_children(child); ASSERT_EQ(parent1.children(0)->peeps(), parent2.children(0)->peeps()); ASSERT_EQ(hpb::interop::upb::GetMessage(parent1.children(0)), hpb::interop::upb::GetMessage(parent2.children(0))); auto childPtr = hpb::Ptr(child); ASSERT_EQ(hpb::interop::upb::GetMessage(childPtr), hpb::interop::upb::GetMessage(parent1.children(0))); } #ifndef NDEBUG TEST(CppGeneratedCode, SetAliasRepeatedFailsForDifferentArena) { hpb::Arena arena; auto child = hpb::CreateMessage(arena); hpb::Arena different_arena; auto parent = hpb::CreateMessage(different_arena); EXPECT_DEATH(parent.add_alias_children(child), "hpb::interop::upb::GetArena"); } #endif TEST(CppGeneratedCode, SetAliasMap) { hpb::Arena arena; auto parent1 = hpb::CreateMessage(arena); auto parent2 = hpb::CreateMessage(arena); auto child = hpb::CreateMessage(arena); constexpr int key = 1; parent1.set_alias_child_map(key, child); parent2.set_alias_child_map(key, child); auto c1 = parent1.get_child_map(key); auto c2 = parent2.get_child_map(key); EXPECT_TRUE(c1.ok()); EXPECT_TRUE(c2.ok()); ASSERT_EQ(hpb::interop::upb::GetMessage(c1.value()), hpb::interop::upb::GetMessage(c2.value())); } #ifndef NDEBUG TEST(CppGeneratedCode, SetAliasMapFailsDifferentArena) { hpb::Arena arena1; hpb::Arena arena2; auto parent1 = hpb::CreateMessage(arena1); auto child = hpb::CreateMessage(arena2); constexpr int key = 1; EXPECT_DEATH(parent1.set_alias_child_map(key, child), "hpb::interop::upb::GetArena"); } #endif TEST(CppGeneratedCode, SetAliasSucceedsForDifferentArenaRefs) { hpb::Arena arena; auto parent1 = hpb::CreateMessage(arena); auto child = parent1.mutable_child(); child->set_peeps(12); hpb::Arena other_arena; auto parent2 = hpb::CreateMessage(other_arena); other_arena.RefArena(arena); parent2.set_alias_child(child); ASSERT_EQ(parent1.child()->peeps(), parent2.child()->peeps()); ASSERT_EQ(hpb::interop::upb::GetMessage(parent1.child()), hpb::interop::upb::GetMessage(parent2.child())); auto childPtr = hpb::Ptr(child); ASSERT_EQ(hpb::interop::upb::GetMessage(childPtr), hpb::interop::upb::GetMessage(parent1.child())); } } // namespace