Path: blob/master/test/jdk/java/util/List/LockStep.java
41152 views
/*1* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 635997926* @summary Compare List implementations for identical behavior27* @author Martin Buchholz28* @key randomness29*/3031import java.io.ByteArrayInputStream;32import java.io.ByteArrayOutputStream;33import java.io.IOException;34import java.io.InputStream;35import java.io.ObjectInputStream;36import java.io.ObjectOutputStream;37import java.util.ArrayList;38import java.util.Arrays;39import java.util.Collection;40import java.util.Collections;41import java.util.ConcurrentModificationException;42import java.util.Iterator;43import java.util.LinkedList;44import java.util.List;45import java.util.ListIterator;46import java.util.Random;47import java.util.Vector;4849@SuppressWarnings("unchecked")50public class LockStep {51final int DEFAULT_SIZE = 5;52int size; // Running time is O(size**2)5354int intArg(String[] args, int i, int defaultValue) {55return args.length > i ? Integer.parseInt(args[i]) : defaultValue;56}5758boolean maybe(int n) { return rnd.nextInt(n) == 0; }5960void test(String[] args) {61size = intArg(args, 0, DEFAULT_SIZE);6263lockSteps(new ArrayList(),64new LinkedList(),65new Vector());66}6768void equalLists(List... lists) {69for (List list : lists)70equalLists(list, lists[0]);71}7273void equalLists(List x, List y) {74equal(x, y);75equal(y, x);76equal(x.size(), y.size());77equal(x.isEmpty(), y.isEmpty());78equal(x.hashCode(), y.hashCode());79equal(x.toString(), y.toString());80equal(x.toArray(), y.toArray());81}8283void lockSteps(List... lists) {84for (int i = 0; i < lists.length; i++)85if (maybe(4)) lists[i] = serialClone(lists[i]);86for (final List list : lists)87testEmptyList(list);88for (int i = 0; i < size; i++) {89ListFrobber adder = randomAdder();90for (final List list : lists) {91adder.frob(list);92equal(list.size(), i+1);93}94equalLists(lists);95}96{97final ListFrobber adder = randomAdder();98final ListFrobber remover = randomRemover();99for (final List list : lists) {100101THROWS(ConcurrentModificationException.class,102new F(){void f(){103Iterator it = list.iterator();104adder.frob(list);105it.next();}},106new F(){void f(){107Iterator it = asSubList(list).iterator();108remover.frob(list);109it.next();}},110new F(){void f(){111Iterator it = asSubList(asSubList(list)).iterator();112adder.frob(list);113it.next();}},114new F(){void f(){115List subList = asSubList(list);116remover.frob(list);117subList.get(0);}},118new F(){void f(){119List sl = asSubList(list);120List ssl = asSubList(sl);121adder.frob(sl);122ssl.get(0);}},123new F(){void f(){124List sl = asSubList(list);125List ssl = asSubList(sl);126remover.frob(sl);127ssl.get(0);}});128}129}130131for (final List l : lists) {132final List sl = asSubList(l);133final List ssl = asSubList(sl);134ssl.add(0, 42);135equal(ssl.get(0), 42);136equal(sl.get(0), 42);137equal(l.get(0), 42);138final int s = l.size();139final int rndIndex = rnd.nextInt(l.size());140THROWS(IndexOutOfBoundsException.class,141new F(){void f(){l.subList(rndIndex, rndIndex).get(0);}},142new F(){void f(){l.subList(s/2, s).get(s/2 + 1);}},143new F(){void f(){l.subList(s/2, s).get(-1);}}144);145THROWS(IllegalArgumentException.class,146new F(){void f(){ l.subList(1, 0);}},147new F(){void f(){ sl.subList(1, 0);}},148new F(){void f(){ssl.subList(1, 0);}});149}150151equalLists(lists);152153for (final List list : lists) {154equalLists(list, asSubList(list));155equalLists(list, asSubList(asSubList(list)));156}157for (final List list : lists)158System.out.println(list);159160for (int i = lists[0].size(); i > 0; i--) {161ListFrobber remover = randomRemover();162for (final List list : lists)163remover.frob(list);164equalLists(lists);165}166}167168<T> List<T> asSubList(List<T> list) {169return list.subList(0, list.size());170}171172void testEmptyCollection(Collection<?> c) {173check(c.isEmpty());174equal(c.size(), 0);175equal(c.toString(),"[]");176equal(c.toArray().length, 0);177equal(c.toArray(new Object[0]).length, 0);178179Object[] a = new Object[1]; a[0] = Boolean.TRUE;180equal(c.toArray(a), a);181equal(a[0], null);182}183184void testEmptyList(List list) {185testEmptyCollection(list);186equal(list.hashCode(), 1);187equal(list, Collections.emptyList());188}189190final Random rnd = new Random();191192abstract class ListFrobber { abstract void frob(List l); }193194ListFrobber randomAdder() {195final Integer e = rnd.nextInt(1024);196final int subListCount = rnd.nextInt(3);197final boolean atBeginning = rnd.nextBoolean();198final boolean useIterator = rnd.nextBoolean();199final boolean simpleIterator = rnd.nextBoolean();200return new ListFrobber() {void frob(List l) {201final int s = l.size();202List ll = l;203for (int i = 0; i < subListCount; i++)204ll = asSubList(ll);205if (! useIterator) {206if (atBeginning) {207switch (rnd.nextInt(3)) {208case 0: ll.add(0, e); break;209case 1: ll.subList(0, rnd.nextInt(s+1)).add(0, e); break;210case 2: ll.subList(0, rnd.nextInt(s+1)).subList(0,0).add(0,e); break;211default: throw new Error();212}213} else {214switch (rnd.nextInt(3)) {215case 0: check(ll.add(e)); break;216case 1: ll.subList(s/2, s).add(s - s/2, e); break;217case 2: ll.subList(s, s).subList(0, 0).add(0, e); break;218default: throw new Error();219}220}221} else {222if (atBeginning) {223ListIterator it = ll.listIterator();224equal(it.nextIndex(), 0);225check(! it.hasPrevious());226it.add(e);227equal(it.previousIndex(), 0);228equal(it.nextIndex(), 1);229check(it.hasPrevious());230} else {231final int siz = ll.size();232ListIterator it = ll.listIterator(siz);233equal(it.previousIndex(), siz-1);234check(! it.hasNext());235it.add(e);236equal(it.previousIndex(), siz);237equal(it.nextIndex(), siz+1);238check(! it.hasNext());239check(it.hasPrevious());240}241}}};242}243244ListFrobber randomRemover() {245final int position = rnd.nextInt(3);246final int subListCount = rnd.nextInt(3);247return new ListFrobber() {void frob(List l) {248final int s = l.size();249List ll = l;250for (int i = 0; i < subListCount; i++)251ll = asSubList(ll);252switch (position) {253case 0: // beginning254switch (rnd.nextInt(3)) {255case 0: ll.remove(0); break;256case 1: {257final Iterator it = ll.iterator();258check(it.hasNext());259THROWS(IllegalStateException.class,260new F(){void f(){it.remove();}});261it.next();262it.remove();263THROWS(IllegalStateException.class,264new F(){void f(){it.remove();}});265break;}266case 2: {267final ListIterator it = ll.listIterator();268check(it.hasNext());269THROWS(IllegalStateException.class,270new F(){void f(){it.remove();}});271it.next();272it.remove();273THROWS(IllegalStateException.class,274new F(){void f(){it.remove();}});275break;}276default: throw new Error();277}278break;279case 1: // midpoint280switch (rnd.nextInt(3)) {281case 0: ll.remove(s/2); break;282case 1: {283final ListIterator it = ll.listIterator(s/2);284it.next();285it.remove();286break;287}288case 2: {289final ListIterator it = ll.listIterator(s/2+1);290it.previous();291it.remove();292break;293}294default: throw new Error();295}296break;297case 2: // end298switch (rnd.nextInt(3)) {299case 0: ll.remove(s-1); break;300case 1: ll.subList(s-1, s).clear(); break;301case 2:302final ListIterator it = ll.listIterator(s);303check(! it.hasNext());304check(it.hasPrevious());305THROWS(IllegalStateException.class,306new F(){void f(){it.remove();}});307it.previous();308equal(it.nextIndex(), s-1);309check(it.hasNext());310it.remove();311equal(it.nextIndex(), s-1);312check(! it.hasNext());313THROWS(IllegalStateException.class,314new F(){void f(){it.remove();}});315break;316default: throw new Error();317}318break;319default: throw new Error();320}}};321}322323//--------------------- Infrastructure ---------------------------324volatile int passed = 0, failed = 0;325void pass() {passed++;}326void fail() {failed++; Thread.dumpStack();}327void fail(String msg) {System.err.println(msg); fail();}328void unexpected(Throwable t) {failed++; t.printStackTrace();}329void check(boolean cond) {if (cond) pass(); else fail();}330void equal(Object x, Object y) {331if (x == null ? y == null : x.equals(y)) pass();332else fail(x + " not equal to " + y);}333<T> void equal(T[] x, T[] y) {check(Arrays.equals(x,y));}334public static void main(String[] args) throws Throwable {335new LockStep().instanceMain(args);}336void instanceMain(String[] args) throws Throwable {337try {test(args);} catch (Throwable t) {unexpected(t);}338System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);339if (failed > 0) throw new AssertionError("Some tests failed");}340abstract class F {abstract void f() throws Throwable;}341void THROWS(Class<? extends Throwable> k, F... fs) {342for (F f : fs)343try {f.f(); fail("Expected " + k.getName() + " not thrown");}344catch (Throwable t) {345if (k.isAssignableFrom(t.getClass())) pass();346else unexpected(t);}}347static byte[] serializedForm(Object obj) {348try {349ByteArrayOutputStream baos = new ByteArrayOutputStream();350new ObjectOutputStream(baos).writeObject(obj);351return baos.toByteArray();352} catch (IOException e) { throw new RuntimeException(e); }}353static Object readObject(byte[] bytes)354throws IOException, ClassNotFoundException {355InputStream is = new ByteArrayInputStream(bytes);356return new ObjectInputStream(is).readObject();}357@SuppressWarnings("unchecked")358static <T> T serialClone(T obj) {359try { return (T) readObject(serializedForm(obj)); }360catch (Exception e) { throw new RuntimeException(e); }}361}362363364