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.assertTrue;
  46 import static org.testng.Assert.fail;
  47 
  48 /*
  49  * @test
  50  * @bug 8048330
  51  * @summary Test convenience static factory methods on Map.
  52  * @run testng MapFactories
  53  */
  54 
  55 public class MapFactories {
  56 
  57     static final int MAX_ENTRIES = 20; // should be larger than the largest fixed-arg overload
  58     static String valueFor(int i) {
  59         // the String literal below should be of length MAX_ENTRIES
  60         return "abcdefghijklmnopqrst".substring(i, i+1);
  61     }
  62 
  63     // for "expected" values
  64     Map<Integer,String> genMap(int n) {
  65         Map<Integer,String> result = new HashMap<>();
  66         for (int i = 0; i < n; i++) {
  67             result.put(i, valueFor(i));
  68         }
  69         return result;
  70     }
  71 
  72     // for varargs Map.Entry methods
  73     @SuppressWarnings("unchecked")
  74     Map.Entry<Integer,String>[] genEntries(int n) {
  75         return IntStream.range(0, n)
  76             .mapToObj(i -> Map.entry(i, valueFor(i)))
  77             .toArray(Map.Entry[]::new);
  78     }
  79 
  80     // returns array of [actual, expected]
  81     static Object[] a(Map<Integer,String> act, Map<Integer,String> exp) {
  82         return new Object[] { act, exp };
  83     }
  84 
  85     @DataProvider(name="empty")
  86     public Iterator<Object[]> empty() {
  87         return Collections.singletonList(
  88             a(Map.of(), genMap(0))
  89         ).iterator();
  90     }
  91 
  92     @DataProvider(name="nonempty")
  93     @SuppressWarnings("unchecked")
  94     public Iterator<Object[]> nonempty() {
  95         return Arrays.asList(
  96             a(Map.of(0, "a"), genMap(1)),
  97             a(Map.of(0, "a", 1, "b"), genMap(2)),
  98             a(Map.of(0, "a", 1, "b", 2, "c"), genMap(3)),
  99             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d"), genMap(4)),
 100             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e"), genMap(5)),
 101             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f"), genMap(6)),
 102             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g"), genMap(7)),
 103             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h"), genMap(8)),
 104             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i"), genMap(9)),
 105             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)),
 106             a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j"),
 107               Map.of(4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j", 0, "a", 1, "b", 2, "c", 3, "d")),
 108             a(Map.ofEntries(genEntries(MAX_ENTRIES)), genMap(MAX_ENTRIES))
 109         ).iterator();
 110     }
 111 
 112     @DataProvider(name="all")
 113     public Iterator<Object[]> all() {
 114         List<Object[]> all = new ArrayList<>();
 115         empty().forEachRemaining(all::add);
 116         nonempty().forEachRemaining(all::add);
 117         return all.iterator();
 118     }
 119 
 120     @Test(dataProvider="all", expectedExceptions=UnsupportedOperationException.class)
 121     public void cannotPutNew(Map<Integer,String> act, Map<Integer,String> exp) {
 122         act.put(-1, "xyzzy");
 123     }
 124 
 125     @Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class)
 126     public void cannotPutOld(Map<Integer,String> act, Map<Integer,String> exp) {
 127         act.put(0, "a");
 128     }
 129 
 130     @Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class)
 131     public void cannotRemove(Map<Integer,String> act, Map<Integer,String> exp) {
 132         act.remove(act.keySet().iterator().next());
 133     }
 134 
 135     @Test(dataProvider="all")
 136     public void contentsMatch(Map<Integer,String> act, Map<Integer,String> exp) {
 137         assertEquals(act, exp);
 138     }
 139 
 140     @Test(dataProvider="all")
 141     public void containsAllKeys(Map<Integer,String> act, Map<Integer,String> exp) {
 142         assertTrue(act.keySet().containsAll(exp.keySet()));
 143         assertTrue(exp.keySet().containsAll(act.keySet()));
 144     }
 145 
 146     @Test(dataProvider="all")
 147     public void containsAllValues(Map<Integer,String> act, Map<Integer,String> exp) {
 148         assertTrue(act.values().containsAll(exp.values()));
 149         assertTrue(exp.values().containsAll(act.values()));
 150     }
 151 
 152     @Test(expectedExceptions=IllegalArgumentException.class)
 153     public void dupKeysDisallowed2() {
 154         Map<Integer, String> map = Map.of(0, "a", 0, "b");
 155     }
 156 
 157     @Test(expectedExceptions=IllegalArgumentException.class)
 158     public void dupKeysDisallowed3() {
 159         Map<Integer, String> map = Map.of(0, "a", 1, "b", 0, "c");
 160     }
 161 
 162     @Test(expectedExceptions=IllegalArgumentException.class)
 163     public void dupKeysDisallowed4() {
 164         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 0, "d");
 165     }
 166 
 167     @Test(expectedExceptions=IllegalArgumentException.class)
 168     public void dupKeysDisallowed5() {
 169         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 0, "e");
 170     }
 171 
 172     @Test(expectedExceptions=IllegalArgumentException.class)
 173     public void dupKeysDisallowed6() {
 174         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 175                                           0, "f");
 176     }
 177 
 178     @Test(expectedExceptions=IllegalArgumentException.class)
 179     public void dupKeysDisallowed7() {
 180         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 181                                           5, "f", 0, "g");
 182     }
 183 
 184     @Test(expectedExceptions=IllegalArgumentException.class)
 185     public void dupKeysDisallowed8() {
 186         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 187                                           5, "f", 6, "g", 0, "h");
 188     }
 189 
 190     @Test(expectedExceptions=IllegalArgumentException.class)
 191     public void dupKeysDisallowed9() {
 192         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 193                                           5, "f", 6, "g", 7, "h", 0, "i");
 194     }
 195 
 196     @Test(expectedExceptions=IllegalArgumentException.class)
 197     public void dupKeysDisallowed10() {
 198         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 199                                           5, "f", 6, "g", 7, "h", 8, "i", 0, "j");
 200     }
 201 
 202     @Test(expectedExceptions=IllegalArgumentException.class)
 203     public void dupKeysDisallowedN() {
 204         Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
 205         entries[MAX_ENTRIES-1] = Map.entry(0, "xxx");
 206         Map<Integer, String> map = Map.ofEntries(entries);
 207     }
 208 
 209     @Test(dataProvider="all")
 210     public void hashCodeEquals(Map<Integer,String> act, Map<Integer,String> exp) {
 211         assertEquals(act.hashCode(), exp.hashCode());
 212     }
 213 
 214     @Test(expectedExceptions=NullPointerException.class)
 215     public void nullKeyDisallowed1() {
 216         Map<Integer, String> map = Map.of(null, "a");
 217     }
 218 
 219     @Test(expectedExceptions=NullPointerException.class)
 220     public void nullValueDisallowed1() {
 221         Map<Integer, String> map = Map.of(0, null);
 222     }
 223 
 224     @Test(expectedExceptions=NullPointerException.class)
 225     public void nullKeyDisallowed2() {
 226         Map<Integer, String> map = Map.of(0, "a", null, "b");
 227     }
 228 
 229     @Test(expectedExceptions=NullPointerException.class)
 230     public void nullValueDisallowed2() {
 231         Map<Integer, String> map = Map.of(0, "a", 1, null);
 232     }
 233 
 234     @Test(expectedExceptions=NullPointerException.class)
 235     public void nullKeyDisallowed3() {
 236         Map<Integer, String> map = Map.of(0, "a", 1, "b", null, "c");
 237     }
 238 
 239     @Test(expectedExceptions=NullPointerException.class)
 240     public void nullValueDisallowed3() {
 241         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, null);
 242     }
 243 
 244     @Test(expectedExceptions=NullPointerException.class)
 245     public void nullKeyDisallowed4() {
 246         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", null, "d");
 247     }
 248 
 249     @Test(expectedExceptions=NullPointerException.class)
 250     public void nullValueDisallowed4() {
 251         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, null);
 252     }
 253 
 254     @Test(expectedExceptions=NullPointerException.class)
 255     public void nullKeyDisallowed5() {
 256         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", null, "e");
 257     }
 258 
 259     @Test(expectedExceptions=NullPointerException.class)
 260     public void nullValueDisallowed5() {
 261         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, null);
 262     }
 263 
 264     @Test(expectedExceptions=NullPointerException.class)
 265     public void nullKeyDisallowed6() {
 266         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 267                                           null, "f");
 268     }
 269 
 270     @Test(expectedExceptions=NullPointerException.class)
 271     public void nullValueDisallowed6() {
 272         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 273                                           5, null);
 274     }
 275 
 276     @Test(expectedExceptions=NullPointerException.class)
 277     public void nullKeyDisallowed7() {
 278         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 279                                           5, "f", null, "g");
 280     }
 281 
 282     @Test(expectedExceptions=NullPointerException.class)
 283     public void nullValueDisallowed7() {
 284         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 285                                           5, "f", 6, null);
 286     }
 287 
 288     @Test(expectedExceptions=NullPointerException.class)
 289     public void nullKeyDisallowed8() {
 290         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 291                                           5, "f", 6, "g", null, "h");
 292     }
 293 
 294     @Test(expectedExceptions=NullPointerException.class)
 295     public void nullValueDisallowed8() {
 296         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 297                                           5, "f", 6, "g", 7, null);
 298     }
 299 
 300     @Test(expectedExceptions=NullPointerException.class)
 301     public void nullKeyDisallowed9() {
 302         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 303                                           5, "f", 6, "g", 7, "h", null, "i");
 304     }
 305 
 306     @Test(expectedExceptions=NullPointerException.class)
 307     public void nullValueDisallowed9() {
 308         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 309                                           5, "f", 6, "g", 7, "h", 8, null);
 310     }
 311 
 312     @Test(expectedExceptions=NullPointerException.class)
 313     public void nullKeyDisallowed10() {
 314         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 315                                           5, "f", 6, "g", 7, "h", 8, "i", null, "j");
 316     }
 317 
 318     @Test(expectedExceptions=NullPointerException.class)
 319     public void nullValueDisallowed10() {
 320         Map<Integer, String> map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e",
 321                                           5, "f", 6, "g", 7, "h", 8, "i", 9, null);
 322     }
 323 
 324     @Test(expectedExceptions=NullPointerException.class)
 325     public void nullKeyDisallowedN() {
 326         Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
 327         entries[0] = new AbstractMap.SimpleImmutableEntry(null, "a");
 328         Map<Integer, String> map = Map.ofEntries(entries);
 329     }
 330 
 331     @Test(expectedExceptions=NullPointerException.class)
 332     public void nullValueDisallowedN() {
 333         Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
 334         entries[0] = new AbstractMap.SimpleImmutableEntry(0, null);
 335         Map<Integer, String> map = Map.ofEntries(entries);
 336     }
 337 
 338     @Test(expectedExceptions=NullPointerException.class)
 339     public void nullEntryDisallowedN() {
 340         Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
 341         entries[5] = null;
 342         Map<Integer, String> map = Map.ofEntries(entries);
 343     }
 344 
 345     @Test(expectedExceptions=NullPointerException.class)
 346     public void nullArrayDisallowed() {
 347         Map.ofEntries(null);
 348     }
 349 
 350     @Test(dataProvider="all")
 351     public void serialEquality(Map<Integer, String> act, Map<Integer, String> exp) {
 352         // assume that act.equals(exp) tested elsewhere
 353         Map<Integer, String> copy = serialClone(act);
 354         assertEquals(act, copy);
 355         assertEquals(copy, exp);
 356     }
 357 
 358     @SuppressWarnings("unchecked")
 359     static <T> T serialClone(T obj) {
 360         try {
 361             ByteArrayOutputStream baos = new ByteArrayOutputStream();
 362             ObjectOutputStream oos = new ObjectOutputStream(baos);
 363             oos.writeObject(obj);
 364             oos.close();
 365             ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
 366             ObjectInputStream ois = new ObjectInputStream(bais);
 367             return (T) ois.readObject();
 368         } catch (IOException | ClassNotFoundException e) {
 369             throw new AssertionError(e);
 370         }
 371     }
 372 
 373     // Map.entry() tests
 374 
 375     @Test(expectedExceptions=NullPointerException.class)
 376     public void entryWithNullKeyDisallowed() {
 377         Map.Entry<Integer,String> e = Map.entry(null, "x");
 378     }
 379 
 380     @Test(expectedExceptions=NullPointerException.class)
 381     public void entryWithNullValueDisallowed() {
 382         Map.Entry<Integer,String> e = Map.entry(0, null);
 383     }
 384 
 385     @Test
 386     public void entryBasicTests() {
 387         Map.Entry<String,String> kvh1 = Map.entry("xyzzy", "plugh");
 388         Map.Entry<String,String> kvh2 = Map.entry("foobar", "blurfl");
 389         Map.Entry<String,String> sie = new AbstractMap.SimpleImmutableEntry("xyzzy", "plugh");
 390 
 391         assertTrue(kvh1.equals(sie));
 392         assertTrue(sie.equals(kvh1));
 393         assertFalse(kvh2.equals(sie));
 394         assertFalse(sie.equals(kvh2));
 395         assertEquals(sie.hashCode(), kvh1.hashCode());
 396         assertEquals(sie.toString(), kvh1.toString());
 397     }
 398 
 399     // compile-time test of wildcards
 400     @Test
 401     public void entryWildcardTests() {
 402         Map.Entry<Integer,Double> e1 = Map.entry(1, 2.0);
 403         Map.Entry<Float,Long> e2 = Map.entry(3.0f, 4L);
 404         Map<Number,Number> map = Map.ofEntries(e1, e2);
 405         assertEquals(map.size(), 2);
 406     }
 407 
 408 }