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 import static org.junit.Assert.assertNotNull; 13 import static org.junit.Assert.assertThrows; 14 import static org.junit.Assert.fail; 15 16 import com.google.protobuf.Descriptors.Descriptor; 17 import com.google.protobuf.Descriptors.EnumDescriptor; 18 import com.google.protobuf.Descriptors.EnumValueDescriptor; 19 import com.google.protobuf.Descriptors.FieldDescriptor; 20 import map_test.MapTestProto.BizarroTestMap; 21 import map_test.MapTestProto.MapContainer; 22 import map_test.MapTestProto.ReservedAsMapField; 23 import map_test.MapTestProto.ReservedAsMapFieldWithEnumValue; 24 import map_test.MapTestProto.TestMap; 25 import map_test.MapTestProto.TestMap.MessageValue; 26 import map_test.MapTestProto.TestMapOrBuilder; 27 import map_test.MapTestProto.TestOnChangeEventPropagation; 28 import java.io.ByteArrayOutputStream; 29 import java.io.IOException; 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.List; 33 import java.util.Map; 34 import java.util.TreeMap; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 import org.junit.runners.JUnit4; 38 39 /** Unit tests for map fields. */ 40 @RunWith(JUnit4.class) 41 public class MapTest { 42 setMapValuesUsingMutableMap(TestMap.Builder builder)43 private void setMapValuesUsingMutableMap(TestMap.Builder builder) { 44 builder.getMutableInt32ToInt32Field().put(1, 11); 45 builder.getMutableInt32ToInt32Field().put(2, 22); 46 builder.getMutableInt32ToInt32Field().put(3, 33); 47 48 builder.getMutableInt32ToStringField().put(1, "11"); 49 builder.getMutableInt32ToStringField().put(2, "22"); 50 builder.getMutableInt32ToStringField().put(3, "33"); 51 52 builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11")); 53 builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22")); 54 builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33")); 55 56 builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO); 57 builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR); 58 builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ); 59 60 builder.getMutableInt32ToMessageField().put( 61 1, MessageValue.newBuilder().setValue(11).build()); 62 builder.getMutableInt32ToMessageField().put( 63 2, MessageValue.newBuilder().setValue(22).build()); 64 builder.getMutableInt32ToMessageField().put( 65 3, MessageValue.newBuilder().setValue(33).build()); 66 67 builder.getMutableStringToInt32Field().put("1", 11); 68 builder.getMutableStringToInt32Field().put("2", 22); 69 builder.getMutableStringToInt32Field().put("3", 33); 70 } 71 setMapValuesUsingAccessors(TestMap.Builder builder)72 private void setMapValuesUsingAccessors(TestMap.Builder builder) { 73 builder 74 .putInt32ToInt32Field(1, 11) 75 .putInt32ToInt32Field(2, 22) 76 .putInt32ToInt32Field(3, 33) 77 .putInt32ToStringField(1, "11") 78 .putInt32ToStringField(2, "22") 79 .putInt32ToStringField(3, "33") 80 .putInt32ToBytesField(1, TestUtil.toBytes("11")) 81 .putInt32ToBytesField(2, TestUtil.toBytes("22")) 82 .putInt32ToBytesField(3, TestUtil.toBytes("33")) 83 .putInt32ToEnumField(1, TestMap.EnumValue.FOO) 84 .putInt32ToEnumField(2, TestMap.EnumValue.BAR) 85 .putInt32ToEnumField(3, TestMap.EnumValue.BAZ) 86 .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build()) 87 .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build()) 88 .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build()) 89 .putStringToInt32Field("1", 11) 90 .putStringToInt32Field("2", 22) 91 .putStringToInt32Field("3", 33); 92 } 93 94 @Test testSetMapValues()95 public void testSetMapValues() { 96 TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder(); 97 setMapValuesUsingMutableMap(usingMutableMapBuilder); 98 TestMap usingMutableMap = usingMutableMapBuilder.build(); 99 assertMapValuesSet(usingMutableMap); 100 101 TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder(); 102 setMapValuesUsingAccessors(usingAccessorsBuilder); 103 TestMap usingAccessors = usingAccessorsBuilder.build(); 104 assertMapValuesSet(usingAccessors); 105 106 assertThat(usingAccessors).isEqualTo(usingMutableMap); 107 } 108 copyMapValues(TestMap source, TestMap.Builder destination)109 private void copyMapValues(TestMap source, TestMap.Builder destination) { 110 destination 111 .putAllInt32ToInt32Field(source.getInt32ToInt32FieldMap()) 112 .putAllInt32ToStringField(source.getInt32ToStringFieldMap()) 113 .putAllInt32ToBytesField(source.getInt32ToBytesFieldMap()) 114 .putAllInt32ToEnumField(source.getInt32ToEnumFieldMap()) 115 .putAllInt32ToMessageField(source.getInt32ToMessageFieldMap()) 116 .putAllStringToInt32Field(source.getStringToInt32FieldMap()); 117 } 118 assertMapValuesSet(TestMap message)119 private void assertMapValuesSet(TestMap message) { 120 assertThat(message.getInt32ToInt32FieldMap()).hasSize(3); 121 assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(11); 122 assertThat(message.getInt32ToInt32FieldMap().get(2).intValue()).isEqualTo(22); 123 assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33); 124 125 assertThat(message.getInt32ToStringFieldMap()).hasSize(3); 126 assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "11"); 127 assertThat(message.getInt32ToStringFieldMap()).containsEntry(2, "22"); 128 assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33"); 129 130 assertThat(message.getInt32ToBytesFieldMap()).hasSize(3); 131 assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("11")); 132 assertThat(message.getInt32ToBytesFieldMap()).containsEntry(2, TestUtil.toBytes("22")); 133 assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33")); 134 135 assertThat(message.getInt32ToEnumFieldMap()).hasSize(3); 136 assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.FOO); 137 assertThat(message.getInt32ToEnumFieldMap()).containsEntry(2, TestMap.EnumValue.BAR); 138 assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ); 139 140 assertThat(message.getInt32ToMessageFieldMap()).hasSize(3); 141 assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(11); 142 assertThat(message.getInt32ToMessageFieldMap().get(2).getValue()).isEqualTo(22); 143 assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33); 144 145 assertThat(message.getStringToInt32FieldMap()).hasSize(3); 146 assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(11); 147 assertThat(message.getStringToInt32FieldMap().get("2").intValue()).isEqualTo(22); 148 assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33); 149 } 150 updateMapValuesUsingMutableMap(TestMap.Builder builder)151 private void updateMapValuesUsingMutableMap(TestMap.Builder builder) { 152 builder.getMutableInt32ToInt32Field().put(1, 111); 153 builder.getMutableInt32ToInt32Field().remove(2); 154 builder.getMutableInt32ToInt32Field().put(4, 44); 155 156 builder.getMutableInt32ToStringField().put(1, "111"); 157 builder.getMutableInt32ToStringField().remove(2); 158 builder.getMutableInt32ToStringField().put(4, "44"); 159 160 builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111")); 161 builder.getMutableInt32ToBytesField().remove(2); 162 builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44")); 163 164 builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR); 165 builder.getMutableInt32ToEnumField().remove(2); 166 builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX); 167 168 builder.getMutableInt32ToMessageField().put( 169 1, MessageValue.newBuilder().setValue(111).build()); 170 builder.getMutableInt32ToMessageField().remove(2); 171 builder.getMutableInt32ToMessageField().put( 172 4, MessageValue.newBuilder().setValue(44).build()); 173 174 builder.getMutableStringToInt32Field().put("1", 111); 175 builder.getMutableStringToInt32Field().remove("2"); 176 builder.getMutableStringToInt32Field().put("4", 44); 177 } 178 updateMapValuesUsingAccessors(TestMap.Builder builder)179 private void updateMapValuesUsingAccessors(TestMap.Builder builder) { 180 builder 181 .putInt32ToInt32Field(1, 111) 182 .removeInt32ToInt32Field(2) 183 .putInt32ToInt32Field(4, 44) 184 .putInt32ToStringField(1, "111") 185 .removeInt32ToStringField(2) 186 .putInt32ToStringField(4, "44") 187 .putInt32ToBytesField(1, TestUtil.toBytes("111")) 188 .removeInt32ToBytesField(2) 189 .putInt32ToBytesField(4, TestUtil.toBytes("44")) 190 .putInt32ToEnumField(1, TestMap.EnumValue.BAR) 191 .removeInt32ToEnumField(2) 192 .putInt32ToEnumField(4, TestMap.EnumValue.QUX) 193 .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build()) 194 .removeInt32ToMessageField(2) 195 .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build()) 196 .putStringToInt32Field("1", 111) 197 .removeStringToInt32Field("2") 198 .putStringToInt32Field("4", 44); 199 } 200 201 @Test testUpdateMapValues()202 public void testUpdateMapValues() { 203 TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder(); 204 setMapValuesUsingMutableMap(usingMutableMapBuilder); 205 TestMap usingMutableMap = usingMutableMapBuilder.build(); 206 assertMapValuesSet(usingMutableMap); 207 208 TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder(); 209 setMapValuesUsingAccessors(usingAccessorsBuilder); 210 TestMap usingAccessors = usingAccessorsBuilder.build(); 211 assertMapValuesSet(usingAccessors); 212 213 assertThat(usingAccessors).isEqualTo(usingMutableMap); 214 215 usingMutableMapBuilder = usingMutableMap.toBuilder(); 216 updateMapValuesUsingMutableMap(usingMutableMapBuilder); 217 usingMutableMap = usingMutableMapBuilder.build(); 218 assertMapValuesUpdated(usingMutableMap); 219 220 usingAccessorsBuilder = usingAccessors.toBuilder(); 221 updateMapValuesUsingAccessors(usingAccessorsBuilder); 222 usingAccessors = usingAccessorsBuilder.build(); 223 assertMapValuesUpdated(usingAccessors); 224 225 assertThat(usingAccessors).isEqualTo(usingMutableMap); 226 } 227 assertMapValuesUpdated(TestMap message)228 private void assertMapValuesUpdated(TestMap message) { 229 assertThat(message.getInt32ToInt32FieldMap()).hasSize(3); 230 assertThat(message.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(111); 231 assertThat(message.getInt32ToInt32FieldMap().get(3).intValue()).isEqualTo(33); 232 assertThat(message.getInt32ToInt32FieldMap().get(4).intValue()).isEqualTo(44); 233 234 assertThat(message.getInt32ToStringFieldMap()).hasSize(3); 235 assertThat(message.getInt32ToStringFieldMap()).containsEntry(1, "111"); 236 assertThat(message.getInt32ToStringFieldMap()).containsEntry(3, "33"); 237 assertThat(message.getInt32ToStringFieldMap()).containsEntry(4, "44"); 238 239 assertThat(message.getInt32ToBytesFieldMap()).hasSize(3); 240 assertThat(message.getInt32ToBytesFieldMap()).containsEntry(1, TestUtil.toBytes("111")); 241 assertThat(message.getInt32ToBytesFieldMap()).containsEntry(3, TestUtil.toBytes("33")); 242 assertThat(message.getInt32ToBytesFieldMap()).containsEntry(4, TestUtil.toBytes("44")); 243 244 assertThat(message.getInt32ToEnumFieldMap()).hasSize(3); 245 assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR); 246 assertThat(message.getInt32ToEnumFieldMap()).containsEntry(3, TestMap.EnumValue.BAZ); 247 assertThat(message.getInt32ToEnumFieldMap()).containsEntry(4, TestMap.EnumValue.QUX); 248 249 assertThat(message.getInt32ToMessageFieldMap()).hasSize(3); 250 assertThat(message.getInt32ToMessageFieldMap().get(1).getValue()).isEqualTo(111); 251 assertThat(message.getInt32ToMessageFieldMap().get(3).getValue()).isEqualTo(33); 252 assertThat(message.getInt32ToMessageFieldMap().get(4).getValue()).isEqualTo(44); 253 254 assertThat(message.getStringToInt32FieldMap()).hasSize(3); 255 assertThat(message.getStringToInt32FieldMap().get("1").intValue()).isEqualTo(111); 256 assertThat(message.getStringToInt32FieldMap().get("3").intValue()).isEqualTo(33); 257 assertThat(message.getStringToInt32FieldMap().get("4").intValue()).isEqualTo(44); 258 } 259 assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder)260 private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) { 261 assertThat(testMapOrBuilder.getInt32ToInt32FieldMap()).isEmpty(); 262 assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(0); 263 assertThat(testMapOrBuilder.getInt32ToStringFieldMap()).isEmpty(); 264 assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(0); 265 assertThat(testMapOrBuilder.getInt32ToBytesFieldMap()).isEmpty(); 266 assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(0); 267 assertThat(testMapOrBuilder.getInt32ToEnumFieldMap()).isEmpty(); 268 assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(0); 269 assertThat(testMapOrBuilder.getInt32ToMessageFieldMap()).isEmpty(); 270 assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(0); 271 assertThat(testMapOrBuilder.getStringToInt32FieldMap()).isEmpty(); 272 assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(0); 273 } 274 275 @Test testGetMapIsImmutable()276 public void testGetMapIsImmutable() { 277 TestMap.Builder builder = TestMap.newBuilder(); 278 assertMapsAreImmutable(builder); 279 assertMapsAreImmutable(builder.build()); 280 281 setMapValuesUsingAccessors(builder); 282 assertMapsAreImmutable(builder); 283 assertMapsAreImmutable(builder.build()); 284 } 285 assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder)286 private void assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder) { 287 assertImmutable(testMapOrBuilder.getInt32ToInt32FieldMap(), 1, 2); 288 assertImmutable(testMapOrBuilder.getInt32ToStringFieldMap(), 1, "2"); 289 assertImmutable(testMapOrBuilder.getInt32ToBytesFieldMap(), 1, TestUtil.toBytes("2")); 290 assertImmutable(testMapOrBuilder.getInt32ToEnumFieldMap(), 1, TestMap.EnumValue.FOO); 291 assertImmutable( 292 testMapOrBuilder.getInt32ToMessageFieldMap(), 1, MessageValue.getDefaultInstance()); 293 assertImmutable(testMapOrBuilder.getStringToInt32FieldMap(), "1", 2); 294 } 295 assertImmutable(Map<K, V> map, K key, V value)296 private <K, V> void assertImmutable(Map<K, V> map, K key, V value) { 297 try { 298 map.put(key, value); 299 assertWithMessage("expected exception").fail(); 300 } catch (UnsupportedOperationException e) { 301 // expected 302 } 303 } 304 305 @Test testMutableMapLifecycle()306 public void testMutableMapLifecycle() { 307 TestMap.Builder builder = TestMap.newBuilder(); 308 Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field(); 309 intMap.put(1, 2); 310 assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2)); 311 try { 312 intMap.put(2, 3); 313 assertWithMessage("expected exception intMap").fail(); 314 } catch (UnsupportedOperationException e) { 315 // expected 316 } 317 assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2)); 318 builder.getMutableInt32ToInt32Field().put(2, 3); 319 assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2, 2, 3)); 320 321 Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField(); 322 enumMap.put(1, TestMap.EnumValue.BAR); 323 assertThat(builder.build().getInt32ToEnumField()) 324 .isEqualTo(newMap(1, TestMap.EnumValue.BAR)); 325 try { 326 enumMap.put(2, TestMap.EnumValue.FOO); 327 assertWithMessage("expected exception enumMap").fail(); 328 } catch (UnsupportedOperationException e) { 329 // expected 330 } 331 assertThat(builder.getInt32ToEnumField()).isEqualTo(newMap(1, TestMap.EnumValue.BAR)); 332 builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO); 333 assertThat(builder.getInt32ToEnumField()).isEqualTo( 334 newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO)); 335 336 Map<Integer, String> stringMap = builder.getMutableInt32ToStringField(); 337 stringMap.put(1, "1"); 338 assertThat(builder.build().getInt32ToStringField()).isEqualTo(newMap(1, "1")); 339 try { 340 stringMap.put(2, "2"); 341 assertWithMessage("expected exception stringMap").fail(); 342 } catch (UnsupportedOperationException e) { 343 // expected 344 } 345 assertThat(builder.getInt32ToStringField()).isEqualTo(newMap(1, "1")); 346 builder.putInt32ToStringField(2, "2"); 347 assertThat(builder.getInt32ToStringField()).isEqualTo(newMap(1, "1", 2, "2")); 348 349 // Message maps are handled differently, and don't freeze old mutable collections. 350 Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField(); 351 messageMap.put(1, TestMap.MessageValue.getDefaultInstance()); 352 assertThat(builder.build().getInt32ToMessageField()) 353 .isEqualTo(newMap(1, TestMap.MessageValue.getDefaultInstance())); 354 // Mutations on old mutable maps don't affect the builder state. 355 messageMap.put(2, TestMap.MessageValue.getDefaultInstance()); 356 assertThat(builder.getInt32ToMessageField()).isEqualTo( 357 newMap(1, TestMap.MessageValue.getDefaultInstance())); 358 builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance()); 359 assertThat(builder.getInt32ToMessageField()).isEqualTo( 360 newMap(1, TestMap.MessageValue.getDefaultInstance(), 361 2, TestMap.MessageValue.getDefaultInstance())); 362 } 363 364 @Test testMutableMapLifecycle_collections()365 public void testMutableMapLifecycle_collections() { 366 TestMap.Builder builder = TestMap.newBuilder(); 367 Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field(); 368 intMap.put(1, 2); 369 assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2)); 370 try { 371 intMap.remove(2); 372 assertWithMessage("expected exception").fail(); 373 } catch (UnsupportedOperationException e) { 374 // expected 375 } 376 try { 377 intMap.entrySet().remove(new Object()); 378 assertWithMessage("expected exception").fail(); 379 } catch (UnsupportedOperationException e) { 380 // expected 381 } 382 try { 383 intMap.entrySet().iterator().remove(); 384 assertWithMessage("expected exception").fail(); 385 } catch (UnsupportedOperationException e) { 386 // expected 387 } 388 try { 389 intMap.keySet().remove(new Object()); 390 assertWithMessage("expected exception").fail(); 391 } catch (UnsupportedOperationException e) { 392 // expected 393 } 394 try { 395 intMap.values().remove(new Object()); 396 assertWithMessage("expected exception").fail(); 397 } catch (UnsupportedOperationException e) { 398 // expected 399 } 400 try { 401 intMap.values().iterator().remove(); 402 assertWithMessage("expected exception").fail(); 403 } catch (UnsupportedOperationException e) { 404 // expected 405 } 406 assertThat(intMap).isEqualTo(newMap(1, 2)); 407 assertThat(builder.getInt32ToInt32Field()).isEqualTo(newMap(1, 2)); 408 assertThat(builder.build().getInt32ToInt32Field()).isEqualTo(newMap(1, 2)); 409 } 410 411 @Test testGettersAndSetters()412 public void testGettersAndSetters() throws Exception { 413 TestMap.Builder builder = TestMap.newBuilder(); 414 TestMap message = builder.build(); 415 assertMapValuesCleared(message); 416 417 builder = message.toBuilder(); 418 setMapValuesUsingAccessors(builder); 419 message = builder.build(); 420 assertMapValuesSet(message); 421 422 builder = message.toBuilder(); 423 updateMapValuesUsingAccessors(builder); 424 message = builder.build(); 425 assertMapValuesUpdated(message); 426 427 builder = message.toBuilder(); 428 builder.clear(); 429 assertMapValuesCleared(builder); 430 message = builder.build(); 431 assertMapValuesCleared(message); 432 } 433 434 @Test testPutAll()435 public void testPutAll() throws Exception { 436 TestMap.Builder sourceBuilder = TestMap.newBuilder(); 437 setMapValuesUsingAccessors(sourceBuilder); 438 TestMap source = sourceBuilder.build(); 439 assertMapValuesSet(source); 440 441 TestMap.Builder destination = TestMap.newBuilder(); 442 copyMapValues(source, destination); 443 assertMapValuesSet(destination.build()); 444 } 445 446 @Test testPutAllWithNullStringValue()447 public void testPutAllWithNullStringValue() throws Exception { 448 TestMap.Builder sourceBuilder = TestMap.newBuilder(); 449 450 // order preserving map used here to help test rollback 451 Map<Integer, String> data = new TreeMap<>(); 452 data.put(7, "foo"); 453 data.put(8, "bar"); 454 data.put(9, null); 455 try { 456 sourceBuilder.putAllInt32ToStringField(data); 457 fail("allowed null string value"); 458 } catch (NullPointerException expected) { 459 // Verify rollback of previously added values. 460 // They all go in or none do. 461 assertThat(sourceBuilder.getInt32ToStringFieldMap()).isEmpty(); 462 } 463 } 464 465 @Test testPutNullStringValue()466 public void testPutNullStringValue() throws Exception { 467 TestMap.Builder sourceBuilder = TestMap.newBuilder(); 468 469 try { 470 sourceBuilder.putInt32ToStringField(8, null); 471 fail("allowed null string value"); 472 } catch (NullPointerException expected) { 473 assertNotNull(expected.getMessage()); 474 } 475 } 476 477 @Test testPutAllForUnknownEnumValues()478 public void testPutAllForUnknownEnumValues() throws Exception { 479 TestMap source = 480 TestMap.newBuilder() 481 .putAllInt32ToEnumFieldValue( 482 newMap( 483 0, 0, 484 1, 1, 485 2, 1000)) // unknown value. 486 .build(); 487 488 TestMap destination = 489 TestMap.newBuilder() 490 .putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValueMap()) 491 .build(); 492 493 assertThat(destination.getInt32ToEnumFieldValueMap().get(0).intValue()).isEqualTo(0); 494 assertThat(destination.getInt32ToEnumFieldValueMap().get(1).intValue()).isEqualTo(1); 495 assertThat(destination.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000); 496 assertThat(destination.getInt32ToEnumFieldCount()).isEqualTo(3); 497 } 498 499 @Test testPutForUnknownEnumValues()500 public void testPutForUnknownEnumValues() throws Exception { 501 TestMap message = 502 TestMap.newBuilder() 503 .putInt32ToEnumFieldValue(0, 0) 504 .putInt32ToEnumFieldValue(1, 1) 505 .putInt32ToEnumFieldValue(2, 1000) // unknown value. 506 .build(); 507 assertThat(message.getInt32ToEnumFieldValueOrThrow(0)).isEqualTo(0); 508 assertThat(message.getInt32ToEnumFieldValueOrThrow(1)).isEqualTo(1); 509 assertThat(message.getInt32ToEnumFieldValueOrThrow(2)).isEqualTo(1000); 510 assertThat(message.getInt32ToEnumFieldCount()).isEqualTo(3); 511 } 512 513 @Test testPutChecksNullKeysAndValues()514 public void testPutChecksNullKeysAndValues() throws Exception { 515 TestMap.Builder builder = TestMap.newBuilder(); 516 517 try { 518 builder.putInt32ToStringField(1, null); 519 assertWithMessage("expected exception").fail(); 520 } catch (NullPointerException e) { 521 // expected. 522 } 523 524 try { 525 builder.putInt32ToBytesField(1, null); 526 assertWithMessage("expected exception").fail(); 527 } catch (NullPointerException e) { 528 // expected. 529 } 530 531 try { 532 builder.putInt32ToEnumField(1, null); 533 assertWithMessage("expected exception").fail(); 534 } catch (NullPointerException e) { 535 // expected. 536 } 537 538 try { 539 builder.putInt32ToMessageField(1, null); 540 assertWithMessage("expected exception").fail(); 541 } catch (NullPointerException e) { 542 // expected. 543 } 544 545 try { 546 builder.putStringToInt32Field(null, 1); 547 assertWithMessage("expected exception").fail(); 548 } catch (NullPointerException e) { 549 // expected. 550 } 551 } 552 553 @Test testPutBuilderIfAbsent()554 public void testPutBuilderIfAbsent() { 555 TestMap.Builder builder = TestMap.newBuilder(); 556 MessageValue.Builder subBuilder = builder.putInt32ToMessageFieldBuilderIfAbsent(1); 557 558 assertThat(builder.putInt32ToMessageFieldBuilderIfAbsent(1)).isSameInstanceAs(subBuilder); 559 560 subBuilder.setValue(11); 561 assertThat(builder.getInt32ToMessageFieldOrThrow(1).getValue()).isEqualTo(11); 562 builder.putInt32ToMessageFieldBuilderIfAbsent(1).setValue(22); 563 assertThat(builder.getInt32ToMessageFieldOrThrow(1).getValue()).isEqualTo(22); 564 565 builder.putInt32ToMessageField(2, MessageValue.newBuilder().setValue(33).build()); 566 assertThat(builder.putInt32ToMessageFieldBuilderIfAbsent(2).getValue()).isEqualTo(33); 567 } 568 569 @Test testSerializeAndParse()570 public void testSerializeAndParse() throws Exception { 571 TestMap.Builder builder = TestMap.newBuilder(); 572 setMapValuesUsingAccessors(builder); 573 TestMap message = builder.build(); 574 assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize()); 575 message = TestMap.parseFrom(message.toByteString()); 576 assertMapValuesSet(message); 577 578 builder = message.toBuilder(); 579 updateMapValuesUsingAccessors(builder); 580 message = builder.build(); 581 assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize()); 582 message = TestMap.parseFrom(message.toByteString()); 583 assertMapValuesUpdated(message); 584 585 builder = message.toBuilder(); 586 builder.clear(); 587 message = builder.build(); 588 assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize()); 589 message = TestMap.parseFrom(message.toByteString()); 590 assertMapValuesCleared(message); 591 } 592 tryParseTestMap(BizarroTestMap bizarroMap)593 private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException { 594 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 595 CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream); 596 bizarroMap.writeTo(output); 597 output.flush(); 598 return TestMap.parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray())); 599 } 600 601 @Test testParseError()602 public void testParseError() throws Exception { 603 ByteString bytes = TestUtil.toBytes("SOME BYTES"); 604 String stringKey = "a string key"; 605 606 TestMap map = 607 tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build()); 608 assertThat(map.getInt32ToInt32FieldOrDefault(5, -1)).isEqualTo(0); 609 610 map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build()); 611 assertThat(map.getInt32ToStringFieldOrDefault(0, null)).isEmpty(); 612 613 map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build()); 614 assertThat(ByteString.EMPTY).isEqualTo(map.getInt32ToBytesFieldOrDefault(0, null)); 615 616 map = 617 tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build()); 618 assertThat(map.getInt32ToEnumFieldOrDefault(0, null)).isEqualTo(TestMap.EnumValue.FOO); 619 620 try { 621 tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build()); 622 assertWithMessage("expected exception").fail(); 623 } catch (InvalidProtocolBufferException expected) { 624 assertThat(expected.getUnfinishedMessage()).isInstanceOf(TestMap.class); 625 map = (TestMap) expected.getUnfinishedMessage(); 626 assertThat(map.getInt32ToMessageFieldMap()).isEmpty(); 627 } 628 629 map = 630 tryParseTestMap( 631 BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build()); 632 assertThat(map.getStringToInt32FieldOrDefault(stringKey, -1)).isEqualTo(0); 633 } 634 635 @Test testMergeFrom()636 public void testMergeFrom() throws Exception { 637 TestMap.Builder builder = TestMap.newBuilder(); 638 setMapValuesUsingAccessors(builder); 639 TestMap message = builder.build(); 640 641 TestMap.Builder other = TestMap.newBuilder(); 642 other.mergeFrom(message); 643 assertMapValuesSet(other.build()); 644 } 645 646 @Test testEqualsAndHashCode()647 public void testEqualsAndHashCode() throws Exception { 648 // Test that generated equals() and hashCode() will disregard the order 649 // of map entries when comparing/hashing map fields. 650 651 // We can't control the order of elements in a HashMap. The best we can do 652 // here is to add elements in different order. 653 TestMap m1 = 654 TestMap.newBuilder() 655 .putInt32ToInt32Field(1, 2) 656 .putInt32ToInt32Field(3, 4) 657 .putInt32ToInt32Field(5, 6) 658 .build(); 659 660 TestMap.Builder b2 = 661 TestMap.newBuilder() 662 .putInt32ToInt32Field(5, 6) 663 .putInt32ToInt32Field(1, 2) 664 .putInt32ToInt32Field(3, 4); 665 TestMap m2 = b2.build(); 666 667 assertThat(m2).isEqualTo(m1); 668 assertThat(m2.hashCode()).isEqualTo(m1.hashCode()); 669 670 // Make sure we did compare map fields. 671 b2.putInt32ToInt32Field(1, 0); 672 m2 = b2.build(); 673 assertThat(m1.equals(m2)).isFalse(); 674 // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed 675 // to be different. 676 677 // Regression test for b/18549190: if a map is a subset of the other map, 678 // equals() should return false. 679 b2.removeInt32ToInt32Field(1); 680 m2 = b2.build(); 681 assertThat(m1.equals(m2)).isFalse(); 682 assertThat(m2.equals(m1)).isFalse(); 683 } 684 685 @Test testNestedBuilderOnChangeEventPropagation()686 public void testNestedBuilderOnChangeEventPropagation() { 687 TestOnChangeEventPropagation.Builder parent = TestOnChangeEventPropagation.newBuilder(); 688 parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 2); 689 TestOnChangeEventPropagation message = parent.build(); 690 assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue()) 691 .isEqualTo(2); 692 693 // Make a change using nested builder. 694 parent.getOptionalMessageBuilder().putInt32ToInt32Field(1, 3); 695 696 // Should be able to observe the change. 697 message = parent.build(); 698 assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue()) 699 .isEqualTo(3); 700 701 // Make another change using mergeFrom() 702 TestMap other = TestMap.newBuilder().putInt32ToInt32Field(1, 4).build(); 703 parent.getOptionalMessageBuilder().mergeFrom(other); 704 705 // Should be able to observe the change. 706 message = parent.build(); 707 assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue()) 708 .isEqualTo(4); 709 710 // Make yet another change by clearing the nested builder. 711 parent.getOptionalMessageBuilder().clear(); 712 713 // Should be able to observe the change. 714 message = parent.build(); 715 assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap()).isEmpty(); 716 } 717 718 @Test testNestedBuilderOnChangeEventPropagationReflection()719 public void testNestedBuilderOnChangeEventPropagationReflection() { 720 FieldDescriptor intMapField = f("int32_to_int32_field"); 721 // Create an outer message builder with nested builder. 722 TestOnChangeEventPropagation.Builder parentBuilder = TestOnChangeEventPropagation.newBuilder(); 723 TestMap.Builder testMapBuilder = parentBuilder.getOptionalMessageBuilder(); 724 725 // Create a map entry message. 726 TestMap.Builder entryBuilder = TestMap.newBuilder().putInt32ToInt32Field(1, 1); 727 728 // Put the entry into the nested builder. 729 testMapBuilder.addRepeatedField(intMapField, entryBuilder.getRepeatedField(intMapField, 0)); 730 731 // Should be able to observe the change. 732 TestOnChangeEventPropagation message = parentBuilder.build(); 733 assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap()).hasSize(1); 734 735 // Change the entry value. 736 entryBuilder.putInt32ToInt32Field(1, 4); 737 testMapBuilder = parentBuilder.getOptionalMessageBuilder(); 738 testMapBuilder.setRepeatedField(intMapField, 0, entryBuilder.getRepeatedField(intMapField, 0)); 739 740 // Should be able to observe the change. 741 message = parentBuilder.build(); 742 assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap().get(1).intValue()) 743 .isEqualTo(4); 744 745 // Clear the nested builder. 746 testMapBuilder = parentBuilder.getOptionalMessageBuilder(); 747 testMapBuilder.clearField(intMapField); 748 749 // Should be able to observe the change. 750 message = parentBuilder.build(); 751 assertThat(message.getOptionalMessage().getInt32ToInt32FieldMap()).isEmpty(); 752 } 753 754 // The following methods are used to test reflection API. 755 f(String name)756 private static FieldDescriptor f(String name) { 757 return TestMap.getDescriptor().findFieldByName(name); 758 } 759 getFieldValue(Message mapEntry, String name)760 private static Object getFieldValue(Message mapEntry, String name) { 761 FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); 762 return mapEntry.getField(field); 763 } 764 setFieldValue( Message.Builder mapEntry, String name, Object value)765 private static Message.Builder setFieldValue( 766 Message.Builder mapEntry, String name, Object value) { 767 FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); 768 mapEntry.setField(field, value); 769 return mapEntry; 770 } 771 assertHasMapValues(Message message, String name, Map<?, ?> values)772 private static void assertHasMapValues(Message message, String name, Map<?, ?> values) { 773 FieldDescriptor field = f(name); 774 for (Object entry : (List<?>) message.getField(field)) { 775 Message mapEntry = (Message) entry; 776 Object key = getFieldValue(mapEntry, "key"); 777 Object value = getFieldValue(mapEntry, "value"); 778 assertThat(values.containsKey(key)).isTrue(); 779 assertThat(values.get(key)).isEqualTo(value); 780 } 781 assertThat(message.getRepeatedFieldCount(field)).isEqualTo(values.size()); 782 for (int i = 0; i < message.getRepeatedFieldCount(field); i++) { 783 Message mapEntry = (Message) message.getRepeatedField(field, i); 784 Object key = getFieldValue(mapEntry, "key"); 785 Object value = getFieldValue(mapEntry, "value"); 786 assertThat(values.containsKey(key)).isTrue(); 787 assertThat(values.get(key)).isEqualTo(value); 788 } 789 } 790 newMapEntry(Message.Builder builder, String name, K key, V value)791 private static <K, V> Message newMapEntry(Message.Builder builder, String name, K key, V value) { 792 FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); 793 Message.Builder entryBuilder = builder.newBuilderForField(field); 794 FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key"); 795 FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value"); 796 entryBuilder.setField(keyField, key); 797 entryBuilder.setField(valueField, value); 798 return entryBuilder.build(); 799 } 800 setMapValues(Message.Builder builder, String name, Map<?, ?> values)801 private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) { 802 List<Message> entryList = new ArrayList<>(); 803 for (Map.Entry<?, ?> entry : values.entrySet()) { 804 entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue())); 805 } 806 FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); 807 builder.setField(field, entryList); 808 } 809 mapForValues(K key1, V value1, K key2, V value2)810 private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) { 811 Map<K, V> map = new HashMap<>(); 812 map.put(key1, value1); 813 map.put(key2, value2); 814 return map; 815 } 816 817 @Test testReflectionApi()818 public void testReflectionApi() throws Exception { 819 // In reflection API, map fields are just repeated message fields. 820 TestMap.Builder builder = 821 TestMap.newBuilder() 822 .putInt32ToInt32Field(1, 2) 823 .putInt32ToInt32Field(3, 4) 824 .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build()) 825 .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build()); 826 TestMap message = builder.build(); 827 828 // Test getField(), getRepeatedFieldCount(), getRepeatedField(). 829 assertHasMapValues(message, "int32_to_int32_field", mapForValues(1, 2, 3, 4)); 830 assertHasMapValues( 831 message, 832 "int32_to_message_field", 833 mapForValues( 834 11, MessageValue.newBuilder().setValue(22).build(), 835 33, MessageValue.newBuilder().setValue(44).build())); 836 837 // Test clearField() 838 builder.clearField(f("int32_to_int32_field")); 839 builder.clearField(f("int32_to_message_field")); 840 message = builder.build(); 841 assertThat(message.getInt32ToInt32FieldMap()).isEmpty(); 842 assertThat(message.getInt32ToMessageFieldMap()).isEmpty(); 843 844 // Test setField() 845 setMapValues(builder, "int32_to_int32_field", mapForValues(11, 22, 33, 44)); 846 setMapValues( 847 builder, 848 "int32_to_message_field", 849 mapForValues( 850 111, MessageValue.newBuilder().setValue(222).build(), 851 333, MessageValue.newBuilder().setValue(444).build())); 852 message = builder.build(); 853 assertThat(message.getInt32ToInt32FieldMap().get(11).intValue()).isEqualTo(22); 854 assertThat(message.getInt32ToInt32FieldMap().get(33).intValue()).isEqualTo(44); 855 assertThat(message.getInt32ToMessageFieldMap().get(111).getValue()).isEqualTo(222); 856 assertThat(message.getInt32ToMessageFieldMap().get(333).getValue()).isEqualTo(444); 857 858 // Test addRepeatedField 859 builder.addRepeatedField( 860 f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 66)); 861 builder.addRepeatedField( 862 f("int32_to_message_field"), 863 newMapEntry( 864 builder, 865 "int32_to_message_field", 866 555, 867 MessageValue.newBuilder().setValue(666).build())); 868 message = builder.build(); 869 assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(66); 870 assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(666); 871 872 // Test addRepeatedField (overriding existing values) 873 builder.addRepeatedField( 874 f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 55)); 875 builder.addRepeatedField( 876 f("int32_to_message_field"), 877 newMapEntry( 878 builder, 879 "int32_to_message_field", 880 555, 881 MessageValue.newBuilder().setValue(555).build())); 882 message = builder.build(); 883 assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55); 884 assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(555); 885 886 // Test setRepeatedField 887 for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) { 888 Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i); 889 int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue(); 890 int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue(); 891 // Swap key with value for each entry. 892 Message.Builder mapEntryBuilder = mapEntry.toBuilder(); 893 setFieldValue(mapEntryBuilder, "key", oldValue); 894 setFieldValue(mapEntryBuilder, "value", oldKey); 895 builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build()); 896 } 897 message = builder.build(); 898 assertThat(message.getInt32ToInt32FieldMap().get(22).intValue()).isEqualTo(11); 899 assertThat(message.getInt32ToInt32FieldMap().get(44).intValue()).isEqualTo(33); 900 assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55); 901 } 902 903 // See additional coverage in TextFormatTest.java. 904 @Test testTextFormat()905 public void testTextFormat() throws Exception { 906 TestMap.Builder builder = TestMap.newBuilder(); 907 setMapValuesUsingAccessors(builder); 908 TestMap message = builder.build(); 909 910 String textData = TextFormat.printer().printToString(message); 911 912 builder = TestMap.newBuilder(); 913 TextFormat.merge(textData, builder); 914 message = builder.build(); 915 916 assertMapValuesSet(message); 917 } 918 919 @Test testDynamicMessage()920 public void testDynamicMessage() throws Exception { 921 TestMap.Builder builder = TestMap.newBuilder(); 922 setMapValuesUsingAccessors(builder); 923 TestMap message = builder.build(); 924 925 Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); 926 Message dynamicMessage = 927 dynamicDefaultInstance 928 .newBuilderForType() 929 .mergeFrom(message.toByteString(), ExtensionRegistry.getEmptyRegistry()) 930 .build(); 931 932 assertThat(dynamicMessage).isEqualTo(message); 933 assertThat(dynamicMessage.hashCode()).isEqualTo(message.hashCode()); 934 } 935 936 // Check that DynamicMessage handles map field serialization the same way as generated code 937 // regarding unset key and value field in a map entry. 938 @Test testDynamicMessageUnsetKeyAndValue()939 public void testDynamicMessageUnsetKeyAndValue() throws Exception { 940 FieldDescriptor field = f("int32_to_int32_field"); 941 942 Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); 943 Message.Builder builder = dynamicDefaultInstance.newBuilderForType(); 944 // Add an entry without key and value. 945 builder.addRepeatedField(field, builder.newBuilderForField(field).build()); 946 Message message = builder.build(); 947 ByteString bytes = message.toByteString(); 948 // Parse it back to the same generated type. 949 Message generatedMessage = TestMap.parseFrom(bytes, ExtensionRegistry.getEmptyRegistry()); 950 // Assert the serialized bytes are equivalent. 951 assertThat(bytes).isEqualTo(generatedMessage.toByteString()); 952 } 953 954 @Test testReflectionEqualsAndHashCode()955 public void testReflectionEqualsAndHashCode() throws Exception { 956 // Test that generated equals() and hashCode() will disregard the order 957 // of map entries when comparing/hashing map fields. 958 959 // We use DynamicMessage to test reflection based equals()/hashCode(). 960 Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); 961 FieldDescriptor field = f("int32_to_int32_field"); 962 963 Message.Builder b1 = dynamicDefaultInstance.newBuilderForType(); 964 b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2)); 965 b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4)); 966 b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6)); 967 Message m1 = b1.build(); 968 969 Message.Builder b2 = dynamicDefaultInstance.newBuilderForType(); 970 b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6)); 971 b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2)); 972 b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4)); 973 Message m2 = b2.build(); 974 975 assertThat(m2).isEqualTo(m1); 976 assertThat(m2.hashCode()).isEqualTo(m1.hashCode()); 977 978 // Make sure we did compare map fields. 979 b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0)); 980 m2 = b2.build(); 981 assertThat(m1).isNotEqualTo(m2); 982 // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed 983 // to be different. 984 } 985 986 @Test 987 @SuppressWarnings("ProtoNewBuilderMergeFrom") testUnknownEnumValues()988 public void testUnknownEnumValues() throws Exception { 989 TestMap.Builder builder = 990 TestMap.newBuilder() 991 .putAllInt32ToEnumFieldValue( 992 newMap( 993 0, 0, 994 1, 1, 995 2, 1000)); // unknown value. 996 TestMap message = builder.build(); 997 998 assertThat(message.getInt32ToEnumFieldMap()).containsEntry(0, TestMap.EnumValue.FOO); 999 assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR); 1000 assertThat(message.getInt32ToEnumFieldMap()).containsEntry(2, TestMap.EnumValue.UNRECOGNIZED); 1001 assertThat(message.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000); 1002 1003 // Unknown enum values should be preserved after: 1004 // 1. Serialization and parsing. 1005 // 2. toBuild(). 1006 // 3. mergeFrom(). 1007 message = TestMap.parseFrom(message.toByteString(), ExtensionRegistry.getEmptyRegistry()); 1008 assertThat(message.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000); 1009 builder = message.toBuilder(); 1010 assertThat(builder.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000); 1011 builder = TestMap.newBuilder().mergeFrom(message); 1012 assertThat(builder.getInt32ToEnumFieldValueMap().get(2).intValue()).isEqualTo(1000); 1013 1014 // hashCode()/equals() should take unknown enum values into account. 1015 builder.putAllInt32ToEnumFieldValue(newMap(2, 1001)); 1016 TestMap message2 = builder.build(); 1017 assertThat(message.hashCode()).isNotEqualTo(message2.hashCode()); 1018 assertThat(message.equals(message2)).isFalse(); 1019 // Unknown values will be converted to UNRECOGNIZED so the resulted enum map 1020 // should be the same. 1021 assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message2.getInt32ToEnumFieldMap()); 1022 } 1023 1024 @Test testUnknownEnumValuesInReflectionApi()1025 public void testUnknownEnumValuesInReflectionApi() throws Exception { 1026 Descriptor descriptor = TestMap.getDescriptor(); 1027 EnumDescriptor enumDescriptor = TestMap.EnumValue.getDescriptor(); 1028 FieldDescriptor field = descriptor.findFieldByName("int32_to_enum_field"); 1029 1030 Map<Integer, Integer> data = 1031 newMap( 1032 0, 0, 1033 1, 1, 1034 2, 1000); // unknown value 1035 1036 TestMap.Builder builder = TestMap.newBuilder().putAllInt32ToEnumFieldValue(data); 1037 1038 // Try to read unknown enum values using reflection API. 1039 for (int i = 0; i < builder.getRepeatedFieldCount(field); i++) { 1040 Message mapEntry = (Message) builder.getRepeatedField(field, i); 1041 int key = ((Integer) getFieldValue(mapEntry, "key")).intValue(); 1042 int value = ((EnumValueDescriptor) getFieldValue(mapEntry, "value")).getNumber(); 1043 assertThat(value).isEqualTo(data.get(key).intValue()); 1044 Message.Builder mapEntryBuilder = mapEntry.toBuilder(); 1045 // Increase the value by 1. 1046 setFieldValue( 1047 mapEntryBuilder, "value", enumDescriptor.findValueByNumberCreatingIfUnknown(value + 1)); 1048 builder.setRepeatedField(field, i, mapEntryBuilder.build()); 1049 } 1050 1051 // Verify that enum values have been successfully updated. 1052 TestMap message = builder.build(); 1053 for (Map.Entry<Integer, Integer> entry : message.getInt32ToEnumFieldValueMap().entrySet()) { 1054 assertThat(entry.getValue().intValue()).isEqualTo(data.get(entry.getKey()) + 1); 1055 } 1056 } 1057 1058 @Test testIterationOrder()1059 public void testIterationOrder() throws Exception { 1060 TestMap.Builder builder = TestMap.newBuilder(); 1061 setMapValuesUsingAccessors(builder); 1062 TestMap message = builder.build(); 1063 1064 assertThat(new ArrayList<>(message.getStringToInt32FieldMap().keySet())) 1065 .containsExactly("1", "2", "3") 1066 .inOrder(); 1067 } 1068 1069 @Test testGetMap()1070 public void testGetMap() { 1071 TestMap.Builder builder = TestMap.newBuilder(); 1072 setMapValuesUsingAccessors(builder); 1073 TestMap message = builder.build(); 1074 assertThat(message.getStringToInt32FieldMap()).isEqualTo(message.getStringToInt32FieldMap()); 1075 assertThat(message.getInt32ToBytesFieldMap()).isEqualTo(message.getInt32ToBytesFieldMap()); 1076 assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message.getInt32ToEnumFieldMap()); 1077 assertThat(message.getInt32ToEnumFieldValueMap()) 1078 .isEqualTo(message.getInt32ToEnumFieldValueMap()); 1079 assertThat(message.getInt32ToMessageFieldMap()).isEqualTo(message.getInt32ToMessageFieldMap()); 1080 } 1081 1082 @Test testContains()1083 public void testContains() { 1084 TestMap.Builder builder = TestMap.newBuilder(); 1085 setMapValuesUsingAccessors(builder); 1086 assertMapContainsSetValues(builder); 1087 assertMapContainsSetValues(builder.build()); 1088 } 1089 assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder)1090 private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) { 1091 assertThat(testMapOrBuilder.containsInt32ToInt32Field(1)).isTrue(); 1092 assertThat(testMapOrBuilder.containsInt32ToInt32Field(2)).isTrue(); 1093 assertThat(testMapOrBuilder.containsInt32ToInt32Field(3)).isTrue(); 1094 assertThat(testMapOrBuilder.containsInt32ToInt32Field(-1)).isFalse(); 1095 1096 assertThat(testMapOrBuilder.containsInt32ToStringField(1)).isTrue(); 1097 assertThat(testMapOrBuilder.containsInt32ToStringField(2)).isTrue(); 1098 assertThat(testMapOrBuilder.containsInt32ToStringField(3)).isTrue(); 1099 assertThat(testMapOrBuilder.containsInt32ToStringField(-1)).isFalse(); 1100 1101 assertThat(testMapOrBuilder.containsInt32ToBytesField(1)).isTrue(); 1102 assertThat(testMapOrBuilder.containsInt32ToBytesField(2)).isTrue(); 1103 assertThat(testMapOrBuilder.containsInt32ToBytesField(3)).isTrue(); 1104 assertThat(testMapOrBuilder.containsInt32ToBytesField(-1)).isFalse(); 1105 1106 assertThat(testMapOrBuilder.containsInt32ToEnumField(1)).isTrue(); 1107 assertThat(testMapOrBuilder.containsInt32ToEnumField(2)).isTrue(); 1108 assertThat(testMapOrBuilder.containsInt32ToEnumField(3)).isTrue(); 1109 assertThat(testMapOrBuilder.containsInt32ToEnumField(-1)).isFalse(); 1110 1111 assertThat(testMapOrBuilder.containsInt32ToMessageField(1)).isTrue(); 1112 assertThat(testMapOrBuilder.containsInt32ToMessageField(2)).isTrue(); 1113 assertThat(testMapOrBuilder.containsInt32ToMessageField(3)).isTrue(); 1114 assertThat(testMapOrBuilder.containsInt32ToMessageField(-1)).isFalse(); 1115 1116 assertThat(testMapOrBuilder.containsStringToInt32Field("1")).isTrue(); 1117 assertThat(testMapOrBuilder.containsStringToInt32Field("2")).isTrue(); 1118 assertThat(testMapOrBuilder.containsStringToInt32Field("3")).isTrue(); 1119 assertThat(testMapOrBuilder.containsStringToInt32Field("-1")).isFalse(); 1120 } 1121 1122 @Test testCount()1123 public void testCount() { 1124 TestMap.Builder builder = TestMap.newBuilder(); 1125 assertMapCounts(0, builder); 1126 1127 setMapValuesUsingAccessors(builder); 1128 assertMapCounts(3, builder); 1129 1130 TestMap message = builder.build(); 1131 assertMapCounts(3, message); 1132 1133 builder = message.toBuilder().putInt32ToInt32Field(4, 44); 1134 assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4); 1135 assertThat(builder.build().getInt32ToInt32FieldCount()).isEqualTo(4); 1136 1137 // already present - should be unchanged 1138 builder.putInt32ToInt32Field(4, 44); 1139 assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4); 1140 } 1141 assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder)1142 private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) { 1143 assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(expectedCount); 1144 assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(expectedCount); 1145 assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(expectedCount); 1146 assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(expectedCount); 1147 assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(expectedCount); 1148 assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(expectedCount); 1149 } 1150 1151 @Test testGetOrDefault()1152 public void testGetOrDefault() { 1153 TestMap.Builder builder = TestMap.newBuilder(); 1154 assertMapCounts(0, builder); 1155 setMapValuesUsingAccessors(builder); 1156 doTestGetOrDefault(builder); 1157 doTestGetOrDefault(builder.build()); 1158 } 1159 doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder)1160 public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) { 1161 assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11)).isEqualTo(11); 1162 assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11)).isEqualTo(-11); 1163 1164 assertThat(testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11")).isEqualTo("11"); 1165 assertWithMessage("-11") 1166 .that(testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null)) 1167 .isNull(); 1168 1169 assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null)) 1170 .isEqualTo(TestUtil.toBytes("11")); 1171 assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null)).isNull(); 1172 1173 assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null)) 1174 .isEqualTo(TestMap.EnumValue.FOO); 1175 assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null)).isNull(); 1176 1177 assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(2, -1)) 1178 .isEqualTo(TestMap.EnumValue.BAR.getNumber()); 1179 assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(-1000, -1)).isEqualTo(-1); 1180 1181 assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null)) 1182 .isEqualTo(MessageValue.newBuilder().setValue(11).build()); 1183 assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null)).isNull(); 1184 1185 assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11)).isEqualTo(11); 1186 assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11)).isEqualTo(-11); 1187 1188 try { 1189 testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11); 1190 assertWithMessage("expected exception").fail(); 1191 } catch (NullPointerException e) { 1192 // expected 1193 } 1194 } 1195 1196 @Test testGetOrThrow()1197 public void testGetOrThrow() { 1198 TestMap.Builder builder = TestMap.newBuilder(); 1199 assertMapCounts(0, builder); 1200 setMapValuesUsingAccessors(builder); 1201 doTestGetOrDefault(builder); 1202 doTestGetOrDefault(builder.build()); 1203 } 1204 doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder)1205 public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) { 1206 assertThat(testMapOrBuilder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11); 1207 try { 1208 testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1); 1209 assertWithMessage("expected exception").fail(); 1210 } catch (IllegalArgumentException e) { 1211 // expected 1212 } 1213 1214 assertThat(testMapOrBuilder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11"); 1215 1216 try { 1217 testMapOrBuilder.getInt32ToStringFieldOrThrow(-1); 1218 assertWithMessage("expected exception").fail(); 1219 } catch (IllegalArgumentException e) { 1220 // expected 1221 } 1222 1223 assertThat(testMapOrBuilder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11")); 1224 1225 try { 1226 testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1); 1227 assertWithMessage("expected exception").fail(); 1228 } catch (IllegalArgumentException e) { 1229 // expected 1230 } 1231 1232 assertThat(testMapOrBuilder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO); 1233 try { 1234 testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1); 1235 assertWithMessage("expected exception").fail(); 1236 } catch (IllegalArgumentException e) { 1237 // expected 1238 } 1239 1240 assertThat(testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(2)) 1241 .isEqualTo(TestMap.EnumValue.BAR.getNumber()); 1242 try { 1243 testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(-1); 1244 assertWithMessage("expected exception").fail(); 1245 } catch (IllegalArgumentException e) { 1246 // expected 1247 } 1248 1249 assertThat(testMapOrBuilder.getInt32ToMessageFieldOrThrow(1)) 1250 .isEqualTo(MessageValue.newBuilder().setValue(11).build()); 1251 try { 1252 testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1); 1253 assertWithMessage("expected exception").fail(); 1254 } catch (IllegalArgumentException e) { 1255 // expected 1256 } 1257 1258 assertThat(testMapOrBuilder.getStringToInt32FieldOrThrow("1")).isEqualTo(11); 1259 try { 1260 testMapOrBuilder.getStringToInt32FieldOrThrow("-1"); 1261 assertWithMessage("expected exception").fail(); 1262 } catch (IllegalArgumentException e) { 1263 // expected 1264 } 1265 1266 try { 1267 testMapOrBuilder.getStringToInt32FieldOrThrow(null); 1268 assertWithMessage("expected exception").fail(); 1269 } catch (NullPointerException e) { 1270 // expected 1271 } 1272 } 1273 1274 @Test testPut()1275 public void testPut() { 1276 TestMap.Builder builder = TestMap.newBuilder(); 1277 builder.putInt32ToInt32Field(1, 11); 1278 assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11); 1279 1280 builder.putInt32ToStringField(1, "a"); 1281 assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("a"); 1282 try { 1283 builder.putInt32ToStringField(1, null); 1284 assertWithMessage("expected exception").fail(); 1285 } catch (NullPointerException e) { 1286 // expected 1287 } 1288 1289 builder.putInt32ToBytesField(1, TestUtil.toBytes("11")); 1290 assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11")); 1291 try { 1292 builder.putInt32ToBytesField(1, null); 1293 assertWithMessage("expected exception").fail(); 1294 } catch (NullPointerException e) { 1295 // expected 1296 } 1297 1298 builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO); 1299 assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO); 1300 try { 1301 builder.putInt32ToEnumField(1, null); 1302 assertWithMessage("expected exception").fail(); 1303 } catch (NullPointerException e) { 1304 // expected 1305 } 1306 1307 builder.putInt32ToEnumFieldValue(1, TestMap.EnumValue.BAR.getNumber()); 1308 assertThat(builder.getInt32ToEnumFieldValueOrThrow(1)) 1309 .isEqualTo(TestMap.EnumValue.BAR.getNumber()); 1310 builder.putInt32ToEnumFieldValue(1, -1); 1311 assertThat(builder.getInt32ToEnumFieldValueOrThrow(1)).isEqualTo(-1); 1312 assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.UNRECOGNIZED); 1313 1314 builder.putStringToInt32Field("a", 1); 1315 assertThat(builder.getStringToInt32FieldOrThrow("a")).isEqualTo(1); 1316 try { 1317 builder.putStringToInt32Field(null, -1); 1318 } catch (NullPointerException e) { 1319 // expected 1320 } 1321 } 1322 1323 @Test testRemove()1324 public void testRemove() { 1325 TestMap.Builder builder = TestMap.newBuilder(); 1326 setMapValuesUsingAccessors(builder); 1327 assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11); 1328 for (int times = 0; times < 2; times++) { 1329 builder.removeInt32ToInt32Field(1); 1330 assertThat(builder.getInt32ToInt32FieldOrDefault(1, -1)).isEqualTo(-1); 1331 } 1332 1333 assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11"); 1334 for (int times = 0; times < 2; times++) { 1335 builder.removeInt32ToStringField(1); 1336 assertThat(builder.getInt32ToStringFieldOrDefault(1, null)).isNull(); 1337 } 1338 1339 assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11")); 1340 for (int times = 0; times < 2; times++) { 1341 builder.removeInt32ToBytesField(1); 1342 assertThat(builder.getInt32ToBytesFieldOrDefault(1, null)).isNull(); 1343 } 1344 1345 assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO); 1346 for (int times = 0; times < 2; times++) { 1347 builder.removeInt32ToEnumField(1); 1348 assertThat(builder.getInt32ToEnumFieldOrDefault(1, null)).isNull(); 1349 } 1350 1351 assertThat(builder.getStringToInt32FieldOrThrow("1")).isEqualTo(11); 1352 for (int times = 0; times < 2; times++) { 1353 builder.removeStringToInt32Field("1"); 1354 assertThat(builder.getStringToInt32FieldOrDefault("1", -1)).isEqualTo(-1); 1355 } 1356 1357 try { 1358 builder.removeStringToInt32Field(null); 1359 assertWithMessage("expected exception").fail(); 1360 } catch (NullPointerException e) { 1361 // expected 1362 } 1363 } 1364 1365 @Test testReservedWordsFieldNames()1366 public void testReservedWordsFieldNames() { 1367 ReservedAsMapField unused1 = ReservedAsMapField.getDefaultInstance(); 1368 ReservedAsMapFieldWithEnumValue unused2 = ReservedAsMapFieldWithEnumValue.getDefaultInstance(); 1369 } 1370 1371 @Test testDeterministicSerialization()1372 public void testDeterministicSerialization() throws Exception { 1373 TestMap.Builder builder = TestMap.newBuilder(); 1374 // int32->int32 1375 builder.putInt32ToInt32Field(5, 1); 1376 builder.putInt32ToInt32Field(1, 1); 1377 builder.putInt32ToInt32Field(4, 1); 1378 builder.putInt32ToInt32Field(-2, 1); 1379 builder.putInt32ToInt32Field(0, 1); 1380 1381 // uint32->int32 1382 builder.putUint32ToInt32Field(5, 1); 1383 builder.putUint32ToInt32Field(1, 1); 1384 builder.putUint32ToInt32Field(4, 1); 1385 builder.putUint32ToInt32Field(-2, 1); 1386 builder.putUint32ToInt32Field(0, 1); 1387 1388 // int64->int32 1389 builder.putInt64ToInt32Field(5L, 1); 1390 builder.putInt64ToInt32Field(1L, 1); 1391 builder.putInt64ToInt32Field(4L, 1); 1392 builder.putInt64ToInt32Field(-2L, 1); 1393 builder.putInt64ToInt32Field(0L, 1); 1394 1395 // string->int32 1396 builder.putStringToInt32Field("baz", 1); 1397 builder.putStringToInt32Field("foo", 1); 1398 builder.putStringToInt32Field("bar", 1); 1399 builder.putStringToInt32Field("", 1); 1400 builder.putStringToInt32Field("hello", 1); 1401 builder.putStringToInt32Field("world", 1); 1402 1403 TestMap message = builder.build(); 1404 byte[] serialized = new byte[message.getSerializedSize()]; 1405 CodedOutputStream output = CodedOutputStream.newInstance(serialized); 1406 output.useDeterministicSerialization(); 1407 message.writeTo(output); 1408 output.flush(); 1409 1410 CodedInputStream input = CodedInputStream.newInstance(serialized); 1411 List<Integer> int32Keys = new ArrayList<>(); 1412 List<Integer> uint32Keys = new ArrayList<>(); 1413 List<Long> int64Keys = new ArrayList<>(); 1414 List<String> stringKeys = new ArrayList<>(); 1415 int tag; 1416 while (true) { 1417 tag = input.readTag(); 1418 if (tag == 0) { 1419 break; 1420 } 1421 int length = input.readRawVarint32(); 1422 int oldLimit = input.pushLimit(length); 1423 switch (WireFormat.getTagFieldNumber(tag)) { 1424 case TestMap.STRING_TO_INT32_FIELD_FIELD_NUMBER: 1425 stringKeys.add(readMapStringKey(input)); 1426 break; 1427 case TestMap.INT32_TO_INT32_FIELD_FIELD_NUMBER: 1428 int32Keys.add(readMapIntegerKey(input)); 1429 break; 1430 case TestMap.UINT32_TO_INT32_FIELD_FIELD_NUMBER: 1431 uint32Keys.add(readMapIntegerKey(input)); 1432 break; 1433 case TestMap.INT64_TO_INT32_FIELD_FIELD_NUMBER: 1434 int64Keys.add(readMapLongKey(input)); 1435 break; 1436 default: 1437 assertWithMessage("Unexpected fields.").fail(); 1438 } 1439 input.popLimit(oldLimit); 1440 } 1441 assertThat(int32Keys).containsExactly(-2, 0, 1, 4, 5).inOrder(); 1442 assertThat(uint32Keys).containsExactly(-2, 0, 1, 4, 5).inOrder(); 1443 assertThat(int64Keys).containsExactly(-2L, 0L, 1L, 4L, 5L).inOrder(); 1444 assertThat(stringKeys).containsExactly("", "bar", "baz", "foo", "hello", "world").inOrder(); 1445 } 1446 1447 @Test testInitFromPartialDynamicMessage()1448 public void testInitFromPartialDynamicMessage() { 1449 FieldDescriptor fieldDescriptor = 1450 TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER); 1451 Descriptor mapEntryType = fieldDescriptor.getMessageType(); 1452 FieldDescriptor keyField = mapEntryType.findFieldByNumber(1); 1453 FieldDescriptor valueField = mapEntryType.findFieldByNumber(2); 1454 DynamicMessage dynamicMessage = 1455 DynamicMessage.newBuilder(TestMap.getDescriptor()) 1456 .addRepeatedField( 1457 fieldDescriptor, 1458 DynamicMessage.newBuilder(mapEntryType) 1459 .setField(keyField, 10) 1460 .setField(valueField, TestMap.MessageValue.newBuilder().setValue(10).build()) 1461 .build()) 1462 .build(); 1463 TestMap message = TestMap.newBuilder().mergeFrom(dynamicMessage).build(); 1464 assertThat(message.getInt32ToMessageFieldMap()) 1465 .containsEntry(10, TestMap.MessageValue.newBuilder().setValue(10).build()); 1466 } 1467 1468 @Test testInitFromFullyDynamicMessage()1469 public void testInitFromFullyDynamicMessage() { 1470 FieldDescriptor fieldDescriptor = 1471 TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER); 1472 Descriptor mapEntryType = fieldDescriptor.getMessageType(); 1473 FieldDescriptor keyField = mapEntryType.findFieldByNumber(1); 1474 FieldDescriptor valueField = mapEntryType.findFieldByNumber(2); 1475 DynamicMessage dynamicMessage = 1476 DynamicMessage.newBuilder(TestMap.getDescriptor()) 1477 .addRepeatedField( 1478 fieldDescriptor, 1479 DynamicMessage.newBuilder(mapEntryType) 1480 .setField(keyField, 10) 1481 .setField( 1482 valueField, 1483 DynamicMessage.newBuilder(TestMap.MessageValue.getDescriptor()) 1484 .setField( 1485 TestMap.MessageValue.getDescriptor().findFieldByName("value"), 10) 1486 .build()) 1487 .build()) 1488 .build(); 1489 TestMap message = TestMap.newBuilder().mergeFrom(dynamicMessage).build(); 1490 assertThat(message.getInt32ToMessageFieldMap()) 1491 .containsEntry(10, TestMap.MessageValue.newBuilder().setValue(10).build()); 1492 } 1493 readMapIntegerKey(CodedInputStream input)1494 private int readMapIntegerKey(CodedInputStream input) throws IOException { 1495 int tag = input.readTag(); 1496 assertThat(tag).isEqualTo(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT)); 1497 int ret = input.readInt32(); 1498 // skip the value field. 1499 input.skipField(input.readTag()); 1500 assertThat(input.isAtEnd()).isTrue(); 1501 return ret; 1502 } 1503 readMapLongKey(CodedInputStream input)1504 private long readMapLongKey(CodedInputStream input) throws IOException { 1505 int tag = input.readTag(); 1506 assertThat(tag).isEqualTo(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT)); 1507 long ret = input.readInt64(); 1508 // skip the value field. 1509 input.skipField(input.readTag()); 1510 assertThat(input.isAtEnd()).isTrue(); 1511 return ret; 1512 } 1513 readMapStringKey(CodedInputStream input)1514 private String readMapStringKey(CodedInputStream input) throws IOException { 1515 int tag = input.readTag(); 1516 assertThat(tag).isEqualTo(WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED)); 1517 String ret = input.readString(); 1518 // skip the value field. 1519 input.skipField(input.readTag()); 1520 assertThat(input.isAtEnd()).isTrue(); 1521 return ret; 1522 } 1523 newMap(K key1, V value1)1524 private static <K, V> Map<K, V> newMap(K key1, V value1) { 1525 Map<K, V> map = new HashMap<>(); 1526 map.put(key1, value1); 1527 return map; 1528 } 1529 newMap(K key1, V value1, K key2, V value2)1530 private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) { 1531 Map<K, V> map = new HashMap<>(); 1532 map.put(key1, value1); 1533 map.put(key2, value2); 1534 return map; 1535 } 1536 newMap(K key1, V value1, K key2, V value2, K key3, V value3)1537 private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2, K key3, V value3) { 1538 Map<K, V> map = new HashMap<>(); 1539 map.put(key1, value1); 1540 map.put(key2, value2); 1541 map.put(key3, value3); 1542 return map; 1543 } 1544 1545 @Test testMap_withNulls()1546 public void testMap_withNulls() { 1547 TestMap.Builder builder = TestMap.newBuilder(); 1548 1549 try { 1550 builder.putStringToInt32Field(null, 3); 1551 assertWithMessage("expected exception").fail(); 1552 } catch (NullPointerException expected) { 1553 } 1554 1555 try { 1556 builder.putAllStringToInt32Field(newMap(null, 3, "hi", 4)); 1557 assertWithMessage("expected exception").fail(); 1558 } catch (NullPointerException expected) { 1559 } 1560 1561 try { 1562 builder.putInt32ToMessageField(3, null); 1563 assertWithMessage("expected exception").fail(); 1564 } catch (NullPointerException expected) { 1565 } 1566 1567 try { 1568 builder.putAllInt32ToMessageField(MapTest.<Integer, MessageValue>newMap(4, null, 5, null)); 1569 assertWithMessage("expected exception").fail(); 1570 } catch (NullPointerException expected) { 1571 } 1572 1573 try { 1574 builder.putAllInt32ToMessageField(null); 1575 assertWithMessage("expected exception").fail(); 1576 } catch (NullPointerException expected) { 1577 } 1578 1579 assertThat(builder.build().toByteArray()).isEqualTo(new byte[0]); 1580 } 1581 1582 @Test 1583 // https://github.com/protocolbuffers/protobuf/issues/9785 testContainer()1584 public void testContainer() { 1585 FieldDescriptor field = MapContainer.getDescriptor().findFieldByName("my_map"); 1586 Descriptor entryDescriptor = field.getMessageType(); 1587 FieldDescriptor valueDescriptor = entryDescriptor.findFieldByName("value"); 1588 Message.Builder builder = MapContainer.newBuilder().newBuilderForField(field); 1589 try { 1590 builder.setField(valueDescriptor, null); 1591 fail("Allowed null field value"); 1592 } catch (NullPointerException expected) { 1593 assertThat(expected).hasMessageThat().isNotNull(); 1594 } 1595 } 1596 1597 @Test getAllFields_mapEntryListMutability()1598 public void getAllFields_mapEntryListMutability() { 1599 TestMap testMap = 1600 TestMap.newBuilder() 1601 .putInt32ToInt32Field(1, 11) 1602 .putInt32ToInt32Field(2, 22) 1603 .putInt32ToMessageField(1, TestMap.MessageValue.newBuilder().setValue(111).build()) 1604 .build(); 1605 FieldDescriptor int2IntMapField = 1606 TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_INT32_FIELD_FIELD_NUMBER); 1607 FieldDescriptor int2MessageMapField = 1608 TestMap.getDescriptor().findFieldByNumber(TestMap.INT32_TO_MESSAGE_FIELD_FIELD_NUMBER); 1609 Map<FieldDescriptor, Object> allFields = testMap.getAllFields(); 1610 List<?> mapEntries = (List<?>) allFields.get(int2IntMapField); 1611 assertThat(mapEntries).hasSize(2); 1612 assertThrows(UnsupportedOperationException.class, mapEntries::clear); 1613 mapEntries = (List<?>) allFields.get(int2MessageMapField); 1614 assertThat(mapEntries).hasSize(1); 1615 assertThrows(UnsupportedOperationException.class, mapEntries::clear); 1616 1617 TestMap.Builder builder = testMap.toBuilder(); 1618 allFields = builder.getAllFields(); 1619 mapEntries = (List<?>) allFields.get(int2IntMapField); 1620 assertThat(mapEntries).hasSize(2); 1621 assertThrows(UnsupportedOperationException.class, mapEntries::clear); 1622 builder.clearField(int2IntMapField); 1623 assertThat(mapEntries).hasSize(2); 1624 mapEntries = (List<?>) allFields.get(int2MessageMapField); 1625 assertThat(mapEntries).hasSize(1); 1626 assertThrows(UnsupportedOperationException.class, mapEntries::clear); 1627 builder.clearField(int2MessageMapField); 1628 assertThat(mapEntries).hasSize(1); 1629 } 1630 } 1631