1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang.builder;
18  
19  import java.math.BigDecimal;
20  import java.util.Arrays;
21  
22  import junit.framework.Test;
23  import junit.framework.TestCase;
24  import junit.framework.TestSuite;
25  import junit.textui.TestRunner;
26  
27  /**
28   * Unit tests {@link org.apache.commons.lang.builder.EqualsBuilder}.
29   *
30   * @author <a href="mailto:sdowney@panix.com">Steve Downey</a>
31   * @author <a href="mailto:scolebourne@joda.org">Stephen Colebourne</a>
32   * @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
33   * @author Maarten Coene
34   * @version $Id: EqualsBuilderTest.java 611543 2008-01-13 07:00:22Z bayard $
35   */
36  public class EqualsBuilderTest extends TestCase {
37  
38      public EqualsBuilderTest(String name) {
39          super(name);
40      }
41  
42      public static void main(String[] args) {
43          TestRunner.run(suite());
44      }
45  
46      public static Test suite() {
47          TestSuite suite = new TestSuite(EqualsBuilderTest.class);
48          suite.setName("EqualsBuilder Tests");
49          return suite;
50      }
51  
52      protected void setUp() throws Exception {
53          super.setUp();
54      }
55  
56      protected void tearDown() throws Exception {
57          super.tearDown();
58      }
59  
60      //-----------------------------------------------------------------------
61  
62      static class TestObject {
63          private int a;
64          public TestObject() {
65          }
66          public TestObject(int a) {
67              this.a = a;
68          }
69          public boolean equals(Object o) {
70              if (o == null) { return false; }
71              if (o == this) { return true; }
72              if (o.getClass() != getClass()) {
73                  return false;
74              }
75  
76              TestObject rhs = (TestObject) o;
77              return (a == rhs.a);
78          }
79  
80          public void setA(int a) {
81              this.a = a;
82          }
83  
84          public int getA() {
85              return a;
86          }
87      }
88  
89      static class TestSubObject extends TestObject {
90          private int b;
91          public TestSubObject() {
92              super(0);
93          }
94          public TestSubObject(int a, int b) {
95              super(a);
96              this.b = b;
97          }
98          public boolean equals(Object o) {
99              if (o == null) { return false; }
100             if (o == this) { return true; }
101             if (o.getClass() != getClass()) {
102                 return false;
103             }
104 
105             TestSubObject rhs = (TestSubObject) o;
106             return super.equals(o) && (b == rhs.b);
107         }
108 
109         public void setB(int b) {
110             this.b = b;
111         }
112 
113         public int getB() {
114             return b;
115         }
116     }
117     
118     static class TestEmptySubObject extends TestObject {
119         public TestEmptySubObject(int a) {
120             super(a);
121         }
122     }
123 
124     static class TestTSubObject extends TestObject {
125         private transient int t;
126         public TestTSubObject(int a, int t) {
127             super(a);
128             this.t = t;
129         }
130     }
131 
132     static class TestTTSubObject extends TestTSubObject {
133         private transient int tt;
134         public TestTTSubObject(int a, int t, int tt) {
135             super(a, t);
136             this.tt = tt;
137         }
138     }
139 
140     static class TestTTLeafObject extends TestTTSubObject {
141         private int leafValue;
142         public TestTTLeafObject(int a, int t, int tt, int leafValue) {
143             super(a, t, tt);
144             this.leafValue = leafValue;
145         }
146     }
147 
148     static class TestTSubObject2 extends TestObject {
149         private transient int t;
150         public TestTSubObject2(int a, int t) {
151             super(a);
152         }
153         public int getT() {
154             return t;
155         }
156         public void setT(int t) {
157             this.t = t;
158         }
159     }
160 
161     public void testReflectionEquals() {
162         TestObject o1 = new TestObject(4);
163         TestObject o2 = new TestObject(5);
164         assertTrue(EqualsBuilder.reflectionEquals(o1, o1));
165         assertTrue(!EqualsBuilder.reflectionEquals(o1, o2));
166         o2.setA(4);
167         assertTrue(EqualsBuilder.reflectionEquals(o1, o2));
168 
169         assertTrue(!EqualsBuilder.reflectionEquals(o1, this));
170 
171         assertTrue(!EqualsBuilder.reflectionEquals(o1, null));
172         assertTrue(!EqualsBuilder.reflectionEquals(null, o2));
173         assertTrue(EqualsBuilder.reflectionEquals((Object) null, (Object) null));
174     }
175     
176     public void testReflectionHierarchyEquals() {
177         testReflectionHierarchyEquals(false);
178         testReflectionHierarchyEquals(true);
179         // Transients
180         assertTrue(EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), true));
181         assertTrue(EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), false));
182         assertTrue(!EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 0, 0, 4), new TestTTLeafObject(1, 2, 3, 4), true));
183         assertTrue(!EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 0), true));
184         assertTrue(!EqualsBuilder.reflectionEquals(new TestTTLeafObject(0, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), true));
185     }
186 
187     public void testReflectionHierarchyEquals(boolean testTransients) {
188         TestObject to1 = new TestObject(4);
189         TestObject to1Bis = new TestObject(4);
190         TestObject to1Ter = new TestObject(4);
191         TestObject to2 = new TestObject(5);
192         TestEmptySubObject teso = new TestEmptySubObject(4);
193         TestTSubObject ttso = new TestTSubObject(4, 1);
194         TestTTSubObject tttso = new TestTTSubObject(4, 1, 2);
195         TestTTLeafObject ttlo = new TestTTLeafObject(4, 1, 2, 3);
196         TestSubObject tso1 = new TestSubObject(1, 4);
197         TestSubObject tso1bis = new TestSubObject(1, 4);
198         TestSubObject tso1ter = new TestSubObject(1, 4);
199         TestSubObject tso2 = new TestSubObject(2, 5);
200 
201         testReflectionEqualsEquivalenceRelationship(to1, to1Bis, to1Ter, to2, new TestObject(), testTransients);
202         testReflectionEqualsEquivalenceRelationship(tso1, tso1bis, tso1ter, tso2, new TestSubObject(), testTransients);
203 
204         // More sanity checks:
205 
206         // same values
207         assertTrue(EqualsBuilder.reflectionEquals(ttlo, ttlo, testTransients));
208         assertTrue(EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(1, 10), testTransients));
209         // same super values, diff sub values
210         assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(1, 11), testTransients));
211         assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(1, 11), new TestSubObject(1, 10), testTransients));
212         // diff super values, same sub values
213         assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(0, 10), new TestSubObject(1, 10), testTransients));
214         assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(0, 10), testTransients));
215 
216         // mix super and sub types: equals
217         assertTrue(EqualsBuilder.reflectionEquals(to1, teso, testTransients));
218         assertTrue(EqualsBuilder.reflectionEquals(teso, to1, testTransients));
219 
220         assertTrue(EqualsBuilder.reflectionEquals(to1, ttso, false)); // Force testTransients = false for this assert
221         assertTrue(EqualsBuilder.reflectionEquals(ttso, to1, false)); // Force testTransients = false for this assert
222 
223         assertTrue(EqualsBuilder.reflectionEquals(to1, tttso, false)); // Force testTransients = false for this assert
224         assertTrue(EqualsBuilder.reflectionEquals(tttso, to1, false)); // Force testTransients = false for this assert
225 
226         assertTrue(EqualsBuilder.reflectionEquals(ttso, tttso, false)); // Force testTransients = false for this assert
227         assertTrue(EqualsBuilder.reflectionEquals(tttso, ttso, false)); // Force testTransients = false for this assert
228 
229         // mix super and sub types: NOT equals
230         assertTrue(!EqualsBuilder.reflectionEquals(new TestObject(0), new TestEmptySubObject(1), testTransients));
231         assertTrue(!EqualsBuilder.reflectionEquals(new TestEmptySubObject(1), new TestObject(0), testTransients));
232 
233         assertTrue(!EqualsBuilder.reflectionEquals(new TestObject(0), new TestTSubObject(1, 1), testTransients));
234         assertTrue(!EqualsBuilder.reflectionEquals(new TestTSubObject(1, 1), new TestObject(0), testTransients));
235 
236         assertTrue(!EqualsBuilder.reflectionEquals(new TestObject(1), new TestSubObject(0, 10), testTransients));
237         assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(0, 10), new TestObject(1), testTransients));
238 
239         assertTrue(!EqualsBuilder.reflectionEquals(to1, ttlo));
240         assertTrue(!EqualsBuilder.reflectionEquals(tso1, this));
241     }
242 
243     /**
244      * Equivalence relationship tests inspired by "Effective Java":
245      * <ul>
246      * <li>reflection</li>
247      * <li>symmetry</li>
248      * <li>transitive</li>
249      * <li>consistency</li>
250      * <li>non-null reference</li>
251      * </ul>
252      * @param to a TestObject
253      * @param toBis a TestObject, equal to to and toTer
254      * @param toTer Left hand side, equal to to and toBis
255      * @param to2 a different TestObject
256      * @param oToChange a TestObject that will be changed
257      */
258     public void testReflectionEqualsEquivalenceRelationship(
259         TestObject to,
260         TestObject toBis,
261         TestObject toTer,
262         TestObject to2,
263         TestObject oToChange,
264         boolean testTransients) {
265 
266         // reflection test
267         assertTrue(EqualsBuilder.reflectionEquals(to, to, testTransients));
268         assertTrue(EqualsBuilder.reflectionEquals(to2, to2, testTransients));
269 
270         // symmetry test
271         assertTrue(EqualsBuilder.reflectionEquals(to, toBis, testTransients) && EqualsBuilder.reflectionEquals(toBis, to, testTransients));
272 
273         // transitive test
274         assertTrue(
275             EqualsBuilder.reflectionEquals(to, toBis, testTransients)
276                 && EqualsBuilder.reflectionEquals(toBis, toTer, testTransients)
277                 && EqualsBuilder.reflectionEquals(to, toTer, testTransients));
278 
279         // consistency test
280         oToChange.setA(to.getA());
281         if (oToChange instanceof TestSubObject) {
282             ((TestSubObject) oToChange).setB(((TestSubObject) to).getB());
283         }
284         assertTrue(EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
285         assertTrue(EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
286         oToChange.setA(to.getA() + 1);
287         if (oToChange instanceof TestSubObject) {
288             ((TestSubObject) oToChange).setB(((TestSubObject) to).getB() + 1);
289         }
290         assertTrue(!EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
291         assertTrue(!EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
292 
293         // non-null reference test
294         assertTrue(!EqualsBuilder.reflectionEquals(to, null, testTransients));
295         assertTrue(!EqualsBuilder.reflectionEquals(to2, null, testTransients));
296         assertTrue(!EqualsBuilder.reflectionEquals(null, to, testTransients));
297         assertTrue(!EqualsBuilder.reflectionEquals(null, to2, testTransients));
298         assertTrue(EqualsBuilder.reflectionEquals((Object) null, (Object) null, testTransients));
299     }
300 
301     public void testSuper() {
302         TestObject o1 = new TestObject(4);
303         TestObject o2 = new TestObject(5);
304         assertEquals(true, new EqualsBuilder().appendSuper(true).append(o1, o1).isEquals());
305         assertEquals(false, new EqualsBuilder().appendSuper(false).append(o1, o1).isEquals());
306         assertEquals(false, new EqualsBuilder().appendSuper(true).append(o1, o2).isEquals());
307         assertEquals(false, new EqualsBuilder().appendSuper(false).append(o1, o2).isEquals());
308     }
309 
310     public void testObject() {
311         TestObject o1 = new TestObject(4);
312         TestObject o2 = new TestObject(5);
313         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
314         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
315         o2.setA(4);
316         assertTrue(new EqualsBuilder().append(o1, o2).isEquals());
317 
318         assertTrue(!new EqualsBuilder().append(o1, this).isEquals());
319         
320         assertTrue(!new EqualsBuilder().append(o1, null).isEquals());
321         assertTrue(!new EqualsBuilder().append(null, o2).isEquals());
322         assertTrue(new EqualsBuilder().append((Object) null, (Object) null).isEquals());
323     }
324 
325     public void testLong() {
326         long o1 = 1L;
327         long o2 = 2L;
328         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
329         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
330     }
331 
332     public void testInt() {
333         int o1 = 1;
334         int o2 = 2;
335         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
336         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
337     }
338 
339     public void testShort() {
340         short o1 = 1;
341         short o2 = 2;
342         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
343         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
344     }
345 
346     public void testChar() {
347         char o1 = 1;
348         char o2 = 2;
349         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
350         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
351     }
352 
353     public void testByte() {
354         byte o1 = 1;
355         byte o2 = 2;
356         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
357         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
358     }
359 
360     public void testDouble() {
361         double o1 = 1;
362         double o2 = 2;
363         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
364         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
365         assertTrue(!new EqualsBuilder().append(o1, Double.NaN).isEquals());
366         assertTrue(new EqualsBuilder().append(Double.NaN, Double.NaN).isEquals());
367         assertTrue(new EqualsBuilder().append(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY).isEquals());
368     }
369 
370     public void testFloat() {
371         float o1 = 1;
372         float o2 = 2;
373         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
374         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
375         assertTrue(!new EqualsBuilder().append(o1, Float.NaN).isEquals());
376         assertTrue(new EqualsBuilder().append(Float.NaN, Float.NaN).isEquals());
377         assertTrue(new EqualsBuilder().append(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY).isEquals());
378     }
379 
380     // https://issues.apache.org/jira/browse/LANG-393
381     public void testBigDecimal() {
382         BigDecimal o1 = new BigDecimal("2.0");
383         BigDecimal o2 = new BigDecimal("2.00");
384         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
385         assertTrue(new EqualsBuilder().append(o1, o2).isEquals());
386     }
387 
388     public void testAccessors() {
389         EqualsBuilder equalsBuilder = new EqualsBuilder();
390         assertTrue(equalsBuilder.isEquals());
391         equalsBuilder.setEquals(true);
392         assertTrue(equalsBuilder.isEquals());
393         equalsBuilder.setEquals(false);
394         assertFalse(equalsBuilder.isEquals());
395     }
396     
397     public void testBoolean() {
398         boolean o1 = true;
399         boolean o2 = false;
400         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
401         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
402     }
403 
404     public void testObjectArray() {
405         TestObject[] obj1 = new TestObject[3];
406         obj1[0] = new TestObject(4);
407         obj1[1] = new TestObject(5);
408         obj1[2] = null;
409         TestObject[] obj2 = new TestObject[3];
410         obj2[0] = new TestObject(4);
411         obj2[1] = new TestObject(5);
412         obj2[2] = null;
413         
414         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
415         assertTrue(new EqualsBuilder().append(obj2, obj2).isEquals());
416         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
417         obj1[1].setA(6);
418         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
419         obj1[1].setA(5);
420         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
421         obj1[2] = obj1[1];
422         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
423         obj1[2] = null;
424         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
425                        
426         obj2 = null;
427         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
428         obj1 = null;
429         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
430     }
431 
432     public void testLongArray() {
433         long[] obj1 = new long[2];
434         obj1[0] = 5L;
435         obj1[1] = 6L;
436         long[] obj2 = new long[2];
437         obj2[0] = 5L;
438         obj2[1] = 6L;
439         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
440         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
441         obj1[1] = 7;
442         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
443 
444         obj2 = null;
445         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
446         obj1 = null;
447         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
448     }
449 
450     public void testIntArray() {
451         int[] obj1 = new int[2];
452         obj1[0] = 5;
453         obj1[1] = 6;
454         int[] obj2 = new int[2];
455         obj2[0] = 5;
456         obj2[1] = 6;
457         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
458         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
459         obj1[1] = 7;
460         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
461 
462         obj2 = null;
463         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
464         obj1 = null;
465         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
466     }
467 
468     public void testShortArray() {
469         short[] obj1 = new short[2];
470         obj1[0] = 5;
471         obj1[1] = 6;
472         short[] obj2 = new short[2];
473         obj2[0] = 5;
474         obj2[1] = 6;
475         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
476         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
477         obj1[1] = 7;
478         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
479 
480         obj2 = null;
481         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
482         obj1 = null;
483         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
484     }
485 
486     public void testCharArray() {
487         char[] obj1 = new char[2];
488         obj1[0] = 5;
489         obj1[1] = 6;
490         char[] obj2 = new char[2];
491         obj2[0] = 5;
492         obj2[1] = 6;
493         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
494         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
495         obj1[1] = 7;
496         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
497 
498         obj2 = null;
499         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
500         obj1 = null;
501         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
502     }
503 
504     public void testByteArray() {
505         byte[] obj1 = new byte[2];
506         obj1[0] = 5;
507         obj1[1] = 6;
508         byte[] obj2 = new byte[2];
509         obj2[0] = 5;
510         obj2[1] = 6;
511         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
512         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
513         obj1[1] = 7;
514         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
515 
516         obj2 = null;
517         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
518         obj1 = null;
519         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
520     }
521 
522     public void testDoubleArray() {
523         double[] obj1 = new double[2];
524         obj1[0] = 5;
525         obj1[1] = 6;
526         double[] obj2 = new double[2];
527         obj2[0] = 5;
528         obj2[1] = 6;
529         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
530         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
531         obj1[1] = 7;
532         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
533 
534         obj2 = null;
535         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
536         obj1 = null;
537         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
538     }
539 
540     public void testFloatArray() {
541         float[] obj1 = new float[2];
542         obj1[0] = 5;
543         obj1[1] = 6;
544         float[] obj2 = new float[2];
545         obj2[0] = 5;
546         obj2[1] = 6;
547         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
548         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
549         obj1[1] = 7;
550         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
551 
552         obj2 = null;
553         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
554         obj1 = null;
555         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
556     }
557 
558     public void testBooleanArray() {
559         boolean[] obj1 = new boolean[2];
560         obj1[0] = true;
561         obj1[1] = false;
562         boolean[] obj2 = new boolean[2];
563         obj2[0] = true;
564         obj2[1] = false;
565         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
566         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
567         obj1[1] = true;
568         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
569 
570         obj2 = null;
571         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
572         obj1 = null;
573         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
574     }
575 
576     public void testMultiLongArray() {
577         long[][] array1 = new long[2][2];
578         long[][] array2 = new long[2][2];
579         for (int i = 0; i < array1.length; ++i) {
580             for (int j = 0; j < array1[0].length; j++) {
581                 array1[i][j] = (i + 1) * (j + 1);
582                 array2[i][j] = (i + 1) * (j + 1);
583             }
584         }
585         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
586         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
587         array1[1][1] = 0;
588         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
589     }
590 
591     public void testMultiIntArray() {
592         int[][] array1 = new int[2][2];
593         int[][] array2 = new int[2][2];
594         for (int i = 0; i < array1.length; ++i) {
595             for (int j = 0; j < array1[0].length; j++) {
596                 array1[i][j] = (i + 1) * (j + 1);
597                 array2[i][j] = (i + 1) * (j + 1);
598             }
599         }
600         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
601         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
602         array1[1][1] = 0;
603         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
604     }
605 
606     public void testMultiShortArray() {
607         short[][] array1 = new short[2][2];
608         short[][] array2 = new short[2][2];
609         for (short i = 0; i < array1.length; ++i) {
610             for (short j = 0; j < array1[0].length; j++) {
611                 array1[i][j] = i;
612                 array2[i][j] = i;
613             }
614         }
615         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
616         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
617         array1[1][1] = 0;
618         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
619     }
620 
621     public void testMultiCharArray() {
622         char[][] array1 = new char[2][2];
623         char[][] array2 = new char[2][2];
624         for (char i = 0; i < array1.length; ++i) {
625             for (char j = 0; j < array1[0].length; j++) {
626                 array1[i][j] = i;
627                 array2[i][j] = i;
628             }
629         }
630         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
631         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
632         array1[1][1] = 0;
633         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
634     }
635 
636     public void testMultiByteArray() {
637         byte[][] array1 = new byte[2][2];
638         byte[][] array2 = new byte[2][2];
639         for (byte i = 0; i < array1.length; ++i) {
640             for (byte j = 0; j < array1[0].length; j++) {
641                 array1[i][j] = i;
642                 array2[i][j] = i;
643             }
644         }
645         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
646         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
647         array1[1][1] = 0;
648         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
649     }
650     public void testMultiFloatArray() {
651         float[][] array1 = new float[2][2];
652         float[][] array2 = new float[2][2];
653         for (int i = 0; i < array1.length; ++i) {
654             for (int j = 0; j < array1[0].length; j++) {
655                 array1[i][j] = (i + 1) * (j + 1);
656                 array2[i][j] = (i + 1) * (j + 1);
657             }
658         }
659         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
660         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
661         array1[1][1] = 0;
662         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
663     }
664 
665     public void testMultiDoubleArray() {
666         double[][] array1 = new double[2][2];
667         double[][] array2 = new double[2][2];
668         for (int i = 0; i < array1.length; ++i) {
669             for (int j = 0; j < array1[0].length; j++) {
670                 array1[i][j] = (i + 1) * (j + 1);
671                 array2[i][j] = (i + 1) * (j + 1);
672             }
673         }
674         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
675         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
676         array1[1][1] = 0;
677         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
678     }
679 
680     public void testMultiBooleanArray() {
681         boolean[][] array1 = new boolean[2][2];
682         boolean[][] array2 = new boolean[2][2];
683         for (int i = 0; i < array1.length; ++i) {
684             for (int j = 0; j < array1[0].length; j++) {
685                 array1[i][j] = (i == 1) || (j == 1);
686                 array2[i][j] = (i == 1) || (j == 1);
687             }
688         }
689         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
690         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
691         array1[1][1] = false;
692         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
693         
694         // compare 1 dim to 2.
695         boolean[] array3 = new boolean[]{true, true};
696         assertFalse(new EqualsBuilder().append(array1, array3).isEquals());
697         assertFalse(new EqualsBuilder().append(array3, array1).isEquals());
698         assertFalse(new EqualsBuilder().append(array2, array3).isEquals());
699         assertFalse(new EqualsBuilder().append(array3, array2).isEquals());
700     }
701 
702     public void testRaggedArray() {
703         long array1[][] = new long[2][];
704         long array2[][] = new long[2][];
705         for (int i = 0; i < array1.length; ++i) {
706             array1[i] = new long[2];
707             array2[i] = new long[2];
708             for (int j = 0; j < array1[i].length; ++j) {
709                 array1[i][j] = (i + 1) * (j + 1);
710                 array2[i][j] = (i + 1) * (j + 1);
711             }
712         }
713         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
714         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
715         array1[1][1] = 0;
716         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
717     }
718 
719     public void testMixedArray() {
720         Object array1[] = new Object[2];
721         Object array2[] = new Object[2];
722         for (int i = 0; i < array1.length; ++i) {
723             array1[i] = new long[2];
724             array2[i] = new long[2];
725             for (int j = 0; j < 2; ++j) {
726                 ((long[]) array1[i])[j] = (i + 1) * (j + 1);
727                 ((long[]) array2[i])[j] = (i + 1) * (j + 1);
728             }
729         }
730         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
731         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
732         ((long[]) array1[1])[1] = 0;
733         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
734     }
735 
736     public void testObjectArrayHiddenByObject() {
737         TestObject[] array1 = new TestObject[2];
738         array1[0] = new TestObject(4);
739         array1[1] = new TestObject(5);
740         TestObject[] array2 = new TestObject[2];
741         array2[0] = new TestObject(4);
742         array2[1] = new TestObject(5);
743         Object obj1 = array1;
744         Object obj2 = array2;
745         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
746         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
747         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
748         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
749         array1[1].setA(6);
750         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
751     }
752 
753     public void testLongArrayHiddenByObject() {
754         long[] array1 = new long[2];
755         array1[0] = 5L;
756         array1[1] = 6L;
757         long[] array2 = new long[2];
758         array2[0] = 5L;
759         array2[1] = 6L;
760         Object obj1 = array1;
761         Object obj2 = array2;
762         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
763         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
764         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
765         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
766         array1[1] = 7;
767         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
768     }
769 
770     public void testIntArrayHiddenByObject() {
771         int[] array1 = new int[2];
772         array1[0] = 5;
773         array1[1] = 6;
774         int[] array2 = new int[2];
775         array2[0] = 5;
776         array2[1] = 6;
777         Object obj1 = array1;
778         Object obj2 = array2;
779         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
780         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
781         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
782         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
783         array1[1] = 7;
784         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
785     }
786 
787     public void testShortArrayHiddenByObject() {
788         short[] array1 = new short[2];
789         array1[0] = 5;
790         array1[1] = 6;
791         short[] array2 = new short[2];
792         array2[0] = 5;
793         array2[1] = 6;
794         Object obj1 = array1;
795         Object obj2 = array2;
796         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
797         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
798         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
799         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
800         array1[1] = 7;
801         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
802     }
803 
804     public void testCharArrayHiddenByObject() {
805         char[] array1 = new char[2];
806         array1[0] = 5;
807         array1[1] = 6;
808         char[] array2 = new char[2];
809         array2[0] = 5;
810         array2[1] = 6;
811         Object obj1 = array1;
812         Object obj2 = array2;
813         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
814         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
815         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
816         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
817         array1[1] = 7;
818         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
819     }
820 
821     public void testByteArrayHiddenByObject() {
822         byte[] array1 = new byte[2];
823         array1[0] = 5;
824         array1[1] = 6;
825         byte[] array2 = new byte[2];
826         array2[0] = 5;
827         array2[1] = 6;
828         Object obj1 = array1;
829         Object obj2 = array2;
830         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
831         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
832         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
833         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
834         array1[1] = 7;
835         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
836     }
837 
838     public void testDoubleArrayHiddenByObject() {
839         double[] array1 = new double[2];
840         array1[0] = 5;
841         array1[1] = 6;
842         double[] array2 = new double[2];
843         array2[0] = 5;
844         array2[1] = 6;
845         Object obj1 = array1;
846         Object obj2 = array2;
847         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
848         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
849         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
850         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
851         array1[1] = 7;
852         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
853     }
854 
855     public void testFloatArrayHiddenByObject() {
856         float[] array1 = new float[2];
857         array1[0] = 5;
858         array1[1] = 6;
859         float[] array2 = new float[2];
860         array2[0] = 5;
861         array2[1] = 6;
862         Object obj1 = array1;
863         Object obj2 = array2;
864         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
865         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
866         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
867         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
868         array1[1] = 7;
869         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
870     }
871 
872     public void testBooleanArrayHiddenByObject() {
873         boolean[] array1 = new boolean[2];
874         array1[0] = true;
875         array1[1] = false;
876         boolean[] array2 = new boolean[2];
877         array2[0] = true;
878         array2[1] = false;
879         Object obj1 = array1;
880         Object obj2 = array2;
881         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
882         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
883         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
884         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
885         array1[1] = true;
886         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
887     }
888     
889     public static class TestACanEqualB {
890         private int a;
891 
892         public TestACanEqualB(int a) {
893             this.a = a;
894         }
895 
896         public boolean equals(Object o) {
897             if (o == this)
898                 return true;
899             if (o instanceof TestACanEqualB)
900                 return this.a == ((TestACanEqualB) o).getA();
901             if (o instanceof TestBCanEqualA)
902                 return this.a == ((TestBCanEqualA) o).getB();
903             return false;
904         }
905 
906         public int getA() {
907             return this.a;
908         }
909     }
910 
911     public static class TestBCanEqualA {
912         private int b;
913 
914         public TestBCanEqualA(int b) {
915             this.b = b;
916         }
917 
918         public boolean equals(Object o) {
919             if (o == this)
920                 return true;
921             if (o instanceof TestACanEqualB)
922                 return this.b == ((TestACanEqualB) o).getA();
923             if (o instanceof TestBCanEqualA)
924                 return this.b == ((TestBCanEqualA) o).getB();
925             return false;
926         }
927 
928         public int getB() {
929             return this.b;
930         }
931     }
932     
933     /**
934      * Tests two instances of classes that can be equal and that are not "related". The two classes are not subclasses
935      * of each other and do not share a parent aside from Object.
936      * See http://issues.apache.org/bugzilla/show_bug.cgi?id=33069
937      */
938     public void testUnrelatedClasses() {
939         Object[] x = new Object[]{new TestACanEqualB(1)};
940         Object[] y = new Object[]{new TestBCanEqualA(1)};
941 
942         // sanity checks:
943         assertTrue(Arrays.equals(x, x));
944         assertTrue(Arrays.equals(y, y));
945         assertTrue(Arrays.equals(x, y));
946         assertTrue(Arrays.equals(y, x));
947         // real tests:
948         assertTrue(x[0].equals(x[0]));
949         assertTrue(y[0].equals(y[0]));
950         assertTrue(x[0].equals(y[0]));
951         assertTrue(y[0].equals(x[0]));
952         assertTrue(new EqualsBuilder().append(x, x).isEquals());
953         assertTrue(new EqualsBuilder().append(y, y).isEquals());
954         assertTrue(new EqualsBuilder().append(x, y).isEquals());
955         assertTrue(new EqualsBuilder().append(y, x).isEquals());
956     }
957     
958     /**
959      * Test from http://issues.apache.org/bugzilla/show_bug.cgi?id=33067
960      */
961     public void testNpeForNullElement() {
962         Object[] x1 = new Object[] { new Integer(1), null, new Integer(3) };
963         Object[] x2 = new Object[] { new Integer(1), new Integer(2), new Integer(3) };
964 
965         // causes an NPE in 2.0 according to:
966         // http://issues.apache.org/bugzilla/show_bug.cgi?id=33067
967         new EqualsBuilder().append(x1, x2);
968     }
969 
970     public void testReflectionEqualsExcludeFields() throws Exception {
971         TestObjectWithMultipleFields x1 = new TestObjectWithMultipleFields(1, 2, 3);
972         TestObjectWithMultipleFields x2 = new TestObjectWithMultipleFields(1, 3, 4);
973 
974         // not equal when including all fields
975         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2));
976 
977         // doesn't barf on null, empty array, or non-existent field, but still tests as not equal
978         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, (String[]) null));
979         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {}));
980         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {"xxx"}));
981 
982         // not equal if only one of the differing fields excluded
983         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {"two"}));
984         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {"three"}));
985 
986         // equal if both differing fields excluded
987         assertTrue(EqualsBuilder.reflectionEquals(x1, x2, new String[] {"two", "three"}));
988 
989         // still equal as long as both differing fields are among excluded
990         assertTrue(EqualsBuilder.reflectionEquals(x1, x2, new String[] {"one", "two", "three"}));
991         assertTrue(EqualsBuilder.reflectionEquals(x1, x2, new String[] {"one", "two", "three", "xxx"}));
992     }
993 
994     static class TestObjectWithMultipleFields {
995         private TestObject one;
996         private TestObject two;
997         private TestObject three;
998 
999         public TestObjectWithMultipleFields(int one, int two, int three) {
1000             this.one = new TestObject(one);
1001             this.two = new TestObject(two);
1002             this.three = new TestObject(three);
1003         }
1004     }
1005 }