• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 package com.google.protobuf;
32 
33 import static com.google.common.truth.Truth.assertThat;
34 import static com.google.common.truth.Truth.assertWithMessage;
35 
36 import protobuf_unittest.UnittestProto;
37 import protobuf_unittest.UnittestProto.ForeignEnum;
38 import protobuf_unittest.UnittestProto.TestAllExtensions;
39 import protobuf_unittest.UnittestProto.TestAllTypes;
40 import protobuf_unittest.UnittestProto.TestEmptyMessage;
41 import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
42 import protobuf_unittest.UnittestProto.TestPackedExtensions;
43 import protobuf_unittest.UnittestProto.TestPackedTypes;
44 import proto3_unittest.UnittestProto3;
45 import java.util.Arrays;
46 import java.util.List;
47 import java.util.Map;
48 import org.junit.Assert;
49 import junit.framework.TestCase;
50 
51 /**
52  * Tests related to unknown field handling.
53  *
54  * @author kenton@google.com (Kenton Varda)
55  */
56 public class UnknownFieldSetTest extends TestCase {
57   @Override
setUp()58   public void setUp() throws Exception {
59     descriptor = TestAllTypes.getDescriptor();
60     allFields = TestUtil.getAllSet();
61     allFieldsData = allFields.toByteString();
62     emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
63     unknownFields = emptyMessage.getUnknownFields();
64   }
65 
getField(String name)66   private UnknownFieldSet.Field getField(String name) {
67     Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
68     assertNotNull(field);
69     return unknownFields.getField(field.getNumber());
70   }
71 
72   // Constructs a protocol buffer which contains fields with all the same
73   // numbers as allFieldsData except that each field is some other wire
74   // type.
getBizarroData()75   ByteString getBizarroData() throws Exception {
76     UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();
77 
78     UnknownFieldSet.Field varintField = UnknownFieldSet.Field.newBuilder().addVarint(1).build();
79     UnknownFieldSet.Field fixed32Field = UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
80 
81     for (Map.Entry<Integer, UnknownFieldSet.Field> entry : unknownFields.asMap().entrySet()) {
82       if (entry.getValue().getVarintList().isEmpty()) {
83         // Original field is not a varint, so use a varint.
84         bizarroFields.addField(entry.getKey(), varintField);
85       } else {
86         // Original field *is* a varint, so use something else.
87         bizarroFields.addField(entry.getKey(), fixed32Field);
88       }
89     }
90 
91     return bizarroFields.build().toByteString();
92   }
93 
94   Descriptors.Descriptor descriptor;
95   TestAllTypes allFields;
96   ByteString allFieldsData;
97 
98   // An empty message that has been parsed from allFieldsData.  So, it has
99   // unknown fields of every type.
100   TestEmptyMessage emptyMessage;
101   UnknownFieldSet unknownFields;
102 
103   // =================================================================
104 
testFieldBuildersAreReusable()105   public void testFieldBuildersAreReusable() {
106     UnknownFieldSet.Field.Builder fieldBuilder = UnknownFieldSet.Field.newBuilder();
107     fieldBuilder.addFixed32(10);
108     UnknownFieldSet.Field first = fieldBuilder.build();
109     UnknownFieldSet.Field second = fieldBuilder.build();
110     fieldBuilder.addFixed32(11);
111     UnknownFieldSet.Field third = fieldBuilder.build();
112 
113     assertThat(first).isEqualTo(second);
114     assertThat(first).isNotEqualTo(third);
115   }
116 
testClone()117   public void testClone() {
118     UnknownFieldSet.Builder unknownSetBuilder = UnknownFieldSet.newBuilder();
119     UnknownFieldSet.Field.Builder fieldBuilder = UnknownFieldSet.Field.newBuilder();
120     fieldBuilder.addFixed32(10);
121     unknownSetBuilder.addField(8, fieldBuilder.build());
122     // necessary to call clone twice to expose the bug
123     UnknownFieldSet.Builder clone1 = unknownSetBuilder.clone();
124     UnknownFieldSet.Builder clone2 = unknownSetBuilder.clone(); // failure is a NullPointerException
125     assertThat(clone1).isNotSameInstanceAs(clone2);
126   }
127 
testClone_lengthDelimited()128   public void testClone_lengthDelimited() {
129     UnknownFieldSet.Builder destUnknownFieldSet =
130         UnknownFieldSet.newBuilder()
131             .addField(997, UnknownFieldSet.Field.newBuilder().addVarint(99).build())
132             .addField(
133                 999,
134                 UnknownFieldSet.Field.newBuilder()
135                     .addLengthDelimited(ByteString.copyFromUtf8("some data"))
136                     .addLengthDelimited(ByteString.copyFromUtf8("some more data"))
137                     .build());
138     UnknownFieldSet clone = destUnknownFieldSet.clone().build();
139     assertThat(clone.getField(997)).isNotNull();
140     UnknownFieldSet.Field field999 = clone.getField(999);
141     List<ByteString> lengthDelimited = field999.getLengthDelimitedList();
142     assertThat(lengthDelimited.get(0).toStringUtf8()).isEqualTo("some data");
143     assertThat(lengthDelimited.get(1).toStringUtf8()).isEqualTo("some more data");
144 
145     UnknownFieldSet clone2 = destUnknownFieldSet.clone().build();
146     assertThat(clone2.getField(997)).isNotNull();
147     UnknownFieldSet.Field secondField = clone2.getField(999);
148     List<ByteString> lengthDelimited2 = secondField.getLengthDelimitedList();
149     assertThat(lengthDelimited2.get(0).toStringUtf8()).isEqualTo("some data");
150     assertThat(lengthDelimited2.get(1).toStringUtf8()).isEqualTo("some more data");
151   }
152 
testReuse()153   public void testReuse() {
154     UnknownFieldSet.Builder builder =
155         UnknownFieldSet.newBuilder()
156             .addField(997, UnknownFieldSet.Field.newBuilder().addVarint(99).build())
157             .addField(
158                 999,
159                 UnknownFieldSet.Field.newBuilder()
160                     .addLengthDelimited(ByteString.copyFromUtf8("some data"))
161                     .addLengthDelimited(ByteString.copyFromUtf8("some more data"))
162                     .build());
163 
164     UnknownFieldSet fieldSet1 = builder.build();
165     UnknownFieldSet fieldSet2 = builder.build();
166     builder.addField(1000, UnknownFieldSet.Field.newBuilder().addVarint(-90).build());
167     UnknownFieldSet fieldSet3 = builder.build();
168 
169     assertThat(fieldSet1).isEqualTo(fieldSet2);
170     assertThat(fieldSet1).isNotEqualTo(fieldSet3);
171   }
172 
173   @SuppressWarnings("ModifiedButNotUsed")
testAddField_zero()174   public void testAddField_zero() {
175     UnknownFieldSet.Field field = getField("optional_int32");
176     try {
177       UnknownFieldSet.newBuilder().addField(0, field);
178       Assert.fail();
179     } catch (IllegalArgumentException expected) {
180       assertThat(expected).hasMessageThat().isEqualTo("0 is not a valid field number.");
181     }
182   }
183 
184   @SuppressWarnings("ModifiedButNotUsed")
testAddField_negative()185   public void testAddField_negative() {
186     UnknownFieldSet.Field field = getField("optional_int32");
187     try {
188       UnknownFieldSet.newBuilder().addField(-2, field);
189       Assert.fail();
190     } catch (IllegalArgumentException expected) {
191       assertThat(expected).hasMessageThat().isEqualTo("-2 is not a valid field number.");
192     }
193   }
194 
195   @SuppressWarnings("ModifiedButNotUsed")
testClearField_negative()196   public void testClearField_negative() {
197     try {
198       UnknownFieldSet.newBuilder().clearField(-28);
199       Assert.fail();
200     } catch (IllegalArgumentException expected) {
201       assertThat(expected).hasMessageThat().isEqualTo("-28 is not a valid field number.");
202     }
203   }
204 
205   @SuppressWarnings("ModifiedButNotUsed")
testMergeField_negative()206   public void testMergeField_negative() {
207     UnknownFieldSet.Field field = getField("optional_int32");
208     try {
209       UnknownFieldSet.newBuilder().mergeField(-2, field);
210       Assert.fail();
211     } catch (IllegalArgumentException expected) {
212       assertThat(expected).hasMessageThat().isEqualTo("-2 is not a valid field number.");
213     }
214   }
215 
216   @SuppressWarnings("ModifiedButNotUsed")
testMergeVarintField_negative()217   public void testMergeVarintField_negative() {
218     try {
219       UnknownFieldSet.newBuilder().mergeVarintField(-2, 78);
220       Assert.fail();
221     } catch (IllegalArgumentException expected) {
222       assertThat(expected).hasMessageThat().isEqualTo("-2 is not a valid field number.");
223     }
224   }
225 
226   @SuppressWarnings("ModifiedButNotUsed")
testHasField_negative()227   public void testHasField_negative() {
228     assertThat(UnknownFieldSet.newBuilder().hasField(-2)).isFalse();
229   }
230 
231   @SuppressWarnings("ModifiedButNotUsed")
testMergeLengthDelimitedField_negative()232   public void testMergeLengthDelimitedField_negative() {
233     ByteString byteString = ByteString.copyFromUtf8("some data");
234     try {
235       UnknownFieldSet.newBuilder().mergeLengthDelimitedField(-2, byteString);
236       Assert.fail();
237     } catch (IllegalArgumentException expected) {
238       assertThat(expected).hasMessageThat().isEqualTo("-2 is not a valid field number.");
239     }
240   }
241 
testAddField()242   public void testAddField() {
243     UnknownFieldSet.Field field = getField("optional_int32");
244     UnknownFieldSet fieldSet = UnknownFieldSet.newBuilder().addField(1, field).build();
245     assertThat(fieldSet.getField(1)).isEqualTo(field);
246   }
247 
testAddField_withReplacement()248   public void testAddField_withReplacement() {
249     UnknownFieldSet.Field first = UnknownFieldSet.Field.newBuilder().addFixed32(56).build();
250     UnknownFieldSet.Field second = UnknownFieldSet.Field.newBuilder().addFixed32(25).build();
251     UnknownFieldSet fieldSet = UnknownFieldSet.newBuilder()
252         .addField(1, first)
253         .addField(1, second)
254         .build();
255     List<Integer> list = fieldSet.getField(1).getFixed32List();
256     assertThat(list).hasSize(1);
257     assertThat(list.get(0)).isEqualTo(25);
258   }
259 
testVarint()260   public void testVarint() throws Exception {
261     UnknownFieldSet.Field field = getField("optional_int32");
262     assertEquals(1, field.getVarintList().size());
263     assertEquals(allFields.getOptionalInt32(), (long) field.getVarintList().get(0));
264   }
265 
testFixed32()266   public void testFixed32() throws Exception {
267     UnknownFieldSet.Field field = getField("optional_fixed32");
268     assertEquals(1, field.getFixed32List().size());
269     assertEquals(allFields.getOptionalFixed32(), (int) field.getFixed32List().get(0));
270   }
271 
testFixed64()272   public void testFixed64() throws Exception {
273     UnknownFieldSet.Field field = getField("optional_fixed64");
274     assertEquals(1, field.getFixed64List().size());
275     assertEquals(allFields.getOptionalFixed64(), (long) field.getFixed64List().get(0));
276   }
277 
testLengthDelimited()278   public void testLengthDelimited() throws Exception {
279     UnknownFieldSet.Field field = getField("optional_bytes");
280     assertEquals(1, field.getLengthDelimitedList().size());
281     assertEquals(allFields.getOptionalBytes(), field.getLengthDelimitedList().get(0));
282   }
283 
testGroup()284   public void testGroup() throws Exception {
285     Descriptors.FieldDescriptor nestedFieldDescriptor =
286         TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a");
287     assertNotNull(nestedFieldDescriptor);
288 
289     UnknownFieldSet.Field field = getField("optionalgroup");
290     assertEquals(1, field.getGroupList().size());
291 
292     UnknownFieldSet group = field.getGroupList().get(0);
293     assertEquals(1, group.asMap().size());
294     assertTrue(group.hasField(nestedFieldDescriptor.getNumber()));
295 
296     UnknownFieldSet.Field nestedField = group.getField(nestedFieldDescriptor.getNumber());
297     assertEquals(1, nestedField.getVarintList().size());
298     assertEquals(allFields.getOptionalGroup().getA(), (long) nestedField.getVarintList().get(0));
299   }
300 
testSerialize()301   public void testSerialize() throws Exception {
302     // Check that serializing the UnknownFieldSet produces the original data
303     // again.
304     ByteString data = emptyMessage.toByteString();
305     assertEquals(allFieldsData, data);
306   }
307 
testCopyFrom()308   public void testCopyFrom() throws Exception {
309     TestEmptyMessage message = TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build();
310 
311     assertEquals(emptyMessage.toString(), message.toString());
312   }
313 
testMergeFrom()314   public void testMergeFrom() throws Exception {
315     TestEmptyMessage source =
316         TestEmptyMessage.newBuilder()
317             .setUnknownFields(
318                 UnknownFieldSet.newBuilder()
319                     .addField(2, UnknownFieldSet.Field.newBuilder().addVarint(2).build())
320                     .addField(3, UnknownFieldSet.Field.newBuilder().addVarint(4).build())
321                     .build())
322             .build();
323     TestEmptyMessage destination =
324         TestEmptyMessage.newBuilder()
325             .setUnknownFields(
326                 UnknownFieldSet.newBuilder()
327                     .addField(1, UnknownFieldSet.Field.newBuilder().addVarint(1).build())
328                     .addField(3, UnknownFieldSet.Field.newBuilder().addVarint(3).build())
329                     .build())
330             .mergeFrom(source)
331             .build();
332 
333     assertEquals("1: 1\n2: 2\n3: 3\n3: 4\n", destination.toString());
334   }
335 
testAsMap()336   public void testAsMap() throws Exception {
337     UnknownFieldSet.Builder builder = UnknownFieldSet.newBuilder().mergeFrom(unknownFields);
338     Map<Integer, UnknownFieldSet.Field> mapFromBuilder = builder.asMap();
339     assertThat(mapFromBuilder).isNotEmpty();
340     UnknownFieldSet fields = builder.build();
341     Map<Integer, UnknownFieldSet.Field> mapFromFieldSet = fields.asMap();
342     assertThat(mapFromFieldSet).containsExactlyEntriesIn(mapFromBuilder);
343   }
344 
testClear()345   public void testClear() throws Exception {
346     UnknownFieldSet fields = UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
347     assertTrue(fields.asMap().isEmpty());
348   }
349 
testClearMessage()350   public void testClearMessage() throws Exception {
351     TestEmptyMessage message =
352         TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
353     assertEquals(0, message.getSerializedSize());
354   }
355 
testClearField()356   public void testClearField() throws Exception {
357     int fieldNumber = unknownFields.asMap().keySet().iterator().next();
358     UnknownFieldSet fields =
359         UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clearField(fieldNumber).build();
360     assertFalse(fields.hasField(fieldNumber));
361   }
362 
testParseKnownAndUnknown()363   public void testParseKnownAndUnknown() throws Exception {
364     // Test mixing known and unknown fields when parsing.
365 
366     UnknownFieldSet fields =
367         UnknownFieldSet.newBuilder(unknownFields)
368             .addField(123456, UnknownFieldSet.Field.newBuilder().addVarint(654321).build())
369             .build();
370 
371     ByteString data = fields.toByteString();
372     TestAllTypes destination = TestAllTypes.parseFrom(data);
373 
374     TestUtil.assertAllFieldsSet(destination);
375     assertEquals(1, destination.getUnknownFields().asMap().size());
376 
377     UnknownFieldSet.Field field = destination.getUnknownFields().getField(123456);
378     assertEquals(1, field.getVarintList().size());
379     assertEquals(654321, (long) field.getVarintList().get(0));
380   }
381 
testWrongTypeTreatedAsUnknown()382   public void testWrongTypeTreatedAsUnknown() throws Exception {
383     // Test that fields of the wrong wire type are treated like unknown fields
384     // when parsing.
385 
386     ByteString bizarroData = getBizarroData();
387     TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
388     TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
389 
390     // All fields should have been interpreted as unknown, so the debug strings
391     // should be the same.
392     assertEquals(emptyMessage.toString(), allTypesMessage.toString());
393   }
394 
testUnknownExtensions()395   public void testUnknownExtensions() throws Exception {
396     // Make sure fields are properly parsed to the UnknownFieldSet even when
397     // they are declared as extension numbers.
398 
399     TestEmptyMessageWithExtensions message =
400         TestEmptyMessageWithExtensions.parseFrom(allFieldsData);
401 
402     assertEquals(unknownFields.asMap().size(), message.getUnknownFields().asMap().size());
403     assertEquals(allFieldsData, message.toByteString());
404   }
405 
testWrongExtensionTypeTreatedAsUnknown()406   public void testWrongExtensionTypeTreatedAsUnknown() throws Exception {
407     // Test that fields of the wrong wire type are treated like unknown fields
408     // when parsing extensions.
409 
410     ByteString bizarroData = getBizarroData();
411     TestAllExtensions allExtensionsMessage = TestAllExtensions.parseFrom(bizarroData);
412     TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
413 
414     // All fields should have been interpreted as unknown, so the debug strings
415     // should be the same.
416     assertEquals(emptyMessage.toString(), allExtensionsMessage.toString());
417   }
418 
testParseUnknownEnumValue()419   public void testParseUnknownEnumValue() throws Exception {
420     Descriptors.FieldDescriptor singularField =
421         TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
422     Descriptors.FieldDescriptor repeatedField =
423         TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
424     assertNotNull(singularField);
425     assertNotNull(repeatedField);
426 
427     ByteString data =
428         UnknownFieldSet.newBuilder()
429             .addField(
430                 singularField.getNumber(),
431                 UnknownFieldSet.Field.newBuilder()
432                     .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
433                     .addVarint(5) // not valid
434                     .build())
435             .addField(
436                 repeatedField.getNumber(),
437                 UnknownFieldSet.Field.newBuilder()
438                     .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
439                     .addVarint(4) // not valid
440                     .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
441                     .addVarint(6) // not valid
442                     .build())
443             .build()
444             .toByteString();
445 
446     {
447       TestAllTypes message = TestAllTypes.parseFrom(data);
448       assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum());
449       assertEquals(
450           Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
451           message.getRepeatedNestedEnumList());
452       assertEquals(
453           Arrays.asList(5L),
454           message.getUnknownFields().getField(singularField.getNumber()).getVarintList());
455       assertEquals(
456           Arrays.asList(4L, 6L),
457           message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList());
458     }
459 
460     {
461       TestAllExtensions message =
462           TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
463       assertEquals(
464           TestAllTypes.NestedEnum.BAR,
465           message.getExtension(UnittestProto.optionalNestedEnumExtension));
466       assertEquals(
467           Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
468           message.getExtension(UnittestProto.repeatedNestedEnumExtension));
469       assertEquals(
470           Arrays.asList(5L),
471           message.getUnknownFields().getField(singularField.getNumber()).getVarintList());
472       assertEquals(
473           Arrays.asList(4L, 6L),
474           message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList());
475     }
476   }
477 
testLargeVarint()478   public void testLargeVarint() throws Exception {
479     ByteString data =
480         UnknownFieldSet.newBuilder()
481             .addField(1, UnknownFieldSet.Field.newBuilder().addVarint(0x7FFFFFFFFFFFFFFFL).build())
482             .build()
483             .toByteString();
484     UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data);
485     UnknownFieldSet.Field field = parsed.getField(1);
486     assertEquals(1, field.getVarintList().size());
487     assertEquals(0x7FFFFFFFFFFFFFFFL, (long) field.getVarintList().get(0));
488   }
489 
testEqualsAndHashCode()490   public void testEqualsAndHashCode() {
491     UnknownFieldSet.Field fixed32Field = UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
492     UnknownFieldSet.Field fixed64Field = UnknownFieldSet.Field.newBuilder().addFixed64(1).build();
493     UnknownFieldSet.Field varIntField = UnknownFieldSet.Field.newBuilder().addVarint(1).build();
494     UnknownFieldSet.Field lengthDelimitedField =
495         UnknownFieldSet.Field.newBuilder().addLengthDelimited(ByteString.EMPTY).build();
496     UnknownFieldSet.Field groupField =
497         UnknownFieldSet.Field.newBuilder().addGroup(unknownFields).build();
498 
499     UnknownFieldSet a = UnknownFieldSet.newBuilder().addField(1, fixed32Field).build();
500     UnknownFieldSet b = UnknownFieldSet.newBuilder().addField(1, fixed64Field).build();
501     UnknownFieldSet c = UnknownFieldSet.newBuilder().addField(1, varIntField).build();
502     UnknownFieldSet d = UnknownFieldSet.newBuilder().addField(1, lengthDelimitedField).build();
503     UnknownFieldSet e = UnknownFieldSet.newBuilder().addField(1, groupField).build();
504 
505     checkEqualsIsConsistent(a);
506     checkEqualsIsConsistent(b);
507     checkEqualsIsConsistent(c);
508     checkEqualsIsConsistent(d);
509     checkEqualsIsConsistent(e);
510 
511     checkNotEqual(a, b);
512     checkNotEqual(a, c);
513     checkNotEqual(a, d);
514     checkNotEqual(a, e);
515     checkNotEqual(b, c);
516     checkNotEqual(b, d);
517     checkNotEqual(b, e);
518     checkNotEqual(c, d);
519     checkNotEqual(c, e);
520     checkNotEqual(d, e);
521   }
522 
523   /**
524    * Asserts that the given field sets are not equal and have different hash codes.
525    *
526    * <p><b>Note:</b> It's valid for non-equal objects to have the same hash code, so this test is
527    * stricter than it needs to be. However, this should happen relatively rarely.
528    */
checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2)529   private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
530     String equalsError = String.format("%s should not be equal to %s", s1, s2);
531     assertFalse(equalsError, s1.equals(s2));
532     assertFalse(equalsError, s2.equals(s1));
533 
534     assertFalse(
535         String.format("%s should have a different hash code from %s", s1, s2),
536         s1.hashCode() == s2.hashCode());
537   }
538 
539   /** Asserts that the given field sets are equal and have identical hash codes. */
checkEqualsIsConsistent(UnknownFieldSet set)540   private void checkEqualsIsConsistent(UnknownFieldSet set) {
541     // Object should be equal to itself.
542     assertEquals(set, set);
543 
544     // Object should be equal to a copy of itself.
545     UnknownFieldSet copy = UnknownFieldSet.newBuilder(set).build();
546     assertEquals(set, copy);
547     assertEquals(copy, set);
548     assertEquals(set.hashCode(), copy.hashCode());
549   }
550 
551   // =================================================================
552 
testProto3RoundTrip()553   public void testProto3RoundTrip() throws Exception {
554     ByteString data = getBizarroData();
555 
556     UnittestProto3.TestEmptyMessage message =
557         UnittestProto3.TestEmptyMessage.parseFrom(data, ExtensionRegistryLite.getEmptyRegistry());
558     assertEquals(data, message.toByteString());
559 
560     message = UnittestProto3.TestEmptyMessage.newBuilder().mergeFrom(message).build();
561     assertEquals(data, message.toByteString());
562 
563     assertEquals(
564         data,
565         UnittestProto3.TestMessageWithDummy.parseFrom(
566                 data, ExtensionRegistryLite.getEmptyRegistry())
567             .toBuilder()
568             // force copy-on-write
569             .setDummy(true)
570             .build()
571             .toBuilder()
572             .clearDummy()
573             .build()
574             .toByteString());
575   }
576 }
577