606c9e56a3
Reviewed-by: prr, jdv
476 lines
14 KiB
Java
476 lines
14 KiB
Java
/*
|
|
* Copyright (c) 2005, 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 6210287
|
|
* @summary Verifies that the various utility shapes implement
|
|
* the equals(Object) and hashCode methods adequately
|
|
*/
|
|
|
|
import java.awt.geom.Arc2D;
|
|
import java.awt.geom.Ellipse2D;
|
|
import java.awt.geom.Rectangle2D;
|
|
import java.awt.geom.RoundRectangle2D;
|
|
import java.util.Vector;
|
|
|
|
public class EqualsHashcode {
|
|
public static final int NUMTESTS = 1000;
|
|
|
|
public static void main(String argv[]) {
|
|
new FloatRectangleTester().test();
|
|
new DoubleRectangleTester().test();
|
|
|
|
new FloatEllipseTester().test();
|
|
new DoubleEllipseTester().test();
|
|
|
|
new FloatArcTester().test();
|
|
new DoubleArcTester().test();
|
|
|
|
new FloatRoundRectTester().test();
|
|
new DoubleRoundRectTester().test();
|
|
}
|
|
|
|
/**
|
|
* Base utility class for random parameters for testing
|
|
*/
|
|
public static abstract class Val {
|
|
protected String name;
|
|
|
|
protected Val(String name) {
|
|
this.name = name;
|
|
}
|
|
|
|
public abstract Object save();
|
|
public abstract void restore(Object save);
|
|
|
|
public abstract void randomize();
|
|
public abstract void perturb();
|
|
}
|
|
|
|
/**
|
|
* Base subclass for parameters with "special" values (Infinity, NaN, etc.)
|
|
*/
|
|
public static abstract class SpecialVal extends Val {
|
|
protected SpecialVal(String name) {
|
|
super(name);
|
|
}
|
|
|
|
public abstract void setSpecial();
|
|
|
|
public abstract boolean isNaN();
|
|
}
|
|
|
|
/**
|
|
* Floating point parameter
|
|
*/
|
|
public static class FloatVal extends SpecialVal {
|
|
private float v;
|
|
|
|
public FloatVal(String name) {
|
|
super(name);
|
|
}
|
|
|
|
public float getVal() {
|
|
return v;
|
|
}
|
|
|
|
public String toString() {
|
|
return name+" = "+v+" (flt)";
|
|
}
|
|
|
|
public Object save() {
|
|
return new Float(v);
|
|
}
|
|
|
|
public void restore(Object o) {
|
|
v = ((Float) o).floatValue();
|
|
}
|
|
|
|
public void randomize() {
|
|
v = (float) (Math.random() * 100);
|
|
}
|
|
|
|
public void perturb() {
|
|
v = v + 1;
|
|
}
|
|
|
|
public boolean hasSpecialCases() {
|
|
return true;
|
|
}
|
|
|
|
public void setSpecial() {
|
|
switch ((int) (Math.random() * 3)) {
|
|
case 0:
|
|
v = Float.NaN;
|
|
break;
|
|
case 1:
|
|
v = Float.POSITIVE_INFINITY;
|
|
break;
|
|
case 2:
|
|
v = Float.NEGATIVE_INFINITY;
|
|
break;
|
|
default:
|
|
throw new InternalError();
|
|
}
|
|
}
|
|
|
|
public boolean isNaN() {
|
|
return (v != v);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Double precision parameter
|
|
*/
|
|
public static class DoubleVal extends SpecialVal {
|
|
private double v;
|
|
|
|
public DoubleVal(String name) {
|
|
super(name);
|
|
}
|
|
|
|
public double getVal() {
|
|
return v;
|
|
}
|
|
|
|
public String toString() {
|
|
return name+" = "+v+" (dbl)";
|
|
}
|
|
|
|
public Object save() {
|
|
return new Double(v);
|
|
}
|
|
|
|
public void restore(Object o) {
|
|
v = ((Double) o).doubleValue();
|
|
}
|
|
|
|
public void randomize() {
|
|
v = Math.random() * 100;
|
|
}
|
|
|
|
public void perturb() {
|
|
v = v + 1;
|
|
}
|
|
|
|
public boolean hasSpecialCases() {
|
|
return true;
|
|
}
|
|
|
|
public void setSpecial() {
|
|
switch ((int) (Math.random() * 3)) {
|
|
case 0:
|
|
v = Double.NaN;
|
|
break;
|
|
case 1:
|
|
v = Double.POSITIVE_INFINITY;
|
|
break;
|
|
case 2:
|
|
v = Double.NEGATIVE_INFINITY;
|
|
break;
|
|
default:
|
|
throw new InternalError();
|
|
}
|
|
}
|
|
|
|
public boolean isNaN() {
|
|
return (v != v);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Integer value with a specified min/max range.
|
|
*/
|
|
public static class IntRangeVal extends Val {
|
|
public int v;
|
|
public int min;
|
|
public int max;
|
|
|
|
public IntRangeVal(String name, int min, int max) {
|
|
super(name);
|
|
this.min = min;
|
|
this.max = max;
|
|
}
|
|
|
|
public int getVal() {
|
|
return v;
|
|
}
|
|
|
|
public String toString() {
|
|
return name+" = "+v;
|
|
}
|
|
|
|
public Object save() {
|
|
return new Integer(v);
|
|
}
|
|
|
|
public void restore(Object o) {
|
|
v = ((Integer) o).intValue();
|
|
}
|
|
|
|
public void randomize() {
|
|
v = min + (int) (Math.random() * (max-min+1));
|
|
}
|
|
|
|
public void perturb() {
|
|
v = v + 1;
|
|
if (v > max) {
|
|
v = min;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Base class for testing a given type of shape.
|
|
* Subclasses must register all of their "parameters" which
|
|
* need to be randomized, specialized, and perturbed for
|
|
* testing.
|
|
* Subclasses must also implement makeShape() which makes
|
|
* a new shape object according to the current values of
|
|
* all of their parameters.
|
|
*/
|
|
public static abstract class ShapeTester {
|
|
public Vector params = new Vector();
|
|
|
|
public void addParam(Val v) {
|
|
params.add(v);
|
|
}
|
|
|
|
public Val[] getParamArray() {
|
|
Val ret[] = new Val[params.size()];
|
|
for (int i = 0; i < params.size(); i++) {
|
|
ret[i] = (Val) params.get(i);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public void error(String desc) {
|
|
Val params[] = getParamArray();
|
|
for (int j = 0; j < params.length; j++) {
|
|
System.err.println(params[j]);
|
|
}
|
|
throw new RuntimeException(desc);
|
|
}
|
|
|
|
public abstract Object makeShape();
|
|
|
|
public void test() {
|
|
Val params[] = getParamArray();
|
|
for (int i = 0; i < NUMTESTS; i++) {
|
|
// First, randomize all parameters
|
|
for (int j = 0; j < params.length; j++) {
|
|
params[j].randomize();
|
|
}
|
|
|
|
// Now make 2 copies from the same params and verify equals()
|
|
Object o1 = makeShape();
|
|
if (!o1.equals(o1)) {
|
|
error("Shapes not equal to itself!");
|
|
}
|
|
Object o2 = makeShape();
|
|
if (!o1.equals(o2)) {
|
|
error("Identical shapes not equal!");
|
|
}
|
|
if (o1.hashCode() != o2.hashCode()) {
|
|
error("Identical hashes not equal!");
|
|
}
|
|
|
|
// Now perturb the params 1 by 1 and verify !equals()
|
|
for (int j = 0; j < params.length; j++) {
|
|
Val param = params[j];
|
|
Object save = param.save();
|
|
|
|
param.perturb();
|
|
Object o3 = makeShape();
|
|
if (o1.equals(o3)) {
|
|
error("Perturbed shape still equal!");
|
|
}
|
|
|
|
// If param has "special values", test them as well
|
|
if (param instanceof SpecialVal) {
|
|
SpecialVal sparam = (SpecialVal) param;
|
|
sparam.setSpecial();
|
|
Object o4 = makeShape();
|
|
if (o1.equals(o4)) {
|
|
error("Specialized shape still equal!");
|
|
}
|
|
Object o5 = makeShape();
|
|
// objects equal iff param is not a NaN
|
|
if (o4.equals(o5) == sparam.isNaN()) {
|
|
error("Identical specialized shapes not equal!");
|
|
}
|
|
// hash codes always equal, even if NaN
|
|
// (Note: equals()/hashCode() contract allows this)
|
|
if (o4.hashCode() != o5.hashCode()) {
|
|
error("Identical specialized hashes not equal!");
|
|
}
|
|
}
|
|
|
|
// Restore original value of param and make sure
|
|
param.restore(save);
|
|
Object o6 = makeShape();
|
|
if (!o1.equals(o6)) {
|
|
error("Restored shape not equal!");
|
|
}
|
|
if (o1.hashCode() != o6.hashCode()) {
|
|
error("Restored hash not equal!");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Base tester class for objects with floating point xywh bounds
|
|
*/
|
|
public static abstract class FloatBoundedShape extends ShapeTester {
|
|
public FloatVal x = new FloatVal("x");
|
|
public FloatVal y = new FloatVal("y");
|
|
public FloatVal w = new FloatVal("w");
|
|
public FloatVal h = new FloatVal("h");
|
|
|
|
public FloatBoundedShape() {
|
|
addParam(x);
|
|
addParam(y);
|
|
addParam(w);
|
|
addParam(h);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Base tester class for objects with double precision xywh bounds
|
|
*/
|
|
public static abstract class DoubleBoundedShape extends ShapeTester {
|
|
public DoubleVal x = new DoubleVal("x");
|
|
public DoubleVal y = new DoubleVal("y");
|
|
public DoubleVal w = new DoubleVal("w");
|
|
public DoubleVal h = new DoubleVal("h");
|
|
|
|
public DoubleBoundedShape() {
|
|
addParam(x);
|
|
addParam(y);
|
|
addParam(w);
|
|
addParam(h);
|
|
}
|
|
}
|
|
|
|
public static class FloatRectangleTester extends FloatBoundedShape {
|
|
public Object makeShape() {
|
|
return new Rectangle2D.Float(x.getVal(), y.getVal(),
|
|
w.getVal(), h.getVal());
|
|
}
|
|
}
|
|
|
|
public static class DoubleRectangleTester extends DoubleBoundedShape {
|
|
public Object makeShape() {
|
|
return new Rectangle2D.Double(x.getVal(), y.getVal(),
|
|
w.getVal(), h.getVal());
|
|
}
|
|
}
|
|
|
|
public static class FloatEllipseTester extends FloatBoundedShape {
|
|
public Object makeShape() {
|
|
return new Ellipse2D.Float(x.getVal(), y.getVal(),
|
|
w.getVal(), h.getVal());
|
|
}
|
|
}
|
|
|
|
public static class DoubleEllipseTester extends DoubleBoundedShape {
|
|
public Object makeShape() {
|
|
return new Ellipse2D.Double(x.getVal(), y.getVal(),
|
|
w.getVal(), h.getVal());
|
|
}
|
|
}
|
|
|
|
public static class FloatArcTester extends FloatBoundedShape {
|
|
public FloatVal start = new FloatVal("start");
|
|
public FloatVal extent = new FloatVal("extent");
|
|
public IntRangeVal type = new IntRangeVal("type", 0, 2);
|
|
|
|
public FloatArcTester() {
|
|
addParam(start);
|
|
addParam(extent);
|
|
addParam(type);
|
|
}
|
|
|
|
public Object makeShape() {
|
|
return new Arc2D.Float(x.getVal(), y.getVal(),
|
|
w.getVal(), h.getVal(),
|
|
start.getVal(), extent.getVal(),
|
|
type.getVal());
|
|
}
|
|
}
|
|
|
|
public static class DoubleArcTester extends DoubleBoundedShape {
|
|
public DoubleVal start = new DoubleVal("start");
|
|
public DoubleVal extent = new DoubleVal("extent");
|
|
public IntRangeVal type = new IntRangeVal("type", 0, 2);
|
|
|
|
public DoubleArcTester() {
|
|
addParam(start);
|
|
addParam(extent);
|
|
addParam(type);
|
|
}
|
|
|
|
public Object makeShape() {
|
|
return new Arc2D.Double(x.getVal(), y.getVal(),
|
|
w.getVal(), h.getVal(),
|
|
start.getVal(), extent.getVal(),
|
|
type.getVal());
|
|
}
|
|
}
|
|
|
|
public static class FloatRoundRectTester extends FloatBoundedShape {
|
|
public FloatVal arcw = new FloatVal("arcw");
|
|
public FloatVal arch = new FloatVal("arch");
|
|
|
|
public FloatRoundRectTester() {
|
|
addParam(arcw);
|
|
addParam(arch);
|
|
}
|
|
|
|
public Object makeShape() {
|
|
return new RoundRectangle2D.Float(x.getVal(), y.getVal(),
|
|
w.getVal(), h.getVal(),
|
|
arcw.getVal(), arch.getVal());
|
|
}
|
|
}
|
|
|
|
public static class DoubleRoundRectTester extends DoubleBoundedShape {
|
|
public DoubleVal arcw = new DoubleVal("arcw");
|
|
public DoubleVal arch = new DoubleVal("arch");
|
|
|
|
public DoubleRoundRectTester() {
|
|
addParam(arcw);
|
|
addParam(arch);
|
|
}
|
|
|
|
public Object makeShape() {
|
|
return new RoundRectangle2D.Double(x.getVal(), y.getVal(),
|
|
w.getVal(), h.getVal(),
|
|
arcw.getVal(), arch.getVal());
|
|
}
|
|
}
|
|
}
|