1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package test.javafx.scene;
  27 
  28 import static org.junit.Assert.fail;
  29 import javafx.geometry.BoundingBox;
  30 import javafx.geometry.Bounds;
  31 import javafx.geometry.Point2D;
  32 import javafx.geometry.Rectangle2D;
  33 import javafx.scene.paint.Color;
  34 
  35 import org.junit.Test;
  36 
  37 
  38 
  39 /**
  40  * Tests equals and hashCode for those classes that override equals. The
  41  * purpose of these tests is to ensure that we honor the contract of
  42  * hashCode and equals. Namely, that two objects for which .equals() returns
  43  * true must have the same hashCode.
  44  */
  45 public class HashCodeTest  {
  46 
  47     private static final boolean VERBOSE = false;
  48     
  49     
  50     void checkEqualsAndHashCode(Object o1, Object o2, boolean isEqual, boolean isNaN) {
  51 
  52         int o1Hash = o1.hashCode();
  53         int o2Hash = o2.hashCode();
  54         boolean o1EqualsO2 = o1.equals(o2);
  55         StringBuffer errMsg = new StringBuffer();
  56 
  57         if (o1EqualsO2 == isEqual) {
  58             if (o1EqualsO2 && (o1Hash != o2Hash)) {
  59                 errMsg.append("ERROR: Equal objects have different hashCode");
  60                 errMsg.append("\n    o1 = ").append(o1); 
  61                 errMsg.append("\n    o2 = ").append(o2);
  62                 
  63                 errMsg.append("\n    o1.hashCode() = ").append(Integer.toHexString(o1Hash)).append(", o2.hashCode() = ").append(Integer.toHexString(o2Hash));
  64                 fail(errMsg.toString());
  65             }
  66             else if ((!o1EqualsO2) && (o1Hash == o2Hash)) {
  67                 if (isNaN) {
  68                     if (VERBOSE) {
  69                         System.out.println("Non-equal objects with NaN have same hashCode (as expected)");
  70                         System.out.println("o1 = " + o1);
  71                         System.out.println("o2 = " + o2);
  72                         System.out.println("o1.hashCode() = " + Integer.toHexString(o1Hash) +
  73                                            ", o2.hashCode() = " +
  74                                            Integer.toHexString(o2Hash));
  75                         System.out.println("");
  76                     }
  77                 }
  78                 else {
  79                     errMsg.append("Warning: Non-equal objects have same hashCode");
  80                     errMsg.append("\n    o1 = ").append(o1);
  81                     errMsg.append("\n    o2 = ").append(o2);
  82                     
  83                     errMsg.append("\n    o1.hashCode() = ").append(Integer.toHexString(o1Hash)).append(", o2.hashCode() = ").append(Integer.toHexString(o2Hash));
  84                     fail(errMsg.toString());
  85                 }
  86             }
  87             else if (VERBOSE) {
  88                 System.out.println("SUCCESS:");
  89                 System.out.println("o1 = " + o1);
  90                 System.out.println("o2 = " + o2);
  91                 System.out.println("o1.equals(o2) = " + o1EqualsO2 + ", expected: " + isEqual);
  92                 System.out.println("o1.hashCode() = " + Integer.toHexString(o1Hash) +
  93                                    ", o2.hashCode() = " + Integer.toHexString(o2Hash));
  94                 System.out.println("");
  95             }
  96         }
  97         else {
  98             errMsg.append("ERROR: o1.equals(o2) incorrect");
  99             errMsg.append("\n    o1 = ").append(o1);
 100             errMsg.append("\n    o2 = ").append(o2);
 101             errMsg.append("\n    o1.equals(o2) = ").append(o1EqualsO2).append(", expected: ").append(isEqual);
 102             errMsg.append("\n    o1.hashCode() = ").append(Integer.toHexString(o1Hash)).append(", o2.hashCode() = ").append(Integer.toHexString(o2Hash));
 103             fail(errMsg.toString());
 104         }
 105     }
 106 
 107     @Test
 108     public void testRectangleHash() {
 109         Rectangle2D r1 = new Rectangle2D(0,0,0,0);
 110         Rectangle2D r2 = new Rectangle2D(0,0,0,0);
 111         checkEqualsAndHashCode(r1, r2, true, false);
 112 
 113         r1 = new Rectangle2D(1,2,3,4);
 114         r2 = new Rectangle2D(1,2,3,4);
 115         checkEqualsAndHashCode(r1, r2, true, false);
 116 
 117         r1 = new Rectangle2D(0,1,0,0);
 118         r2 = new Rectangle2D(1,0,0,0);
 119         checkEqualsAndHashCode(r1, r2, false, false);
 120 
 121         r1 = new Rectangle2D(0.0f,1,0,0);
 122         r2 = new Rectangle2D(0.0f,1,0,0);
 123         checkEqualsAndHashCode(r1, r2, true, false);
 124 
 125         // Cannot test -0 versus +0 due to RT-xxxx
 126         /*
 127         r1 = Rectangle2D(0.0 minY:1 width:0 height:0 }
 128         r2 = Rectangle2D(-0.0 minY:1 width:0 height:0 }
 129         checkEqualsAndHashCode(r1, r2, true, false);
 130         */
 131 
 132         r1 = new Rectangle2D(1.0f,Float.POSITIVE_INFINITY, 0.0f, 0.0f);
 133         r2 = new Rectangle2D(Float.POSITIVE_INFINITY, 1.0f, 0.0f, 0.0f);
 134         checkEqualsAndHashCode(r1, r2, false, false);
 135 
 136         r1 = new Rectangle2D(Float.POSITIVE_INFINITY, 1.0f, 0.0f,  0.0f);
 137         r2 = new Rectangle2D(Float.POSITIVE_INFINITY, 1.0f, 0.0f,  0.0f);
 138         checkEqualsAndHashCode(r1, r2, true, false);
 139 
 140         r1 = new Rectangle2D(1.0f, Float.POSITIVE_INFINITY, 0.0f, 0.0f);
 141         r2 = new Rectangle2D(1.0f, Float.POSITIVE_INFINITY, 0.0f, 0.0f);
 142         checkEqualsAndHashCode(r1, r2, true, false);
 143 
 144         r1 = new Rectangle2D(Float.NaN, 1.0f, 0.0f, 0.0f);
 145         r2 = new Rectangle2D(Float.NaN, 1.0f, 0.0f, 0.0f);
 146         checkEqualsAndHashCode(r1, r2, false, true);
 147 
 148         r1 = new Rectangle2D(1.0f, Float.NaN, 0.0f, 0.0f);
 149         r2 = new Rectangle2D(1.0f, Float.NaN, 0.0f, 0.0f);
 150         checkEqualsAndHashCode(r1, r2, false, true);
 151     }
 152 
 153     @Test
 154     public void testPointHash() {
 155         Point2D p1 = new Point2D(0,0);
 156         Point2D p2 = new Point2D(0,0);
 157         checkEqualsAndHashCode(p1, p2, true, false);
 158 
 159         p1 = new Point2D(1, 2);
 160         p2 = new Point2D(1, 2);
 161         checkEqualsAndHashCode(p1, p2, true, false);
 162 
 163         p1 = new Point2D(0, 1);
 164         p2 = new Point2D(1, 0);
 165         checkEqualsAndHashCode(p1, p2, false, false);
 166 
 167         p1 = new Point2D(1, 0.0f);
 168         p2 = new Point2D(1, 0.0f);
 169         checkEqualsAndHashCode(p1, p2, true, false);
 170 
 171         // Cannot test -0 versus +0 due to RT-xxxx
 172         
 173         //p1 = Point2D { x:1 y:-0.0 }
 174         //p2 = Point2D { x:1 y:0.0 }
 175         //checkEqualsAndHashCode(p1, p2, true, false);
 176     }
 177 
 178     @Test
 179     public void testBoundingBoxHash() {
 180         Bounds b1 = new BoundingBox(0,0,0,0);
 181         Bounds b2 = new BoundingBox(0,0,0,0);
 182         checkEqualsAndHashCode(b1, b2, true, false);
 183 
 184         b1 = new BoundingBox(1,2,3,4);
 185         b2 = new BoundingBox(1,2,3,4);
 186         checkEqualsAndHashCode(b1, b2, true, false);
 187 
 188         b1 = new BoundingBox(0,1,0,0);
 189         b2 = new BoundingBox(1,0,0,0);
 190         checkEqualsAndHashCode(b1, b2, false, false);
 191 
 192         b1 = new BoundingBox(0.0f,1,0,0);
 193         b2 = new BoundingBox(0.0f,1,0,0);
 194         checkEqualsAndHashCode(b1, b2, true, false);
 195 
 196         // Cannot test -0 versus +0 due to RT-xxxx
 197         
 198         //b1 = BoundingBox(0.0 minY:1 width:0 height:0 }
 199         //b2 = BoundingBox(-0.0 minY:1 width:0 height:0 }
 200         //checkEqualsAndHashCode(b1, b2, true, false);
 201         
 202 
 203         b1 = new BoundingBox(1.0f, Float.POSITIVE_INFINITY,0.0f,0.0f);
 204         b2 = new BoundingBox(Float.POSITIVE_INFINITY, 1.0f, 0.0f, 0.0f);
 205         checkEqualsAndHashCode(b1, b2, false, false);
 206 
 207         b1 = new BoundingBox(Float.POSITIVE_INFINITY, 1.0f, 0.0f, 0.0f);
 208         b2 = new BoundingBox(Float.POSITIVE_INFINITY, 1.0f, 0.0f, 0.0f);
 209         checkEqualsAndHashCode(b1, b2, true, false);
 210 
 211         b1 = new BoundingBox(1.0f, Float.POSITIVE_INFINITY, 0.0f, 0.0f);
 212         b2 = new BoundingBox(1.0f, Float.POSITIVE_INFINITY, 0.0f, 0.0f);
 213         checkEqualsAndHashCode(b1, b2, true, false);
 214 
 215         b1 = new BoundingBox(Float.NaN, 1.0f, 0.0f, 0.0f);
 216         b2 = new BoundingBox(Float.NaN, 1.0f, 0.0f, 0.0f);
 217         checkEqualsAndHashCode(b1, b2, false, true);
 218 
 219         b1 = new BoundingBox(1.0f, Float.NaN, 0.0f, 0.0f);
 220         b2 = new BoundingBox(1.0f, Float.NaN, 0.0f, 0.0f);
 221         checkEqualsAndHashCode(b1, b2, false, true);
 222     }
 223 
 224     @Test
 225     public void testColorHash() {
 226         Color c1 = new Color(0,0,0,1);
 227         Color c2 = new Color(0,0,0,1);
 228         checkEqualsAndHashCode(c1, c2, true, false);
 229 
 230         c1 = Color.RED;
 231         c2 = new Color(1.0f,0.0f,0.0f,1.0f);
 232         checkEqualsAndHashCode(c1, c2, true, false);
 233 
 234         c1 = Color.LIME; // Why LIME? Because w3c decided that GREEN is only 50% green
 235         c2 = new Color(0.0f,1.0f,0.0f,1.0f);
 236         checkEqualsAndHashCode(c1, c2, true, false);
 237 
 238         c1 = Color.BLUE;
 239         c2 = new Color(0.0f,0.0f,1.0f,1.0f);
 240         checkEqualsAndHashCode(c1, c2, true, false);
 241 
 242         c1 = Color.WHITE;
 243         c2 = new Color(1.0f,1.0f,1.0f,1.0f);
 244         checkEqualsAndHashCode(c1, c2, true, false);
 245 
 246         c1 = Color.RED;
 247         c2 = Color.color(1.0f, 0.0f, 0.0f, 1.0f);
 248         checkEqualsAndHashCode(c1, c2, true, false);
 249 
 250         c1 = Color.LIME; // Why LIME? Because w3c decided that GREEN is only 50% green
 251         c2 = Color.color(0.0f, 1.0f, 0.0f, 1.0f);
 252         checkEqualsAndHashCode(c1, c2, true, false);
 253 
 254         c1 = Color.BLUE;
 255         c2 = Color.color(0.0f, 0.0f, 1.0f, 1.0f);
 256         checkEqualsAndHashCode(c1, c2, true, false);
 257 
 258         c1 = Color.WHITE;
 259         c2 = Color.color(1.0f, 1.0f, 1.0f, 1.0f);
 260         checkEqualsAndHashCode(c1, c2, true, false);
 261 
 262         c1 = Color.color(0.5f, 0.0f, 0.0f, 0.0f);
 263         c2 = Color.color(0.5f, 0.0f, 0.0f, 0.0f);
 264         checkEqualsAndHashCode(c1, c2, true, false);
 265 
 266         c1 = Color.color(0.5f, 0.0f, 0.0f, 0.0f);
 267         c2 = Color.color(0.0f, 0.5f, 0.0f, 0.0f);
 268         checkEqualsAndHashCode(c1, c2, false, false);
 269 
 270         c1 = Color.color(0.5f, 0.0f, 0.0f, 0.0f);
 271         c2 = Color.color(0.0f, 0.0f, 0.5f, 0.0f);
 272         checkEqualsAndHashCode(c1, c2, false, false);
 273 
 274         c1 = Color.color(0.5f, 0.0f, 0.0f, 0.0f);
 275         c2 = Color.color(0.0f, 0.0f, 0.0f, 0.5f);
 276         checkEqualsAndHashCode(c1, c2, false, false);
 277 
 278         c1 = Color.color(0.0f, 0.5f, 0.0f, 0.0f);
 279         c2 = Color.color(0.0f, 0.0f, 0.5f, 0.0f);
 280         checkEqualsAndHashCode(c1, c2, false, false);
 281 
 282         c1 = Color.color(0.0f, 0.5f, 0.0f, 0.0f);
 283         c2 = Color.color(0.0f, 0.0f, 0.0f, 0.5f);
 284         checkEqualsAndHashCode(c1, c2, false, false);
 285 
 286         c1 = Color.color(0.0f, 0.0f, 0.5f, 0.0f);
 287         c2 = Color.color(0.0f, 0.0f, 0.0f, 0.5f);
 288         checkEqualsAndHashCode(c1, c2, false, false);
 289     }
 290 }