/* * Copyright (c) 2006, 2014, 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 6415641 6377302 * @summary Concurrent collections are permitted to lie about their size * @author Martin Buchholz */ import java.io.*; import java.util.*; import java.util.concurrent.*; @SuppressWarnings("unchecked") public class BiggernYours { static final Random rnd = new Random(18675309); static void compareCollections(Collection c1, Collection c2) { Object[] c1Array = c1.toArray(); Object[] c2Array = c2.toArray(); check(c1Array.length == c2Array.length); for(Object aC1 : c1Array) { boolean found = false; for(Object aC2 : c2Array) { if(Objects.equals(aC1, aC2)) { found = true; break; } } if(!found) fail(aC1 + " not found in " + Arrays.toString(c2Array)); } } static void compareMaps(Map m1, Map m2) { compareCollections(m1.keySet(), m2.keySet()); compareCollections(m1.values(), m2.values()); compareCollections(m1.entrySet(), m2.entrySet()); } static void compareNavigableMaps(NavigableMap m1, NavigableMap m2) { compareMaps(m1, m2); compareMaps(m1.descendingMap(), m2.descendingMap()); compareMaps(m1.tailMap(Integer.MIN_VALUE), m2.tailMap(Integer.MIN_VALUE)); compareMaps(m1.headMap(Integer.MAX_VALUE), m2.headMap(Integer.MAX_VALUE)); } static void compareNavigableSets(NavigableSet s1, NavigableSet s2) { compareCollections(s1, s2); compareCollections(s1.descendingSet(), s2.descendingSet()); compareCollections(s1.tailSet(Integer.MIN_VALUE), s2.tailSet(Integer.MIN_VALUE)); } static abstract class MapFrobber { abstract void frob(Map m); } static abstract class SetFrobber { abstract void frob(Set s); } static abstract class ColFrobber { abstract void frob(Collection c); } static ColFrobber adder(final int i) { return new ColFrobber() {void frob(Collection c) { c.add(i); }}; } static final ColFrobber[] adders = { adder(1), adder(3), adder(2) }; static MapFrobber putter(final int k, final int v) { return new MapFrobber() {void frob(Map m) { m.put(k,v); }}; } static final MapFrobber[] putters = { putter(1, -2), putter(3, -6), putter(2, -4) }; static void unexpected(Throwable t, Object suspect) { System.out.println(suspect.getClass()); unexpected(t); } static void testCollections(Collection c1, Collection c2) { try { compareCollections(c1, c2); for (ColFrobber adder : adders) { for (Collection c : new Collection[]{c1, c2}) adder.frob(c); compareCollections(c1, c2); } } catch (Throwable t) { unexpected(t, c1); } } static void testNavigableSets(NavigableSet s1, NavigableSet s2) { try { compareNavigableSets(s1, s2); for (ColFrobber adder : adders) { for (Set s : new Set[]{s1, s2}) adder.frob(s); compareNavigableSets(s1, s2); } } catch (Throwable t) { unexpected(t, s1); } } static void testMaps(Map m1, Map m2) { try { compareMaps(m1, m2); for (MapFrobber putter : putters) { for (Map m : new Map[]{m1, m2}) putter.frob(m); compareMaps(m1, m2); } } catch (Throwable t) { unexpected(t, m1); } } static void testNavigableMaps(NavigableMap m1, NavigableMap m2) { try { compareNavigableMaps(m1, m2); for (MapFrobber putter : putters) { for (Map m : new Map[]{m1, m2}) putter.frob(m); compareNavigableMaps(m1, m2); } } catch (Throwable t) { unexpected(t, m1); } } static int randomize(int size) { return rnd.nextInt(size + 2); } @SuppressWarnings("serial") private static void realMain(String[] args) throws Throwable { testNavigableMaps( new ConcurrentSkipListMap(), new ConcurrentSkipListMap() { public int size() {return randomize(super.size());}}); testNavigableSets( new ConcurrentSkipListSet(), new ConcurrentSkipListSet() { public int size() {return randomize(super.size());}}); testCollections( new CopyOnWriteArraySet(), new CopyOnWriteArraySet() { public int size() {return randomize(super.size());}}); testCollections( new CopyOnWriteArrayList(), new CopyOnWriteArrayList() { public int size() {return randomize(super.size());}}); testCollections( new TreeSet(), new TreeSet() { public int size() {return randomize(super.size());}}); testMaps( new ConcurrentHashMap(), new ConcurrentHashMap() { public int size() {return randomize(super.size());}}); testCollections( new ConcurrentLinkedDeque(), new ConcurrentLinkedDeque() { public int size() {return randomize(super.size());}}); testCollections( new ConcurrentLinkedQueue(), new ConcurrentLinkedQueue() { public int size() {return randomize(super.size());}}); testCollections( new LinkedTransferQueue(), new LinkedTransferQueue() { public int size() {return randomize(super.size());}}); testCollections( new LinkedBlockingQueue(), new LinkedBlockingQueue() { public int size() {return randomize(super.size());}}); testCollections( new LinkedBlockingDeque(), new LinkedBlockingDeque() { public int size() {return randomize(super.size());}}); testCollections( new ArrayBlockingQueue(5), new ArrayBlockingQueue(5) { public int size() {return randomize(super.size());}}); testCollections( new PriorityBlockingQueue(5), new PriorityBlockingQueue(5) { public int size() {return randomize(super.size());}}); } //--------------------- Infrastructure --------------------------- static volatile int passed = 0, failed = 0; static void pass() {passed++;} static void fail() {failed++; Thread.dumpStack();} static void fail(String msg) {System.out.println(msg); fail();} static void unexpected(Throwable t) {failed++; t.printStackTrace();} static void check(boolean cond) {if (cond) pass(); else fail();} static void equal(Object x, Object y) { if (x == null ? y == null : x.equals(y)) pass(); else fail(x + " not equal to " + y);} static void arrayEqual(Object[] x, Object[] y) { if (x == null ? y == null : Arrays.equals(x, y)) pass(); else fail(Arrays.toString(x) + " not equal to " + Arrays.toString(y));} public static void main(String[] args) throws Throwable { try {realMain(args);} catch (Throwable t) {unexpected(t);} System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); if (failed > 0) throw new AssertionError("Some tests failed");} private static abstract class CheckedThread extends Thread { abstract void realRun() throws Throwable; public void run() { try {realRun();} catch (Throwable t) {unexpected(t);}}} }