From 881db010cbe1126bf85258c1c19b2b805bfa68f7 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Thu, 4 Sep 2008 14:43:17 +0100 Subject: [PATCH] Fix initialization check when an optional field has required subfields --- .../GeneratedMessageTest.cs | 16 + .../UnitTestOptimizeForProtoFile.cs | 305 +++++++++++++++++- csharp/ProtocolBuffers/GeneratedMessage.cs | 2 +- .../com/google/protobuf/GeneratedMessage.java | 2 +- .../google/protobuf/GeneratedMessageTest.java | 41 ++- .../protobuf/unittest_optimize_for.proto | 8 + 6 files changed, 355 insertions(+), 19 deletions(-) diff --git a/csharp/ProtocolBuffers.Test/GeneratedMessageTest.cs b/csharp/ProtocolBuffers.Test/GeneratedMessageTest.cs index f51f9755..c820b582 100644 --- a/csharp/ProtocolBuffers.Test/GeneratedMessageTest.cs +++ b/csharp/ProtocolBuffers.Test/GeneratedMessageTest.cs @@ -270,5 +270,21 @@ namespace Google.ProtocolBuffers { Assert.IsFalse(TestAllExtensions.DefaultInstance.HasExtension(MultiFileProto.ExtensionWithOuter)); } + + [Test] + public void OptionalFieldWithRequiredSubfieldsOptimizedForSize() { + TestOptionalOptimizedForSize message = TestOptionalOptimizedForSize.DefaultInstance; + Assert.IsTrue(message.IsInitialized); + + message = TestOptionalOptimizedForSize.CreateBuilder().SetO( + TestRequiredOptimizedForSize.CreateBuilder().BuildPartial() + ).BuildPartial(); + Assert.IsFalse(message.IsInitialized); + + message = TestOptionalOptimizedForSize.CreateBuilder().SetO( + TestRequiredOptimizedForSize.CreateBuilder().SetX(5).BuildPartial() + ).BuildPartial(); + Assert.IsTrue(message.IsInitialized); + } } } diff --git a/csharp/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs b/csharp/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs index de07d033..260be712 100644 --- a/csharp/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs +++ b/csharp/ProtocolBuffers.Test/TestProtos/UnitTestOptimizeForProtoFile.cs @@ -26,11 +26,18 @@ namespace Google.ProtocolBuffers.TestProtos { 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x02, 0x32, 0x40, 0x0a, 0x0e, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, - 0x7a, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x18, 0xd2, 0x09, 0x20, 0x01, 0x28, 0x05, 0x42, 0x45, 0x48, - 0x02, 0xc2, 0x3e, 0x21, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x42, - 0x75, 0x66, 0x66, 0x65, 0x72, 0x73, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0xca, 0x3e, 0x1c, - 0x55, 0x6e, 0x69, 0x74, 0x54, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x46, 0x6f, 0x72, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x46, 0x69, 0x6c, 0x65, + 0x7a, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x18, 0xd2, 0x09, 0x20, 0x01, 0x28, 0x05, 0x22, 0x29, 0x0a, + 0x1c, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, + 0x65, 0x64, 0x46, 0x6f, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x09, 0x0a, 0x01, 0x78, 0x18, 0x01, 0x20, 0x02, 0x28, 0x05, + 0x22, 0x5a, 0x0a, 0x1c, 0x54, 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4f, 0x70, 0x74, 0x69, + 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x3a, 0x0a, 0x01, 0x6f, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x5f, 0x75, 0x6e, 0x69, 0x74, 0x74, + 0x65, 0x73, 0x74, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, + 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x46, 0x6f, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x45, 0x48, 0x02, 0xc2, 0x3e, 0x21, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, + 0x73, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0xca, 0x3e, 0x1c, 0x55, 0x6e, 0x69, 0x74, 0x54, + 0x65, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x46, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x46, + 0x69, 0x6c, 0x65, }, new pbd::FileDescriptor[] { global::Google.ProtocolBuffers.TestProtos.UnitTestProtoFile.Descriptor, }); @@ -45,6 +52,16 @@ namespace Google.ProtocolBuffers.TestProtos { internal static pb::FieldAccess.FieldAccessorTable internal__static_protobuf_unittest_TestOptimizedForSize__FieldAccessorTable = new pb::FieldAccess.FieldAccessorTable(internal__static_protobuf_unittest_TestOptimizedForSize__Descriptor, new string[] { "I", "Msg", }); + internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_TestRequiredOptimizedForSize__Descriptor + = Descriptor.MessageTypes[1]; + internal static pb::FieldAccess.FieldAccessorTable internal__static_protobuf_unittest_TestRequiredOptimizedForSize__FieldAccessorTable + = new pb::FieldAccess.FieldAccessorTable(internal__static_protobuf_unittest_TestRequiredOptimizedForSize__Descriptor, + new string[] { "X", }); + internal static readonly pbd::MessageDescriptor internal__static_protobuf_unittest_TestOptionalOptimizedForSize__Descriptor + = Descriptor.MessageTypes[2]; + internal static pb::FieldAccess.FieldAccessorTable internal__static_protobuf_unittest_TestOptionalOptimizedForSize__FieldAccessorTable + = new pb::FieldAccess.FieldAccessorTable(internal__static_protobuf_unittest_TestOptionalOptimizedForSize__Descriptor, + new string[] { "O", }); #endregion } @@ -236,6 +253,284 @@ namespace Google.ProtocolBuffers.TestProtos { } } + public sealed partial class TestRequiredOptimizedForSize : pb::GeneratedMessage { + private static readonly TestRequiredOptimizedForSize defaultInstance = new Builder().BuildPartial(); + public static TestRequiredOptimizedForSize DefaultInstance { + get { return defaultInstance; } + } + + public override TestRequiredOptimizedForSize DefaultInstanceForType { + get { return defaultInstance; } + } + + protected override TestRequiredOptimizedForSize ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::Google.ProtocolBuffers.TestProtos.UnitTestOptimizeForProtoFile.internal__static_protobuf_unittest_TestRequiredOptimizedForSize__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { + get { return global::Google.ProtocolBuffers.TestProtos.UnitTestOptimizeForProtoFile.internal__static_protobuf_unittest_TestRequiredOptimizedForSize__FieldAccessorTable; } + } + + // required int32 x = 1; + private bool hasX; + private int x_ = 0; + public bool HasX { + get { return hasX; } + } + public int X { + get { return x_; } + } + + public static global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize ParseFrom(pb::ByteString data, + pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) + .BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize ParseFrom(byte[] data, + pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) + .BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize ParseFrom( + global::System.IO.Stream input, + pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)) + .BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize ParseFrom(pb::CodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize ParseFrom(pb::CodedInputStream input, + pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)) + .BuildParsed(); + } + + public static Builder CreateBuilder() { return new Builder(); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize prototype) { + return (Builder) new Builder().MergeFrom(prototype); + } + + public sealed partial class Builder : pb::GeneratedBuilder { + protected override Builder ThisBuilder { + get { return this; } + } + + // Construct using global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.CreateBuilder() + public Builder() {} + + global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize result = new global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize(); + + protected override global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize MessageBeingBuilt { + get { return result; } + } + + public override Builder Clear() { + result = new global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize(); + return this; + } + + public override Builder Clone() { + return new Builder().MergeFrom(result); + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.Descriptor; } + } + + public override global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize DefaultInstanceForType { + get { return global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.DefaultInstance; } + } + + public override global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize BuildPartial() { + global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize returnMe = result; + result = null; + return returnMe; + } + + + // required int32 x = 1; + public bool HasX { + get { return result.HasX; } + } + public int X { + get { return result.X; } + set { SetX(value); } + } + public Builder SetX(int value) { + result.hasX = true; + result.x_ = value; + return this; + } + public Builder ClearX() { + result.hasX = false; + result.x_ = 0; + return this; + } + } + } + + public sealed partial class TestOptionalOptimizedForSize : pb::GeneratedMessage { + private static readonly TestOptionalOptimizedForSize defaultInstance = new Builder().BuildPartial(); + public static TestOptionalOptimizedForSize DefaultInstance { + get { return defaultInstance; } + } + + public override TestOptionalOptimizedForSize DefaultInstanceForType { + get { return defaultInstance; } + } + + protected override TestOptionalOptimizedForSize ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::Google.ProtocolBuffers.TestProtos.UnitTestOptimizeForProtoFile.internal__static_protobuf_unittest_TestOptionalOptimizedForSize__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { + get { return global::Google.ProtocolBuffers.TestProtos.UnitTestOptimizeForProtoFile.internal__static_protobuf_unittest_TestOptionalOptimizedForSize__FieldAccessorTable; } + } + + // optional .protobuf_unittest.TestRequiredOptimizedForSize o = 1; + private bool hasO; + private global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize o_ = global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.DefaultInstance; + public bool HasO { + get { return hasO; } + } + public global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize O { + get { return o_; } + } + + public static global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize ParseFrom(pb::ByteString data, + pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) + .BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize ParseFrom(byte[] data, + pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)) + .BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize ParseFrom( + global::System.IO.Stream input, + pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)) + .BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize ParseFrom(pb::CodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize ParseFrom(pb::CodedInputStream input, + pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)) + .BuildParsed(); + } + + public static Builder CreateBuilder() { return new Builder(); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize prototype) { + return (Builder) new Builder().MergeFrom(prototype); + } + + public sealed partial class Builder : pb::GeneratedBuilder { + protected override Builder ThisBuilder { + get { return this; } + } + + // Construct using global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize.CreateBuilder() + public Builder() {} + + global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize result = new global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize(); + + protected override global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize MessageBeingBuilt { + get { return result; } + } + + public override Builder Clear() { + result = new global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize(); + return this; + } + + public override Builder Clone() { + return new Builder().MergeFrom(result); + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize.Descriptor; } + } + + public override global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize DefaultInstanceForType { + get { return global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize.DefaultInstance; } + } + + public override global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize BuildPartial() { + global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize returnMe = result; + result = null; + return returnMe; + } + + + // optional .protobuf_unittest.TestRequiredOptimizedForSize o = 1; + public bool HasO { + get { return result.HasO; } + } + public global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize O { + get { return result.O; } + set { SetO(value); } + } + public Builder SetO(global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize value) { + result.hasO = true; + result.o_ = value; + return this; + } + public Builder SetO(global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.Builder builderForValue) { + result.hasO = true; + result.o_ = builderForValue.Build(); + return this; + } + public Builder MergeO(global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize value) { + if (result.HasO && + result.o_ != global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.DefaultInstance) { + result.o_ = + global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.CreateBuilder(result.o_).MergeFrom(value).BuildPartial(); + } else { + result.o_ = value; + } + result.hasO = true; + return this; + } + public Builder ClearO() { + result.hasO = false; + result.o_ = global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.DefaultInstance; + return this; + } + } + } + #endregion #region Services diff --git a/csharp/ProtocolBuffers/GeneratedMessage.cs b/csharp/ProtocolBuffers/GeneratedMessage.cs index 47722d0b..7801d521 100644 --- a/csharp/ProtocolBuffers/GeneratedMessage.cs +++ b/csharp/ProtocolBuffers/GeneratedMessage.cs @@ -92,7 +92,7 @@ namespace Google.ProtocolBuffers { } } } else { - if (!((IMessage) this[field]).IsInitialized) { + if (HasField(field) && !((IMessage) this[field]).IsInitialized) { return false; } } diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java index d4b7dab8..91fa74c9 100644 --- a/java/src/main/java/com/google/protobuf/GeneratedMessage.java +++ b/java/src/main/java/com/google/protobuf/GeneratedMessage.java @@ -94,7 +94,7 @@ public abstract class GeneratedMessage extends AbstractMessage { } } } else { - if (!((Message) getField(field)).isInitialized()) { + if (hasField(field) && !((Message) getField(field)).isInitialized()) { return false; } } diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java index 30d73d28..a2c009ef 100644 --- a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java @@ -16,19 +16,21 @@ package com.google.protobuf; -import protobuf_unittest.UnittestProto; -import protobuf_unittest.UnittestProto.ForeignMessage; -import protobuf_unittest.UnittestProto.ForeignEnum; -import protobuf_unittest.UnittestProto.TestAllTypes; -import protobuf_unittest.UnittestProto.TestAllExtensions; -import protobuf_unittest.UnittestProto.TestExtremeDefaultValues; -import protobuf_unittest.MultipleFilesTestProto; -import protobuf_unittest.MessageWithNoOuter; -import protobuf_unittest.EnumWithNoOuter; -import protobuf_unittest.ServiceWithNoOuter; +import java.util.Arrays; import junit.framework.TestCase; -import java.util.Arrays; +import protobuf_unittest.EnumWithNoOuter; +import protobuf_unittest.MessageWithNoOuter; +import protobuf_unittest.MultipleFilesTestProto; +import protobuf_unittest.ServiceWithNoOuter; +import protobuf_unittest.UnittestProto; +import protobuf_unittest.UnittestOptimizeFor.TestOptionalOptimizedForSize; +import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize; +import protobuf_unittest.UnittestProto.ForeignEnum; +import protobuf_unittest.UnittestProto.ForeignMessage; +import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestAllTypes; +import protobuf_unittest.UnittestProto.TestExtremeDefaultValues; /** * Unit test for generated messages and generated code. See also @@ -93,7 +95,7 @@ public class GeneratedMessageTest extends TestCase { // TODO(ngd): Upgrade to using real #equals method once implemented assertEquals(expectedMessage.toString(), message.toString()); } - + public void testSettingRepeatedForeignMessageUsingBuilder() throws Exception { TestAllTypes message = TestAllTypes.newBuilder() // Pass builder for foreign message instance. @@ -243,4 +245,19 @@ public class GeneratedMessageTest extends TestCase { TestAllExtensions.getDefaultInstance().hasExtension( MultipleFilesTestProto.extensionWithOuter)); } + + public void testOptionalFieldWithRequiredSubfieldsOptimizedForSize() throws Exception { + TestOptionalOptimizedForSize message = TestOptionalOptimizedForSize.getDefaultInstance(); + assertTrue(message.isInitialized()); + + message = TestOptionalOptimizedForSize.newBuilder().setO( + TestRequiredOptimizedForSize.newBuilder().buildPartial() + ).buildPartial(); + assertFalse(message.isInitialized()); + + message = TestOptionalOptimizedForSize.newBuilder().setO( + TestRequiredOptimizedForSize.newBuilder().setX(5).buildPartial() + ).buildPartial(); + assertTrue(message.isInitialized()); + } } diff --git a/src/google/protobuf/unittest_optimize_for.proto b/src/google/protobuf/unittest_optimize_for.proto index 660eeda8..cccfe233 100644 --- a/src/google/protobuf/unittest_optimize_for.proto +++ b/src/google/protobuf/unittest_optimize_for.proto @@ -39,3 +39,11 @@ message TestOptimizedForSize { optional int32 test_extension = 1234; } } + +message TestRequiredOptimizedForSize { + required int32 x = 1; +} + +message TestOptionalOptimizedForSize { + optional TestRequiredOptimizedForSize o = 1; +}