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