diff --git a/java/core/generate-test-sources-build.xml b/java/core/generate-test-sources-build.xml index 92c0b1c8ae..71a88d07b3 100644 --- a/java/core/generate-test-sources-build.xml +++ b/java/core/generate-test-sources-build.xml @@ -17,6 +17,7 @@ + diff --git a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java index 53ec6fe68c..a1c98c0cef 100644 --- a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java +++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java @@ -38,6 +38,7 @@ import com.google.protobuf.Descriptors.OneofDescriptor; import com.google.protobuf.FieldPresenceTestProto.TestAllTypes; import com.google.protobuf.FieldPresenceTestProto.TestOptionalFieldsOnly; import com.google.protobuf.FieldPresenceTestProto.TestRepeatedFieldsOnly; +import com.google.protobuf.testing.proto.TestProto3Optional; import protobuf_unittest.UnittestProto; import junit.framework.TestCase; @@ -101,6 +102,113 @@ public class FieldPresenceTest extends TestCase { UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, "OneofBytes"); } + public void testHasMethodForProto3Optional() throws Exception { + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalInt32()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalInt64()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalUint32()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalUint64()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalSint32()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalSint64()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalFixed32()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalFixed64()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalFloat()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalDouble()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalBool()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalString()); + assertFalse(TestProto3Optional.getDefaultInstance().hasOptionalBytes()); + + TestProto3Optional.Builder builder = TestProto3Optional.newBuilder().setOptionalInt32(0); + assertTrue(builder.hasOptionalInt32()); + assertTrue(builder.build().hasOptionalInt32()); + + TestProto3Optional.Builder otherBuilder = TestProto3Optional.newBuilder().setOptionalInt32(1); + otherBuilder.mergeFrom(builder.build()); + assertTrue(otherBuilder.hasOptionalInt32()); + assertEquals(0, otherBuilder.getOptionalInt32()); + + TestProto3Optional.Builder builder3 = + TestProto3Optional.newBuilder().setOptionalNestedEnumValue(5); + assertTrue(builder3.hasOptionalNestedEnum()); + + TestProto3Optional.Builder builder4 = + TestProto3Optional.newBuilder().setOptionalNestedEnum(TestProto3Optional.NestedEnum.FOO); + assertTrue(builder4.hasOptionalNestedEnum()); + + TestProto3Optional proto = TestProto3Optional.parseFrom(builder.build().toByteArray()); + assertTrue(proto.hasOptionalInt32()); + assertTrue(proto.toBuilder().hasOptionalInt32()); + } + + private static void assertProto3OptionalReflection(String name) throws Exception { + FieldDescriptor fieldDescriptor = TestProto3Optional.getDescriptor().findFieldByName(name); + OneofDescriptor oneofDescriptor = fieldDescriptor.getContainingOneof(); + assertNotNull(fieldDescriptor.getContainingOneof()); + assertTrue(fieldDescriptor.hasOptionalKeyword()); + assertTrue(fieldDescriptor.hasPresence()); + + assertFalse(TestProto3Optional.getDefaultInstance().hasOneof(oneofDescriptor)); + assertNull(TestProto3Optional.getDefaultInstance().getOneofFieldDescriptor(oneofDescriptor)); + + TestProto3Optional.Builder builder = TestProto3Optional.newBuilder(); + builder.setField(fieldDescriptor, fieldDescriptor.getDefaultValue()); + assertTrue(builder.hasField(fieldDescriptor)); + assertEquals(fieldDescriptor.getDefaultValue(), builder.getField(fieldDescriptor)); + assertTrue(builder.build().hasField(fieldDescriptor)); + assertEquals(fieldDescriptor.getDefaultValue(), builder.build().getField(fieldDescriptor)); + assertTrue(builder.hasOneof(oneofDescriptor)); + assertEquals(fieldDescriptor, builder.getOneofFieldDescriptor(oneofDescriptor)); + assertTrue(builder.build().hasOneof(oneofDescriptor)); + assertEquals(fieldDescriptor, builder.build().getOneofFieldDescriptor(oneofDescriptor)); + + TestProto3Optional.Builder otherBuilder = TestProto3Optional.newBuilder(); + otherBuilder.mergeFrom(builder.build()); + assertTrue(otherBuilder.hasField(fieldDescriptor)); + assertEquals(fieldDescriptor.getDefaultValue(), otherBuilder.getField(fieldDescriptor)); + + TestProto3Optional proto = TestProto3Optional.parseFrom(builder.build().toByteArray()); + assertTrue(proto.hasField(fieldDescriptor)); + assertTrue(proto.toBuilder().hasField(fieldDescriptor)); + + DynamicMessage.Builder dynamicBuilder = + DynamicMessage.newBuilder(TestProto3Optional.getDescriptor()); + dynamicBuilder.setField(fieldDescriptor, fieldDescriptor.getDefaultValue()); + assertTrue(dynamicBuilder.hasField(fieldDescriptor)); + assertEquals(fieldDescriptor.getDefaultValue(), dynamicBuilder.getField(fieldDescriptor)); + assertTrue(dynamicBuilder.build().hasField(fieldDescriptor)); + assertEquals( + fieldDescriptor.getDefaultValue(), dynamicBuilder.build().getField(fieldDescriptor)); + assertTrue(dynamicBuilder.hasOneof(oneofDescriptor)); + assertEquals(fieldDescriptor, dynamicBuilder.getOneofFieldDescriptor(oneofDescriptor)); + assertTrue(dynamicBuilder.build().hasOneof(oneofDescriptor)); + assertEquals(fieldDescriptor, dynamicBuilder.build().getOneofFieldDescriptor(oneofDescriptor)); + + DynamicMessage.Builder otherDynamicBuilder = + DynamicMessage.newBuilder(TestProto3Optional.getDescriptor()); + otherDynamicBuilder.mergeFrom(dynamicBuilder.build()); + assertTrue(otherDynamicBuilder.hasField(fieldDescriptor)); + assertEquals(fieldDescriptor.getDefaultValue(), otherDynamicBuilder.getField(fieldDescriptor)); + + DynamicMessage dynamicProto = + DynamicMessage.parseFrom(TestProto3Optional.getDescriptor(), builder.build().toByteArray()); + assertTrue(dynamicProto.hasField(fieldDescriptor)); + assertTrue(dynamicProto.toBuilder().hasField(fieldDescriptor)); + } + + public void testProto3Optional_reflection() throws Exception { + assertProto3OptionalReflection("optional_int32"); + assertProto3OptionalReflection("optional_int64"); + assertProto3OptionalReflection("optional_uint32"); + assertProto3OptionalReflection("optional_uint64"); + assertProto3OptionalReflection("optional_sint32"); + assertProto3OptionalReflection("optional_sint64"); + assertProto3OptionalReflection("optional_fixed32"); + assertProto3OptionalReflection("optional_fixed64"); + assertProto3OptionalReflection("optional_float"); + assertProto3OptionalReflection("optional_double"); + assertProto3OptionalReflection("optional_bool"); + assertProto3OptionalReflection("optional_string"); + assertProto3OptionalReflection("optional_bytes"); + } public void testOneofEquals() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java index 50ba0168da..6ca3ae111f 100644 --- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java @@ -40,6 +40,8 @@ import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy; +import com.google.protobuf.testing.proto.TestProto3Optional; +import com.google.protobuf.testing.proto.TestProto3Optional.NestedEnum; import any_test.AnyTestProto.TestAny; import map_test.MapTestProto.TestMap; import protobuf_unittest.UnittestMset.TestMessageSetExtension1; @@ -319,6 +321,24 @@ public class TextFormatTest extends TestCase { assertEquals(canonicalExoticText, message.toString()); } + public void testRoundtripProto3Optional() throws Exception { + Message message = + TestProto3Optional.newBuilder() + .setOptionalInt32(1) + .setOptionalInt64(2) + .setOptionalNestedEnum(NestedEnum.BAZ) + .build(); + TestProto3Optional.Builder message2 = TestProto3Optional.newBuilder(); + TextFormat.merge(message.toString(), message2); + + assertTrue(message2.hasOptionalInt32()); + assertTrue(message2.hasOptionalInt64()); + assertTrue(message2.hasOptionalNestedEnum()); + assertEquals(1, message2.getOptionalInt32()); + assertEquals(2, message2.getOptionalInt64()); + assertEquals(NestedEnum.BAZ, message2.getOptionalNestedEnum()); + } + public void testPrintMessageSet() throws Exception { TestMessageSet messageSet = TestMessageSet.newBuilder() diff --git a/java/lite/generate-test-sources-build.xml b/java/lite/generate-test-sources-build.xml index 1c1a18c544..62bca93c86 100644 --- a/java/lite/generate-test-sources-build.xml +++ b/java/lite/generate-test-sources-build.xml @@ -15,6 +15,7 @@ + diff --git a/python/google/protobuf/internal/test_proto3_optional.proto b/python/google/protobuf/internal/test_proto3_optional.proto index a5abd19d13..f3e0a2e761 100644 --- a/python/google/protobuf/internal/test_proto3_optional.proto +++ b/python/google/protobuf/internal/test_proto3_optional.proto @@ -30,10 +30,7 @@ syntax = "proto3"; -package protobuf_unittest; - -option java_multiple_files = true; -option java_package = "com.google.protobuf.testing.proto"; +package google.protobuf.python.internal; message TestProto3Optional { message NestedMessage { diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index 6322ee566e..32cff15fec 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -225,6 +225,7 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers( printer->Print(variables_, "$deprecation$public Builder " "${$set$capitalized_name$Value$}$(int value) {\n" + " $set_has_field_bit_builder$\n" " $name$_ = value;\n" " $on_changed$\n" " return this;\n"