// Protocol Buffers - Google's data interchange format // Copyright 2024 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 "hpb_generator/tests/child_model.hpb.h" #include "hpb_generator/tests/test_extension.hpb.h" #include "hpb_generator/tests/test_model.hpb.h" #include "hpb/arena.h" #include "hpb/ptr.h" #include "hpb/requires.h" namespace { using ::hpb::internal::Requires; using ::hpb_unittest::protos::ChildModel1; using ::hpb_unittest::protos::TestModel; using ::testing::ElementsAre; const char kTestStr1[] = "abcdefg"; const char kTestStr2[] = "just another test string"; TEST(CppGeneratedCode, RepeatedMessages) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(0, test_model.child_models_size()); // Should be able to clear repeated field when empty. test_model.mutable_child_models()->clear(); EXPECT_EQ(0, test_model.child_models_size()); // Add 2 children. auto new_child = test_model.add_child_models(); EXPECT_EQ(true, new_child.ok()); new_child.value()->set_child_str1(kTestStr1); new_child = test_model.add_child_models(); EXPECT_EQ(true, new_child.ok()); new_child.value()->set_child_str1(kTestStr2); EXPECT_EQ(2, test_model.child_models_size()); // Mutable access. auto mutable_first = test_model.mutable_child_models(0); EXPECT_EQ(mutable_first->child_str1(), kTestStr1); mutable_first->set_child_str1("change1"); auto mutable_second = test_model.mutable_child_models(1); EXPECT_EQ(mutable_second->child_str1(), kTestStr2); mutable_second->set_child_str1("change2"); // Check mutations using views. auto view_first = test_model.child_models(0); EXPECT_EQ(view_first->child_str1(), "change1"); auto view_second = test_model.child_models(1); EXPECT_EQ(view_second->child_str1(), "change2"); } TEST(CppGeneratedCode, RepeatedScalar) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(0, test_model.value_array_size()); // Should be able to clear repeated field when empty. test_model.mutable_value_array()->clear(); EXPECT_EQ(0, test_model.value_array_size()); // Add 2 children. EXPECT_EQ(true, test_model.add_value_array(5)); EXPECT_EQ(true, test_model.add_value_array(6)); EXPECT_EQ(2, test_model.value_array_size()); EXPECT_EQ(5, test_model.value_array(0)); EXPECT_EQ(6, test_model.value_array(1)); EXPECT_EQ(true, test_model.resize_value_array(3)); EXPECT_EQ(3, test_model.value_array_size()); test_model.set_value_array(2, 7); EXPECT_EQ(5, test_model.value_array(0)); EXPECT_EQ(6, test_model.value_array(1)); EXPECT_EQ(7, test_model.value_array(2)); } TEST(CppGeneratedCode, RepeatedFieldClear) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); test_model.mutable_value_array()->push_back(5); test_model.mutable_value_array()->push_back(16); test_model.mutable_value_array()->push_back(27); ASSERT_EQ(test_model.mutable_value_array()->size(), 3); test_model.mutable_value_array()->clear(); EXPECT_EQ(test_model.mutable_value_array()->size(), 0); } TEST(CppGeneratedCode, RepeatedFieldProxyForScalars) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(0, test_model.value_array().size()); EXPECT_EQ(0, test_model.mutable_value_array()->size()); test_model.mutable_value_array()->push_back(5); test_model.mutable_value_array()->push_back(16); test_model.mutable_value_array()->push_back(27); ASSERT_EQ(test_model.mutable_value_array()->size(), 3); EXPECT_EQ((*test_model.mutable_value_array())[0], 5); EXPECT_EQ((*test_model.mutable_value_array())[1], 16); EXPECT_EQ((*test_model.mutable_value_array())[2], 27); const auto value_array = test_model.value_array(); ASSERT_EQ(value_array.size(), 3); EXPECT_EQ(value_array[0], 5); EXPECT_EQ(value_array[1], 16); EXPECT_EQ(value_array[2], 27); EXPECT_THAT(value_array, ElementsAre(5, 16, 27)); EXPECT_THAT(std::vector(value_array.begin(), value_array.end()), ElementsAre(5, 16, 27)); EXPECT_THAT(std::vector(value_array.cbegin(), value_array.cend()), ElementsAre(5, 16, 27)); EXPECT_THAT(std::vector(value_array.rbegin(), value_array.rend()), ElementsAre(27, 16, 5)); EXPECT_THAT(std::vector(value_array.crbegin(), value_array.crend()), ElementsAre(27, 16, 5)); } TEST(CppGeneratedCode, RepeatedScalarIterator) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); test_model.mutable_value_array()->push_back(5); test_model.mutable_value_array()->push_back(16); test_model.mutable_value_array()->push_back(27); int sum = 0; // Access by value. const ::hpb::RepeatedField::CProxy rep1 = test_model.value_array(); for (auto i : rep1) { sum += i; } EXPECT_EQ(sum, 5 + 16 + 27); // Access by const reference. sum = 0; for (const auto& i : *test_model.mutable_value_array()) { sum += i; } EXPECT_EQ(sum, 5 + 16 + 27); // Access by forwarding reference. sum = 0; for (auto&& i : *test_model.mutable_value_array()) { sum += i; } EXPECT_EQ(sum, 5 + 16 + 27); // Test iterator operators. auto begin = test_model.value_array().begin(); auto end = test_model.value_array().end(); sum = 0; for (auto it = begin; it != end; ++it) { sum += *it; } EXPECT_EQ(sum, 5 + 16 + 27); auto it = begin; ++it; EXPECT_TRUE(begin < it); EXPECT_TRUE(begin <= it); it = end; EXPECT_TRUE(it == end); EXPECT_TRUE(it > begin); EXPECT_TRUE(it >= begin); EXPECT_TRUE(it != begin); // difference type it = end; --it; --it; EXPECT_EQ(end - it, 2); it = begin; EXPECT_EQ(it[0], 5); EXPECT_EQ(it[1], 16); EXPECT_EQ(it[2], 27); // ValueProxy. sum = 0; for (::hpb::RepeatedField::ValueCProxy c : test_model.value_array()) { sum += c; } EXPECT_EQ(sum, 5 + 16 + 27); sum = 0; for (::hpb::RepeatedField::ValueProxy c : *test_model.mutable_value_array()) { sum += c; } EXPECT_EQ(sum, 5 + 16 + 27); } TEST(CppGeneratedCode, RepeatedFieldProxyForStrings) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(0, test_model.repeated_string().size()); EXPECT_EQ(0, test_model.mutable_repeated_string()->size()); test_model.mutable_repeated_string()->push_back("a"); test_model.mutable_repeated_string()->push_back("b"); test_model.mutable_repeated_string()->push_back("c"); ASSERT_EQ(test_model.repeated_string().size(), 3); EXPECT_EQ(test_model.repeated_string()[0], "a"); EXPECT_EQ(test_model.repeated_string()[1], "b"); EXPECT_EQ(test_model.repeated_string()[2], "c"); EXPECT_THAT(test_model.repeated_string(), ElementsAre("a", "b", "c")); EXPECT_THAT(*test_model.mutable_repeated_string(), ElementsAre("a", "b", "c")); ASSERT_EQ(test_model.mutable_repeated_string()->size(), 3); EXPECT_EQ((*test_model.mutable_repeated_string())[0], "a"); EXPECT_EQ((*test_model.mutable_repeated_string())[1], "b"); EXPECT_EQ((*test_model.mutable_repeated_string())[2], "c"); // The const accessor can't be used to modify the element EXPECT_FALSE((std::is_assignable::value)); // But the mutable one is fine. (*test_model.mutable_repeated_string())[1] = "other"; EXPECT_THAT(test_model.repeated_string(), ElementsAre("a", "other", "c")); test_model.mutable_repeated_string()->clear(); EXPECT_EQ(test_model.mutable_repeated_string()->size(), 0); } TEST(CppGeneratedCode, RepeatedFieldProxyForMessages) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(0, test_model.child_models().size()); ChildModel1 child1; child1.set_child_str1(kTestStr1); test_model.mutable_child_models()->push_back(child1); ChildModel1 child2; child2.set_child_str1(kTestStr2); test_model.mutable_child_models()->push_back(std::move(child2)); int i = 0; for (auto child : test_model.child_models()) { EXPECT_FALSE(Requires( [](auto&& x) -> decltype(x.set_child_str1("")) {})); if (i++ == 0) { EXPECT_EQ(child.child_str1(), kTestStr1); } else { EXPECT_EQ(child.child_str1(), kTestStr2); } } i = 0; for (const auto& child : *test_model.mutable_child_models()) { if (i++ == 0) { EXPECT_EQ(child.child_str1(), kTestStr1); } else { EXPECT_EQ(child.child_str1(), kTestStr2); } } using testing::_; EXPECT_THAT(test_model.child_models(), ElementsAre(_, _)); EXPECT_EQ(test_model.child_models().size(), 2); EXPECT_EQ(test_model.child_models()[0].child_str1(), kTestStr1); EXPECT_EQ(test_model.child_models()[1].child_str1(), kTestStr2); EXPECT_EQ((*test_model.mutable_child_models())[0].child_str1(), kTestStr1); EXPECT_EQ((*test_model.mutable_child_models())[1].child_str1(), kTestStr2); (*test_model.mutable_child_models())[0].set_child_str1("change1"); EXPECT_EQ((*test_model.mutable_child_models())[0].child_str1(), "change1"); test_model.mutable_child_models()->clear(); EXPECT_EQ(test_model.mutable_child_models()->size(), 0); } TEST(CppGeneratedCode, EmptyRepeatedFieldProxyForMessages) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(0, test_model.child_models().size()); ChildModel1 child1; child1.set_child_str1(kTestStr1); EXPECT_EQ(test_model.child_models().size(), 0); EXPECT_EQ(std::distance(test_model.child_models().begin(), test_model.child_models().end()), 0); } TEST(CppGeneratedCode, EmptyRepeatedFieldScalarProxy) { hpb::Arena arena; hpb::Ptr test_model = hpb::CreateMessage(arena); EXPECT_EQ(std::distance(test_model->repeated_int64().begin(), test_model->repeated_int64().end()), 0); } TEST(CppGeneratedCode, RepeatedFieldProxyForMessagesIndexOperator) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(0, test_model.child_models().size()); ChildModel1 child1; child1.set_child_str1(kTestStr1); test_model.mutable_child_models()->push_back(child1); ChildModel1 child2; child2.set_child_str1(kTestStr2); test_model.mutable_child_models()->push_back(std::move(child2)); ASSERT_EQ(test_model.child_models().size(), 2); // test_model.child_models()[0].set_child_str1("change1"); (*test_model.mutable_child_models())[0].set_child_str1("change1"); EXPECT_EQ((*test_model.mutable_child_models())[0].child_str1(), "change1"); } TEST(CppGeneratedCode, RepeatedStrings) { ::hpb::Arena arena; auto test_model = ::hpb::CreateMessage(arena); EXPECT_EQ(0, test_model.repeated_string_size()); // Should be able to clear repeated field when empty. test_model.mutable_repeated_string()->clear(); EXPECT_EQ(0, test_model.repeated_string_size()); // Add 2 children. EXPECT_EQ(true, test_model.add_repeated_string("Hello")); EXPECT_EQ(true, test_model.add_repeated_string("World")); EXPECT_EQ(2, test_model.repeated_string_size()); EXPECT_EQ("Hello", test_model.repeated_string(0)); EXPECT_EQ("World", test_model.repeated_string(1)); EXPECT_EQ(true, test_model.resize_repeated_string(3)); EXPECT_EQ(3, test_model.repeated_string_size()); test_model.set_repeated_string(2, "Test"); EXPECT_EQ("Hello", test_model.repeated_string(0)); EXPECT_EQ("World", test_model.repeated_string(1)); EXPECT_EQ("Test", test_model.repeated_string(2)); } } // namespace