Kaynağa Gözat

Fix initialization check when an optional field has required subfields

Jon Skeet 17 yıl önce
ebeveyn
işleme
881db010cb

+ 16 - 0
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);
+    }
   }
 }

+ 300 - 5
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<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize, global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.Builder> internal__static_protobuf_unittest_TestOptimizedForSize__FieldAccessorTable
         = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize, global::Google.ProtocolBuffers.TestProtos.TestOptimizedForSize.Builder>(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<global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize, global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.Builder> internal__static_protobuf_unittest_TestRequiredOptimizedForSize__FieldAccessorTable
+        = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize, global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize.Builder>(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<global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize, global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize.Builder> internal__static_protobuf_unittest_TestOptionalOptimizedForSize__FieldAccessorTable
+        = new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize, global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize.Builder>(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<TestRequiredOptimizedForSize, TestRequiredOptimizedForSize.Builder> {
+    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<TestRequiredOptimizedForSize, TestRequiredOptimizedForSize.Builder> 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<global::Google.ProtocolBuffers.TestProtos.TestRequiredOptimizedForSize, Builder> {
+      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<TestOptionalOptimizedForSize, TestOptionalOptimizedForSize.Builder> {
+    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<TestOptionalOptimizedForSize, TestOptionalOptimizedForSize.Builder> 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<global::Google.ProtocolBuffers.TestProtos.TestOptionalOptimizedForSize, Builder> {
+      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

+ 1 - 1
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;
               }
             }

+ 1 - 1
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;
           }
         }

+ 27 - 10
java/src/test/java/com/google/protobuf/GeneratedMessageTest.java

@@ -16,19 +16,21 @@
 
 package com.google.protobuf;
 
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+import protobuf_unittest.EnumWithNoOuter;
+import protobuf_unittest.MessageWithNoOuter;
+import protobuf_unittest.MultipleFilesTestProto;
+import protobuf_unittest.ServiceWithNoOuter;
 import protobuf_unittest.UnittestProto;
-import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestOptimizeFor.TestOptionalOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
 import protobuf_unittest.UnittestProto.ForeignEnum;
-import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.ForeignMessage;
 import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
-import protobuf_unittest.MultipleFilesTestProto;
-import protobuf_unittest.MessageWithNoOuter;
-import protobuf_unittest.EnumWithNoOuter;
-import protobuf_unittest.ServiceWithNoOuter;
-
-import junit.framework.TestCase;
-import java.util.Arrays;
 
 /**
  * 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());
+   }
 }

+ 8 - 0
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;
+}