test/java/util/Map/Defaults.java

Print this page
rev 8192 : 8024688: j.u.Map.merge doesn't work as specified if contains key:null pair
Reviewed-by: duke


  24 /*
  25  * @test
  26  * @bug 8010122 8004518 8024331
  27  * @summary Test Map default methods
  28  * @author Mike Duigou
  29  * @run testng Defaults
  30  */
  31 import java.util.AbstractMap;
  32 import java.util.AbstractSet;
  33 import java.util.ArrayList;
  34 import java.util.Arrays;
  35 import java.util.Collection;
  36 import java.util.Collections;
  37 import java.util.EnumMap;
  38 import java.util.HashMap;
  39 import java.util.HashSet;
  40 import java.util.Hashtable;
  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.function.BiFunction;
  52 import java.util.function.Supplier;
  53 
  54 import org.testng.annotations.Test;
  55 import org.testng.annotations.DataProvider;
  56 import static org.testng.Assert.fail;
  57 import static org.testng.Assert.assertEquals;
  58 import static org.testng.Assert.assertTrue;
  59 import static org.testng.Assert.assertFalse;
  60 import static org.testng.Assert.assertNull;
  61 import static org.testng.Assert.assertSame;
  62 
  63 public class Defaults {


 271         assertTrue(map.containsKey(null), "null key absent");
 272         assertNull(map.get(null), "value not null");
 273         assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, description);
 274         assertSame(map.get(null), EXTRA_VALUE, description);
 275     }
 276 
 277     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 278     public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) {
 279         assertTrue(map.containsKey(KEYS[1]));
 280         Object expected = map.get(KEYS[1]);
 281         assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected));
 282         expected = (null == expected) ? EXTRA_VALUE : expected;
 283         assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description);
 284         assertSame(map.get(KEYS[1]), expected, description);
 285 
 286         assertFalse(map.containsKey(EXTRA_KEY));
 287         assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE);
 288         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 289     }
 290 
 291     @Test(expectedExceptions = {NullPointerException.class})
 292     public void testComputeIfAbsentNPEHashMap() {
 293         Object value = new HashMap().computeIfAbsent(KEYS[1], null);
 294     }
 295 
 296     @Test(expectedExceptions = {NullPointerException.class})
 297     public void testComputeIfAbsentNPEHashtable() {
 298         Object value = new Hashtable().computeIfAbsent(KEYS[1], null);
 299     }
 300 
 301     @Test(expectedExceptions = {NullPointerException.class})
 302     public void testComputeIfAbsentNPETreeMap() {
 303         Object value = new TreeMap().computeIfAbsent(KEYS[1], null);
 304     }
 305 
 306     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 307     public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) {
 308         assertTrue(map.containsKey(null), description + ": null key absent");
 309         assertNull(map.get(null), description + ": value not null");
 310         assertSame(map.computeIfPresent(null, (k, v) -> {
 311             fail(description + ": null value is not deemed present");
 312             return EXTRA_VALUE;
 313         }), null, description);
 314         assertTrue(map.containsKey(null));
 315         assertNull(map.get(null), description);
 316         assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping");
 317         assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value");
 318         assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
 319             fail(description + ": null value is not deemed present");
 320             return EXTRA_VALUE;
 321         }), null, description);
 322         assertNull(map.get(EXTRA_KEY), description + ": null mapping gone");
 323     }


 326     public void testComputeIfPresent(String description, Map<IntegerEnum, String> map) {
 327         assertTrue(map.containsKey(KEYS[1]));
 328         Object value = map.get(KEYS[1]);
 329         assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
 330         Object expected = (null == value) ? null : EXTRA_VALUE;
 331         assertSame(map.computeIfPresent(KEYS[1], (k, v) -> {
 332             assertSame(v, value);
 333             return EXTRA_VALUE;
 334         }), expected, description);
 335         assertSame(map.get(KEYS[1]), expected, description);
 336 
 337         assertFalse(map.containsKey(EXTRA_KEY));
 338         assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
 339             fail();
 340             return EXTRA_VALUE;
 341         }), null);
 342         assertFalse(map.containsKey(EXTRA_KEY));
 343         assertSame(map.get(EXTRA_KEY), null);
 344     }
 345 
 346     @Test(expectedExceptions = {NullPointerException.class})
 347     public void testComputeIfPresentNPEHashMap() {
 348         Object value = new HashMap().computeIfPresent(KEYS[1], null);
 349     }
 350 
 351     @Test(expectedExceptions = {NullPointerException.class})
 352     public void testComputeIfPresentNPEHashtable() {
 353         Object value = new Hashtable().computeIfPresent(KEYS[1], null);
 354     }
 355 
 356     @Test(expectedExceptions = {NullPointerException.class})
 357     public void testComputeIfPresentNPETreeMap() {
 358         Object value = new TreeMap().computeIfPresent(KEYS[1], null);
 359     }
 360 
 361     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 362     public void testComputeNulls(String description, Map<IntegerEnum, String> map) {
 363         assertTrue(map.containsKey(null), "null key absent");
 364         assertNull(map.get(null), "value not null");
 365         assertSame(map.compute(null, (k, v) -> {
 366             assertNull(k);
 367             assertNull(v);
 368             return null;
 369         }), null, description);
 370         assertFalse(map.containsKey(null), description + ": null key present.");
 371         assertSame(map.compute(null, (k, v) -> {
 372             assertSame(k, null);
 373             assertNull(v);
 374             return EXTRA_VALUE;
 375         }), EXTRA_VALUE, description);
 376         assertTrue(map.containsKey(null));
 377         assertSame(map.get(null), EXTRA_VALUE, description);
 378         assertSame(map.remove(null), EXTRA_VALUE, description + ": removed value not expected");


 427             assertSame(k, KEYS[1]);
 428             assertSame(v, value);
 429             return EXTRA_VALUE;
 430         }), EXTRA_VALUE, description);
 431         assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
 432         assertNull(map.compute(KEYS[1], (k, v) -> {
 433             assertSame(v, EXTRA_VALUE);
 434             return null;
 435         }), description);
 436         assertFalse(map.containsKey(KEYS[1]));
 437 
 438         assertFalse(map.containsKey(EXTRA_KEY));
 439         assertSame(map.compute(EXTRA_KEY, (k, v) -> {
 440             assertNull(v);
 441             return EXTRA_VALUE;
 442         }), EXTRA_VALUE);
 443         assertTrue(map.containsKey(EXTRA_KEY));
 444         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 445     }
 446 
 447     @Test(expectedExceptions = {NullPointerException.class})
 448     public void testComputeNPEHashMap() {
 449         Object value = new HashMap().compute(KEYS[1], null);


 450     }
 451 
 452     @Test(expectedExceptions = {NullPointerException.class})
 453     public void testComputeNPEHashtable() {
 454         Object value = new Hashtable().compute(KEYS[1], null);
 455     }






















 456 
 457     @Test(expectedExceptions = {NullPointerException.class})
 458     public void testComputeNPETreeMap() {
 459         Object value = new TreeMap().compute(KEYS[1], null);
 460     }
 461 
 462     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 463     public void testMergeNulls(String description, Map<IntegerEnum, String> map) {
 464         assertTrue(map.containsKey(null), "null key absent");
 465         assertNull(map.get(null), "value not null");
 466         assertSame(map.merge(null, EXTRA_VALUE, (v, vv) -> {
 467             assertNull(v);
 468             assertSame(vv, EXTRA_VALUE);
 469             return vv;
 470         }), EXTRA_VALUE, description);
 471         assertTrue(map.containsKey(null));
 472         assertSame(map.get(null), EXTRA_VALUE, description);






















 473     }
 474 
 475     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 476     public void testMerge(String description, Map<IntegerEnum, String> map) {
 477         assertTrue(map.containsKey(KEYS[1]));
 478         Object value = map.get(KEYS[1]);
 479         assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
 480         assertSame(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> {
 481             assertSame(v, value);
 482             assertSame(vv, EXTRA_VALUE);
 483             return vv;
 484         }), EXTRA_VALUE, description);
 485         assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
 486         assertNull(map.merge(KEYS[1], EXTRA_VALUE, (v, vv) -> {
 487             assertSame(v, EXTRA_VALUE);
 488             assertSame(vv, EXTRA_VALUE);
 489             return null;
 490         }), description);
 491         assertFalse(map.containsKey(KEYS[1]));
 492 
 493         assertFalse(map.containsKey(EXTRA_KEY));
 494         assertSame(map.merge(EXTRA_KEY, EXTRA_VALUE, (v, vv) -> {
 495             assertNull(v);
 496             assertSame(vv, EXTRA_VALUE);
 497             return EXTRA_VALUE;
 498         }), EXTRA_VALUE);
 499         assertTrue(map.containsKey(EXTRA_KEY));
 500         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 501     }
 502 
 503     @Test(expectedExceptions = {NullPointerException.class})
 504     public void testMergeNPEHashMap() {
 505         Object value = new HashMap().merge(KEYS[1], VALUES[1], null);
 506     }
 507 
 508     @Test(expectedExceptions = {NullPointerException.class})
 509     public void testMergeNPEHashtable() {
 510         Object value = new Hashtable().merge(KEYS[1], VALUES[1], null);
 511     }
 512 
 513     @Test(expectedExceptions = {NullPointerException.class})
 514     public void testMergeNPETreeMap() {
 515         Object value = new TreeMap().merge(KEYS[1], VALUES[1], null);
 516     }
 517 
 518     enum IntegerEnum {
 519 
 520         e0, e1, e2, e3, e4, e5, e6, e7, e8, e9,
 521         e10, e11, e12, e13, e14, e15, e16, e17, e18, e19,
 522         e20, e21, e22, e23, e24, e25, e26, e27, e28, e29,
 523         e30, e31, e32, e33, e34, e35, e36, e37, e38, e39,
 524         e40, e41, e42, e43, e44, e45, e46, e47, e48, e49,
 525         e50, e51, e52, e53, e54, e55, e56, e57, e58, e59,
 526         e60, e61, e62, e63, e64, e65, e66, e67, e68, e69,
 527         e70, e71, e72, e73, e74, e75, e76, e77, e78, e79,
 528         e80, e81, e82, e83, e84, e85, e86, e87, e88, e89,
 529         e90, e91, e92, e93, e94, e95, e96, e97, e98, e99,
 530         EXTRA_KEY;
 531         public static final int SIZE = values().length;
 532     };
 533     private static final int TEST_SIZE = IntegerEnum.SIZE - 1;
 534     /**
 535      * Realized keys ensure that there is always a hard ref to all test objects.
 536      */
 537     private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE];
 538     /**


 696 
 697      /**
 698      *
 699      * @param supplier a supplier of mutable map instances.
 700      *
 701      * @param nullKeys   include null keys
 702      * @param nullValues include null values
 703      * @return
 704      */
 705     private static Map<IntegerEnum, String> makeMap(Supplier<Map<IntegerEnum, String>> supplier, boolean nullKeys, boolean nullValues) {
 706         Map<IntegerEnum, String> result = supplier.get();
 707 
 708         for (int each = 0; each < TEST_SIZE; each++) {
 709             IntegerEnum key = nullKeys ? (each == 0) ? null : KEYS[each] : KEYS[each];
 710             String value = nullValues ? (each == 0) ? null : VALUES[each] : VALUES[each];
 711 
 712             result.put(key, value);
 713         }
 714 
 715         return result;



















































































 716     }
 717 
 718     public interface Thrower<T extends Throwable> {
 719 
 720         public void run() throws T;
 721     }
 722 
 723     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable) {
 724         assertThrows(thrower, throwable, null);
 725     }
 726 
 727     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) {
 728         Throwable thrown;
 729         try {
 730             thrower.run();
 731             thrown = null;
 732         } catch (Throwable caught) {
 733             thrown = caught;
 734         }
 735 




  24 /*
  25  * @test
  26  * @bug 8010122 8004518 8024331
  27  * @summary Test Map default methods
  28  * @author Mike Duigou
  29  * @run testng Defaults
  30  */
  31 import java.util.AbstractMap;
  32 import java.util.AbstractSet;
  33 import java.util.ArrayList;
  34 import java.util.Arrays;
  35 import java.util.Collection;
  36 import java.util.Collections;
  37 import java.util.EnumMap;
  38 import java.util.HashMap;
  39 import java.util.HashSet;
  40 import java.util.Hashtable;
  41 import java.util.IdentityHashMap;
  42 import java.util.Iterator;
  43 import java.util.LinkedHashMap;
  44 import java.util.List;
  45 import java.util.Map;
  46 import java.util.TreeMap;
  47 import java.util.Set;
  48 import java.util.WeakHashMap;
  49 import java.util.concurrent.ConcurrentMap;
  50 import java.util.concurrent.ConcurrentHashMap;
  51 import java.util.concurrent.ConcurrentSkipListMap;
  52 import java.util.function.BiFunction;
  53 import java.util.function.Supplier;
  54 
  55 import org.testng.annotations.Test;
  56 import org.testng.annotations.DataProvider;
  57 import static org.testng.Assert.fail;
  58 import static org.testng.Assert.assertEquals;
  59 import static org.testng.Assert.assertTrue;
  60 import static org.testng.Assert.assertFalse;
  61 import static org.testng.Assert.assertNull;
  62 import static org.testng.Assert.assertSame;
  63 
  64 public class Defaults {


 272         assertTrue(map.containsKey(null), "null key absent");
 273         assertNull(map.get(null), "value not null");
 274         assertSame(map.computeIfAbsent(null, (k) -> EXTRA_VALUE), EXTRA_VALUE, description);
 275         assertSame(map.get(null), EXTRA_VALUE, description);
 276     }
 277 
 278     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 279     public void testComputeIfAbsent(String description, Map<IntegerEnum, String> map) {
 280         assertTrue(map.containsKey(KEYS[1]));
 281         Object expected = map.get(KEYS[1]);
 282         assertTrue(null == expected || expected == VALUES[1], description + String.valueOf(expected));
 283         expected = (null == expected) ? EXTRA_VALUE : expected;
 284         assertSame(map.computeIfAbsent(KEYS[1], (k) -> EXTRA_VALUE), expected, description);
 285         assertSame(map.get(KEYS[1]), expected, description);
 286 
 287         assertFalse(map.containsKey(EXTRA_KEY));
 288         assertSame(map.computeIfAbsent(EXTRA_KEY, (k) -> EXTRA_VALUE), EXTRA_VALUE);
 289         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 290     }
 291 
 292     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 293     public void testComputeIfAbsentNullFunction(String description, Map<IntegerEnum, String> map) {
 294         assertThrows( () -> { map.computeIfAbsent(KEYS[1], null);},
 295                 NullPointerException.class,
 296                 "Should throw NPE");








 297     }
 298 
 299     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 300     public void testComputeIfPresentNulls(String description, Map<IntegerEnum, String> map) {
 301         assertTrue(map.containsKey(null), description + ": null key absent");
 302         assertNull(map.get(null), description + ": value not null");
 303         assertSame(map.computeIfPresent(null, (k, v) -> {
 304             fail(description + ": null value is not deemed present");
 305             return EXTRA_VALUE;
 306         }), null, description);
 307         assertTrue(map.containsKey(null));
 308         assertNull(map.get(null), description);
 309         assertNull(map.remove(EXTRA_KEY), description + ": unexpected mapping");
 310         assertNull(map.put(EXTRA_KEY, null), description + ": unexpected value");
 311         assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
 312             fail(description + ": null value is not deemed present");
 313             return EXTRA_VALUE;
 314         }), null, description);
 315         assertNull(map.get(EXTRA_KEY), description + ": null mapping gone");
 316     }


 319     public void testComputeIfPresent(String description, Map<IntegerEnum, String> map) {
 320         assertTrue(map.containsKey(KEYS[1]));
 321         Object value = map.get(KEYS[1]);
 322         assertTrue(null == value || value == VALUES[1], description + String.valueOf(value));
 323         Object expected = (null == value) ? null : EXTRA_VALUE;
 324         assertSame(map.computeIfPresent(KEYS[1], (k, v) -> {
 325             assertSame(v, value);
 326             return EXTRA_VALUE;
 327         }), expected, description);
 328         assertSame(map.get(KEYS[1]), expected, description);
 329 
 330         assertFalse(map.containsKey(EXTRA_KEY));
 331         assertSame(map.computeIfPresent(EXTRA_KEY, (k, v) -> {
 332             fail();
 333             return EXTRA_VALUE;
 334         }), null);
 335         assertFalse(map.containsKey(EXTRA_KEY));
 336         assertSame(map.get(EXTRA_KEY), null);
 337     }
 338 
 339     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 340     public void testComputeIfPresentNullFunction(String description, Map<IntegerEnum, String> map) {
 341         assertThrows( () -> { map.computeIfPresent(KEYS[1], null);},
 342                 NullPointerException.class,
 343                 "Should throw NPE");








 344     }
 345 
 346      @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
 347     public void testComputeNulls(String description, Map<IntegerEnum, String> map) {
 348         assertTrue(map.containsKey(null), "null key absent");
 349         assertNull(map.get(null), "value not null");
 350         assertSame(map.compute(null, (k, v) -> {
 351             assertNull(k);
 352             assertNull(v);
 353             return null;
 354         }), null, description);
 355         assertFalse(map.containsKey(null), description + ": null key present.");
 356         assertSame(map.compute(null, (k, v) -> {
 357             assertSame(k, null);
 358             assertNull(v);
 359             return EXTRA_VALUE;
 360         }), EXTRA_VALUE, description);
 361         assertTrue(map.containsKey(null));
 362         assertSame(map.get(null), EXTRA_VALUE, description);
 363         assertSame(map.remove(null), EXTRA_VALUE, description + ": removed value not expected");


 412             assertSame(k, KEYS[1]);
 413             assertSame(v, value);
 414             return EXTRA_VALUE;
 415         }), EXTRA_VALUE, description);
 416         assertSame(map.get(KEYS[1]), EXTRA_VALUE, description);
 417         assertNull(map.compute(KEYS[1], (k, v) -> {
 418             assertSame(v, EXTRA_VALUE);
 419             return null;
 420         }), description);
 421         assertFalse(map.containsKey(KEYS[1]));
 422 
 423         assertFalse(map.containsKey(EXTRA_KEY));
 424         assertSame(map.compute(EXTRA_KEY, (k, v) -> {
 425             assertNull(v);
 426             return EXTRA_VALUE;
 427         }), EXTRA_VALUE);
 428         assertTrue(map.containsKey(EXTRA_KEY));
 429         assertSame(map.get(EXTRA_KEY), EXTRA_VALUE);
 430     }
 431 
 432     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 433     public void testComputeNullFunction(String description, Map<IntegerEnum, String> map) {
 434         assertThrows( () -> { map.compute(KEYS[1], null);},
 435                 NullPointerException.class,
 436                 "Should throw NPE");
 437     }
 438 
 439     @Test(dataProvider = "MergeCases")
 440     private void testMerge(String description, Map<IntegerEnum, String> map, Merging.Value oldValue, Merging.Value newValue, Merging.Merger merger, Merging.Value put, Merging.Value result) {
 441             // add and check initial conditions.
 442             switch(oldValue) {
 443                 case ABSENT :
 444                     map.remove(EXTRA_KEY);
 445                     assertFalse(map.containsKey(EXTRA_KEY), "key not absent");
 446                     break;
 447                 case NULL :
 448                     map.put(EXTRA_KEY, null);
 449                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 450                     assertNull(map.get(EXTRA_KEY), "wrong value");
 451                     break;
 452                 case OLDVALUE :
 453                     map.put(EXTRA_KEY, VALUES[1]);
 454                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 455                     assertSame(map.get(EXTRA_KEY), VALUES[1], "wrong value");
 456                     break;
 457                 default:
 458                     fail("unexpected old value");
 459             }
 460 
 461             String returned = map.merge(EXTRA_KEY,
 462                 newValue == Merging.Value.NULL ? (String) null : VALUES[2],
 463                 merger
 464                 );
 465 
 466             // check result



 467 
 468             switch(result) {
 469                 case NULL :
 470                     assertNull(returned, "wrong value");
 471                     break;
 472                 case NEWVALUE :
 473                     assertSame(returned, VALUES[2], "wrong value");
 474                     break;
 475                 case RESULT :
 476                     assertSame(returned, VALUES[3], "wrong value");
 477                     break;
 478                 default:
 479                     fail("unexpected new value");
 480             }
 481 
 482             // check map
 483             switch(put) {
 484                 case ABSENT :
 485                     assertFalse(map.containsKey(EXTRA_KEY), "key not absent");
 486                     break;
 487                 case NULL :
 488                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 489                     assertNull(map.get(EXTRA_KEY), "wrong value");
 490                     break;
 491                 case NEWVALUE :
 492                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 493                     assertSame(map.get(EXTRA_KEY), VALUES[2], "wrong value");
 494                     break;
 495                 case RESULT :
 496                     assertTrue(map.containsKey(EXTRA_KEY), "key absent");
 497                     assertSame(map.get(EXTRA_KEY), VALUES[3], "wrong value");
 498                     break;
 499                 default:
 500                     fail("unexpected new value");
 501             }



























 502     }
 503 
 504     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
 505     public void testMergeNullMerger(String description, Map<IntegerEnum, String> map) {
 506         assertThrows( () -> { map.merge(KEYS[1], VALUES[1], null);},
 507                 NullPointerException.class,
 508                 "Should throw NPE");








 509     }
 510 
 511     public enum IntegerEnum {
 512 
 513         e0, e1, e2, e3, e4, e5, e6, e7, e8, e9,
 514         e10, e11, e12, e13, e14, e15, e16, e17, e18, e19,
 515         e20, e21, e22, e23, e24, e25, e26, e27, e28, e29,
 516         e30, e31, e32, e33, e34, e35, e36, e37, e38, e39,
 517         e40, e41, e42, e43, e44, e45, e46, e47, e48, e49,
 518         e50, e51, e52, e53, e54, e55, e56, e57, e58, e59,
 519         e60, e61, e62, e63, e64, e65, e66, e67, e68, e69,
 520         e70, e71, e72, e73, e74, e75, e76, e77, e78, e79,
 521         e80, e81, e82, e83, e84, e85, e86, e87, e88, e89,
 522         e90, e91, e92, e93, e94, e95, e96, e97, e98, e99,
 523         EXTRA_KEY;
 524         public static final int SIZE = values().length;
 525     };
 526     private static final int TEST_SIZE = IntegerEnum.SIZE - 1;
 527     /**
 528      * Realized keys ensure that there is always a hard ref to all test objects.
 529      */
 530     private static final IntegerEnum[] KEYS = new IntegerEnum[TEST_SIZE];
 531     /**


 689 
 690      /**
 691      *
 692      * @param supplier a supplier of mutable map instances.
 693      *
 694      * @param nullKeys   include null keys
 695      * @param nullValues include null values
 696      * @return
 697      */
 698     private static Map<IntegerEnum, String> makeMap(Supplier<Map<IntegerEnum, String>> supplier, boolean nullKeys, boolean nullValues) {
 699         Map<IntegerEnum, String> result = supplier.get();
 700 
 701         for (int each = 0; each < TEST_SIZE; each++) {
 702             IntegerEnum key = nullKeys ? (each == 0) ? null : KEYS[each] : KEYS[each];
 703             String value = nullValues ? (each == 0) ? null : VALUES[each] : VALUES[each];
 704 
 705             result.put(key, value);
 706         }
 707 
 708         return result;
 709     }
 710 
 711     static class Merging {
 712         public enum Value {
 713             ABSENT,
 714             NULL,
 715             OLDVALUE,
 716             NEWVALUE,
 717             RESULT
 718         }
 719 
 720         public enum Merger implements BiFunction<String,String,String> {
 721             UNUSED {
 722                 public String apply(String oldValue, String newValue) {
 723                     fail("should not be called");
 724                     return null;
 725                 }
 726             },
 727             NULL {
 728                 public String apply(String oldValue, String newValue) {
 729                     return null;
 730                 }
 731             },
 732             RESULT {
 733                 public String apply(String oldValue, String newValue) {
 734                     return VALUES[3];
 735                 }
 736             },
 737         }
 738     }
 739 
 740     @DataProvider(name = "MergeCases", parallel = true)
 741     public Iterator<Object[]> mergeCasesProvider() {
 742         Collection<Object[]> cases = new ArrayList<>();
 743 
 744         cases.addAll(makeMergeTestCases());
 745         cases.addAll(makeMergeNullValueTestCases());
 746 
 747         return cases.iterator();
 748     }
 749 
 750     static Collection<Object[]> makeMergeTestCases() {
 751         Collection<Object[]> cases = new ArrayList<>();
 752 
 753         for( Object[] mapParams : makeAllRWMaps() ) {
 754             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.ABSENT, Merging.Value.NEWVALUE, Merging.Merger.UNUSED, Merging.Value.NEWVALUE, Merging.Value.NEWVALUE });
 755         }
 756 
 757         for( Object[] mapParams : makeAllRWMaps() ) {
 758             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.NULL, Merging.Value.ABSENT, Merging.Value.NULL });
 759         }
 760 
 761         for( Object[] mapParams : makeAllRWMaps() ) {
 762             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NEWVALUE, Merging.Merger.RESULT, Merging.Value.RESULT, Merging.Value.RESULT });
 763         }
 764 
 765         return cases;
 766     }
 767 
 768     static Collection<Object[]> makeMergeNullValueTestCases() {
 769         Collection<Object[]> cases = new ArrayList<>();
 770 
 771         for( Object[] mapParams : makeAllRWMapsWithNulls() ) {
 772             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NULL, Merging.Merger.NULL, Merging.Value.ABSENT, Merging.Value.NULL });
 773         }
 774 
 775         for( Object[] mapParams : makeAllRWMapsWithNulls() ) {
 776             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.OLDVALUE, Merging.Value.NULL, Merging.Merger.RESULT, Merging.Value.RESULT, Merging.Value.RESULT });
 777         }
 778 
 779         for( Object[] mapParams : makeAllRWMapsWithNulls() ) {
 780             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.ABSENT, Merging.Value.NULL, Merging.Merger.UNUSED, Merging.Value.ABSENT, Merging.Value.NULL });
 781         }
 782 
 783         for( Object[] mapParams : makeAllRWMapsWithNulls() ) {
 784             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.NULL, Merging.Value.NULL, Merging.Merger.UNUSED, Merging.Value.ABSENT, Merging.Value.NULL });
 785         }
 786 
 787         for( Object[] mapParams : makeAllRWMapsWithNulls() ) {
 788             cases.add(new Object[] { mapParams[0], mapParams[1], Merging.Value.NULL, Merging.Value.NEWVALUE, Merging.Merger.UNUSED, Merging.Value.NEWVALUE, Merging.Value.NEWVALUE });
 789         }
 790 
 791         return cases;
 792     }
 793 
 794     public interface Thrower<T extends Throwable> {
 795 
 796         public void run() throws T;
 797     }
 798 
 799     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable) {
 800         assertThrows(thrower, throwable, null);
 801     }
 802 
 803     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) {
 804         Throwable thrown;
 805         try {
 806             thrower.run();
 807             thrown = null;
 808         } catch (Throwable caught) {
 809             thrown = caught;
 810         }
 811