MapsTest.java revision 0888a09821a98ac0680fad765217302858e70fa4
1/* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.common.collect; 18 19import static com.google.common.collect.Maps.transformEntries; 20import static com.google.common.collect.Maps.transformValues; 21import static com.google.common.collect.testing.Helpers.mapEntry; 22import static java.util.Arrays.asList; 23import static org.truth0.Truth.ASSERT; 24 25import com.google.common.annotations.GwtCompatible; 26import com.google.common.annotations.GwtIncompatible; 27import com.google.common.base.Converter; 28import com.google.common.base.Equivalence; 29import com.google.common.base.Function; 30import com.google.common.base.Functions; 31import com.google.common.base.Predicate; 32import com.google.common.base.Predicates; 33import com.google.common.collect.Maps.EntryTransformer; 34import com.google.common.collect.Maps.ValueDifferenceImpl; 35import com.google.common.collect.SetsTest.Derived; 36import com.google.common.testing.EqualsTester; 37import com.google.common.testing.NullPointerTester; 38import com.google.common.testing.SerializableTester; 39 40import junit.framework.TestCase; 41 42import java.io.IOException; 43import java.io.StringBufferInputStream; 44import java.lang.reflect.Field; 45import java.util.Arrays; 46import java.util.Collection; 47import java.util.Collections; 48import java.util.Comparator; 49import java.util.EnumMap; 50import java.util.Enumeration; 51import java.util.HashMap; 52import java.util.IdentityHashMap; 53import java.util.Iterator; 54import java.util.LinkedHashMap; 55import java.util.List; 56import java.util.Map; 57import java.util.Map.Entry; 58import java.util.Properties; 59import java.util.Set; 60import java.util.SortedMap; 61import java.util.SortedSet; 62import java.util.TreeMap; 63import java.util.concurrent.ConcurrentMap; 64 65/** 66 * Unit test for {@code Maps}. 67 * 68 * @author Kevin Bourrillion 69 * @author Mike Bostock 70 * @author Jared Levy 71 */ 72@GwtCompatible(emulated = true) 73public class MapsTest extends TestCase { 74 75 private static final Comparator<Integer> SOME_COMPARATOR = 76 Collections.reverseOrder(); 77 78 public void testHashMap() { 79 HashMap<Integer, Integer> map = Maps.newHashMap(); 80 assertEquals(Collections.emptyMap(), map); 81 } 82 83 public void testHashMapWithInitialMap() { 84 Map<String, Integer> original = new TreeMap<String, Integer>(); 85 original.put("a", 1); 86 original.put("b", 2); 87 original.put("c", 3); 88 HashMap<String, Integer> map = Maps.newHashMap(original); 89 assertEquals(original, map); 90 } 91 92 public void testHashMapGeneralizesTypes() { 93 Map<String, Integer> original = new TreeMap<String, Integer>(); 94 original.put("a", 1); 95 original.put("b", 2); 96 original.put("c", 3); 97 HashMap<Object, Object> map = 98 Maps.newHashMap((Map<? extends Object, ? extends Object>) original); 99 assertEquals(original, map); 100 } 101 102 public void testCapacityForNegativeSizeFails() { 103 try { 104 Maps.capacity(-1); 105 fail("Negative expected size must result in IllegalArgumentException"); 106 } catch (IllegalArgumentException ex) { 107 } 108 } 109 110 /** 111 * Tests that nHMWES makes hash maps large enough that adding the expected 112 * number of elements won't cause a rehash. 113 * 114 * As of jdk7u40, HashMap has an empty-map optimization. The argument to 115 * new HashMap(int) is noted, but the initial table is a zero-length array. 116 * 117 * This test may fail miserably on non-OpenJDK environments... 118 */ 119 @GwtIncompatible("reflection") 120 public void testNewHashMapWithExpectedSize_wontGrow() throws Exception { 121 // before jdk7u40: creates one-bucket table 122 // after jdk7u40: creates empty table 123 assertTrue(bucketsOf(Maps.newHashMapWithExpectedSize(0)) <= 1); 124 125 for (int size = 1; size < 200; size++) { 126 HashMap<Integer, Void> map1 = Maps.newHashMapWithExpectedSize(size); 127 128 // Only start measuring table size after the first element inserted, to 129 // deal with empty-map optimization. 130 map1.put(0, null); 131 132 int initialBuckets = bucketsOf(map1); 133 134 for (int i = 1; i < size; i++) { 135 map1.put(i, null); 136 } 137 assertEquals("table size after adding " + size + " elements", 138 initialBuckets, bucketsOf(map1)); 139 140 /* 141 * Something slightly different happens when the entries are added all at 142 * once; make sure that passes too. 143 */ 144 HashMap<Integer, Void> map2 = Maps.newHashMapWithExpectedSize(size); 145 map2.putAll(map1); 146 assertEquals("table size after adding " + size + "elements", 147 initialBuckets, bucketsOf(map2)); 148 } 149 } 150 151 @GwtIncompatible("reflection") 152 private static int bucketsOf(HashMap<?, ?> hashMap) throws Exception { 153 Field tableField = HashMap.class.getDeclaredField("table"); 154 tableField.setAccessible(true); 155 Object[] table = (Object[]) tableField.get(hashMap); 156 return table.length; 157 } 158 159 public void testCapacityForLargeSizes() { 160 int[] largeExpectedSizes = new int[] { 161 Integer.MAX_VALUE / 2 - 1, 162 Integer.MAX_VALUE / 2, 163 Integer.MAX_VALUE / 2 + 1, 164 Integer.MAX_VALUE - 1, 165 Integer.MAX_VALUE}; 166 for (int expectedSize : largeExpectedSizes) { 167 int capacity = Maps.capacity(expectedSize); 168 assertTrue( 169 "capacity (" + capacity + ") must be >= expectedSize (" + expectedSize + ")", 170 capacity >= expectedSize); 171 } 172 } 173 174 public void testLinkedHashMap() { 175 LinkedHashMap<Integer, Integer> map = Maps.newLinkedHashMap(); 176 assertEquals(Collections.emptyMap(), map); 177 } 178 179 @SuppressWarnings("serial") 180 public void testLinkedHashMapWithInitialMap() { 181 Map<String, String> map = new LinkedHashMap<String, String>() {{ 182 put("Hello", "World"); 183 put("first", "second"); 184 put("polygene", "lubricants"); 185 put("alpha", "betical"); 186 }}; 187 188 LinkedHashMap<String, String> copy = Maps.newLinkedHashMap(map); 189 190 Iterator<Entry<String, String>> iter = copy.entrySet().iterator(); 191 assertTrue(iter.hasNext()); 192 Entry<String, String> entry = iter.next(); 193 assertEquals("Hello", entry.getKey()); 194 assertEquals("World", entry.getValue()); 195 assertTrue(iter.hasNext()); 196 197 entry = iter.next(); 198 assertEquals("first", entry.getKey()); 199 assertEquals("second", entry.getValue()); 200 assertTrue(iter.hasNext()); 201 202 entry = iter.next(); 203 assertEquals("polygene", entry.getKey()); 204 assertEquals("lubricants", entry.getValue()); 205 assertTrue(iter.hasNext()); 206 207 entry = iter.next(); 208 assertEquals("alpha", entry.getKey()); 209 assertEquals("betical", entry.getValue()); 210 assertFalse(iter.hasNext()); 211 } 212 213 public void testLinkedHashMapGeneralizesTypes() { 214 Map<String, Integer> original = new LinkedHashMap<String, Integer>(); 215 original.put("a", 1); 216 original.put("b", 2); 217 original.put("c", 3); 218 HashMap<Object, Object> map 219 = Maps.<Object, Object>newLinkedHashMap(original); 220 assertEquals(original, map); 221 } 222 223 public void testIdentityHashMap() { 224 IdentityHashMap<Integer, Integer> map = Maps.newIdentityHashMap(); 225 assertEquals(Collections.emptyMap(), map); 226 } 227 228 public void testConcurrentMap() { 229 ConcurrentMap<Integer, Integer> map = Maps.newConcurrentMap(); 230 assertEquals(Collections.emptyMap(), map); 231 } 232 233 public void testTreeMap() { 234 TreeMap<Integer, Integer> map = Maps.newTreeMap(); 235 assertEquals(Collections.emptyMap(), map); 236 assertNull(map.comparator()); 237 } 238 239 public void testTreeMapDerived() { 240 TreeMap<Derived, Integer> map = Maps.newTreeMap(); 241 assertEquals(Collections.emptyMap(), map); 242 map.put(new Derived("foo"), 1); 243 map.put(new Derived("bar"), 2); 244 ASSERT.that(map.keySet()).has().exactly( 245 new Derived("bar"), new Derived("foo")).inOrder(); 246 ASSERT.that(map.values()).has().exactly(2, 1).inOrder(); 247 assertNull(map.comparator()); 248 } 249 250 public void testTreeMapNonGeneric() { 251 TreeMap<LegacyComparable, Integer> map = Maps.newTreeMap(); 252 assertEquals(Collections.emptyMap(), map); 253 map.put(new LegacyComparable("foo"), 1); 254 map.put(new LegacyComparable("bar"), 2); 255 ASSERT.that(map.keySet()).has().exactly( 256 new LegacyComparable("bar"), new LegacyComparable("foo")).inOrder(); 257 ASSERT.that(map.values()).has().exactly(2, 1).inOrder(); 258 assertNull(map.comparator()); 259 } 260 261 public void testTreeMapWithComparator() { 262 TreeMap<Integer, Integer> map = Maps.newTreeMap(SOME_COMPARATOR); 263 assertEquals(Collections.emptyMap(), map); 264 assertSame(SOME_COMPARATOR, map.comparator()); 265 } 266 267 public void testTreeMapWithInitialMap() { 268 SortedMap<Integer, Integer> map = Maps.newTreeMap(); 269 map.put(5, 10); 270 map.put(3, 20); 271 map.put(1, 30); 272 TreeMap<Integer, Integer> copy = Maps.newTreeMap(map); 273 assertEquals(copy, map); 274 assertSame(copy.comparator(), map.comparator()); 275 } 276 277 public enum SomeEnum { SOME_INSTANCE } 278 279 public void testEnumMap() { 280 EnumMap<SomeEnum, Integer> map = Maps.newEnumMap(SomeEnum.class); 281 assertEquals(Collections.emptyMap(), map); 282 map.put(SomeEnum.SOME_INSTANCE, 0); 283 assertEquals(Collections.singletonMap(SomeEnum.SOME_INSTANCE, 0), map); 284 } 285 286 public void testEnumMapNullClass() { 287 try { 288 Maps.<SomeEnum, Long>newEnumMap((Class<MapsTest.SomeEnum>) null); 289 fail("no exception thrown"); 290 } catch (NullPointerException expected) { 291 } 292 } 293 294 public void testEnumMapWithInitialEnumMap() { 295 EnumMap<SomeEnum, Integer> original = Maps.newEnumMap(SomeEnum.class); 296 original.put(SomeEnum.SOME_INSTANCE, 0); 297 EnumMap<SomeEnum, Integer> copy = Maps.newEnumMap(original); 298 assertEquals(original, copy); 299 } 300 301 public void testEnumMapWithInitialEmptyEnumMap() { 302 EnumMap<SomeEnum, Integer> original = Maps.newEnumMap(SomeEnum.class); 303 EnumMap<SomeEnum, Integer> copy = Maps.newEnumMap(original); 304 assertEquals(original, copy); 305 assertNotSame(original, copy); 306 } 307 308 public void testEnumMapWithInitialMap() { 309 HashMap<SomeEnum, Integer> original = Maps.newHashMap(); 310 original.put(SomeEnum.SOME_INSTANCE, 0); 311 EnumMap<SomeEnum, Integer> copy = Maps.newEnumMap(original); 312 assertEquals(original, copy); 313 } 314 315 public void testEnumMapWithInitialEmptyMap() { 316 Map<SomeEnum, Integer> original = Maps.newHashMap(); 317 try { 318 Maps.newEnumMap(original); 319 fail("Empty map must result in an IllegalArgumentException"); 320 } catch (IllegalArgumentException expected) {} 321 } 322 323 public void testToStringImplWithNullKeys() throws Exception { 324 Map<String, String> hashmap = Maps.newHashMap(); 325 hashmap.put("foo", "bar"); 326 hashmap.put(null, "baz"); 327 328 assertEquals(hashmap.toString(), Maps.toStringImpl(hashmap)); 329 } 330 331 public void testToStringImplWithNullValues() throws Exception { 332 Map<String, String> hashmap = Maps.newHashMap(); 333 hashmap.put("foo", "bar"); 334 hashmap.put("baz", null); 335 336 assertEquals(hashmap.toString(), Maps.toStringImpl(hashmap)); 337 } 338 339 @GwtIncompatible("NullPointerTester") 340 public void testNullPointerExceptions() { 341 new NullPointerTester().testAllPublicStaticMethods(Maps.class); 342 } 343 344 private static final Map<Integer, Integer> EMPTY 345 = Collections.emptyMap(); 346 private static final Map<Integer, Integer> SINGLETON 347 = Collections.singletonMap(1, 2); 348 349 public void testMapDifferenceEmptyEmpty() { 350 MapDifference<Integer, Integer> diff = Maps.difference(EMPTY, EMPTY); 351 assertTrue(diff.areEqual()); 352 assertEquals(EMPTY, diff.entriesOnlyOnLeft()); 353 assertEquals(EMPTY, diff.entriesOnlyOnRight()); 354 assertEquals(EMPTY, diff.entriesInCommon()); 355 assertEquals(EMPTY, diff.entriesDiffering()); 356 assertEquals("equal", diff.toString()); 357 } 358 359 public void testMapDifferenceEmptySingleton() { 360 MapDifference<Integer, Integer> diff = Maps.difference(EMPTY, SINGLETON); 361 assertFalse(diff.areEqual()); 362 assertEquals(EMPTY, diff.entriesOnlyOnLeft()); 363 assertEquals(SINGLETON, diff.entriesOnlyOnRight()); 364 assertEquals(EMPTY, diff.entriesInCommon()); 365 assertEquals(EMPTY, diff.entriesDiffering()); 366 assertEquals("not equal: only on right={1=2}", diff.toString()); 367 } 368 369 public void testMapDifferenceSingletonEmpty() { 370 MapDifference<Integer, Integer> diff = Maps.difference(SINGLETON, EMPTY); 371 assertFalse(diff.areEqual()); 372 assertEquals(SINGLETON, diff.entriesOnlyOnLeft()); 373 assertEquals(EMPTY, diff.entriesOnlyOnRight()); 374 assertEquals(EMPTY, diff.entriesInCommon()); 375 assertEquals(EMPTY, diff.entriesDiffering()); 376 assertEquals("not equal: only on left={1=2}", diff.toString()); 377 } 378 379 public void testMapDifferenceTypical() { 380 Map<Integer, String> left = ImmutableMap.of( 381 1, "a", 2, "b", 3, "c", 4, "d", 5, "e"); 382 Map<Integer, String> right = ImmutableMap.of( 383 1, "a", 3, "f", 5, "g", 6, "z"); 384 385 MapDifference<Integer, String> diff1 = Maps.difference(left, right); 386 assertFalse(diff1.areEqual()); 387 assertEquals(ImmutableMap.of(2, "b", 4, "d"), diff1.entriesOnlyOnLeft()); 388 assertEquals(ImmutableMap.of(6, "z"), diff1.entriesOnlyOnRight()); 389 assertEquals(ImmutableMap.of(1, "a"), diff1.entriesInCommon()); 390 assertEquals(ImmutableMap.of(3, 391 ValueDifferenceImpl.create("c", "f"), 5, 392 ValueDifferenceImpl.create("e", "g")), 393 diff1.entriesDiffering()); 394 assertEquals("not equal: only on left={2=b, 4=d}: only on right={6=z}: " 395 + "value differences={3=(c, f), 5=(e, g)}", diff1.toString()); 396 397 MapDifference<Integer, String> diff2 = Maps.difference(right, left); 398 assertFalse(diff2.areEqual()); 399 assertEquals(ImmutableMap.of(6, "z"), diff2.entriesOnlyOnLeft()); 400 assertEquals(ImmutableMap.of(2, "b", 4, "d"), diff2.entriesOnlyOnRight()); 401 assertEquals(ImmutableMap.of(1, "a"), diff2.entriesInCommon()); 402 assertEquals(ImmutableMap.of(3, 403 ValueDifferenceImpl.create("f", "c"), 5, 404 ValueDifferenceImpl.create("g", "e")), 405 diff2.entriesDiffering()); 406 assertEquals("not equal: only on left={6=z}: only on right={2=b, 4=d}: " 407 + "value differences={3=(f, c), 5=(g, e)}", diff2.toString()); 408 } 409 410 public void testMapDifferenceEquals() { 411 Map<Integer, String> left = ImmutableMap.of( 412 1, "a", 2, "b", 3, "c", 4, "d", 5, "e"); 413 Map<Integer, String> right = ImmutableMap.of( 414 1, "a", 3, "f", 5, "g", 6, "z"); 415 Map<Integer, String> right2 = ImmutableMap.of( 416 1, "a", 3, "h", 5, "g", 6, "z"); 417 MapDifference<Integer, String> original = Maps.difference(left, right); 418 MapDifference<Integer, String> same = Maps.difference(left, right); 419 MapDifference<Integer, String> reverse = Maps.difference(right, left); 420 MapDifference<Integer, String> diff2 = Maps.difference(left, right2); 421 422 new EqualsTester() 423 .addEqualityGroup(original, same) 424 .addEqualityGroup(reverse) 425 .addEqualityGroup(diff2) 426 .testEquals(); 427 } 428 429 public void testMapDifferencePredicateTypical() { 430 Map<Integer, String> left = ImmutableMap.of( 431 1, "a", 2, "b", 3, "c", 4, "d", 5, "e"); 432 Map<Integer, String> right = ImmutableMap.of( 433 1, "A", 3, "F", 5, "G", 6, "Z"); 434 435 // TODO(kevinb): replace with Ascii.caseInsensitiveEquivalence() when it 436 // exists 437 Equivalence<String> caseInsensitiveEquivalence = Equivalence.equals().onResultOf( 438 new Function<String, String>() { 439 @Override public String apply(String input) { 440 return input.toLowerCase(); 441 } 442 }); 443 444 MapDifference<Integer, String> diff1 = Maps.difference(left, right, 445 caseInsensitiveEquivalence); 446 assertFalse(diff1.areEqual()); 447 assertEquals(ImmutableMap.of(2, "b", 4, "d"), diff1.entriesOnlyOnLeft()); 448 assertEquals(ImmutableMap.of(6, "Z"), diff1.entriesOnlyOnRight()); 449 assertEquals(ImmutableMap.of(1, "a"), diff1.entriesInCommon()); 450 assertEquals(ImmutableMap.of(3, 451 ValueDifferenceImpl.create("c", "F"), 5, 452 ValueDifferenceImpl.create("e", "G")), 453 diff1.entriesDiffering()); 454 assertEquals("not equal: only on left={2=b, 4=d}: only on right={6=Z}: " 455 + "value differences={3=(c, F), 5=(e, G)}", diff1.toString()); 456 457 MapDifference<Integer, String> diff2 = Maps.difference(right, left, 458 caseInsensitiveEquivalence); 459 assertFalse(diff2.areEqual()); 460 assertEquals(ImmutableMap.of(6, "Z"), diff2.entriesOnlyOnLeft()); 461 assertEquals(ImmutableMap.of(2, "b", 4, "d"), diff2.entriesOnlyOnRight()); 462 assertEquals(ImmutableMap.of(1, "A"), diff2.entriesInCommon()); 463 assertEquals(ImmutableMap.of(3, 464 ValueDifferenceImpl.create("F", "c"), 5, 465 ValueDifferenceImpl.create("G", "e")), 466 diff2.entriesDiffering()); 467 assertEquals("not equal: only on left={6=Z}: only on right={2=b, 4=d}: " 468 + "value differences={3=(F, c), 5=(G, e)}", diff2.toString()); 469 } 470 471 private static final SortedMap<Integer, Integer> SORTED_EMPTY = Maps.newTreeMap(); 472 private static final SortedMap<Integer, Integer> SORTED_SINGLETON = 473 ImmutableSortedMap.of(1, 2); 474 475 public void testMapDifferenceOfSortedMapIsSorted() { 476 Map<Integer, Integer> map = SORTED_SINGLETON; 477 MapDifference<Integer, Integer> difference = Maps.difference(map, EMPTY); 478 assertTrue(difference instanceof SortedMapDifference); 479 } 480 481 public void testSortedMapDifferenceEmptyEmpty() { 482 SortedMapDifference<Integer, Integer> diff = 483 Maps.difference(SORTED_EMPTY, SORTED_EMPTY); 484 assertTrue(diff.areEqual()); 485 assertEquals(SORTED_EMPTY, diff.entriesOnlyOnLeft()); 486 assertEquals(SORTED_EMPTY, diff.entriesOnlyOnRight()); 487 assertEquals(SORTED_EMPTY, diff.entriesInCommon()); 488 assertEquals(SORTED_EMPTY, diff.entriesDiffering()); 489 assertEquals("equal", diff.toString()); 490 } 491 492 public void testSortedMapDifferenceEmptySingleton() { 493 SortedMapDifference<Integer, Integer> diff = 494 Maps.difference(SORTED_EMPTY, SORTED_SINGLETON); 495 assertFalse(diff.areEqual()); 496 assertEquals(SORTED_EMPTY, diff.entriesOnlyOnLeft()); 497 assertEquals(SORTED_SINGLETON, diff.entriesOnlyOnRight()); 498 assertEquals(SORTED_EMPTY, diff.entriesInCommon()); 499 assertEquals(SORTED_EMPTY, diff.entriesDiffering()); 500 assertEquals("not equal: only on right={1=2}", diff.toString()); 501 } 502 503 public void testSortedMapDifferenceSingletonEmpty() { 504 SortedMapDifference<Integer, Integer> diff = 505 Maps.difference(SORTED_SINGLETON, SORTED_EMPTY); 506 assertFalse(diff.areEqual()); 507 assertEquals(SORTED_SINGLETON, diff.entriesOnlyOnLeft()); 508 assertEquals(SORTED_EMPTY, diff.entriesOnlyOnRight()); 509 assertEquals(SORTED_EMPTY, diff.entriesInCommon()); 510 assertEquals(SORTED_EMPTY, diff.entriesDiffering()); 511 assertEquals("not equal: only on left={1=2}", diff.toString()); 512 } 513 514 public void testSortedMapDifferenceTypical() { 515 SortedMap<Integer, String> left = 516 ImmutableSortedMap.<Integer, String>reverseOrder() 517 .put(1, "a").put(2, "b").put(3, "c").put(4, "d").put(5, "e") 518 .build(); 519 520 SortedMap<Integer, String> right = 521 ImmutableSortedMap.of(1, "a", 3, "f", 5, "g", 6, "z"); 522 523 SortedMapDifference<Integer, String> diff1 = 524 Maps.difference(left, right); 525 assertFalse(diff1.areEqual()); 526 ASSERT.that(diff1.entriesOnlyOnLeft().entrySet()).has().exactly( 527 Maps.immutableEntry(4, "d"), Maps.immutableEntry(2, "b")).inOrder(); 528 ASSERT.that(diff1.entriesOnlyOnRight().entrySet()).has().item( 529 Maps.immutableEntry(6, "z")); 530 ASSERT.that(diff1.entriesInCommon().entrySet()).has().item( 531 Maps.immutableEntry(1, "a")); 532 ASSERT.that(diff1.entriesDiffering().entrySet()).has().exactly( 533 Maps.immutableEntry(5, ValueDifferenceImpl.create("e", "g")), 534 Maps.immutableEntry(3, ValueDifferenceImpl.create("c", "f"))).inOrder(); 535 assertEquals("not equal: only on left={4=d, 2=b}: only on right={6=z}: " 536 + "value differences={5=(e, g), 3=(c, f)}", diff1.toString()); 537 538 SortedMapDifference<Integer, String> diff2 = 539 Maps.difference(right, left); 540 assertFalse(diff2.areEqual()); 541 ASSERT.that(diff2.entriesOnlyOnLeft().entrySet()).has().item( 542 Maps.immutableEntry(6, "z")); 543 ASSERT.that(diff2.entriesOnlyOnRight().entrySet()).has().exactly( 544 Maps.immutableEntry(2, "b"), Maps.immutableEntry(4, "d")).inOrder(); 545 ASSERT.that(diff1.entriesInCommon().entrySet()).has().item( 546 Maps.immutableEntry(1, "a")); 547 assertEquals(ImmutableMap.of( 548 3, ValueDifferenceImpl.create("f", "c"), 549 5, ValueDifferenceImpl.create("g", "e")), 550 diff2.entriesDiffering()); 551 assertEquals("not equal: only on left={6=z}: only on right={2=b, 4=d}: " 552 + "value differences={3=(f, c), 5=(g, e)}", diff2.toString()); 553 } 554 555 public void testSortedMapDifferenceImmutable() { 556 SortedMap<Integer, String> left = Maps.newTreeMap( 557 ImmutableSortedMap.of(1, "a", 2, "b", 3, "c", 4, "d", 5, "e")); 558 SortedMap<Integer, String> right = 559 Maps.newTreeMap(ImmutableSortedMap.of(1, "a", 3, "f", 5, "g", 6, "z")); 560 561 SortedMapDifference<Integer, String> diff1 = 562 Maps.difference(left, right); 563 left.put(6, "z"); 564 assertFalse(diff1.areEqual()); 565 ASSERT.that(diff1.entriesOnlyOnLeft().entrySet()).has().exactly( 566 Maps.immutableEntry(2, "b"), Maps.immutableEntry(4, "d")).inOrder(); 567 ASSERT.that(diff1.entriesOnlyOnRight().entrySet()).has().item( 568 Maps.immutableEntry(6, "z")); 569 ASSERT.that(diff1.entriesInCommon().entrySet()).has().item( 570 Maps.immutableEntry(1, "a")); 571 ASSERT.that(diff1.entriesDiffering().entrySet()).has().exactly( 572 Maps.immutableEntry(3, ValueDifferenceImpl.create("c", "f")), 573 Maps.immutableEntry(5, ValueDifferenceImpl.create("e", "g"))).inOrder(); 574 try { 575 diff1.entriesInCommon().put(7, "x"); 576 fail(); 577 } catch (UnsupportedOperationException expected) { 578 } 579 try { 580 diff1.entriesOnlyOnLeft().put(7, "x"); 581 fail(); 582 } catch (UnsupportedOperationException expected) { 583 } 584 try { 585 diff1.entriesOnlyOnRight().put(7, "x"); 586 fail(); 587 } catch (UnsupportedOperationException expected) { 588 } 589 } 590 591 public void testSortedMapDifferenceEquals() { 592 SortedMap<Integer, String> left = 593 ImmutableSortedMap.of(1, "a", 2, "b", 3, "c", 4, "d", 5, "e"); 594 SortedMap<Integer, String> right = 595 ImmutableSortedMap.of(1, "a", 3, "f", 5, "g", 6, "z"); 596 SortedMap<Integer, String> right2 = 597 ImmutableSortedMap.of(1, "a", 3, "h", 5, "g", 6, "z"); 598 SortedMapDifference<Integer, String> original = 599 Maps.difference(left, right); 600 SortedMapDifference<Integer, String> same = 601 Maps.difference(left, right); 602 SortedMapDifference<Integer, String> reverse = 603 Maps.difference(right, left); 604 SortedMapDifference<Integer, String> diff2 = 605 Maps.difference(left, right2); 606 607 new EqualsTester() 608 .addEqualityGroup(original, same) 609 .addEqualityGroup(reverse) 610 .addEqualityGroup(diff2) 611 .testEquals(); 612 } 613 614 private static final Function<String, Integer> LENGTH_FUNCTION = 615 new Function<String, Integer>() { 616 @Override 617 public Integer apply(String input) { 618 return input.length(); 619 } 620 }; 621 622 public void testAsMap() { 623 Set<String> strings = ImmutableSet.of("one", "two", "three"); 624 Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION); 625 assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map); 626 assertEquals(Integer.valueOf(5), map.get("three")); 627 assertNull(map.get("five")); 628 ASSERT.that(map.entrySet()).has().exactly( 629 mapEntry("one", 3), 630 mapEntry("two", 3), 631 mapEntry("three", 5)).inOrder(); 632 } 633 634 public void testAsMapReadsThrough() { 635 Set<String> strings = Sets.newLinkedHashSet(); 636 Collections.addAll(strings, "one", "two", "three"); 637 Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION); 638 assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map); 639 assertNull(map.get("four")); 640 strings.add("four"); 641 assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5, "four", 4), map); 642 assertEquals(Integer.valueOf(4), map.get("four")); 643 } 644 645 public void testAsMapWritesThrough() { 646 Set<String> strings = Sets.newLinkedHashSet(); 647 Collections.addAll(strings, "one", "two", "three"); 648 Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION); 649 assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map); 650 assertEquals(Integer.valueOf(3), map.remove("two")); 651 ASSERT.that(strings).has().exactly("one", "three").inOrder(); 652 } 653 654 public void testAsMapEmpty() { 655 Set<String> strings = ImmutableSet.of(); 656 Map<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION); 657 ASSERT.that(map.entrySet()).isEmpty(); 658 assertTrue(map.isEmpty()); 659 assertNull(map.get("five")); 660 } 661 662 private static class NonNavigableSortedSet 663 extends ForwardingSortedSet<String> { 664 private final SortedSet<String> delegate = Sets.newTreeSet(); 665 666 @Override 667 protected SortedSet<String> delegate() { 668 return delegate; 669 } 670 } 671 672 public void testAsMapReturnsSortedMapForSortedSetInput() { 673 Set<String> set = new NonNavigableSortedSet(); 674 assertTrue(Maps.asMap(set, Functions.identity()) instanceof SortedMap); 675 } 676 677 public void testAsMapSorted() { 678 SortedSet<String> strings = new NonNavigableSortedSet(); 679 Collections.addAll(strings, "one", "two", "three"); 680 SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION); 681 assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map); 682 assertEquals(Integer.valueOf(5), map.get("three")); 683 assertNull(map.get("five")); 684 ASSERT.that(map.entrySet()).has().exactly( 685 mapEntry("one", 3), 686 mapEntry("three", 5), 687 mapEntry("two", 3)).inOrder(); 688 ASSERT.that(map.tailMap("onea").entrySet()).has().exactly( 689 mapEntry("three", 5), 690 mapEntry("two", 3)).inOrder(); 691 ASSERT.that(map.subMap("one", "two").entrySet()).has().exactly( 692 mapEntry("one", 3), 693 mapEntry("three", 5)).inOrder(); 694 } 695 696 public void testAsMapSortedReadsThrough() { 697 SortedSet<String> strings = new NonNavigableSortedSet(); 698 Collections.addAll(strings, "one", "two", "three"); 699 SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION); 700 assertNull(map.comparator()); 701 assertEquals(ImmutableSortedMap.of("one", 3, "two", 3, "three", 5), map); 702 assertNull(map.get("four")); 703 strings.add("four"); 704 assertEquals( 705 ImmutableSortedMap.of("one", 3, "two", 3, "three", 5, "four", 4), 706 map); 707 assertEquals(Integer.valueOf(4), map.get("four")); 708 SortedMap<String, Integer> headMap = map.headMap("two"); 709 assertEquals( 710 ImmutableSortedMap.of("four", 4, "one", 3, "three", 5), 711 headMap); 712 strings.add("five"); 713 strings.remove("one"); 714 assertEquals( 715 ImmutableSortedMap.of("five", 4, "four", 4, "three", 5), 716 headMap); 717 ASSERT.that(map.entrySet()).has().exactly( 718 mapEntry("five", 4), 719 mapEntry("four", 4), 720 mapEntry("three", 5), 721 mapEntry("two", 3)).inOrder(); 722 } 723 724 public void testAsMapSortedWritesThrough() { 725 SortedSet<String> strings = new NonNavigableSortedSet(); 726 Collections.addAll(strings, "one", "two", "three"); 727 SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION); 728 assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map); 729 assertEquals(Integer.valueOf(3), map.remove("two")); 730 ASSERT.that(strings).has().exactly("one", "three").inOrder(); 731 } 732 733 public void testAsMapSortedSubViewKeySetsDoNotSupportAdd() { 734 SortedMap<String, Integer> map = Maps.asMap( 735 new NonNavigableSortedSet(), LENGTH_FUNCTION); 736 try { 737 map.subMap("a", "z").keySet().add("a"); 738 fail(); 739 } catch (UnsupportedOperationException expected) { 740 } 741 try { 742 map.tailMap("a").keySet().add("a"); 743 fail(); 744 } catch (UnsupportedOperationException expected) { 745 } 746 try { 747 map.headMap("r").keySet().add("a"); 748 fail(); 749 } catch (UnsupportedOperationException expected) { 750 } 751 try { 752 map.headMap("r").tailMap("m").keySet().add("a"); 753 fail(); 754 } catch (UnsupportedOperationException expected) { 755 } 756 } 757 758 public void testAsMapSortedEmpty() { 759 SortedSet<String> strings = new NonNavigableSortedSet(); 760 SortedMap<String, Integer> map = Maps.asMap(strings, LENGTH_FUNCTION); 761 ASSERT.that(map.entrySet()).isEmpty(); 762 assertTrue(map.isEmpty()); 763 assertNull(map.get("five")); 764 } 765 766 public void testToMap() { 767 Iterable<String> strings = ImmutableList.of("one", "two", "three"); 768 ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION); 769 assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map); 770 ASSERT.that(map.entrySet()).has().exactly( 771 mapEntry("one", 3), 772 mapEntry("two", 3), 773 mapEntry("three", 5)).inOrder(); 774 } 775 776 public void testToMapIterator() { 777 Iterator<String> strings = ImmutableList.of("one", "two", "three").iterator(); 778 ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION); 779 assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map); 780 ASSERT.that(map.entrySet()).has().exactly( 781 mapEntry("one", 3), 782 mapEntry("two", 3), 783 mapEntry("three", 5)).inOrder(); 784 } 785 786 public void testToMapWithDuplicateKeys() { 787 Iterable<String> strings = ImmutableList.of("one", "two", "three", "two", "one"); 788 ImmutableMap<String, Integer> map = Maps.toMap(strings, LENGTH_FUNCTION); 789 assertEquals(ImmutableMap.of("one", 3, "two", 3, "three", 5), map); 790 ASSERT.that(map.entrySet()).has().exactly( 791 mapEntry("one", 3), 792 mapEntry("two", 3), 793 mapEntry("three", 5)).inOrder(); 794 } 795 796 public void testToMapWithNullKeys() { 797 Iterable<String> strings = Arrays.asList("one", null, "three"); 798 try { 799 Maps.toMap(strings, Functions.constant("foo")); 800 fail(); 801 } catch (NullPointerException expected) { 802 } 803 } 804 805 public void testToMapWithNullValues() { 806 Iterable<String> strings = ImmutableList.of("one", "two", "three"); 807 try { 808 Maps.toMap(strings, Functions.constant(null)); 809 fail(); 810 } catch (NullPointerException expected) { 811 } 812 } 813 814 private static final BiMap<Integer, String> INT_TO_STRING_MAP = 815 new ImmutableBiMap.Builder<Integer, String>() 816 .put(1, "one") 817 .put(2, "two") 818 .put(3, "three") 819 .build(); 820 821 public void testUniqueIndexCollection() { 822 ImmutableMap<Integer, String> outputMap = 823 Maps.uniqueIndex(INT_TO_STRING_MAP.values(), 824 Functions.forMap(INT_TO_STRING_MAP.inverse())); 825 assertEquals(INT_TO_STRING_MAP, outputMap); 826 } 827 828 public void testUniqueIndexIterable() { 829 ImmutableMap<Integer, String> outputMap = 830 Maps.uniqueIndex(new Iterable<String>() { 831 @Override 832 public Iterator<String> iterator() { 833 return INT_TO_STRING_MAP.values().iterator(); 834 } 835 }, 836 Functions.forMap(INT_TO_STRING_MAP.inverse())); 837 assertEquals(INT_TO_STRING_MAP, outputMap); 838 } 839 840 public void testUniqueIndexIterator() { 841 ImmutableMap<Integer, String> outputMap = 842 Maps.uniqueIndex(INT_TO_STRING_MAP.values().iterator(), 843 Functions.forMap(INT_TO_STRING_MAP.inverse())); 844 assertEquals(INT_TO_STRING_MAP, outputMap); 845 } 846 847 /** Can't create the map if more than one value maps to the same key. */ 848 public void testUniqueIndexDuplicates() { 849 try { 850 Maps.uniqueIndex(ImmutableSet.of("one", "uno"), Functions.constant(1)); 851 fail(); 852 } catch (IllegalArgumentException expected) { 853 } 854 } 855 856 /** Null values are not allowed. */ 857 public void testUniqueIndexNullValue() { 858 List<String> listWithNull = Lists.newArrayList((String) null); 859 try { 860 Maps.uniqueIndex(listWithNull, Functions.constant(1)); 861 fail(); 862 } catch (NullPointerException expected) { 863 } 864 } 865 866 /** Null keys aren't allowed either. */ 867 public void testUniqueIndexNullKey() { 868 List<String> oneStringList = Lists.newArrayList("foo"); 869 try { 870 Maps.uniqueIndex(oneStringList, Functions.constant(null)); 871 fail(); 872 } catch (NullPointerException expected) { 873 } 874 } 875 876 @GwtIncompatible("Maps.fromProperties") 877 @SuppressWarnings("deprecation") // StringBufferInputStream 878 public void testFromProperties() throws IOException { 879 Properties testProp = new Properties(); 880 881 Map<String, String> result = Maps.fromProperties(testProp); 882 assertTrue(result.isEmpty()); 883 testProp.setProperty("first", "true"); 884 885 result = Maps.fromProperties(testProp); 886 assertEquals("true", result.get("first")); 887 assertEquals(1, result.size()); 888 testProp.setProperty("second", "null"); 889 890 result = Maps.fromProperties(testProp); 891 assertEquals("true", result.get("first")); 892 assertEquals("null", result.get("second")); 893 assertEquals(2, result.size()); 894 895 // Now test values loaded from a stream. 896 String props = "test\n second = 2\n Third item : a short phrase "; 897 898 testProp.load(new StringBufferInputStream(props)); 899 900 result = Maps.fromProperties(testProp); 901 assertEquals(4, result.size()); 902 assertEquals("true", result.get("first")); 903 assertEquals("", result.get("test")); 904 assertEquals("2", result.get("second")); 905 assertEquals("item : a short phrase ", result.get("Third")); 906 assertFalse(result.containsKey("not here")); 907 908 // Test loading system properties 909 result = Maps.fromProperties(System.getProperties()); 910 assertTrue(result.containsKey("java.version")); 911 912 // Test that defaults work, too. 913 testProp = new Properties(System.getProperties()); 914 String override = "test\njava.version : hidden"; 915 916 testProp.load(new StringBufferInputStream(override)); 917 918 result = Maps.fromProperties(testProp); 919 assertTrue(result.size() > 2); 920 assertEquals("", result.get("test")); 921 assertEquals("hidden", result.get("java.version")); 922 assertNotSame(System.getProperty("java.version"), 923 result.get("java.version")); 924 } 925 926 @GwtIncompatible("Maps.fromProperties") 927 @SuppressWarnings("serial") // never serialized 928 public void testFromPropertiesNullKey() { 929 Properties properties = new Properties() { 930 @Override public Enumeration<?> propertyNames() { 931 return Iterators.asEnumeration( 932 Arrays.asList(null, "first", "second").iterator()); 933 } 934 }; 935 properties.setProperty("first", "true"); 936 properties.setProperty("second", "null"); 937 938 try { 939 Maps.fromProperties(properties); 940 fail(); 941 } catch (NullPointerException expected) {} 942 } 943 944 @GwtIncompatible("Maps.fromProperties") 945 @SuppressWarnings("serial") // never serialized 946 public void testFromPropertiesNonStringKeys() { 947 Properties properties = new Properties() { 948 @Override public Enumeration<?> propertyNames() { 949 return Iterators.asEnumeration( 950 Arrays.<Object>asList(Integer.valueOf(123), "first").iterator()); 951 } 952 }; 953 954 try { 955 Maps.fromProperties(properties); 956 fail(); 957 } catch (ClassCastException expected) {} 958 } 959 960 /** 961 * Constructs a "nefarious" map entry with the specified key and value, 962 * meaning an entry that is suitable for testing that map entries cannot be 963 * modified via a nefarious implementation of equals. This is used for testing 964 * unmodifiable collections of map entries; for example, it should not be 965 * possible to access the raw (modifiable) map entry via a nefarious equals 966 * method. 967 */ 968 public static <K, V> Map.Entry<K, V> nefariousEntry( 969 final K key, final V value) { 970 return new AbstractMapEntry<K, V>() { 971 @Override public K getKey() { 972 return key; 973 } 974 @Override public V getValue() { 975 return value; 976 } 977 @Override public V setValue(V value) { 978 throw new UnsupportedOperationException(); 979 } 980 @SuppressWarnings("unchecked") 981 @Override public boolean equals(Object o) { 982 if (o instanceof Map.Entry) { 983 Map.Entry<K, V> e = (Map.Entry<K, V>) o; 984 e.setValue(value); // muhahaha! 985 } 986 return super.equals(o); 987 } 988 }; 989 } 990 991 public void testAsConverter_nominal() throws Exception { 992 ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of( 993 "one", 1, 994 "two", 2); 995 Converter<String, Integer> converter = Maps.asConverter(biMap); 996 for (Entry<String, Integer> entry : biMap.entrySet()) { 997 assertSame(entry.getValue(), converter.convert(entry.getKey())); 998 } 999 } 1000 1001 public void testAsConverter_inverse() throws Exception { 1002 ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of( 1003 "one", 1, 1004 "two", 2); 1005 Converter<String, Integer> converter = Maps.asConverter(biMap); 1006 for (Entry<String, Integer> entry : biMap.entrySet()) { 1007 assertSame(entry.getKey(), converter.reverse().convert(entry.getValue())); 1008 } 1009 } 1010 1011 public void testAsConverter_noMapping() throws Exception { 1012 ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of( 1013 "one", 1, 1014 "two", 2); 1015 Converter<String, Integer> converter = Maps.asConverter(biMap); 1016 try { 1017 converter.convert("three"); 1018 fail(); 1019 } catch (IllegalArgumentException expected) { 1020 } 1021 } 1022 1023 public void testAsConverter_nullConversions() throws Exception { 1024 ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of( 1025 "one", 1, 1026 "two", 2); 1027 Converter<String, Integer> converter = Maps.asConverter(biMap); 1028 assertNull(converter.convert(null)); 1029 assertNull(converter.reverse().convert(null)); 1030 } 1031 1032 public void testAsConverter_isAView() throws Exception { 1033 BiMap<String, Integer> biMap = HashBiMap.create(); 1034 biMap.put("one", 1); 1035 biMap.put("two", 2); 1036 Converter<String, Integer> converter = Maps.asConverter(biMap); 1037 1038 assertSame(1, converter.convert("one")); 1039 assertSame(2, converter.convert("two")); 1040 try { 1041 converter.convert("three"); 1042 fail(); 1043 } catch (IllegalArgumentException expected) { 1044 } 1045 1046 biMap.put("three", 3); 1047 1048 assertSame(1, converter.convert("one")); 1049 assertSame(2, converter.convert("two")); 1050 assertSame(3, converter.convert("three")); 1051 } 1052 1053 public void testAsConverter_withNullMapping() throws Exception { 1054 BiMap<String, Integer> biMap = HashBiMap.create(); 1055 biMap.put("one", 1); 1056 biMap.put("two", 2); 1057 biMap.put("three", null); 1058 try { 1059 Maps.asConverter(biMap).convert("three"); 1060 fail(); 1061 } catch (IllegalArgumentException expected) { 1062 } 1063 } 1064 1065 public void testAsConverter_toString() { 1066 ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of( 1067 "one", 1, 1068 "two", 2); 1069 Converter<String, Integer> converter = Maps.asConverter(biMap); 1070 assertEquals("Maps.asConverter({one=1, two=2})", converter.toString()); 1071 } 1072 1073 public void testAsConverter_serialization() { 1074 ImmutableBiMap<String, Integer> biMap = ImmutableBiMap.of( 1075 "one", 1, 1076 "two", 2); 1077 Converter<String, Integer> converter = Maps.asConverter(biMap); 1078 SerializableTester.reserializeAndAssert(converter); 1079 } 1080 1081 public void testUnmodifiableBiMap() { 1082 BiMap<Integer, String> mod = HashBiMap.create(); 1083 mod.put(1, "one"); 1084 mod.put(2, "two"); 1085 mod.put(3, "three"); 1086 1087 BiMap<Number, String> unmod = Maps.<Number, String>unmodifiableBiMap(mod); 1088 1089 /* No aliasing on inverse operations. */ 1090 assertSame(unmod.inverse(), unmod.inverse()); 1091 assertSame(unmod, unmod.inverse().inverse()); 1092 1093 /* Unmodifiable is a view. */ 1094 mod.put(4, "four"); 1095 assertEquals(true, unmod.get(4).equals("four")); 1096 assertEquals(true, unmod.inverse().get("four").equals(4)); 1097 1098 /* UnsupportedOperationException on direct modifications. */ 1099 try { 1100 unmod.put(4, "four"); 1101 fail("UnsupportedOperationException expected"); 1102 } catch (UnsupportedOperationException expected) {} 1103 try { 1104 unmod.forcePut(4, "four"); 1105 fail("UnsupportedOperationException expected"); 1106 } catch (UnsupportedOperationException expected) {} 1107 try { 1108 unmod.putAll(Collections.singletonMap(4, "four")); 1109 fail("UnsupportedOperationException expected"); 1110 } catch (UnsupportedOperationException expected) {} 1111 1112 /* UnsupportedOperationException on indirect modifications. */ 1113 BiMap<String, Number> inverse = unmod.inverse(); 1114 try { 1115 inverse.put("four", 4); 1116 fail("UnsupportedOperationException expected"); 1117 } catch (UnsupportedOperationException expected) {} 1118 try { 1119 inverse.forcePut("four", 4); 1120 fail("UnsupportedOperationException expected"); 1121 } catch (UnsupportedOperationException expected) {} 1122 try { 1123 inverse.putAll(Collections.singletonMap("four", 4)); 1124 fail("UnsupportedOperationException expected"); 1125 } catch (UnsupportedOperationException expected) {} 1126 Set<String> values = unmod.values(); 1127 try { 1128 values.remove("four"); 1129 fail("UnsupportedOperationException expected"); 1130 } catch (UnsupportedOperationException expected) {} 1131 Set<Map.Entry<Number, String>> entries = unmod.entrySet(); 1132 Map.Entry<Number, String> entry = entries.iterator().next(); 1133 try { 1134 entry.setValue("four"); 1135 fail("UnsupportedOperationException expected"); 1136 } catch (UnsupportedOperationException expected) {} 1137 @SuppressWarnings("unchecked") 1138 Map.Entry<Integer, String> entry2 1139 = (Map.Entry<Integer, String>) entries.toArray()[0]; 1140 try { 1141 entry2.setValue("four"); 1142 fail("UnsupportedOperationException expected"); 1143 } catch (UnsupportedOperationException expected) {} 1144 } 1145 1146 public void testImmutableEntry() { 1147 Map.Entry<String, Integer> e = Maps.immutableEntry("foo", 1); 1148 assertEquals("foo", e.getKey()); 1149 assertEquals(1, (int) e.getValue()); 1150 try { 1151 e.setValue(2); 1152 fail("UnsupportedOperationException expected"); 1153 } catch (UnsupportedOperationException expected) {} 1154 assertEquals("foo=1", e.toString()); 1155 assertEquals(101575, e.hashCode()); 1156 } 1157 1158 public void testImmutableEntryNull() { 1159 Map.Entry<String, Integer> e 1160 = Maps.immutableEntry((String) null, (Integer) null); 1161 assertNull(e.getKey()); 1162 assertNull(e.getValue()); 1163 try { 1164 e.setValue(null); 1165 fail("UnsupportedOperationException expected"); 1166 } catch (UnsupportedOperationException expected) {} 1167 assertEquals("null=null", e.toString()); 1168 assertEquals(0, e.hashCode()); 1169 } 1170 1171 /** See {@link SynchronizedBiMapTest} for more tests. */ 1172 public void testSynchronizedBiMap() { 1173 BiMap<String, Integer> bimap = HashBiMap.create(); 1174 bimap.put("one", 1); 1175 BiMap<String, Integer> sync = Maps.synchronizedBiMap(bimap); 1176 bimap.put("two", 2); 1177 sync.put("three", 3); 1178 assertEquals(ImmutableSet.of(1, 2, 3), bimap.inverse().keySet()); 1179 assertEquals(ImmutableSet.of(1, 2, 3), sync.inverse().keySet()); 1180 } 1181 1182 private static final Predicate<String> NOT_LENGTH_3 1183 = new Predicate<String>() { 1184 @Override 1185 public boolean apply(String input) { 1186 return input == null || input.length() != 3; 1187 } 1188 }; 1189 1190 private static final Predicate<Integer> EVEN 1191 = new Predicate<Integer>() { 1192 @Override 1193 public boolean apply(Integer input) { 1194 return input == null || input % 2 == 0; 1195 } 1196 }; 1197 1198 private static final Predicate<Entry<String, Integer>> CORRECT_LENGTH 1199 = new Predicate<Entry<String, Integer>>() { 1200 @Override 1201 public boolean apply(Entry<String, Integer> input) { 1202 return input.getKey().length() == input.getValue(); 1203 } 1204 }; 1205 1206 private static final Function<Integer, Double> SQRT_FUNCTION = new Function<Integer, Double>() { 1207 @Override 1208 public Double apply(Integer in) { 1209 return Math.sqrt(in); 1210 } 1211 }; 1212 1213 public static class FilteredMapTest extends TestCase { 1214 Map<String, Integer> createUnfiltered() { 1215 return Maps.newHashMap(); 1216 } 1217 1218 public void testFilteredKeysIllegalPut() { 1219 Map<String, Integer> unfiltered = createUnfiltered(); 1220 Map<String, Integer> filtered = Maps.filterKeys(unfiltered, NOT_LENGTH_3); 1221 filtered.put("a", 1); 1222 filtered.put("b", 2); 1223 assertEquals(ImmutableMap.of("a", 1, "b", 2), filtered); 1224 1225 try { 1226 filtered.put("yyy", 3); 1227 fail(); 1228 } catch (IllegalArgumentException expected) {} 1229 } 1230 1231 public void testFilteredKeysIllegalPutAll() { 1232 Map<String, Integer> unfiltered = createUnfiltered(); 1233 Map<String, Integer> filtered = Maps.filterKeys(unfiltered, NOT_LENGTH_3); 1234 filtered.put("a", 1); 1235 filtered.put("b", 2); 1236 assertEquals(ImmutableMap.of("a", 1, "b", 2), filtered); 1237 1238 try { 1239 filtered.putAll(ImmutableMap.of("c", 3, "zzz", 4, "b", 5)); 1240 fail(); 1241 } catch (IllegalArgumentException expected) {} 1242 1243 assertEquals(ImmutableMap.of("a", 1, "b", 2), filtered); 1244 } 1245 1246 public void testFilteredKeysFilteredReflectsBackingChanges() { 1247 Map<String, Integer> unfiltered = createUnfiltered(); 1248 Map<String, Integer> filtered = Maps.filterKeys(unfiltered, NOT_LENGTH_3); 1249 unfiltered.put("two", 2); 1250 unfiltered.put("three", 3); 1251 unfiltered.put("four", 4); 1252 assertEquals(ImmutableMap.of("two", 2, "three", 3, "four", 4), unfiltered); 1253 assertEquals(ImmutableMap.of("three", 3, "four", 4), filtered); 1254 1255 unfiltered.remove("three"); 1256 assertEquals(ImmutableMap.of("two", 2, "four", 4), unfiltered); 1257 assertEquals(ImmutableMap.of("four", 4), filtered); 1258 1259 unfiltered.clear(); 1260 assertEquals(ImmutableMap.of(), unfiltered); 1261 assertEquals(ImmutableMap.of(), filtered); 1262 } 1263 1264 public void testFilteredValuesIllegalPut() { 1265 Map<String, Integer> unfiltered = createUnfiltered(); 1266 Map<String, Integer> filtered = Maps.filterValues(unfiltered, EVEN); 1267 filtered.put("a", 2); 1268 unfiltered.put("b", 4); 1269 unfiltered.put("c", 5); 1270 assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered); 1271 1272 try { 1273 filtered.put("yyy", 3); 1274 fail(); 1275 } catch (IllegalArgumentException expected) {} 1276 assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered); 1277 } 1278 1279 public void testFilteredValuesIllegalPutAll() { 1280 Map<String, Integer> unfiltered = createUnfiltered(); 1281 Map<String, Integer> filtered = Maps.filterValues(unfiltered, EVEN); 1282 filtered.put("a", 2); 1283 unfiltered.put("b", 4); 1284 unfiltered.put("c", 5); 1285 assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered); 1286 1287 try { 1288 filtered.putAll(ImmutableMap.of("c", 4, "zzz", 5, "b", 6)); 1289 fail(); 1290 } catch (IllegalArgumentException expected) {} 1291 assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered); 1292 } 1293 1294 public void testFilteredValuesIllegalSetValue() { 1295 Map<String, Integer> unfiltered = createUnfiltered(); 1296 Map<String, Integer> filtered = Maps.filterValues(unfiltered, EVEN); 1297 filtered.put("a", 2); 1298 filtered.put("b", 4); 1299 assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered); 1300 1301 Entry<String, Integer> entry = filtered.entrySet().iterator().next(); 1302 try { 1303 entry.setValue(5); 1304 fail(); 1305 } catch (IllegalArgumentException expected) {} 1306 1307 assertEquals(ImmutableMap.of("a", 2, "b", 4), filtered); 1308 } 1309 1310 public void testFilteredValuesClear() { 1311 Map<String, Integer> unfiltered = createUnfiltered(); 1312 unfiltered.put("one", 1); 1313 unfiltered.put("two", 2); 1314 unfiltered.put("three", 3); 1315 unfiltered.put("four", 4); 1316 Map<String, Integer> filtered = Maps.filterValues(unfiltered, EVEN); 1317 assertEquals(ImmutableMap.of("one", 1, "two", 2, "three", 3, "four", 4), 1318 unfiltered); 1319 assertEquals(ImmutableMap.of("two", 2, "four", 4), filtered); 1320 1321 filtered.clear(); 1322 assertEquals(ImmutableMap.of("one", 1, "three", 3), unfiltered); 1323 assertTrue(filtered.isEmpty()); 1324 } 1325 1326 public void testFilteredEntriesIllegalPut() { 1327 Map<String, Integer> unfiltered = createUnfiltered(); 1328 unfiltered.put("cat", 3); 1329 unfiltered.put("dog", 2); 1330 unfiltered.put("horse", 5); 1331 Map<String, Integer> filtered 1332 = Maps.filterEntries(unfiltered, CORRECT_LENGTH); 1333 assertEquals(ImmutableMap.of("cat", 3, "horse", 5), filtered); 1334 1335 filtered.put("chicken", 7); 1336 assertEquals(ImmutableMap.of("cat", 3, "horse", 5, "chicken", 7), filtered); 1337 1338 try { 1339 filtered.put("cow", 7); 1340 fail(); 1341 } catch (IllegalArgumentException expected) {} 1342 assertEquals(ImmutableMap.of("cat", 3, "horse", 5, "chicken", 7), filtered); 1343 } 1344 1345 public void testFilteredEntriesIllegalPutAll() { 1346 Map<String, Integer> unfiltered = createUnfiltered(); 1347 unfiltered.put("cat", 3); 1348 unfiltered.put("dog", 2); 1349 unfiltered.put("horse", 5); 1350 Map<String, Integer> filtered 1351 = Maps.filterEntries(unfiltered, CORRECT_LENGTH); 1352 assertEquals(ImmutableMap.of("cat", 3, "horse", 5), filtered); 1353 1354 filtered.put("chicken", 7); 1355 assertEquals(ImmutableMap.of("cat", 3, "horse", 5, "chicken", 7), filtered); 1356 1357 try { 1358 filtered.putAll(ImmutableMap.of("sheep", 5, "cow", 7)); 1359 fail(); 1360 } catch (IllegalArgumentException expected) {} 1361 assertEquals(ImmutableMap.of("cat", 3, "horse", 5, "chicken", 7), filtered); 1362 } 1363 1364 public void testFilteredEntriesObjectPredicate() { 1365 Map<String, Integer> unfiltered = createUnfiltered(); 1366 unfiltered.put("cat", 3); 1367 unfiltered.put("dog", 2); 1368 unfiltered.put("horse", 5); 1369 Predicate<Object> predicate = Predicates.alwaysFalse(); 1370 Map<String, Integer> filtered 1371 = Maps.filterEntries(unfiltered, predicate); 1372 assertTrue(filtered.isEmpty()); 1373 } 1374 1375 public void testFilteredEntriesWildCardEntryPredicate() { 1376 Map<String, Integer> unfiltered = createUnfiltered(); 1377 unfiltered.put("cat", 3); 1378 unfiltered.put("dog", 2); 1379 unfiltered.put("horse", 5); 1380 Predicate<Entry<?, ?>> predicate = new Predicate<Entry<?, ?>>() { 1381 @Override 1382 public boolean apply(Entry<?, ?> input) { 1383 return "cat".equals(input.getKey()) 1384 || Integer.valueOf(2) == input.getValue(); 1385 } 1386 }; 1387 Map<String, Integer> filtered 1388 = Maps.filterEntries(unfiltered, predicate); 1389 assertEquals(ImmutableMap.of("cat", 3, "dog", 2), filtered); 1390 } 1391 } 1392 1393 public static class FilteredSortedMapTest extends FilteredMapTest { 1394 @Override 1395 SortedMap<String, Integer> createUnfiltered() { 1396 return Maps.newTreeMap(); 1397 } 1398 1399 public void testFilterKeysIdentifiesSortedMap() { 1400 SortedMap<String, Integer> map = createUnfiltered(); 1401 assertTrue(Maps.filterKeys((Map<String, Integer>) map, NOT_LENGTH_3) 1402 instanceof SortedMap); 1403 } 1404 1405 public void testFilterValuesIdentifiesSortedMap() { 1406 SortedMap<String, Integer> map = createUnfiltered(); 1407 assertTrue(Maps.filterValues((Map<String, Integer>) map, EVEN) 1408 instanceof SortedMap); 1409 } 1410 1411 public void testFilterEntriesIdentifiesSortedMap() { 1412 SortedMap<String, Integer> map = createUnfiltered(); 1413 assertTrue(Maps.filterEntries((Map<String, Integer>) map, CORRECT_LENGTH) 1414 instanceof SortedMap); 1415 } 1416 1417 public void testFirstAndLastKeyFilteredMap() { 1418 SortedMap<String, Integer> unfiltered = createUnfiltered(); 1419 unfiltered.put("apple", 2); 1420 unfiltered.put("banana", 6); 1421 unfiltered.put("cat", 3); 1422 unfiltered.put("dog", 5); 1423 1424 SortedMap<String, Integer> filtered = Maps.filterEntries(unfiltered, CORRECT_LENGTH); 1425 assertEquals("banana", filtered.firstKey()); 1426 assertEquals("cat", filtered.lastKey()); 1427 } 1428 1429 public void testHeadSubTailMap_FilteredMap() { 1430 SortedMap<String, Integer> unfiltered = createUnfiltered(); 1431 unfiltered.put("apple", 2); 1432 unfiltered.put("banana", 6); 1433 unfiltered.put("cat", 4); 1434 unfiltered.put("dog", 3); 1435 SortedMap<String, Integer> filtered = Maps.filterEntries(unfiltered, CORRECT_LENGTH); 1436 1437 assertEquals(ImmutableMap.of("banana", 6), filtered.headMap("dog")); 1438 assertEquals(ImmutableMap.of(), filtered.headMap("banana")); 1439 assertEquals(ImmutableMap.of("banana", 6, "dog", 3), filtered.headMap("emu")); 1440 1441 assertEquals(ImmutableMap.of("banana", 6), filtered.subMap("banana", "dog")); 1442 assertEquals(ImmutableMap.of("dog", 3), filtered.subMap("cat", "emu")); 1443 1444 assertEquals(ImmutableMap.of("dog", 3), filtered.tailMap("cat")); 1445 assertEquals(ImmutableMap.of("banana", 6, "dog", 3), filtered.tailMap("banana")); 1446 } 1447 } 1448 1449 public static class FilteredBiMapTest extends FilteredMapTest { 1450 @Override 1451 BiMap<String, Integer> createUnfiltered() { 1452 return HashBiMap.create(); 1453 } 1454 1455 public void testFilterKeysIdentifiesBiMap() { 1456 BiMap<String, Integer> map = createUnfiltered(); 1457 assertTrue(Maps.filterKeys((Map<String, Integer>) map, NOT_LENGTH_3) 1458 instanceof BiMap); 1459 } 1460 1461 public void testFilterValuesIdentifiesBiMap() { 1462 BiMap<String, Integer> map = createUnfiltered(); 1463 assertTrue(Maps.filterValues((Map<String, Integer>) map, EVEN) 1464 instanceof BiMap); 1465 } 1466 1467 public void testFilterEntriesIdentifiesBiMap() { 1468 BiMap<String, Integer> map = createUnfiltered(); 1469 assertTrue(Maps.filterEntries((Map<String, Integer>) map, CORRECT_LENGTH) 1470 instanceof BiMap); 1471 } 1472 } 1473 1474 public void testTransformValues() { 1475 Map<String, Integer> map = ImmutableMap.of("a", 4, "b", 9); 1476 Map<String, Double> transformed = transformValues(map, SQRT_FUNCTION); 1477 1478 assertEquals(ImmutableMap.of("a", 2.0, "b", 3.0), transformed); 1479 } 1480 1481 public void testTransformValuesSecretlySorted() { 1482 Map<String, Integer> map = 1483 sortedNotNavigable(ImmutableSortedMap.of("a", 4, "b", 9)); 1484 Map<String, Double> transformed = transformValues(map, SQRT_FUNCTION); 1485 1486 assertEquals(ImmutableMap.of("a", 2.0, "b", 3.0), transformed); 1487 assertTrue(transformed instanceof SortedMap); 1488 } 1489 1490 public void testTransformEntries() { 1491 Map<String, String> map = ImmutableMap.of("a", "4", "b", "9"); 1492 EntryTransformer<String, String, String> concat = 1493 new EntryTransformer<String, String, String>() { 1494 @Override 1495 public String transformEntry(String key, String value) { 1496 return key + value; 1497 } 1498 }; 1499 Map<String, String> transformed = transformEntries(map, concat); 1500 1501 assertEquals(ImmutableMap.of("a", "a4", "b", "b9"), transformed); 1502 } 1503 1504 public void testTransformEntriesSecretlySorted() { 1505 Map<String, String> map = ImmutableSortedMap.of("a", "4", "b", "9"); 1506 EntryTransformer<String, String, String> concat = 1507 new EntryTransformer<String, String, String>() { 1508 @Override 1509 public String transformEntry(String key, String value) { 1510 return key + value; 1511 } 1512 }; 1513 Map<String, String> transformed = transformEntries(map, concat); 1514 1515 assertEquals(ImmutableMap.of("a", "a4", "b", "b9"), transformed); 1516 assertTrue(transformed instanceof SortedMap); 1517 } 1518 1519 @SuppressWarnings("unused") 1520 public void testTransformEntriesGenerics() { 1521 Map<Object, Object> map1 = ImmutableMap.<Object, Object>of(1, 2); 1522 Map<Object, Number> map2 = ImmutableMap.<Object, Number>of(1, 2); 1523 Map<Object, Integer> map3 = ImmutableMap.<Object, Integer>of(1, 2); 1524 Map<Number, Object> map4 = ImmutableMap.<Number, Object>of(1, 2); 1525 Map<Number, Number> map5 = ImmutableMap.<Number, Number>of(1, 2); 1526 Map<Number, Integer> map6 = ImmutableMap.<Number, Integer>of(1, 2); 1527 Map<Integer, Object> map7 = ImmutableMap.<Integer, Object>of(1, 2); 1528 Map<Integer, Number> map8 = ImmutableMap.<Integer, Number>of(1, 2); 1529 Map<Integer, Integer> map9 = ImmutableMap.<Integer, Integer>of(1, 2); 1530 Map<? extends Number, ? extends Number> map0 = ImmutableMap.of(1, 2); 1531 1532 EntryTransformer<Number, Number, Double> transformer = 1533 new EntryTransformer<Number, Number, Double>() { 1534 @Override 1535 public Double transformEntry(Number key, Number value) { 1536 return key.doubleValue() + value.doubleValue(); 1537 } 1538 }; 1539 1540 Map<Object, Double> objectKeyed; 1541 Map<Number, Double> numberKeyed; 1542 Map<Integer, Double> integerKeyed; 1543 1544 numberKeyed = transformEntries(map5, transformer); 1545 numberKeyed = transformEntries(map6, transformer); 1546 integerKeyed = transformEntries(map8, transformer); 1547 integerKeyed = transformEntries(map9, transformer); 1548 1549 Map<? extends Number, Double> wildcarded = transformEntries(map0, transformer); 1550 1551 // Can't loosen the key type: 1552 // objectKeyed = transformEntries(map5, transformer); 1553 // objectKeyed = transformEntries(map6, transformer); 1554 // objectKeyed = transformEntries(map8, transformer); 1555 // objectKeyed = transformEntries(map9, transformer); 1556 // numberKeyed = transformEntries(map8, transformer); 1557 // numberKeyed = transformEntries(map9, transformer); 1558 1559 // Can't loosen the value type: 1560 // Map<Number, Number> looseValued1 = transformEntries(map5, transformer); 1561 // Map<Number, Number> looseValued2 = transformEntries(map6, transformer); 1562 // Map<Integer, Number> looseValued3 = transformEntries(map8, transformer); 1563 // Map<Integer, Number> looseValued4 = transformEntries(map9, transformer); 1564 1565 // Can't call with too loose a key: 1566 // transformEntries(map1, transformer); 1567 // transformEntries(map2, transformer); 1568 // transformEntries(map3, transformer); 1569 1570 // Can't call with too loose a value: 1571 // transformEntries(map1, transformer); 1572 // transformEntries(map4, transformer); 1573 // transformEntries(map7, transformer); 1574 } 1575 1576 public void testTransformEntriesExample() { 1577 Map<String, Boolean> options = 1578 ImmutableMap.of("verbose", true, "sort", false); 1579 EntryTransformer<String, Boolean, String> flagPrefixer = 1580 new EntryTransformer<String, Boolean, String>() { 1581 @Override 1582 public String transformEntry(String key, Boolean value) { 1583 return value ? key : "no" + key; 1584 } 1585 }; 1586 Map<String, String> transformed = transformEntries(options, flagPrefixer); 1587 assertEquals("{verbose=verbose, sort=nosort}", transformed.toString()); 1588 } 1589 1590 // Logically this would accept a NavigableMap, but that won't work under GWT. 1591 private static <K, V> SortedMap<K, V> sortedNotNavigable( 1592 final SortedMap<K, V> map) { 1593 return new ForwardingSortedMap<K, V>() { 1594 @Override protected SortedMap<K, V> delegate() { 1595 return map; 1596 } 1597 }; 1598 } 1599 1600 public void testSortedMapTransformValues() { 1601 SortedMap<String, Integer> map = 1602 sortedNotNavigable(ImmutableSortedMap.of("a", 4, "b", 9)); 1603 SortedMap<String, Double> transformed = 1604 transformValues(map, SQRT_FUNCTION); 1605 1606 /* 1607 * We'd like to sanity check that we didn't get a NavigableMap out, but we 1608 * can't easily do so while maintaining GWT compatibility. 1609 */ 1610 assertEquals(ImmutableSortedMap.of("a", 2.0, "b", 3.0), transformed); 1611 } 1612 1613 public void testSortedMapTransformEntries() { 1614 SortedMap<String, String> map = 1615 sortedNotNavigable(ImmutableSortedMap.of("a", "4", "b", "9")); 1616 EntryTransformer<String, String, String> concat = 1617 new EntryTransformer<String, String, String>() { 1618 @Override 1619 public String transformEntry(String key, String value) { 1620 return key + value; 1621 } 1622 }; 1623 SortedMap<String, String> transformed = transformEntries(map, concat); 1624 1625 /* 1626 * We'd like to sanity check that we didn't get a NavigableMap out, but we 1627 * can't easily do so while maintaining GWT compatibility. 1628 */ 1629 assertEquals(ImmutableSortedMap.of("a", "a4", "b", "b9"), transformed); 1630 } 1631} 1632