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.Descriptor;
34 import com.google.protobuf.Descriptors.FieldDescriptor;
35 import com.google.protobuf.FieldPresenceTestProto.TestAllTypes;
36 import com.google.protobuf.FieldPresenceTestProto.TestOptionalFieldsOnly;
37 import com.google.protobuf.FieldPresenceTestProto.TestRepeatedFieldsOnly;
38 import protobuf_unittest.UnittestProto;
39 
40 import junit.framework.TestCase;
41 
42 /**
43  * Unit tests for protos that doesn't support field presence test for optional
44  * non-message fields.
45  */
46 public class FieldPresenceTest extends TestCase {
hasMethod(Class<?> clazz, String name)47   private static boolean hasMethod(Class<?> clazz, String name) {
48     try {
49       if (clazz.getMethod(name) != null) {
50         return true;
51       } else {
52         return false;
53       }
54     } catch (NoSuchMethodException e) {
55       return false;
56     }
57   }
58 
assertHasMethodRemoved( Class<?> classWithFieldPresence, Class<?> classWithoutFieldPresence, String camelName)59   private static void assertHasMethodRemoved(
60       Class<?> classWithFieldPresence,
61       Class<?> classWithoutFieldPresence,
62       String camelName) {
63     assertTrue(hasMethod(classWithFieldPresence, "get" + camelName));
64     assertTrue(hasMethod(classWithFieldPresence, "has" + camelName));
65     assertTrue(hasMethod(classWithoutFieldPresence, "get" + camelName));
66     assertFalse(hasMethod(classWithoutFieldPresence, "has" + camelName));
67   }
68 
testHasMethod()69   public void testHasMethod() {
70     // Optional non-message fields don't have a hasFoo() method generated.
71     assertHasMethodRemoved(
72         UnittestProto.TestAllTypes.class,
73         TestAllTypes.class,
74         "OptionalInt32");
75     assertHasMethodRemoved(
76         UnittestProto.TestAllTypes.class,
77         TestAllTypes.class,
78         "OptionalString");
79     assertHasMethodRemoved(
80         UnittestProto.TestAllTypes.class,
81         TestAllTypes.class,
82         "OptionalBytes");
83     assertHasMethodRemoved(
84         UnittestProto.TestAllTypes.class,
85         TestAllTypes.class,
86         "OptionalNestedEnum");
87 
88     assertHasMethodRemoved(
89         UnittestProto.TestAllTypes.Builder.class,
90         TestAllTypes.Builder.class,
91         "OptionalInt32");
92     assertHasMethodRemoved(
93         UnittestProto.TestAllTypes.Builder.class,
94         TestAllTypes.Builder.class,
95         "OptionalString");
96     assertHasMethodRemoved(
97         UnittestProto.TestAllTypes.Builder.class,
98         TestAllTypes.Builder.class,
99         "OptionalBytes");
100     assertHasMethodRemoved(
101         UnittestProto.TestAllTypes.Builder.class,
102         TestAllTypes.Builder.class,
103         "OptionalNestedEnum");
104 
105     // message fields still have the hasFoo() method generated.
106     assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage());
107     assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage());
108 
109     // oneof fields don't have hasFoo() methods (even for message types).
110     assertHasMethodRemoved(
111         UnittestProto.TestAllTypes.class,
112         TestAllTypes.class,
113         "OneofUint32");
114     assertHasMethodRemoved(
115         UnittestProto.TestAllTypes.class,
116         TestAllTypes.class,
117         "OneofString");
118     assertHasMethodRemoved(
119         UnittestProto.TestAllTypes.class,
120         TestAllTypes.class,
121         "OneofBytes");
122     assertHasMethodRemoved(
123         UnittestProto.TestAllTypes.class,
124         TestAllTypes.class,
125         "OneofNestedMessage");
126 
127     assertHasMethodRemoved(
128         UnittestProto.TestAllTypes.Builder.class,
129         TestAllTypes.Builder.class,
130         "OneofUint32");
131     assertHasMethodRemoved(
132         UnittestProto.TestAllTypes.Builder.class,
133         TestAllTypes.Builder.class,
134         "OneofString");
135     assertHasMethodRemoved(
136         UnittestProto.TestAllTypes.Builder.class,
137         TestAllTypes.Builder.class,
138         "OneofBytes");
139     assertHasMethodRemoved(
140         UnittestProto.TestAllTypes.Builder.class,
141         TestAllTypes.Builder.class,
142         "OneofNestedMessage");
143   }
144 
testOneofEquals()145   public void testOneofEquals() throws Exception {
146     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
147     TestAllTypes message1 = builder.build();
148     // Set message2's oneof_uint32 field to defalut value. The two
149     // messages should be different when check with oneof case.
150     builder.setOneofUint32(0);
151     TestAllTypes message2 = builder.build();
152     assertFalse(message1.equals(message2));
153   }
154 
testFieldPresence()155   public void testFieldPresence() {
156     // Optional non-message fields set to their default value are treated the
157     // same way as not set.
158 
159     // Serialization will ignore such fields.
160     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
161     builder.setOptionalInt32(0);
162     builder.setOptionalString("");
163     builder.setOptionalBytes(ByteString.EMPTY);
164     builder.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO);
165     TestAllTypes message = builder.build();
166     assertEquals(0, message.getSerializedSize());
167 
168     // mergeFrom() will ignore such fields.
169     TestAllTypes.Builder a = TestAllTypes.newBuilder();
170     a.setOptionalInt32(1);
171     a.setOptionalString("x");
172     a.setOptionalBytes(ByteString.copyFromUtf8("y"));
173     a.setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR);
174     TestAllTypes.Builder b = TestAllTypes.newBuilder();
175     b.setOptionalInt32(0);
176     b.setOptionalString("");
177     b.setOptionalBytes(ByteString.EMPTY);
178     b.setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO);
179     a.mergeFrom(b.build());
180     message = a.build();
181     assertEquals(1, message.getOptionalInt32());
182     assertEquals("x", message.getOptionalString());
183     assertEquals(ByteString.copyFromUtf8("y"), message.getOptionalBytes());
184     assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum());
185 
186     // equals()/hashCode() should produce the same results.
187     TestAllTypes empty = TestAllTypes.newBuilder().build();
188     message = builder.build();
189     assertTrue(empty.equals(message));
190     assertTrue(message.equals(empty));
191     assertEquals(empty.hashCode(), message.hashCode());
192   }
193 
testFieldPresenceByReflection()194   public void testFieldPresenceByReflection() {
195     Descriptor descriptor = TestAllTypes.getDescriptor();
196     FieldDescriptor optionalInt32Field = descriptor.findFieldByName("optional_int32");
197     FieldDescriptor optionalStringField = descriptor.findFieldByName("optional_string");
198     FieldDescriptor optionalBytesField = descriptor.findFieldByName("optional_bytes");
199     FieldDescriptor optionalNestedEnumField = descriptor.findFieldByName("optional_nested_enum");
200 
201     // Field not present.
202     TestAllTypes message = TestAllTypes.newBuilder().build();
203     assertFalse(message.hasField(optionalInt32Field));
204     assertFalse(message.hasField(optionalStringField));
205     assertFalse(message.hasField(optionalBytesField));
206     assertFalse(message.hasField(optionalNestedEnumField));
207     assertEquals(0, message.getAllFields().size());
208 
209     // Field set to default value is seen as not present.
210     message = TestAllTypes.newBuilder()
211         .setOptionalInt32(0)
212         .setOptionalString("")
213         .setOptionalBytes(ByteString.EMPTY)
214         .setOptionalNestedEnum(TestAllTypes.NestedEnum.FOO)
215         .build();
216     assertFalse(message.hasField(optionalInt32Field));
217     assertFalse(message.hasField(optionalStringField));
218     assertFalse(message.hasField(optionalBytesField));
219     assertFalse(message.hasField(optionalNestedEnumField));
220     assertEquals(0, message.getAllFields().size());
221 
222     // Field set to non-default value is seen as present.
223     message = TestAllTypes.newBuilder()
224         .setOptionalInt32(1)
225         .setOptionalString("x")
226         .setOptionalBytes(ByteString.copyFromUtf8("y"))
227         .setOptionalNestedEnum(TestAllTypes.NestedEnum.BAR)
228         .build();
229     assertTrue(message.hasField(optionalInt32Field));
230     assertTrue(message.hasField(optionalStringField));
231     assertTrue(message.hasField(optionalBytesField));
232     assertTrue(message.hasField(optionalNestedEnumField));
233     assertEquals(4, message.getAllFields().size());
234   }
235 
testMessageField()236   public void testMessageField() {
237     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
238     assertFalse(builder.hasOptionalNestedMessage());
239     assertFalse(builder.build().hasOptionalNestedMessage());
240 
241     TestAllTypes.NestedMessage.Builder nestedBuilder =
242         builder.getOptionalNestedMessageBuilder();
243     assertTrue(builder.hasOptionalNestedMessage());
244     assertTrue(builder.build().hasOptionalNestedMessage());
245 
246     nestedBuilder.setValue(1);
247     assertEquals(1, builder.build().getOptionalNestedMessage().getValue());
248 
249     builder.clearOptionalNestedMessage();
250     assertFalse(builder.hasOptionalNestedMessage());
251     assertFalse(builder.build().hasOptionalNestedMessage());
252 
253     // Unlike non-message fields, if we set a message field to its default value (i.e.,
254     // default instance), the field should be seen as present.
255     builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
256     assertTrue(builder.hasOptionalNestedMessage());
257     assertTrue(builder.build().hasOptionalNestedMessage());
258   }
259 
testSerializeAndParse()260   public void testSerializeAndParse() throws Exception {
261     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
262     builder.setOptionalInt32(1234);
263     builder.setOptionalString("hello");
264     builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
265     // Set an oneof field to its default value and expect it to be serialized (i.e.,
266     // an oneof field set to the default value should be treated as present).
267     builder.setOneofInt32(0);
268     ByteString data = builder.build().toByteString();
269 
270     TestAllTypes message = TestAllTypes.parseFrom(data);
271     assertEquals(1234, message.getOptionalInt32());
272     assertEquals("hello", message.getOptionalString());
273     // Fields not set will have the default value.
274     assertEquals(ByteString.EMPTY, message.getOptionalBytes());
275     assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum());
276     // The message field is set despite that it's set with a default instance.
277     assertTrue(message.hasOptionalNestedMessage());
278     assertEquals(0, message.getOptionalNestedMessage().getValue());
279     // The oneof field set to its default value is also present.
280     assertEquals(
281         TestAllTypes.OneofFieldCase.ONEOF_INT32, message.getOneofFieldCase());
282   }
283 
284   // Regression test for b/16173397
285   // Make sure we haven't screwed up the code generation for repeated fields.
testRepeatedFields()286   public void testRepeatedFields() throws Exception {
287     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
288     builder.setOptionalInt32(1234);
289     builder.setOptionalString("hello");
290     builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
291     builder.addRepeatedInt32(4321);
292     builder.addRepeatedString("world");
293     builder.addRepeatedNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance());
294     ByteString data = builder.build().toByteString();
295 
296     TestOptionalFieldsOnly optionalOnlyMessage = TestOptionalFieldsOnly.parseFrom(data);
297     assertEquals(1234, optionalOnlyMessage.getOptionalInt32());
298     assertEquals("hello", optionalOnlyMessage.getOptionalString());
299     assertTrue(optionalOnlyMessage.hasOptionalNestedMessage());
300     assertEquals(0, optionalOnlyMessage.getOptionalNestedMessage().getValue());
301 
302     TestRepeatedFieldsOnly repeatedOnlyMessage = TestRepeatedFieldsOnly.parseFrom(data);
303     assertEquals(1, repeatedOnlyMessage.getRepeatedInt32Count());
304     assertEquals(4321, repeatedOnlyMessage.getRepeatedInt32(0));
305     assertEquals(1, repeatedOnlyMessage.getRepeatedStringCount());
306     assertEquals("world", repeatedOnlyMessage.getRepeatedString(0));
307     assertEquals(1, repeatedOnlyMessage.getRepeatedNestedMessageCount());
308     assertEquals(0, repeatedOnlyMessage.getRepeatedNestedMessage(0).getValue());
309   }
310 
testIsInitialized()311   public void testIsInitialized() throws Exception {
312     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
313 
314     // Test optional proto2 message fields.
315     UnittestProto.TestRequired.Builder proto2Builder =
316         builder.getOptionalProto2MessageBuilder();
317     assertFalse(builder.isInitialized());
318     assertFalse(builder.buildPartial().isInitialized());
319 
320     proto2Builder.setA(1).setB(2).setC(3);
321     assertTrue(builder.isInitialized());
322     assertTrue(builder.buildPartial().isInitialized());
323 
324     // Test oneof proto2 message fields.
325     proto2Builder = builder.getOneofProto2MessageBuilder();
326     assertFalse(builder.isInitialized());
327     assertFalse(builder.buildPartial().isInitialized());
328 
329     proto2Builder.setA(1).setB(2).setC(3);
330     assertTrue(builder.isInitialized());
331     assertTrue(builder.buildPartial().isInitialized());
332 
333     // Test repeated proto2 message fields.
334     proto2Builder = builder.addRepeatedProto2MessageBuilder();
335     assertFalse(builder.isInitialized());
336     assertFalse(builder.buildPartial().isInitialized());
337 
338     proto2Builder.setA(1).setB(2).setC(3);
339     assertTrue(builder.isInitialized());
340     assertTrue(builder.buildPartial().isInitialized());
341   }
342 
343 
344   // Test that unknown fields are dropped.
testUnknownFields()345   public void testUnknownFields() throws Exception {
346     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
347     builder.setOptionalInt32(1234);
348     builder.addRepeatedInt32(5678);
349     TestAllTypes message = builder.build();
350     ByteString data = message.toByteString();
351 
352     TestOptionalFieldsOnly optionalOnlyMessage =
353         TestOptionalFieldsOnly.parseFrom(data);
354     // UnknownFieldSet should be empty.
355     assertEquals(
356         0, optionalOnlyMessage.getUnknownFields().toByteString().size());
357     assertEquals(1234, optionalOnlyMessage.getOptionalInt32());
358     message = TestAllTypes.parseFrom(optionalOnlyMessage.toByteString());
359     assertEquals(1234, message.getOptionalInt32());
360     // The repeated field is discarded because it's unknown to the optional-only
361     // message.
362     assertEquals(0, message.getRepeatedInt32Count());
363 
364     DynamicMessage dynamicOptionalOnlyMessage =
365         DynamicMessage.getDefaultInstance(
366             TestOptionalFieldsOnly.getDescriptor())
367         .getParserForType().parseFrom(data);
368     assertEquals(
369         0, dynamicOptionalOnlyMessage.getUnknownFields().toByteString().size());
370     assertEquals(optionalOnlyMessage.toByteString(),
371         dynamicOptionalOnlyMessage.toByteString());
372   }
373 }
374