< prev index next >

test/java/util/Map/Defaults.java

Print this page


   1 /*
   2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */


  36 import java.util.Collections;
  37 import java.util.EnumMap;
  38 import java.util.HashMap;
  39 import java.util.Hashtable;
  40 import java.util.HashSet;
  41 import java.util.IdentityHashMap;
  42 import java.util.Iterator;
  43 import java.util.LinkedHashMap;
  44 import java.util.Map;
  45 import java.util.TreeMap;
  46 import java.util.Set;
  47 import java.util.WeakHashMap;
  48 import java.util.concurrent.ConcurrentMap;
  49 import java.util.concurrent.ConcurrentHashMap;
  50 import java.util.concurrent.ConcurrentSkipListMap;
  51 import java.util.concurrent.atomic.AtomicBoolean;
  52 import java.util.function.BiFunction;
  53 import java.util.function.Function;
  54 import java.util.function.Supplier;
  55 

  56 import org.testng.annotations.Test;
  57 import org.testng.annotations.DataProvider;

  58 import static java.util.Objects.requireNonNull;

  59 import static org.testng.Assert.fail;
  60 import static org.testng.Assert.assertEquals;
  61 import static org.testng.Assert.assertTrue;
  62 import static org.testng.Assert.assertFalse;
  63 import static org.testng.Assert.assertNull;
  64 import static org.testng.Assert.assertSame;

  65 
  66 public class Defaults {
  67 
  68     @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull")
  69     public void testGetOrDefaultNulls(String description, Map<IntegerEnum, String> map) {
  70         assertTrue(map.containsKey(null), description + ": null key absent");
  71         assertNull(map.get(null), description + ": value not null");
  72         assertSame(map.get(null), map.getOrDefault(null, EXTRA_VALUE), description + ": values should match");
  73     }
  74 
  75     @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=all values=all")
  76     public void testGetOrDefault(String description, Map<IntegerEnum, String> map) {
  77         assertTrue(map.containsKey(KEYS[1]), "expected key missing");
  78         assertSame(map.get(KEYS[1]), map.getOrDefault(KEYS[1], EXTRA_VALUE), "values should match");
  79         assertFalse(map.containsKey(EXTRA_KEY), "expected absent key");
  80         assertSame(map.getOrDefault(EXTRA_KEY, EXTRA_VALUE), EXTRA_VALUE, "value not returned as default");
  81         assertNull(map.getOrDefault(EXTRA_KEY, null), "null not returned as default");
  82     }
  83 
  84     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")


 142         Set<String> EACH_REPLACE = new HashSet<>(map.size());
 143 
 144         map.replaceAll((k,v) -> {
 145             int idx = (null == k) ? 0 : k.ordinal(); // substitute for index.
 146             assertNull(EACH_KEY[idx]);
 147             EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison.
 148             assertSame(v, map.get(k));
 149             String replacement = v + " replaced";
 150             EACH_REPLACE.add(replacement);
 151             return replacement;
 152         });
 153 
 154         assertEquals(KEYS, EACH_KEY, description);
 155         assertEquals(map.values().size(), EACH_REPLACE.size(), description + EACH_REPLACE);
 156         assertTrue(EACH_REPLACE.containsAll(map.values()), description + " : " + EACH_REPLACE + " != " + map.values());
 157         assertTrue(map.values().containsAll(EACH_REPLACE), description + " : " + EACH_REPLACE + " != " + map.values());
 158     }
 159 
 160     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
 161     public static void testReplaceAllNoNullReplacement(String description, Map<IntegerEnum, String> map) {
 162         assertThrows(
 163             () -> { map.replaceAll(null); },
 164             NullPointerException.class,
 165             description);
 166         assertThrows(
 167             () -> { map.replaceAll((k,v) -> null); },
 168             NullPointerException.class,
 169             description + " should not allow replacement with null value");
 170     }
 171 
 172     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 173     public static void testRemoveNulls(String description, Map<IntegerEnum, String> map) {
 174         assertTrue(map.containsKey(null), "null key absent");
 175         assertNull(map.get(null), "value not null");
 176         assertFalse(map.remove(null, EXTRA_VALUE), description);
 177         assertTrue(map.containsKey(null));
 178         assertNull(map.get(null));
 179         assertTrue(map.remove(null, null));
 180         assertFalse(map.containsKey(null));
 181         assertNull(map.get(null));
 182         assertFalse(map.remove(null, null));
 183     }
 184 
 185     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 186     public static void testRemove(String description, Map<IntegerEnum, String> map) {
 187         assertTrue(map.containsKey(KEYS[1]));
 188         Object expected = map.get(KEYS[1]);
 189         assertTrue(null == expected || expected == VALUES[1]);


 192         assertTrue(map.remove(KEYS[1], expected));
 193         assertNull(map.get(KEYS[1]));
 194         assertFalse(map.remove(KEYS[1], expected));
 195 
 196         assertFalse(map.containsKey(EXTRA_KEY));
 197         assertFalse(map.remove(EXTRA_KEY, EXTRA_VALUE));
 198     }
 199 
 200     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 201     public void testReplaceKVNulls(String description, Map<IntegerEnum, String> map) {
 202         assertTrue(map.containsKey(null), "null key absent");
 203         assertNull(map.get(null), "value not null");
 204         assertSame(map.replace(null, EXTRA_VALUE), null);
 205         assertSame(map.get(null), EXTRA_VALUE);
 206     }
 207 
 208     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
 209     public void testReplaceKVNoNulls(String description, Map<IntegerEnum, String> map) {
 210         assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
 211         assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
 212         assertThrows( () -> {map.replace(FIRST_KEY, null);}, NullPointerException.class, description + ": should throw NPE");
 213         assertSame(map.replace(FIRST_KEY, EXTRA_VALUE), FIRST_VALUE, description + ": replaced wrong value");
 214         assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
 215     }
 216 
 217     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 218     public void testReplaceKV(String description, Map<IntegerEnum, String> map) {
 219         assertTrue(map.containsKey(KEYS[1]));
 220         Object expected = map.get(KEYS[1]);
 221         assertTrue(null == expected || expected == VALUES[1]);
 222         assertSame(map.replace(KEYS[1], EXTRA_VALUE), expected);
 223         assertSame(map.get(KEYS[1]), EXTRA_VALUE);
 224 
 225         assertFalse(map.containsKey(EXTRA_KEY));
 226         assertNull(map.replace(EXTRA_KEY, EXTRA_VALUE));
 227         assertFalse(map.containsKey(EXTRA_KEY));
 228         assertNull(map.get(EXTRA_KEY));
 229         assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
 230         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 231         assertSame(map.replace(EXTRA_KEY, (String)expected), EXTRA_VALUE);
 232         assertSame(map.get(EXTRA_KEY), expected);
 233     }
 234 
 235     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 236     public void testReplaceKVVNulls(String description, Map<IntegerEnum, String> map) {
 237         assertTrue(map.containsKey(null), "null key absent");
 238         assertNull(map.get(null), "value not null");
 239         assertFalse(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
 240         assertNull(map.get(null));
 241         assertTrue(map.replace(null, null, EXTRA_VALUE));
 242         assertSame(map.get(null), EXTRA_VALUE);
 243         assertTrue(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
 244         assertSame(map.get(null), EXTRA_VALUE);
 245     }
 246 
 247     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
 248     public void testReplaceKVVNoNulls(String description, Map<IntegerEnum, String> map) {
 249         assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
 250         assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
 251         assertThrows( () -> {map.replace(FIRST_KEY, FIRST_VALUE, null);}, NullPointerException.class, description + ": should throw NPE");
 252         assertThrows( () -> {if (!map.replace(FIRST_KEY, null, EXTRA_VALUE)) throw new NullPointerException("default returns false rather than throwing");}, NullPointerException.class,  description + ": should throw NPE");





 253         assertTrue(map.replace(FIRST_KEY, FIRST_VALUE, EXTRA_VALUE), description + ": replaced wrong value");
 254         assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
 255     }
 256 
 257     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 258     public void testReplaceKVV(String description, Map<IntegerEnum, String> map) {
 259         assertTrue(map.containsKey(KEYS[1]));
 260         Object expected = map.get(KEYS[1]);
 261         assertTrue(null == expected || expected == VALUES[1]);
 262         assertFalse(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
 263         assertSame(map.get(KEYS[1]), expected);
 264         assertTrue(map.replace(KEYS[1], (String)expected, EXTRA_VALUE));
 265         assertSame(map.get(KEYS[1]), EXTRA_VALUE);
 266         assertTrue(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
 267         assertSame(map.get(KEYS[1]), EXTRA_VALUE);
 268 
 269         assertFalse(map.containsKey(EXTRA_KEY));
 270         assertFalse(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
 271         assertFalse(map.containsKey(EXTRA_KEY));
 272         assertNull(map.get(EXTRA_KEY));


 302     public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) {
 303         // 1 -> 1
 304         assertTrue(map.containsKey(KEYS[1]));
 305         Object expected = map.get(KEYS[1]);
 306         assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected));
 307         expected = (null == expected) ? EXTRA_VALUE : expected;
 308         assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description);
 309         assertSame(map.get(KEYS[1]), expected, description);
 310 
 311         // EXTRA_KEY -> <absent>
 312         assertFalse(map.containsKey(EXTRA_KEY));
 313         assertNull(map.computeIfAbsent(EXTRA_KEY, (k) -> null));
 314         assertFalse(map.containsKey(EXTRA_KEY));
 315         assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE);
 316         // EXTRA_KEY -> EXTRA_VALUE
 317         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 318     }
 319 
 320     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 321     public void testComputeIfAbsentNullFunction(String description, Map<IntegerEnum, String> map) {
 322         assertThrows( () -> { map.computeIfAbsent(KEYS[1], null);},
 323                 NullPointerException.class,
 324                 "Should throw NPE");
 325     }
 326 
 327     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 328     public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) {
 329         assertTrue(map.containsKey(null), description + ": null key absent");
 330         assertNull(map.get(null), description + ": value not null");
 331         assertSame(map.computeIfPresent(null, (k, v) -> {
 332             fail(description + ": null value is not deemed present");
 333             return EXTRA_VALUE;
 334         }), null, description);
 335         assertTrue(map.containsKey(null));
 336         assertNull(map.get(null), description);
 337         assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping");
 338         assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value");
 339         assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
 340             fail(description + ": null value is not deemed present");
 341             return EXTRA_VALUE;
 342         }), null, description);
 343         assertNull(map.get(EXTRA_KEY), description + ": null mapping gone");
 344     }


 349         Object value = map.get(KEYS[1]);
 350         assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
 351         Object expected = (null == value) ? null : EXTRA_VALUE;
 352         assertSame(map.computeIfPresent(KEYS[1], (k, v) -> {
 353             assertSame(v, value);
 354             return EXTRA_VALUE;
 355         }), expected, description);
 356         assertSame(map.get(KEYS[1]), expected, description);
 357 
 358         assertFalse(map.containsKey(EXTRA_KEY));
 359         assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
 360             fail();
 361             return EXTRA_VALUE;
 362         }), null);
 363         assertFalse(map.containsKey(EXTRA_KEY));
 364         assertSame(map.get(EXTRA_KEY), null);
 365     }
 366 
 367     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 368     public void testComputeIfPresentNullFunction(String description, Map<IntegerEnum, String> map) {
 369         assertThrows( () -> { map.computeIfPresent(KEYS[1], null);},
 370                 NullPointerException.class,
 371                 "Should throw NPE");
 372     }
 373 
 374      @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 375     public void testComputeNulls(String description, Map<IntegerEnum, String> map) {
 376         assertTrue(map.containsKey(null), "null key absent");
 377         assertNull(map.get(null), "value not null");
 378         assertSame(map.compute(null, (k, v) -> {
 379             assertNull(k);
 380             assertNull(v);
 381             return null;
 382         }), null, description);
 383         assertFalse(map.containsKey(null), description + ": null key present.");
 384         assertSame(map.compute(null, (k, v) -> {
 385             assertSame(k, null);
 386             assertNull(v);
 387             return EXTRA_VALUE;
 388         }), EXTRA_VALUE, description);
 389         assertTrue(map.containsKey(null));
 390         assertSame(map.get(null), EXTRA_VALUE, description);
 391         assertSame(map.remove(null), EXTRA_VALUE, description + ": removed value not expected");


 442             return EXTRA_VALUE;
 443         }), EXTRA_VALUE, description);
 444         assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
 445         assertNull(map.compute(KEYS[1], (k, v) -> {
 446             assertSame(v, EXTRA_VALUE);
 447             return null;
 448         }), description);
 449         assertFalse(map.containsKey(KEYS[1]));
 450 
 451         assertFalse(map.containsKey(EXTRA_KEY));
 452         assertSame(map.compute(EXTRA_KEY, (k, v) -> {
 453             assertNull(v);
 454             return EXTRA_VALUE;
 455         }), EXTRA_VALUE);
 456         assertTrue(map.containsKey(EXTRA_KEY));
 457         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 458     }
 459 
 460     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 461     public void testComputeNullFunction(String description, Map<IntegerEnum, String> map) {
 462         assertThrows( () -> { map.compute(KEYS[1], null);},
 463                 NullPointerException.class,
 464                 "Should throw NPE");
 465     }
 466 
 467     @Test(dataProvider = "MergeCases")
 468     private void testMerge(String description, Map<IntegerEnum, String> map, Merging.Value oldValue, Merging.Value newValue, Merging.Merger merger, Merging.Value put, Merging.Value result) {
 469             // add and check initial conditions.
 470             switch (oldValue) {
 471                 case ABSENT :
 472                     map.remove(EXTRA_KEY);
 473                     assertFalse(map.containsKey(EXTRA_KEY), "key not absent");
 474                     break;
 475                 case NULL :
 476                     map.put(EXTRA_KEY, null);
 477                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 478                     assertNull(map.get(EXTRA_KEY), "wrong value");
 479                     break;
 480                 case OLDVALUE :
 481                     map.put(EXTRA_KEY, VALUES[1]);
 482                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 483                     assertSame(map.get(EXTRA_KEY), VALUES[1], "wrong value");
 484                     break;


 514                     break;
 515                 case NULL :
 516                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 517                     assertNull(map.get(EXTRA_KEY), "wrong value");
 518                     break;
 519                 case NEWVALUE :
 520                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 521                     assertSame(map.get(EXTRA_KEY), VALUES[2], "wrong value");
 522                     break;
 523                 case RESULT :
 524                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 525                     assertSame(map.get(EXTRA_KEY), VALUES[3], "wrong value");
 526                     break;
 527                 default:
 528                     fail("unexpected new value");
 529             }
 530     }
 531 
 532     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 533     public void testMergeNullMerger(String description, Map<IntegerEnum, String> map) {
 534         assertThrows( () -> { map.merge(KEYS[1], VALUES[1], null);},
 535                 NullPointerException.class,
 536                 "Should throw NPE");
 537     }
 538 
 539     /** A function that flipflops between running two other functions. */
 540     static <T,U,V> BiFunction<T,U,V> twoStep(AtomicBoolean b,
 541                                              BiFunction<T,U,V> first,
 542                                              BiFunction<T,U,V> second) {
 543         return (t, u) -> {
 544             boolean bb = b.get();
 545             try {
 546                 return (b.get() ? first : second).apply(t, u);
 547             } finally {
 548                 b.set(!bb);
 549             }};
 550     }
 551 
 552     /**
 553      * Simulates races by modifying the map within the mapping function.
 554      */
 555     @Test
 556     public void testConcurrentMap_computeIfAbsent_racy() {


 956     }
 957 
 958     static Collection<Object[]> makeMergeTestCases() {
 959         Collection<Object[]> cases = new ArrayList<>();
 960 
 961         for (Object[] mapParams : makeAllRWMaps() ) {
 962             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.ABSENT, Merging.Value.NEWVALUE, Merging.Merger.UNUSED, Merging.Value.NEWVALUE, Merging.Value.NEWVALUE });
 963         }
 964 
 965         for (Object[] mapParams : makeAllRWMaps() ) {
 966             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.NULL, Merging.Value.ABSENT, Merging.Value.NULL });
 967         }
 968 
 969         for (Object[] mapParams : makeAllRWMaps() ) {
 970             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.RESULT, Merging.Value.RESULT, Merging.Value.RESULT });
 971         }
 972 
 973         return cases;
 974     }
 975 
 976     public interface Thrower<T extends Throwable> {
 977 
 978         public void run() throws T;
 979     }
 980 
 981     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable) {
 982         assertThrows(thrower, throwable, null);
 983     }
 984 
 985     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) {
 986         Throwable thrown;
 987         try {
 988             thrower.run();
 989             thrown = null;
 990         } catch (Throwable caught) {
 991             thrown = caught;
 992         }
 993 
 994         assertInstance(thrown, throwable,
 995             ((null != message) ? message : "") +
 996             " Failed to throw " + throwable.getCanonicalName());
 997     }
 998 
 999     public static <T extends Throwable> void assertThrows(Class<T> throwable, String message, Thrower<T>... throwers) {
1000         for (Thrower<T> thrower : throwers) {
1001             assertThrows(thrower, throwable, message);
1002         }
1003     }
1004 
1005     public static void assertInstance(Object actual, Class<?> expected) {
1006         assertInstance(expected.isInstance(actual), null);
1007     }
1008 
1009     public static void assertInstance(Object actual, Class<?> expected, String message) {
1010         assertTrue(expected.isInstance(actual), message);
1011     }
1012 
1013     /**
1014      * A simple mutable map implementation that provides only default
1015      * implementations of all methods. ie. none of the Map interface default
1016      * methods have overridden implementations.
1017      *
1018      * @param <K> Type of keys
1019      * @param <V> Type of values
1020      */
1021     public static class ExtendsAbstractMap<M extends Map<K,V>, K, V> extends AbstractMap<K,V> {
1022 
1023         protected final M map;
1024 
1025         public ExtendsAbstractMap() { this( (M) new HashMap<K,V>()); }
1026 
1027         protected ExtendsAbstractMap(M map) { this.map = map; }
1028 
1029         @Override public Set<Map.Entry<K,V>> entrySet() {
1030             return new AbstractSet<Map.Entry<K,V>>() {


   1 /*
   2  * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */


  36 import java.util.Collections;
  37 import java.util.EnumMap;
  38 import java.util.HashMap;
  39 import java.util.Hashtable;
  40 import java.util.HashSet;
  41 import java.util.IdentityHashMap;
  42 import java.util.Iterator;
  43 import java.util.LinkedHashMap;
  44 import java.util.Map;
  45 import java.util.TreeMap;
  46 import java.util.Set;
  47 import java.util.WeakHashMap;
  48 import java.util.concurrent.ConcurrentMap;
  49 import java.util.concurrent.ConcurrentHashMap;
  50 import java.util.concurrent.ConcurrentSkipListMap;
  51 import java.util.concurrent.atomic.AtomicBoolean;
  52 import java.util.function.BiFunction;
  53 import java.util.function.Function;
  54 import java.util.function.Supplier;
  55 
  56 import org.testng.Assert.ThrowingRunnable;
  57 import org.testng.annotations.Test;
  58 import org.testng.annotations.DataProvider;
  59 
  60 import static java.util.Objects.requireNonNull;
  61 
  62 import static org.testng.Assert.fail;
  63 import static org.testng.Assert.assertEquals;
  64 import static org.testng.Assert.assertTrue;
  65 import static org.testng.Assert.assertFalse;
  66 import static org.testng.Assert.assertNull;
  67 import static org.testng.Assert.assertSame;
  68 import static org.testng.Assert.assertThrows;
  69 
  70 public class Defaults {
  71 
  72     @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=withNull values=withNull")
  73     public void testGetOrDefaultNulls(String description, Map<IntegerEnum, String> map) {
  74         assertTrue(map.containsKey(null), description + ": null key absent");
  75         assertNull(map.get(null), description + ": value not null");
  76         assertSame(map.get(null), map.getOrDefault(null, EXTRA_VALUE), description + ": values should match");
  77     }
  78 
  79     @Test(dataProvider = "Map<IntegerEnum,String> rw=all keys=all values=all")
  80     public void testGetOrDefault(String description, Map<IntegerEnum, String> map) {
  81         assertTrue(map.containsKey(KEYS[1]), "expected key missing");
  82         assertSame(map.get(KEYS[1]), map.getOrDefault(KEYS[1], EXTRA_VALUE), "values should match");
  83         assertFalse(map.containsKey(EXTRA_KEY), "expected absent key");
  84         assertSame(map.getOrDefault(EXTRA_KEY, EXTRA_VALUE), EXTRA_VALUE, "value not returned as default");
  85         assertNull(map.getOrDefault(EXTRA_KEY, null), "null not returned as default");
  86     }
  87 
  88     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")


 146         Set<String> EACH_REPLACE = new HashSet<>(map.size());
 147 
 148         map.replaceAll((k,v) -> {
 149             int idx = (null == k) ? 0 : k.ordinal(); // substitute for index.
 150             assertNull(EACH_KEY[idx]);
 151             EACH_KEY[idx] = (idx == 0) ? KEYS[0] : k; // substitute for comparison.
 152             assertSame(v, map.get(k));
 153             String replacement = v + " replaced";
 154             EACH_REPLACE.add(replacement);
 155             return replacement;
 156         });
 157 
 158         assertEquals(KEYS, EACH_KEY, description);
 159         assertEquals(map.values().size(), EACH_REPLACE.size(), description + EACH_REPLACE);
 160         assertTrue(EACH_REPLACE.containsAll(map.values()), description + " : " + EACH_REPLACE + " != " + map.values());
 161         assertTrue(map.values().containsAll(EACH_REPLACE), description + " : " + EACH_REPLACE + " != " + map.values());
 162     }
 163 
 164     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
 165     public static void testReplaceAllNoNullReplacement(String description, Map<IntegerEnum, String> map) {
 166         assertThrowsNPE(() -> map.replaceAll(null));
 167         assertThrowsNPE(() -> { map.replaceAll((k,v) -> null); });






 168     }
 169 
 170     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 171     public static void testRemoveNulls(String description, Map<IntegerEnum, String> map) {
 172         assertTrue(map.containsKey(null), "null key absent");
 173         assertNull(map.get(null), "value not null");
 174         assertFalse(map.remove(null, EXTRA_VALUE), description);
 175         assertTrue(map.containsKey(null));
 176         assertNull(map.get(null));
 177         assertTrue(map.remove(null, null));
 178         assertFalse(map.containsKey(null));
 179         assertNull(map.get(null));
 180         assertFalse(map.remove(null, null));
 181     }
 182 
 183     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 184     public static void testRemove(String description, Map<IntegerEnum, String> map) {
 185         assertTrue(map.containsKey(KEYS[1]));
 186         Object expected = map.get(KEYS[1]);
 187         assertTrue(null == expected || expected == VALUES[1]);


 190         assertTrue(map.remove(KEYS[1], expected));
 191         assertNull(map.get(KEYS[1]));
 192         assertFalse(map.remove(KEYS[1], expected));
 193 
 194         assertFalse(map.containsKey(EXTRA_KEY));
 195         assertFalse(map.remove(EXTRA_KEY, EXTRA_VALUE));
 196     }
 197 
 198     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 199     public void testReplaceKVNulls(String description, Map<IntegerEnum, String> map) {
 200         assertTrue(map.containsKey(null), "null key absent");
 201         assertNull(map.get(null), "value not null");
 202         assertSame(map.replace(null, EXTRA_VALUE), null);
 203         assertSame(map.get(null), EXTRA_VALUE);
 204     }
 205 
 206     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
 207     public void testReplaceKVNoNulls(String description, Map<IntegerEnum, String> map) {
 208         assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
 209         assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
 210         assertThrowsNPE(() -> map.replace(FIRST_KEY, null));
 211         assertSame(map.replace(FIRST_KEY, EXTRA_VALUE), FIRST_VALUE, description + ": replaced wrong value");
 212         assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
 213     }
 214 
 215     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 216     public void testReplaceKV(String description, Map<IntegerEnum, String> map) {
 217         assertTrue(map.containsKey(KEYS[1]));
 218         Object expected = map.get(KEYS[1]);
 219         assertTrue(null == expected || expected == VALUES[1]);
 220         assertSame(map.replace(KEYS[1], EXTRA_VALUE), expected);
 221         assertSame(map.get(KEYS[1]), EXTRA_VALUE);
 222 
 223         assertFalse(map.containsKey(EXTRA_KEY));
 224         assertNull(map.replace(EXTRA_KEY, EXTRA_VALUE));
 225         assertFalse(map.containsKey(EXTRA_KEY));
 226         assertNull(map.get(EXTRA_KEY));
 227         assertNull(map.put(EXTRA_KEY, EXTRA_VALUE));
 228         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 229         assertSame(map.replace(EXTRA_KEY, (String)expected), EXTRA_VALUE);
 230         assertSame(map.get(EXTRA_KEY), expected);
 231     }
 232 
 233     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 234     public void testReplaceKVVNulls(String description, Map<IntegerEnum, String> map) {
 235         assertTrue(map.containsKey(null), "null key absent");
 236         assertNull(map.get(null), "value not null");
 237         assertFalse(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
 238         assertNull(map.get(null));
 239         assertTrue(map.replace(null, null, EXTRA_VALUE));
 240         assertSame(map.get(null), EXTRA_VALUE);
 241         assertTrue(map.replace(null, EXTRA_VALUE, EXTRA_VALUE));
 242         assertSame(map.get(null), EXTRA_VALUE);
 243     }
 244 
 245     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
 246     public void testReplaceKVVNoNulls(String description, Map<IntegerEnum, String> map) {
 247         assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
 248         assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
 249         assertThrowsNPE(() -> map.replace(FIRST_KEY, FIRST_VALUE, null));
 250         assertThrowsNPE(
 251                 () -> {
 252                     if (!map.replace(FIRST_KEY, null, EXTRA_VALUE)) {
 253                         throw new NullPointerException("default returns false rather than throwing");
 254                     }
 255                 });
 256         assertTrue(map.replace(FIRST_KEY, FIRST_VALUE, EXTRA_VALUE), description + ": replaced wrong value");
 257         assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
 258     }
 259 
 260     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 261     public void testReplaceKVV(String description, Map<IntegerEnum, String> map) {
 262         assertTrue(map.containsKey(KEYS[1]));
 263         Object expected = map.get(KEYS[1]);
 264         assertTrue(null == expected || expected == VALUES[1]);
 265         assertFalse(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
 266         assertSame(map.get(KEYS[1]), expected);
 267         assertTrue(map.replace(KEYS[1], (String)expected, EXTRA_VALUE));
 268         assertSame(map.get(KEYS[1]), EXTRA_VALUE);
 269         assertTrue(map.replace(KEYS[1], EXTRA_VALUE, EXTRA_VALUE));
 270         assertSame(map.get(KEYS[1]), EXTRA_VALUE);
 271 
 272         assertFalse(map.containsKey(EXTRA_KEY));
 273         assertFalse(map.replace(EXTRA_KEY, EXTRA_VALUE, EXTRA_VALUE));
 274         assertFalse(map.containsKey(EXTRA_KEY));
 275         assertNull(map.get(EXTRA_KEY));


 305     public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) {
 306         // 1 -> 1
 307         assertTrue(map.containsKey(KEYS[1]));
 308         Object expected = map.get(KEYS[1]);
 309         assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected));
 310         expected = (null == expected) ? EXTRA_VALUE : expected;
 311         assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description);
 312         assertSame(map.get(KEYS[1]), expected, description);
 313 
 314         // EXTRA_KEY -> <absent>
 315         assertFalse(map.containsKey(EXTRA_KEY));
 316         assertNull(map.computeIfAbsent(EXTRA_KEY, (k) -> null));
 317         assertFalse(map.containsKey(EXTRA_KEY));
 318         assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE);
 319         // EXTRA_KEY -> EXTRA_VALUE
 320         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 321     }
 322 
 323     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 324     public void testComputeIfAbsentNullFunction(String description, Map<IntegerEnum, String> map) {
 325         assertThrowsNPE(() -> map.computeIfAbsent(KEYS[1], null));


 326     }
 327 
 328     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 329     public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) {
 330         assertTrue(map.containsKey(null), description + ": null key absent");
 331         assertNull(map.get(null), description + ": value not null");
 332         assertSame(map.computeIfPresent(null, (k, v) -> {
 333             fail(description + ": null value is not deemed present");
 334             return EXTRA_VALUE;
 335         }), null, description);
 336         assertTrue(map.containsKey(null));
 337         assertNull(map.get(null), description);
 338         assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping");
 339         assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value");
 340         assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
 341             fail(description + ": null value is not deemed present");
 342             return EXTRA_VALUE;
 343         }), null, description);
 344         assertNull(map.get(EXTRA_KEY), description + ": null mapping gone");
 345     }


 350         Object value = map.get(KEYS[1]);
 351         assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
 352         Object expected = (null == value) ? null : EXTRA_VALUE;
 353         assertSame(map.computeIfPresent(KEYS[1], (k, v) -> {
 354             assertSame(v, value);
 355             return EXTRA_VALUE;
 356         }), expected, description);
 357         assertSame(map.get(KEYS[1]), expected, description);
 358 
 359         assertFalse(map.containsKey(EXTRA_KEY));
 360         assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
 361             fail();
 362             return EXTRA_VALUE;
 363         }), null);
 364         assertFalse(map.containsKey(EXTRA_KEY));
 365         assertSame(map.get(EXTRA_KEY), null);
 366     }
 367 
 368     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 369     public void testComputeIfPresentNullFunction(String description, Map<IntegerEnum, String> map) {
 370         assertThrowsNPE(() -> map.computeIfPresent(KEYS[1], null));


 371     }
 372 
 373      @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 374     public void testComputeNulls(String description, Map<IntegerEnum, String> map) {
 375         assertTrue(map.containsKey(null), "null key absent");
 376         assertNull(map.get(null), "value not null");
 377         assertSame(map.compute(null, (k, v) -> {
 378             assertNull(k);
 379             assertNull(v);
 380             return null;
 381         }), null, description);
 382         assertFalse(map.containsKey(null), description + ": null key present.");
 383         assertSame(map.compute(null, (k, v) -> {
 384             assertSame(k, null);
 385             assertNull(v);
 386             return EXTRA_VALUE;
 387         }), EXTRA_VALUE, description);
 388         assertTrue(map.containsKey(null));
 389         assertSame(map.get(null), EXTRA_VALUE, description);
 390         assertSame(map.remove(null), EXTRA_VALUE, description + ": removed value not expected");


 441             return EXTRA_VALUE;
 442         }), EXTRA_VALUE, description);
 443         assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
 444         assertNull(map.compute(KEYS[1], (k, v) -> {
 445             assertSame(v, EXTRA_VALUE);
 446             return null;
 447         }), description);
 448         assertFalse(map.containsKey(KEYS[1]));
 449 
 450         assertFalse(map.containsKey(EXTRA_KEY));
 451         assertSame(map.compute(EXTRA_KEY, (k, v) -> {
 452             assertNull(v);
 453             return EXTRA_VALUE;
 454         }), EXTRA_VALUE);
 455         assertTrue(map.containsKey(EXTRA_KEY));
 456         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 457     }
 458 
 459     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 460     public void testComputeNullFunction(String description, Map<IntegerEnum, String> map) {
 461         assertThrowsNPE(() -> map.compute(KEYS[1], null));


 462     }
 463 
 464     @Test(dataProvider = "MergeCases")
 465     private void testMerge(String description, Map<IntegerEnum, String> map, Merging.Value oldValue, Merging.Value newValue, Merging.Merger merger, Merging.Value put, Merging.Value result) {
 466             // add and check initial conditions.
 467             switch (oldValue) {
 468                 case ABSENT :
 469                     map.remove(EXTRA_KEY);
 470                     assertFalse(map.containsKey(EXTRA_KEY), "key not absent");
 471                     break;
 472                 case NULL :
 473                     map.put(EXTRA_KEY, null);
 474                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 475                     assertNull(map.get(EXTRA_KEY), "wrong value");
 476                     break;
 477                 case OLDVALUE :
 478                     map.put(EXTRA_KEY, VALUES[1]);
 479                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 480                     assertSame(map.get(EXTRA_KEY), VALUES[1], "wrong value");
 481                     break;


 511                     break;
 512                 case NULL :
 513                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 514                     assertNull(map.get(EXTRA_KEY), "wrong value");
 515                     break;
 516                 case NEWVALUE :
 517                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 518                     assertSame(map.get(EXTRA_KEY), VALUES[2], "wrong value");
 519                     break;
 520                 case RESULT :
 521                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 522                     assertSame(map.get(EXTRA_KEY), VALUES[3], "wrong value");
 523                     break;
 524                 default:
 525                     fail("unexpected new value");
 526             }
 527     }
 528 
 529     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 530     public void testMergeNullMerger(String description, Map<IntegerEnum, String> map) {
 531         assertThrowsNPE(() -> map.merge(KEYS[1], VALUES[1], null));


 532     }
 533 
 534     /** A function that flipflops between running two other functions. */
 535     static <T,U,V> BiFunction<T,U,V> twoStep(AtomicBoolean b,
 536                                              BiFunction<T,U,V> first,
 537                                              BiFunction<T,U,V> second) {
 538         return (t, u) -> {
 539             boolean bb = b.get();
 540             try {
 541                 return (b.get() ? first : second).apply(t, u);
 542             } finally {
 543                 b.set(!bb);
 544             }};
 545     }
 546 
 547     /**
 548      * Simulates races by modifying the map within the mapping function.
 549      */
 550     @Test
 551     public void testConcurrentMap_computeIfAbsent_racy() {


 951     }
 952 
 953     static Collection<Object[]> makeMergeTestCases() {
 954         Collection<Object[]> cases = new ArrayList<>();
 955 
 956         for (Object[] mapParams : makeAllRWMaps() ) {
 957             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.ABSENT, Merging.Value.NEWVALUE, Merging.Merger.UNUSED, Merging.Value.NEWVALUE, Merging.Value.NEWVALUE });
 958         }
 959 
 960         for (Object[] mapParams : makeAllRWMaps() ) {
 961             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.NULL, Merging.Value.ABSENT, Merging.Value.NULL });
 962         }
 963 
 964         for (Object[] mapParams : makeAllRWMaps() ) {
 965             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.RESULT, Merging.Value.RESULT, Merging.Value.RESULT });
 966         }
 967 
 968         return cases;
 969     }
 970 
 971     public static void assertThrowsNPE(ThrowingRunnable r) {
 972         assertThrows(NullPointerException.class, r);

































 973     }
 974     
 975     /**
 976      * A simple mutable map implementation that provides only default
 977      * implementations of all methods. ie. none of the Map interface default
 978      * methods have overridden implementations.
 979      *
 980      * @param <K> Type of keys
 981      * @param <V> Type of values
 982      */
 983     public static class ExtendsAbstractMap<M extends Map<K,V>, K, V> extends AbstractMap<K,V> {
 984 
 985         protected final M map;
 986 
 987         public ExtendsAbstractMap() { this( (M) new HashMap<K,V>()); }
 988 
 989         protected ExtendsAbstractMap(M map) { this.map = map; }
 990 
 991         @Override public Set<Map.Entry<K,V>> entrySet() {
 992             return new AbstractSet<Map.Entry<K,V>>() {


< prev index next >