Add unit test coverage for SwapField for implicit presence fields.

When swap is being called on a scalar field in an implicit-presence message,
calling accessors on the swapped-out field should give zero.

When swap is being called on a repeated field in an implicit-presence message,
calling accessors on the swapped-out field should give the empty list.

When swap is being called on a oneof field in an implicit-presence message,
calling `has_foo` on the swapped-out field should return false.

PiperOrigin-RevId: 684582416
pull/18626/head
Tony Liao 4 months ago committed by Copybara-Service
parent d9caebc313
commit bd375ce7c1
  1. 317
      src/google/protobuf/no_field_presence_test.cc

@ -33,6 +33,7 @@ using ::proto2_nofieldpresence_unittest::ForeignMessage;
using ::proto2_nofieldpresence_unittest::TestAllTypes;
using ::testing::Eq;
using ::testing::Gt;
using ::testing::IsEmpty;
using ::testing::Not;
using ::testing::StrEq;
using ::testing::UnorderedPointwise;
@ -258,6 +259,322 @@ TEST(NoFieldPresenceTest, MessageFieldPresenceTest) {
TestAllTypes::default_instance().has_optional_nested_message());
}
class NoFieldPresenceSwapFieldTest : public testing::Test {
protected:
NoFieldPresenceSwapFieldTest()
: m1_(),
m2_(),
r1_(m1_.GetReflection()),
r2_(m2_.GetReflection()),
d1_(m1_.GetDescriptor()),
d2_(m2_.GetDescriptor()) {}
// Returns a field descriptor that corresponds to the field name.
// Note that different messages would still return the same field descriptor.
const FieldDescriptor* FindFieldByName(absl::string_view field_name) {
const FieldDescriptor* f1 = d1_->FindFieldByName(field_name);
const FieldDescriptor* f2 = d2_->FindFieldByName(field_name);
// We actually ensure uniqueness of *field descriptors* even if we try to
// obtain them from different *message descriptors*.
ABSL_CHECK_EQ(f1, f2);
return f1;
}
TestAllTypes m1_;
TestAllTypes m2_;
const Reflection* r1_;
const Reflection* r2_;
const Descriptor* d1_;
const Descriptor* d2_;
};
TEST_F(NoFieldPresenceSwapFieldTest, ReflectionSwapFieldScalarNonZeroTest) {
m1_.set_optional_int32(1);
m2_.set_optional_int32(2);
const FieldDescriptor* f = FindFieldByName("optional_int32");
r1_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_TRUE(r1_->HasField(m1_, f));
EXPECT_TRUE(r2_->HasField(m2_, f));
EXPECT_EQ(2, m1_.optional_int32());
EXPECT_EQ(1, m2_.optional_int32());
// It doesn't matter which reflection or descriptor gets used; swapping should
// still work if m2_'s descriptor is provided.
r2_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped again.
EXPECT_TRUE(r1_->HasField(m1_, f));
EXPECT_TRUE(r2_->HasField(m2_, f));
EXPECT_EQ(1, m1_.optional_int32());
EXPECT_EQ(2, m2_.optional_int32());
}
TEST_F(NoFieldPresenceSwapFieldTest, ReflectionSwapFieldScalarOneZeroTest) {
m1_.set_optional_int32(1);
const FieldDescriptor* f = FindFieldByName("optional_int32");
r1_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_FALSE(r1_->HasField(m1_, f));
EXPECT_TRUE(r2_->HasField(m2_, f));
EXPECT_EQ(0, m1_.optional_int32());
EXPECT_EQ(1, m2_.optional_int32());
// It doesn't matter which reflection or descriptor gets used; swapping should
// still work if m2_'s descriptor is provided.
r2_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped again.
EXPECT_TRUE(r1_->HasField(m1_, f));
EXPECT_FALSE(r2_->HasField(m2_, f));
EXPECT_EQ(1, m1_.optional_int32());
EXPECT_EQ(0, m2_.optional_int32());
}
TEST_F(NoFieldPresenceSwapFieldTest, ReflectionSwapFieldScalarBothZeroTest) {
m1_.set_optional_int32(0); // setting an int field to zero should be noop
const FieldDescriptor* f = FindFieldByName("optional_int32");
r1_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_FALSE(r1_->HasField(m1_, f));
EXPECT_FALSE(r2_->HasField(m2_, f));
EXPECT_EQ(0, m1_.optional_int32());
EXPECT_EQ(0, m2_.optional_int32());
// It doesn't matter which reflection or descriptor gets used; swapping should
// still work if m2_'s descriptor is provided.
r2_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped again.
EXPECT_FALSE(r1_->HasField(m1_, f));
EXPECT_FALSE(r2_->HasField(m2_, f));
EXPECT_EQ(0, m1_.optional_int32());
EXPECT_EQ(0, m2_.optional_int32());
}
TEST_F(NoFieldPresenceSwapFieldTest, ReflectionSwapFieldRepeatedNonZeroTest) {
m1_.add_repeated_int32(1);
m2_.add_repeated_int32(2);
m2_.add_repeated_int32(22);
const FieldDescriptor* f = FindFieldByName("repeated_int32");
r1_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_EQ(r1_->FieldSize(m1_, f), 2);
EXPECT_EQ(r2_->FieldSize(m2_, f), 1);
EXPECT_THAT(m1_.repeated_int32(), UnorderedPointwise(Eq(), {2, 22}));
EXPECT_THAT(m2_.repeated_int32(), UnorderedPointwise(Eq(), {1}));
// It doesn't matter which reflection or descriptor gets used; swapping should
// still work if m2_'s descriptor is provided.
r2_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped again.
EXPECT_EQ(r1_->FieldSize(m1_, f), 1);
EXPECT_EQ(r2_->FieldSize(m2_, f), 2);
EXPECT_THAT(m1_.repeated_int32(), UnorderedPointwise(Eq(), {1}));
EXPECT_THAT(m2_.repeated_int32(), UnorderedPointwise(Eq(), {2, 22}));
}
TEST_F(NoFieldPresenceSwapFieldTest, ReflectionSwapFieldRepeatedOneZeroTest) {
m1_.add_repeated_int32(1);
const FieldDescriptor* f = FindFieldByName("repeated_int32");
r1_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_EQ(r1_->FieldSize(m1_, f), 0);
EXPECT_EQ(r2_->FieldSize(m2_, f), 1);
EXPECT_THAT(m1_.repeated_int32(), IsEmpty());
EXPECT_THAT(m2_.repeated_int32(), UnorderedPointwise(Eq(), {1}));
// It doesn't matter which reflection or descriptor gets used; swapping should
// still work if m2_'s descriptor is provided.
r2_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped again.
EXPECT_EQ(r1_->FieldSize(m1_, f), 1);
EXPECT_EQ(r2_->FieldSize(m2_, f), 0);
EXPECT_THAT(m1_.repeated_int32(), UnorderedPointwise(Eq(), {1}));
EXPECT_THAT(m2_.repeated_int32(), IsEmpty());
}
TEST_F(NoFieldPresenceSwapFieldTest,
ReflectionSwapFieldRepeatedExplicitZeroTest) {
// For repeated fields, explicitly adding zero would cause it to be added into
// the repeated field.
m1_.add_repeated_int32(0);
const FieldDescriptor* f = FindFieldByName("repeated_int32");
r1_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_EQ(r1_->FieldSize(m1_, f), 0);
EXPECT_EQ(r2_->FieldSize(m2_, f), 1);
EXPECT_THAT(m1_.repeated_int32(), IsEmpty());
EXPECT_THAT(m2_.repeated_int32(), UnorderedPointwise(Eq(), {0}));
// It doesn't matter which reflection or descriptor gets used; swapping should
// still work if m2_'s descriptor is provided.
r2_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped again.
EXPECT_EQ(r1_->FieldSize(m1_, f), 1);
EXPECT_EQ(r2_->FieldSize(m2_, f), 0);
EXPECT_THAT(m1_.repeated_int32(), UnorderedPointwise(Eq(), {0}));
EXPECT_THAT(m2_.repeated_int32(), IsEmpty());
}
TEST_F(NoFieldPresenceSwapFieldTest,
ReflectionSwapFieldOneofFieldDescriptorTest) {
m1_.set_oneof_uint32(1);
m2_.set_oneof_string("test");
// NOTE: Calling swap on any field descriptor within the oneof works --
// even a completely unrelated field.
const FieldDescriptor* never_set_field = d1_->FindFieldByName("oneof_enum");
r1_->SwapFields(&m1_, &m2_, /*fields=*/{never_set_field});
// Fields should be swapped.
EXPECT_FALSE(r1_->HasField(m1_, never_set_field));
EXPECT_FALSE(r1_->HasField(m2_, never_set_field));
EXPECT_TRUE(m1_.has_oneof_string());
EXPECT_TRUE(m2_.has_oneof_uint32());
EXPECT_EQ(m1_.oneof_string(), "test");
EXPECT_EQ(m2_.oneof_uint32(), 1);
// Calling oneof accessors on a swapped-out field will give the default value.
EXPECT_FALSE(m1_.has_oneof_uint32());
EXPECT_FALSE(m2_.has_oneof_string());
EXPECT_EQ(m1_.oneof_uint32(), 0);
EXPECT_THAT(m2_.oneof_string(), IsEmpty());
}
TEST_F(NoFieldPresenceSwapFieldTest,
ReflectionSwapFieldOneofFieldMultipleIdenticalDescriptorTest) {
m1_.set_oneof_uint32(1);
m2_.set_oneof_string("test");
// NOTE: Calling swap on any field descriptor within the oneof works --
// even a completely unrelated field.
const FieldDescriptor* never_set_field = d1_->FindFieldByName("oneof_enum");
const FieldDescriptor* f1 = d1_->FindFieldByName("oneof_uint32");
const FieldDescriptor* f2 = d2_->FindFieldByName("oneof_string");
// Multiple instances of the identical descriptor is ignored.
r1_->SwapFields(&m1_, &m2_, /*fields=*/{never_set_field, never_set_field});
// Fields should be swapped (just once).
EXPECT_EQ(m1_.oneof_string(), "test");
EXPECT_EQ(m2_.oneof_uint32(), 1);
// Multiple instances of the identical descriptor is ignored.
r2_->SwapFields(&m1_, &m2_, /*fields=*/{f1, f2, never_set_field});
// Fields should be swapped (just once).
EXPECT_TRUE(m1_.has_oneof_uint32());
EXPECT_TRUE(m2_.has_oneof_string());
EXPECT_TRUE(r1_->HasField(m1_, f1));
EXPECT_TRUE(r2_->HasField(m2_, f2));
EXPECT_EQ(m1_.oneof_uint32(), 1);
EXPECT_EQ(m2_.oneof_string(), "test");
// Calling oneof accessors on a swapped-out field will give the default value.
EXPECT_FALSE(m1_.has_oneof_string());
EXPECT_FALSE(m2_.has_oneof_uint32());
EXPECT_FALSE(r1_->HasField(m1_, d1_->FindFieldByName("oneof_string")));
EXPECT_FALSE(r2_->HasField(m2_, d2_->FindFieldByName("oneof_uint32")));
EXPECT_THAT(m1_.oneof_string(), IsEmpty());
EXPECT_EQ(m2_.oneof_uint32(), 0);
}
TEST_F(NoFieldPresenceSwapFieldTest, ReflectionSwapFieldOneofNonZeroTest) {
m1_.set_oneof_uint32(1);
m2_.set_oneof_string("test");
const FieldDescriptor* f = FindFieldByName("oneof_uint32");
r1_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_TRUE(m1_.has_oneof_string());
EXPECT_TRUE(m2_.has_oneof_uint32());
EXPECT_TRUE(r1_->HasField(m1_, d1_->FindFieldByName("oneof_string")));
EXPECT_TRUE(r2_->HasField(m2_, f));
EXPECT_EQ(m1_.oneof_string(), "test");
EXPECT_EQ(m2_.oneof_uint32(), 1);
// It doesn't matter which reflection or descriptor gets used; swapping should
// still work if m2_'s descriptor is provided.
r2_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_TRUE(m1_.has_oneof_uint32());
EXPECT_TRUE(m2_.has_oneof_string());
EXPECT_TRUE(r1_->HasField(m1_, f));
EXPECT_TRUE(r2_->HasField(m2_, d2_->FindFieldByName("oneof_string")));
EXPECT_EQ(m1_.oneof_uint32(), 1);
EXPECT_EQ(m2_.oneof_string(), "test");
}
TEST_F(NoFieldPresenceSwapFieldTest, ReflectionSwapFieldOneofDefaultTest) {
m1_.set_oneof_uint32(1);
const FieldDescriptor* f = FindFieldByName("oneof_uint32");
r1_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_FALSE(r1_->HasField(m1_, d1_->FindFieldByName("oneof_string")));
EXPECT_TRUE(r2_->HasField(m2_, f));
EXPECT_FALSE(m1_.has_oneof_string());
EXPECT_EQ(m2_.oneof_uint32(), 1);
// It doesn't matter which reflection or descriptor gets used; swapping should
// still work if m2_'s descriptor is provided.
r2_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_TRUE(r1_->HasField(m1_, f));
EXPECT_FALSE(r2_->HasField(m2_, d2_->FindFieldByName("oneof_string")));
EXPECT_EQ(m1_.oneof_uint32(), 1);
EXPECT_FALSE(m2_.has_oneof_string());
}
TEST_F(NoFieldPresenceSwapFieldTest, ReflectionSwapFieldOneofExplicitZeroTest) {
// Oneof fields essentially have explicit presence -- if set to zero, they
// will still be considered present.
m1_.set_oneof_uint32(0);
const FieldDescriptor* f = FindFieldByName("oneof_uint32");
r1_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_FALSE(r1_->HasField(m1_, f));
EXPECT_TRUE(r2_->HasField(m2_, f));
EXPECT_FALSE(m1_.has_oneof_uint32());
EXPECT_TRUE(m2_.has_oneof_uint32());
EXPECT_EQ(m2_.oneof_uint32(), 0);
// It doesn't matter which reflection or descriptor gets used; swapping should
// still work if m2_'s descriptor is provided.
r2_->SwapFields(&m1_, &m2_, /*fields=*/{f});
// Fields should be swapped.
EXPECT_TRUE(r1_->HasField(m1_, f));
EXPECT_FALSE(r2_->HasField(m2_, f));
EXPECT_TRUE(m1_.has_oneof_uint32());
EXPECT_EQ(m1_.oneof_uint32(), 0);
EXPECT_FALSE(m2_.has_oneof_uint32());
}
class NoFieldPresenceListFieldsTest : public testing::Test {
protected:
NoFieldPresenceListFieldsTest()

Loading…
Cancel
Save