blob: df9d119d7a4de2d853573ca56fd6aeb8b849d854 [file] [log] [blame]
// 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include "google/protobuf/compiler/hpb/tests/child_model.upb.proto.h"
#include "google/protobuf/compiler/hpb/tests/test_extension.upb.proto.h"
#include "google/protobuf/compiler/hpb/tests/test_model.upb.proto.h"
#include "google/protobuf/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<TestModel>(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<TestModel>(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<TestModel>(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<TestModel>(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<TestModel>(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<int32_t>::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<int32_t>::ValueCProxy c :
test_model.value_array()) {
sum += c;
}
EXPECT_EQ(sum, 5 + 16 + 27);
sum = 0;
for (::hpb::RepeatedField<int32_t>::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<TestModel>(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<decltype(test_model.repeated_string()[1]),
absl::string_view>::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<TestModel>(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<decltype(child)>(
[](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<TestModel>(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, RepeatedFieldProxyForMessagesIndexOperator) {
::hpb::Arena arena;
auto test_model = ::hpb::CreateMessage<TestModel>(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<TestModel>(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