--- /dev/null 2015-03-27 09:29:21.329177995 +0100 +++ new/test/java/awt/geom/Path2D/Path2DEmpty.java 2015-03-27 16:31:25.984793287 +0100 @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2015, 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. + */ + + +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.IllegalPathStateException; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +/** + * @summary Check Path2D constructor with zero capacity + * @run main Path2DTrimCopy + */ +public class Path2DEmpty { + + private final static float EPSILON = 5e-6f; + private final static float FLATNESS = 1e-2f; + + private final static AffineTransform at + = AffineTransform.getScaleInstance(1.3, 2.4); + + private final static Rectangle2D.Double rect2d + = new Rectangle2D.Double(3.2, 4.1, 5.0, 10.0); + + private final static Point2D.Double pt2d + = new Point2D.Double(2.0, 2.5); + + public static void main(String[] args) { + testDoublePaths(); + + testFloatPaths(); + testGeneralPath(); + } + + static void testDoublePaths() { + System.out.println("\n - Test(Path2D.Double) ---"); + test(() -> new Path2D.Double(Path2D.WIND_NON_ZERO, 0)); + } + + static void testFloatPaths() { + System.out.println("\n - Test(Path2D.Float) ---"); + test(() -> new Path2D.Float(Path2D.WIND_NON_ZERO, 0)); + } + + static void testGeneralPath() { + System.out.println("\n - Test(GeneralPath) ---"); + test(() -> new GeneralPath(Path2D.WIND_NON_ZERO, 0)); + } + + interface PathFactory { + + Path2D makePath(); + } + + /** + - Perform each of the above tests on a (set of) clone(s) of the following paths: + - each of the following executed on both a Float and a Double instance... + - an empty path + - a path with just a moveto + - a path with a moveto+some lines + - a path with a moveto+some curves + */ + static void test(PathFactory pf) { + System.out.println("\n --- test: path(empty) ---"); + test(pf.makePath(), true); + } + + static Path2D addMove(Path2D p2d) { + p2d.moveTo(1.0, 0.5); + return p2d; + } + + static Path2D addLinesOnly(Path2D p2d) { + for (int i = 0; i < 10; i++) { + p2d.lineTo(1.1 * i, 2.3 * i); + } + return p2d; + } + + static Path2D addCurvesOnly(Path2D p2d) { + for (int i = 0; i < 10; i++) { + p2d.quadTo(1.1 * i, 1.2 * i, 1.3 * i, 1.4 * i); + p2d.curveTo(1.1 * i, 1.2 * i, 1.3 * i, 1.4 * i, 1.5 * i, 1.6 * i); + } + return p2d; + } + + /** + - Write tests that create paths in various forms and run them through the following sub-tests: + - each of the following should be tested on a fresh clone... + - get a PathIterator and iterate it through until it is done + (optional - compare to the expected segments that were in the original) + - get a flattened PathIterator using "getPathIterator(flatness,)" and make sure it works + (optional - compare to original path if the original was already flat) + (but, also run it on a path with curves to make sure flattening engine didn't break) + - add various kinds of segments to the cloned path + - get the bounds of the cloned path + - use the transform() method on the cloned path + - call intersects(point), intersects(rect) and contains(rect) on a cloned path + - call getCurrentPoint() on the cloned path + */ + static void test(Path2D p2d, boolean isEmpty) { + testEqual(new Path2D.Float(p2d), p2d); + testEqual(new Path2D.Double(p2d), p2d); + testEqual(new GeneralPath(p2d), p2d); + + // 3 clone variants: + testIterator(new Path2D.Float(p2d), p2d); + testIterator(new Path2D.Double(p2d), p2d); + testIterator((Path2D) p2d.clone(), p2d); + + // 3 clone variants: + testFlattening(new Path2D.Float(p2d), p2d); + testFlattening(new Path2D.Double(p2d), p2d); + testFlattening((Path2D) p2d.clone(), p2d); + + // 3 clone variants: + testAddMove(new Path2D.Float(p2d)); + testAddMove(new Path2D.Double(p2d)); + testAddMove((Path2D) p2d.clone()); + + // These should expect exception if empty + // 3 clone variants: + testAddLine(new Path2D.Float(p2d), isEmpty); + testAddLine(new Path2D.Double(p2d), isEmpty); + testAddLine((Path2D) p2d.clone(), isEmpty); + + // 3 clone variants: + testAddQuad(new Path2D.Float(p2d), isEmpty); + testAddQuad(new Path2D.Double(p2d), isEmpty); + testAddQuad((Path2D) p2d.clone(), isEmpty); + + // 3 clone variants: + testGetBounds(new Path2D.Float(p2d), p2d); + testGetBounds(new Path2D.Double(p2d), p2d); + testGetBounds((Path2D) p2d.clone(), p2d); + + // 3 clone variants: + testTransform(new Path2D.Float(p2d)); + testTransform(new Path2D.Double(p2d)); + testTransform((Path2D) p2d.clone()); + + final boolean doTestThatFail = true; + + // FAILS JDK8 + if (doTestThatFail) { + // 3 clone variants: + testIntersect(new Path2D.Float(p2d), p2d); + testIntersect(new Path2D.Double(p2d), p2d); + testIntersect((Path2D) p2d.clone(), p2d); + } + + // FAILS JDK8 + if (doTestThatFail) { + // 3 clone variants: + testContains(new Path2D.Float(p2d), p2d); + testContains(new Path2D.Double(p2d), p2d); + testContains((Path2D) p2d.clone(), p2d); + } + + // 3 clone variants: + testGetCurrentPoint(new Path2D.Float(p2d), p2d); + testGetCurrentPoint(new Path2D.Double(p2d), p2d); + testGetCurrentPoint((Path2D) p2d.clone(), p2d); + + // TODO: add all other public methods ? + /* + public abstract void append(PathIterator pi, boolean connect) + public final synchronized void closePath() + */ + } + + static void testEqual(Path2D pathA, Path2D pathB) { + // Grab 2 path iterators and test for equality with float coords[] + final PathIterator itA = pathA.getPathIterator(null); + final PathIterator itB = pathB.getPathIterator(null); + + float[] coordsA = new float[6]; + float[] coordsB = new float[6]; + + int n = 0; + for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) { + int typeA = itA.currentSegment(coordsA); + int typeB = itB.currentSegment(coordsB); + + if (typeA != typeB) { + throw new IllegalStateException("Path-segment[" + n + "] " + + " type are not equals [" + typeA + "|" + typeB + "] !"); + } + if (!Arrays.equals(coordsA, coordsB)) { + throw new IllegalStateException("Path-segment[" + n + "] coords" + + " are not equals [" + Arrays.toString(coordsA) + "|" + + Arrays.toString(coordsB) + "] !"); + } + } + if (!itA.isDone() || !itB.isDone()) { + throw new IllegalStateException("Paths do not have same lengths !"); + } + System.out.println("testEqual: " + n + " segments."); + } + + static void testIterator(Path2D pathA, Path2D pathB) { + // - get a PathIterator and iterate it through until it is done + // (optional - compare to the expected segments that were in the original) + final PathIterator itA = pathA.getPathIterator(at); + final PathIterator itB = pathB.getPathIterator(at); + + float[] coordsA = new float[6]; + float[] coordsB = new float[6]; + + int n = 0; + for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) { + int typeA = itA.currentSegment(coordsA); + int typeB = itB.currentSegment(coordsB); + + if (typeA != typeB) { + throw new IllegalStateException("Path-segment[" + n + "] " + + "type are not equals [" + typeA + "|" + typeB + "] !"); + } + // Take care of floating-point precision: + if (!equalsArray(coordsA, coordsB)) { + throw new IllegalStateException("Path-segment[" + n + "] coords" + + " are not equals [" + Arrays.toString(coordsA) + "|" + + Arrays.toString(coordsB) + "] !"); + } + } + if (!itA.isDone() || !itB.isDone()) { + throw new IllegalStateException("Paths do not have same lengths !"); + } + System.out.println("testIterator: " + n + " segments."); + } + + static void testFlattening(Path2D pathA, Path2D pathB) { + // - get a flattened PathIterator using "getPathIterator(flatness,)" and make sure it works + // (optional - compare to original path if the original was already flat) + // (but, also run it on a path with curves to make sure flattening engine didn't break) + final PathIterator itA = pathA.getPathIterator(at, FLATNESS); + final PathIterator itB = pathB.getPathIterator(at, FLATNESS); + + float[] coordsA = new float[6]; + float[] coordsB = new float[6]; + + int n = 0; + for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) { + int typeA = itA.currentSegment(coordsA); + int typeB = itB.currentSegment(coordsB); + + if (typeA != typeB) { + throw new IllegalStateException("Path-segment[" + n + "] " + + "type are not equals [" + typeA + "|" + typeB + "] !"); + } + // Take care of floating-point precision: + if (!equalsArray(coordsA, coordsB)) { + throw new IllegalStateException("Path-segment[" + n + "] coords" + + " are not equals [" + Arrays.toString(coordsA) + "|" + + Arrays.toString(coordsB) + "] !"); + } + } + if (!itA.isDone() || !itB.isDone()) { + throw new IllegalStateException("Paths do not have same lengths !"); + } + System.out.println("testFlattening: " + n + " segments."); + } + + static void testAddMove(Path2D pathA) { + addMove(pathA); + System.out.println("testAddMove: passed."); + } + + static void testAddLine(Path2D pathA, boolean isEmpty) { + try { + addLinesOnly(pathA); + } + catch (IllegalPathStateException ipse) { + if (isEmpty) { + System.out.println("testAddLine: passed " + + "(expected IllegalPathStateException catched)."); + return; + } else { + throw ipse; + } + } + if (isEmpty) { + throw new IllegalStateException("IllegalPathStateException not thrown !"); + } + System.out.println("testAddLine: passed."); + } + + static void testAddQuad(Path2D pathA, boolean isEmpty) { + try { + addCurvesOnly(pathA); + } + catch (IllegalPathStateException ipse) { + if (isEmpty) { + System.out.println("testAddQuad: passed " + + "(expected IllegalPathStateException catched)."); + return; + } else { + throw ipse; + } + } + if (isEmpty) { + throw new IllegalStateException("IllegalPathStateException not thrown !"); + } + System.out.println("testAddQuad: passed."); + } + + static void testGetBounds(Path2D pathA, Path2D pathB) { + // - get the bounds of the cloned path + final Rectangle rA = pathA.getBounds(); + final Rectangle rB = pathB.getBounds(); + + if (!rA.equals(rB)) { + throw new IllegalStateException("Bounds are not equals [" + rA + + "|" + rB + "] !"); + } + final Rectangle2D r2dA = pathA.getBounds2D(); + final Rectangle2D r2dB = pathB.getBounds2D(); + + if (!equalsRectangle2D(r2dA, r2dB)) { + throw new IllegalStateException("Bounds2D are not equals [" + + r2dA + "|" + r2dB + "] !"); + } + System.out.println("testGetBounds: passed."); + } + + static void testTransform(Path2D pathA) { + // - use the transform() method on the cloned path + pathA.transform(at); + System.out.println("testTransform: passed."); + } + + static void testIntersect(Path2D pathA, Path2D pathB) { + // - call intersects(points), intersects(rect) on a cloned path + boolean resA = pathA.intersects(rect2d); + boolean resB = pathB.intersects(rect2d); + if (resA != resB) { + throw new IllegalStateException("Intersects(rect2d) are not equals [" + + resA + "|" + resB + "] !"); + } + resA = pathA.intersects(1.0, 2.0, 13.0, 17.0); + resB = pathB.intersects(1.0, 2.0, 13.0, 17.0); + if (resA != resB) { + throw new IllegalStateException("Intersects(doubles) are not equals [" + + resA + "|" + resB + "] !"); + } + System.out.println("testIntersect: passed."); + } + + static void testContains(Path2D pathA, Path2D pathB) { + // - call contains(pt), contains(rect) on a cloned path + boolean resA = pathA.contains(pt2d); + boolean resB = pathB.contains(pt2d); + if (resA != resB) { + throw new IllegalStateException("Contains(pt) are not equals [" + + resA + "|" + resB + "] !"); + } + resA = pathA.contains(pt2d.getX(), pt2d.getY()); + resB = pathB.contains(pt2d.getX(), pt2d.getY()); + if (resA != resB) { + throw new IllegalStateException("Contains(x,y) are not equals [" + + resA + "|" + resB + "] !"); + } + resA = pathA.contains(rect2d); + resB = pathB.contains(rect2d); + if (resA != resB) { + throw new IllegalStateException("Contains(rect2d) are not equals [" + + resA + "|" + resB + "] !"); + } + resA = pathA.contains(1.0, 2.0, 13.0, 17.0); + resB = pathB.contains(1.0, 2.0, 13.0, 17.0); + if (resA != resB) { + throw new IllegalStateException("Contains(doubles) are not equals [" + + resA + "|" + resB + "] !"); + } + System.out.println("testContains: passed."); + } + + static void testGetCurrentPoint(Path2D pathA, Path2D pathB) { + // - call getCurrentPoint() on the cloned path + final Point2D ptA = pathA.getCurrentPoint(); + final Point2D ptB = pathA.getCurrentPoint(); + if (((ptA == null) && (ptB != null)) + || ((ptA != null) && !ptA.equals(ptB))) + { + throw new IllegalStateException("getCurrentPoint() are not equals [" + + ptA + "|" + ptB + "] !"); + } + System.out.println("testGetCurrentPoint: passed."); + } + + // Custom equals methods --- + static boolean equalsArray(float[] a, float[] a2) { + if (a == a2) { + return true; + } + if (a == null || a2 == null) { + return false; + } + + int length = a.length; + if (a2.length != length) { + return false; + } + + for (int i = 0; i < length; i++) { + if (!equals(a[i], a2[i])) { + return false; + } + } + + return true; + } + + static boolean equalsRectangle2D(Rectangle2D a, Rectangle2D b) { + if (a == b) { + return true; + } + return equals(a.getX(), b.getX()) + && equals(a.getY(), b.getY()) + && equals(a.getWidth(), b.getWidth()) + && equals(a.getHeight(), b.getHeight()); + } + + static boolean equals(float a, float b) { + return (Math.abs(a - b) <= EPSILON); + } + + static boolean equals(double a, double b) { + return (Math.abs(a - b) <= EPSILON); + } + +}