1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // http://code.google.com/p/protobuf/ 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; 34 import protobuf_unittest.UnittestProto.TestAllExtensions; 35 import protobuf_unittest.UnittestProto.TestAllTypes; 36 import protobuf_unittest.UnittestProto.TestEmptyMessage; 37 import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions; 38 39 import junit.framework.TestCase; 40 41 import java.util.Arrays; 42 import java.util.Map; 43 44 /** 45 * Tests related to unknown field handling. 46 * 47 * @author kenton (at) google.com (Kenton Varda) 48 */ 49 public class UnknownFieldSetTest extends TestCase { 50 public void setUp() throws Exception { 51 descriptor = TestAllTypes.getDescriptor(); 52 allFields = TestUtil.getAllSet(); 53 allFieldsData = allFields.toByteString(); 54 emptyMessage = TestEmptyMessage.parseFrom(allFieldsData); 55 unknownFields = emptyMessage.getUnknownFields(); 56 } 57 58 UnknownFieldSet.Field getField(String name) { 59 Descriptors.FieldDescriptor field = descriptor.findFieldByName(name); 60 assertNotNull(field); 61 return unknownFields.getField(field.getNumber()); 62 } 63 64 // Constructs a protocol buffer which contains fields with all the same 65 // numbers as allFieldsData except that each field is some other wire 66 // type. 67 ByteString getBizarroData() throws Exception { 68 UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder(); 69 70 UnknownFieldSet.Field varintField = 71 UnknownFieldSet.Field.newBuilder().addVarint(1).build(); 72 UnknownFieldSet.Field fixed32Field = 73 UnknownFieldSet.Field.newBuilder().addFixed32(1).build(); 74 75 for (Map.Entry<Integer, UnknownFieldSet.Field> entry : 76 unknownFields.asMap().entrySet()) { 77 if (entry.getValue().getVarintList().isEmpty()) { 78 // Original field is not a varint, so use a varint. 79 bizarroFields.addField(entry.getKey(), varintField); 80 } else { 81 // Original field *is* a varint, so use something else. 82 bizarroFields.addField(entry.getKey(), fixed32Field); 83 } 84 } 85 86 return bizarroFields.build().toByteString(); 87 } 88 89 Descriptors.Descriptor descriptor; 90 TestAllTypes allFields; 91 ByteString allFieldsData; 92 93 // An empty message that has been parsed from allFieldsData. So, it has 94 // unknown fields of every type. 95 TestEmptyMessage emptyMessage; 96 UnknownFieldSet unknownFields; 97 98 // ================================================================= 99 100 public void testVarint() throws Exception { 101 UnknownFieldSet.Field field = getField("optional_int32"); 102 assertEquals(1, field.getVarintList().size()); 103 assertEquals(allFields.getOptionalInt32(), 104 (long) field.getVarintList().get(0)); 105 } 106 107 public void testFixed32() throws Exception { 108 UnknownFieldSet.Field field = getField("optional_fixed32"); 109 assertEquals(1, field.getFixed32List().size()); 110 assertEquals(allFields.getOptionalFixed32(), 111 (int) field.getFixed32List().get(0)); 112 } 113 114 public void testFixed64() throws Exception { 115 UnknownFieldSet.Field field = getField("optional_fixed64"); 116 assertEquals(1, field.getFixed64List().size()); 117 assertEquals(allFields.getOptionalFixed64(), 118 (long) field.getFixed64List().get(0)); 119 } 120 121 public void testLengthDelimited() throws Exception { 122 UnknownFieldSet.Field field = getField("optional_bytes"); 123 assertEquals(1, field.getLengthDelimitedList().size()); 124 assertEquals(allFields.getOptionalBytes(), 125 field.getLengthDelimitedList().get(0)); 126 } 127 128 public void testGroup() throws Exception { 129 Descriptors.FieldDescriptor nestedFieldDescriptor = 130 TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a"); 131 assertNotNull(nestedFieldDescriptor); 132 133 UnknownFieldSet.Field field = getField("optionalgroup"); 134 assertEquals(1, field.getGroupList().size()); 135 136 UnknownFieldSet group = field.getGroupList().get(0); 137 assertEquals(1, group.asMap().size()); 138 assertTrue(group.hasField(nestedFieldDescriptor.getNumber())); 139 140 UnknownFieldSet.Field nestedField = 141 group.getField(nestedFieldDescriptor.getNumber()); 142 assertEquals(1, nestedField.getVarintList().size()); 143 assertEquals(allFields.getOptionalGroup().getA(), 144 (long) nestedField.getVarintList().get(0)); 145 } 146 147 public void testSerialize() throws Exception { 148 // Check that serializing the UnknownFieldSet produces the original data 149 // again. 150 ByteString data = emptyMessage.toByteString(); 151 assertEquals(allFieldsData, data); 152 } 153 154 public void testCopyFrom() throws Exception { 155 TestEmptyMessage message = 156 TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build(); 157 158 assertEquals(emptyMessage.toString(), message.toString()); 159 } 160 161 public void testMergeFrom() throws Exception { 162 TestEmptyMessage source = 163 TestEmptyMessage.newBuilder() 164 .setUnknownFields( 165 UnknownFieldSet.newBuilder() 166 .addField(2, 167 UnknownFieldSet.Field.newBuilder() 168 .addVarint(2).build()) 169 .addField(3, 170 UnknownFieldSet.Field.newBuilder() 171 .addVarint(4).build()) 172 .build()) 173 .build(); 174 TestEmptyMessage destination = 175 TestEmptyMessage.newBuilder() 176 .setUnknownFields( 177 UnknownFieldSet.newBuilder() 178 .addField(1, 179 UnknownFieldSet.Field.newBuilder() 180 .addVarint(1).build()) 181 .addField(3, 182 UnknownFieldSet.Field.newBuilder() 183 .addVarint(3).build()) 184 .build()) 185 .mergeFrom(source) 186 .build(); 187 188 assertEquals( 189 "1: 1\n" + 190 "2: 2\n" + 191 "3: 3\n" + 192 "3: 4\n", 193 destination.toString()); 194 } 195 196 public void testClear() throws Exception { 197 UnknownFieldSet fields = 198 UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build(); 199 assertTrue(fields.asMap().isEmpty()); 200 } 201 202 public void testClearMessage() throws Exception { 203 TestEmptyMessage message = 204 TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build(); 205 assertEquals(0, message.getSerializedSize()); 206 } 207 208 public void testParseKnownAndUnknown() throws Exception { 209 // Test mixing known and unknown fields when parsing. 210 211 UnknownFieldSet fields = 212 UnknownFieldSet.newBuilder(unknownFields) 213 .addField(123456, 214 UnknownFieldSet.Field.newBuilder().addVarint(654321).build()) 215 .build(); 216 217 ByteString data = fields.toByteString(); 218 TestAllTypes destination = TestAllTypes.parseFrom(data); 219 220 TestUtil.assertAllFieldsSet(destination); 221 assertEquals(1, destination.getUnknownFields().asMap().size()); 222 223 UnknownFieldSet.Field field = 224 destination.getUnknownFields().getField(123456); 225 assertEquals(1, field.getVarintList().size()); 226 assertEquals(654321, (long) field.getVarintList().get(0)); 227 } 228 229 public void testWrongTypeTreatedAsUnknown() throws Exception { 230 // Test that fields of the wrong wire type are treated like unknown fields 231 // when parsing. 232 233 ByteString bizarroData = getBizarroData(); 234 TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData); 235 TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData); 236 237 // All fields should have been interpreted as unknown, so the debug strings 238 // should be the same. 239 assertEquals(emptyMessage.toString(), allTypesMessage.toString()); 240 } 241 242 public void testUnknownExtensions() throws Exception { 243 // Make sure fields are properly parsed to the UnknownFieldSet even when 244 // they are declared as extension numbers. 245 246 TestEmptyMessageWithExtensions message = 247 TestEmptyMessageWithExtensions.parseFrom(allFieldsData); 248 249 assertEquals(unknownFields.asMap().size(), 250 message.getUnknownFields().asMap().size()); 251 assertEquals(allFieldsData, message.toByteString()); 252 } 253 254 public void testWrongExtensionTypeTreatedAsUnknown() throws Exception { 255 // Test that fields of the wrong wire type are treated like unknown fields 256 // when parsing extensions. 257 258 ByteString bizarroData = getBizarroData(); 259 TestAllExtensions allExtensionsMessage = 260 TestAllExtensions.parseFrom(bizarroData); 261 TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData); 262 263 // All fields should have been interpreted as unknown, so the debug strings 264 // should be the same. 265 assertEquals(emptyMessage.toString(), 266 allExtensionsMessage.toString()); 267 } 268 269 public void testParseUnknownEnumValue() throws Exception { 270 Descriptors.FieldDescriptor singularField = 271 TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum"); 272 Descriptors.FieldDescriptor repeatedField = 273 TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum"); 274 assertNotNull(singularField); 275 assertNotNull(repeatedField); 276 277 ByteString data = 278 UnknownFieldSet.newBuilder() 279 .addField(singularField.getNumber(), 280 UnknownFieldSet.Field.newBuilder() 281 .addVarint(TestAllTypes.NestedEnum.BAR.getNumber()) 282 .addVarint(5) // not valid 283 .build()) 284 .addField(repeatedField.getNumber(), 285 UnknownFieldSet.Field.newBuilder() 286 .addVarint(TestAllTypes.NestedEnum.FOO.getNumber()) 287 .addVarint(4) // not valid 288 .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber()) 289 .addVarint(6) // not valid 290 .build()) 291 .build() 292 .toByteString(); 293 294 { 295 TestAllTypes message = TestAllTypes.parseFrom(data); 296 assertEquals(TestAllTypes.NestedEnum.BAR, 297 message.getOptionalNestedEnum()); 298 assertEquals( 299 Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ), 300 message.getRepeatedNestedEnumList()); 301 assertEquals(Arrays.asList(5L), 302 message.getUnknownFields() 303 .getField(singularField.getNumber()) 304 .getVarintList()); 305 assertEquals(Arrays.asList(4L, 6L), 306 message.getUnknownFields() 307 .getField(repeatedField.getNumber()) 308 .getVarintList()); 309 } 310 311 { 312 TestAllExtensions message = 313 TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry()); 314 assertEquals(TestAllTypes.NestedEnum.BAR, 315 message.getExtension(UnittestProto.optionalNestedEnumExtension)); 316 assertEquals( 317 Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ), 318 message.getExtension(UnittestProto.repeatedNestedEnumExtension)); 319 assertEquals(Arrays.asList(5L), 320 message.getUnknownFields() 321 .getField(singularField.getNumber()) 322 .getVarintList()); 323 assertEquals(Arrays.asList(4L, 6L), 324 message.getUnknownFields() 325 .getField(repeatedField.getNumber()) 326 .getVarintList()); 327 } 328 } 329 330 public void testLargeVarint() throws Exception { 331 ByteString data = 332 UnknownFieldSet.newBuilder() 333 .addField(1, 334 UnknownFieldSet.Field.newBuilder() 335 .addVarint(0x7FFFFFFFFFFFFFFFL) 336 .build()) 337 .build() 338 .toByteString(); 339 UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data); 340 UnknownFieldSet.Field field = parsed.getField(1); 341 assertEquals(1, field.getVarintList().size()); 342 assertEquals(0x7FFFFFFFFFFFFFFFL, (long)field.getVarintList().get(0)); 343 } 344 345 public void testEqualsAndHashCode() { 346 UnknownFieldSet.Field fixed32Field = 347 UnknownFieldSet.Field.newBuilder() 348 .addFixed32(1) 349 .build(); 350 UnknownFieldSet.Field fixed64Field = 351 UnknownFieldSet.Field.newBuilder() 352 .addFixed64(1) 353 .build(); 354 UnknownFieldSet.Field varIntField = 355 UnknownFieldSet.Field.newBuilder() 356 .addVarint(1) 357 .build(); 358 UnknownFieldSet.Field lengthDelimitedField = 359 UnknownFieldSet.Field.newBuilder() 360 .addLengthDelimited(ByteString.EMPTY) 361 .build(); 362 UnknownFieldSet.Field groupField = 363 UnknownFieldSet.Field.newBuilder() 364 .addGroup(unknownFields) 365 .build(); 366 367 UnknownFieldSet a = 368 UnknownFieldSet.newBuilder() 369 .addField(1, fixed32Field) 370 .build(); 371 UnknownFieldSet b = 372 UnknownFieldSet.newBuilder() 373 .addField(1, fixed64Field) 374 .build(); 375 UnknownFieldSet c = 376 UnknownFieldSet.newBuilder() 377 .addField(1, varIntField) 378 .build(); 379 UnknownFieldSet d = 380 UnknownFieldSet.newBuilder() 381 .addField(1, lengthDelimitedField) 382 .build(); 383 UnknownFieldSet e = 384 UnknownFieldSet.newBuilder() 385 .addField(1, groupField) 386 .build(); 387 388 checkEqualsIsConsistent(a); 389 checkEqualsIsConsistent(b); 390 checkEqualsIsConsistent(c); 391 checkEqualsIsConsistent(d); 392 checkEqualsIsConsistent(e); 393 394 checkNotEqual(a, b); 395 checkNotEqual(a, c); 396 checkNotEqual(a, d); 397 checkNotEqual(a, e); 398 checkNotEqual(b, c); 399 checkNotEqual(b, d); 400 checkNotEqual(b, e); 401 checkNotEqual(c, d); 402 checkNotEqual(c, e); 403 checkNotEqual(d, e); 404 } 405 406 /** 407 * Asserts that the given field sets are not equal and have different 408 * hash codes. 409 * 410 * @warning It's valid for non-equal objects to have the same hash code, so 411 * this test is stricter than it needs to be. However, this should happen 412 * relatively rarely. 413 */ 414 private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) { 415 String equalsError = String.format("%s should not be equal to %s", s1, s2); 416 assertFalse(equalsError, s1.equals(s2)); 417 assertFalse(equalsError, s2.equals(s1)); 418 419 assertFalse( 420 String.format("%s should have a different hash code from %s", s1, s2), 421 s1.hashCode() == s2.hashCode()); 422 } 423 424 /** 425 * Asserts that the given field sets are equal and have identical hash codes. 426 */ 427 private void checkEqualsIsConsistent(UnknownFieldSet set) { 428 // Object should be equal to itself. 429 assertEquals(set, set); 430 431 // Object should be equal to a copy of itself. 432 UnknownFieldSet copy = UnknownFieldSet.newBuilder(set).build(); 433 assertEquals(set, copy); 434 assertEquals(copy, set); 435 assertEquals(set.hashCode(), copy.hashCode()); 436 } 437 } 438