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