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 protobuf_unittest.UnittestProto.ForeignMessage;
34 import protobuf_unittest.UnittestProto.TestAllExtensions;
35 import protobuf_unittest.UnittestProto.TestAllTypes;
36 import protobuf_unittest.UnittestProto.TestRequired;
37 import protobuf_unittest.UnittestProto.TestRequiredForeign;
38 import java.util.List;
39 import junit.framework.TestCase;
40 
41 /**
42  * Misc. unit tests for message operations that apply to both generated and dynamic messages.
43  *
44  * @author kenton@google.com Kenton Varda
45  */
46 public class MessageTest extends TestCase {
47   // =================================================================
48   // Message-merging tests.
49 
50   static final TestAllTypes MERGE_SOURCE =
51       TestAllTypes.newBuilder()
52           .setOptionalInt32(1)
53           .setOptionalString("foo")
54           .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
55           .addRepeatedString("bar")
56           .build();
57 
58   static final TestAllTypes MERGE_DEST =
59       TestAllTypes.newBuilder()
60           .setOptionalInt64(2)
61           .setOptionalString("baz")
62           .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
63           .addRepeatedString("qux")
64           .build();
65 
66   static final String MERGE_RESULT_TEXT =
67       ""
68           + "optional_int32: 1\n"
69           + "optional_int64: 2\n"
70           + "optional_string: \"foo\"\n"
71           + "optional_foreign_message {\n"
72           + "  c: 3\n"
73           + "}\n"
74           + "repeated_string: \"qux\"\n"
75           + "repeated_string: \"bar\"\n";
76 
testParsingWithNullExtensionRegistry()77   public void testParsingWithNullExtensionRegistry() throws Exception {
78     try {
79       TestAllTypes.parseFrom(new byte[] {}, null);
80       fail();
81     } catch (NullPointerException expected) {
82     }
83   }
84 
testMergeFrom()85   public void testMergeFrom() throws Exception {
86     TestAllTypes result = TestAllTypes.newBuilder(MERGE_DEST).mergeFrom(MERGE_SOURCE).build();
87 
88     assertEquals(MERGE_RESULT_TEXT, result.toString());
89   }
90 
91   /**
92    * Test merging a DynamicMessage into a GeneratedMessage. As long as they have the same
93    * descriptor, this should work, but it is an entirely different code path.
94    */
testMergeFromDynamic()95   public void testMergeFromDynamic() throws Exception {
96     TestAllTypes result =
97         TestAllTypes.newBuilder(MERGE_DEST)
98             .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
99             .build();
100 
101     assertEquals(MERGE_RESULT_TEXT, result.toString());
102   }
103 
104   /** Test merging two DynamicMessages. */
testDynamicMergeFrom()105   public void testDynamicMergeFrom() throws Exception {
106     DynamicMessage result =
107         DynamicMessage.newBuilder(MERGE_DEST)
108             .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
109             .build();
110 
111     assertEquals(MERGE_RESULT_TEXT, result.toString());
112   }
113 
114   // =================================================================
115   // Required-field-related tests.
116 
117   private static final TestRequired TEST_REQUIRED_UNINITIALIZED = TestRequired.getDefaultInstance();
118   private static final TestRequired TEST_REQUIRED_INITIALIZED =
119       TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
120 
testRequired()121   public void testRequired() throws Exception {
122     TestRequired.Builder builder = TestRequired.newBuilder();
123 
124     assertFalse(builder.isInitialized());
125     builder.setA(1);
126     assertFalse(builder.isInitialized());
127     builder.setB(1);
128     assertFalse(builder.isInitialized());
129     builder.setC(1);
130     assertTrue(builder.isInitialized());
131   }
132 
testRequiredForeign()133   public void testRequiredForeign() throws Exception {
134     TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
135 
136     assertTrue(builder.isInitialized());
137 
138     builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
139     assertFalse(builder.isInitialized());
140 
141     builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
142     assertTrue(builder.isInitialized());
143 
144     builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
145     assertFalse(builder.isInitialized());
146 
147     builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
148     assertTrue(builder.isInitialized());
149   }
150 
testRequiredExtension()151   public void testRequiredExtension() throws Exception {
152     TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
153 
154     assertTrue(builder.isInitialized());
155 
156     builder.setExtension(TestRequired.single, TEST_REQUIRED_UNINITIALIZED);
157     assertFalse(builder.isInitialized());
158 
159     builder.setExtension(TestRequired.single, TEST_REQUIRED_INITIALIZED);
160     assertTrue(builder.isInitialized());
161 
162     builder.addExtension(TestRequired.multi, TEST_REQUIRED_UNINITIALIZED);
163     assertFalse(builder.isInitialized());
164 
165     builder.setExtension(TestRequired.multi, 0, TEST_REQUIRED_INITIALIZED);
166     assertTrue(builder.isInitialized());
167   }
168 
testRequiredDynamic()169   public void testRequiredDynamic() throws Exception {
170     Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
171     DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
172 
173     assertFalse(builder.isInitialized());
174     builder.setField(descriptor.findFieldByName("a"), 1);
175     assertFalse(builder.isInitialized());
176     builder.setField(descriptor.findFieldByName("b"), 1);
177     assertFalse(builder.isInitialized());
178     builder.setField(descriptor.findFieldByName("c"), 1);
179     assertTrue(builder.isInitialized());
180   }
181 
testRequiredDynamicForeign()182   public void testRequiredDynamicForeign() throws Exception {
183     Descriptors.Descriptor descriptor = TestRequiredForeign.getDescriptor();
184     DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
185 
186     assertTrue(builder.isInitialized());
187 
188     builder.setField(descriptor.findFieldByName("optional_message"), TEST_REQUIRED_UNINITIALIZED);
189     assertFalse(builder.isInitialized());
190 
191     builder.setField(descriptor.findFieldByName("optional_message"), TEST_REQUIRED_INITIALIZED);
192     assertTrue(builder.isInitialized());
193 
194     builder.addRepeatedField(
195         descriptor.findFieldByName("repeated_message"), TEST_REQUIRED_UNINITIALIZED);
196     assertFalse(builder.isInitialized());
197 
198     builder.setRepeatedField(
199         descriptor.findFieldByName("repeated_message"), 0, TEST_REQUIRED_INITIALIZED);
200     assertTrue(builder.isInitialized());
201   }
202 
testUninitializedException()203   public void testUninitializedException() throws Exception {
204     try {
205       TestRequired.newBuilder().build();
206       fail("Should have thrown an exception.");
207     } catch (UninitializedMessageException e) {
208       assertEquals("Message missing required fields: a, b, c", e.getMessage());
209     }
210   }
211 
testBuildPartial()212   public void testBuildPartial() throws Exception {
213     // We're mostly testing that no exception is thrown.
214     TestRequired message = TestRequired.newBuilder().buildPartial();
215     assertFalse(message.isInitialized());
216   }
217 
testNestedUninitializedException()218   public void testNestedUninitializedException() throws Exception {
219     try {
220       TestRequiredForeign.newBuilder()
221           .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
222           .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
223           .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
224           .build();
225       fail("Should have thrown an exception.");
226     } catch (UninitializedMessageException e) {
227       assertEquals(
228           "Message missing required fields: "
229               + "optional_message.a, "
230               + "optional_message.b, "
231               + "optional_message.c, "
232               + "repeated_message[0].a, "
233               + "repeated_message[0].b, "
234               + "repeated_message[0].c, "
235               + "repeated_message[1].a, "
236               + "repeated_message[1].b, "
237               + "repeated_message[1].c",
238           e.getMessage());
239     }
240   }
241 
testBuildNestedPartial()242   public void testBuildNestedPartial() throws Exception {
243     // We're mostly testing that no exception is thrown.
244     TestRequiredForeign message =
245         TestRequiredForeign.newBuilder()
246             .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
247             .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
248             .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
249             .buildPartial();
250     assertFalse(message.isInitialized());
251   }
252 
testParseUnititialized()253   public void testParseUnititialized() throws Exception {
254     try {
255       TestRequired.parseFrom(ByteString.EMPTY);
256       fail("Should have thrown an exception.");
257     } catch (InvalidProtocolBufferException e) {
258       assertEquals("Message missing required fields: a, b, c", e.getMessage());
259     }
260   }
261 
testParseNestedUnititialized()262   public void testParseNestedUnititialized() throws Exception {
263     ByteString data =
264         TestRequiredForeign.newBuilder()
265             .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
266             .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
267             .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
268             .buildPartial()
269             .toByteString();
270 
271     try {
272       TestRequiredForeign.parseFrom(data);
273       fail("Should have thrown an exception.");
274     } catch (InvalidProtocolBufferException e) {
275       assertEquals(
276           "Message missing required fields: "
277               + "optional_message.a, "
278               + "optional_message.b, "
279               + "optional_message.c, "
280               + "repeated_message[0].a, "
281               + "repeated_message[0].b, "
282               + "repeated_message[0].c, "
283               + "repeated_message[1].a, "
284               + "repeated_message[1].b, "
285               + "repeated_message[1].c",
286           e.getMessage());
287     }
288   }
289 
testDynamicUninitializedException()290   public void testDynamicUninitializedException() throws Exception {
291     try {
292       DynamicMessage.newBuilder(TestRequired.getDescriptor()).build();
293       fail("Should have thrown an exception.");
294     } catch (UninitializedMessageException e) {
295       assertEquals("Message missing required fields: a, b, c", e.getMessage());
296     }
297   }
298 
testDynamicBuildPartial()299   public void testDynamicBuildPartial() throws Exception {
300     // We're mostly testing that no exception is thrown.
301     DynamicMessage message = DynamicMessage.newBuilder(TestRequired.getDescriptor()).buildPartial();
302     assertFalse(message.isInitialized());
303   }
304 
testDynamicParseUnititialized()305   public void testDynamicParseUnititialized() throws Exception {
306     try {
307       Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
308       DynamicMessage.parseFrom(descriptor, ByteString.EMPTY);
309       fail("Should have thrown an exception.");
310     } catch (InvalidProtocolBufferException e) {
311       assertEquals("Message missing required fields: a, b, c", e.getMessage());
312     }
313   }
314 
315   /** Test reading unset repeated message from DynamicMessage. */
testDynamicRepeatedMessageNull()316   public void testDynamicRepeatedMessageNull() throws Exception {
317     TestRequired.getDescriptor();
318     DynamicMessage result =
319         DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
320             .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
321             .build();
322 
323     assertTrue(
324         result.getField(result.getDescriptorForType().findFieldByName("repeated_foreign_message"))
325             instanceof List<?>);
326     assertEquals(
327         0,
328         result.getRepeatedFieldCount(
329             result.getDescriptorForType().findFieldByName("repeated_foreign_message")));
330   }
331 
332   /** Test reading repeated message from DynamicMessage. */
testDynamicRepeatedMessageNotNull()333   public void testDynamicRepeatedMessageNotNull() throws Exception {
334     TestAllTypes repeatedNested =
335         TestAllTypes.newBuilder()
336             .setOptionalInt32(1)
337             .setOptionalString("foo")
338             .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
339             .addRepeatedString("bar")
340             .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
341             .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
342             .build();
343     TestRequired.getDescriptor();
344     DynamicMessage result =
345         DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
346             .mergeFrom(DynamicMessage.newBuilder(repeatedNested).build())
347             .build();
348 
349     assertTrue(
350         result.getField(result.getDescriptorForType().findFieldByName("repeated_foreign_message"))
351             instanceof List<?>);
352     assertEquals(
353         2,
354         result.getRepeatedFieldCount(
355             result.getDescriptorForType().findFieldByName("repeated_foreign_message")));
356   }
357 }
358