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