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.FieldDescriptor; 34 import map_test.MapForProto2TestProto.TestMap; 35 import map_test.MapForProto2TestProto.TestMap.MessageValue; 36 import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields; 37 import map_test.MapForProto2TestProto.TestRecursiveMap; 38 import map_test.MapForProto2TestProto.TestUnknownEnumValue; 39 import junit.framework.TestCase; 40 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.HashMap; 44 import java.util.List; 45 import java.util.Map; 46 47 /** 48 * Unit tests for map fields in proto2 protos. 49 */ 50 public class MapForProto2Test extends TestCase { setMapValues(TestMap.Builder builder)51 private void setMapValues(TestMap.Builder builder) { 52 builder.getMutableInt32ToInt32Field().put(1, 11); 53 builder.getMutableInt32ToInt32Field().put(2, 22); 54 builder.getMutableInt32ToInt32Field().put(3, 33); 55 56 builder.getMutableInt32ToStringField().put(1, "11"); 57 builder.getMutableInt32ToStringField().put(2, "22"); 58 builder.getMutableInt32ToStringField().put(3, "33"); 59 60 builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11")); 61 builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22")); 62 builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33")); 63 64 builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO); 65 builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR); 66 builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ); 67 68 builder.getMutableInt32ToMessageField().put( 69 1, MessageValue.newBuilder().setValue(11).build()); 70 builder.getMutableInt32ToMessageField().put( 71 2, MessageValue.newBuilder().setValue(22).build()); 72 builder.getMutableInt32ToMessageField().put( 73 3, MessageValue.newBuilder().setValue(33).build()); 74 75 builder.getMutableStringToInt32Field().put("1", 11); 76 builder.getMutableStringToInt32Field().put("2", 22); 77 builder.getMutableStringToInt32Field().put("3", 33); 78 } 79 copyMapValues(TestMap source, TestMap.Builder destination)80 private void copyMapValues(TestMap source, TestMap.Builder destination) { 81 destination 82 .putAllInt32ToInt32Field(source.getInt32ToInt32Field()) 83 .putAllInt32ToStringField(source.getInt32ToStringField()) 84 .putAllInt32ToBytesField(source.getInt32ToBytesField()) 85 .putAllInt32ToEnumField(source.getInt32ToEnumField()) 86 .putAllInt32ToMessageField(source.getInt32ToMessageField()) 87 .putAllStringToInt32Field(source.getStringToInt32Field()); 88 } 89 assertMapValuesSet(TestMap message)90 private void assertMapValuesSet(TestMap message) { 91 assertEquals(3, message.getInt32ToInt32Field().size()); 92 assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); 93 assertEquals(22, message.getInt32ToInt32Field().get(2).intValue()); 94 assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); 95 96 assertEquals(3, message.getInt32ToStringField().size()); 97 assertEquals("11", message.getInt32ToStringField().get(1)); 98 assertEquals("22", message.getInt32ToStringField().get(2)); 99 assertEquals("33", message.getInt32ToStringField().get(3)); 100 101 assertEquals(3, message.getInt32ToBytesField().size()); 102 assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1)); 103 assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2)); 104 assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); 105 106 assertEquals(3, message.getInt32ToEnumField().size()); 107 assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1)); 108 assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2)); 109 assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); 110 111 assertEquals(3, message.getInt32ToMessageField().size()); 112 assertEquals(11, message.getInt32ToMessageField().get(1).getValue()); 113 assertEquals(22, message.getInt32ToMessageField().get(2).getValue()); 114 assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); 115 116 assertEquals(3, message.getStringToInt32Field().size()); 117 assertEquals(11, message.getStringToInt32Field().get("1").intValue()); 118 assertEquals(22, message.getStringToInt32Field().get("2").intValue()); 119 assertEquals(33, message.getStringToInt32Field().get("3").intValue()); 120 } 121 updateMapValues(TestMap.Builder builder)122 private void updateMapValues(TestMap.Builder builder) { 123 builder.getMutableInt32ToInt32Field().put(1, 111); 124 builder.getMutableInt32ToInt32Field().remove(2); 125 builder.getMutableInt32ToInt32Field().put(4, 44); 126 127 builder.getMutableInt32ToStringField().put(1, "111"); 128 builder.getMutableInt32ToStringField().remove(2); 129 builder.getMutableInt32ToStringField().put(4, "44"); 130 131 builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111")); 132 builder.getMutableInt32ToBytesField().remove(2); 133 builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44")); 134 135 builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR); 136 builder.getMutableInt32ToEnumField().remove(2); 137 builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX); 138 139 builder.getMutableInt32ToMessageField().put( 140 1, MessageValue.newBuilder().setValue(111).build()); 141 builder.getMutableInt32ToMessageField().remove(2); 142 builder.getMutableInt32ToMessageField().put( 143 4, MessageValue.newBuilder().setValue(44).build()); 144 145 builder.getMutableStringToInt32Field().put("1", 111); 146 builder.getMutableStringToInt32Field().remove("2"); 147 builder.getMutableStringToInt32Field().put("4", 44); 148 } 149 assertMapValuesUpdated(TestMap message)150 private void assertMapValuesUpdated(TestMap message) { 151 assertEquals(3, message.getInt32ToInt32Field().size()); 152 assertEquals(111, message.getInt32ToInt32Field().get(1).intValue()); 153 assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); 154 assertEquals(44, message.getInt32ToInt32Field().get(4).intValue()); 155 156 assertEquals(3, message.getInt32ToStringField().size()); 157 assertEquals("111", message.getInt32ToStringField().get(1)); 158 assertEquals("33", message.getInt32ToStringField().get(3)); 159 assertEquals("44", message.getInt32ToStringField().get(4)); 160 161 assertEquals(3, message.getInt32ToBytesField().size()); 162 assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1)); 163 assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); 164 assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4)); 165 166 assertEquals(3, message.getInt32ToEnumField().size()); 167 assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); 168 assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); 169 assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4)); 170 171 assertEquals(3, message.getInt32ToMessageField().size()); 172 assertEquals(111, message.getInt32ToMessageField().get(1).getValue()); 173 assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); 174 assertEquals(44, message.getInt32ToMessageField().get(4).getValue()); 175 176 assertEquals(3, message.getStringToInt32Field().size()); 177 assertEquals(111, message.getStringToInt32Field().get("1").intValue()); 178 assertEquals(33, message.getStringToInt32Field().get("3").intValue()); 179 assertEquals(44, message.getStringToInt32Field().get("4").intValue()); 180 } 181 assertMapValuesCleared(TestMap message)182 private void assertMapValuesCleared(TestMap message) { 183 assertEquals(0, message.getInt32ToInt32Field().size()); 184 assertEquals(0, message.getInt32ToStringField().size()); 185 assertEquals(0, message.getInt32ToBytesField().size()); 186 assertEquals(0, message.getInt32ToEnumField().size()); 187 assertEquals(0, message.getInt32ToMessageField().size()); 188 assertEquals(0, message.getStringToInt32Field().size()); 189 } 190 testMutableMapLifecycle()191 public void testMutableMapLifecycle() { 192 TestMap.Builder builder = TestMap.newBuilder(); 193 Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field(); 194 intMap.put(1, 2); 195 assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); 196 try { 197 intMap.put(2, 3); 198 fail(); 199 } catch (UnsupportedOperationException e) { 200 // expected 201 } 202 assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); 203 builder.getMutableInt32ToInt32Field().put(2, 3); 204 assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field()); 205 206 Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField(); 207 enumMap.put(1, TestMap.EnumValue.BAR); 208 assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField()); 209 try { 210 enumMap.put(2, TestMap.EnumValue.FOO); 211 fail(); 212 } catch (UnsupportedOperationException e) { 213 // expected 214 } 215 assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField()); 216 builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO); 217 assertEquals( 218 newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO), 219 builder.getInt32ToEnumField()); 220 221 Map<Integer, String> stringMap = builder.getMutableInt32ToStringField(); 222 stringMap.put(1, "1"); 223 assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField()); 224 try { 225 stringMap.put(2, "2"); 226 fail(); 227 } catch (UnsupportedOperationException e) { 228 // expected 229 } 230 assertEquals(newMap(1, "1"), builder.getInt32ToStringField()); 231 builder.getMutableInt32ToStringField().put(2, "2"); 232 assertEquals( 233 newMap(1, "1", 2, "2"), 234 builder.getInt32ToStringField()); 235 236 Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField(); 237 messageMap.put(1, TestMap.MessageValue.getDefaultInstance()); 238 assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()), 239 builder.build().getInt32ToMessageField()); 240 try { 241 messageMap.put(2, TestMap.MessageValue.getDefaultInstance()); 242 fail(); 243 } catch (UnsupportedOperationException e) { 244 // expected 245 } 246 assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()), 247 builder.getInt32ToMessageField()); 248 builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance()); 249 assertEquals( 250 newMap(1, TestMap.MessageValue.getDefaultInstance(), 251 2, TestMap.MessageValue.getDefaultInstance()), 252 builder.getInt32ToMessageField()); 253 } 254 testMutableMapLifecycle_collections()255 public void testMutableMapLifecycle_collections() { 256 TestMap.Builder builder = TestMap.newBuilder(); 257 Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field(); 258 intMap.put(1, 2); 259 assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); 260 try { 261 intMap.remove(2); 262 fail(); 263 } catch (UnsupportedOperationException e) { 264 // expected 265 } 266 try { 267 intMap.entrySet().remove(new Object()); 268 fail(); 269 } catch (UnsupportedOperationException e) { 270 // expected 271 } 272 try { 273 intMap.entrySet().iterator().remove(); 274 fail(); 275 } catch (UnsupportedOperationException e) { 276 // expected 277 } 278 try { 279 intMap.keySet().remove(new Object()); 280 fail(); 281 } catch (UnsupportedOperationException e) { 282 // expected 283 } 284 try { 285 intMap.values().remove(new Object()); 286 fail(); 287 } catch (UnsupportedOperationException e) { 288 // expected 289 } 290 try { 291 intMap.values().iterator().remove(); 292 fail(); 293 } catch (UnsupportedOperationException e) { 294 // expected 295 } 296 assertEquals(newMap(1, 2), intMap); 297 assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); 298 assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); 299 } 300 testGettersAndSetters()301 public void testGettersAndSetters() throws Exception { 302 TestMap.Builder builder = TestMap.newBuilder(); 303 TestMap message = builder.build(); 304 assertMapValuesCleared(message); 305 306 builder = message.toBuilder(); 307 setMapValues(builder); 308 message = builder.build(); 309 assertMapValuesSet(message); 310 311 builder = message.toBuilder(); 312 updateMapValues(builder); 313 message = builder.build(); 314 assertMapValuesUpdated(message); 315 316 builder = message.toBuilder(); 317 builder.clear(); 318 message = builder.build(); 319 assertMapValuesCleared(message); 320 } 321 testPutAll()322 public void testPutAll() throws Exception { 323 TestMap.Builder sourceBuilder = TestMap.newBuilder(); 324 setMapValues(sourceBuilder); 325 TestMap source = sourceBuilder.build(); 326 327 TestMap.Builder destination = TestMap.newBuilder(); 328 copyMapValues(source, destination); 329 assertMapValuesSet(destination.build()); 330 } 331 testSerializeAndParse()332 public void testSerializeAndParse() throws Exception { 333 TestMap.Builder builder = TestMap.newBuilder(); 334 setMapValues(builder); 335 TestMap message = builder.build(); 336 assertEquals(message.getSerializedSize(), message.toByteString().size()); 337 message = TestMap.parser().parseFrom(message.toByteString()); 338 assertMapValuesSet(message); 339 340 builder = message.toBuilder(); 341 updateMapValues(builder); 342 message = builder.build(); 343 assertEquals(message.getSerializedSize(), message.toByteString().size()); 344 message = TestMap.parser().parseFrom(message.toByteString()); 345 assertMapValuesUpdated(message); 346 347 builder = message.toBuilder(); 348 builder.clear(); 349 message = builder.build(); 350 assertEquals(message.getSerializedSize(), message.toByteString().size()); 351 message = TestMap.parser().parseFrom(message.toByteString()); 352 assertMapValuesCleared(message); 353 } 354 testMergeFrom()355 public void testMergeFrom() throws Exception { 356 TestMap.Builder builder = TestMap.newBuilder(); 357 setMapValues(builder); 358 TestMap message = builder.build(); 359 360 TestMap.Builder other = TestMap.newBuilder(); 361 other.mergeFrom(message); 362 assertMapValuesSet(other.build()); 363 } 364 testEqualsAndHashCode()365 public void testEqualsAndHashCode() throws Exception { 366 // Test that generated equals() and hashCode() will disregard the order 367 // of map entries when comparing/hashing map fields. 368 369 // We can't control the order of elements in a HashMap. The best we can do 370 // here is to add elements in different order. 371 TestMap.Builder b1 = TestMap.newBuilder(); 372 b1.getMutableInt32ToInt32Field().put(1, 2); 373 b1.getMutableInt32ToInt32Field().put(3, 4); 374 b1.getMutableInt32ToInt32Field().put(5, 6); 375 TestMap m1 = b1.build(); 376 377 TestMap.Builder b2 = TestMap.newBuilder(); 378 b2.getMutableInt32ToInt32Field().put(5, 6); 379 b2.getMutableInt32ToInt32Field().put(1, 2); 380 b2.getMutableInt32ToInt32Field().put(3, 4); 381 TestMap m2 = b2.build(); 382 383 assertEquals(m1, m2); 384 assertEquals(m1.hashCode(), m2.hashCode()); 385 386 // Make sure we did compare map fields. 387 b2.getMutableInt32ToInt32Field().put(1, 0); 388 m2 = b2.build(); 389 assertFalse(m1.equals(m2)); 390 // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed 391 // to be different. 392 } 393 394 395 // The following methods are used to test reflection API. 396 f(String name)397 private static FieldDescriptor f(String name) { 398 return TestMap.getDescriptor().findFieldByName(name); 399 } 400 getFieldValue(Message mapEntry, String name)401 private static Object getFieldValue(Message mapEntry, String name) { 402 FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); 403 return mapEntry.getField(field); 404 } 405 setFieldValue( Message.Builder mapEntry, String name, Object value)406 private static Message.Builder setFieldValue( 407 Message.Builder mapEntry, String name, Object value) { 408 FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); 409 mapEntry.setField(field, value); 410 return mapEntry; 411 } 412 assertHasMapValues(Message message, String name, Map<?, ?> values)413 private static void assertHasMapValues(Message message, String name, Map<?, ?> values) { 414 FieldDescriptor field = f(name); 415 for (Object entry : (List<?>) message.getField(field)) { 416 Message mapEntry = (Message) entry; 417 Object key = getFieldValue(mapEntry, "key"); 418 Object value = getFieldValue(mapEntry, "value"); 419 assertTrue(values.containsKey(key)); 420 assertEquals(value, values.get(key)); 421 } 422 assertEquals(values.size(), message.getRepeatedFieldCount(field)); 423 for (int i = 0; i < message.getRepeatedFieldCount(field); i++) { 424 Message mapEntry = (Message) message.getRepeatedField(field, i); 425 Object key = getFieldValue(mapEntry, "key"); 426 Object value = getFieldValue(mapEntry, "value"); 427 assertTrue(values.containsKey(key)); 428 assertEquals(value, values.get(key)); 429 } 430 } 431 432 private static <KeyType, ValueType> newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value)433 Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) { 434 FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); 435 Message.Builder entryBuilder = builder.newBuilderForField(field); 436 FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key"); 437 FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value"); 438 entryBuilder.setField(keyField, key); 439 entryBuilder.setField(valueField, value); 440 return entryBuilder.build(); 441 } 442 setMapValues(Message.Builder builder, String name, Map<?, ?> values)443 private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) { 444 List<Message> entryList = new ArrayList<Message>(); 445 for (Map.Entry<?, ?> entry : values.entrySet()) { 446 entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue())); 447 } 448 FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); 449 builder.setField(field, entryList); 450 } 451 452 private static <KeyType, ValueType> mapForValues( KeyType key1, ValueType value1, KeyType key2, ValueType value2)453 Map<KeyType, ValueType> mapForValues( 454 KeyType key1, ValueType value1, KeyType key2, ValueType value2) { 455 Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>(); 456 map.put(key1, value1); 457 map.put(key2, value2); 458 return map; 459 } 460 testReflectionApi()461 public void testReflectionApi() throws Exception { 462 // In reflection API, map fields are just repeated message fields. 463 TestMap.Builder builder = TestMap.newBuilder(); 464 builder.getMutableInt32ToInt32Field().put(1, 2); 465 builder.getMutableInt32ToInt32Field().put(3, 4); 466 builder.getMutableInt32ToMessageField().put( 467 11, MessageValue.newBuilder().setValue(22).build()); 468 builder.getMutableInt32ToMessageField().put( 469 33, MessageValue.newBuilder().setValue(44).build()); 470 TestMap message = builder.build(); 471 472 // Test getField(), getRepeatedFieldCount(), getRepeatedField(). 473 assertHasMapValues(message, "int32_to_int32_field", 474 mapForValues(1, 2, 3, 4)); 475 assertHasMapValues(message, "int32_to_message_field", 476 mapForValues( 477 11, MessageValue.newBuilder().setValue(22).build(), 478 33, MessageValue.newBuilder().setValue(44).build())); 479 480 // Test clearField() 481 builder.clearField(f("int32_to_int32_field")); 482 builder.clearField(f("int32_to_message_field")); 483 message = builder.build(); 484 assertEquals(0, message.getInt32ToInt32Field().size()); 485 assertEquals(0, message.getInt32ToMessageField().size()); 486 487 // Test setField() 488 setMapValues(builder, "int32_to_int32_field", 489 mapForValues(11, 22, 33, 44)); 490 setMapValues(builder, "int32_to_message_field", 491 mapForValues( 492 111, MessageValue.newBuilder().setValue(222).build(), 493 333, MessageValue.newBuilder().setValue(444).build())); 494 message = builder.build(); 495 assertEquals(22, message.getInt32ToInt32Field().get(11).intValue()); 496 assertEquals(44, message.getInt32ToInt32Field().get(33).intValue()); 497 assertEquals(222, message.getInt32ToMessageField().get(111).getValue()); 498 assertEquals(444, message.getInt32ToMessageField().get(333).getValue()); 499 500 // Test addRepeatedField 501 builder.addRepeatedField(f("int32_to_int32_field"), 502 newMapEntry(builder, "int32_to_int32_field", 55, 66)); 503 builder.addRepeatedField(f("int32_to_message_field"), 504 newMapEntry(builder, "int32_to_message_field", 555, 505 MessageValue.newBuilder().setValue(666).build())); 506 message = builder.build(); 507 assertEquals(66, message.getInt32ToInt32Field().get(55).intValue()); 508 assertEquals(666, message.getInt32ToMessageField().get(555).getValue()); 509 510 // Test addRepeatedField (overriding existing values) 511 builder.addRepeatedField(f("int32_to_int32_field"), 512 newMapEntry(builder, "int32_to_int32_field", 55, 55)); 513 builder.addRepeatedField(f("int32_to_message_field"), 514 newMapEntry(builder, "int32_to_message_field", 555, 515 MessageValue.newBuilder().setValue(555).build())); 516 message = builder.build(); 517 assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); 518 assertEquals(555, message.getInt32ToMessageField().get(555).getValue()); 519 520 // Test setRepeatedField 521 for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) { 522 Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i); 523 int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue(); 524 int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue(); 525 // Swap key with value for each entry. 526 Message.Builder mapEntryBuilder = mapEntry.toBuilder(); 527 setFieldValue(mapEntryBuilder, "key", oldValue); 528 setFieldValue(mapEntryBuilder, "value", oldKey); 529 builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build()); 530 } 531 message = builder.build(); 532 assertEquals(11, message.getInt32ToInt32Field().get(22).intValue()); 533 assertEquals(33, message.getInt32ToInt32Field().get(44).intValue()); 534 assertEquals(55, message.getInt32ToInt32Field().get(55).intValue()); 535 } 536 testTextFormat()537 public void testTextFormat() throws Exception { 538 TestMap.Builder builder = TestMap.newBuilder(); 539 setMapValues(builder); 540 TestMap message = builder.build(); 541 542 String textData = TextFormat.printToString(message); 543 544 builder = TestMap.newBuilder(); 545 TextFormat.merge(textData, builder); 546 message = builder.build(); 547 548 assertMapValuesSet(message); 549 } 550 testDynamicMessage()551 public void testDynamicMessage() throws Exception { 552 TestMap.Builder builder = TestMap.newBuilder(); 553 setMapValues(builder); 554 TestMap message = builder.build(); 555 556 Message dynamicDefaultInstance = 557 DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); 558 Message dynamicMessage = dynamicDefaultInstance 559 .newBuilderForType().mergeFrom(message.toByteString()).build(); 560 561 assertEquals(message, dynamicMessage); 562 assertEquals(message.hashCode(), dynamicMessage.hashCode()); 563 } 564 testReflectionEqualsAndHashCode()565 public void testReflectionEqualsAndHashCode() throws Exception { 566 // Test that generated equals() and hashCode() will disregard the order 567 // of map entries when comparing/hashing map fields. 568 569 // We use DynamicMessage to test reflection based equals()/hashCode(). 570 Message dynamicDefaultInstance = 571 DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); 572 FieldDescriptor field = f("int32_to_int32_field"); 573 574 Message.Builder b1 = dynamicDefaultInstance.newBuilderForType(); 575 b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2)); 576 b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4)); 577 b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6)); 578 Message m1 = b1.build(); 579 580 Message.Builder b2 = dynamicDefaultInstance.newBuilderForType(); 581 b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6)); 582 b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2)); 583 b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4)); 584 Message m2 = b2.build(); 585 586 assertEquals(m1, m2); 587 assertEquals(m1.hashCode(), m2.hashCode()); 588 589 // Make sure we did compare map fields. 590 b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0)); 591 m2 = b2.build(); 592 assertFalse(m1.equals(m2)); 593 // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed 594 // to be different. 595 } 596 testUnknownEnumValues()597 public void testUnknownEnumValues() throws Exception { 598 TestUnknownEnumValue.Builder builder = 599 TestUnknownEnumValue.newBuilder(); 600 builder.getMutableInt32ToInt32Field().put(1, 1); 601 builder.getMutableInt32ToInt32Field().put(2, 54321); 602 ByteString data = builder.build().toByteString(); 603 604 TestMap message = TestMap.parseFrom(data); 605 // Entries with unknown enum values will be stored into UnknownFieldSet so 606 // there is only one entry in the map. 607 assertEquals(1, message.getInt32ToEnumField().size()); 608 assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); 609 // UnknownFieldSet should not be empty. 610 assertFalse(message.getUnknownFields().asMap().isEmpty()); 611 // Serializing and parsing should preserve the unknown entry. 612 data = message.toByteString(); 613 TestUnknownEnumValue messageWithUnknownEnums = 614 TestUnknownEnumValue.parseFrom(data); 615 assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size()); 616 assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue()); 617 assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue()); 618 } 619 620 testRequiredMessage()621 public void testRequiredMessage() throws Exception { 622 TestMap.Builder builder = TestMap.newBuilder(); 623 builder.getMutableRequiredMessageMap().put(0, 624 MessageWithRequiredFields.newBuilder().buildPartial()); 625 TestMap message = builder.buildPartial(); 626 assertFalse(message.isInitialized()); 627 628 builder.getMutableRequiredMessageMap().put(0, 629 MessageWithRequiredFields.newBuilder().setValue(1).build()); 630 message = builder.build(); 631 assertTrue(message.isInitialized()); 632 } 633 testRecursiveMap()634 public void testRecursiveMap() throws Exception { 635 TestRecursiveMap.Builder builder = TestRecursiveMap.newBuilder(); 636 builder.getMutableRecursiveMapField().put( 637 1, TestRecursiveMap.newBuilder().setValue(2).build()); 638 builder.getMutableRecursiveMapField().put( 639 3, TestRecursiveMap.newBuilder().setValue(4).build()); 640 ByteString data = builder.build().toByteString(); 641 642 TestRecursiveMap message = TestRecursiveMap.parseFrom(data); 643 assertEquals(2, message.getRecursiveMapField().get(1).getValue()); 644 assertEquals(4, message.getRecursiveMapField().get(3).getValue()); 645 } 646 testIterationOrder()647 public void testIterationOrder() throws Exception { 648 TestMap.Builder builder = TestMap.newBuilder(); 649 setMapValues(builder); 650 TestMap message = builder.build(); 651 652 assertEquals(Arrays.asList("1", "2", "3"), 653 new ArrayList<String>(message.getStringToInt32Field().keySet())); 654 } 655 656 // Regression test for b/20494788 testMapInitializationOrder()657 public void testMapInitializationOrder() throws Exception { 658 assertEquals("RedactAllTypes", map_test.RedactAllTypes 659 .getDefaultInstance().getDescriptorForType().getName()); 660 661 map_test.Message1.Builder builder = 662 map_test.Message1.newBuilder(); 663 builder.getMutableMapField().put("key", true); 664 map_test.Message1 message = builder.build(); 665 Message mapEntry = (Message) message.getRepeatedField( 666 message.getDescriptorForType().findFieldByName("map_field"), 0); 667 assertEquals(2, mapEntry.getAllFields().size()); 668 } 669 newMap(K key1, V value1)670 private static <K, V> Map<K, V> newMap(K key1, V value1) { 671 Map<K, V> map = new HashMap<K, V>(); 672 map.put(key1, value1); 673 return map; 674 } 675 newMap(K key1, V value1, K key2, V value2)676 private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) { 677 Map<K, V> map = new HashMap<K, V>(); 678 map.put(key1, value1); 679 map.put(key2, value2); 680 return map; 681 } 682 } 683 684