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.fail; 14 15 import com.google.protobuf.Descriptors.FieldDescriptor; 16 import map_test.MapForProto2TestProto.BizarroTestMap; 17 import map_test.MapForProto2TestProto.ReservedAsMapField; 18 import map_test.MapForProto2TestProto.ReservedAsMapFieldWithEnumValue; 19 import map_test.MapForProto2TestProto.TestMap; 20 import map_test.MapForProto2TestProto.TestMap.MessageValue; 21 import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields; 22 import map_test.MapForProto2TestProto.TestMapOrBuilder; 23 import map_test.MapForProto2TestProto.TestRecursiveMap; 24 import map_test.MapForProto2TestProto.TestUnknownEnumValue; 25 import map_test.Message1; 26 import map_test.RedactAllTypes; 27 import java.io.ByteArrayOutputStream; 28 import java.io.IOException; 29 import java.util.ArrayList; 30 import java.util.HashMap; 31 import java.util.LinkedHashMap; 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 in proto2 protos. */ 40 @RunWith(JUnit4.class) 41 public class MapForProto2Test { 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(TestMapOrBuilder message)119 private void assertMapValuesSet(TestMapOrBuilder 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()) 334 .isEqualTo(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.getMutableInt32ToStringField().put(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 newMap(K key1, V value1)411 private static <K, V> Map<K, V> newMap(K key1, V value1) { 412 Map<K, V> map = new HashMap<K, V>(); 413 map.put(key1, value1); 414 return map; 415 } 416 newMap(K key1, V value1, K key2, V value2)417 private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) { 418 Map<K, V> map = new HashMap<K, V>(); 419 map.put(key1, value1); 420 map.put(key2, value2); 421 return map; 422 } 423 424 @Test testGettersAndSetters()425 public void testGettersAndSetters() throws Exception { 426 TestMap.Builder builder = TestMap.newBuilder(); 427 TestMap message = builder.build(); 428 assertMapValuesCleared(message); 429 430 builder = message.toBuilder(); 431 setMapValuesUsingAccessors(builder); 432 message = builder.build(); 433 assertMapValuesSet(message); 434 435 builder = message.toBuilder(); 436 updateMapValuesUsingAccessors(builder); 437 message = builder.build(); 438 assertMapValuesUpdated(message); 439 440 builder = message.toBuilder(); 441 builder.clear(); 442 assertMapValuesCleared(builder); 443 message = builder.build(); 444 assertMapValuesCleared(message); 445 } 446 447 @Test testPutAll()448 public void testPutAll() throws Exception { 449 TestMap.Builder sourceBuilder = TestMap.newBuilder(); 450 setMapValuesUsingAccessors(sourceBuilder); 451 TestMap source = sourceBuilder.build(); 452 assertMapValuesSet(source); 453 454 TestMap.Builder destination = TestMap.newBuilder(); 455 copyMapValues(source, destination); 456 assertMapValuesSet(destination.build()); 457 458 assertThat(destination.getInt32ToEnumFieldCount()).isEqualTo(3); 459 } 460 461 @Test testPutChecksNullValues()462 public void testPutChecksNullValues() throws Exception { 463 TestMap.Builder builder = TestMap.newBuilder(); 464 465 try { 466 builder.putInt32ToBytesField(1, null); 467 assertWithMessage("expected exception").fail(); 468 } catch (NullPointerException e) { 469 // expected. 470 } 471 472 try { 473 builder.putInt32ToEnumField(1, null); 474 assertWithMessage("expected exception").fail(); 475 } catch (NullPointerException e) { 476 // expected. 477 } 478 479 try { 480 builder.putInt32ToMessageField(1, null); 481 assertWithMessage("expected exception").fail(); 482 } catch (NullPointerException e) { 483 // expected. 484 } 485 486 try { 487 builder.putStringToInt32Field(null, 1); 488 assertWithMessage("expected exception").fail(); 489 } catch (NullPointerException e) { 490 // expected. 491 } 492 } 493 494 @Test testPutChecksNullKey()495 public void testPutChecksNullKey() throws Exception { 496 TestMap.Builder builder = TestMap.newBuilder(); 497 498 try { 499 builder.putStringToInt32Field(null, 1); 500 assertWithMessage("expected exception").fail(); 501 } catch (NullPointerException expected) { 502 } 503 } 504 505 @Test testSerializeAndParse()506 public void testSerializeAndParse() throws Exception { 507 TestMap.Builder builder = TestMap.newBuilder(); 508 setMapValuesUsingAccessors(builder); 509 TestMap message = builder.build(); 510 assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize()); 511 message = TestMap.parseFrom(message.toByteString()); 512 assertMapValuesSet(message); 513 514 builder = message.toBuilder(); 515 updateMapValuesUsingAccessors(builder); 516 message = builder.build(); 517 assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize()); 518 message = TestMap.parseFrom(message.toByteString()); 519 assertMapValuesUpdated(message); 520 521 builder = message.toBuilder(); 522 builder.clear(); 523 message = builder.build(); 524 assertThat(message.toByteString().size()).isEqualTo(message.getSerializedSize()); 525 message = TestMap.parseFrom(message.toByteString()); 526 assertMapValuesCleared(message); 527 } 528 tryParseTestMap(BizarroTestMap bizarroMap)529 private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException { 530 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 531 CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream); 532 bizarroMap.writeTo(output); 533 output.flush(); 534 return TestMap.parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray())); 535 } 536 537 @Test testParseError()538 public void testParseError() throws Exception { 539 ByteString bytes = TestUtil.toBytes("SOME BYTES"); 540 String stringKey = "a string key"; 541 542 TestMap map = 543 tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build()); 544 assertThat(map.getInt32ToInt32FieldOrDefault(5, -1)).isEqualTo(0); 545 546 map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build()); 547 assertThat(map.getInt32ToStringFieldOrDefault(0, null)).isEmpty(); 548 549 map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build()); 550 assertThat(ByteString.EMPTY).isEqualTo(map.getInt32ToBytesFieldOrDefault(0, null)); 551 552 map = 553 tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build()); 554 assertThat(map.getInt32ToEnumFieldOrDefault(0, null)).isEqualTo(TestMap.EnumValue.FOO); 555 556 try { 557 tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build()); 558 assertWithMessage("expected exception").fail(); 559 } catch (InvalidProtocolBufferException expected) { 560 assertThat(expected.getUnfinishedMessage()).isInstanceOf(TestMap.class); 561 map = (TestMap) expected.getUnfinishedMessage(); 562 assertThat(map.getInt32ToMessageFieldMap()).isEmpty(); 563 } 564 565 map = 566 tryParseTestMap( 567 BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build()); 568 assertThat(map.getStringToInt32FieldOrDefault(stringKey, -1)).isEqualTo(0); 569 } 570 571 @Test testMergeFrom()572 public void testMergeFrom() throws Exception { 573 TestMap.Builder builder = TestMap.newBuilder(); 574 setMapValuesUsingAccessors(builder); 575 TestMap message = builder.build(); 576 577 TestMap.Builder other = TestMap.newBuilder(); 578 other.mergeFrom(message); 579 assertMapValuesSet(other.build()); 580 } 581 582 @Test testEqualsAndHashCode()583 public void testEqualsAndHashCode() throws Exception { 584 // Test that generated equals() and hashCode() will disregard the order 585 // of map entries when comparing/hashing map fields. 586 587 // We can't control the order of elements in a HashMap. The best we can do 588 // here is to add elements in different order. 589 TestMap.Builder b1 = TestMap.newBuilder(); 590 b1.putInt32ToInt32Field(1, 2); 591 b1.putInt32ToInt32Field(3, 4); 592 b1.putInt32ToInt32Field(5, 6); 593 TestMap m1 = b1.build(); 594 595 TestMap.Builder b2 = TestMap.newBuilder(); 596 b2.putInt32ToInt32Field(5, 6); 597 b2.putInt32ToInt32Field(1, 2); 598 b2.putInt32ToInt32Field(3, 4); 599 TestMap m2 = b2.build(); 600 601 assertThat(m2).isEqualTo(m1); 602 assertThat(m2.hashCode()).isEqualTo(m1.hashCode()); 603 604 // Make sure we did compare map fields. 605 b2.putInt32ToInt32Field(1, 0); 606 m2 = b2.build(); 607 assertThat(m1.equals(m2)).isFalse(); 608 // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed 609 // to be different. 610 } 611 612 // The following methods are used to test reflection API. 613 f(String name)614 private static FieldDescriptor f(String name) { 615 return TestMap.getDescriptor().findFieldByName(name); 616 } 617 getFieldValue(Message mapEntry, String name)618 private static Object getFieldValue(Message mapEntry, String name) { 619 FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); 620 return mapEntry.getField(field); 621 } 622 setFieldValue( Message.Builder mapEntry, String name, Object value)623 private static Message.Builder setFieldValue( 624 Message.Builder mapEntry, String name, Object value) { 625 FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name); 626 mapEntry.setField(field, value); 627 return mapEntry; 628 } 629 assertHasMapValues(Message message, String name, Map<?, ?> values)630 private static void assertHasMapValues(Message message, String name, Map<?, ?> values) { 631 FieldDescriptor field = f(name); 632 for (Object entry : (List<?>) message.getField(field)) { 633 Message mapEntry = (Message) entry; 634 Object key = getFieldValue(mapEntry, "key"); 635 Object value = getFieldValue(mapEntry, "value"); 636 assertThat(values.containsKey(key)).isTrue(); 637 assertThat(values.get(key)).isEqualTo(value); 638 } 639 assertThat(message.getRepeatedFieldCount(field)).isEqualTo(values.size()); 640 for (int i = 0; i < message.getRepeatedFieldCount(field); i++) { 641 Message mapEntry = (Message) message.getRepeatedField(field, i); 642 Object key = getFieldValue(mapEntry, "key"); 643 Object value = getFieldValue(mapEntry, "value"); 644 assertThat(values.containsKey(key)).isTrue(); 645 assertThat(values.get(key)).isEqualTo(value); 646 } 647 } 648 newMapEntry(Message.Builder builder, String name, K key, V value)649 private static <K, V> Message newMapEntry(Message.Builder builder, String name, K key, V value) { 650 FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); 651 Message.Builder entryBuilder = builder.newBuilderForField(field); 652 FieldDescriptor keyField = entryBuilder.getDescriptorForType().findFieldByName("key"); 653 FieldDescriptor valueField = entryBuilder.getDescriptorForType().findFieldByName("value"); 654 entryBuilder.setField(keyField, key); 655 entryBuilder.setField(valueField, value); 656 return entryBuilder.build(); 657 } 658 setMapValues(Message.Builder builder, String name, Map<?, ?> values)659 private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) { 660 List<Message> entryList = new ArrayList<>(); 661 for (Map.Entry<?, ?> entry : values.entrySet()) { 662 entryList.add(newMapEntry(builder, name, entry.getKey(), entry.getValue())); 663 } 664 FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name); 665 builder.setField(field, entryList); 666 } 667 mapForValues(K key1, V value1, K key2, V value2)668 private static <K, V> Map<K, V> mapForValues(K key1, V value1, K key2, V value2) { 669 Map<K, V> map = new HashMap<>(); 670 map.put(key1, value1); 671 map.put(key2, value2); 672 return map; 673 } 674 675 @Test testReflectionApi()676 public void testReflectionApi() throws Exception { 677 // In reflection API, map fields are just repeated message fields. 678 TestMap.Builder builder = 679 TestMap.newBuilder() 680 .putInt32ToInt32Field(1, 2) 681 .putInt32ToInt32Field(3, 4) 682 .putInt32ToMessageField(11, MessageValue.newBuilder().setValue(22).build()) 683 .putInt32ToMessageField(33, MessageValue.newBuilder().setValue(44).build()); 684 TestMap message = builder.build(); 685 686 // Test getField(), getRepeatedFieldCount(), getRepeatedField(). 687 assertHasMapValues(message, "int32_to_int32_field", mapForValues(1, 2, 3, 4)); 688 assertHasMapValues( 689 message, 690 "int32_to_message_field", 691 mapForValues( 692 11, MessageValue.newBuilder().setValue(22).build(), 693 33, MessageValue.newBuilder().setValue(44).build())); 694 695 // Test clearField() 696 builder.clearField(f("int32_to_int32_field")); 697 builder.clearField(f("int32_to_message_field")); 698 message = builder.build(); 699 assertThat(message.getInt32ToInt32FieldMap()).isEmpty(); 700 assertThat(message.getInt32ToMessageFieldMap()).isEmpty(); 701 702 // Test setField() 703 setMapValues(builder, "int32_to_int32_field", mapForValues(11, 22, 33, 44)); 704 setMapValues( 705 builder, 706 "int32_to_message_field", 707 mapForValues( 708 111, MessageValue.newBuilder().setValue(222).build(), 709 333, MessageValue.newBuilder().setValue(444).build())); 710 message = builder.build(); 711 assertThat(message.getInt32ToInt32FieldMap().get(11).intValue()).isEqualTo(22); 712 assertThat(message.getInt32ToInt32FieldMap().get(33).intValue()).isEqualTo(44); 713 assertThat(message.getInt32ToMessageFieldMap().get(111).getValue()).isEqualTo(222); 714 assertThat(message.getInt32ToMessageFieldMap().get(333).getValue()).isEqualTo(444); 715 716 // Test addRepeatedField 717 builder.addRepeatedField( 718 f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 66)); 719 builder.addRepeatedField( 720 f("int32_to_message_field"), 721 newMapEntry( 722 builder, 723 "int32_to_message_field", 724 555, 725 MessageValue.newBuilder().setValue(666).build())); 726 message = builder.build(); 727 assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(66); 728 assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(666); 729 730 // Test addRepeatedField (overriding existing values) 731 builder.addRepeatedField( 732 f("int32_to_int32_field"), newMapEntry(builder, "int32_to_int32_field", 55, 55)); 733 builder.addRepeatedField( 734 f("int32_to_message_field"), 735 newMapEntry( 736 builder, 737 "int32_to_message_field", 738 555, 739 MessageValue.newBuilder().setValue(555).build())); 740 message = builder.build(); 741 assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55); 742 assertThat(message.getInt32ToMessageFieldMap().get(555).getValue()).isEqualTo(555); 743 744 // Test setRepeatedField 745 for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) { 746 Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i); 747 int oldKey = ((Integer) getFieldValue(mapEntry, "key")).intValue(); 748 int oldValue = ((Integer) getFieldValue(mapEntry, "value")).intValue(); 749 // Swap key with value for each entry. 750 Message.Builder mapEntryBuilder = mapEntry.toBuilder(); 751 setFieldValue(mapEntryBuilder, "key", oldValue); 752 setFieldValue(mapEntryBuilder, "value", oldKey); 753 builder.setRepeatedField(f("int32_to_int32_field"), i, mapEntryBuilder.build()); 754 } 755 message = builder.build(); 756 assertThat(message.getInt32ToInt32FieldMap().get(22).intValue()).isEqualTo(11); 757 assertThat(message.getInt32ToInt32FieldMap().get(44).intValue()).isEqualTo(33); 758 assertThat(message.getInt32ToInt32FieldMap().get(55).intValue()).isEqualTo(55); 759 } 760 761 // See additional coverage in TextFormatTest.java. 762 @Test testTextFormat()763 public void testTextFormat() throws Exception { 764 TestMap.Builder builder = TestMap.newBuilder(); 765 setMapValuesUsingAccessors(builder); 766 TestMap message = builder.build(); 767 768 String textData = TextFormat.printer().printToString(message); 769 770 builder = TestMap.newBuilder(); 771 TextFormat.merge(textData, builder); 772 message = builder.build(); 773 774 assertMapValuesSet(message); 775 } 776 777 @Test testDynamicMessage()778 public void testDynamicMessage() throws Exception { 779 TestMap.Builder builder = TestMap.newBuilder(); 780 setMapValuesUsingAccessors(builder); 781 TestMap message = builder.build(); 782 783 Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); 784 Message dynamicMessage = 785 dynamicDefaultInstance 786 .newBuilderForType() 787 .mergeFrom(message.toByteString(), ExtensionRegistry.getEmptyRegistry()) 788 .build(); 789 790 assertThat(dynamicMessage).isEqualTo(message); 791 assertThat(dynamicMessage.hashCode()).isEqualTo(message.hashCode()); 792 } 793 794 // Check that DynamicMessage handles map field serialization the same way as generated code 795 // regarding unset key and value field in a map entry. 796 @Test testDynamicMessageUnsetKeyAndValue()797 public void testDynamicMessageUnsetKeyAndValue() throws Exception { 798 FieldDescriptor field = f("int32_to_int32_field"); 799 800 Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); 801 Message.Builder builder = dynamicDefaultInstance.newBuilderForType(); 802 // Add an entry without key and value. 803 builder.addRepeatedField(field, builder.newBuilderForField(field).build()); 804 Message message = builder.build(); 805 ByteString bytes = message.toByteString(); 806 // Parse it back to the same generated type. 807 Message generatedMessage = TestMap.parseFrom(bytes, ExtensionRegistry.getEmptyRegistry()); 808 // Assert the serialized bytes are equivalent. 809 assertThat(bytes).isEqualTo(generatedMessage.toByteString()); 810 } 811 812 @Test testReflectionEqualsAndHashCode()813 public void testReflectionEqualsAndHashCode() throws Exception { 814 // Test that generated equals() and hashCode() will disregard the order 815 // of map entries when comparing/hashing map fields. 816 817 // We use DynamicMessage to test reflection based equals()/hashCode(). 818 Message dynamicDefaultInstance = DynamicMessage.getDefaultInstance(TestMap.getDescriptor()); 819 FieldDescriptor field = f("int32_to_int32_field"); 820 821 Message.Builder b1 = dynamicDefaultInstance.newBuilderForType(); 822 b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2)); 823 b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4)); 824 b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6)); 825 Message m1 = b1.build(); 826 827 Message.Builder b2 = dynamicDefaultInstance.newBuilderForType(); 828 b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6)); 829 b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2)); 830 b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4)); 831 Message m2 = b2.build(); 832 833 assertThat(m2).isEqualTo(m1); 834 assertThat(m2.hashCode()).isEqualTo(m1.hashCode()); 835 836 // Make sure we did compare map fields. 837 b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0)); 838 m2 = b2.build(); 839 assertThat(m1.equals(m2)).isFalse(); 840 // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed 841 // to be different. 842 } 843 844 @Test testUnknownEnumValues()845 public void testUnknownEnumValues() throws Exception { 846 TestUnknownEnumValue builder = 847 TestUnknownEnumValue.newBuilder() 848 .putInt32ToInt32Field(1, 1) 849 .putInt32ToInt32Field(2, 54321) 850 .build(); 851 ByteString data = builder.toByteString(); 852 853 TestMap message = TestMap.parseFrom(data, ExtensionRegistry.getEmptyRegistry()); 854 // Entries with unknown enum values will be stored into UnknownFieldSet so 855 // there is only one entry in the map. 856 assertThat(message.getInt32ToEnumFieldMap()).hasSize(1); 857 assertThat(message.getInt32ToEnumFieldMap()).containsEntry(1, TestMap.EnumValue.BAR); 858 // UnknownFieldSet should not be empty. 859 assertThat(message.getUnknownFields().asMap()).isNotEmpty(); 860 // Serializing and parsing should preserve the unknown entry. 861 data = message.toByteString(); 862 TestUnknownEnumValue messageWithUnknownEnums = 863 TestUnknownEnumValue.parseFrom(data, ExtensionRegistry.getEmptyRegistry()); 864 assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap()).hasSize(2); 865 assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap().get(1).intValue()).isEqualTo(1); 866 assertThat(messageWithUnknownEnums.getInt32ToInt32FieldMap().get(2).intValue()) 867 .isEqualTo(54321); 868 } 869 870 @Test testRequiredMessage()871 public void testRequiredMessage() throws Exception { 872 TestMap.Builder builder = TestMap.newBuilder(); 873 builder.putRequiredMessageMap(0, MessageWithRequiredFields.newBuilder().buildPartial()); 874 TestMap message = builder.buildPartial(); 875 assertThat(message.isInitialized()).isFalse(); 876 877 builder.putRequiredMessageMap(0, MessageWithRequiredFields.newBuilder().setValue(1).build()); 878 message = builder.build(); 879 assertThat(message.isInitialized()).isTrue(); 880 } 881 882 @Test testRecursiveMap()883 public void testRecursiveMap() throws Exception { 884 TestRecursiveMap.Builder builder = TestRecursiveMap.newBuilder(); 885 builder.putRecursiveMapField(1, TestRecursiveMap.newBuilder().setValue(2).build()); 886 builder.putRecursiveMapField(3, TestRecursiveMap.newBuilder().setValue(4).build()); 887 ByteString data = builder.build().toByteString(); 888 889 TestRecursiveMap message = 890 TestRecursiveMap.parseFrom(data, ExtensionRegistry.getEmptyRegistry()); 891 assertThat(message.getRecursiveMapFieldMap().get(1).getValue()).isEqualTo(2); 892 assertThat(message.getRecursiveMapFieldMap().get(3).getValue()).isEqualTo(4); 893 } 894 895 @Test testIterationOrder()896 public void testIterationOrder() throws Exception { 897 TestMap.Builder builder = TestMap.newBuilder(); 898 setMapValuesUsingAccessors(builder); 899 TestMap message = builder.build(); 900 901 assertThat(new ArrayList<String>(message.getStringToInt32FieldMap().keySet())) 902 .containsExactly("1", "2", "3") 903 .inOrder(); 904 } 905 906 @Test testContains()907 public void testContains() { 908 TestMap.Builder builder = TestMap.newBuilder(); 909 setMapValuesUsingAccessors(builder); 910 assertMapContainsSetValues(builder); 911 assertMapContainsSetValues(builder.build()); 912 } 913 assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder)914 private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) { 915 assertThat(testMapOrBuilder.containsInt32ToInt32Field(1)).isTrue(); 916 assertThat(testMapOrBuilder.containsInt32ToInt32Field(2)).isTrue(); 917 assertThat(testMapOrBuilder.containsInt32ToInt32Field(3)).isTrue(); 918 assertThat(testMapOrBuilder.containsInt32ToInt32Field(-1)).isFalse(); 919 920 assertThat(testMapOrBuilder.containsInt32ToStringField(1)).isTrue(); 921 assertThat(testMapOrBuilder.containsInt32ToStringField(2)).isTrue(); 922 assertThat(testMapOrBuilder.containsInt32ToStringField(3)).isTrue(); 923 assertThat(testMapOrBuilder.containsInt32ToStringField(-1)).isFalse(); 924 925 assertThat(testMapOrBuilder.containsInt32ToBytesField(1)).isTrue(); 926 assertThat(testMapOrBuilder.containsInt32ToBytesField(2)).isTrue(); 927 assertThat(testMapOrBuilder.containsInt32ToBytesField(3)).isTrue(); 928 assertThat(testMapOrBuilder.containsInt32ToBytesField(-1)).isFalse(); 929 930 assertThat(testMapOrBuilder.containsInt32ToEnumField(1)).isTrue(); 931 assertThat(testMapOrBuilder.containsInt32ToEnumField(2)).isTrue(); 932 assertThat(testMapOrBuilder.containsInt32ToEnumField(3)).isTrue(); 933 assertThat(testMapOrBuilder.containsInt32ToEnumField(-1)).isFalse(); 934 935 assertThat(testMapOrBuilder.containsInt32ToMessageField(1)).isTrue(); 936 assertThat(testMapOrBuilder.containsInt32ToMessageField(2)).isTrue(); 937 assertThat(testMapOrBuilder.containsInt32ToMessageField(3)).isTrue(); 938 assertThat(testMapOrBuilder.containsInt32ToMessageField(-1)).isFalse(); 939 940 assertThat(testMapOrBuilder.containsStringToInt32Field("1")).isTrue(); 941 assertThat(testMapOrBuilder.containsStringToInt32Field("2")).isTrue(); 942 assertThat(testMapOrBuilder.containsStringToInt32Field("3")).isTrue(); 943 assertThat(testMapOrBuilder.containsStringToInt32Field("-1")).isFalse(); 944 } 945 946 @Test testCount()947 public void testCount() { 948 TestMap.Builder builder = TestMap.newBuilder(); 949 assertMapCounts(0, builder); 950 951 setMapValuesUsingAccessors(builder); 952 assertMapCounts(3, builder); 953 954 TestMap message = builder.build(); 955 assertMapCounts(3, message); 956 957 builder = message.toBuilder().putInt32ToInt32Field(4, 44); 958 assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4); 959 assertThat(builder.build().getInt32ToInt32FieldCount()).isEqualTo(4); 960 961 // already present - should be unchanged 962 builder.putInt32ToInt32Field(4, 44); 963 assertThat(builder.getInt32ToInt32FieldCount()).isEqualTo(4); 964 } 965 assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder)966 private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) { 967 assertThat(testMapOrBuilder.getInt32ToInt32FieldCount()).isEqualTo(expectedCount); 968 assertThat(testMapOrBuilder.getInt32ToStringFieldCount()).isEqualTo(expectedCount); 969 assertThat(testMapOrBuilder.getInt32ToBytesFieldCount()).isEqualTo(expectedCount); 970 assertThat(testMapOrBuilder.getInt32ToEnumFieldCount()).isEqualTo(expectedCount); 971 assertThat(testMapOrBuilder.getInt32ToMessageFieldCount()).isEqualTo(expectedCount); 972 assertThat(testMapOrBuilder.getStringToInt32FieldCount()).isEqualTo(expectedCount); 973 } 974 975 @Test testGetOrDefault()976 public void testGetOrDefault() { 977 TestMap.Builder builder = TestMap.newBuilder(); 978 assertMapCounts(0, builder); 979 setMapValuesUsingAccessors(builder); 980 doTestGetOrDefault(builder); 981 doTestGetOrDefault(builder.build()); 982 } 983 doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder)984 public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) { 985 assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11)).isEqualTo(11); 986 assertThat(testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11)).isEqualTo(-11); 987 988 assertThat(testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11")).isEqualTo("11"); 989 assertWithMessage("-11") 990 .that(testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null)) 991 .isNull(); 992 993 assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null)) 994 .isEqualTo(TestUtil.toBytes("11")); 995 assertThat(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null)).isNull(); 996 997 assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null)) 998 .isEqualTo(TestMap.EnumValue.FOO); 999 assertThat(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null)).isNull(); 1000 1001 assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null)) 1002 .isEqualTo(MessageValue.newBuilder().setValue(11).build()); 1003 assertThat(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null)).isNull(); 1004 1005 assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11)).isEqualTo(11); 1006 assertThat(testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11)).isEqualTo(-11); 1007 1008 try { 1009 testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11); 1010 assertWithMessage("expected exception").fail(); 1011 } catch (NullPointerException e) { 1012 // expected 1013 } 1014 } 1015 1016 @Test testGetOrThrow()1017 public void testGetOrThrow() { 1018 TestMap.Builder builder = TestMap.newBuilder(); 1019 assertMapCounts(0, builder); 1020 setMapValuesUsingAccessors(builder); 1021 doTestGetOrDefault(builder); 1022 doTestGetOrDefault(builder.build()); 1023 } 1024 doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder)1025 public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) { 1026 assertThat(testMapOrBuilder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11); 1027 try { 1028 testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1); 1029 assertWithMessage("expected exception").fail(); 1030 } catch (IllegalArgumentException e) { 1031 // expected 1032 } 1033 1034 assertThat(testMapOrBuilder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11"); 1035 1036 try { 1037 testMapOrBuilder.getInt32ToStringFieldOrThrow(-1); 1038 assertWithMessage("expected exception").fail(); 1039 } catch (IllegalArgumentException e) { 1040 // expected 1041 } 1042 1043 assertThat(testMapOrBuilder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11")); 1044 1045 try { 1046 testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1); 1047 assertWithMessage("expected exception").fail(); 1048 } catch (IllegalArgumentException e) { 1049 // expected 1050 } 1051 1052 assertThat(testMapOrBuilder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO); 1053 try { 1054 testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1); 1055 assertWithMessage("expected exception").fail(); 1056 } catch (IllegalArgumentException e) { 1057 // expected 1058 } 1059 1060 assertThat(testMapOrBuilder.getInt32ToMessageFieldOrThrow(1)) 1061 .isEqualTo(MessageValue.newBuilder().setValue(11).build()); 1062 try { 1063 testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1); 1064 assertWithMessage("expected exception").fail(); 1065 } catch (IllegalArgumentException e) { 1066 // expected 1067 } 1068 1069 assertThat(testMapOrBuilder.getStringToInt32FieldOrThrow("1")).isEqualTo(11); 1070 try { 1071 testMapOrBuilder.getStringToInt32FieldOrThrow("-1"); 1072 assertWithMessage("expected exception").fail(); 1073 } catch (IllegalArgumentException e) { 1074 // expected 1075 } 1076 1077 try { 1078 testMapOrBuilder.getStringToInt32FieldOrThrow(null); 1079 assertWithMessage("expected exception").fail(); 1080 } catch (NullPointerException e) { 1081 // expected 1082 } 1083 } 1084 1085 @Test testPut()1086 public void testPut() { 1087 TestMap.Builder builder = TestMap.newBuilder(); 1088 builder.putInt32ToInt32Field(1, 11); 1089 assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11); 1090 1091 builder.putInt32ToStringField(1, "a"); 1092 assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("a"); 1093 try { 1094 builder.putInt32ToStringField(1, null); 1095 assertWithMessage("expected exception").fail(); 1096 } catch (NullPointerException e) { 1097 // expected 1098 } 1099 1100 builder.putInt32ToBytesField(1, TestUtil.toBytes("11")); 1101 assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11")); 1102 try { 1103 builder.putInt32ToBytesField(1, null); 1104 assertWithMessage("expected exception").fail(); 1105 } catch (NullPointerException e) { 1106 // expected 1107 } 1108 1109 builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO); 1110 assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO); 1111 try { 1112 builder.putInt32ToEnumField(1, null); 1113 assertWithMessage("expected exception").fail(); 1114 } catch (NullPointerException e) { 1115 // expected 1116 } 1117 1118 builder.putStringToInt32Field("a", 1); 1119 assertThat(builder.getStringToInt32FieldOrThrow("a")).isEqualTo(1); 1120 try { 1121 builder.putStringToInt32Field(null, -1); 1122 } catch (NullPointerException e) { 1123 // expected 1124 } 1125 } 1126 1127 @Test testRemove()1128 public void testRemove() { 1129 TestMap.Builder builder = TestMap.newBuilder(); 1130 setMapValuesUsingAccessors(builder); 1131 assertThat(builder.getInt32ToInt32FieldOrThrow(1)).isEqualTo(11); 1132 for (int times = 0; times < 2; times++) { 1133 builder.removeInt32ToInt32Field(1); 1134 assertThat(builder.getInt32ToInt32FieldOrDefault(1, -1)).isEqualTo(-1); 1135 } 1136 1137 assertThat(builder.getInt32ToStringFieldOrThrow(1)).isEqualTo("11"); 1138 for (int times = 0; times < 2; times++) { 1139 builder.removeInt32ToStringField(1); 1140 assertThat(builder.getInt32ToStringFieldOrDefault(1, null)).isNull(); 1141 } 1142 1143 assertThat(builder.getInt32ToBytesFieldOrThrow(1)).isEqualTo(TestUtil.toBytes("11")); 1144 for (int times = 0; times < 2; times++) { 1145 builder.removeInt32ToBytesField(1); 1146 assertThat(builder.getInt32ToBytesFieldOrDefault(1, null)).isNull(); 1147 } 1148 1149 assertThat(builder.getInt32ToEnumFieldOrThrow(1)).isEqualTo(TestMap.EnumValue.FOO); 1150 for (int times = 0; times < 2; times++) { 1151 builder.removeInt32ToEnumField(1); 1152 assertThat(builder.getInt32ToEnumFieldOrDefault(1, null)).isNull(); 1153 } 1154 1155 assertThat(builder.getStringToInt32FieldOrThrow("1")).isEqualTo(11); 1156 for (int times = 0; times < 2; times++) { 1157 builder.removeStringToInt32Field("1"); 1158 assertThat(builder.getStringToInt32FieldOrDefault("1", -1)).isEqualTo(-1); 1159 } 1160 1161 try { 1162 builder.removeStringToInt32Field(null); 1163 assertWithMessage("expected exception").fail(); 1164 } catch (NullPointerException e) { 1165 // expected 1166 } 1167 } 1168 1169 // Regression test for b/20494788 1170 @Test testMapInitializationOrder()1171 public void testMapInitializationOrder() throws Exception { 1172 assertThat(RedactAllTypes.getDefaultInstance().getDescriptorForType().getName()) 1173 .isEqualTo("RedactAllTypes"); 1174 1175 Message1.Builder builder = Message1.newBuilder(); 1176 builder.putMapField("key", true); 1177 Message1 message = builder.build(); 1178 Message mapEntry = 1179 (Message) 1180 message.getRepeatedField( 1181 message.getDescriptorForType().findFieldByName("map_field"), 0); 1182 assertThat(mapEntry.getAllFields()).hasSize(2); 1183 } 1184 1185 @Test testReservedWordsFieldNames()1186 public void testReservedWordsFieldNames() { 1187 ReservedAsMapField unused1 = ReservedAsMapField.getDefaultInstance(); 1188 ReservedAsMapFieldWithEnumValue unused2 = ReservedAsMapFieldWithEnumValue.getDefaultInstance(); 1189 } 1190 1191 @Test testGetMap()1192 public void testGetMap() { 1193 TestMap.Builder builder = TestMap.newBuilder(); 1194 setMapValuesUsingAccessors(builder); 1195 assertMapValuesSet(builder); 1196 TestMap message = builder.build(); 1197 assertThat(message.getStringToInt32FieldMap()).isEqualTo(message.getStringToInt32FieldMap()); 1198 assertThat(message.getInt32ToBytesFieldMap()).isEqualTo(message.getInt32ToBytesFieldMap()); 1199 assertThat(message.getInt32ToEnumFieldMap()).isEqualTo(message.getInt32ToEnumFieldMap()); 1200 assertThat(message.getInt32ToMessageFieldMap()).isEqualTo(message.getInt32ToMessageFieldMap()); 1201 } 1202 1203 @Test testPutAllWithNullStringValue()1204 public void testPutAllWithNullStringValue() throws Exception { 1205 TestMap.Builder sourceBuilder = TestMap.newBuilder(); 1206 1207 // order preserving map used here to help test rollback 1208 Map<Integer, String> data = new TreeMap<>(); 1209 data.put(7, "foo"); 1210 data.put(8, "bar"); 1211 data.put(9, null); 1212 try { 1213 sourceBuilder.putAllInt32ToStringField(data); 1214 fail("allowed null string value"); 1215 } catch (NullPointerException expected) { 1216 // Verify rollback of previously added values. 1217 // They all go in or none do. 1218 assertThat(sourceBuilder.getInt32ToStringFieldMap()).isEmpty(); 1219 } 1220 } 1221 1222 @Test testPutAllWithNullStringKey()1223 public void testPutAllWithNullStringKey() throws Exception { 1224 TestMap.Builder sourceBuilder = TestMap.newBuilder(); 1225 1226 // order preserving map used here to help test rollback 1227 Map<Integer, String> data = new LinkedHashMap<>(); 1228 data.put(7, "foo"); 1229 data.put(null, "bar"); 1230 data.put(9, "baz"); 1231 try { 1232 sourceBuilder.putAllInt32ToStringField(data); 1233 fail("allowed null string key"); 1234 } catch (NullPointerException expected) { 1235 // Verify rollback of previously added values. 1236 // They all go in or none do. 1237 assertThat(sourceBuilder.getInt32ToStringFieldMap()).isEmpty(); 1238 } 1239 } 1240 1241 @Test testPutNullStringValue()1242 public void testPutNullStringValue() throws Exception { 1243 TestMap.Builder sourceBuilder = TestMap.newBuilder(); 1244 1245 try { 1246 sourceBuilder.putInt32ToStringField(8, null); 1247 fail("allowed null string value"); 1248 } catch (NullPointerException expected) { 1249 assertNotNull(expected.getMessage()); 1250 } 1251 } 1252 } 1253