• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.UnittestOptimizeFor.TestOptimizedForSize;
34 import protobuf_unittest.UnittestProto;
35 import protobuf_unittest.UnittestProto.ForeignMessage;
36 import protobuf_unittest.UnittestProto.TestAllExtensions;
37 import protobuf_unittest.UnittestProto.TestAllTypes;
38 import protobuf_unittest.UnittestProto.TestPackedTypes;
39 import protobuf_unittest.UnittestProto.TestRequired;
40 import protobuf_unittest.UnittestProto.TestRequiredForeign;
41 import protobuf_unittest.UnittestProto.TestUnpackedTypes;
42 
43 import junit.framework.TestCase;
44 
45 import java.util.Map;
46 
47 /**
48  * Unit test for {@link AbstractMessage}.
49  *
50  * @author kenton@google.com Kenton Varda
51  */
52 public class AbstractMessageTest extends TestCase {
53   /**
54    * Extends AbstractMessage and wraps some other message object.  The methods
55    * of the Message interface which aren't explicitly implemented by
56    * AbstractMessage are forwarded to the wrapped object.  This allows us to
57    * test that AbstractMessage's implementations work even if the wrapped
58    * object does not use them.
59    */
60   private static class AbstractMessageWrapper extends AbstractMessage {
61     private final Message wrappedMessage;
62 
AbstractMessageWrapper(Message wrappedMessage)63     public AbstractMessageWrapper(Message wrappedMessage) {
64       this.wrappedMessage = wrappedMessage;
65     }
66 
getDescriptorForType()67     public Descriptors.Descriptor getDescriptorForType() {
68       return wrappedMessage.getDescriptorForType();
69     }
getDefaultInstanceForType()70     public AbstractMessageWrapper getDefaultInstanceForType() {
71       return new AbstractMessageWrapper(
72         wrappedMessage.getDefaultInstanceForType());
73     }
getAllFields()74     public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
75       return wrappedMessage.getAllFields();
76     }
hasField(Descriptors.FieldDescriptor field)77     public boolean hasField(Descriptors.FieldDescriptor field) {
78       return wrappedMessage.hasField(field);
79     }
getField(Descriptors.FieldDescriptor field)80     public Object getField(Descriptors.FieldDescriptor field) {
81       return wrappedMessage.getField(field);
82     }
getRepeatedFieldCount(Descriptors.FieldDescriptor field)83     public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
84       return wrappedMessage.getRepeatedFieldCount(field);
85     }
getRepeatedField( Descriptors.FieldDescriptor field, int index)86     public Object getRepeatedField(
87         Descriptors.FieldDescriptor field, int index) {
88       return wrappedMessage.getRepeatedField(field, index);
89     }
getUnknownFields()90     public UnknownFieldSet getUnknownFields() {
91       return wrappedMessage.getUnknownFields();
92     }
newBuilderForType()93     public Builder newBuilderForType() {
94       return new Builder(wrappedMessage.newBuilderForType());
95     }
toBuilder()96     public Builder toBuilder() {
97       return new Builder(wrappedMessage.toBuilder());
98     }
99 
100     static class Builder extends AbstractMessage.Builder<Builder> {
101       private final Message.Builder wrappedBuilder;
102 
Builder(Message.Builder wrappedBuilder)103       public Builder(Message.Builder wrappedBuilder) {
104         this.wrappedBuilder = wrappedBuilder;
105       }
106 
build()107       public AbstractMessageWrapper build() {
108         return new AbstractMessageWrapper(wrappedBuilder.build());
109       }
buildPartial()110       public AbstractMessageWrapper buildPartial() {
111         return new AbstractMessageWrapper(wrappedBuilder.buildPartial());
112       }
clone()113       public Builder clone() {
114         return new Builder(wrappedBuilder.clone());
115       }
isInitialized()116       public boolean isInitialized() {
117         return clone().buildPartial().isInitialized();
118       }
getDescriptorForType()119       public Descriptors.Descriptor getDescriptorForType() {
120         return wrappedBuilder.getDescriptorForType();
121       }
getDefaultInstanceForType()122       public AbstractMessageWrapper getDefaultInstanceForType() {
123         return new AbstractMessageWrapper(
124           wrappedBuilder.getDefaultInstanceForType());
125       }
getAllFields()126       public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
127         return wrappedBuilder.getAllFields();
128       }
newBuilderForField(Descriptors.FieldDescriptor field)129       public Builder newBuilderForField(Descriptors.FieldDescriptor field) {
130         return new Builder(wrappedBuilder.newBuilderForField(field));
131       }
hasField(Descriptors.FieldDescriptor field)132       public boolean hasField(Descriptors.FieldDescriptor field) {
133         return wrappedBuilder.hasField(field);
134       }
getField(Descriptors.FieldDescriptor field)135       public Object getField(Descriptors.FieldDescriptor field) {
136         return wrappedBuilder.getField(field);
137       }
setField(Descriptors.FieldDescriptor field, Object value)138       public Builder setField(Descriptors.FieldDescriptor field, Object value) {
139         wrappedBuilder.setField(field, value);
140         return this;
141       }
clearField(Descriptors.FieldDescriptor field)142       public Builder clearField(Descriptors.FieldDescriptor field) {
143         wrappedBuilder.clearField(field);
144         return this;
145       }
getRepeatedFieldCount(Descriptors.FieldDescriptor field)146       public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
147         return wrappedBuilder.getRepeatedFieldCount(field);
148       }
getRepeatedField( Descriptors.FieldDescriptor field, int index)149       public Object getRepeatedField(
150           Descriptors.FieldDescriptor field, int index) {
151         return wrappedBuilder.getRepeatedField(field, index);
152       }
setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value)153       public Builder setRepeatedField(Descriptors.FieldDescriptor field,
154                                       int index, Object value) {
155         wrappedBuilder.setRepeatedField(field, index, value);
156         return this;
157       }
addRepeatedField( Descriptors.FieldDescriptor field, Object value)158       public Builder addRepeatedField(
159           Descriptors.FieldDescriptor field, Object value) {
160         wrappedBuilder.addRepeatedField(field, value);
161         return this;
162       }
getUnknownFields()163       public UnknownFieldSet getUnknownFields() {
164         return wrappedBuilder.getUnknownFields();
165       }
setUnknownFields(UnknownFieldSet unknownFields)166       public Builder setUnknownFields(UnknownFieldSet unknownFields) {
167         wrappedBuilder.setUnknownFields(unknownFields);
168         return this;
169       }
170     }
171   }
172 
173   // =================================================================
174 
175   TestUtil.ReflectionTester reflectionTester =
176     new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
177 
178   TestUtil.ReflectionTester extensionsReflectionTester =
179     new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
180                                   TestUtil.getExtensionRegistry());
181 
testClear()182   public void testClear() throws Exception {
183     AbstractMessageWrapper message =
184       new AbstractMessageWrapper.Builder(
185           TestAllTypes.newBuilder(TestUtil.getAllSet()))
186         .clear().build();
187     TestUtil.assertClear((TestAllTypes) message.wrappedMessage);
188   }
189 
testCopy()190   public void testCopy() throws Exception {
191     AbstractMessageWrapper message =
192       new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder())
193         .mergeFrom(TestUtil.getAllSet()).build();
194     TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
195   }
196 
testSerializedSize()197   public void testSerializedSize() throws Exception {
198     TestAllTypes message = TestUtil.getAllSet();
199     Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
200 
201     assertEquals(message.getSerializedSize(),
202                  abstractMessage.getSerializedSize());
203   }
204 
testSerialization()205   public void testSerialization() throws Exception {
206     Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
207 
208     TestUtil.assertAllFieldsSet(
209       TestAllTypes.parseFrom(abstractMessage.toByteString()));
210 
211     assertEquals(TestUtil.getAllSet().toByteString(),
212                  abstractMessage.toByteString());
213   }
214 
testParsing()215   public void testParsing() throws Exception {
216     AbstractMessageWrapper.Builder builder =
217       new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder());
218     AbstractMessageWrapper message =
219       builder.mergeFrom(TestUtil.getAllSet().toByteString()).build();
220     TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
221   }
222 
testPackedSerialization()223   public void testPackedSerialization() throws Exception {
224     Message abstractMessage =
225         new AbstractMessageWrapper(TestUtil.getPackedSet());
226 
227     TestUtil.assertPackedFieldsSet(
228       TestPackedTypes.parseFrom(abstractMessage.toByteString()));
229 
230     assertEquals(TestUtil.getPackedSet().toByteString(),
231                  abstractMessage.toByteString());
232   }
233 
testPackedParsing()234   public void testPackedParsing() throws Exception {
235     AbstractMessageWrapper.Builder builder =
236       new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
237     AbstractMessageWrapper message =
238       builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
239     TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
240   }
241 
testUnpackedSerialization()242   public void testUnpackedSerialization() throws Exception {
243     Message abstractMessage =
244       new AbstractMessageWrapper(TestUtil.getUnpackedSet());
245 
246     TestUtil.assertUnpackedFieldsSet(
247       TestUnpackedTypes.parseFrom(abstractMessage.toByteString()));
248 
249     assertEquals(TestUtil.getUnpackedSet().toByteString(),
250                  abstractMessage.toByteString());
251   }
252 
testParsePackedToUnpacked()253   public void testParsePackedToUnpacked() throws Exception {
254     AbstractMessageWrapper.Builder builder =
255       new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
256     AbstractMessageWrapper message =
257       builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
258     TestUtil.assertUnpackedFieldsSet(
259       (TestUnpackedTypes) message.wrappedMessage);
260   }
261 
testParseUnpackedToPacked()262   public void testParseUnpackedToPacked() throws Exception {
263     AbstractMessageWrapper.Builder builder =
264       new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
265     AbstractMessageWrapper message =
266       builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
267     TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
268   }
269 
testUnpackedParsing()270   public void testUnpackedParsing() throws Exception {
271     AbstractMessageWrapper.Builder builder =
272       new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
273     AbstractMessageWrapper message =
274       builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
275     TestUtil.assertUnpackedFieldsSet(
276       (TestUnpackedTypes) message.wrappedMessage);
277   }
278 
testOptimizedForSize()279   public void testOptimizedForSize() throws Exception {
280     // We're mostly only checking that this class was compiled successfully.
281     TestOptimizedForSize message =
282       TestOptimizedForSize.newBuilder().setI(1).build();
283     message = TestOptimizedForSize.parseFrom(message.toByteString());
284     assertEquals(2, message.getSerializedSize());
285   }
286 
287   // -----------------------------------------------------------------
288   // Tests for isInitialized().
289 
290   private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
291     TestRequired.getDefaultInstance();
292   private static final TestRequired TEST_REQUIRED_INITIALIZED =
293     TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
294 
testIsInitialized()295   public void testIsInitialized() throws Exception {
296     TestRequired.Builder builder = TestRequired.newBuilder();
297     AbstractMessageWrapper.Builder abstractBuilder =
298       new AbstractMessageWrapper.Builder(builder);
299 
300     assertFalse(abstractBuilder.isInitialized());
301     builder.setA(1);
302     assertFalse(abstractBuilder.isInitialized());
303     builder.setB(1);
304     assertFalse(abstractBuilder.isInitialized());
305     builder.setC(1);
306     assertTrue(abstractBuilder.isInitialized());
307   }
308 
testForeignIsInitialized()309   public void testForeignIsInitialized() throws Exception {
310     TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
311     AbstractMessageWrapper.Builder abstractBuilder =
312       new AbstractMessageWrapper.Builder(builder);
313 
314     assertTrue(abstractBuilder.isInitialized());
315 
316     builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
317     assertFalse(abstractBuilder.isInitialized());
318 
319     builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
320     assertTrue(abstractBuilder.isInitialized());
321 
322     builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
323     assertFalse(abstractBuilder.isInitialized());
324 
325     builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
326     assertTrue(abstractBuilder.isInitialized());
327   }
328 
329   // -----------------------------------------------------------------
330   // Tests for mergeFrom
331 
332   static final TestAllTypes MERGE_SOURCE =
333     TestAllTypes.newBuilder()
334       .setOptionalInt32(1)
335       .setOptionalString("foo")
336       .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
337       .addRepeatedString("bar")
338       .build();
339 
340   static final TestAllTypes MERGE_DEST =
341     TestAllTypes.newBuilder()
342       .setOptionalInt64(2)
343       .setOptionalString("baz")
344       .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
345       .addRepeatedString("qux")
346       .build();
347 
348   static final String MERGE_RESULT_TEXT =
349       "optional_int32: 1\n" +
350       "optional_int64: 2\n" +
351       "optional_string: \"foo\"\n" +
352       "optional_foreign_message {\n" +
353       "  c: 3\n" +
354       "}\n" +
355       "repeated_string: \"qux\"\n" +
356       "repeated_string: \"bar\"\n";
357 
testMergeFrom()358   public void testMergeFrom() throws Exception {
359     AbstractMessageWrapper result =
360       new AbstractMessageWrapper.Builder(
361         TestAllTypes.newBuilder(MERGE_DEST))
362       .mergeFrom(MERGE_SOURCE).build();
363 
364     assertEquals(MERGE_RESULT_TEXT, result.toString());
365   }
366 
367   // -----------------------------------------------------------------
368   // Tests for equals and hashCode
369 
testEqualsAndHashCode()370   public void testEqualsAndHashCode() throws Exception {
371     TestAllTypes a = TestUtil.getAllSet();
372     TestAllTypes b = TestAllTypes.newBuilder().build();
373     TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build();
374     TestAllTypes d = TestAllTypes.newBuilder(c).addRepeatedString("y").build();
375     TestAllExtensions e = TestUtil.getAllExtensionsSet();
376     TestAllExtensions f = TestAllExtensions.newBuilder(e)
377         .addExtension(UnittestProto.repeatedInt32Extension, 999).build();
378 
379     checkEqualsIsConsistent(a);
380     checkEqualsIsConsistent(b);
381     checkEqualsIsConsistent(c);
382     checkEqualsIsConsistent(d);
383     checkEqualsIsConsistent(e);
384     checkEqualsIsConsistent(f);
385 
386     checkNotEqual(a, b);
387     checkNotEqual(a, c);
388     checkNotEqual(a, d);
389     checkNotEqual(a, e);
390     checkNotEqual(a, f);
391 
392     checkNotEqual(b, c);
393     checkNotEqual(b, d);
394     checkNotEqual(b, e);
395     checkNotEqual(b, f);
396 
397     checkNotEqual(c, d);
398     checkNotEqual(c, e);
399     checkNotEqual(c, f);
400 
401     checkNotEqual(d, e);
402     checkNotEqual(d, f);
403 
404     checkNotEqual(e, f);
405 
406     // Deserializing into the TestEmptyMessage such that every field
407     // is an {@link UnknownFieldSet.Field}.
408     UnittestProto.TestEmptyMessage eUnknownFields =
409         UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
410     UnittestProto.TestEmptyMessage fUnknownFields =
411         UnittestProto.TestEmptyMessage.parseFrom(f.toByteArray());
412     checkNotEqual(eUnknownFields, fUnknownFields);
413     checkEqualsIsConsistent(eUnknownFields);
414     checkEqualsIsConsistent(fUnknownFields);
415 
416     // Subseqent reconstitutions should be identical
417     UnittestProto.TestEmptyMessage eUnknownFields2 =
418         UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
419     checkEqualsIsConsistent(eUnknownFields, eUnknownFields2);
420   }
421 
422   /**
423    * Asserts that the given proto has symetric equals and hashCode methods.
424    */
checkEqualsIsConsistent(Message message)425   private void checkEqualsIsConsistent(Message message) {
426     // Object should be equal to itself.
427     assertEquals(message, message);
428 
429     // Object should be equal to a dynamic copy of itself.
430     DynamicMessage dynamic = DynamicMessage.newBuilder(message).build();
431     checkEqualsIsConsistent(message, dynamic);
432   }
433 
434   /**
435    * Asserts that the given protos are equal and have the same hash code.
436    */
checkEqualsIsConsistent(Message message1, Message message2)437   private void checkEqualsIsConsistent(Message message1, Message message2) {
438     assertEquals(message1, message2);
439     assertEquals(message2, message1);
440     assertEquals(message2.hashCode(), message1.hashCode());
441   }
442 
443   /**
444    * Asserts that the given protos are not equal and have different hash codes.
445    *
446    * @warning It's valid for non-equal objects to have the same hash code, so
447    *   this test is stricter than it needs to be. However, this should happen
448    *   relatively rarely.
449    */
checkNotEqual(Message m1, Message m2)450   private void checkNotEqual(Message m1, Message m2) {
451     String equalsError = String.format("%s should not be equal to %s", m1, m2);
452     assertFalse(equalsError, m1.equals(m2));
453     assertFalse(equalsError, m2.equals(m1));
454 
455     assertFalse(
456         String.format("%s should have a different hash code from %s", m1, m2),
457         m1.hashCode() == m2.hashCode());
458   }
459 }
460