• 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 
12 import protobuf_unittest.UnittestMset.RawMessageSet;
13 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
14 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
15 import protobuf_unittest.UnittestProto;
16 import protobuf_unittest.UnittestProto.TestAllExtensions;
17 import protobuf_unittest.UnittestProto.TestAllTypes;
18 import protobuf_unittest.UnittestProto.TestExtensionInsideTable;
19 import protobuf_unittest.UnittestProto.TestFieldOrderings;
20 import protobuf_unittest.UnittestProto.TestOneof2;
21 import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
22 import protobuf_unittest.UnittestProto.TestPackedExtensions;
23 import protobuf_unittest.UnittestProto.TestPackedTypes;
24 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.util.List;
28 import org.junit.After;
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 import org.junit.runners.JUnit4;
32 
33 /** Tests related to parsing and serialization. */
34 @RunWith(JUnit4.class)
35 public class WireFormatTest {
36 
37   private static final int TYPE_ID_1 =
38       TestMessageSetExtension1.getDescriptor().getExtensions().get(0).getNumber();
39   private static final int TYPE_ID_2 =
40       TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber();
41   private static final int UNKNOWN_TYPE_ID = 1550055;
42 
43   @After
tearDown()44   public void tearDown() {
45     // Whether to parse message sets eagerly is stored in a global static. Since some tests modify
46     // the value, make sure to reset it between test runs.
47     ExtensionRegistryLite.setEagerlyParseMessageSets(false);
48   }
49 
50   @Test
testSerialization()51   public void testSerialization() throws Exception {
52     TestAllTypes message = TestUtil.getAllSet();
53 
54     ByteString rawBytes = message.toByteString();
55     assertThat(rawBytes.size()).isEqualTo(message.getSerializedSize());
56 
57     TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
58 
59     TestUtil.assertAllFieldsSet(message2);
60   }
61 
62   @Test
testSerializationPacked()63   public void testSerializationPacked() throws Exception {
64     TestPackedTypes message = TestUtil.getPackedSet();
65 
66     ByteString rawBytes = message.toByteString();
67     assertThat(message.getSerializedSize()).isEqualTo(rawBytes.size());
68 
69     TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
70 
71     TestUtil.assertPackedFieldsSet(message2);
72   }
73 
74   @Test
testSerializeExtensions()75   public void testSerializeExtensions() throws Exception {
76     // TestAllTypes and TestAllExtensions should have compatible wire formats,
77     // so if we serialize a TestAllExtensions then parse it as TestAllTypes
78     // it should work.
79 
80     TestAllExtensions message = TestUtil.getAllExtensionsSet();
81     ByteString rawBytes = message.toByteString();
82     assertThat(message.getSerializedSize()).isEqualTo(rawBytes.size());
83 
84     TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
85 
86     TestUtil.assertAllFieldsSet(message2);
87   }
88 
89   @Test
testSerializePackedExtensions()90   public void testSerializePackedExtensions() throws Exception {
91     // TestPackedTypes and TestPackedExtensions should have compatible wire
92     // formats; check that they serialize to the same string.
93     TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
94     ByteString rawBytes = message.toByteString();
95 
96     TestPackedTypes message2 = TestUtil.getPackedSet();
97     ByteString rawBytes2 = message2.toByteString();
98 
99     assertThat(rawBytes).isEqualTo(rawBytes2);
100   }
101 
102   @Test
testSerializationPackedWithoutGetSerializedSize()103   public void testSerializationPackedWithoutGetSerializedSize() throws Exception {
104     // Write directly to an OutputStream, without invoking getSerializedSize()
105     // This used to be a bug where the size of a packed field was incorrect,
106     // since getSerializedSize() was never invoked.
107     TestPackedTypes message = TestUtil.getPackedSet();
108 
109     // Directly construct a CodedOutputStream around the actual OutputStream,
110     // in case writeTo(OutputStream output) invokes getSerializedSize();
111     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
112     CodedOutputStream codedOutput = CodedOutputStream.newInstance(outputStream);
113 
114     message.writeTo(codedOutput);
115 
116     codedOutput.flush();
117 
118     TestPackedTypes message2 = TestPackedTypes.parseFrom(outputStream.toByteArray());
119 
120     TestUtil.assertPackedFieldsSet(message2);
121   }
122 
123   @Test
testParseExtensions()124   public void testParseExtensions() throws Exception {
125     // TestAllTypes and TestAllExtensions should have compatible wire formats,
126     // so if we serialize a TestAllTypes then parse it as TestAllExtensions
127     // it should work.
128 
129     TestAllTypes message = TestUtil.getAllSet();
130     ByteString rawBytes = message.toByteString();
131 
132     ExtensionRegistryLite registry = TestUtil.getExtensionRegistry();
133 
134     TestAllExtensions message2 = TestAllExtensions.parseFrom(rawBytes, registry);
135 
136     TestUtil.assertAllExtensionsSet(message2);
137   }
138 
139   @Test
testParsePackedExtensions()140   public void testParsePackedExtensions() throws Exception {
141     // Ensure that packed extensions can be properly parsed.
142     TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
143     ByteString rawBytes = message.toByteString();
144 
145     ExtensionRegistryLite registry = TestUtil.getExtensionRegistry();
146 
147     TestPackedExtensions message2 = TestPackedExtensions.parseFrom(rawBytes, registry);
148 
149     TestUtil.assertPackedExtensionsSet(message2);
150   }
151 
152   @Test
testSerializeDelimited()153   public void testSerializeDelimited() throws Exception {
154     ByteArrayOutputStream output = new ByteArrayOutputStream();
155     TestUtil.getAllSet().writeDelimitedTo(output);
156     output.write(12);
157     TestUtil.getPackedSet().writeDelimitedTo(output);
158     output.write(34);
159 
160     ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
161 
162     TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input));
163     assertThat(input.read()).isEqualTo(12);
164     TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input));
165     assertThat(input.read()).isEqualTo(34);
166     assertThat(input.read()).isEqualTo(-1);
167 
168     // We're at EOF, so parsing again should return null.
169     assertThat(TestAllTypes.parseDelimitedFrom(input)).isNull();
170   }
171 
assertFieldsInOrder(ByteString data)172   private void assertFieldsInOrder(ByteString data) throws Exception {
173     CodedInputStream input = data.newCodedInput();
174     int previousTag = 0;
175 
176     while (true) {
177       int tag = input.readTag();
178       if (tag == 0) {
179         break;
180       }
181 
182       assertThat(tag).isGreaterThan(previousTag);
183       previousTag = tag;
184       input.skipField(tag);
185     }
186   }
187 
188   @Test
testInterleavedFieldsAndExtensions()189   public void testInterleavedFieldsAndExtensions() throws Exception {
190     // Tests that fields are written in order even when extension ranges
191     // are interleaved with field numbers.
192     ByteString data =
193         TestFieldOrderings.newBuilder()
194             .setMyInt(1)
195             .setMyString("foo")
196             .setMyFloat(1.0F)
197             .setExtension(UnittestProto.myExtensionInt, 23)
198             .setExtension(UnittestProto.myExtensionString, "bar")
199             .build()
200             .toByteString();
201     assertFieldsInOrder(data);
202 
203     Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
204     ByteString dynamicData =
205         DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
206             .setField(descriptor.findFieldByName("my_int"), 1L)
207             .setField(descriptor.findFieldByName("my_string"), "foo")
208             .setField(descriptor.findFieldByName("my_float"), 1.0F)
209             .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
210             .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
211             .build()
212             .toByteString();
213     assertFieldsInOrder(dynamicData);
214   }
215 
getTestFieldOrderingsRegistry()216   private ExtensionRegistry getTestFieldOrderingsRegistry() {
217     ExtensionRegistry result = ExtensionRegistry.newInstance();
218     result.add(UnittestProto.myExtensionInt);
219     result.add(UnittestProto.myExtensionString);
220     return result;
221   }
222 
223   @Test
testParseMultipleExtensionRanges()224   public void testParseMultipleExtensionRanges() throws Exception {
225     // Make sure we can parse a message that contains multiple extensions
226     // ranges.
227     TestFieldOrderings source =
228         TestFieldOrderings.newBuilder()
229             .setMyInt(1)
230             .setMyString("foo")
231             .setMyFloat(1.0F)
232             .setExtension(UnittestProto.myExtensionInt, 23)
233             .setExtension(UnittestProto.myExtensionString, "bar")
234             .build();
235     TestFieldOrderings dest =
236         TestFieldOrderings.parseFrom(source.toByteString(), getTestFieldOrderingsRegistry());
237     assertThat(source).isEqualTo(dest);
238   }
239 
getTestExtensionInsideTableRegistry()240   private static ExtensionRegistry getTestExtensionInsideTableRegistry() {
241     ExtensionRegistry result = ExtensionRegistry.newInstance();
242     result.add(UnittestProto.testExtensionInsideTableExtension);
243     return result;
244   }
245 
246   @Test
testExtensionInsideTable()247   public void testExtensionInsideTable() throws Exception {
248     // Make sure the extension within the range of table is parsed correctly in experimental
249     // runtime.
250     TestExtensionInsideTable source =
251         TestExtensionInsideTable.newBuilder()
252             .setField1(1)
253             .setExtension(UnittestProto.testExtensionInsideTableExtension, 23)
254             .build();
255     TestExtensionInsideTable dest =
256         TestExtensionInsideTable.parseFrom(
257             source.toByteString(), getTestExtensionInsideTableRegistry());
258     assertThat(source).isEqualTo(dest);
259   }
260 
261   @Test
testParseMultipleExtensionRangesDynamic()262   public void testParseMultipleExtensionRangesDynamic() throws Exception {
263     // Same as above except with DynamicMessage.
264     Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
265     DynamicMessage source =
266         DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
267             .setField(descriptor.findFieldByName("my_int"), 1L)
268             .setField(descriptor.findFieldByName("my_string"), "foo")
269             .setField(descriptor.findFieldByName("my_float"), 1.0F)
270             .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
271             .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
272             .build();
273     DynamicMessage dest =
274         DynamicMessage.parseFrom(
275             descriptor, source.toByteString(), getTestFieldOrderingsRegistry());
276     assertThat(source).isEqualTo(dest);
277   }
278 
279   @Test
testSerializeMessageSetEagerly()280   public void testSerializeMessageSetEagerly() throws Exception {
281     testSerializeMessageSetWithFlag(true);
282   }
283 
284   @Test
testSerializeMessageSetNotEagerly()285   public void testSerializeMessageSetNotEagerly() throws Exception {
286     testSerializeMessageSetWithFlag(false);
287   }
288 
testSerializeMessageSetWithFlag(boolean eagerParsing)289   private void testSerializeMessageSetWithFlag(boolean eagerParsing) throws Exception {
290     ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
291     // Set up a TestMessageSet with two known messages and an unknown one.
292     TestMessageSet messageSet =
293         TestMessageSet.newBuilder()
294             .setExtension(
295                 TestMessageSetExtension1.messageSetExtension,
296                 TestMessageSetExtension1.newBuilder().setI(123).build())
297             .setExtension(
298                 TestMessageSetExtension2.messageSetExtension,
299                 TestMessageSetExtension2.newBuilder().setStr("foo").build())
300             .setUnknownFields(
301                 UnknownFieldSet.newBuilder()
302                     .addField(
303                         UNKNOWN_TYPE_ID,
304                         UnknownFieldSet.Field.newBuilder()
305                             .addLengthDelimited(ByteString.copyFromUtf8("bar"))
306                             .build())
307                     .build())
308             .build();
309 
310     ByteString data = messageSet.toByteString();
311 
312     // Parse back using RawMessageSet and check the contents.
313     RawMessageSet raw = RawMessageSet.parseFrom(data);
314 
315     assertThat(raw.getUnknownFields().asMap()).isEmpty();
316 
317     assertThat(raw.getItemCount()).isEqualTo(3);
318     assertThat(raw.getItem(0).getTypeId()).isEqualTo(TYPE_ID_1);
319     assertThat(raw.getItem(1).getTypeId()).isEqualTo(TYPE_ID_2);
320     assertThat(raw.getItem(2).getTypeId()).isEqualTo(UNKNOWN_TYPE_ID);
321 
322     TestMessageSetExtension1 message1 =
323         TestMessageSetExtension1.parseFrom(raw.getItem(0).getMessage());
324     assertThat(message1.getI()).isEqualTo(123);
325 
326     TestMessageSetExtension2 message2 =
327         TestMessageSetExtension2.parseFrom(raw.getItem(1).getMessage());
328     assertThat(message2.getStr()).isEqualTo("foo");
329 
330     assertThat(raw.getItem(2).getMessage().toStringUtf8()).isEqualTo("bar");
331   }
332 
333   @Test
testParseMessageSetEagerly()334   public void testParseMessageSetEagerly() throws Exception {
335     testParseMessageSetWithFlag(true);
336   }
337 
338   @Test
testParseMessageSetNotEagerly()339   public void testParseMessageSetNotEagerly() throws Exception {
340     testParseMessageSetWithFlag(false);
341   }
342 
testParseMessageSetWithFlag(boolean eagerParsing)343   private void testParseMessageSetWithFlag(boolean eagerParsing) throws Exception {
344     ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
345     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
346     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
347     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
348 
349     // Set up a RawMessageSet with two known messages and an unknown one.
350     RawMessageSet raw =
351         RawMessageSet.newBuilder()
352             .addItem(
353                 RawMessageSet.Item.newBuilder()
354                     .setTypeId(TYPE_ID_1)
355                     .setMessage(
356                         TestMessageSetExtension1.newBuilder().setI(123).build().toByteString())
357                     .build())
358             .addItem(
359                 RawMessageSet.Item.newBuilder()
360                     .setTypeId(TYPE_ID_2)
361                     .setMessage(
362                         TestMessageSetExtension2.newBuilder().setStr("foo").build().toByteString())
363                     .build())
364             .addItem(
365                 RawMessageSet.Item.newBuilder()
366                     .setTypeId(UNKNOWN_TYPE_ID)
367                     .setMessage(ByteString.copyFromUtf8("bar"))
368                     .build())
369             .build();
370 
371     ByteString data = raw.toByteString();
372 
373     // Parse as a TestMessageSet and check the contents.
374     TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry);
375 
376     assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
377         .isEqualTo(123);
378     assertThat(messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr())
379         .isEqualTo("foo");
380 
381     // Check for unknown field with type LENGTH_DELIMITED,
382     //   number UNKNOWN_TYPE_ID, and contents "bar".
383     UnknownFieldSet unknownFields = messageSet.getUnknownFields();
384     assertThat(unknownFields.asMap()).hasSize(1);
385     assertThat(unknownFields.hasField(UNKNOWN_TYPE_ID)).isTrue();
386 
387     UnknownFieldSet.Field field = unknownFields.getField(UNKNOWN_TYPE_ID);
388     assertThat(field.getLengthDelimitedList()).hasSize(1);
389     assertThat(field.getLengthDelimitedList().get(0).toStringUtf8()).isEqualTo("bar");
390   }
391 
392   @Test
testParseMessageSetExtensionEagerly()393   public void testParseMessageSetExtensionEagerly() throws Exception {
394     testParseMessageSetExtensionWithFlag(true);
395   }
396 
397   @Test
testParseMessageSetExtensionNotEagerly()398   public void testParseMessageSetExtensionNotEagerly() throws Exception {
399     testParseMessageSetExtensionWithFlag(false);
400   }
401 
testParseMessageSetExtensionWithFlag(boolean eagerParsing)402   private void testParseMessageSetExtensionWithFlag(boolean eagerParsing) throws Exception {
403     ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
404     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
405     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
406 
407     // Set up a RawMessageSet with a known messages.
408     RawMessageSet raw =
409         RawMessageSet.newBuilder()
410             .addItem(
411                 RawMessageSet.Item.newBuilder()
412                     .setTypeId(TYPE_ID_1)
413                     .setMessage(
414                         TestMessageSetExtension1.newBuilder().setI(123).build().toByteString())
415                     .build())
416             .build();
417 
418     ByteString data = raw.toByteString();
419 
420     // Parse as a TestMessageSet and check the contents.
421     TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry);
422     assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
423         .isEqualTo(123);
424   }
425 
426   @Test
testMergeLazyMessageSetExtensionEagerly()427   public void testMergeLazyMessageSetExtensionEagerly() throws Exception {
428     testMergeLazyMessageSetExtensionWithFlag(true);
429   }
430 
431   @Test
testMergeLazyMessageSetExtensionNotEagerly()432   public void testMergeLazyMessageSetExtensionNotEagerly() throws Exception {
433     testMergeLazyMessageSetExtensionWithFlag(false);
434   }
435 
testMergeLazyMessageSetExtensionWithFlag(boolean eagerParsing)436   private void testMergeLazyMessageSetExtensionWithFlag(boolean eagerParsing) throws Exception {
437     ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
438     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
439     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
440 
441     // Set up a RawMessageSet with a known messages.
442     RawMessageSet raw =
443         RawMessageSet.newBuilder()
444             .addItem(
445                 RawMessageSet.Item.newBuilder()
446                     .setTypeId(TYPE_ID_1)
447                     .setMessage(
448                         TestMessageSetExtension1.newBuilder().setI(123).build().toByteString())
449                     .build())
450             .build();
451 
452     ByteString data = raw.toByteString();
453 
454     // Parse as a TestMessageSet and store value into lazy field
455     TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry);
456     // Merge lazy field check the contents.
457     messageSet = messageSet.toBuilder().mergeFrom(data, extensionRegistry).build();
458     assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
459         .isEqualTo(123);
460   }
461 
462   @Test
testMergeMessageSetExtensionEagerly()463   public void testMergeMessageSetExtensionEagerly() throws Exception {
464     testMergeMessageSetExtensionWithFlag(true);
465   }
466 
467   @Test
testMergeMessageSetExtensionNotEagerly()468   public void testMergeMessageSetExtensionNotEagerly() throws Exception {
469     testMergeMessageSetExtensionWithFlag(false);
470   }
471 
testMergeMessageSetExtensionWithFlag(boolean eagerParsing)472   private void testMergeMessageSetExtensionWithFlag(boolean eagerParsing) throws Exception {
473     ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
474     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
475     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
476 
477     // Set up a RawMessageSet with a known messages.
478     RawMessageSet raw =
479         RawMessageSet.newBuilder()
480             .addItem(
481                 RawMessageSet.Item.newBuilder()
482                     .setTypeId(TYPE_ID_1)
483                     .setMessage(
484                         TestMessageSetExtension1.newBuilder().setI(123).build().toByteString())
485                     .build())
486             .build();
487 
488     // Serialize RawMessageSet unnormally (message value before type id)
489     ByteString.CodedBuilder out = ByteString.newCodedBuilder(raw.getSerializedSize());
490     CodedOutputStream output = out.getCodedOutput();
491     List<RawMessageSet.Item> items = raw.getItemList();
492     for (int i = 0; i < items.size(); i++) {
493       RawMessageSet.Item item = items.get(i);
494       output.writeTag(1, WireFormat.WIRETYPE_START_GROUP);
495       output.writeBytes(3, item.getMessage());
496       output.writeInt32(2, item.getTypeId());
497       output.writeTag(1, WireFormat.WIRETYPE_END_GROUP);
498     }
499     ByteString data = out.build();
500 
501     // Merge bytes into TestMessageSet and check the contents.
502     TestMessageSet messageSet =
503         TestMessageSet.newBuilder().mergeFrom(data, extensionRegistry).build();
504     assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI())
505         .isEqualTo(123);
506   }
507 
508   // ================================================================
509   // oneof
510   @Test
testOneofWireFormat()511   public void testOneofWireFormat() throws Exception {
512     TestOneof2.Builder builder = TestOneof2.newBuilder();
513     TestUtil.setOneof(builder);
514     TestOneof2 message = builder.build();
515     ByteString rawBytes = message.toByteString();
516 
517     assertThat(message.getSerializedSize()).isEqualTo(rawBytes.size());
518 
519     TestOneof2 message2 = TestOneof2.parseFrom(rawBytes);
520     TestUtil.assertOneofSet(message2);
521   }
522 
523   @Test
testOneofOnlyLastSet()524   public void testOneofOnlyLastSet() throws Exception {
525     TestOneofBackwardsCompatible source =
526         TestOneofBackwardsCompatible.newBuilder().setFooInt(100).setFooString("101").build();
527 
528     ByteString rawBytes = source.toByteString();
529     TestOneof2 message = TestOneof2.parseFrom(rawBytes);
530     assertThat(message.hasFooInt()).isFalse();
531     assertThat(message.hasFooString()).isTrue();
532   }
533 }
534