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