1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // http://code.google.com/p/protobuf/
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 protobuf_unittest.UnittestProto;
34 import protobuf_unittest.UnittestProto.TestAllExtensions;
35 import protobuf_unittest.UnittestProto.TestAllTypes;
36 import protobuf_unittest.UnittestProto.TestEmptyMessage;
37 import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
38 
39 import junit.framework.TestCase;
40 
41 import java.util.Arrays;
42 import java.util.Map;
43 
44 /**
45  * Tests related to unknown field handling.
46  *
47  * @author kenton@google.com (Kenton Varda)
48  */
49 public class UnknownFieldSetTest extends TestCase {
setUp()50   public void setUp() throws Exception {
51     descriptor = TestAllTypes.getDescriptor();
52     allFields = TestUtil.getAllSet();
53     allFieldsData = allFields.toByteString();
54     emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
55     unknownFields = emptyMessage.getUnknownFields();
56   }
57 
getField(String name)58   UnknownFieldSet.Field getField(String name) {
59     Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
60     assertNotNull(field);
61     return unknownFields.getField(field.getNumber());
62   }
63 
64   // Constructs a protocol buffer which contains fields with all the same
65   // numbers as allFieldsData except that each field is some other wire
66   // type.
getBizarroData()67   ByteString getBizarroData() throws Exception {
68     UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();
69 
70     UnknownFieldSet.Field varintField =
71       UnknownFieldSet.Field.newBuilder().addVarint(1).build();
72     UnknownFieldSet.Field fixed32Field =
73       UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
74 
75     for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
76          unknownFields.asMap().entrySet()) {
77       if (entry.getValue().getVarintList().isEmpty()) {
78         // Original field is not a varint, so use a varint.
79         bizarroFields.addField(entry.getKey(), varintField);
80       } else {
81         // Original field *is* a varint, so use something else.
82         bizarroFields.addField(entry.getKey(), fixed32Field);
83       }
84     }
85 
86     return bizarroFields.build().toByteString();
87   }
88 
89   Descriptors.Descriptor descriptor;
90   TestAllTypes allFields;
91   ByteString allFieldsData;
92 
93   // An empty message that has been parsed from allFieldsData.  So, it has
94   // unknown fields of every type.
95   TestEmptyMessage emptyMessage;
96   UnknownFieldSet unknownFields;
97 
98   // =================================================================
99 
testVarint()100   public void testVarint() throws Exception {
101     UnknownFieldSet.Field field = getField("optional_int32");
102     assertEquals(1, field.getVarintList().size());
103     assertEquals(allFields.getOptionalInt32(),
104                  (long) field.getVarintList().get(0));
105   }
106 
testFixed32()107   public void testFixed32() throws Exception {
108     UnknownFieldSet.Field field = getField("optional_fixed32");
109     assertEquals(1, field.getFixed32List().size());
110     assertEquals(allFields.getOptionalFixed32(),
111                  (int) field.getFixed32List().get(0));
112   }
113 
testFixed64()114   public void testFixed64() throws Exception {
115     UnknownFieldSet.Field field = getField("optional_fixed64");
116     assertEquals(1, field.getFixed64List().size());
117     assertEquals(allFields.getOptionalFixed64(),
118                  (long) field.getFixed64List().get(0));
119   }
120 
testLengthDelimited()121   public void testLengthDelimited() throws Exception {
122     UnknownFieldSet.Field field = getField("optional_bytes");
123     assertEquals(1, field.getLengthDelimitedList().size());
124     assertEquals(allFields.getOptionalBytes(),
125                  field.getLengthDelimitedList().get(0));
126   }
127 
testGroup()128   public void testGroup() throws Exception {
129     Descriptors.FieldDescriptor nestedFieldDescriptor =
130       TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a");
131     assertNotNull(nestedFieldDescriptor);
132 
133     UnknownFieldSet.Field field = getField("optionalgroup");
134     assertEquals(1, field.getGroupList().size());
135 
136     UnknownFieldSet group = field.getGroupList().get(0);
137     assertEquals(1, group.asMap().size());
138     assertTrue(group.hasField(nestedFieldDescriptor.getNumber()));
139 
140     UnknownFieldSet.Field nestedField =
141       group.getField(nestedFieldDescriptor.getNumber());
142     assertEquals(1, nestedField.getVarintList().size());
143     assertEquals(allFields.getOptionalGroup().getA(),
144                  (long) nestedField.getVarintList().get(0));
145   }
146 
testSerialize()147   public void testSerialize() throws Exception {
148     // Check that serializing the UnknownFieldSet produces the original data
149     // again.
150     ByteString data = emptyMessage.toByteString();
151     assertEquals(allFieldsData, data);
152   }
153 
testCopyFrom()154   public void testCopyFrom() throws Exception {
155     TestEmptyMessage message =
156       TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build();
157 
158     assertEquals(emptyMessage.toString(), message.toString());
159   }
160 
testMergeFrom()161   public void testMergeFrom() throws Exception {
162     TestEmptyMessage source =
163       TestEmptyMessage.newBuilder()
164         .setUnknownFields(
165           UnknownFieldSet.newBuilder()
166             .addField(2,
167               UnknownFieldSet.Field.newBuilder()
168                 .addVarint(2).build())
169             .addField(3,
170               UnknownFieldSet.Field.newBuilder()
171                 .addVarint(4).build())
172             .build())
173         .build();
174     TestEmptyMessage destination =
175       TestEmptyMessage.newBuilder()
176         .setUnknownFields(
177           UnknownFieldSet.newBuilder()
178             .addField(1,
179               UnknownFieldSet.Field.newBuilder()
180                 .addVarint(1).build())
181             .addField(3,
182               UnknownFieldSet.Field.newBuilder()
183                 .addVarint(3).build())
184             .build())
185         .mergeFrom(source)
186         .build();
187 
188     assertEquals(
189       "1: 1\n" +
190       "2: 2\n" +
191       "3: 3\n" +
192       "3: 4\n",
193       destination.toString());
194   }
195 
testClear()196   public void testClear() throws Exception {
197     UnknownFieldSet fields =
198       UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
199     assertTrue(fields.asMap().isEmpty());
200   }
201 
testClearMessage()202   public void testClearMessage() throws Exception {
203     TestEmptyMessage message =
204       TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
205     assertEquals(0, message.getSerializedSize());
206   }
207 
testParseKnownAndUnknown()208   public void testParseKnownAndUnknown() throws Exception {
209     // Test mixing known and unknown fields when parsing.
210 
211     UnknownFieldSet fields =
212       UnknownFieldSet.newBuilder(unknownFields)
213         .addField(123456,
214           UnknownFieldSet.Field.newBuilder().addVarint(654321).build())
215         .build();
216 
217     ByteString data = fields.toByteString();
218     TestAllTypes destination = TestAllTypes.parseFrom(data);
219 
220     TestUtil.assertAllFieldsSet(destination);
221     assertEquals(1, destination.getUnknownFields().asMap().size());
222 
223     UnknownFieldSet.Field field =
224       destination.getUnknownFields().getField(123456);
225     assertEquals(1, field.getVarintList().size());
226     assertEquals(654321, (long) field.getVarintList().get(0));
227   }
228 
testWrongTypeTreatedAsUnknown()229   public void testWrongTypeTreatedAsUnknown() throws Exception {
230     // Test that fields of the wrong wire type are treated like unknown fields
231     // when parsing.
232 
233     ByteString bizarroData = getBizarroData();
234     TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
235     TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
236 
237     // All fields should have been interpreted as unknown, so the debug strings
238     // should be the same.
239     assertEquals(emptyMessage.toString(), allTypesMessage.toString());
240   }
241 
testUnknownExtensions()242   public void testUnknownExtensions() throws Exception {
243     // Make sure fields are properly parsed to the UnknownFieldSet even when
244     // they are declared as extension numbers.
245 
246     TestEmptyMessageWithExtensions message =
247       TestEmptyMessageWithExtensions.parseFrom(allFieldsData);
248 
249     assertEquals(unknownFields.asMap().size(),
250                  message.getUnknownFields().asMap().size());
251     assertEquals(allFieldsData, message.toByteString());
252   }
253 
testWrongExtensionTypeTreatedAsUnknown()254   public void testWrongExtensionTypeTreatedAsUnknown() throws Exception {
255     // Test that fields of the wrong wire type are treated like unknown fields
256     // when parsing extensions.
257 
258     ByteString bizarroData = getBizarroData();
259     TestAllExtensions allExtensionsMessage =
260       TestAllExtensions.parseFrom(bizarroData);
261     TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
262 
263     // All fields should have been interpreted as unknown, so the debug strings
264     // should be the same.
265     assertEquals(emptyMessage.toString(),
266                  allExtensionsMessage.toString());
267   }
268 
testParseUnknownEnumValue()269   public void testParseUnknownEnumValue() throws Exception {
270     Descriptors.FieldDescriptor singularField =
271       TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
272     Descriptors.FieldDescriptor repeatedField =
273       TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
274     assertNotNull(singularField);
275     assertNotNull(repeatedField);
276 
277     ByteString data =
278       UnknownFieldSet.newBuilder()
279         .addField(singularField.getNumber(),
280           UnknownFieldSet.Field.newBuilder()
281             .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
282             .addVarint(5)   // not valid
283             .build())
284         .addField(repeatedField.getNumber(),
285           UnknownFieldSet.Field.newBuilder()
286             .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
287             .addVarint(4)   // not valid
288             .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
289             .addVarint(6)   // not valid
290             .build())
291         .build()
292         .toByteString();
293 
294     {
295       TestAllTypes message = TestAllTypes.parseFrom(data);
296       assertEquals(TestAllTypes.NestedEnum.BAR,
297                    message.getOptionalNestedEnum());
298       assertEquals(
299         Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
300         message.getRepeatedNestedEnumList());
301       assertEquals(Arrays.asList(5L),
302                    message.getUnknownFields()
303                           .getField(singularField.getNumber())
304                           .getVarintList());
305       assertEquals(Arrays.asList(4L, 6L),
306                    message.getUnknownFields()
307                           .getField(repeatedField.getNumber())
308                           .getVarintList());
309     }
310 
311     {
312       TestAllExtensions message =
313         TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
314       assertEquals(TestAllTypes.NestedEnum.BAR,
315         message.getExtension(UnittestProto.optionalNestedEnumExtension));
316       assertEquals(
317         Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
318         message.getExtension(UnittestProto.repeatedNestedEnumExtension));
319       assertEquals(Arrays.asList(5L),
320                    message.getUnknownFields()
321                           .getField(singularField.getNumber())
322                           .getVarintList());
323       assertEquals(Arrays.asList(4L, 6L),
324                    message.getUnknownFields()
325                           .getField(repeatedField.getNumber())
326                           .getVarintList());
327     }
328   }
329 
testLargeVarint()330   public void testLargeVarint() throws Exception {
331     ByteString data =
332       UnknownFieldSet.newBuilder()
333         .addField(1,
334           UnknownFieldSet.Field.newBuilder()
335             .addVarint(0x7FFFFFFFFFFFFFFFL)
336             .build())
337         .build()
338         .toByteString();
339     UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data);
340     UnknownFieldSet.Field field = parsed.getField(1);
341     assertEquals(1, field.getVarintList().size());
342     assertEquals(0x7FFFFFFFFFFFFFFFL, (long)field.getVarintList().get(0));
343   }
344 
testEqualsAndHashCode()345   public void testEqualsAndHashCode() {
346     UnknownFieldSet.Field fixed32Field =
347         UnknownFieldSet.Field.newBuilder()
348             .addFixed32(1)
349             .build();
350     UnknownFieldSet.Field fixed64Field =
351         UnknownFieldSet.Field.newBuilder()
352             .addFixed64(1)
353             .build();
354     UnknownFieldSet.Field varIntField =
355         UnknownFieldSet.Field.newBuilder()
356             .addVarint(1)
357             .build();
358     UnknownFieldSet.Field lengthDelimitedField =
359         UnknownFieldSet.Field.newBuilder()
360             .addLengthDelimited(ByteString.EMPTY)
361             .build();
362     UnknownFieldSet.Field groupField =
363         UnknownFieldSet.Field.newBuilder()
364             .addGroup(unknownFields)
365             .build();
366 
367     UnknownFieldSet a =
368         UnknownFieldSet.newBuilder()
369             .addField(1, fixed32Field)
370             .build();
371     UnknownFieldSet b =
372         UnknownFieldSet.newBuilder()
373             .addField(1, fixed64Field)
374             .build();
375     UnknownFieldSet c =
376         UnknownFieldSet.newBuilder()
377             .addField(1, varIntField)
378             .build();
379     UnknownFieldSet d =
380         UnknownFieldSet.newBuilder()
381             .addField(1, lengthDelimitedField)
382             .build();
383     UnknownFieldSet e =
384         UnknownFieldSet.newBuilder()
385             .addField(1, groupField)
386             .build();
387 
388     checkEqualsIsConsistent(a);
389     checkEqualsIsConsistent(b);
390     checkEqualsIsConsistent(c);
391     checkEqualsIsConsistent(d);
392     checkEqualsIsConsistent(e);
393 
394     checkNotEqual(a, b);
395     checkNotEqual(a, c);
396     checkNotEqual(a, d);
397     checkNotEqual(a, e);
398     checkNotEqual(b, c);
399     checkNotEqual(b, d);
400     checkNotEqual(b, e);
401     checkNotEqual(c, d);
402     checkNotEqual(c, e);
403     checkNotEqual(d, e);
404   }
405 
406   /**
407    * Asserts that the given field sets are not equal and have different
408    * hash codes.
409    *
410    * @warning It's valid for non-equal objects to have the same hash code, so
411    *   this test is stricter than it needs to be. However, this should happen
412    *   relatively rarely.
413    */
checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2)414   private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
415     String equalsError = String.format("%s should not be equal to %s", s1, s2);
416     assertFalse(equalsError, s1.equals(s2));
417     assertFalse(equalsError, s2.equals(s1));
418 
419     assertFalse(
420         String.format("%s should have a different hash code from %s", s1, s2),
421         s1.hashCode() == s2.hashCode());
422   }
423 
424   /**
425    * Asserts that the given field sets are equal and have identical hash codes.
426    */
checkEqualsIsConsistent(UnknownFieldSet set)427   private void checkEqualsIsConsistent(UnknownFieldSet set) {
428     // Object should be equal to itself.
429     assertEquals(set, set);
430 
431     // Object should be equal to a copy of itself.
432     UnknownFieldSet copy = UnknownFieldSet.newBuilder(set).build();
433     assertEquals(set, copy);
434     assertEquals(copy, set);
435     assertEquals(set.hashCode(), copy.hashCode());
436   }
437 }
438