--- /dev/null 2013-02-26 17:16:58.251395135 +0400 +++ new/test/java/util/Collections/CollectionStress01.java 2013-02-27 17:23:39.299013289 +0400 @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2011, 2013, 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 + @summary + @summary com.apple.junit.java.util; + @run main CollectionStress01 + */ + +/* + + This test generates a field of boolean values, then uses recursive checks to + attempt to find a minimal set of rectangles that contain only the false values. + + Puts a fair bit of stress on the collection classes. + +*/ + +import junit.framework.*; + +import java.awt.*; +import java.util.*; + + +public class CollectionStress01 extends TestCase { + + static final boolean kDebug = false; + static final int kSeed = 12225; + static final int kPaintThreshold = 50000; + static final int kPauseTime = 5; + static final int kBooleanDensity = 25; + static final int kWidth = 32; + static final int kHeight = 36; + static final int kScale = 18; + static final Rectangle kBoolRect = new Rectangle( 0, 0, kWidth, kHeight); + static final Rectangle kDisplayRect = new Rectangle( 0, 0, kWidth*kScale, kHeight*kScale); + + boolean[][] boolSpace = new boolean[kWidth][kHeight]; + + Frame displayFrame = null; + DisplayArea displayArea = new DisplayArea(); + Random rand = new Random(kSeed); + + HashMap> cache = new HashMap> (); + + class DisplayArea extends Panel { + private static final long serialVersionUID = 1L; + Vector currEmpties; + Vector debugCases; + String debugInfo; + Rectangle currRect; + Point currPoint; + + public Dimension getPreferredSize() { + return ( new Dimension(kDisplayRect.width, kDisplayRect.height) ); + } + + public void paint( Graphics g){ + super.paint(g); + g.clearRect(0,0, kDisplayRect.width, kDisplayRect.height); + + // representation of boolean field + g.setColor( Color.RED ); + for(int i = 0; i < boolSpace.length; i+=1) { + for(int ii = 0; ii < boolSpace[i].length; ii+=1) { + if (boolSpace[i][ii]) { + g.fillRect(i*kScale, ii*kScale, kScale, kScale); + } + } + } + + // draw the currPoint + g.setColor( Color.BLUE ); + Point p = null; + synchronized (this) { + p = currPoint; + } + if (p != null) { + g.fillRect(p.x*kScale, p.y*kScale, kScale, kScale); + } + + // draw the debugCases + g.setColor( new Color( 0x40, 0xFF, 0x40, 0x80 )); + Vector dVect = null; + synchronized (this) { + dVect = debugCases; + } + if (dVect != null) { + for (Rectangle e : dVect) { + g.fillRoundRect((e.x*kScale)+1, (e.y*kScale)+1, (e.width*kScale)-2, (e.height*kScale) -2 , 15, 15); + } + } + + // draw the currEmpties + g.setColor( Color.CYAN); + Vector eVect = null; + synchronized (this) { + eVect = currEmpties; + } + if (eVect != null) { + for (Rectangle e : eVect) { + g.fillRoundRect((e.x*kScale)+1, (e.y*kScale)+1, (e.width*kScale)-2, (e.height*kScale) -2 , 15, 15); + } + } + + // draw the currRect + g.setColor( Color.BLACK ); + Rectangle r = null; + synchronized (this) { + r = currRect; + } + if (r != null) { + g.drawRect(r.x*kScale+2, r.y*kScale+2, r.width*kScale-4, r.height*kScale-4); + } + + // draw debugInfo at currPoint + g.setColor(Color.BLACK); + String d = null; + synchronized (this) { + d = debugInfo; + } + if (d != null) { + if ( p != null ) { + g.drawString(d, p.x*kScale, p.y*kScale+10); + } + else { + g.drawString(d, 5, 15); + } + } + } + + int paintCount = 0; + void tickle() { + if (paintCount > kPaintThreshold) { + paintCount = 0; + repaint(); + try { + Thread.sleep(kPauseTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + else { + paintCount +=1; + } + + } + + // setters which also (occasionally) redisplay + public void setCurrEmpties(Vector currEmpties) { + synchronized (this) { + this.currEmpties = currEmpties; + } + tickle(); + } + + public void setCurrPoint(Point currPoint) { + synchronized (this) { + this.currPoint = currPoint; + } + tickle(); + } + + public void setCurrRect(Rectangle currRect) { + synchronized (this) { + this.currRect = currRect; + } + tickle(); + } + + public void setDebugCases(Vector debugCases) { + synchronized (this) { + this.debugCases = debugCases; + } + tickle(); + } + + public void setDebugInfo(String debugInfo) { + synchronized (this) { + this.debugInfo = debugInfo; + } + tickle(); + } + + } + + protected void setUp() throws Exception { + super.setUp(); + displayFrame = new Frame(); + displayFrame.setLocation(10,10); + displayFrame.add( displayArea ); + displayFrame.pack(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + displayFrame.dispose(); + } + + public void xxtestSplit() throws Exception { + init(); + + assertNotNull(displayFrame); + displayFrame.setVisible(true); + + + for (int i = 0; i < 200; i+=1) { + int ww = rand.nextInt(1+kBoolRect.width); + int hh = rand.nextInt(1+kBoolRect.height); + int xx = rand.nextInt(1+kBoolRect.width-ww); + int yy = rand.nextInt(1+kBoolRect.height-hh); + + Rectangle probe = new Rectangle(xx, yy, ww, hh); + displayArea.setCurrRect(probe); + + Point p = split(probe); + displayArea.setCurrPoint(p); + displayArea.repaint(); + // Thread.sleep(1250); + } + + Thread.sleep(125); + } + + public void testSubRects() throws Exception { + init(); + + assertNotNull(displayFrame); + // displayFrame.setVisible(true); + + for (int i = 0; i < 10; i+=1) { + int x = kBoolRect.x + rand.nextInt( kBoolRect.width); + int y = kBoolRect.y + rand.nextInt( kBoolRect.height); + + Point p = new Point(x,y); + displayArea.setCurrPoint(p); + for (int kind =0; kind< 8; kind++) { + Vector caseRects = divideRectForSubcase(kBoolRect, p, kind); + displayArea.setDebugInfo( kind + " " + caseRects.size() ); + displayArea.setDebugCases(caseRects); + } + } + + displayArea.setCurrRect(kBoolRect); + displayArea.setDebugCases(null); + + Thread.sleep(125); + } + + public void testRecursiveStress() throws Exception { + init(); + + assertNotNull(displayFrame); + displayFrame.setVisible(true); + + Vector answer = findEmptyRects(kBoolRect, 0); + assertTrue( answer.size() < (kBoolRect.width * kBoolRect.height) ); + + //System.out.println(answer.size()); + + displayArea.setCurrPoint(null); + displayArea.setCurrRect(kBoolRect); + displayArea.setDebugCases(null); + displayArea.setCurrEmpties(answer); + displayArea.setDebugInfo( ""+ answer.size() ); + displayArea.repaint(); + + Thread.sleep(125); + } + + // initialize the boolean field to random values, and load 1,1 empties into cache + void init() { + for(int i = 0; i < boolSpace.length; i+=1) { + for(int ii = 0; ii < boolSpace[i].length; ii+=1) { + boolean val = (rand.nextInt(100)<= kBooleanDensity); + boolSpace[i][ii] = val; + + if (!val) { + Rectangle r = new Rectangle(i,ii,1,1); + Vector v = new Vector(); + v.add(r); + cache.put(r, v); + } + } + } + } + + // text display of boolean field + void displayRaw() { + System.out.println(); + for(int i = 0; i < boolSpace.length; i+=1) { + for(int ii = 0; ii < boolSpace[i].length; ii+=1) { + System.out.print( boolSpace[i][ii] ? " " : "X" ); + } + System.out.println(); + } + } + + + // return an OK fracture point, or null if rectangle is empty + // algorithm is correct for any fracture point, but will converge faster for central points + Point split(Rectangle r) { + Point result = null; + + int midx = r.x + r.width/2; + int midy = r.y + r.height/2; + int score = Integer.MAX_VALUE; + + for(int xoff = 0; (xoff < r.width); xoff+=1) { + for(int yoff = 0; (yoff < r.height); yoff+=1) { + int x = r.x + xoff; + int y = r.y + yoff; + displayArea.setCurrPoint( new Point(x,y)); + + if (boolSpace[x][y] ) { + int newscore = (x-midx)*(x-midx)+(y-midy)*(y-midy); + if (newscore < score) { + score = newscore; + result = new Point(x,y); + } + } + } + } + + return result; + } + + Vector findEmptyRects( Rectangle r, int depth) throws Exception { + debug( depth, "findEmptyRects " + show(r)); + displayArea.setCurrEmpties(null); + displayArea.setCurrRect(r); + + if (r.width <= 0 || r.height <= 0) { + debug( depth, "Unexpected rectagle :" + r); + return null ; + } + + if ( cache.containsKey(r) ) { + debug( depth, "C :" + show(r) + "--" + show( cache.get(r))); + return cache.get(r); + } + + if (r.width == 1 && r.height == 1) { + debug( depth, "F :" + show(r) + "--"); + assertTrue( boolSpace[r.x][r.y]); + return null; + } + + // figure it out recursively + Vector empties = new Vector(); + + Point p = split( r ); + displayArea.setCurrPoint(p); + + if (p == null) { + debug( depth, "S :" + show(r) + "--" + show(r)); + empties.add(r); + } + else { + debug( depth, "point :" + p.x + " "+ p.y); + + Vector bestEmpties = null; + // iterate through the 8 possible cases + for (int kind =0; kind< 8; kind++) { + debug( depth, "case :" + kind); + Vector caseRects = divideRectForSubcase(r, p, kind); + displayArea.setCurrRect(r); + displayArea.setCurrEmpties(null); + displayArea.setDebugInfo(""+caseRects.size()); + displayArea.setDebugCases(caseRects); + + Vector caseEmpties = new Vector(); + for ( Rectangle caseRect : caseRects) { + Vector subEmpties = findEmptyRects( caseRect, depth+1 ); + if (subEmpties != null) { + caseEmpties.addAll(subEmpties); + } + } + displayArea.setCurrEmpties(caseEmpties); + debug( depth, "totals :" + caseEmpties.size()); + + + if ( (bestEmpties == null) || (bestEmpties.size() > caseEmpties.size())) { + debug( depth, "new best! :" + caseEmpties.size()); + displayArea.setCurrEmpties(caseEmpties); + bestEmpties = caseEmpties; + } + + if (caseRects.size() <= 2) { + break; // simple case, so exit early + } + } + + debug(depth, "R : " + r + "--"+show(bestEmpties)); + empties = bestEmpties; + + } + + cache.put(r, empties); + return empties; + } + + + Vector divideRectForSubcase(Rectangle r, Point p, int i ) { + Vector fullCase = new Vector(); + + int topHeight = p.y - r.y; + int botHeight = (r.height - topHeight) -1; + int leftWidth = p.x - r.x; + int rightWidth = (r.width - leftWidth) -1; + + switch(i) { + case 0: + fullCase.add(new Rectangle( r.x, r.y, r.width, topHeight)); + fullCase.add(new Rectangle( r.x, p.y+1, r.width, botHeight)); + fullCase.add(new Rectangle( r.x, p.y, leftWidth, 1)); + fullCase.add(new Rectangle( p.x+1, p.y, rightWidth, 1)); + break; + case 1: + fullCase.add(new Rectangle( r.x, r.y, leftWidth, r.height)); + fullCase.add(new Rectangle( p.x, r.y, 1, topHeight)); + fullCase.add(new Rectangle( p.x+1, r.y, rightWidth, r.height)); + fullCase.add(new Rectangle( p.x, p.y+1, 1, botHeight)); + break; + case 2: + fullCase.add(new Rectangle( r.x, r.y, leftWidth, topHeight+1)); + fullCase.add(new Rectangle( p.x, r.y, 1, topHeight)); + fullCase.add(new Rectangle( r.x, p.y+1, r.width, botHeight)); + fullCase.add(new Rectangle( p.x+1, r.y, rightWidth, topHeight+1)); + break; + case 3: + fullCase.add(new Rectangle( r.x, r.y, leftWidth, r.height)); + fullCase.add(new Rectangle( p.x, r.y, rightWidth+1, topHeight)); + fullCase.add(new Rectangle( p.x, p.y+1, rightWidth+1, botHeight)); + fullCase.add(new Rectangle( p.x+1, p.y, rightWidth, 1)); + break; + case 4: + fullCase.add(new Rectangle( r.x, r.y, r.width, topHeight)); + fullCase.add(new Rectangle( r.x, p.y, leftWidth, botHeight+1)); + fullCase.add(new Rectangle( p.x, p.y+1, 1, botHeight)); + fullCase.add(new Rectangle( p.x+1, p.y, rightWidth, botHeight+1)); + break; + case 5: + fullCase.add(new Rectangle( r.x, r.y, leftWidth+1, topHeight)); + fullCase.add(new Rectangle( r.x, p.y, leftWidth, 1)); + fullCase.add(new Rectangle( r.x, p.y+1, leftWidth+1, botHeight)); + fullCase.add(new Rectangle( p.x+1, r.y, rightWidth, r.height)); + break; + case 6: + fullCase.add(new Rectangle( r.x, r.y, leftWidth+1, topHeight)); + fullCase.add(new Rectangle( r.x, p.y, leftWidth, botHeight+1)); + fullCase.add(new Rectangle( p.x, p.y+1, rightWidth+1, botHeight)); + fullCase.add(new Rectangle( p.x+1, r.y, rightWidth, topHeight+1)); + break; + case 7: + fullCase.add(new Rectangle( r.x, r.y, leftWidth, topHeight+1)); + fullCase.add(new Rectangle( r.x, p.y+1, leftWidth+1, botHeight)); + fullCase.add(new Rectangle( p.x, r.y, rightWidth+1, topHeight)); + fullCase.add(new Rectangle( p.x+1, p.y, rightWidth, botHeight+1)); + break; + /* ### note that there are 8! more cases.... ### */ + + default: + System.out.println("Unexpected case!"); break; + } + + + Vector result = new Vector(); + for (Rectangle rr : fullCase ) { + if (rr.width > 0 && rr.height > 0) { + result.add(rr); + } + } + return result; + + } + + // debugging utilities + static void debug( int depth, String s) { + if (kDebug) { + for(int i= 0; i rects) { + String result = "" + rects.size() + " "; + for( Rectangle r : rects) { + result = result + " " +show(r); + } + return result; + } + + + // boilerplate for running as a JUnit test + public static Test suite() { + return new TestSuite(CollectionStress01.class); + } + + public static void main (String[] args) throws RuntimeException { + TestResult tr = junit.textui.TestRunner.run(suite()); + if((tr.errorCount() != 0) || (tr.failureCount() != 0)) { + throw new RuntimeException("### Unexpected JUnit errors or failures."); + } + } +} +