WireFormatTest.java revision d0332953cda33fb4f8e24ebff9c49159b69c43d6
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
31package com.google.protobuf;
32
33import junit.framework.TestCase;
34
35import java.io.ByteArrayInputStream;
36import java.io.ByteArrayOutputStream;
37
38import protobuf_unittest.UnittestProto;
39import protobuf_unittest.UnittestProto.TestAllExtensions;
40import protobuf_unittest.UnittestProto.TestAllTypes;
41import protobuf_unittest.UnittestProto.TestFieldOrderings;
42import protobuf_unittest.UnittestProto.TestPackedExtensions;
43import protobuf_unittest.UnittestProto.TestPackedTypes;
44import protobuf_unittest.UnittestMset.TestMessageSet;
45import protobuf_unittest.UnittestMset.RawMessageSet;
46import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
47import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
48import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
49import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
50
51/**
52 * Tests related to parsing and serialization.
53 *
54 * @author kenton@google.com (Kenton Varda)
55 */
56public class WireFormatTest extends TestCase {
57  public void testSerialization() throws Exception {
58    TestAllTypes message = TestUtil.getAllSet();
59
60    ByteString rawBytes = message.toByteString();
61    assertEquals(rawBytes.size(), message.getSerializedSize());
62
63    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
64
65    TestUtil.assertAllFieldsSet(message2);
66  }
67
68  public void testSerializationPacked() throws Exception {
69    TestPackedTypes message = TestUtil.getPackedSet();
70
71    ByteString rawBytes = message.toByteString();
72    assertEquals(rawBytes.size(), message.getSerializedSize());
73
74    TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
75
76    TestUtil.assertPackedFieldsSet(message2);
77  }
78
79  public void testSerializeExtensions() throws Exception {
80    // TestAllTypes and TestAllExtensions should have compatible wire formats,
81    // so if we serialize a TestAllExtensions then parse it as TestAllTypes
82    // it should work.
83
84    TestAllExtensions message = TestUtil.getAllExtensionsSet();
85    ByteString rawBytes = message.toByteString();
86    assertEquals(rawBytes.size(), message.getSerializedSize());
87
88    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
89
90    TestUtil.assertAllFieldsSet(message2);
91  }
92
93  public void testSerializePackedExtensions() throws Exception {
94    // TestPackedTypes and TestPackedExtensions should have compatible wire
95    // formats; check that they serialize to the same string.
96    TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
97    ByteString rawBytes = message.toByteString();
98
99    TestPackedTypes message2 = TestUtil.getPackedSet();
100    ByteString rawBytes2 = message2.toByteString();
101
102    assertEquals(rawBytes, rawBytes2);
103  }
104
105  public void testSerializationPackedWithoutGetSerializedSize()
106      throws Exception {
107    // Write directly to an OutputStream, without invoking getSerializedSize()
108    // This used to be a bug where the size of a packed field was incorrect,
109    // since getSerializedSize() was never invoked.
110    TestPackedTypes message = TestUtil.getPackedSet();
111
112    // Directly construct a CodedOutputStream around the actual OutputStream,
113    // in case writeTo(OutputStream output) invokes getSerializedSize();
114    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
115    CodedOutputStream codedOutput = CodedOutputStream.newInstance(outputStream);
116
117    message.writeTo(codedOutput);
118
119    codedOutput.flush();
120
121    TestPackedTypes message2 = TestPackedTypes.parseFrom(
122        outputStream.toByteArray());
123
124    TestUtil.assertPackedFieldsSet(message2);
125  }
126
127  public void testSerializeExtensionsLite() throws Exception {
128    // TestAllTypes and TestAllExtensions should have compatible wire formats,
129    // so if we serialize a TestAllExtensions then parse it as TestAllTypes
130    // it should work.
131
132    TestAllExtensionsLite message = TestUtil.getAllLiteExtensionsSet();
133    ByteString rawBytes = message.toByteString();
134    assertEquals(rawBytes.size(), message.getSerializedSize());
135
136    TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
137
138    TestUtil.assertAllFieldsSet(message2);
139  }
140
141  public void testSerializePackedExtensionsLite() throws Exception {
142    // TestPackedTypes and TestPackedExtensions should have compatible wire
143    // formats; check that they serialize to the same string.
144    TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
145    ByteString rawBytes = message.toByteString();
146
147    TestPackedTypes message2 = TestUtil.getPackedSet();
148    ByteString rawBytes2 = message2.toByteString();
149
150    assertEquals(rawBytes, rawBytes2);
151  }
152
153  public void testParseExtensions() throws Exception {
154    // TestAllTypes and TestAllExtensions should have compatible wire formats,
155    // so if we serialize a TestAllTypes then parse it as TestAllExtensions
156    // it should work.
157
158    TestAllTypes message = TestUtil.getAllSet();
159    ByteString rawBytes = message.toByteString();
160
161    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
162
163    TestAllExtensions message2 =
164      TestAllExtensions.parseFrom(rawBytes, registry);
165
166    TestUtil.assertAllExtensionsSet(message2);
167  }
168
169  public void testParsePackedExtensions() throws Exception {
170    // Ensure that packed extensions can be properly parsed.
171    TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
172    ByteString rawBytes = message.toByteString();
173
174    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
175
176    TestPackedExtensions message2 =
177        TestPackedExtensions.parseFrom(rawBytes, registry);
178
179    TestUtil.assertPackedExtensionsSet(message2);
180  }
181
182  public void testParseExtensionsLite() throws Exception {
183    // TestAllTypes and TestAllExtensions should have compatible wire formats,
184    // so if we serialize a TestAllTypes then parse it as TestAllExtensions
185    // it should work.
186
187    TestAllTypes message = TestUtil.getAllSet();
188    ByteString rawBytes = message.toByteString();
189
190    ExtensionRegistryLite registry_lite = TestUtil.getExtensionRegistryLite();
191
192    TestAllExtensionsLite message2 =
193      TestAllExtensionsLite.parseFrom(rawBytes, registry_lite);
194
195    TestUtil.assertAllExtensionsSet(message2);
196
197    // Try again using a full extension registry.
198    ExtensionRegistry registry = TestUtil.getExtensionRegistry();
199
200    TestAllExtensionsLite message3 =
201      TestAllExtensionsLite.parseFrom(rawBytes, registry);
202
203    TestUtil.assertAllExtensionsSet(message3);
204  }
205
206  public void testParsePackedExtensionsLite() throws Exception {
207    // Ensure that packed extensions can be properly parsed.
208    TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
209    ByteString rawBytes = message.toByteString();
210
211    ExtensionRegistryLite registry = TestUtil.getExtensionRegistryLite();
212
213    TestPackedExtensionsLite message2 =
214        TestPackedExtensionsLite.parseFrom(rawBytes, registry);
215
216    TestUtil.assertPackedExtensionsSet(message2);
217  }
218
219  public void testExtensionsSerializedSize() throws Exception {
220    assertEquals(TestUtil.getAllSet().getSerializedSize(),
221                 TestUtil.getAllExtensionsSet().getSerializedSize());
222  }
223
224  public void testSerializeDelimited() throws Exception {
225    ByteArrayOutputStream output = new ByteArrayOutputStream();
226    TestUtil.getAllSet().writeDelimitedTo(output);
227    output.write(12);
228    TestUtil.getPackedSet().writeDelimitedTo(output);
229    output.write(34);
230
231    ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
232
233    TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input));
234    assertEquals(12, input.read());
235    TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input));
236    assertEquals(34, input.read());
237    assertEquals(-1, input.read());
238
239    // We're at EOF, so parsing again should return null.
240    assertTrue(TestAllTypes.parseDelimitedFrom(input) == null);
241  }
242
243  private void assertFieldsInOrder(ByteString data) throws Exception {
244    CodedInputStream input = data.newCodedInput();
245    int previousTag = 0;
246
247    while (true) {
248      int tag = input.readTag();
249      if (tag == 0) {
250        break;
251      }
252
253      assertTrue(tag > previousTag);
254      previousTag = tag;
255      input.skipField(tag);
256    }
257  }
258
259  public void testInterleavedFieldsAndExtensions() throws Exception {
260    // Tests that fields are written in order even when extension ranges
261    // are interleaved with field numbers.
262    ByteString data =
263      TestFieldOrderings.newBuilder()
264        .setMyInt(1)
265        .setMyString("foo")
266        .setMyFloat(1.0F)
267        .setExtension(UnittestProto.myExtensionInt, 23)
268        .setExtension(UnittestProto.myExtensionString, "bar")
269        .build().toByteString();
270    assertFieldsInOrder(data);
271
272    Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
273    ByteString dynamic_data =
274      DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
275        .setField(descriptor.findFieldByName("my_int"), 1L)
276        .setField(descriptor.findFieldByName("my_string"), "foo")
277        .setField(descriptor.findFieldByName("my_float"), 1.0F)
278        .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
279        .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
280        .build().toByteString();
281    assertFieldsInOrder(dynamic_data);
282  }
283
284  private ExtensionRegistry getTestFieldOrderingsRegistry() {
285    ExtensionRegistry result = ExtensionRegistry.newInstance();
286    result.add(UnittestProto.myExtensionInt);
287    result.add(UnittestProto.myExtensionString);
288    return result;
289  }
290
291  public void testParseMultipleExtensionRanges() throws Exception {
292    // Make sure we can parse a message that contains multiple extensions
293    // ranges.
294    TestFieldOrderings source =
295      TestFieldOrderings.newBuilder()
296        .setMyInt(1)
297        .setMyString("foo")
298        .setMyFloat(1.0F)
299        .setExtension(UnittestProto.myExtensionInt, 23)
300        .setExtension(UnittestProto.myExtensionString, "bar")
301        .build();
302    TestFieldOrderings dest =
303      TestFieldOrderings.parseFrom(source.toByteString(),
304                                   getTestFieldOrderingsRegistry());
305    assertEquals(source, dest);
306  }
307
308  public void testParseMultipleExtensionRangesDynamic() throws Exception {
309    // Same as above except with DynamicMessage.
310    Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
311    DynamicMessage source =
312      DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
313        .setField(descriptor.findFieldByName("my_int"), 1L)
314        .setField(descriptor.findFieldByName("my_string"), "foo")
315        .setField(descriptor.findFieldByName("my_float"), 1.0F)
316        .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
317        .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
318        .build();
319    DynamicMessage dest =
320      DynamicMessage.parseFrom(descriptor, source.toByteString(),
321                               getTestFieldOrderingsRegistry());
322    assertEquals(source, dest);
323  }
324
325  private static final int UNKNOWN_TYPE_ID = 1550055;
326  private static final int TYPE_ID_1 =
327    TestMessageSetExtension1.getDescriptor().getExtensions().get(0).getNumber();
328  private static final int TYPE_ID_2 =
329    TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber();
330
331  public void testSerializeMessageSet() throws Exception {
332    // Set up a TestMessageSet with two known messages and an unknown one.
333    TestMessageSet messageSet =
334      TestMessageSet.newBuilder()
335        .setExtension(
336          TestMessageSetExtension1.messageSetExtension,
337          TestMessageSetExtension1.newBuilder().setI(123).build())
338        .setExtension(
339          TestMessageSetExtension2.messageSetExtension,
340          TestMessageSetExtension2.newBuilder().setStr("foo").build())
341        .setUnknownFields(
342          UnknownFieldSet.newBuilder()
343            .addField(UNKNOWN_TYPE_ID,
344              UnknownFieldSet.Field.newBuilder()
345                .addLengthDelimited(ByteString.copyFromUtf8("bar"))
346                .build())
347            .build())
348        .build();
349
350    ByteString data = messageSet.toByteString();
351
352    // Parse back using RawMessageSet and check the contents.
353    RawMessageSet raw = RawMessageSet.parseFrom(data);
354
355    assertTrue(raw.getUnknownFields().asMap().isEmpty());
356
357    assertEquals(3, raw.getItemCount());
358    assertEquals(TYPE_ID_1, raw.getItem(0).getTypeId());
359    assertEquals(TYPE_ID_2, raw.getItem(1).getTypeId());
360    assertEquals(UNKNOWN_TYPE_ID, raw.getItem(2).getTypeId());
361
362    TestMessageSetExtension1 message1 =
363      TestMessageSetExtension1.parseFrom(
364        raw.getItem(0).getMessage().toByteArray());
365    assertEquals(123, message1.getI());
366
367    TestMessageSetExtension2 message2 =
368      TestMessageSetExtension2.parseFrom(
369        raw.getItem(1).getMessage().toByteArray());
370    assertEquals("foo", message2.getStr());
371
372    assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8());
373  }
374
375  public void testParseMessageSet() throws Exception {
376    ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
377    extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
378    extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
379
380    // Set up a RawMessageSet with two known messages and an unknown one.
381    RawMessageSet raw =
382      RawMessageSet.newBuilder()
383        .addItem(
384          RawMessageSet.Item.newBuilder()
385            .setTypeId(TYPE_ID_1)
386            .setMessage(
387              TestMessageSetExtension1.newBuilder()
388                .setI(123)
389                .build().toByteString())
390            .build())
391        .addItem(
392          RawMessageSet.Item.newBuilder()
393            .setTypeId(TYPE_ID_2)
394            .setMessage(
395              TestMessageSetExtension2.newBuilder()
396                .setStr("foo")
397                .build().toByteString())
398            .build())
399        .addItem(
400          RawMessageSet.Item.newBuilder()
401            .setTypeId(UNKNOWN_TYPE_ID)
402            .setMessage(ByteString.copyFromUtf8("bar"))
403            .build())
404        .build();
405
406    ByteString data = raw.toByteString();
407
408    // Parse as a TestMessageSet and check the contents.
409    TestMessageSet messageSet =
410      TestMessageSet.parseFrom(data, extensionRegistry);
411
412    assertEquals(123, messageSet.getExtension(
413      TestMessageSetExtension1.messageSetExtension).getI());
414    assertEquals("foo", messageSet.getExtension(
415      TestMessageSetExtension2.messageSetExtension).getStr());
416
417    // Check for unknown field with type LENGTH_DELIMITED,
418    //   number UNKNOWN_TYPE_ID, and contents "bar".
419    UnknownFieldSet unknownFields = messageSet.getUnknownFields();
420    assertEquals(1, unknownFields.asMap().size());
421    assertTrue(unknownFields.hasField(UNKNOWN_TYPE_ID));
422
423    UnknownFieldSet.Field field = unknownFields.getField(UNKNOWN_TYPE_ID);
424    assertEquals(1, field.getLengthDelimitedList().size());
425    assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8());
426  }
427}
428