1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import static org.junit.Assert.assertArrayEquals; 34 35 import map_lite_test.MapTestProto.BizarroTestMap; 36 import map_lite_test.MapTestProto.TestMap; 37 import map_lite_test.MapTestProto.TestMap.MessageValue; 38 import map_lite_test.MapTestProto.TestMapOrBuilder; 39 import java.io.ByteArrayOutputStream; 40 import java.io.IOException; 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.HashMap; 44 import java.util.Map; 45 import junit.framework.TestCase; 46 47 /** Unit tests for map fields. */ 48 public final class MapLiteTest extends TestCase { 49 setMapValues(TestMap.Builder builder)50 private void setMapValues(TestMap.Builder builder) { 51 builder 52 .putInt32ToInt32Field(1, 11) 53 .putInt32ToInt32Field(2, 22) 54 .putInt32ToInt32Field(3, 33) 55 .putInt32ToStringField(1, "11") 56 .putInt32ToStringField(2, "22") 57 .putInt32ToStringField(3, "33") 58 .putInt32ToBytesField(1, TestUtil.toBytes("11")) 59 .putInt32ToBytesField(2, TestUtil.toBytes("22")) 60 .putInt32ToBytesField(3, TestUtil.toBytes("33")) 61 .putInt32ToEnumField(1, TestMap.EnumValue.FOO) 62 .putInt32ToEnumField(2, TestMap.EnumValue.BAR) 63 .putInt32ToEnumField(3, TestMap.EnumValue.BAZ) 64 .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build()) 65 .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build()) 66 .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build()) 67 .putStringToInt32Field("1", 11) 68 .putStringToInt32Field("2", 22) 69 .putStringToInt32Field("3", 33); 70 } 71 testSetMapValues()72 public void testSetMapValues() { 73 TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder(); 74 setMapValues(usingMutableMapBuilder); 75 TestMap usingMutableMap = usingMutableMapBuilder.build(); 76 assertMapValuesSet(usingMutableMap); 77 78 TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder(); 79 setMapValues(usingAccessorsBuilder); 80 TestMap usingAccessors = usingAccessorsBuilder.build(); 81 assertMapValuesSet(usingAccessors); 82 assertEquals(usingAccessors, usingMutableMap); 83 } 84 copyMapValues(TestMap source, TestMap.Builder destination)85 private void copyMapValues(TestMap source, TestMap.Builder destination) { 86 destination 87 .putAllInt32ToInt32Field(source.getInt32ToInt32Field()) 88 .putAllInt32ToStringField(source.getInt32ToStringField()) 89 .putAllInt32ToBytesField(source.getInt32ToBytesField()) 90 .putAllInt32ToEnumField(source.getInt32ToEnumField()) 91 .putAllInt32ToMessageField(source.getInt32ToMessageField()) 92 .putAllStringToInt32Field(source.getStringToInt32Field()); 93 } 94 assertMapValuesSet(TestMap message)95 private void assertMapValuesSet(TestMap message) { 96 assertEquals(3, message.getInt32ToInt32Field().size()); 97 assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); 98 assertEquals(22, message.getInt32ToInt32Field().get(2).intValue()); 99 assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); 100 101 assertEquals(3, message.getInt32ToStringField().size()); 102 assertEquals("11", message.getInt32ToStringField().get(1)); 103 assertEquals("22", message.getInt32ToStringField().get(2)); 104 assertEquals("33", message.getInt32ToStringField().get(3)); 105 106 assertEquals(3, message.getInt32ToBytesField().size()); 107 assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1)); 108 assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2)); 109 assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); 110 111 assertEquals(3, message.getInt32ToEnumField().size()); 112 assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1)); 113 assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2)); 114 assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); 115 116 assertEquals(3, message.getInt32ToMessageField().size()); 117 assertEquals(11, message.getInt32ToMessageField().get(1).getValue()); 118 assertEquals(22, message.getInt32ToMessageField().get(2).getValue()); 119 assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); 120 121 assertEquals(3, message.getStringToInt32Field().size()); 122 assertEquals(11, message.getStringToInt32Field().get("1").intValue()); 123 assertEquals(22, message.getStringToInt32Field().get("2").intValue()); 124 assertEquals(33, message.getStringToInt32Field().get("3").intValue()); 125 } 126 updateMapValues(TestMap.Builder builder)127 private void updateMapValues(TestMap.Builder builder) { 128 builder 129 .putInt32ToInt32Field(1, 111) 130 .removeInt32ToInt32Field(2) 131 .putInt32ToInt32Field(4, 44) 132 .putInt32ToStringField(1, "111") 133 .removeInt32ToStringField(2) 134 .putInt32ToStringField(4, "44") 135 .putInt32ToBytesField(1, TestUtil.toBytes("111")) 136 .removeInt32ToBytesField(2) 137 .putInt32ToBytesField(4, TestUtil.toBytes("44")) 138 .putInt32ToEnumField(1, TestMap.EnumValue.BAR) 139 .removeInt32ToEnumField(2) 140 .putInt32ToEnumField(4, TestMap.EnumValue.QUX) 141 .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build()) 142 .removeInt32ToMessageField(2) 143 .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build()) 144 .putStringToInt32Field("1", 111) 145 .removeStringToInt32Field("2") 146 .putStringToInt32Field("4", 44); 147 } 148 testUpdateMapValues()149 public void testUpdateMapValues() { 150 TestMap.Builder mapBuilder = TestMap.newBuilder(); 151 setMapValues(mapBuilder); 152 TestMap map = mapBuilder.build(); 153 assertMapValuesSet(map); 154 155 mapBuilder = map.toBuilder(); 156 updateMapValues(mapBuilder); 157 map = mapBuilder.build(); 158 assertMapValuesUpdated(map); 159 } 160 assertMapValuesUpdated(TestMap message)161 private void assertMapValuesUpdated(TestMap message) { 162 assertEquals(3, message.getInt32ToInt32Field().size()); 163 assertEquals(111, message.getInt32ToInt32Field().get(1).intValue()); 164 assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); 165 assertEquals(44, message.getInt32ToInt32Field().get(4).intValue()); 166 167 assertEquals(3, message.getInt32ToStringField().size()); 168 assertEquals("111", message.getInt32ToStringField().get(1)); 169 assertEquals("33", message.getInt32ToStringField().get(3)); 170 assertEquals("44", message.getInt32ToStringField().get(4)); 171 172 assertEquals(3, message.getInt32ToBytesField().size()); 173 assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1)); 174 assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); 175 assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4)); 176 177 assertEquals(3, message.getInt32ToEnumField().size()); 178 assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); 179 assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); 180 assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4)); 181 182 assertEquals(3, message.getInt32ToMessageField().size()); 183 assertEquals(111, message.getInt32ToMessageField().get(1).getValue()); 184 assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); 185 assertEquals(44, message.getInt32ToMessageField().get(4).getValue()); 186 187 assertEquals(3, message.getStringToInt32Field().size()); 188 assertEquals(111, message.getStringToInt32Field().get("1").intValue()); 189 assertEquals(33, message.getStringToInt32Field().get("3").intValue()); 190 assertEquals(44, message.getStringToInt32Field().get("4").intValue()); 191 } 192 assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder)193 private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) { 194 assertEquals(0, testMapOrBuilder.getInt32ToInt32Field().size()); 195 assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount()); 196 assertEquals(0, testMapOrBuilder.getInt32ToStringField().size()); 197 assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount()); 198 assertEquals(0, testMapOrBuilder.getInt32ToBytesField().size()); 199 assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount()); 200 assertEquals(0, testMapOrBuilder.getInt32ToEnumField().size()); 201 assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount()); 202 assertEquals(0, testMapOrBuilder.getInt32ToMessageField().size()); 203 assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount()); 204 assertEquals(0, testMapOrBuilder.getStringToInt32Field().size()); 205 assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount()); 206 } 207 testSanityCopyOnWrite()208 public void testSanityCopyOnWrite() throws InvalidProtocolBufferException { 209 // Since builders are implemented as a thin wrapper around a message 210 // instance, we attempt to verify that we can't cause the builder to modify 211 // a produced message. 212 213 TestMap.Builder builder = TestMap.newBuilder(); 214 TestMap message = builder.build(); 215 builder.putInt32ToInt32Field(1, 2); 216 assertTrue(message.getInt32ToInt32Field().isEmpty()); 217 assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); 218 message = builder.build(); 219 builder.putInt32ToInt32Field(2, 3); 220 assertEquals(newMap(1, 2), message.getInt32ToInt32Field()); 221 assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field()); 222 } 223 testGetMapIsImmutable()224 public void testGetMapIsImmutable() { 225 TestMap.Builder builder = TestMap.newBuilder(); 226 assertMapsAreImmutable(builder); 227 assertMapsAreImmutable(builder.build()); 228 229 setMapValues(builder); 230 assertMapsAreImmutable(builder); 231 assertMapsAreImmutable(builder.build()); 232 } 233 assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder)234 private void assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder) { 235 assertImmutable(testMapOrBuilder.getInt32ToInt32Field(), 1, 2); 236 assertImmutable(testMapOrBuilder.getInt32ToStringField(), 1, "2"); 237 assertImmutable(testMapOrBuilder.getInt32ToBytesField(), 1, TestUtil.toBytes("2")); 238 assertImmutable(testMapOrBuilder.getInt32ToEnumField(), 1, TestMap.EnumValue.FOO); 239 assertImmutable( 240 testMapOrBuilder.getInt32ToMessageField(), 1, MessageValue.getDefaultInstance()); 241 assertImmutable(testMapOrBuilder.getStringToInt32Field(), "1", 2); 242 } 243 assertImmutable(Map<K, V> map, K key, V value)244 private <K, V> void assertImmutable(Map<K, V> map, K key, V value) { 245 try { 246 map.put(key, value); 247 fail(); 248 } catch (UnsupportedOperationException e) { 249 // expected 250 } 251 if (!map.isEmpty()) { 252 try { 253 map.entrySet().remove(map.entrySet().iterator().next()); 254 fail(); 255 } catch (UnsupportedOperationException e) { 256 // expected 257 } 258 } 259 } 260 testMapFieldClear()261 public void testMapFieldClear() { 262 TestMap.Builder builder = TestMap.newBuilder().putInt32ToInt32Field(1, 2); 263 builder.clearInt32ToInt32Field(); 264 assertEquals(0, builder.getInt32ToInt32FieldCount()); 265 } 266 testMutableMapLifecycle()267 public void testMutableMapLifecycle() { 268 TestMap.Builder builder = TestMap.newBuilder().putInt32ToInt32Field(1, 2); 269 assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); 270 assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); 271 builder.putInt32ToInt32Field(2, 3); 272 assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field()); 273 274 builder.putInt32ToEnumField(1, TestMap.EnumValue.BAR); 275 assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField()); 276 assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField()); 277 builder.putInt32ToEnumField(2, TestMap.EnumValue.FOO); 278 assertEquals( 279 newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO), builder.getInt32ToEnumField()); 280 281 builder.putInt32ToStringField(1, "1"); 282 assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField()); 283 assertEquals(newMap(1, "1"), builder.getInt32ToStringField()); 284 builder.putInt32ToStringField(2, "2"); 285 assertEquals(newMap(1, "1", 2, "2"), builder.getInt32ToStringField()); 286 287 builder.putInt32ToMessageField(1, TestMap.MessageValue.getDefaultInstance()); 288 assertEquals( 289 newMap(1, TestMap.MessageValue.getDefaultInstance()), 290 builder.build().getInt32ToMessageField()); 291 assertEquals( 292 newMap(1, TestMap.MessageValue.getDefaultInstance()), builder.getInt32ToMessageField()); 293 builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance()); 294 assertEquals( 295 newMap( 296 1, 297 TestMap.MessageValue.getDefaultInstance(), 298 2, 299 TestMap.MessageValue.getDefaultInstance()), 300 builder.getInt32ToMessageField()); 301 } 302 testGettersAndSetters()303 public void testGettersAndSetters() throws Exception { 304 TestMap.Builder builder = TestMap.newBuilder(); 305 TestMap message = builder.build(); 306 assertMapValuesCleared(message); 307 308 builder = message.toBuilder(); 309 setMapValues(builder); 310 message = builder.build(); 311 assertMapValuesSet(message); 312 313 builder = message.toBuilder(); 314 updateMapValues(builder); 315 message = builder.build(); 316 assertMapValuesUpdated(message); 317 318 builder = message.toBuilder(); 319 builder.clear(); 320 assertMapValuesCleared(builder); 321 message = builder.build(); 322 assertMapValuesCleared(message); 323 } 324 testPutAll()325 public void testPutAll() throws Exception { 326 TestMap.Builder sourceBuilder = TestMap.newBuilder(); 327 setMapValues(sourceBuilder); 328 TestMap source = sourceBuilder.build(); 329 assertMapValuesSet(source); 330 331 TestMap.Builder destination = TestMap.newBuilder(); 332 copyMapValues(source, destination); 333 assertMapValuesSet(destination.build()); 334 } 335 testPutAllForUnknownEnumValues()336 public void testPutAllForUnknownEnumValues() throws Exception { 337 TestMap.Builder sourceBuilder = 338 TestMap.newBuilder() 339 .putInt32ToEnumFieldValue(0, 0) 340 .putInt32ToEnumFieldValue(1, 1) 341 .putAllInt32ToEnumFieldValue(newMap(2, 1000)); // unknown value. 342 TestMap source = sourceBuilder.build(); 343 344 TestMap.Builder destinationBuilder = TestMap.newBuilder(); 345 destinationBuilder.putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValue()); 346 TestMap destination = destinationBuilder.build(); 347 348 assertEquals(0, destination.getInt32ToEnumFieldValue().get(0).intValue()); 349 assertEquals(1, destination.getInt32ToEnumFieldValue().get(1).intValue()); 350 assertEquals(1000, destination.getInt32ToEnumFieldValue().get(2).intValue()); 351 assertEquals(3, destination.getInt32ToEnumFieldCount()); 352 } 353 testPutForUnknownEnumValues()354 public void testPutForUnknownEnumValues() throws Exception { 355 TestMap.Builder builder = 356 TestMap.newBuilder() 357 .putInt32ToEnumFieldValue(0, 0) 358 .putInt32ToEnumFieldValue(1, 1) 359 .putInt32ToEnumFieldValue(2, 1000); // unknown value. 360 TestMap message = builder.build(); 361 362 assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0)); 363 assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1)); 364 assertEquals(1000, message.getInt32ToEnumFieldValueOrThrow(2)); 365 assertEquals(3, message.getInt32ToEnumFieldCount()); 366 } 367 testPutChecksNullKeysAndValues()368 public void testPutChecksNullKeysAndValues() throws Exception { 369 TestMap.Builder builder = TestMap.newBuilder(); 370 371 try { 372 builder.putInt32ToStringField(1, null); 373 fail(); 374 } catch (NullPointerException e) { 375 // expected. 376 } 377 378 try { 379 builder.putInt32ToBytesField(1, null); 380 fail(); 381 } catch (NullPointerException e) { 382 // expected. 383 } 384 385 try { 386 builder.putInt32ToEnumField(1, null); 387 fail(); 388 } catch (NullPointerException e) { 389 // expected. 390 } 391 392 try { 393 builder.putInt32ToMessageField(1, null); 394 fail(); 395 } catch (NullPointerException e) { 396 // expected. 397 } 398 399 try { 400 builder.putStringToInt32Field(null, 1); 401 fail(); 402 } catch (NullPointerException e) { 403 // expected. 404 } 405 } 406 testSerializeAndParse()407 public void testSerializeAndParse() throws Exception { 408 TestMap.Builder builder = TestMap.newBuilder(); 409 setMapValues(builder); 410 TestMap message = builder.build(); 411 assertEquals(message.getSerializedSize(), message.toByteString().size()); 412 message = TestMap.parser().parseFrom(message.toByteString()); 413 assertMapValuesSet(message); 414 415 builder = message.toBuilder(); 416 updateMapValues(builder); 417 message = builder.build(); 418 assertEquals(message.getSerializedSize(), message.toByteString().size()); 419 message = TestMap.parser().parseFrom(message.toByteString()); 420 assertMapValuesUpdated(message); 421 422 builder = message.toBuilder(); 423 builder.clear(); 424 message = builder.build(); 425 assertEquals(message.getSerializedSize(), message.toByteString().size()); 426 message = TestMap.parser().parseFrom(message.toByteString()); 427 assertMapValuesCleared(message); 428 } 429 tryParseTestMap(BizarroTestMap bizarroMap)430 private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException { 431 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 432 CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream); 433 bizarroMap.writeTo(output); 434 output.flush(); 435 return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray())); 436 } 437 testParseError()438 public void testParseError() throws Exception { 439 ByteString bytes = TestUtil.toBytes("SOME BYTES"); 440 String stringKey = "a string key"; 441 442 TestMap map = 443 tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToInt32Field(5, bytes).build()); 444 assertEquals(0, map.getInt32ToInt32FieldOrDefault(5, -1)); 445 446 map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToStringField(stringKey, 5).build()); 447 assertEquals("", map.getInt32ToStringFieldOrDefault(0, null)); 448 449 map = tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToBytesField(stringKey, 5).build()); 450 assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY); 451 452 map = 453 tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToEnumField(stringKey, bytes).build()); 454 assertEquals(TestMap.EnumValue.FOO, map.getInt32ToEnumFieldOrDefault(0, null)); 455 456 try { 457 tryParseTestMap(BizarroTestMap.newBuilder().putInt32ToMessageField(stringKey, bytes).build()); 458 fail(); 459 } catch (InvalidProtocolBufferException expected) { 460 assertTrue(expected.getUnfinishedMessage() instanceof TestMap); 461 map = (TestMap) expected.getUnfinishedMessage(); 462 assertTrue(map.getInt32ToMessageField().isEmpty()); 463 } 464 465 map = 466 tryParseTestMap( 467 BizarroTestMap.newBuilder().putStringToInt32Field(stringKey, bytes).build()); 468 assertEquals(0, map.getStringToInt32FieldOrDefault(stringKey, -1)); 469 } 470 testMergeFrom()471 public void testMergeFrom() throws Exception { 472 TestMap.Builder builder = TestMap.newBuilder(); 473 setMapValues(builder); 474 TestMap message = builder.build(); 475 476 TestMap.Builder other = TestMap.newBuilder(); 477 other.mergeFrom(message); 478 assertMapValuesSet(other.build()); 479 } 480 testEqualsAndHashCode()481 public void testEqualsAndHashCode() throws Exception { 482 // Test that generated equals() and hashCode() will disregard the order 483 // of map entries when comparing/hashing map fields. 484 485 // We can't control the order of elements in a HashMap. The best we can do 486 // here is to add elements in different order. 487 TestMap.Builder b1 = 488 TestMap.newBuilder() 489 .putInt32ToInt32Field(1, 2) 490 .putInt32ToInt32Field(3, 4) 491 .putInt32ToInt32Field(5, 6); 492 TestMap m1 = b1.build(); 493 494 TestMap.Builder b2 = 495 TestMap.newBuilder() 496 .putInt32ToInt32Field(5, 6) 497 .putInt32ToInt32Field(1, 2) 498 .putInt32ToInt32Field(3, 4); 499 TestMap m2 = b2.build(); 500 501 assertEquals(m1, m2); 502 assertEquals(m1.hashCode(), m2.hashCode()); 503 504 // Make sure we did compare map fields. 505 b2.putInt32ToInt32Field(1, 0); 506 m2 = b2.build(); 507 assertFalse(m1.equals(m2)); 508 // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed 509 // to be different. 510 511 // Regression test for b/18549190: if a map is a subset of the other map, 512 // equals() should return false. 513 b2.removeInt32ToInt32Field(1); 514 m2 = b2.build(); 515 assertFalse(m1.equals(m2)); 516 assertFalse(m2.equals(m1)); 517 } 518 testUnknownEnumValues()519 public void testUnknownEnumValues() throws Exception { 520 TestMap.Builder builder = 521 TestMap.newBuilder() 522 .putInt32ToEnumFieldValue(0, 0) 523 .putInt32ToEnumFieldValue(1, 1) 524 .putInt32ToEnumFieldValue(2, 1000); // unknown value. 525 TestMap message = builder.build(); 526 527 assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(0)); 528 assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); 529 assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumField().get(2)); 530 531 builder.putAllInt32ToEnumFieldValue(newMap(2, 1000)); // unknown value. 532 message = builder.build(); 533 assertEquals(TestMap.EnumValue.UNRECOGNIZED, message.getInt32ToEnumField().get(2)); 534 535 // Unknown enum values should be preserved after: 536 // 1. Serialization and parsing. 537 // 2. toBuild(). 538 // 3. mergeFrom(). 539 message = TestMap.parseFrom(message.toByteString()); 540 assertEquals(1000, message.getInt32ToEnumFieldValue().get(2).intValue()); 541 builder = message.toBuilder(); 542 assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue()); 543 builder = TestMap.newBuilder().mergeFrom(message); 544 assertEquals(1000, builder.getInt32ToEnumFieldValue().get(2).intValue()); 545 546 // hashCode()/equals() should take unknown enum values into account. 547 builder.putAllInt32ToEnumFieldValue(newMap(2, 1001)); 548 TestMap message2 = builder.build(); 549 assertFalse(message.hashCode() == message2.hashCode()); 550 assertFalse(message.equals(message2)); 551 // Unknown values will be converted to UNRECOGNIZED so the resulted enum map 552 // should be the same. 553 assertEquals(message2.getInt32ToEnumField(), message.getInt32ToEnumField()); 554 } 555 testIterationOrder()556 public void testIterationOrder() throws Exception { 557 TestMap.Builder builder = TestMap.newBuilder(); 558 setMapValues(builder); 559 TestMap message = builder.build(); 560 561 assertEquals( 562 Arrays.asList("1", "2", "3"), new ArrayList<>(message.getStringToInt32Field().keySet())); 563 } 564 testGetMap()565 public void testGetMap() { 566 TestMap.Builder builder = TestMap.newBuilder(); 567 setMapValues(builder); 568 TestMap message = builder.build(); 569 assertEquals(message.getStringToInt32Field(), message.getStringToInt32FieldMap()); 570 assertEquals(message.getInt32ToBytesField(), message.getInt32ToBytesFieldMap()); 571 assertEquals(message.getInt32ToEnumField(), message.getInt32ToEnumFieldMap()); 572 assertEquals(message.getInt32ToEnumFieldValue(), message.getInt32ToEnumFieldValueMap()); 573 assertEquals(message.getInt32ToMessageField(), message.getInt32ToMessageFieldMap()); 574 } 575 testContains()576 public void testContains() { 577 TestMap.Builder builder = TestMap.newBuilder(); 578 setMapValues(builder); 579 assertMapContainsSetValues(builder); 580 assertMapContainsSetValues(builder.build()); 581 } 582 assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder)583 private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) { 584 assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1)); 585 assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2)); 586 assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3)); 587 assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1)); 588 589 assertTrue(testMapOrBuilder.containsInt32ToStringField(1)); 590 assertTrue(testMapOrBuilder.containsInt32ToStringField(2)); 591 assertTrue(testMapOrBuilder.containsInt32ToStringField(3)); 592 assertFalse(testMapOrBuilder.containsInt32ToStringField(-1)); 593 594 assertTrue(testMapOrBuilder.containsInt32ToBytesField(1)); 595 assertTrue(testMapOrBuilder.containsInt32ToBytesField(2)); 596 assertTrue(testMapOrBuilder.containsInt32ToBytesField(3)); 597 assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1)); 598 599 assertTrue(testMapOrBuilder.containsInt32ToEnumField(1)); 600 assertTrue(testMapOrBuilder.containsInt32ToEnumField(2)); 601 assertTrue(testMapOrBuilder.containsInt32ToEnumField(3)); 602 assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1)); 603 604 assertTrue(testMapOrBuilder.containsInt32ToMessageField(1)); 605 assertTrue(testMapOrBuilder.containsInt32ToMessageField(2)); 606 assertTrue(testMapOrBuilder.containsInt32ToMessageField(3)); 607 assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1)); 608 609 assertTrue(testMapOrBuilder.containsStringToInt32Field("1")); 610 assertTrue(testMapOrBuilder.containsStringToInt32Field("2")); 611 assertTrue(testMapOrBuilder.containsStringToInt32Field("3")); 612 assertFalse(testMapOrBuilder.containsStringToInt32Field("-1")); 613 } 614 testCount()615 public void testCount() { 616 TestMap.Builder builder = TestMap.newBuilder(); 617 assertMapCounts(0, builder); 618 619 setMapValues(builder); 620 assertMapCounts(3, builder); 621 622 TestMap message = builder.build(); 623 assertMapCounts(3, message); 624 625 builder = message.toBuilder().putInt32ToInt32Field(4, 44); 626 assertEquals(4, builder.getInt32ToInt32FieldCount()); 627 assertEquals(4, builder.build().getInt32ToInt32FieldCount()); 628 629 // already present - should be unchanged 630 builder.putInt32ToInt32Field(4, 44); 631 assertEquals(4, builder.getInt32ToInt32FieldCount()); 632 } 633 assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder)634 private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) { 635 assertEquals(expectedCount, testMapOrBuilder.getInt32ToInt32FieldCount()); 636 assertEquals(expectedCount, testMapOrBuilder.getInt32ToStringFieldCount()); 637 assertEquals(expectedCount, testMapOrBuilder.getInt32ToBytesFieldCount()); 638 assertEquals(expectedCount, testMapOrBuilder.getInt32ToEnumFieldCount()); 639 assertEquals(expectedCount, testMapOrBuilder.getInt32ToMessageFieldCount()); 640 assertEquals(expectedCount, testMapOrBuilder.getStringToInt32FieldCount()); 641 } 642 testGetOrDefault()643 public void testGetOrDefault() { 644 TestMap.Builder builder = TestMap.newBuilder(); 645 assertMapCounts(0, builder); 646 setMapValues(builder); 647 doTestGetOrDefault(builder); 648 doTestGetOrDefault(builder.build()); 649 } 650 doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder)651 public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) { 652 assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11)); 653 assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11)); 654 655 assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11")); 656 assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null)); 657 658 assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null)); 659 assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null)); 660 661 assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null)); 662 assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null)); 663 664 assertEquals( 665 TestMap.EnumValue.BAR.getNumber(), 666 testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(2, -1)); 667 assertEquals(-1, testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(-1000, -1)); 668 669 assertEquals( 670 MessageValue.newBuilder().setValue(11).build(), 671 testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null)); 672 assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null)); 673 674 assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11)); 675 assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11)); 676 677 try { 678 testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11); 679 fail(); 680 } catch (NullPointerException e) { 681 // expected 682 } 683 } 684 testGetOrThrow()685 public void testGetOrThrow() { 686 TestMap.Builder builder = TestMap.newBuilder(); 687 assertMapCounts(0, builder); 688 setMapValues(builder); 689 doTestGetOrDefault(builder); 690 doTestGetOrDefault(builder.build()); 691 } 692 doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder)693 public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) { 694 assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1)); 695 try { 696 testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1); 697 fail(); 698 } catch (IllegalArgumentException e) { 699 // expected 700 } 701 702 assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1)); 703 704 try { 705 testMapOrBuilder.getInt32ToStringFieldOrThrow(-1); 706 fail(); 707 } catch (IllegalArgumentException e) { 708 // expected 709 } 710 711 assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1)); 712 713 try { 714 testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1); 715 fail(); 716 } catch (IllegalArgumentException e) { 717 // expected 718 } 719 720 assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1)); 721 try { 722 testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1); 723 fail(); 724 } catch (IllegalArgumentException e) { 725 // expected 726 } 727 728 assertEquals( 729 TestMap.EnumValue.BAR.getNumber(), testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(2)); 730 try { 731 testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(-1); 732 fail(); 733 } catch (IllegalArgumentException e) { 734 // expected 735 } 736 737 assertEquals( 738 MessageValue.newBuilder().setValue(11).build(), 739 testMapOrBuilder.getInt32ToMessageFieldOrThrow(1)); 740 try { 741 testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1); 742 fail(); 743 } catch (IllegalArgumentException e) { 744 // expected 745 } 746 747 assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1")); 748 try { 749 testMapOrBuilder.getStringToInt32FieldOrThrow("-1"); 750 fail(); 751 } catch (IllegalArgumentException e) { 752 // expected 753 } 754 755 try { 756 testMapOrBuilder.getStringToInt32FieldOrThrow(null); 757 fail(); 758 } catch (NullPointerException e) { 759 // expected 760 } 761 } 762 testPut()763 public void testPut() { 764 TestMap.Builder builder = TestMap.newBuilder(); 765 builder.putInt32ToInt32Field(1, 11); 766 assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1)); 767 768 builder.putInt32ToStringField(1, "a"); 769 assertEquals("a", builder.getInt32ToStringFieldOrThrow(1)); 770 try { 771 builder.putInt32ToStringField(1, null); 772 fail(); 773 } catch (NullPointerException e) { 774 // expected 775 } 776 777 builder.putInt32ToBytesField(1, TestUtil.toBytes("11")); 778 assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1)); 779 try { 780 builder.putInt32ToBytesField(1, null); 781 fail(); 782 } catch (NullPointerException e) { 783 // expected 784 } 785 786 builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO); 787 assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1)); 788 try { 789 builder.putInt32ToEnumField(1, null); 790 fail(); 791 } catch (NullPointerException e) { 792 // expected 793 } 794 795 builder.putStringToInt32Field("a", 1); 796 assertEquals(1, builder.getStringToInt32FieldOrThrow("a")); 797 try { 798 builder.putStringToInt32Field(null, -1); 799 } catch (NullPointerException e) { 800 // expected 801 } 802 } 803 testRemove()804 public void testRemove() { 805 TestMap.Builder builder = TestMap.newBuilder(); 806 setMapValues(builder); 807 assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1)); 808 for (int times = 0; times < 2; times++) { 809 builder.removeInt32ToInt32Field(1); 810 assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1)); 811 } 812 813 assertEquals("11", builder.getInt32ToStringFieldOrThrow(1)); 814 for (int times = 0; times < 2; times++) { 815 builder.removeInt32ToStringField(1); 816 assertNull(builder.getInt32ToStringFieldOrDefault(1, null)); 817 } 818 819 assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1)); 820 for (int times = 0; times < 2; times++) { 821 builder.removeInt32ToBytesField(1); 822 assertNull(builder.getInt32ToBytesFieldOrDefault(1, null)); 823 } 824 825 assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1)); 826 for (int times = 0; times < 2; times++) { 827 builder.removeInt32ToEnumField(1); 828 assertNull(builder.getInt32ToEnumFieldOrDefault(1, null)); 829 } 830 831 assertEquals(11, builder.getStringToInt32FieldOrThrow("1")); 832 for (int times = 0; times < 2; times++) { 833 builder.removeStringToInt32Field("1"); 834 assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1)); 835 } 836 837 try { 838 builder.removeStringToInt32Field(null); 839 fail(); 840 } catch (NullPointerException e) { 841 // expected 842 } 843 } 844 newMap(K key1, V value1)845 private static <K, V> Map<K, V> newMap(K key1, V value1) { 846 Map<K, V> map = new HashMap<>(); 847 map.put(key1, value1); 848 return map; 849 } 850 newMap(K key1, V value1, K key2, V value2)851 private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) { 852 Map<K, V> map = new HashMap<>(); 853 map.put(key1, value1); 854 map.put(key2, value2); 855 return map; 856 } 857 testMap_withNulls()858 public void testMap_withNulls() { 859 TestMap.Builder builder = TestMap.newBuilder(); 860 861 try { 862 builder.putStringToInt32Field(null, 3); 863 fail(); 864 } catch (NullPointerException expected) { 865 } 866 867 try { 868 builder.putAllStringToInt32Field(newMap(null, 3, "hi", 4)); 869 fail(); 870 } catch (NullPointerException expected) { 871 } 872 873 try { 874 builder.putInt32ToMessageField(3, null); 875 fail(); 876 } catch (NullPointerException expected) { 877 } 878 879 try { 880 builder.putAllInt32ToMessageField( 881 MapLiteTest.<Integer, MessageValue>newMap(4, null, 5, null)); 882 fail(); 883 } catch (NullPointerException expected) { 884 } 885 886 try { 887 builder.putAllInt32ToMessageField(null); 888 fail(); 889 } catch (NullPointerException expected) { 890 } 891 892 assertArrayEquals(new byte[0], builder.build().toByteArray()); 893 } 894 } 895