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 map_lite_test.MapForProto2TestProto.TestMap; 34 import map_lite_test.MapForProto2TestProto.TestMap.MessageValue; 35 import map_lite_test.MapForProto2TestProto.TestUnknownEnumValue; 36 37 import junit.framework.TestCase; 38 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.HashMap; 42 import java.util.Map; 43 44 /** 45 * Unit tests for map fields. 46 */ 47 public class MapForProto2LiteTest extends TestCase { setMapValues(TestMap.Builder builder)48 private void setMapValues(TestMap.Builder builder) { 49 builder.getMutableInt32ToInt32Field().put(1, 11); 50 builder.getMutableInt32ToInt32Field().put(2, 22); 51 builder.getMutableInt32ToInt32Field().put(3, 33); 52 53 builder.getMutableInt32ToStringField().put(1, "11"); 54 builder.getMutableInt32ToStringField().put(2, "22"); 55 builder.getMutableInt32ToStringField().put(3, "33"); 56 57 builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11")); 58 builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22")); 59 builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33")); 60 61 builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO); 62 builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR); 63 builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ); 64 65 builder.getMutableInt32ToMessageField().put( 66 1, MessageValue.newBuilder().setValue(11).build()); 67 builder.getMutableInt32ToMessageField().put( 68 2, MessageValue.newBuilder().setValue(22).build()); 69 builder.getMutableInt32ToMessageField().put( 70 3, MessageValue.newBuilder().setValue(33).build()); 71 72 builder.getMutableStringToInt32Field().put("1", 11); 73 builder.getMutableStringToInt32Field().put("2", 22); 74 builder.getMutableStringToInt32Field().put("3", 33); 75 } 76 copyMapValues(TestMap source, TestMap.Builder destination)77 private void copyMapValues(TestMap source, TestMap.Builder destination) { 78 destination 79 .putAllInt32ToInt32Field(source.getInt32ToInt32Field()) 80 .putAllInt32ToStringField(source.getInt32ToStringField()) 81 .putAllInt32ToBytesField(source.getInt32ToBytesField()) 82 .putAllInt32ToEnumField(source.getInt32ToEnumField()) 83 .putAllInt32ToMessageField(source.getInt32ToMessageField()) 84 .putAllStringToInt32Field(source.getStringToInt32Field()); 85 } 86 assertMapValuesSet(TestMap message)87 private void assertMapValuesSet(TestMap message) { 88 assertEquals(3, message.getInt32ToInt32Field().size()); 89 assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); 90 assertEquals(22, message.getInt32ToInt32Field().get(2).intValue()); 91 assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); 92 93 assertEquals(3, message.getInt32ToStringField().size()); 94 assertEquals("11", message.getInt32ToStringField().get(1)); 95 assertEquals("22", message.getInt32ToStringField().get(2)); 96 assertEquals("33", message.getInt32ToStringField().get(3)); 97 98 assertEquals(3, message.getInt32ToBytesField().size()); 99 assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1)); 100 assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2)); 101 assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); 102 103 assertEquals(3, message.getInt32ToEnumField().size()); 104 assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1)); 105 assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2)); 106 assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); 107 108 assertEquals(3, message.getInt32ToMessageField().size()); 109 assertEquals(11, message.getInt32ToMessageField().get(1).getValue()); 110 assertEquals(22, message.getInt32ToMessageField().get(2).getValue()); 111 assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); 112 113 assertEquals(3, message.getStringToInt32Field().size()); 114 assertEquals(11, message.getStringToInt32Field().get("1").intValue()); 115 assertEquals(22, message.getStringToInt32Field().get("2").intValue()); 116 assertEquals(33, message.getStringToInt32Field().get("3").intValue()); 117 } 118 updateMapValues(TestMap.Builder builder)119 private void updateMapValues(TestMap.Builder builder) { 120 builder.getMutableInt32ToInt32Field().put(1, 111); 121 builder.getMutableInt32ToInt32Field().remove(2); 122 builder.getMutableInt32ToInt32Field().put(4, 44); 123 124 builder.getMutableInt32ToStringField().put(1, "111"); 125 builder.getMutableInt32ToStringField().remove(2); 126 builder.getMutableInt32ToStringField().put(4, "44"); 127 128 builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111")); 129 builder.getMutableInt32ToBytesField().remove(2); 130 builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44")); 131 132 builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR); 133 builder.getMutableInt32ToEnumField().remove(2); 134 builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX); 135 136 builder.getMutableInt32ToMessageField().put( 137 1, MessageValue.newBuilder().setValue(111).build()); 138 builder.getMutableInt32ToMessageField().remove(2); 139 builder.getMutableInt32ToMessageField().put( 140 4, MessageValue.newBuilder().setValue(44).build()); 141 142 builder.getMutableStringToInt32Field().put("1", 111); 143 builder.getMutableStringToInt32Field().remove("2"); 144 builder.getMutableStringToInt32Field().put("4", 44); 145 } 146 assertMapValuesUpdated(TestMap message)147 private void assertMapValuesUpdated(TestMap message) { 148 assertEquals(3, message.getInt32ToInt32Field().size()); 149 assertEquals(111, message.getInt32ToInt32Field().get(1).intValue()); 150 assertEquals(33, message.getInt32ToInt32Field().get(3).intValue()); 151 assertEquals(44, message.getInt32ToInt32Field().get(4).intValue()); 152 153 assertEquals(3, message.getInt32ToStringField().size()); 154 assertEquals("111", message.getInt32ToStringField().get(1)); 155 assertEquals("33", message.getInt32ToStringField().get(3)); 156 assertEquals("44", message.getInt32ToStringField().get(4)); 157 158 assertEquals(3, message.getInt32ToBytesField().size()); 159 assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1)); 160 assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3)); 161 assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4)); 162 163 assertEquals(3, message.getInt32ToEnumField().size()); 164 assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); 165 assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3)); 166 assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4)); 167 168 assertEquals(3, message.getInt32ToMessageField().size()); 169 assertEquals(111, message.getInt32ToMessageField().get(1).getValue()); 170 assertEquals(33, message.getInt32ToMessageField().get(3).getValue()); 171 assertEquals(44, message.getInt32ToMessageField().get(4).getValue()); 172 173 assertEquals(3, message.getStringToInt32Field().size()); 174 assertEquals(111, message.getStringToInt32Field().get("1").intValue()); 175 assertEquals(33, message.getStringToInt32Field().get("3").intValue()); 176 assertEquals(44, message.getStringToInt32Field().get("4").intValue()); 177 } 178 assertMapValuesCleared(TestMap message)179 private void assertMapValuesCleared(TestMap message) { 180 assertEquals(0, message.getInt32ToInt32Field().size()); 181 assertEquals(0, message.getInt32ToStringField().size()); 182 assertEquals(0, message.getInt32ToBytesField().size()); 183 assertEquals(0, message.getInt32ToEnumField().size()); 184 assertEquals(0, message.getInt32ToMessageField().size()); 185 assertEquals(0, message.getStringToInt32Field().size()); 186 } 187 testSanityCopyOnWrite()188 public void testSanityCopyOnWrite() throws InvalidProtocolBufferException { 189 // Since builders are implemented as a thin wrapper around a message 190 // instance, we attempt to verify that we can't cause the builder to modify 191 // a produced message. 192 193 TestMap.Builder builder = TestMap.newBuilder(); 194 TestMap message = builder.build(); 195 Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field(); 196 intMap.put(1, 2); 197 assertTrue(message.getInt32ToInt32Field().isEmpty()); 198 message = builder.build(); 199 try { 200 intMap.put(2, 3); 201 fail(); 202 } catch (UnsupportedOperationException e) { 203 // expected 204 } 205 assertEquals(newMap(1, 2), message.getInt32ToInt32Field()); 206 assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); 207 builder.getMutableInt32ToInt32Field().put(2, 3); 208 assertEquals(newMap(1, 2), message.getInt32ToInt32Field()); 209 assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field()); 210 } 211 testMutableMapLifecycle()212 public void testMutableMapLifecycle() { 213 TestMap.Builder builder = TestMap.newBuilder(); 214 Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field(); 215 intMap.put(1, 2); 216 assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); 217 try { 218 intMap.put(2, 3); 219 fail(); 220 } catch (UnsupportedOperationException e) { 221 // expected 222 } 223 assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); 224 builder.getMutableInt32ToInt32Field().put(2, 3); 225 assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field()); 226 227 Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField(); 228 enumMap.put(1, TestMap.EnumValue.BAR); 229 assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField()); 230 try { 231 enumMap.put(2, TestMap.EnumValue.FOO); 232 fail(); 233 } catch (UnsupportedOperationException e) { 234 // expected 235 } 236 assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField()); 237 builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO); 238 assertEquals( 239 newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO), 240 builder.getInt32ToEnumField()); 241 242 Map<Integer, String> stringMap = builder.getMutableInt32ToStringField(); 243 stringMap.put(1, "1"); 244 assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField()); 245 try { 246 stringMap.put(2, "2"); 247 fail(); 248 } catch (UnsupportedOperationException e) { 249 // expected 250 } 251 assertEquals(newMap(1, "1"), builder.getInt32ToStringField()); 252 builder.getMutableInt32ToStringField().put(2, "2"); 253 assertEquals( 254 newMap(1, "1", 2, "2"), 255 builder.getInt32ToStringField()); 256 257 Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField(); 258 messageMap.put(1, TestMap.MessageValue.getDefaultInstance()); 259 assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()), 260 builder.build().getInt32ToMessageField()); 261 try { 262 messageMap.put(2, TestMap.MessageValue.getDefaultInstance()); 263 fail(); 264 } catch (UnsupportedOperationException e) { 265 // expected 266 } 267 assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()), 268 builder.getInt32ToMessageField()); 269 builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance()); 270 assertEquals( 271 newMap(1, TestMap.MessageValue.getDefaultInstance(), 272 2, TestMap.MessageValue.getDefaultInstance()), 273 builder.getInt32ToMessageField()); 274 } 275 testMutableMapLifecycle_collections()276 public void testMutableMapLifecycle_collections() { 277 TestMap.Builder builder = TestMap.newBuilder(); 278 Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field(); 279 intMap.put(1, 2); 280 assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); 281 try { 282 intMap.remove(2); 283 fail(); 284 } catch (UnsupportedOperationException e) { 285 // expected 286 } 287 try { 288 intMap.entrySet().remove(new Object()); 289 fail(); 290 } catch (UnsupportedOperationException e) { 291 // expected 292 } 293 try { 294 intMap.entrySet().iterator().remove(); 295 fail(); 296 } catch (UnsupportedOperationException e) { 297 // expected 298 } 299 try { 300 intMap.keySet().remove(new Object()); 301 fail(); 302 } catch (UnsupportedOperationException e) { 303 // expected 304 } 305 try { 306 intMap.values().remove(new Object()); 307 fail(); 308 } catch (UnsupportedOperationException e) { 309 // expected 310 } 311 try { 312 intMap.values().iterator().remove(); 313 fail(); 314 } catch (UnsupportedOperationException e) { 315 // expected 316 } 317 assertEquals(newMap(1, 2), intMap); 318 assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); 319 assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); 320 } 321 testGettersAndSetters()322 public void testGettersAndSetters() throws Exception { 323 TestMap.Builder builder = TestMap.newBuilder(); 324 TestMap message = builder.build(); 325 assertMapValuesCleared(message); 326 327 builder = message.toBuilder(); 328 setMapValues(builder); 329 message = builder.build(); 330 assertMapValuesSet(message); 331 332 builder = message.toBuilder(); 333 updateMapValues(builder); 334 message = builder.build(); 335 assertMapValuesUpdated(message); 336 337 builder = message.toBuilder(); 338 builder.clear(); 339 message = builder.build(); 340 assertMapValuesCleared(message); 341 } 342 testPutAll()343 public void testPutAll() throws Exception { 344 TestMap.Builder sourceBuilder = TestMap.newBuilder(); 345 setMapValues(sourceBuilder); 346 TestMap source = sourceBuilder.build(); 347 348 TestMap.Builder destination = TestMap.newBuilder(); 349 copyMapValues(source, destination); 350 assertMapValuesSet(destination.build()); 351 } 352 testSerializeAndParse()353 public void testSerializeAndParse() throws Exception { 354 TestMap.Builder builder = TestMap.newBuilder(); 355 setMapValues(builder); 356 TestMap message = builder.build(); 357 assertEquals(message.getSerializedSize(), message.toByteString().size()); 358 message = TestMap.parser().parseFrom(message.toByteString()); 359 assertMapValuesSet(message); 360 361 builder = message.toBuilder(); 362 updateMapValues(builder); 363 message = builder.build(); 364 assertEquals(message.getSerializedSize(), message.toByteString().size()); 365 message = TestMap.parser().parseFrom(message.toByteString()); 366 assertMapValuesUpdated(message); 367 368 builder = message.toBuilder(); 369 builder.clear(); 370 message = builder.build(); 371 assertEquals(message.getSerializedSize(), message.toByteString().size()); 372 message = TestMap.parser().parseFrom(message.toByteString()); 373 assertMapValuesCleared(message); 374 } 375 testMergeFrom()376 public void testMergeFrom() throws Exception { 377 TestMap.Builder builder = TestMap.newBuilder(); 378 setMapValues(builder); 379 TestMap message = builder.build(); 380 381 TestMap.Builder other = TestMap.newBuilder(); 382 other.mergeFrom(message); 383 assertMapValuesSet(other.build()); 384 } 385 testEqualsAndHashCode()386 public void testEqualsAndHashCode() throws Exception { 387 // Test that generated equals() and hashCode() will disregard the order 388 // of map entries when comparing/hashing map fields. 389 390 // We can't control the order of elements in a HashMap. The best we can do 391 // here is to add elements in different order. 392 TestMap.Builder b1 = TestMap.newBuilder(); 393 b1.getMutableInt32ToInt32Field().put(1, 2); 394 b1.getMutableInt32ToInt32Field().put(3, 4); 395 b1.getMutableInt32ToInt32Field().put(5, 6); 396 TestMap m1 = b1.build(); 397 398 TestMap.Builder b2 = TestMap.newBuilder(); 399 b2.getMutableInt32ToInt32Field().put(5, 6); 400 b2.getMutableInt32ToInt32Field().put(1, 2); 401 b2.getMutableInt32ToInt32Field().put(3, 4); 402 TestMap m2 = b2.build(); 403 404 assertEquals(m1, m2); 405 assertEquals(m1.hashCode(), m2.hashCode()); 406 407 // Make sure we did compare map fields. 408 b2.getMutableInt32ToInt32Field().put(1, 0); 409 m2 = b2.build(); 410 assertFalse(m1.equals(m2)); 411 // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed 412 // to be different. 413 } 414 testUnknownEnumValues()415 public void testUnknownEnumValues() throws Exception { 416 TestUnknownEnumValue.Builder builder = 417 TestUnknownEnumValue.newBuilder(); 418 builder.getMutableInt32ToInt32Field().put(1, 1); 419 builder.getMutableInt32ToInt32Field().put(2, 54321); 420 ByteString data = builder.build().toByteString(); 421 422 TestMap message = TestMap.parseFrom(data); 423 // Entries with unknown enum values will be stored into UnknownFieldSet so 424 // there is only one entry in the map. 425 assertEquals(1, message.getInt32ToEnumField().size()); 426 assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1)); 427 // Serializing and parsing should preserve the unknown entry. 428 data = message.toByteString(); 429 TestUnknownEnumValue messageWithUnknownEnums = 430 TestUnknownEnumValue.parseFrom(data); 431 assertEquals(2, messageWithUnknownEnums.getInt32ToInt32Field().size()); 432 assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue()); 433 assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue()); 434 } 435 436 testIterationOrder()437 public void testIterationOrder() throws Exception { 438 TestMap.Builder builder = TestMap.newBuilder(); 439 setMapValues(builder); 440 TestMap message = builder.build(); 441 442 assertEquals(Arrays.asList("1", "2", "3"), 443 new ArrayList<String>(message.getStringToInt32Field().keySet())); 444 } 445 newMap(K key1, V value1)446 private static <K, V> Map<K, V> newMap(K key1, V value1) { 447 Map<K, V> map = new HashMap<K, V>(); 448 map.put(key1, value1); 449 return map; 450 } 451 newMap(K key1, V value1, K key2, V value2)452 private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) { 453 Map<K, V> map = new HashMap<K, V>(); 454 map.put(key1, value1); 455 map.put(key2, value2); 456 return map; 457 } 458 } 459