--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/Collection/RandomizedIteration.java Fri May 25 11:18:22 2018 -0700
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8201518
+ * @key randomness
+ * @summary Ensure that randomized iteration order of unmodifiable sets
+ * and maps is actually randomized. Must be run othervm so that
+ * the per-VM-instance salt value differs.
+ * @run main/othervm RandomizedIteration 0
+ * @run main/othervm RandomizedIteration 1
+ * @run main/othervm RandomizedIteration 2
+ * @run main/othervm RandomizedIteration 3
+ * @run main/othervm RandomizedIteration 4
+ * @run main/othervm RandomizedIteration verify 5
+ */
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static java.util.stream.Collectors.toUnmodifiableMap;
+
+/**
+ * Test of randomized iteration of unmodifiable sets and maps.
+ *
+ * Usage: RandomizedIteration n
+ * - writes files suffixed with 'n' containing set elements and map keys
+ * in iteration order
+ * RandomizedIteration "verify" count
+ * - reads files 0..count-1 and checks to ensure that their orders differ
+ *
+ * The idea is to generate several test files by invoking this test with an arg
+ * of 0 through count-1. Then invoke the test once more with two args, the first being
+ * the word "verify" and the second arg being the count. This will read all the generated
+ * files and perform verification.
+ *
+ * The test is considered to pass if any of the runs result in different iteration
+ * orders. The randomization is not actually very random, so over many runs there is
+ * the possibility of a couple of the test files having the same order. That's ok, as
+ * long as the iteration order is usually different. The test fails if *all* of the
+ * iteration orders are the same.
+ */
+public class RandomizedIteration {
+ /**
+ * Generates a set and a map from the word array, and then writes
+ * text files "set.#" and "map.#" containing the set elements and
+ * map keys in iteration order.
+ *
+ * @param suffix number used for the file suffix
+ */
+ static void writeFiles(int suffix) throws IOException {
+ try (PrintStream setOut = new PrintStream("set." + suffix)) {
+ Set.of(WORDS)
+ .forEach(setOut::println);
+ }
+
+ try (PrintStream mapOut = new PrintStream("map." + suffix)) {
+ var map = Map.ofEntries(Arrays.stream(WORDS)
+ .map(word -> Map.entry(word, ""))
+ .toArray(Map.Entry<?, ?>[]::new));
+ map.keySet()
+ .forEach(mapOut::println);
+ }
+ }
+
+ /**
+ * Reads lines from each file derived from the prefix and index from 0..count-1
+ * into a list, computes its hashcode, and returns a set of those hashcodes.
+ * The hashcode of the list is order sensitive, so the same lines in a different
+ * order should have different hashcodes.
+ *
+ * @param prefix the file prefix
+ * @param count the number of files to read
+ * @return a set of hashcodes of each file
+ */
+ static Set<Integer> readFiles(String prefix, int count) throws IOException {
+ Set<Integer> hashes = new HashSet<>();
+ for (int suffix = 0; suffix < count; suffix++) {
+ String name = prefix + suffix;
+ int hash = Files.readAllLines(Paths.get(name)).hashCode();
+ System.out.println(name + ": " + hash);
+ hashes.add(hash);
+ }
+ return hashes;
+ }
+
+ /**
+ * Test main routine.
+ *
+ * @param args n | "verify" count
+ * @throws IOException if an error occurred
+ */
+ public static void main(String[] args) throws IOException {
+ if ("verify".equals(args[0])) {
+ int count = Integer.parseInt(args[1]);
+ System.out.println("Verifying " + count + " files.");
+ Set<Integer> setHashes = readFiles("set.", count);
+ Set<Integer> mapHashes = readFiles("map.", count);
+ if (setHashes.size() > 1 && mapHashes.size() > 1) {
+ System.out.println("Passed: differing iteration orders were detected.");
+ } else {
+ throw new AssertionError("FAILED: iteration order not randomized!");
+ }
+ } else {
+ int suffix = Integer.parseInt(args[0]);
+ System.out.println("Generating files: " + suffix);
+ writeFiles(suffix);
+ }
+ }
+
+ /**
+ * List of 63 words of 22 or more letters from BSD /usr/share/dict/words.
+ */
+ static final String[] WORDS = {
+ "anatomicophysiological",
+ "anthropomorphologically",
+ "aquopentamminecobaltic",
+ "blepharoconjunctivitis",
+ "blepharosphincterectomy",
+ "cholecystenterorrhaphy",
+ "cholecystoduodenostomy",
+ "choledochoduodenostomy",
+ "counterexcommunication",
+ "dacryocystoblennorrhea",
+ "dacryocystosyringotomy",
+ "deanthropomorphization",
+ "duodenocholecystostomy",
+ "electroencephalography",
+ "electrotelethermometer",
+ "epididymodeferentectomy",
+ "formaldehydesulphoxylate",
+ "formaldehydesulphoxylic",
+ "gastroenteroanastomosis",
+ "hematospectrophotometer",
+ "hexamethylenetetramine",
+ "hexanitrodiphenylamine",
+ "historicocabbalistical",
+ "hydropneumopericardium",
+ "hyperconscientiousness",
+ "laparocolpohysterotomy",
+ "lymphangioendothelioma",
+ "macracanthrorhynchiasis",
+ "microcryptocrystalline",
+ "naphthylaminesulphonic",
+ "nonrepresentationalism",
+ "omnirepresentativeness",
+ "pancreaticoduodenostomy",
+ "pancreaticogastrostomy",
+ "pathologicohistological",
+ "pathologicopsychological",
+ "pericardiomediastinitis",
+ "phenolsulphonephthalein",
+ "philosophicohistorical",
+ "philosophicotheological",
+ "photochronographically",
+ "photospectroheliograph",
+ "pneumohydropericardium",
+ "pneumoventriculography",
+ "polioencephalomyelitis",
+ "Prorhipidoglossomorpha",
+ "Pseudolamellibranchiata",
+ "pseudolamellibranchiate",
+ "pseudomonocotyledonous",
+ "pyopneumocholecystitis",
+ "scientificogeographical",
+ "scientificophilosophical",
+ "scleroticochorioiditis",
+ "stereophotomicrography",
+ "tetraiodophenolphthalein",
+ "theologicoastronomical",
+ "theologicometaphysical",
+ "thymolsulphonephthalein",
+ "thyroparathyroidectomize",
+ "thyroparathyroidectomy",
+ "transubstantiationalist",
+ "ureterocystanastomosis",
+ "zoologicoarchaeologist"
+ };
+}