1 /*
   2  * Copyright (c) 2015, 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  */
  23 
  24 import java.io.ByteArrayInputStream;
  25 import java.io.ByteArrayOutputStream;
  26 import java.io.IOException;
  27 import java.io.ObjectInputStream;
  28 import java.io.ObjectOutputStream;
  29 import java.util.AbstractMap;
  30 import java.util.ArrayList;
  31 import java.util.Arrays;
  32 import java.util.Collections;
  33 import java.util.Iterator;
  34 import java.util.HashMap;
  35 import java.util.List;
  36 import java.util.Map;
  37 import java.util.stream.Collectors;
  38 import java.util.stream.IntStream;
  39 
  40 import org.testng.annotations.DataProvider;
  41 import org.testng.annotations.Test;
  42 
  43 import static org.testng.Assert.assertEquals;
  44 import static org.testng.Assert.assertFalse;
  45 import static org.testng.Assert.assertNotEquals;
  46 import static org.testng.Assert.assertNotSame;
  47 import static org.testng.Assert.assertSame;
  48 import static org.testng.Assert.assertTrue;
  49 import static org.testng.Assert.fail;
  50 
  51 /*
  52  * @test
  53  * @bug 8048330
  54  * @summary Test convenience static factory methods on Map.
  55  * @run testng MapFactories
  56  */
  57 
  58 public class MapFactories {
  59 
  60     static final int MAX_ENTRIES = 20; // should be larger than the largest fixed-arg overload
  61     static String valueFor(int i) {
  62         // the String literal below should be of length MAX_ENTRIES
  63         return "abcdefghijklmnopqrst".substring(i, i+1);
  64     }
  65 
  66     // for "expected" values
  67     Map<Integer,String> genMap(int n) {
  68         Map<Integer,String> result = new HashMap<>();
  69         for (int i = 0; i < n; i++) {
  70             result.put(i, valueFor(i));
  71         }
  72         return result;
  73     }
  74 
  75     // for varargs Map.Entry methods
  76 
  77     @SuppressWarnings("unchecked")
  78     Map.Entry<Integer,String>[] genEmptyEntryArray1() {
  79         return (Map.Entry<Integer,String>[])new Map.Entry<?,?>[1];
  80     }
  81 
  82     @SuppressWarnings("unchecked")
  83     Map.Entry<Integer,String>[] genEntries(int n) {
  84         return IntStream.range(0, n)
  85             .mapToObj(i -> Map.entry(i, valueFor(i)))
  86             .toArray(Map.Entry[]::new);
  87     }
  88 
  89     // returns array of [actual, expected]
  90     static Object[] a(Map<Integer,String> act, Map<Integer,String> exp) {
  91         return new Object[] { act, exp };
  92     }
  93 
  94     @DataProvider(name="empty")
  95     public Iterator<Object[]> empty() {
  96         return Collections.singletonList(
  97             a(Map.of(), genMap(0))
  98         ).iterator();
  99     }
 100 
 101     @DataProvider(name="nonempty")
 102     @SuppressWarnings("unchecked")
 103     public Iterator<Object[]> nonempty() {
 104         return Arrays.asList(
 105             a(Map.of(0, "a"), genMap(1)),
 106             a(Map.of(0, "a", 1, "b"), genMap(2)),
 107             a(Map.of(0, "a", 1, "b", 2, "c"), genMap(3)),
 108             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d"), genMap(4)),
 109             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e"), genMap(5)),
 110             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f"), genMap(6)),
 111             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g"), genMap(7)),
 112             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h"), genMap(8)),
 113             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i"), genMap(9)),
 114             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j"), genMap(10)),
 115             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j"),
 116               Map.of(4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j", 0, "a", 1, "b", 2, "c", 3, "d")),
 117             a(Map.ofEntries(genEntries(MAX_ENTRIES)), genMap(MAX_ENTRIES))
 118         ).iterator();
 119     }
 120 
 121     @DataProvider(name="all")
 122     public Iterator<Object[]> all() {
 123         List<Object[]> all = new ArrayList<>();
 124         empty().forEachRemaining(all::add);
 125         nonempty().forEachRemaining(all::add);
 126         return all.iterator();
 127     }
 128 
 129     @Test(dataProvider="all", expectedExceptions=UnsupportedOperationException.class)
 130     public void cannotPutNew(Map<Integer,String> act, Map<Integer,String> exp) {
 131         act.put(-1, "xyzzy");
 132     }
 133 
 134     @Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class)
 135     public void cannotPutOld(Map<Integer,String> act, Map<Integer,String> exp) {
 136         act.put(0, "a");
 137     }
 138 
 139     @Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class)
 140     public void cannotRemove(Map<Integer,String> act, Map<Integer,String> exp) {
 141         act.remove(act.keySet().iterator().next());
 142     }
 143 
 144     @Test(dataProvider="all")
 145     public void contentsMatch(Map<Integer,String> act, Map<Integer,String> exp) {
 146         assertEquals(act, exp);
 147     }
 148 
 149     @Test(dataProvider="all")
 150     public void containsAllKeys(Map<Integer,String> act, Map<Integer,String> exp) {
 151         assertTrue(act.keySet().containsAll(exp.keySet()));
 152         assertTrue(exp.keySet().containsAll(act.keySet()));
 153     }
 154 
 155     @Test(dataProvider="all")
 156     public void containsAllValues(Map<Integer,String> act, Map<Integer,String> exp) {
 157         assertTrue(act.values().containsAll(exp.values()));
 158         assertTrue(exp.values().containsAll(act.values()));
 159     }
 160 
 161     @Test(expectedExceptions=IllegalArgumentException.class)
 162     public void dupKeysDisallowed2() {
 163         Map<Integer, String> map = Map.of(0, "a", 0, "b");
 164     }
 165 
 166     @Test(expectedExceptions=IllegalArgumentException.class)
 167     public void dupKeysDisallowed3() {
 168         Map<Integer, String> map = Map.of(0, "a", 1, "b", 0, "c");
 169     }
 170 
 171     @Test(expectedExceptions=IllegalArgumentException.class)
 172     public void dupKeysDisallowed4() {
 173         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 0, "d");
 174     }
 175 
 176     @Test(expectedExceptions=IllegalArgumentException.class)
 177     public void dupKeysDisallowed5() {
 178         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 0, "e");
 179     }
 180 
 181     @Test(expectedExceptions=IllegalArgumentException.class)
 182     public void dupKeysDisallowed6() {
 183         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 184                                           0, "f");
 185     }
 186 
 187     @Test(expectedExceptions=IllegalArgumentException.class)
 188     public void dupKeysDisallowed7() {
 189         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 190                                           5, "f", 0, "g");
 191     }
 192 
 193     @Test(expectedExceptions=IllegalArgumentException.class)
 194     public void dupKeysDisallowed8() {
 195         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 196                                           5, "f", 6, "g", 0, "h");
 197     }
 198 
 199     @Test(expectedExceptions=IllegalArgumentException.class)
 200     public void dupKeysDisallowed9() {
 201         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 202                                           5, "f", 6, "g", 7, "h", 0, "i");
 203     }
 204 
 205     @Test(expectedExceptions=IllegalArgumentException.class)
 206     public void dupKeysDisallowed10() {
 207         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 208                                           5, "f", 6, "g", 7, "h", 8, "i", 0, "j");
 209     }
 210 
 211     @Test(expectedExceptions=IllegalArgumentException.class)
 212     public void dupKeysDisallowedN() {
 213         Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
 214         entries[MAX_ENTRIES-1] = Map.entry(0, "xxx");
 215         Map<Integer, String> map = Map.ofEntries(entries);
 216     }
 217 
 218     @Test(dataProvider="all")
 219     public void hashCodeEquals(Map<Integer,String> act, Map<Integer,String> exp) {
 220         assertEquals(act.hashCode(), exp.hashCode());
 221     }
 222 
 223     @Test(expectedExceptions=NullPointerException.class)
 224     public void nullKeyDisallowed1() {
 225         Map<Integer, String> map = Map.of(null, "a");
 226     }
 227 
 228     @Test(expectedExceptions=NullPointerException.class)
 229     public void nullValueDisallowed1() {
 230         Map<Integer, String> map = Map.of(0, null);
 231     }
 232 
 233     @Test(expectedExceptions=NullPointerException.class)
 234     public void nullKeyDisallowed2() {
 235         Map<Integer, String> map = Map.of(0, "a", null, "b");
 236     }
 237 
 238     @Test(expectedExceptions=NullPointerException.class)
 239     public void nullValueDisallowed2() {
 240         Map<Integer, String> map = Map.of(0, "a", 1, null);
 241     }
 242 
 243     @Test(expectedExceptions=NullPointerException.class)
 244     public void nullKeyDisallowed3() {
 245         Map<Integer, String> map = Map.of(0, "a", 1, "b", null, "c");
 246     }
 247 
 248     @Test(expectedExceptions=NullPointerException.class)
 249     public void nullValueDisallowed3() {
 250         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, null);
 251     }
 252 
 253     @Test(expectedExceptions=NullPointerException.class)
 254     public void nullKeyDisallowed4() {
 255         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", null, "d");
 256     }
 257 
 258     @Test(expectedExceptions=NullPointerException.class)
 259     public void nullValueDisallowed4() {
 260         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, null);
 261     }
 262 
 263     @Test(expectedExceptions=NullPointerException.class)
 264     public void nullKeyDisallowed5() {
 265         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", null, "e");
 266     }
 267 
 268     @Test(expectedExceptions=NullPointerException.class)
 269     public void nullValueDisallowed5() {
 270         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, null);
 271     }
 272 
 273     @Test(expectedExceptions=NullPointerException.class)
 274     public void nullKeyDisallowed6() {
 275         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 276                                           null, "f");
 277     }
 278 
 279     @Test(expectedExceptions=NullPointerException.class)
 280     public void nullValueDisallowed6() {
 281         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 282                                           5, null);
 283     }
 284 
 285     @Test(expectedExceptions=NullPointerException.class)
 286     public void nullKeyDisallowed7() {
 287         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 288                                           5, "f", null, "g");
 289     }
 290 
 291     @Test(expectedExceptions=NullPointerException.class)
 292     public void nullValueDisallowed7() {
 293         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 294                                           5, "f", 6, null);
 295     }
 296 
 297     @Test(expectedExceptions=NullPointerException.class)
 298     public void nullKeyDisallowed8() {
 299         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 300                                           5, "f", 6, "g", null, "h");
 301     }
 302 
 303     @Test(expectedExceptions=NullPointerException.class)
 304     public void nullValueDisallowed8() {
 305         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 306                                           5, "f", 6, "g", 7, null);
 307     }
 308 
 309     @Test(expectedExceptions=NullPointerException.class)
 310     public void nullKeyDisallowed9() {
 311         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 312                                           5, "f", 6, "g", 7, "h", null, "i");
 313     }
 314 
 315     @Test(expectedExceptions=NullPointerException.class)
 316     public void nullValueDisallowed9() {
 317         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 318                                           5, "f", 6, "g", 7, "h", 8, null);
 319     }
 320 
 321     @Test(expectedExceptions=NullPointerException.class)
 322     public void nullKeyDisallowed10() {
 323         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 324                                           5, "f", 6, "g", 7, "h", 8, "i", null, "j");
 325     }
 326 
 327     @Test(expectedExceptions=NullPointerException.class)
 328     public void nullValueDisallowed10() {
 329         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 330                                           5, "f", 6, "g", 7, "h", 8, "i", 9, null);
 331     }
 332 
 333     @Test(expectedExceptions=NullPointerException.class)
 334     public void nullKeyDisallowedVar1() {
 335         Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
 336         entries[0] = new AbstractMap.SimpleImmutableEntry<>(null, "a");
 337         Map<Integer, String> map = Map.ofEntries(entries);
 338     }
 339 
 340     @Test(expectedExceptions=NullPointerException.class)
 341     public void nullValueDisallowedVar1() {
 342         Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
 343         entries[0] = new AbstractMap.SimpleImmutableEntry<>(0, null);
 344         Map<Integer, String> map = Map.ofEntries(entries);
 345     }
 346 
 347     @Test(expectedExceptions=NullPointerException.class)
 348     public void nullEntryDisallowedVar1() {
 349         Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
 350         Map<Integer, String> map = Map.ofEntries(entries);
 351     }
 352 
 353     @Test(expectedExceptions=NullPointerException.class)
 354     public void nullKeyDisallowedVarN() {
 355         Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
 356         entries[0] = new AbstractMap.SimpleImmutableEntry<>(null, "a");
 357         Map<Integer, String> map = Map.ofEntries(entries);
 358     }
 359 
 360     @Test(expectedExceptions=NullPointerException.class)
 361     public void nullValueDisallowedVarN() {
 362         Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
 363         entries[0] = new AbstractMap.SimpleImmutableEntry<>(0, null);
 364         Map<Integer, String> map = Map.ofEntries(entries);
 365     }
 366 
 367     @Test(expectedExceptions=NullPointerException.class)
 368     public void nullEntryDisallowedVarN() {
 369         Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
 370         entries[5] = null;
 371         Map<Integer, String> map = Map.ofEntries(entries);
 372     }
 373 
 374     @Test(expectedExceptions=NullPointerException.class)
 375     public void nullArrayDisallowed() {
 376         Map.ofEntries((Map.Entry<?,?>[])null);
 377     }
 378 
 379     @Test(dataProvider="all", expectedExceptions=NullPointerException.class)
 380     public void containsValueNullShouldThrowNPE(Map<Integer,String> act, Map<Integer,String> exp) {
 381         act.containsValue(null);
 382     }
 383 
 384     @Test(dataProvider="all", expectedExceptions=NullPointerException.class)
 385     public void containsKeyNullShouldThrowNPE(Map<Integer,String> act, Map<Integer,String> exp) {
 386         act.containsKey(null);
 387     }
 388 
 389     @Test(dataProvider="all")
 390     public void serialEquality(Map<Integer, String> act, Map<Integer, String> exp) {
 391         // assume that act.equals(exp) tested elsewhere
 392         Map<Integer, String> copy = serialClone(act);
 393         assertEquals(act, copy);
 394         assertEquals(copy, exp);
 395     }
 396 
 397     @SuppressWarnings("unchecked")
 398     static <T> T serialClone(T obj) {
 399         try {
 400             ByteArrayOutputStream baos = new ByteArrayOutputStream();
 401             try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
 402                 oos.writeObject(obj);
 403             }
 404             ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
 405             ObjectInputStream ois = new ObjectInputStream(bais);
 406             return (T) ois.readObject();
 407         } catch (IOException | ClassNotFoundException e) {
 408             throw new AssertionError(e);
 409         }
 410     }
 411 
 412     Map<Integer, String> genMap() {
 413         Map<Integer, String> map = new HashMap<>();
 414         map.put(1, "a");
 415         map.put(2, "b");
 416         map.put(3, "c");
 417         return map;
 418     }
 419 
 420     @Test
 421     public void copyOfResultsEqual() {
 422         Map<Integer, String> orig = genMap();
 423         Map<Integer, String> copy = Map.copyOf(orig);
 424 
 425         assertEquals(orig, copy);
 426         assertEquals(copy, orig);
 427     }
 428 
 429     @Test
 430     public void copyOfModifiedUnequal() {
 431         Map<Integer, String> orig = genMap();
 432         Map<Integer, String> copy = Map.copyOf(orig);
 433         orig.put(4, "d");
 434 
 435         assertNotEquals(orig, copy);
 436         assertNotEquals(copy, orig);
 437     }
 438 
 439     @Test
 440     public void copyOfIdentity() {
 441         Map<Integer, String> orig = genMap();
 442         Map<Integer, String> copy1 = Map.copyOf(orig);
 443         Map<Integer, String> copy2 = Map.copyOf(copy1);
 444 
 445         assertNotSame(orig, copy1);
 446         assertSame(copy1, copy2);
 447     }
 448 
 449     @Test(expectedExceptions=NullPointerException.class)
 450     public void copyOfRejectsNullMap() {
 451         Map<Integer, String> map = Map.copyOf(null);
 452     }
 453 
 454     @Test(expectedExceptions=NullPointerException.class)
 455     public void copyOfRejectsNullKey() {
 456         Map<Integer, String> map = genMap();
 457         map.put(null, "x");
 458         Map<Integer, String> copy = Map.copyOf(map);
 459     }
 460 
 461     @Test(expectedExceptions=NullPointerException.class)
 462     public void copyOfRejectsNullValue() {
 463         Map<Integer, String> map = genMap();
 464         map.put(-1, null);
 465         Map<Integer, String> copy = Map.copyOf(map);
 466     }
 467 
 468     // Map.entry() tests
 469 
 470     @Test(expectedExceptions=NullPointerException.class)
 471     public void entryWithNullKeyDisallowed() {
 472         Map.Entry<Integer,String> e = Map.entry(null, "x");
 473     }
 474 
 475     @Test(expectedExceptions=NullPointerException.class)
 476     public void entryWithNullValueDisallowed() {
 477         Map.Entry<Integer,String> e = Map.entry(0, null);
 478     }
 479 
 480     @Test
 481     public void entryBasicTests() {
 482         Map.Entry<String,String> kvh1 = Map.entry("xyzzy", "plugh");
 483         Map.Entry<String,String> kvh2 = Map.entry("foobar", "blurfl");
 484         Map.Entry<String,String> sie = new AbstractMap.SimpleImmutableEntry<>("xyzzy", "plugh");
 485 
 486         assertTrue(kvh1.equals(sie));
 487         assertTrue(sie.equals(kvh1));
 488         assertFalse(kvh2.equals(sie));
 489         assertFalse(sie.equals(kvh2));
 490         assertEquals(sie.hashCode(), kvh1.hashCode());
 491         assertEquals(sie.toString(), kvh1.toString());
 492     }
 493 
 494     // compile-time test of wildcards
 495     @Test
 496     public void entryWildcardTests() {
 497         Map.Entry<Integer,Double> e1 = Map.entry(1, 2.0);
 498         Map.Entry<Float,Long> e2 = Map.entry(3.0f, 4L);
 499         Map<Number,Number> map = Map.ofEntries(e1, e2);
 500         assertEquals(map.size(), 2);
 501     }
 502 }