1 /* 2 * Copyright (c) 2019, 2024, 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.util.ArrayList; 25 import java.util.Arrays; 26 import java.util.Collection; 27 import java.util.HashMap; 28 import java.util.HashSet; 29 import java.util.LinkedHashMap; 30 import java.util.LinkedHashSet; 31 import java.util.List; 32 import java.util.Map; 33 import java.util.stream.LongStream; 34 35 /* 36 * @test 37 * @bug 8336669 38 * @summary HashMap.toArray() behavior tests 39 * @author tvaleev 40 */ 41 public class ToArray { 42 // An interned identity class holding an int (like non-Preview Integer) 43 record Int(int intValue) implements Comparable<Int> { 44 @Override 45 public int compareTo(Int o) { 46 return Integer.compare(intValue, o.intValue); 47 } 48 } 49 50 public static void main(String[] args) { 51 checkMap(false); 52 checkMap(true); 53 checkSet(false); 54 checkSet(true); 55 } 56 57 private static <T extends Comparable<T>> void checkToArray(String message, T[] expected, Collection<T> collection, 58 boolean ignoreOrder) { 59 if (ignoreOrder) { 60 Arrays.sort(expected); 61 } 62 checkToObjectArray(message, expected, collection, ignoreOrder); 63 checkToTypedArray(message, expected, Arrays.copyOf(expected, 0), collection, ignoreOrder); 64 checkToTypedArray(message, expected, expected.clone(), collection, ignoreOrder); 65 if (expected.length > 0) { 66 T[] biggerArray = Arrays.copyOf(expected, expected.length * 2); 67 System.arraycopy(expected, 0, biggerArray, expected.length, expected.length); 68 checkToTypedArray(message, expected, biggerArray, collection, ignoreOrder); 69 } 70 } 71 72 private static <T extends Comparable<T>> void checkToTypedArray(String message, T[] expected, T[] inputArray, 73 Collection<T> collection, boolean ignoreOrder) { 74 T[] res = collection.toArray(inputArray); 75 if (expected.length <= inputArray.length && res != inputArray) { 76 throw new AssertionError(message + ": not the same array returned"); 77 } 78 if (res.getClass() != expected.getClass()) { 79 throw new AssertionError(message + ": wrong class returned: " + res.getClass()); 80 } 81 if (res.length < expected.length) { 82 throw new AssertionError(message + ": length is smaller than expected: " + res.length + " < " + expected.length); 83 } 84 if (ignoreOrder) { 85 Arrays.sort(res, 0, Math.min(res.length, expected.length)); 86 } 87 if (inputArray.length <= expected.length) { 88 if (!Arrays.equals(res, expected)) { 89 throw new AssertionError(message + ": not equal: " + Arrays.toString(expected) + " != " + 90 Arrays.toString(res)); 91 } 92 } else { 93 int mismatch = Arrays.mismatch(expected, res); 94 if (mismatch != expected.length) { 95 throw new AssertionError(message + ": mismatch at " + mismatch); 96 } 97 if (res[expected.length] != null) { 98 throw new AssertionError(message + ": no null at position " + expected.length); 99 } 100 // The tail of bigger array after expected.length position must be untouched 101 mismatch = Arrays 102 .mismatch(expected, 1, expected.length, res, expected.length + 1, res.length); 103 if (mismatch != -1) { 104 throw new AssertionError(message + ": mismatch at " + mismatch); 105 } 106 } 107 } 108 109 private static <T extends Comparable<T>> void checkToObjectArray(String message, T[] expected, 110 Collection<T> collection, boolean ignoreOrder) { 111 Object[] objects = collection.toArray(); 112 if (objects.getClass() != Object[].class) { 113 throw new AssertionError(message + ": wrong class returned: " + objects.getClass()); 114 } 115 if (ignoreOrder) { 116 Arrays.sort(objects); 117 } 118 int mismatch = Arrays.mismatch(expected, objects); 119 if (mismatch != -1) { 120 throw new AssertionError(message + ": mismatch at " + mismatch); 121 } 122 } 123 124 private static void checkMap(boolean ordered) { 125 Map<String, String> map = ordered ? new LinkedHashMap<>() : new HashMap<>(); 126 checkToArray("Empty-keys", new String[0], map.keySet(), !ordered); 127 checkToArray("Empty-values", new String[0], map.values(), !ordered); 128 129 List<String> keys = new ArrayList<>(); 130 List<String> values = new ArrayList<>(); 131 for (int i = 0; i < 100; i++) { 132 keys.add(String.valueOf(i)); 133 values.add(String.valueOf(i * 2)); 134 map.put(String.valueOf(i), String.valueOf(i * 2)); 135 checkToArray(i + "-keys", keys.toArray(new String[0]), map.keySet(), !ordered); 136 checkToArray(i + "-values", values.toArray(new String[0]), map.values(), !ordered); 137 } 138 map.clear(); 139 checkToArray("Empty-keys", new String[0], map.keySet(), !ordered); 140 checkToArray("Empty-values", new String[0], map.values(), !ordered); 141 } 142 143 private static void checkSet(boolean ordered) { 144 Collection<String> set = ordered ? new LinkedHashSet<>() : new HashSet<>(); 145 checkToArray("Empty", new String[0], set, !ordered); 146 set.add("foo"); 147 checkToArray("One", new String[]{"foo"}, set, !ordered); 148 set.add("bar"); 149 checkToArray("Two", new String[]{"foo", "bar"}, set, !ordered); 150 151 Collection<Long> longSet = ordered ? new LinkedHashSet<>() : new HashSet<>(); 152 for (int x = 0; x < 100; x++) { 153 longSet.add((long) x); 154 } 155 checkToArray("100", LongStream.range(0, 100).boxed().toArray(Long[]::new), longSet, !ordered); 156 longSet.clear(); 157 checkToArray("After clear", new Long[0], longSet, !ordered); 158 for (int x = 0; x < 100; x++) { 159 longSet.add(((long) x) | (((long) x) << 32)); 160 } 161 checkToArray("Collisions", LongStream.range(0, 100).mapToObj(x -> x | (x << 32)) 162 .toArray(Long[]::new), longSet, !ordered); 163 } 164 }