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