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")
 380     public void serialEquality(Map<Integer, String> act, Map<Integer, String> exp) {
 381         // assume that act.equals(exp) tested elsewhere
 382         Map<Integer, String> copy = serialClone(act);
 383         assertEquals(act, copy);
 384         assertEquals(copy, exp);
 385     }
 386 
 387     @SuppressWarnings("unchecked")
 388     static <T> T serialClone(T obj) {
 389         try {
 390             ByteArrayOutputStream baos = new ByteArrayOutputStream();
 391             try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
 392                 oos.writeObject(obj);
 393             }
 394             ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
 395             ObjectInputStream ois = new ObjectInputStream(bais);
 396             return (T) ois.readObject();
 397         } catch (IOException | ClassNotFoundException e) {
 398             throw new AssertionError(e);
 399         }
 400     }
 401 
 402     Map<Integer, String> genMap() {
 403         Map<Integer, String> map = new HashMap<>();
 404         map.put(1, "a");
 405         map.put(2, "b");
 406         map.put(3, "c");
 407         return map;
 408     }
 409 
 410     @Test
 411     public void copyOfResultsEqual() {
 412         Map<Integer, String> orig = genMap();
 413         Map<Integer, String> copy = Map.copyOf(orig);
 414 
 415         assertEquals(orig, copy);
 416         assertEquals(copy, orig);
 417     }
 418 
 419     @Test
 420     public void copyOfModifiedUnequal() {
 421         Map<Integer, String> orig = genMap();
 422         Map<Integer, String> copy = Map.copyOf(orig);
 423         orig.put(4, "d");
 424 
 425         assertNotEquals(orig, copy);
 426         assertNotEquals(copy, orig);
 427     }
 428 
 429     @Test
 430     public void copyOfIdentity() {
 431         Map<Integer, String> orig = genMap();
 432         Map<Integer, String> copy1 = Map.copyOf(orig);
 433         Map<Integer, String> copy2 = Map.copyOf(copy1);
 434 
 435         assertNotSame(orig, copy1);
 436         assertSame(copy1, copy2);
 437     }
 438 
 439     @Test(expectedExceptions=NullPointerException.class)
 440     public void copyOfRejectsNullMap() {
 441         Map<Integer, String> map = Map.copyOf(null);
 442     }
 443 
 444     @Test(expectedExceptions=NullPointerException.class)
 445     public void copyOfRejectsNullKey() {
 446         Map<Integer, String> map = genMap();
 447         map.put(null, "x");
 448         Map<Integer, String> copy = Map.copyOf(map);
 449     }
 450 
 451     @Test(expectedExceptions=NullPointerException.class)
 452     public void copyOfRejectsNullValue() {
 453         Map<Integer, String> map = genMap();
 454         map.put(-1, null);
 455         Map<Integer, String> copy = Map.copyOf(map);
 456     }
 457 
 458     // Map.entry() tests
 459 
 460     @Test(expectedExceptions=NullPointerException.class)
 461     public void entryWithNullKeyDisallowed() {
 462         Map.Entry<Integer,String> e = Map.entry(null, "x");
 463     }
 464 
 465     @Test(expectedExceptions=NullPointerException.class)
 466     public void entryWithNullValueDisallowed() {
 467         Map.Entry<Integer,String> e = Map.entry(0, null);
 468     }
 469 
 470     @Test
 471     public void entryBasicTests() {
 472         Map.Entry<String,String> kvh1 = Map.entry("xyzzy", "plugh");
 473         Map.Entry<String,String> kvh2 = Map.entry("foobar", "blurfl");
 474         Map.Entry<String,String> sie = new AbstractMap.SimpleImmutableEntry<>("xyzzy", "plugh");
 475 
 476         assertTrue(kvh1.equals(sie));
 477         assertTrue(sie.equals(kvh1));
 478         assertFalse(kvh2.equals(sie));
 479         assertFalse(sie.equals(kvh2));
 480         assertEquals(sie.hashCode(), kvh1.hashCode());
 481         assertEquals(sie.toString(), kvh1.toString());
 482     }
 483 
 484     // compile-time test of wildcards
 485     @Test
 486     public void entryWildcardTests() {
 487         Map.Entry<Integer,Double> e1 = Map.entry(1, 2.0);
 488         Map.Entry<Float,Long> e2 = Map.entry(3.0f, 4L);
 489         Map<Number,Number> map = Map.ofEntries(e1, e2);
 490         assertEquals(map.size(), 2);
 491     }
 492 }