Add GeneratedMessageLiteTest and UnknownFieldSetLiteTest to the Java test suites. PiperOrigin-RevId: 1002600286
diff --git a/java/core/BUILD.bazel b/java/core/BUILD.bazel index 80a01d4..71207ac 100644 --- a/java/core/BUILD.bazel +++ b/java/core/BUILD.bazel
@@ -430,26 +430,30 @@ text_format_failure_list = "//conformance:text_format_failure_list_java.txt", ) +# Tests excluded from core_tests, also reused by the v25 compatibility tests. +FULL_TEST_EXCLUSIONS = [ + "src/test/java/com/google/protobuf/DecodeUtf8Test.java", + "src/test/java/com/google/protobuf/IsValidUtf8Test.java", + "src/test/java/com/google/protobuf/IsValidUtf8FourByteTest.java", + "src/test/java/com/google/protobuf/TestUtil.java", + "src/test/java/com/google/protobuf/TestUtilLite.java", + "src/test/java/com/google/protobuf/RuntimeVersionTest.java", + "src/test/java/com/google/protobuf/ParserLiteTest.java", + "src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java", + # Defunct experimental schema tests + "src/test/java/com/google/protobuf/Proto2LiteSchemaTest.java", + "src/test/java/com/google/protobuf/Proto3LiteSchemaTest.java", + "src/test/java/com/google/protobuf/Proto2ExtensionLiteLookupSchemaTest.java", + "src/test/java/com/google/protobuf/MessageSetLiteSchemaTest.java", + "src/test/java/com/google/protobuf/CodedAdapterTest.java", +] + junit_tests( name = "core_tests", size = "small", srcs = glob( ["src/test/java/**/*.java"], - exclude = [ - "src/test/java/com/google/protobuf/DecodeUtf8Test.java", - "src/test/java/com/google/protobuf/IsValidUtf8Test.java", - "src/test/java/com/google/protobuf/IsValidUtf8FourByteTest.java", - "src/test/java/com/google/protobuf/TestUtil.java", - "src/test/java/com/google/protobuf/TestUtilLite.java", - "src/test/java/com/google/protobuf/RuntimeVersionTest.java", - "src/test/java/com/google/protobuf/ParserLiteTest.java", - # Defunct experimental schema tests - "src/test/java/com/google/protobuf/Proto2LiteSchemaTest.java", - "src/test/java/com/google/protobuf/Proto3LiteSchemaTest.java", - "src/test/java/com/google/protobuf/Proto2ExtensionLiteLookupSchemaTest.java", - "src/test/java/com/google/protobuf/MessageSetLiteSchemaTest.java", - "src/test/java/com/google/protobuf/CodedAdapterTest.java", - ], + exclude = FULL_TEST_EXCLUSIONS, ), data = ["//src/google/protobuf:testdata"], deps = [ @@ -610,7 +614,6 @@ "src/test/java/com/google/protobuf/TestUtilLite.java", "src/test/java/com/google/protobuf/TypeRegistryTest.java", "src/test/java/com/google/protobuf/UnknownEnumValueTest.java", - "src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java", "src/test/java/com/google/protobuf/UnknownFieldSetPerformanceTest.java", "src/test/java/com/google/protobuf/UnknownFieldSetTest.java", "src/test/java/com/google/protobuf/UnredactedDebugFormatForTestTest.java", @@ -677,21 +680,7 @@ "src/test/java/com/google/protobuf/LargeEnumLiteTest.java", "src/test/java/com/google/protobuf/ImportOptionTest.java", "src/test/java/com/google/protobuf/ImportJavaFeaturesTest.java", - # Excluded in core_tests - "src/test/java/com/google/protobuf/DecodeUtf8Test.java", - "src/test/java/com/google/protobuf/IsValidUtf8Test.java", - "src/test/java/com/google/protobuf/IsValidUtf8FourByteTest.java", - "src/test/java/com/google/protobuf/TestUtil.java", - "src/test/java/com/google/protobuf/TestUtilLite.java", - "src/test/java/com/google/protobuf/RuntimeVersionTest.java", - "src/test/java/com/google/protobuf/ParserLiteTest.java", - # Defunct experimental schema tests - "src/test/java/com/google/protobuf/Proto2LiteSchemaTest.java", - "src/test/java/com/google/protobuf/Proto3LiteSchemaTest.java", - "src/test/java/com/google/protobuf/Proto2ExtensionLiteLookupSchemaTest.java", - "src/test/java/com/google/protobuf/MessageSetLiteSchemaTest.java", - "src/test/java/com/google/protobuf/CodedAdapterTest.java", - ], + ] + FULL_TEST_EXCLUSIONS, ), test_prefix = "v25SrcJar", deps = [ @@ -742,21 +731,7 @@ "src/test/java/com/google/protobuf/LargeEnumLiteTest.java", "src/test/java/com/google/protobuf/ImportOptionTest.java", "src/test/java/com/google/protobuf/ImportJavaFeaturesTest.java", - # Excluded in core_tests - "src/test/java/com/google/protobuf/DecodeUtf8Test.java", - "src/test/java/com/google/protobuf/IsValidUtf8Test.java", - "src/test/java/com/google/protobuf/IsValidUtf8FourByteTest.java", - "src/test/java/com/google/protobuf/TestUtil.java", - "src/test/java/com/google/protobuf/TestUtilLite.java", - "src/test/java/com/google/protobuf/RuntimeVersionTest.java", - "src/test/java/com/google/protobuf/ParserLiteTest.java", - # Defunct experimental schema tests - "src/test/java/com/google/protobuf/Proto2LiteSchemaTest.java", - "src/test/java/com/google/protobuf/Proto3LiteSchemaTest.java", - "src/test/java/com/google/protobuf/Proto2ExtensionLiteLookupSchemaTest.java", - "src/test/java/com/google/protobuf/MessageSetLiteSchemaTest.java", - "src/test/java/com/google/protobuf/CodedAdapterTest.java", - ], + ] + FULL_TEST_EXCLUSIONS, ), test_prefix = "v25Jar", deps = [
diff --git a/java/core/src/test/java/com/google/protobuf/GeneratedMessageLiteTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageLiteTest.java new file mode 100644 index 0000000..dda3e26 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageLiteTest.java
@@ -0,0 +1,99 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +package com.google.protobuf; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.protobuf.UnittestLite.TestAllExtensionsLite; +import proto2_unittest.NestedExtensionLite.MyNestedExtensionLite; +import proto2_unittest.NonNestedExtensionLite; +import proto2_unittest.NonNestedExtensionLite.MessageLiteToBeExtended; +import proto2_unittest.NonNestedExtensionLite.MyNonNestedExtensionLite; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GeneratedMessageLiteTest { + // ================================================================= + // Lite Extensions. + + @Test + public void testLiteExtensionMessageOrBuilder() throws Exception { + TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder(); + TestUtilLite.setAllExtensions(builder); + TestUtil.assertAllExtensionsSet(builder); + + TestAllExtensionsLite message = builder.build(); + TestUtil.assertAllExtensionsSet(message); + } + + @Test + public void testLiteExtensionRepeatedSetters() throws Exception { + TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder(); + TestUtilLite.setAllExtensions(builder); + TestUtilLite.modifyRepeatedExtensions(builder); + TestUtil.assertRepeatedExtensionsModified(builder); + + TestAllExtensionsLite message = builder.build(); + TestUtil.assertRepeatedExtensionsModified(message); + } + + @Test + public void testLiteExtensionDefaults() throws Exception { + TestUtil.assertExtensionsClear(TestAllExtensionsLite.getDefaultInstance()); + TestUtil.assertExtensionsClear(TestAllExtensionsLite.newBuilder().build()); + } + + @Test + public void testClearLiteExtension() throws Exception { + // clearExtension() is not actually used in TestUtil, so try it manually. + assertThat( + TestAllExtensionsLite.newBuilder() + .setExtension(UnittestLite.optionalInt32ExtensionLite, 1) + .clearExtension(UnittestLite.optionalInt32ExtensionLite) + .hasExtension(UnittestLite.optionalInt32ExtensionLite)) + .isFalse(); + assertThat( + TestAllExtensionsLite.newBuilder() + .addExtension(UnittestLite.repeatedInt32ExtensionLite, 1) + .clearExtension(UnittestLite.repeatedInt32ExtensionLite) + .getExtensionCount(UnittestLite.repeatedInt32ExtensionLite)) + .isEqualTo(0); + } + + @Test + public void testLiteExtensionCopy() throws Exception { + TestAllExtensionsLite original = TestUtilLite.getAllLiteExtensionsSet(); + TestAllExtensionsLite copy = TestAllExtensionsLite.newBuilder(original).build(); + TestUtil.assertAllExtensionsSet(copy); + } + + @Test + public void testLiteExtensionMergeFrom() throws Exception { + TestAllExtensionsLite original = + TestAllExtensionsLite.newBuilder() + .setExtension(UnittestLite.optionalInt32ExtensionLite, 1) + .build(); + TestAllExtensionsLite merged = TestAllExtensionsLite.newBuilder().mergeFrom(original).build(); + assertThat(merged.hasExtension(UnittestLite.optionalInt32ExtensionLite)).isTrue(); + assertThat((int) merged.getExtension(UnittestLite.optionalInt32ExtensionLite)).isEqualTo(1); + } + + @Test + public void testNonNestedExtensionLiteInitialization() { + assertThat(NonNestedExtensionLite.nonNestedExtensionLite.getMessageDefaultInstance()) + .isInstanceOf(MyNonNestedExtensionLite.class); + } + + @Test + public void testNestedExtensionLiteInitialization() { + assertThat(MyNestedExtensionLite.recursiveExtensionLite.getMessageDefaultInstance()) + .isInstanceOf(MessageLiteToBeExtended.class); + } +}
diff --git a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java index d585861..24658d3 100644 --- a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -21,6 +21,9 @@ import proto2_unittest.NonNestedExtension; import proto2_unittest.NonNestedExtension.MessageToBeExtended; import proto2_unittest.NonNestedExtension.MyNonNestedExtension; +import proto2_unittest.NonNestedExtensionLite; +import proto2_unittest.NonNestedExtensionLite.MessageLiteToBeExtended; +import proto2_unittest.NonNestedExtensionLite.MyNonNestedExtensionLite; import proto2_unittest.OuterClassNameTest2OuterClass; import proto2_unittest.OuterClassNameTest3OuterClass; import proto2_unittest.OuterClassNameTestOuterClass; @@ -1041,6 +1044,47 @@ } @Test + public void testSerializationWithExtension() throws Exception { + MessageLiteToBeExtended messageWithExtension = + MessageLiteToBeExtended.newBuilder() + .setExtension( + NonNestedExtensionLite.nonNestedExtensionLite, + MyNonNestedExtensionLite.getDefaultInstance()) + .build(); + + byte[] serializedMessage = serializeMessage(messageWithExtension); + MessageLiteToBeExtended deserializedMessage = + deserializeMessage(MessageLiteToBeExtended.class, serializedMessage); + + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + NonNestedExtensionLite.registerAllExtensions(registry); + assertThat(MessageLiteToBeExtended.parseFrom(deserializedMessage.toByteString(), registry)) + .isEqualTo(messageWithExtension); + } + + private static <T extends MessageLite> T deserializeMessage( + Class<T> clazz, byte[] serializedMessage) { + try (ByteArrayInputStream inByteArrayStream = new ByteArrayInputStream(serializedMessage); + ObjectInputStream inStream = new ObjectInputStream(inByteArrayStream)) { + return clazz.cast(inStream.readObject()); + } catch (IOException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + private static byte[] serializeMessage(MessageLite message) { + byte[] serializedMessage; + try (ByteArrayOutputStream outByteArrayStream = new ByteArrayOutputStream(); + ObjectOutputStream outStream = new ObjectOutputStream(outByteArrayStream)) { + outStream.writeObject(message); + serializedMessage = outByteArrayStream.toByteArray(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return serializedMessage; + } + + @Test public void testDeserializeWithoutClassField() throws Exception { // serialized form for version <=3.6.0 // just includes messageClassName and asBytes
diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java new file mode 100644 index 0000000..3a9ea04 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
@@ -0,0 +1,672 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +package com.google.protobuf; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertThrows; + +import com.google.protobuf.UnittestLite.TestAllExtensionsLite; +import com.google.protobuf.UnittestLite.TestAllTypesLite; +import proto2_unittest.UnittestProto; +import proto2_unittest.UnittestProto.ForeignEnum; +import proto2_unittest.UnittestProto.TestAllExtensions; +import proto2_unittest.UnittestProto.TestAllTypes; +import proto2_unittest.UnittestProto.TestEmptyMessage; +import proto2_unittest.UnittestProto.TestPackedExtensions; +import proto2_unittest.UnittestProto.TestPackedTypes; +import proto2_unittest.lite_equals_and_hash.LiteEqualsAndHash; +import proto2_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar; +import proto2_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo; +import proto3_unittest.UnittestProto3; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link UnknownFieldSetLite}. */ +@RunWith(JUnit4.class) +public class UnknownFieldSetLiteTest { + + @Before + public void setUp() throws Exception { + allFields = TestUtil.getAllSet(); + allFieldsData = allFields.toByteString(); + emptyMessage = TestEmptyMessage.parseFrom(allFieldsData); + } + + TestAllTypes allFields; + ByteString allFieldsData; + + // Constructs a protocol buffer which contains multiple conflicting definitions for the same field + // number. + private ByteString getBizarroData() throws Exception { + UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance(); + unknownFields.storeField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT), 1337L); + unknownFields.storeField(WireFormat.makeTag(1, WireFormat.WIRETYPE_FIXED32), 42); + unknownFields.storeField(WireFormat.makeTag(1, WireFormat.WIRETYPE_FIXED64), 0xDEADBEEFL); + return toByteString(unknownFields); + } + + // An empty message that has been parsed from allFieldsData. So, it has + // unknown fields of every type. + TestEmptyMessage emptyMessage; + + @Test + public void testDefaultInstance() { + UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance(); + + assertThat(unknownFields.getSerializedSize()).isEqualTo(0); + assertThat(toByteString(unknownFields)).isEqualTo(ByteString.EMPTY); + } + + @Test + public void testEmptyInstance() { + UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance(); + + assertThat(instance.getSerializedSize()).isEqualTo(0); + assertThat(toByteString(instance)).isEqualTo(ByteString.EMPTY); + assertThat(instance).isEqualTo(UnknownFieldSetLite.getDefaultInstance()); + } + + @Test + public void testMergeFieldFrom() throws IOException { + Foo foo = Foo.newBuilder().setValue(2).build(); + + CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); + + UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance(); + instance.mergeFieldFrom(input.readTag(), input); + + assertThat(toByteString(instance)).isEqualTo(foo.toByteString()); + } + + @Test + public void testMergeFieldFromInvalidEndGroup() throws IOException { + byte[] data = new byte[] {(byte) WireFormat.makeTag(1, WireFormat.WIRETYPE_END_GROUP)}; + CodedInputStream input = CodedInputStream.newInstance(data); + + UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance(); + assertThrows( + InvalidProtocolBufferException.class, + () -> instance.mergeFieldFrom(input.readTag(), input)); + } + + @Test + public void testSerializedSize() throws IOException { + Foo foo = Foo.newBuilder().setValue(2).build(); + + CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray()); + + UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance(); + instance.mergeFieldFrom(input.readTag(), input); + + assertThat(foo.toByteString().size()).isEqualTo(instance.getSerializedSize()); + } + + @Test + public void testHashCodeAfterDeserialization() throws IOException { + Foo foo = Foo.newBuilder().setValue(2).build(); + + Foo fooDeserialized = Foo.parseFrom(foo.toByteArray()); + + assertThat(foo).isEqualTo(fooDeserialized); + assertThat(foo.hashCode()).isEqualTo(fooDeserialized.hashCode()); + } + + @Test + public void testNewInstanceHashCode() { + UnknownFieldSetLite emptyFieldSet = UnknownFieldSetLite.getDefaultInstance(); + UnknownFieldSetLite paddedFieldSet = UnknownFieldSetLite.newInstance(); + + assertThat(paddedFieldSet).isEqualTo(emptyFieldSet); + assertThat(paddedFieldSet.hashCode()).isEqualTo(emptyFieldSet.hashCode()); + } + + @Test + public void testMergeVarintField() throws IOException { + UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance(); + unknownFields.mergeVarintField(10, 2); + + CodedInputStream input = + CodedInputStream.newInstance(toByteString(unknownFields).toByteArray()); + + int tag = input.readTag(); + assertThat(WireFormat.getTagFieldNumber(tag)).isEqualTo(10); + assertThat(WireFormat.getTagWireType(tag)).isEqualTo(WireFormat.WIRETYPE_VARINT); + assertThat(input.readUInt64()).isEqualTo(2); + assertThat(input.isAtEnd()).isTrue(); + } + + @Test + public void testMergeVarintField_negative() throws IOException { + UnknownFieldSetLite builder = UnknownFieldSetLite.newInstance(); + builder.mergeVarintField(10, -6); + + CodedInputStream input = CodedInputStream.newInstance(toByteString(builder).toByteArray()); + + int tag = input.readTag(); + assertThat(WireFormat.getTagFieldNumber(tag)).isEqualTo(10); + assertThat(WireFormat.getTagWireType(tag)).isEqualTo(WireFormat.WIRETYPE_VARINT); + assertThat(input.readUInt64()).isEqualTo(-6); + assertThat(input.isAtEnd()).isTrue(); + } + + @Test + public void testEqualsAndHashCode() { + UnknownFieldSetLite unknownFields1 = UnknownFieldSetLite.newInstance(); + unknownFields1.mergeVarintField(10, 2); + + UnknownFieldSetLite unknownFields2 = UnknownFieldSetLite.newInstance(); + unknownFields2.mergeVarintField(10, 2); + + assertThat(unknownFields2).isEqualTo(unknownFields1); + assertThat(unknownFields1.hashCode()).isEqualTo(unknownFields2.hashCode()); + assertThat(unknownFields1.equals(UnknownFieldSetLite.getDefaultInstance())).isFalse(); + assertThat(unknownFields1.hashCode()) + .isNotEqualTo(UnknownFieldSetLite.getDefaultInstance().hashCode()); + } + + @Test + public void testMutableCopyOf() throws IOException { + UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance(); + unknownFields.mergeVarintField(10, 2); + unknownFields = UnknownFieldSetLite.mutableCopyOf(unknownFields, unknownFields); + unknownFields.checkMutable(); + + CodedInputStream input = + CodedInputStream.newInstance(toByteString(unknownFields).toByteArray()); + + int tag = input.readTag(); + assertThat(WireFormat.getTagFieldNumber(tag)).isEqualTo(10); + assertThat(WireFormat.getTagWireType(tag)).isEqualTo(WireFormat.WIRETYPE_VARINT); + assertThat(input.readUInt64()).isEqualTo(2); + assertThat(input.isAtEnd()).isFalse(); + input.readTag(); + assertThat(WireFormat.getTagFieldNumber(tag)).isEqualTo(10); + assertThat(WireFormat.getTagWireType(tag)).isEqualTo(WireFormat.WIRETYPE_VARINT); + assertThat(input.readUInt64()).isEqualTo(2); + assertThat(input.isAtEnd()).isTrue(); + } + + @Test + public void testMutableCopyOf_empty() { + UnknownFieldSetLite unknownFields = + UnknownFieldSetLite.mutableCopyOf( + UnknownFieldSetLite.getDefaultInstance(), UnknownFieldSetLite.getDefaultInstance()); + unknownFields.checkMutable(); + + assertThat(unknownFields.getSerializedSize()).isEqualTo(0); + assertThat(toByteString(unknownFields)).isEqualTo(ByteString.EMPTY); + } + + @Test + public void testRoundTrips() throws InvalidProtocolBufferException { + Foo foo = + Foo.newBuilder() + .setValue(1) + .setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build()) + .setExtension(LiteEqualsAndHash.varint, 22) + .setExtension(LiteEqualsAndHash.fixed32, 44) + .setExtension(LiteEqualsAndHash.fixed64, 66L) + .setExtension( + LiteEqualsAndHash.myGroup, + LiteEqualsAndHash.MyGroup.newBuilder().setGroupValue("value").build()) + .build(); + + Foo copy = Foo.parseFrom(foo.toByteArray()); + + assertThat(foo.getSerializedSize()).isEqualTo(copy.getSerializedSize()); + assertThat(foo.equals(copy)).isFalse(); + + Foo secondCopy = Foo.parseFrom(foo.toByteArray()); + assertThat(secondCopy).isEqualTo(copy); + + ExtensionRegistryLite extensionRegistry = ExtensionRegistryLite.newInstance(); + LiteEqualsAndHash.registerAllExtensions(extensionRegistry); + Foo copyOfCopy = Foo.parseFrom(copy.toByteArray(), extensionRegistry); + + assertThat(copyOfCopy).isEqualTo(foo); + } + + @Test + public void testMalformedBytes() throws Exception { + try { + Foo.parseFrom("this is a malformed protocol buffer".getBytes(StandardCharsets.UTF_8)); + assertWithMessage("expected exception").fail(); + } catch (InvalidProtocolBufferException e) { + // Expected. + } + } + + @Test + public void testMissingStartGroupTag() throws IOException { + ByteString.Output byteStringOutput = ByteString.newOutput(); + CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); + output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); + output.writeTag(100, WireFormat.WIRETYPE_END_GROUP); + output.flush(); + + try { + Foo.parseFrom(byteStringOutput.toByteString()); + assertWithMessage("expected exception").fail(); + } catch (InvalidProtocolBufferException e) { + // Expected. + } + } + + @Test + public void testMissingEndGroupTag() throws IOException { + ByteString.Output byteStringOutput = ByteString.newOutput(); + CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); + output.writeTag(100, WireFormat.WIRETYPE_START_GROUP); + output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); + output.flush(); + + try { + Foo.parseFrom(byteStringOutput.toByteString()); + assertWithMessage("expected exception").fail(); + } catch (InvalidProtocolBufferException e) { + // Expected. + } + } + + @Test + public void testMismatchingGroupTags() throws IOException { + ByteString.Output byteStringOutput = ByteString.newOutput(); + CodedOutputStream output = CodedOutputStream.newInstance(byteStringOutput); + output.writeTag(100, WireFormat.WIRETYPE_START_GROUP); + output.writeGroupNoTag(Foo.newBuilder().setValue(11).build()); + output.writeTag(101, WireFormat.WIRETYPE_END_GROUP); + output.flush(); + + try { + Foo.parseFrom(byteStringOutput.toByteString()); + assertWithMessage("expected exception").fail(); + } catch (InvalidProtocolBufferException e) { + // Expected. + } + } + + @Test + public void testTruncatedInput() { + Foo foo = + Foo.newBuilder() + .setValue(1) + .setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build()) + .setExtension(LiteEqualsAndHash.varint, 22) + .setExtension( + LiteEqualsAndHash.myGroup, + LiteEqualsAndHash.MyGroup.newBuilder().setGroupValue("value").build()) + .build(); + + try { + Foo.parseFrom(foo.toByteString().substring(0, foo.toByteString().size() - 10)); + assertWithMessage("expected exception").fail(); + } catch (InvalidProtocolBufferException e) { + // Expected. + } + } + + @Test + public void testMakeImmutable() throws Exception { + UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance(); + unknownFields.makeImmutable(); + + try { + unknownFields.mergeVarintField(1, 1); + assertWithMessage("expected exception").fail(); + } catch (UnsupportedOperationException expected) { + } + + try { + unknownFields.mergeLengthDelimitedField(2, ByteString.copyFromUtf8("hello")); + assertWithMessage("expected exception").fail(); + } catch (UnsupportedOperationException expected) { + } + + try { + unknownFields.mergeFieldFrom(1, CodedInputStream.newInstance(new byte[0])); + assertWithMessage("expected exception").fail(); + } catch (UnsupportedOperationException expected) { + } + } + + @Test + public void testEndToEnd() throws Exception { + TestAllTypesLite testAllTypes = TestAllTypesLite.getDefaultInstance(); + try { + testAllTypes.unknownFields.checkMutable(); + assertWithMessage("expected exception").fail(); + } catch (UnsupportedOperationException expected) { + } + + testAllTypes = TestAllTypesLite.parseFrom(new byte[0]); + try { + testAllTypes.unknownFields.checkMutable(); + assertWithMessage("expected exception").fail(); + } catch (UnsupportedOperationException expected) { + } + + testAllTypes = TestAllTypesLite.newBuilder().build(); + try { + testAllTypes.unknownFields.checkMutable(); + assertWithMessage("expected exception").fail(); + } catch (UnsupportedOperationException expected) { + } + + testAllTypes = TestAllTypesLite.newBuilder().setDefaultBool(true).build(); + try { + testAllTypes.unknownFields.checkMutable(); + assertWithMessage("expected exception").fail(); + } catch (UnsupportedOperationException expected) { + } + + TestAllExtensionsLite testAllExtensions = + TestAllExtensionsLite.newBuilder() + .mergeFrom( + TestAllExtensionsLite.newBuilder() + .setExtension(UnittestLite.optionalInt32ExtensionLite, 2) + .build() + .toByteArray()) + .build(); + try { + testAllExtensions.unknownFields.checkMutable(); + assertWithMessage("expected exception").fail(); + } catch (UnsupportedOperationException expected) { + } + } + + private static ByteString toByteString(UnknownFieldSetLite unknownFields) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream); + try { + unknownFields.writeTo(output); + output.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return ByteString.copyFrom(byteArrayOutputStream.toByteArray()); + } + + @Test + public void testSerializeLite() throws Exception { + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData); + assertThat(emptyMessageLite.getSerializedSize()).isEqualTo(allFieldsData.size()); + ByteString data = emptyMessageLite.toByteString(); + TestAllTypes message = TestAllTypes.parseFrom(data); + TestUtil.assertAllFieldsSet(message); + assertThat(data).isEqualTo(allFieldsData); + } + + @Test + public void testAllExtensionsLite() throws Exception { + TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet(); + ByteString allExtensionsData = allExtensions.toByteString(); + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(allExtensionsData); + ByteString data = emptyMessageLite.toByteString(); + TestAllExtensions message = TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry()); + TestUtil.assertAllExtensionsSet(message); + assertThat(data).isEqualTo(allExtensionsData); + } + + @Test + public void testAllExtensions_areImmutable() throws Exception { + // Empty message + TestUtil.assertRepeatedExtensionsImmutable(TestAllExtensions.getDefaultInstance()); + + // Message populated with all extensions + TestUtil.assertRepeatedExtensionsImmutable(TestUtil.getAllExtensionsSet()); + } + + @Test + public void testAllPackedFieldsLite() throws Exception { + TestPackedTypes allPackedFields = TestUtil.getPackedSet(); + ByteString allPackedData = allPackedFields.toByteString(); + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(allPackedData); + ByteString data = emptyMessageLite.toByteString(); + TestPackedTypes message = TestPackedTypes.parseFrom(data, TestUtil.getExtensionRegistry()); + TestUtil.assertPackedFieldsSet(message); + assertThat(data).isEqualTo(allPackedData); + } + + @Test + public void testAllPackedExtensionsLite() throws Exception { + TestPackedExtensions allPackedExtensions = TestUtil.getPackedExtensionsSet(); + ByteString allPackedExtensionsData = allPackedExtensions.toByteString(); + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(allPackedExtensionsData); + ByteString data = emptyMessageLite.toByteString(); + TestPackedExtensions message = + TestPackedExtensions.parseFrom(data, TestUtil.getExtensionRegistry()); + TestUtil.assertPackedExtensionsSet(message); + assertThat(data).isEqualTo(allPackedExtensionsData); + } + + @Test + @SuppressWarnings("ProtoNewBuilderMergeFrom") + public void testCopyFromLite() throws Exception { + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData); + UnittestLite.TestEmptyMessageLite emptyMessageLite2 = + UnittestLite.TestEmptyMessageLite.newBuilder().mergeFrom(emptyMessageLite).build(); + assertThat(emptyMessageLite2.toByteString()).isEqualTo(emptyMessageLite.toByteString()); + } + + @Test + public void testMergeFromLite() throws Exception { + TestAllTypes message1 = + TestAllTypes.newBuilder() + .setOptionalInt32(1) + .setOptionalString("foo") + .addRepeatedString("bar") + .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAZ) + .build(); + + TestAllTypes message2 = + TestAllTypes.newBuilder() + .setOptionalInt64(2) + .setOptionalString("baz") + .addRepeatedString("qux") + .setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ) + .build(); + + ByteString data1 = message1.toByteString(); + UnittestLite.TestEmptyMessageLite emptyMessageLite1 = + UnittestLite.TestEmptyMessageLite.parseFrom(data1); + ByteString data2 = message2.toByteString(); + UnittestLite.TestEmptyMessageLite emptyMessageLite2 = + UnittestLite.TestEmptyMessageLite.parseFrom(data2); + + message1 = TestAllTypes.newBuilder(message1).mergeFrom(message2).build(); + emptyMessageLite1 = + UnittestLite.TestEmptyMessageLite.newBuilder(emptyMessageLite1) + .mergeFrom(emptyMessageLite2) + .build(); + + data1 = emptyMessageLite1.toByteString(); + message2 = TestAllTypes.parseFrom(data1); + + assertThat(message2).isEqualTo(message1); + } + + @Test + public void testWrongTypeTreatedAsUnknownLite() throws Exception { + // Test that fields of the wrong wire type are treated like unknown fields + // when parsing. + + ByteString bizarroData = getBizarroData(); + TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData); + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData); + ByteString data = emptyMessageLite.toByteString(); + TestAllTypes allTypesMessage2 = TestAllTypes.parseFrom(data); + + assertThat(allTypesMessage2.toString()).isEqualTo(allTypesMessage.toString()); + } + + @Test + public void testUnknownExtensionsLite() throws Exception { + // Make sure fields are properly parsed to the UnknownFieldSet even when + // they are declared as extension numbers. + + UnittestLite.TestEmptyMessageWithExtensionsLite message = + UnittestLite.TestEmptyMessageWithExtensionsLite.parseFrom(allFieldsData); + + assertThat(message.toByteString()).isEqualTo(allFieldsData); + } + + @Test + public void testWrongExtensionTypeTreatedAsUnknownLite() throws Exception { + // Test that fields of the wrong wire type are treated like unknown fields + // when parsing extensions. + + ByteString bizarroData = getBizarroData(); + TestAllExtensions allExtensionsMessage = TestAllExtensions.parseFrom(bizarroData); + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(bizarroData); + + // All fields should have been interpreted as unknown, so the byte strings + // should be the same. + assertThat(allExtensionsMessage.toByteString()).isEqualTo(emptyMessageLite.toByteString()); + } + + @Test + public void testParseUnknownEnumValueLite() throws Exception { + ByteString data = + toByteString( + UnknownFieldSetLite.newInstance() + .mergeVarintField( + TestAllTypes.OPTIONAL_NESTED_ENUM_FIELD_NUMBER, + TestAllTypes.NestedEnum.BAR_VALUE) + .mergeVarintField( + TestAllTypes.REPEATED_NESTED_ENUM_FIELD_NUMBER, + TestAllTypes.NestedEnum.FOO_VALUE) + .mergeVarintField( + TestAllTypes.REPEATED_NESTED_ENUM_FIELD_NUMBER, + TestAllTypes.NestedEnum.BAZ_VALUE) + // Invalid values. Since the internals of UnknownFieldSetLite are private, the only + // way to verify that unknown values are preserved is to do a round-trip test, and + // unknown values are always serialized last. + .mergeVarintField(TestAllTypes.OPTIONAL_NESTED_ENUM_FIELD_NUMBER, 5) + .mergeVarintField(TestAllTypes.REPEATED_NESTED_ENUM_FIELD_NUMBER, 4) + .mergeVarintField(TestAllTypes.REPEATED_NESTED_ENUM_FIELD_NUMBER, 6)); + + UnittestLite.TestEmptyMessageLite emptyMessageLite = + UnittestLite.TestEmptyMessageLite.parseFrom(data); + assertThat(emptyMessageLite.toByteString()).isEqualTo(data); + + { + TestAllTypes message = TestAllTypes.parseFrom(data); + assertThat(message.getOptionalNestedEnum()).isEqualTo(TestAllTypes.NestedEnum.BAR); + assertThat(message.getRepeatedNestedEnumList()) + .containsExactly(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ) + .inOrder(); + assertThat(message.toByteString()).isEqualTo(data); + } + + { + TestAllExtensions message = + TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry()); + assertThat(message.getExtension(UnittestProto.optionalNestedEnumExtension)) + .isEqualTo(TestAllTypes.NestedEnum.BAR); + assertThat(message.getExtension(UnittestProto.repeatedNestedEnumExtension)) + .containsExactly(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ) + .inOrder(); + assertThat(message.toByteString()).isEqualTo(data); + } + } + + @Test + @SuppressWarnings("ProtoNewBuilderMergeFrom") + public void testClearLite() throws Exception { + UnittestLite.TestEmptyMessageLite emptyMessageLite1 = + UnittestLite.TestEmptyMessageLite.parseFrom(allFieldsData); + UnittestLite.TestEmptyMessageLite emptyMessageLite2 = + UnittestLite.TestEmptyMessageLite.newBuilder().mergeFrom(emptyMessageLite1).clear().build(); + assertThat(emptyMessageLite2.getSerializedSize()).isEqualTo(0); + ByteString data = emptyMessageLite2.toByteString(); + assertThat(data.size()).isEqualTo(0); + } + + @Test + @SuppressWarnings("ProtoNewBuilderMergeFrom") + public void testProto3RoundTrip() throws Exception { + ByteString data = getBizarroData(); + + UnittestProto3.TestEmptyMessage message = + UnittestProto3.TestEmptyMessage.parseFrom(data, ExtensionRegistryLite.getEmptyRegistry()); + assertThat(message.toByteString()).isEqualTo(data); + + message = UnittestProto3.TestEmptyMessage.newBuilder().mergeFrom(message).build(); + assertThat(message.toByteString()).isEqualTo(data); + + // regression test for b/142710815 + assertThat(data) + .isEqualTo( + UnittestProto3.TestMessageWithDummy.parseFrom( + data, ExtensionRegistryLite.getEmptyRegistry()) + .toBuilder() + // force copy-on-write + .setDummy(true) + .build() + .toBuilder() + .clearDummy() + .build() + .toByteString()); + } + + @Test + public void testNestedUnknownGroupsExceeded() throws Exception { + UnknownFieldSetLite current = UnknownFieldSetLite.newInstance(); + current.storeField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT), 1L); + + for (int i = 0; i < 98; i++) { + UnknownFieldSetLite parent = UnknownFieldSetLite.newInstance(); + parent.storeField(WireFormat.makeTag(1, WireFormat.WIRETYPE_START_GROUP), current); + current = parent; + } + + ByteString data = toByteString(current); + CodedInputStream input = CodedInputStream.newInstance(data.toByteArray()); + + UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance(); + + int tag = input.readTag(); + assertThat(instance.mergeFieldFrom(tag, input)).isTrue(); + } + + @Test + public void testRecursionLimitExceeded() throws Exception { + UnknownFieldSetLite current = UnknownFieldSetLite.newInstance(); + current.storeField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT), 1L); + + for (int i = 0; i < 150; i++) { + UnknownFieldSetLite parent = UnknownFieldSetLite.newInstance(); + parent.storeField(WireFormat.makeTag(1, WireFormat.WIRETYPE_START_GROUP), current); + current = parent; + } + + ByteString data = toByteString(current); + CodedInputStream input = CodedInputStream.newInstance(data.toByteArray()); + + UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance(); + + int tag = input.readTag(); + InvalidProtocolBufferException e = + assertThrows( + InvalidProtocolBufferException.class, () -> instance.mergeFieldFrom(tag, input)); + assertThat(e).hasMessageThat().contains("too many levels of nesting"); + } +}