content: // Protocol Buffers - Google's data interchange format
  // Copyright 2008 Google Inc.  All rights reserved.
  // https://developers.google.com/protocol-buffers/
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
  //
  //     * Redistributions of source code must retain the above copyright
  // notice, this list of conditions and the following disclaimer.
  //     * Redistributions in binary form must reproduce the above
  // copyright notice, this list of conditions and the following disclaimer
  // in the documentation and/or other materials provided with the
  // distribution.
  //     * Neither the name of Google Inc. nor the names of its
  // contributors may be used to endorse or promote products derived from
  // this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  package com.google.protobuf;
  
  import com.google.protobuf.Descriptors.Descriptor;
  import com.google.protobuf.Descriptors.EnumDescriptor;
  import com.google.protobuf.Descriptors.EnumValueDescriptor;
  import com.google.protobuf.Descriptors.FieldDescriptor;
  import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
  import com.google.protobuf.FieldPresenceTestProto.TestOptionalFieldsOnly;
  import com.google.protobuf.FieldPresenceTestProto.TestRepeatedFieldsOnly;
  import protobuf_unittest.UnittestProto;
  
  import junit.framework.TestCase;
  
  /**
   * Unit tests for protos that doesn't support field presence test for optional
   * non-message fields.
   */
  public class FieldPresenceTest extends TestCase {
    private static boolean hasMethod(Class<?> clazz, String name) {
      try {
        if (clazz.getMethod(name) != null) {
          return true;
        } else {
          return false;
        }
      } catch (NoSuchMethodException e) {
        return false;
      }
    }
  
    private static void assertHasMethodRemoved(
        Class<?> classWithFieldPresence,
        Class<?> classWithoutFieldPresence,
        String camelName) {
      assertTrue(hasMethod(classWithFieldPresence, "get" + camelName));
      assertTrue(hasMethod(classWithFieldPresence, "has" + camelName));
      assertTrue(hasMethod(classWithoutFieldPresence, "get" + camelName));
      assertFalse(hasMethod(classWithoutFieldPresence, "has" + camelName));
    }
  
    public void testHasMethod() {
      // Optional non-message fields don't have a hasFoo() method generated.
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.class,
          TestAllTypes.class,
          "OptionalInt32");
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.class,
          TestAllTypes.class,
          "OptionalString");
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.class,
          TestAllTypes.class,
          "OptionalBytes");
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.class,
          TestAllTypes.class,
          "OptionalNestedEnum");
  
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.Builder.class,
          TestAllTypes.Builder.class,
          "OptionalInt32");
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.Builder.class,
          TestAllTypes.Builder.class,
          "OptionalString");
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.Builder.class,
          TestAllTypes.Builder.class,
          "OptionalBytes");
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.Builder.class,
          TestAllTypes.Builder.class,
          "OptionalNestedEnum");
  
      // message fields still have the hasFoo() method generated.
      assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage());
      assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage());
  
      // oneof fields don't have hasFoo() methods for non-message types.
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.class,
          TestAllTypes.class,
          "OneofUint32");
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.class,
          TestAllTypes.class,
          "OneofString");
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.class,
          TestAllTypes.class,
          "OneofBytes");
      assertFalse(TestAllTypes.newBuilder().build().hasOneofNestedMessage());
      assertFalse(TestAllTypes.newBuilder().hasOneofNestedMessage());
  
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.Builder.class,
          TestAllTypes.Builder.class,
          "OneofUint32");
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.Builder.class,
          TestAllTypes.Builder.class,
          "OneofString");
      assertHasMethodRemoved(
          UnittestProto.TestAllTypes.Builder.class,
          TestAllTypes.Builder.class,
          "OneofBytes");
    }
  
    public void testOneofEquals() throws Exception {
      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
      TestAllTypes message1 = builder.build();
      // Set message2's oneof_uint32 field to defalut value. The two
      // messages should be different when check with oneof case.
      builder.setOneofUint32(0);
      TestAllTypes message2 = builder.build();
      assertFalse(message1.equals(message2));
    }
  
    public void testLazyField() throws Exception {
      // Test default constructed message.
      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
      TestAllTypes message = builder.build();
      assertFalse(message.hasOptionalLazyMessage());
      assertEquals(0, message.getSerializedSize());
      assertEquals(ByteString.EMPTY, message.toByteString());
  
      // Set default instance to the field.
      builder.setOptionalLazyMessage(TestAllTypes.NestedMessage.getDefaultInstance());
      message = builder.build();
      assertTrue(message.hasOptionalLazyMessage());
      assertEquals(2, message.getSerializedSize());
  
      // Test parse zero-length from wire sets the presence.
      TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteString());
      assertTrue(parsed.hasOptionalLazyMessage());
      assertEquals(message.getOptionalLazyMessage(), parsed.getOptionalLazyMessage());
    }
  
    public void testFieldPresence() {
      // Optional non-message fields set to their default value are treated the
      // same way as not set.
  
      // Serialization will ignore such fields.
      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
      builder.setOptionalInt32(0);
      builder.setOptionalString("");
      builder.setOptionalBytes(ByteString.EMPTY);
      builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO);
      TestAllTypes message = builder.build();
      assertEquals(0, message.getSerializedSize());
  
      // mergeFrom() will ignore such fields.
      TestAllTypes.Builder a = TestAllTypes.newBuilder();
      a.setOptionalInt32(1);
      a.setOptionalString("x");
      a.setOptionalBytes(ByteString.copyFromUtf8("y"));
      a.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR);
      TestAllTypes.Builder b = TestAllTypes.newBuilder();
      b.setOptionalInt32(0);
      b.setOptionalString("");
      b.setOptionalBytes(ByteString.EMPTY);
      b.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO);
      a.mergeFrom(b.build());
      message = a.build();
      assertEquals(1, message.getOptionalInt32());
      assertEquals("x", message.getOptionalString());
      assertEquals(ByteString.copyFromUtf8("y"), message.getOptionalBytes());
      assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum());
  
      // equals()/hashCode() should produce the same results.
      TestAllTypes empty = TestAllTypes.newBuilder().build();
      message = builder.build();
      assertTrue(empty.equals(message));
      assertTrue(message.equals(empty));
      assertEquals(empty.hashCode(), message.hashCode());
    }
  
    public void testFieldPresenceByReflection() {
      Descriptor descriptor = TestAllTypes.getDescriptor();
      FieldDescriptor optionalInt32Field = descriptor.findFieldByName("optional_int32");
      FieldDescriptor optionalStringField = descriptor.findFieldByName("optional_string");
      FieldDescriptor optionalBytesField = descriptor.findFieldByName("optional_bytes");
      FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
  
      // Field not present.
      TestAllTypes message = TestAllTypes.newBuilder().build();
      assertFalse(message.hasField(optionalInt32Field));
      assertFalse(message.hasField(optionalStringField));
      assertFalse(message.hasField(optionalBytesField));
      assertFalse(message.hasField(optionalNestedEnumField));
      assertEquals(0, message.getAllFields().size());
  
      // Field set to default value is seen as not present.
      message = TestAllTypes.newBuilder()
          .setOptionalInt32(0)
          .setOptionalString("")
          .setOptionalBytes(ByteString.EMPTY)
          .setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO)
          .build();
      assertFalse(message.hasField(optionalInt32Field));
      assertFalse(message.hasField(optionalStringField));
      assertFalse(message.hasField(optionalBytesField));
      assertFalse(message.hasField(optionalNestedEnumField));
      assertEquals(0, message.getAllFields().size());
  
      // Field set to non-default value is seen as present.
      message = TestAllTypes.newBuilder()
          .setOptionalInt32(1)
          .setOptionalString("x")
          .setOptionalBytes(ByteString.copyFromUtf8("y"))
          .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR)
          .build();
      assertTrue(message.hasField(optionalInt32Field));
      assertTrue(message.hasField(optionalStringField));
      assertTrue(message.hasField(optionalBytesField));
      assertTrue(message.hasField(optionalNestedEnumField));
      assertEquals(4, message.getAllFields().size());
    }
  
    public void testFieldPresenceDynamicMessage() {
      Descriptor descriptor = TestAllTypes.getDescriptor();
      FieldDescriptor optionalInt32Field = descriptor.findFieldByName("optional_int32");
      FieldDescriptor optionalStringField = descriptor.findFieldByName("optional_string");
      FieldDescriptor optionalBytesField = descriptor.findFieldByName("optional_bytes");
      FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
      EnumDescriptor enumDescriptor = optionalNestedEnumField.getEnumType();
      EnumValueDescriptor defaultEnumValueDescriptor = enumDescriptor.getValues().get(0);
      EnumValueDescriptor nonDefaultEnumValueDescriptor = enumDescriptor.getValues().get(1);
  
      DynamicMessage defaultInstance = DynamicMessage.getDefaultInstance(descriptor);
      // Field not present.
      DynamicMessage message = defaultInstance.newBuilderForType().build();
      assertFalse(message.hasField(optionalInt32Field));
      assertFalse(message.hasField(optionalStringField));
      assertFalse(message.hasField(optionalBytesField));
      assertFalse(message.hasField(optionalNestedEnumField));
      assertEquals(0, message.getAllFields().size());
  
      // Field set to non-default value is seen as present.
      message =
          defaultInstance
              .newBuilderForType()
              .setField(optionalInt32Field, 1)
              .setField(optionalStringField, "x")
              .setField(optionalBytesField, ByteString.copyFromUtf8("y"))
              .setField(optionalNestedEnumField, nonDefaultEnumValueDescriptor)
              .build();
      assertTrue(message.hasField(optionalInt32Field));
      assertTrue(message.hasField(optionalStringField));
      assertTrue(message.hasField(optionalBytesField));
      assertTrue(message.hasField(optionalNestedEnumField));
      assertEquals(4, message.getAllFields().size());
  
      // Field set to default value is seen as not present.
      message = message.toBuilder()
              .setField(optionalInt32Field, 0)
              .setField(optionalStringField, "")
              .setField(optionalBytesField, ByteString.EMPTY)
              .setField(optionalNestedEnumField, defaultEnumValueDescriptor)
              .build();
      assertFalse(message.hasField(optionalInt32Field));
      assertFalse(message.hasField(optionalStringField));
      assertFalse(message.hasField(optionalBytesField));
      assertFalse(message.hasField(optionalNestedEnumField));
      assertEquals(0, message.getAllFields().size());
    }
  
    public void testMessageField() {
      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
      assertFalse(builder.hasOptionalNestedMessage());
      assertFalse(builder.build().hasOptionalNestedMessage());
  
      TestAllTypes.NestedMessage.Builder nestedBuilder =
          builder.getOptionalNestedMessageBuilder();
      assertTrue(builder.hasOptionalNestedMessage());
      assertTrue(builder.build().hasOptionalNestedMessage());
  
      nestedBuilder.setValue(1);
      assertEquals(1, builder.build().getOptionalNestedMessage().getValue());
  
      builder.clearOptionalNestedMessage();
      assertFalse(builder.hasOptionalNestedMessage());
      assertFalse(builder.build().hasOptionalNestedMessage());
  
      // Unlike non-message fields, if we set a message field to its default value (i.e.,
      // default instance), the field should be seen as present.
      builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
      assertTrue(builder.hasOptionalNestedMessage());
      assertTrue(builder.build().hasOptionalNestedMessage());
    }
  
    public void testSerializeAndParse() throws Exception {
      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
      builder.setOptionalInt32(1234);
      builder.setOptionalString("hello");
      builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
      // Set an oneof field to its default value and expect it to be serialized (i.e.,
      // an oneof field set to the default value should be treated as present).
      builder.setOneofInt32(0);
      ByteString data = builder.build().toByteString();
  
      TestAllTypes message = TestAllTypes.parseFrom(data);
      assertEquals(1234, message.getOptionalInt32());
      assertEquals("hello", message.getOptionalString());
      // Fields not set will have the default value.
      assertEquals(ByteString.EMPTY, message.getOptionalBytes());
      assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum());
      // The message field is set despite that it's set with a default instance.
      assertTrue(message.hasOptionalNestedMessage());
      assertEquals(0, message.getOptionalNestedMessage().getValue());
      // The oneof field set to its default value is also present.
      assertEquals(
          TestAllTypes.OneofFieldCase.ONEOF_INT32, message.getOneofFieldCase());
    }
  
    // Regression test for b/16173397
    // Make sure we haven't screwed up the code generation for repeated fields.
    public void testRepeatedFields() throws Exception {
      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
      builder.setOptionalInt32(1234);
      builder.setOptionalString("hello");
      builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
      builder.addRepeatedInt32(4321);
      builder.addRepeatedString("world");
      builder.addRepeatedNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
      ByteString data = builder.build().toByteString();
  
      TestOptionalFieldsOnly optionalOnlyMessage = TestOptionalFieldsOnly.parseFrom(data);
      assertEquals(1234, optionalOnlyMessage.getOptionalInt32());
      assertEquals("hello", optionalOnlyMessage.getOptionalString());
      assertTrue(optionalOnlyMessage.hasOptionalNestedMessage());
      assertEquals(0, optionalOnlyMessage.getOptionalNestedMessage().getValue());
  
      TestRepeatedFieldsOnly repeatedOnlyMessage = TestRepeatedFieldsOnly.parseFrom(data);
      assertEquals(1, repeatedOnlyMessage.getRepeatedInt32Count());
      assertEquals(4321, repeatedOnlyMessage.getRepeatedInt32(0));
      assertEquals(1, repeatedOnlyMessage.getRepeatedStringCount());
      assertEquals("world", repeatedOnlyMessage.getRepeatedString(0));
      assertEquals(1, repeatedOnlyMessage.getRepeatedNestedMessageCount());
      assertEquals(0, repeatedOnlyMessage.getRepeatedNestedMessage(0).getValue());
    }
  
    public void testIsInitialized() throws Exception {
      TestAllTypes.Builder builder = TestAllTypes.newBuilder();
  
      // Test optional proto2 message fields.
      UnittestProto.TestRequired.Builder proto2Builder =
          builder.getOptionalProto2MessageBuilder();
      assertFalse(builder.isInitialized());
      assertFalse(builder.buildPartial().isInitialized());
  
      proto2Builder.setA(1).setB(2).setC(3);
      assertTrue(builder.isInitialized());
      assertTrue(builder.buildPartial().isInitialized());
  
      // Test oneof proto2 message fields.
      proto2Builder = builder.getOneofProto2MessageBuilder();
      assertFalse(builder.isInitialized());
      assertFalse(builder.buildPartial().isInitialized());
  
      proto2Builder.setA(1).setB(2).setC(3);
      assertTrue(builder.isInitialized());
      assertTrue(builder.buildPartial().isInitialized());
  
      // Test repeated proto2 message fields.
      proto2Builder = builder.addRepeatedProto2MessageBuilder();
      assertFalse(builder.isInitialized());
      assertFalse(builder.buildPartial().isInitialized());
  
      proto2Builder.setA(1).setB(2).setC(3);
      assertTrue(builder.isInitialized());
      assertTrue(builder.buildPartial().isInitialized());
    }
  
  }
  