View Javadoc
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.lang3.builder;
18  
19  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertNotEquals;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  
25  import java.lang.reflect.Method;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.List;
29  
30  import org.apache.commons.lang3.AbstractLangTest;
31  import org.apache.commons.lang3.reflect.MethodUtils;
32  import org.junit.jupiter.api.Test;
33  
34  /**
35   * Unit tests {@link org.apache.commons.lang3.builder.EqualsBuilder}.
36   */
37  public class EqualsBuilderTest extends AbstractLangTest {
38  
39      public static class TestACanEqualB {
40          private final int a;
41  
42          public TestACanEqualB(final int a) {
43              this.a = a;
44          }
45  
46          @Override
47          public boolean equals(final Object o) {
48              if (o == this) {
49                  return true;
50              }
51              if (o instanceof TestACanEqualB) {
52                  return this.a == ((TestACanEqualB) o).getA();
53              }
54              if (o instanceof TestBCanEqualA) {
55                  return this.a == ((TestBCanEqualA) o).getB();
56              }
57              return false;
58          }
59  
60          public int getA() {
61              return this.a;
62          }
63  
64          @Override
65          public int hashCode() {
66              return a;
67          }
68      }
69  
70      public static class TestBCanEqualA {
71          private final int b;
72  
73          public TestBCanEqualA(final int b) {
74              this.b = b;
75          }
76  
77          @Override
78          public boolean equals(final Object o) {
79              if (o == this) {
80                  return true;
81              }
82              if (o instanceof TestACanEqualB) {
83                  return this.b == ((TestACanEqualB) o).getA();
84              }
85              if (o instanceof TestBCanEqualA) {
86                  return this.b == ((TestBCanEqualA) o).getB();
87              }
88              return false;
89          }
90  
91          public int getB() {
92              return this.b;
93          }
94  
95          @Override
96          public int hashCode() {
97              return b;
98          }
99      }
100 
101     static class TestEmptySubObject extends TestObject {
102         TestEmptySubObject(final int a) {
103             super(a);
104         }
105     }
106 
107     static class TestObject {
108         private int a;
109 
110         TestObject() {
111         }
112 
113         TestObject(final int a) {
114             this.a = a;
115         }
116 
117         @Override
118         public boolean equals(final Object o) {
119             if (o == null) {
120                 return false;
121             }
122             if (o == this) {
123                 return true;
124             }
125             if (o.getClass() != getClass()) {
126                 return false;
127             }
128 
129             final TestObject rhs = (TestObject) o;
130             return a == rhs.a;
131         }
132 
133         public int getA() {
134             return a;
135         }
136 
137         @Override
138         public int hashCode() {
139             return a;
140         }
141 
142         public void setA(final int a) {
143             this.a = a;
144         }
145     }
146 
147     static class TestObjectEqualsExclude {
148         @EqualsExclude
149         private final int a;
150         private final int b;
151 
152         TestObjectEqualsExclude(final int a, final int b) {
153             this.a = a;
154             this.b = b;
155         }
156 
157         public int getA() {
158             return a;
159         }
160 
161         public int getB() {
162             return b;
163         }
164     }
165 
166     static class TestObjectReference {
167         @SuppressWarnings("unused")
168         private TestObjectReference reference;
169         @SuppressWarnings("unused")
170         private final TestObject one;
171 
172         TestObjectReference(final int one) {
173             this.one = new TestObject(one);
174         }
175 
176         @Override
177         public boolean equals(final Object obj) {
178             return EqualsBuilder.reflectionEquals(this, obj);
179         }
180 
181         public void setObjectReference(final TestObjectReference reference) {
182             this.reference = reference;
183         }
184     }
185 
186     static class TestObjectWithMultipleFields {
187         @SuppressWarnings("unused")
188         private final TestObject one;
189         @SuppressWarnings("unused")
190         private final TestObject two;
191         @SuppressWarnings("unused")
192         private final TestObject three;
193 
194         TestObjectWithMultipleFields(final int one, final int two, final int three) {
195             this.one = new TestObject(one);
196             this.two = new TestObject(two);
197             this.three = new TestObject(three);
198         }
199     }
200 
201     static class TestRecursiveCycleObject {
202         private TestRecursiveCycleObject cycle;
203         private final int n;
204 
205         TestRecursiveCycleObject(final int n) {
206             this.n = n;
207             this.cycle = this;
208         }
209 
210         TestRecursiveCycleObject(final TestRecursiveCycleObject cycle, final int n) {
211             this.n = n;
212             this.cycle = cycle;
213         }
214 
215         public TestRecursiveCycleObject getCycle() {
216             return cycle;
217         }
218 
219         public int getN() {
220             return n;
221         }
222 
223         public void setCycle(final TestRecursiveCycleObject cycle) {
224             this.cycle = cycle;
225         }
226     }
227 
228     static class TestRecursiveGenericObject<T> {
229 
230         private final T a;
231 
232         TestRecursiveGenericObject(final T a) {
233             this.a = a;
234         }
235 
236         public T getA() {
237             return a;
238         }
239     }
240 
241     static class TestRecursiveInnerObject {
242         private final int n;
243 
244         TestRecursiveInnerObject(final int n) {
245             this.n = n;
246         }
247 
248         public int getN() {
249             return n;
250         }
251     }
252 
253     static class TestRecursiveObject {
254         private final TestRecursiveInnerObject a;
255         private final TestRecursiveInnerObject b;
256         private int z;
257 
258         TestRecursiveObject(final TestRecursiveInnerObject a,
259                             final TestRecursiveInnerObject b, final int z) {
260             this.a = a;
261             this.b = b;
262         }
263 
264         public TestRecursiveInnerObject getA() {
265             return a;
266         }
267 
268         public TestRecursiveInnerObject getB() {
269             return b;
270         }
271 
272         public int getZ() {
273             return z;
274         }
275 
276     }
277 
278     static class TestSubObject extends TestObject {
279         private int b;
280 
281         TestSubObject() {
282             super(0);
283         }
284 
285         TestSubObject(final int a, final int b) {
286             super(a);
287             this.b = b;
288         }
289 
290         @Override
291         public boolean equals(final Object o) {
292             if (o == null) {
293                 return false;
294             }
295             if (o == this) {
296                 return true;
297             }
298             if (o.getClass() != getClass()) {
299                 return false;
300             }
301 
302             final TestSubObject rhs = (TestSubObject) o;
303             return super.equals(o) && b == rhs.b;
304         }
305 
306         public int getB() {
307             return b;
308         }
309 
310         @Override
311         public int hashCode() {
312             return b * 17 + super.hashCode();
313         }
314 
315         public void setB(final int b) {
316             this.b = b;
317         }
318     }
319 
320     static class TestTSubObject extends TestObject {
321         @SuppressWarnings("unused")
322         private final transient int t;
323 
324         TestTSubObject(final int a, final int t) {
325             super(a);
326             this.t = t;
327         }
328     }
329 
330     static class TestTSubObject2 extends TestObject {
331         private transient int t;
332 
333         TestTSubObject2(final int a, final int t) {
334             super(a);
335         }
336 
337         public int getT() {
338             return t;
339         }
340 
341         public void setT(final int t) {
342             this.t = t;
343         }
344     }
345 
346     static class TestTTLeafObject extends TestTTSubObject {
347         @SuppressWarnings("unused")
348         private final int leafValue;
349 
350         TestTTLeafObject(final int a, final int t, final int tt, final int leafValue) {
351             super(a, t, tt);
352             this.leafValue = leafValue;
353         }
354     }
355 
356     static class TestTTSubObject extends TestTSubObject {
357         @SuppressWarnings("unused")
358         private final transient int tt;
359 
360         TestTTSubObject(final int a, final int t, final int tt) {
361             super(a, t);
362             this.tt = tt;
363         }
364     }
365 
366     @Test
367     public void testAccessors() {
368         final EqualsBuilder equalsBuilder = new EqualsBuilder();
369         assertTrue(equalsBuilder.isEquals());
370         equalsBuilder.setEquals(true);
371         assertTrue(equalsBuilder.isEquals());
372         equalsBuilder.setEquals(false);
373         assertFalse(equalsBuilder.isEquals());
374     }
375 
376     @Test
377     public void testBoolean() {
378         final boolean o1 = true;
379         final boolean o2 = false;
380         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
381         assertFalse(new EqualsBuilder().append(o1, o2).isEquals());
382         assertFalse(new EqualsBuilder().append(o1, o2).append(o1, o1).isEquals());
383     }
384 
385     @Test
386     public void testBooleanArray() {
387         final boolean[] obj1 = new boolean[2];
388         obj1[0] = true;
389         obj1[1] = false;
390         final boolean[] obj2 = new boolean[2];
391         obj2[0] = true;
392         obj2[1] = false;
393         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
394         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
395         obj1[1] = true;
396         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
397         assertFalse(new EqualsBuilder().append(obj1, obj2).append(obj1, obj1).isEquals());
398 
399         final boolean[] nullArr1 = null;
400         final boolean[] nullArr2 = null;
401         assertFalse(new EqualsBuilder().append(obj1, nullArr2).isEquals());
402         assertFalse(new EqualsBuilder().append(nullArr1, obj2).isEquals());
403         assertTrue(new EqualsBuilder().append(nullArr1, nullArr2).isEquals());
404         assertTrue(new EqualsBuilder().append(nullArr1, nullArr1).isEquals());
405     }
406 
407     @Test
408     public void testBooleanArrayHiddenByObject() {
409         final boolean[] array1 = new boolean[2];
410         array1[0] = true;
411         array1[1] = false;
412         final boolean[] array2 = new boolean[2];
413         array2[0] = true;
414         array2[1] = false;
415         final Object obj1 = array1;
416         final Object obj2 = array2;
417         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
418         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
419         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
420         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
421         array1[1] = true;
422         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
423     }
424 
425     @Test
426     public void testByte() {
427         final byte o1 = 1;
428         final byte o2 = 2;
429         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
430         assertFalse(new EqualsBuilder().append(o1, o2).isEquals());
431         assertFalse(new EqualsBuilder().append(o1, o2).append(o1, o1).isEquals());
432     }
433 
434     @Test
435     public void testByteArray() {
436         final byte[] obj1 = new byte[2];
437         obj1[0] = 5;
438         obj1[1] = 6;
439         final byte[] obj2 = new byte[2];
440         obj2[0] = 5;
441         obj2[1] = 6;
442         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
443         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
444         obj1[1] = 7;
445         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
446         assertFalse(new EqualsBuilder().append(obj1, obj2).append(obj1, obj1).isEquals());
447 
448         final byte[] nullArr1 = null;
449         final byte[] nullArr2 = null;
450         assertFalse(new EqualsBuilder().append(obj1, nullArr2).isEquals());
451         assertFalse(new EqualsBuilder().append(nullArr1, obj2).isEquals());
452         assertTrue(new EqualsBuilder().append(nullArr1, nullArr2).isEquals());
453         assertTrue(new EqualsBuilder().append(nullArr1, nullArr1).isEquals());
454     }
455 
456     @Test
457     public void testByteArrayHiddenByObject() {
458         final byte[] array1 = new byte[2];
459         array1[0] = 5;
460         array1[1] = 6;
461         final byte[] array2 = new byte[2];
462         array2[0] = 5;
463         array2[1] = 6;
464         final Object obj1 = array1;
465         final Object obj2 = array2;
466         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
467         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
468         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
469         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
470         array1[1] = 7;
471         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
472     }
473 
474     @Test
475     public void testChar() {
476         final char o1 = 1;
477         final char o2 = 2;
478         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
479         assertFalse(new EqualsBuilder().append(o1, o2).isEquals());
480         assertFalse(new EqualsBuilder().append(o1, o2).append(o1, o1).isEquals());
481     }
482 
483     @Test
484     public void testCharArray() {
485         final char[] obj1 = new char[2];
486         obj1[0] = 5;
487         obj1[1] = 6;
488         final char[] obj2 = new char[2];
489         obj2[0] = 5;
490         obj2[1] = 6;
491         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
492         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
493         obj1[1] = 7;
494         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
495         assertFalse(new EqualsBuilder().append(obj1, obj2).append(obj1, obj1).isEquals());
496 
497         final char[] nullArr1 = null;
498         final char[] nullArr2 = null;
499         assertFalse(new EqualsBuilder().append(obj1, nullArr2).isEquals());
500         assertFalse(new EqualsBuilder().append(nullArr1, obj2).isEquals());
501         assertTrue(new EqualsBuilder().append(nullArr1, nullArr2).isEquals());
502         assertTrue(new EqualsBuilder().append(nullArr1, nullArr1).isEquals());
503     }
504 
505     @Test
506     public void testCharArrayHiddenByObject() {
507         final char[] array1 = new char[2];
508         array1[0] = 5;
509         array1[1] = 6;
510         final char[] array2 = new char[2];
511         array2[0] = 5;
512         array2[1] = 6;
513         final Object obj1 = array1;
514         final Object obj2 = array2;
515         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
516         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
517         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
518         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
519         array1[1] = 7;
520         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
521     }
522 
523     /**
524      * Test cyclical object references which cause a StackOverflowException if
525      * not handled properly. s. LANG-606
526      */
527     @Test
528     public void testCyclicalObjectReferences() {
529         final TestObjectReference refX1 = new TestObjectReference(1);
530         final TestObjectReference x1 = new TestObjectReference(1);
531         x1.setObjectReference(refX1);
532         refX1.setObjectReference(x1);
533 
534         final TestObjectReference refX2 = new TestObjectReference(1);
535         final TestObjectReference x2 = new TestObjectReference(1);
536         x2.setObjectReference(refX2);
537         refX2.setObjectReference(x2);
538 
539         final TestObjectReference refX3 = new TestObjectReference(2);
540         final TestObjectReference x3 = new TestObjectReference(2);
541         x3.setObjectReference(refX3);
542         refX3.setObjectReference(x3);
543 
544         assertEquals(x1, x2);
545         assertNotEquals(x1, x3);
546         assertNotEquals(x2, x3);
547     }
548 
549     @Test
550     public void testDouble() {
551         final double o1 = 1;
552         final double o2 = 2;
553         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
554         assertFalse(new EqualsBuilder().append(o1, o2).isEquals());
555         assertFalse(new EqualsBuilder().append(o1, o2).append(o1, o1).isEquals());
556         assertFalse(new EqualsBuilder().append(o1, Double.NaN).isEquals());
557         assertTrue(new EqualsBuilder().append(Double.NaN, Double.NaN).isEquals());
558         assertTrue(new EqualsBuilder().append(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY).isEquals());
559     }
560 
561     @Test
562     public void testDoubleArray() {
563         final double[] obj1 = new double[2];
564         obj1[0] = 5;
565         obj1[1] = 6;
566         final double[] obj2 = new double[2];
567         obj2[0] = 5;
568         obj2[1] = 6;
569         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
570         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
571         obj1[1] = 7;
572         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
573         assertFalse(new EqualsBuilder().append(obj1, obj2).append(obj1, obj1).isEquals());
574 
575         final double[] nullArr1 = null;
576         final double[] nullArr2 = null;
577         assertFalse(new EqualsBuilder().append(obj1, nullArr2).isEquals());
578         assertFalse(new EqualsBuilder().append(nullArr1, obj2).isEquals());
579         assertTrue(new EqualsBuilder().append(nullArr1, nullArr2).isEquals());
580         assertTrue(new EqualsBuilder().append(nullArr1, nullArr1).isEquals());
581     }
582 
583     @Test
584     public void testDoubleArrayHiddenByObject() {
585         final double[] array1 = new double[2];
586         array1[0] = 5;
587         array1[1] = 6;
588         final double[] array2 = new double[2];
589         array2[0] = 5;
590         array2[1] = 6;
591         final Object obj1 = array1;
592         final Object obj2 = array2;
593         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
594         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
595         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
596         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
597         array1[1] = 7;
598         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
599     }
600 
601     @Test
602     public void testFloat() {
603         final float o1 = 1;
604         final float o2 = 2;
605         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
606         assertFalse(new EqualsBuilder().append(o1, o2).isEquals());
607         assertFalse(new EqualsBuilder().append(o1, o2).append(o1, o1).isEquals());
608         assertFalse(new EqualsBuilder().append(o1, Float.NaN).isEquals());
609         assertTrue(new EqualsBuilder().append(Float.NaN, Float.NaN).isEquals());
610         assertTrue(new EqualsBuilder().append(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY).isEquals());
611     }
612 
613     @Test
614     public void testFloatArray() {
615         final float[] obj1 = new float[2];
616         obj1[0] = 5;
617         obj1[1] = 6;
618         final float[] obj2 = new float[2];
619         obj2[0] = 5;
620         obj2[1] = 6;
621         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
622         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
623         obj1[1] = 7;
624         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
625         assertFalse(new EqualsBuilder().append(obj1, obj2).append(obj1, obj1).isEquals());
626 
627         final float[] nullArr1 = null;
628         final float[] nullArr2 = null;
629         assertFalse(new EqualsBuilder().append(obj1, nullArr2).isEquals());
630         assertFalse(new EqualsBuilder().append(nullArr1, obj2).isEquals());
631         assertTrue(new EqualsBuilder().append(nullArr1, nullArr2).isEquals());
632         assertTrue(new EqualsBuilder().append(nullArr1, nullArr1).isEquals());
633     }
634 
635     @Test
636     public void testFloatArrayHiddenByObject() {
637         final float[] array1 = new float[2];
638         array1[0] = 5;
639         array1[1] = 6;
640         final float[] array2 = new float[2];
641         array2[0] = 5;
642         array2[1] = 6;
643         final Object obj1 = array1;
644         final Object obj2 = array2;
645         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
646         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
647         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
648         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
649         array1[1] = 7;
650         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
651     }
652 
653     @Test
654     public void testInt() {
655         final int o1 = 1;
656         final int o2 = 2;
657         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
658         assertFalse(new EqualsBuilder().append(o1, o2).isEquals());
659         assertFalse(new EqualsBuilder().append(o1, o2).append(o1, o1).isEquals());
660     }
661 
662     @Test
663     public void testIntArray() {
664         final int[] obj1 = new int[2];
665         obj1[0] = 5;
666         obj1[1] = 6;
667         final int[] obj2 = new int[2];
668         obj2[0] = 5;
669         obj2[1] = 6;
670         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
671         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
672         obj1[1] = 7;
673         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
674         assertFalse(new EqualsBuilder().append(obj1, obj2).append(obj1, obj1).isEquals());
675 
676         final int[] nullArr1 = null;
677         final int[] nullArr2 = null;
678         assertFalse(new EqualsBuilder().append(obj1, nullArr2).isEquals());
679         assertFalse(new EqualsBuilder().append(nullArr1, obj2).isEquals());
680         assertTrue(new EqualsBuilder().append(nullArr1, nullArr2).isEquals());
681         assertTrue(new EqualsBuilder().append(nullArr1, nullArr1).isEquals());
682     }
683 
684     @Test
685     public void testIntArrayHiddenByObject() {
686         final int[] array1 = new int[2];
687         array1[0] = 5;
688         array1[1] = 6;
689         final int[] array2 = new int[2];
690         array2[0] = 5;
691         array2[1] = 6;
692         final Object obj1 = array1;
693         final Object obj2 = array2;
694         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
695         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
696         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
697         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
698         array1[1] = 7;
699         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
700     }
701 
702     @Test
703     public void testIsRegistered() throws Exception {
704         final Object firstObject = new Object();
705         final Object secondObject = new Object();
706 
707         try {
708             final Method registerMethod = MethodUtils.getMatchingMethod(EqualsBuilder.class, "register", Object.class, Object.class);
709             registerMethod.setAccessible(true);
710             registerMethod.invoke(null, firstObject, secondObject);
711 
712             assertTrue(EqualsBuilder.isRegistered(firstObject, secondObject));
713             assertTrue(EqualsBuilder.isRegistered(secondObject, firstObject)); // LANG-1349
714         } finally {
715             final Method unregisterMethod = MethodUtils.getMatchingMethod(EqualsBuilder.class, "unregister", Object.class, Object.class);
716             unregisterMethod.setAccessible(true);
717             unregisterMethod.invoke(null, firstObject, secondObject);
718         }
719     }
720 
721     @Test
722     public void testLong() {
723         final long o1 = 1L;
724         final long o2 = 2L;
725         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
726         assertFalse(new EqualsBuilder().append(o1, o2).isEquals());
727         assertFalse(new EqualsBuilder().append(o1, o2).append(o1, o1).isEquals());
728     }
729 
730     @Test
731     public void testLongArray() {
732         final long[] obj1 = new long[2];
733         obj1[0] = 5L;
734         obj1[1] = 6L;
735         final long[] obj2 = new long[2];
736         obj2[0] = 5L;
737         obj2[1] = 6L;
738         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
739         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
740         obj1[1] = 7;
741         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
742         assertFalse(new EqualsBuilder().append(obj1, obj2).append(obj1, obj1).isEquals());
743 
744         final long[] nullArr1 = null;
745         final long[] nullArr2 = null;
746         assertFalse(new EqualsBuilder().append(obj1, nullArr2).isEquals());
747         assertFalse(new EqualsBuilder().append(nullArr1, obj2).isEquals());
748         assertTrue(new EqualsBuilder().append(nullArr1, nullArr2).isEquals());
749         assertTrue(new EqualsBuilder().append(nullArr1, nullArr1).isEquals());
750     }
751 
752     @Test
753     public void testLongArrayHiddenByObject() {
754         final long[] array1 = new long[2];
755         array1[0] = 5L;
756         array1[1] = 6L;
757         final long[] array2 = new long[2];
758         array2[0] = 5L;
759         array2[1] = 6L;
760         final Object obj1 = array1;
761         final 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         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
768     }
769 
770     @Test
771     public void testMixedArray() {
772         final Object[] array1 = new Object[2];
773         final Object[] array2 = new Object[2];
774         for (int i = 0; i < array1.length; ++i) {
775             array1[i] = new long[2];
776             array2[i] = new long[2];
777             for (int j = 0; j < 2; ++j) {
778                 ((long[]) array1[i])[j] = (i + 1) * (j + 1);
779                 ((long[]) array2[i])[j] = (i + 1) * (j + 1);
780             }
781         }
782         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
783         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
784         ((long[]) array1[1])[1] = 0;
785         assertFalse(new EqualsBuilder().append(array1, array2).isEquals());
786         assertFalse(new EqualsBuilder().append(array1, array2).append(array1, array2).isEquals());
787     }
788 
789     @Test
790     public void testMultiBooleanArray() {
791         final boolean[][] array1 = new boolean[2][2];
792         final boolean[][] array2 = new boolean[2][2];
793         for (int i = 0; i < array1.length; ++i) {
794             for (int j = 0; j < array1[0].length; j++) {
795                 array1[i][j] = i == 1 || j == 1;
796                 array2[i][j] = i == 1 || j == 1;
797             }
798         }
799         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
800         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
801         array1[1][1] = false;
802         assertFalse(new EqualsBuilder().append(array1, array2).isEquals());
803 
804         // compare 1 dim to 2.
805         final boolean[] array3 = {true, true};
806         assertFalse(new EqualsBuilder().append(array1, array3).isEquals());
807         assertFalse(new EqualsBuilder().append(array3, array1).isEquals());
808         assertFalse(new EqualsBuilder().append(array2, array3).isEquals());
809         assertFalse(new EqualsBuilder().append(array3, array2).isEquals());
810     }
811 
812     @Test
813     public void testMultiByteArray() {
814         final byte[][] array1 = new byte[2][2];
815         final byte[][] array2 = new byte[2][2];
816         for (byte i = 0; i < array1.length; ++i) {
817             for (byte j = 0; j < array1[0].length; j++) {
818                 array1[i][j] = i;
819                 array2[i][j] = i;
820             }
821         }
822         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
823         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
824         array1[1][1] = 0;
825         assertFalse(new EqualsBuilder().append(array1, array2).isEquals());
826     }
827 
828     @Test
829     public void testMultiCharArray() {
830         final char[][] array1 = new char[2][2];
831         final char[][] array2 = new char[2][2];
832         for (char i = 0; i < array1.length; ++i) {
833             for (char j = 0; j < array1[0].length; j++) {
834                 array1[i][j] = i;
835                 array2[i][j] = i;
836             }
837         }
838         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
839         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
840         array1[1][1] = 0;
841         assertFalse(new EqualsBuilder().append(array1, array2).isEquals());
842     }
843 
844     @Test
845     public void testMultiDoubleArray() {
846         final double[][] array1 = new double[2][2];
847         final double[][] array2 = new double[2][2];
848         for (int i = 0; i < array1.length; ++i) {
849             for (int j = 0; j < array1[0].length; j++) {
850                 array1[i][j] = (i + 1) * (j + 1);
851                 array2[i][j] = (i + 1) * (j + 1);
852             }
853         }
854         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
855         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
856         array1[1][1] = 0;
857         assertFalse(new EqualsBuilder().append(array1, array2).isEquals());
858     }
859 
860     @Test
861     public void testMultiFloatArray() {
862         final float[][] array1 = new float[2][2];
863         final float[][] array2 = new float[2][2];
864         for (int i = 0; i < array1.length; ++i) {
865             for (int j = 0; j < array1[0].length; j++) {
866                 array1[i][j] = (i + 1) * (j + 1);
867                 array2[i][j] = (i + 1) * (j + 1);
868             }
869         }
870         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
871         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
872         array1[1][1] = 0;
873         assertFalse(new EqualsBuilder().append(array1, array2).isEquals());
874     }
875 
876     @Test
877     public void testMultiIntArray() {
878         final int[][] array1 = new int[2][2];
879         final int[][] array2 = new int[2][2];
880         for (int i = 0; i < array1.length; ++i) {
881             for (int j = 0; j < array1[0].length; j++) {
882                 array1[i][j] = (i + 1) * (j + 1);
883                 array2[i][j] = (i + 1) * (j + 1);
884             }
885         }
886         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
887         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
888         array1[1][1] = 0;
889         assertFalse(new EqualsBuilder().append(array1, array2).isEquals());
890     }
891 
892     @Test
893     public void testMultiLongArray() {
894         final long[][] array1 = new long[2][2];
895         final long[][] array2 = new long[2][2];
896         for (int i = 0; i < array1.length; ++i) {
897             for (int j = 0; j < array1[0].length; j++) {
898                 array1[i][j] = (i + 1) * (j + 1);
899                 array2[i][j] = (i + 1) * (j + 1);
900             }
901         }
902         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
903         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
904         array1[1][1] = 0;
905         assertFalse(new EqualsBuilder().append(array1, array2).isEquals());
906     }
907 
908     @Test
909     public void testMultiShortArray() {
910         final short[][] array1 = new short[2][2];
911         final short[][] array2 = new short[2][2];
912         for (short i = 0; i < array1.length; ++i) {
913             for (short j = 0; j < array1[0].length; j++) {
914                 array1[i][j] = i;
915                 array2[i][j] = i;
916             }
917         }
918         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
919         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
920         array1[1][1] = 0;
921         assertFalse(new EqualsBuilder().append(array1, array2).isEquals());
922     }
923 
924     /**
925      * Test from https://issues.apache.org/jira/browse/LANG-42
926      */
927     @Test
928     public void testNpeForNullElement() {
929         final Object[] x1 = {Integer.valueOf(1), null, Integer.valueOf(3)};
930         final Object[] x2 = {Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)};
931 
932         // causes an NPE in 2.0 according to:
933         // https://issues.apache.org/jira/browse/LANG-42
934         new EqualsBuilder().append(x1, x2);
935     }
936 
937     @Test
938     public void testObject() {
939         final TestObject o1 = new TestObject(4);
940         final TestObject o2 = new TestObject(5);
941         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
942         assertFalse(new EqualsBuilder().append(o1, o2).isEquals());
943         o2.setA(4);
944         assertTrue(new EqualsBuilder().append(o1, o2).isEquals());
945 
946         assertFalse(new EqualsBuilder().append(o1, this).isEquals());
947 
948         assertFalse(new EqualsBuilder().append(o1, null).isEquals());
949         assertFalse(new EqualsBuilder().append(null, o2).isEquals());
950         assertTrue(new EqualsBuilder().append((Object) null, null).isEquals());
951     }
952 
953     @Test
954     public void testObjectArray() {
955         final TestObject[] obj1 = new TestObject[3];
956         obj1[0] = new TestObject(4);
957         obj1[1] = new TestObject(5);
958         obj1[2] = null;
959         final TestObject[] obj2 = new TestObject[3];
960         obj2[0] = new TestObject(4);
961         obj2[1] = new TestObject(5);
962         obj2[2] = null;
963 
964         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
965         assertTrue(new EqualsBuilder().append(obj2, obj2).isEquals());
966         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
967         obj1[1].setA(6);
968         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
969         assertFalse(new EqualsBuilder().append(obj1, obj2).append(obj1, obj1).isEquals());
970         obj1[1].setA(5);
971         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
972         obj1[2] = obj1[1];
973         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
974         obj1[2] = null;
975         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
976 
977         final TestObject[] nullArr1 = null;
978         final TestObject[] nullArr2 = null;
979         assertFalse(new EqualsBuilder().append(obj1, nullArr2).isEquals());
980         assertFalse(new EqualsBuilder().append(nullArr1, obj2).isEquals());
981         assertTrue(new EqualsBuilder().append(nullArr1, nullArr2).isEquals());
982         assertTrue(new EqualsBuilder().append(nullArr1, nullArr1).isEquals());
983     }
984 
985     @Test
986     public void testObjectArrayHiddenByObject() {
987         final TestObject[] array1 = new TestObject[2];
988         array1[0] = new TestObject(4);
989         array1[1] = new TestObject(5);
990         final TestObject[] array2 = new TestObject[2];
991         array2[0] = new TestObject(4);
992         array2[1] = new TestObject(5);
993         final Object obj1 = array1;
994         final Object obj2 = array2;
995         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
996         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
997         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
998         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
999         array1[1].setA(6);
1000         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
1001     }
1002 
1003     @Test
1004     public void testObjectBuild() {
1005         final TestObject o1 = new TestObject(4);
1006         final TestObject o2 = new TestObject(5);
1007         assertEquals(Boolean.TRUE, new EqualsBuilder().append(o1, o1).build());
1008         assertEquals(Boolean.FALSE, new EqualsBuilder().append(o1, o2).build());
1009         o2.setA(4);
1010         assertEquals(Boolean.TRUE, new EqualsBuilder().append(o1, o2).build());
1011 
1012         assertEquals(Boolean.FALSE, new EqualsBuilder().append(o1, this).build());
1013 
1014         assertEquals(Boolean.FALSE, new EqualsBuilder().append(o1, null).build());
1015         assertEquals(Boolean.FALSE, new EqualsBuilder().append(null, o2).build());
1016         assertEquals(Boolean.TRUE, new EqualsBuilder().append((Object) null, null).build());
1017     }
1018 
1019     @Test
1020     public void testObjectRecursive() {
1021         final TestRecursiveInnerObject i1_1 = new TestRecursiveInnerObject(1);
1022         final TestRecursiveInnerObject i1_2 = new TestRecursiveInnerObject(1);
1023         final TestRecursiveInnerObject i2_1 = new TestRecursiveInnerObject(2);
1024         final TestRecursiveInnerObject i2_2 = new TestRecursiveInnerObject(2);
1025         final TestRecursiveInnerObject i3 = new TestRecursiveInnerObject(3);
1026         final TestRecursiveInnerObject i4 = new TestRecursiveInnerObject(4);
1027 
1028         final TestRecursiveObject o1A = new TestRecursiveObject(i1_1, i2_1, 1);
1029         final TestRecursiveObject o1B = new TestRecursiveObject(i1_2, i2_2, 1);
1030         final TestRecursiveObject o2 = new TestRecursiveObject(i3, i4, 2);
1031         final TestRecursiveObject oNull = new TestRecursiveObject(null, null, 2);
1032 
1033         assertTrue(new EqualsBuilder().setTestRecursive(true).append(o1A, o1A).isEquals());
1034         assertTrue(new EqualsBuilder().setTestRecursive(true).append(o1A, o1B).isEquals());
1035 
1036         assertFalse(new EqualsBuilder().setTestRecursive(true).append(o1A, o2).isEquals());
1037 
1038         assertTrue(new EqualsBuilder().setTestRecursive(true).append(oNull, oNull).isEquals());
1039         assertFalse(new EqualsBuilder().setTestRecursive(true).append(o1A, oNull).isEquals());
1040     }
1041 
1042     @Test
1043     public void testObjectRecursiveCycle() {
1044         final TestRecursiveCycleObject o1A = new TestRecursiveCycleObject(1);
1045         final TestRecursiveCycleObject i1A = new TestRecursiveCycleObject(o1A, 100);
1046         o1A.setCycle(i1A);
1047 
1048         final TestRecursiveCycleObject o1B = new TestRecursiveCycleObject(1);
1049         final TestRecursiveCycleObject i1B = new TestRecursiveCycleObject(o1B, 100);
1050         o1B.setCycle(i1B);
1051 
1052         final TestRecursiveCycleObject o2 = new TestRecursiveCycleObject(2);
1053         final TestRecursiveCycleObject i2 = new TestRecursiveCycleObject(o1B, 200);
1054         o2.setCycle(i2);
1055 
1056         assertTrue(new EqualsBuilder().setTestRecursive(true).append(o1A, o1A).isEquals());
1057         assertTrue(new EqualsBuilder().setTestRecursive(true).append(o1A, o1B).isEquals());
1058         assertFalse(new EqualsBuilder().setTestRecursive(true).append(o1A, o2).isEquals());
1059 
1060         assertTrue(EqualsBuilder.reflectionEquals(o1A, o1B, false, null, true));
1061         assertFalse(EqualsBuilder.reflectionEquals(o1A, o2, false, null, true));
1062     }
1063 
1064     @Test
1065     public void testObjectRecursiveCycleSelfreference() {
1066         final TestRecursiveCycleObject o1A = new TestRecursiveCycleObject(1);
1067         final TestRecursiveCycleObject o1B = new TestRecursiveCycleObject(1);
1068         final TestRecursiveCycleObject o2 = new TestRecursiveCycleObject(2);
1069 
1070         assertTrue(new EqualsBuilder().setTestRecursive(true).append(o1A, o1A).isEquals());
1071         assertTrue(new EqualsBuilder().setTestRecursive(true).append(o1A, o1B).isEquals());
1072         assertFalse(new EqualsBuilder().setTestRecursive(true).append(o1A, o2).isEquals());
1073     }
1074 
1075     @Test
1076     public void testObjectRecursiveGenericInteger() {
1077         final TestRecursiveGenericObject<Integer> o1A = new TestRecursiveGenericObject<>(1);
1078         final TestRecursiveGenericObject<Integer> o1B = new TestRecursiveGenericObject<>(1);
1079         final TestRecursiveGenericObject<Integer> o2 = new TestRecursiveGenericObject<>(2);
1080 
1081         assertTrue(new EqualsBuilder().setTestRecursive(true).append(o1A, o1B).isEquals());
1082         assertTrue(new EqualsBuilder().setTestRecursive(true).append(o1B, o1A).isEquals());
1083 
1084         assertFalse(new EqualsBuilder().setTestRecursive(true).append(o1B, o2).isEquals());
1085     }
1086 
1087     @Test
1088     public void testObjectRecursiveGenericString() {
1089         // Note: Do not use literals, because string literals are always mapped by same object (internal() of String))!
1090         final String s1A = String.valueOf(1);
1091         final TestRecursiveGenericObject<String> o1A = new TestRecursiveGenericObject<>(s1A);
1092         final TestRecursiveGenericObject<String> o1B = new TestRecursiveGenericObject<>(String.valueOf(1));
1093         final TestRecursiveGenericObject<String> o2 = new TestRecursiveGenericObject<>(String.valueOf(2));
1094 
1095         // To trigger bug reported in LANG-1356, call hashCode only on string in instance o1_a
1096         s1A.hashCode();
1097 
1098         assertTrue(new EqualsBuilder().setTestRecursive(true).append(o1A, o1B).isEquals());
1099         assertTrue(new EqualsBuilder().setTestRecursive(true).append(o1B, o1A).isEquals());
1100 
1101         assertFalse(new EqualsBuilder().setTestRecursive(true).append(o1B, o2).isEquals());
1102     }
1103 
1104     @Test
1105     public void testObjectsBypassReflectionClasses() {
1106         final List<Class<?>> bypassReflectionClasses = new ArrayList<>();
1107         bypassReflectionClasses.add(List.class);
1108         bypassReflectionClasses.add(Boolean.class);
1109         assertTrue(new EqualsBuilder().setBypassReflectionClasses(bypassReflectionClasses).isEquals());
1110     }
1111 
1112     @Test
1113     public void testRaggedArray() {
1114         final long[][] array1 = new long[2][];
1115         final long[][] array2 = new long[2][];
1116         for (int i = 0; i < array1.length; ++i) {
1117             array1[i] = new long[2];
1118             array2[i] = new long[2];
1119             for (int j = 0; j < array1[i].length; ++j) {
1120                 array1[i][j] = (i + 1) * (j + 1);
1121                 array2[i][j] = (i + 1) * (j + 1);
1122             }
1123         }
1124         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
1125         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
1126         array1[1][1] = 0;
1127         assertFalse(new EqualsBuilder().append(array1, array2).isEquals());
1128     }
1129 
1130     @Test
1131     public void testReflectionAppend() {
1132         assertTrue(EqualsBuilder.reflectionEquals(null, null));
1133 
1134         final TestObject o1 = new TestObject(4);
1135         final TestObject o2 = new TestObject(5);
1136         assertTrue(new EqualsBuilder().reflectionAppend(o1, o1).build());
1137         assertFalse(new EqualsBuilder().reflectionAppend(o1, o2).build());
1138         assertFalse(new EqualsBuilder().reflectionAppend(o1, o2).reflectionAppend(o1, o1).build());
1139 
1140         o2.setA(4);
1141         assertTrue(new EqualsBuilder().reflectionAppend(o1, o2).build());
1142 
1143         assertFalse(new EqualsBuilder().reflectionAppend(o1, this).build());
1144 
1145         assertFalse(new EqualsBuilder().reflectionAppend(o1, null).build());
1146         assertFalse(new EqualsBuilder().reflectionAppend(null, o2).build());
1147     }
1148 
1149     @Test
1150     public void testReflectionArrays() {
1151 
1152         final TestObject one = new TestObject(1);
1153         final TestObject two = new TestObject(2);
1154 
1155         final Object[] o1 = {one};
1156         final Object[] o2 = {two};
1157         final Object[] o3 = {one};
1158 
1159         assertFalse(EqualsBuilder.reflectionEquals(o1, o2));
1160         assertTrue(EqualsBuilder.reflectionEquals(o1, o1));
1161         assertTrue(EqualsBuilder.reflectionEquals(o1, o3));
1162 
1163         final double[] d1 = {0, 1};
1164         final double[] d2 = {2, 3};
1165         final double[] d3 = {0, 1};
1166 
1167         assertFalse(EqualsBuilder.reflectionEquals(d1, d2));
1168         assertTrue(EqualsBuilder.reflectionEquals(d1, d1));
1169         assertTrue(EqualsBuilder.reflectionEquals(d1, d3));
1170     }
1171 
1172     @Test
1173     public void testReflectionEquals() {
1174         final TestObject o1 = new TestObject(4);
1175         final TestObject o2 = new TestObject(5);
1176         assertTrue(EqualsBuilder.reflectionEquals(o1, o1));
1177         assertFalse(EqualsBuilder.reflectionEquals(o1, o2));
1178         o2.setA(4);
1179         assertTrue(EqualsBuilder.reflectionEquals(o1, o2));
1180 
1181         assertFalse(EqualsBuilder.reflectionEquals(o1, this));
1182 
1183         assertFalse(EqualsBuilder.reflectionEquals(o1, null));
1184         assertFalse(EqualsBuilder.reflectionEquals(null, o2));
1185         assertTrue(EqualsBuilder.reflectionEquals(null, null));
1186     }
1187 
1188     /**
1189      * Equivalence relationship tests inspired by "Effective Java":
1190      * <ul>
1191      * <li>reflection</li>
1192      * <li>symmetry</li>
1193      * <li>transitive</li>
1194      * <li>consistency</li>
1195      * <li>non-null reference</li>
1196      * </ul>
1197      *
1198      * @param to             a TestObject
1199      * @param toBis          a TestObject, equal to to and toTer
1200      * @param toTer          left-hand side side, equal to to and toBis
1201      * @param to2            a different TestObject
1202      * @param oToChange      a TestObject that will be changed
1203      * @param testTransients whether to test transient instance variables
1204      */
1205     private void testReflectionEqualsEquivalenceRelationship(
1206             final TestObject to,
1207             final TestObject toBis,
1208             final TestObject toTer,
1209             final TestObject to2,
1210             final TestObject oToChange,
1211             final boolean testTransients) {
1212 
1213         // reflection test
1214         assertTrue(EqualsBuilder.reflectionEquals(to, to, testTransients));
1215         assertTrue(EqualsBuilder.reflectionEquals(to2, to2, testTransients));
1216 
1217         // symmetry test
1218         assertTrue(EqualsBuilder.reflectionEquals(to, toBis, testTransients) && EqualsBuilder.reflectionEquals(toBis, to, testTransients));
1219 
1220         // transitive test
1221         assertTrue(
1222                 EqualsBuilder.reflectionEquals(to, toBis, testTransients)
1223                         && EqualsBuilder.reflectionEquals(toBis, toTer, testTransients)
1224                         && EqualsBuilder.reflectionEquals(to, toTer, testTransients));
1225 
1226         // consistency test
1227         oToChange.setA(to.getA());
1228         if (oToChange instanceof TestSubObject) {
1229             ((TestSubObject) oToChange).setB(((TestSubObject) to).getB());
1230         }
1231         assertTrue(EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
1232         assertTrue(EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
1233         oToChange.setA(to.getA() + 1);
1234         if (oToChange instanceof TestSubObject) {
1235             ((TestSubObject) oToChange).setB(((TestSubObject) to).getB() + 1);
1236         }
1237         assertFalse(EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
1238         assertFalse(EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
1239 
1240         // non-null reference test
1241         assertFalse(EqualsBuilder.reflectionEquals(to, null, testTransients));
1242         assertFalse(EqualsBuilder.reflectionEquals(to2, null, testTransients));
1243         assertFalse(EqualsBuilder.reflectionEquals(null, to, testTransients));
1244         assertFalse(EqualsBuilder.reflectionEquals(null, to2, testTransients));
1245         assertTrue(EqualsBuilder.reflectionEquals(null, null, testTransients));
1246     }
1247 
1248     @Test
1249     public void testReflectionEqualsExcludeFields() {
1250         final TestObjectWithMultipleFields x1 = new TestObjectWithMultipleFields(1, 2, 3);
1251         final TestObjectWithMultipleFields x2 = new TestObjectWithMultipleFields(1, 3, 4);
1252 
1253         // not equal when including all fields
1254         assertFalse(EqualsBuilder.reflectionEquals(x1, x2));
1255 
1256         // doesn't barf on null, empty array, or non-existent field, but still tests as not equal
1257         assertFalse(EqualsBuilder.reflectionEquals(x1, x2, (String[]) null));
1258         assertFalse(EqualsBuilder.reflectionEquals(x1, x2));
1259         assertFalse(EqualsBuilder.reflectionEquals(x1, x2, "xxx"));
1260 
1261         // not equal if only one of the differing fields excluded
1262         assertFalse(EqualsBuilder.reflectionEquals(x1, x2, "two"));
1263         assertFalse(EqualsBuilder.reflectionEquals(x1, x2, "three"));
1264 
1265         // equal if both differing fields excluded
1266         assertTrue(EqualsBuilder.reflectionEquals(x1, x2, "two", "three"));
1267 
1268         // still equal as long as both differing fields are among excluded
1269         assertTrue(EqualsBuilder.reflectionEquals(x1, x2, "one", "two", "three"));
1270         assertTrue(EqualsBuilder.reflectionEquals(x1, x2, "one", "two", "three", "xxx"));
1271 
1272         // still equal as long as both differing fields are among excluded
1273         assertTrue(EqualsBuilder.reflectionEquals(x1, x2, Arrays.asList("one", "two", "three")));
1274         assertTrue(EqualsBuilder.reflectionEquals(x1, x2,  Arrays.asList("one", "two", "three", "xxx")));
1275 
1276     }
1277 
1278     @Test
1279     public void testReflectionHierarchyEquals() {
1280         testReflectionHierarchyEquals(false);
1281         testReflectionHierarchyEquals(true);
1282         // Transients
1283         assertTrue(EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), true));
1284         assertTrue(EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), false));
1285         assertFalse(EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 0, 0, 4), new TestTTLeafObject(1, 2, 3, 4), true));
1286         assertFalse(EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 0), true));
1287         assertFalse(EqualsBuilder.reflectionEquals(new TestTTLeafObject(0, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), true));
1288     }
1289 
1290     private void testReflectionHierarchyEquals(final boolean testTransients) {
1291         final TestObject to1 = new TestObject(4);
1292         final TestObject to1Bis = new TestObject(4);
1293         final TestObject to1Ter = new TestObject(4);
1294         final TestObject to2 = new TestObject(5);
1295         final TestEmptySubObject teso = new TestEmptySubObject(4);
1296         final TestTSubObject ttso = new TestTSubObject(4, 1);
1297         final TestTTSubObject tttso = new TestTTSubObject(4, 1, 2);
1298         final TestTTLeafObject ttlo = new TestTTLeafObject(4, 1, 2, 3);
1299         final TestSubObject tso1 = new TestSubObject(1, 4);
1300         final TestSubObject tso1bis = new TestSubObject(1, 4);
1301         final TestSubObject tso1ter = new TestSubObject(1, 4);
1302         final TestSubObject tso2 = new TestSubObject(2, 5);
1303 
1304         testReflectionEqualsEquivalenceRelationship(to1, to1Bis, to1Ter, to2, new TestObject(), testTransients);
1305         testReflectionEqualsEquivalenceRelationship(tso1, tso1bis, tso1ter, tso2, new TestSubObject(), testTransients);
1306 
1307         // More sanity checks:
1308 
1309         // same values
1310         assertTrue(EqualsBuilder.reflectionEquals(ttlo, ttlo, testTransients));
1311         assertTrue(EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(1, 10), testTransients));
1312         // same super values, diff sub values
1313         assertFalse(EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(1, 11), testTransients));
1314         assertFalse(EqualsBuilder.reflectionEquals(new TestSubObject(1, 11), new TestSubObject(1, 10), testTransients));
1315         // diff super values, same sub values
1316         assertFalse(EqualsBuilder.reflectionEquals(new TestSubObject(0, 10), new TestSubObject(1, 10), testTransients));
1317         assertFalse(EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(0, 10), testTransients));
1318 
1319         // mix super and sub types: equals
1320         assertTrue(EqualsBuilder.reflectionEquals(to1, teso, testTransients));
1321         assertTrue(EqualsBuilder.reflectionEquals(teso, to1, testTransients));
1322 
1323         assertTrue(EqualsBuilder.reflectionEquals(to1, ttso, false)); // Force testTransients = false for this assert
1324         assertTrue(EqualsBuilder.reflectionEquals(ttso, to1, false)); // Force testTransients = false for this assert
1325 
1326         assertTrue(EqualsBuilder.reflectionEquals(to1, tttso, false)); // Force testTransients = false for this assert
1327         assertTrue(EqualsBuilder.reflectionEquals(tttso, to1, false)); // Force testTransients = false for this assert
1328 
1329         assertTrue(EqualsBuilder.reflectionEquals(ttso, tttso, false)); // Force testTransients = false for this assert
1330         assertTrue(EqualsBuilder.reflectionEquals(tttso, ttso, false)); // Force testTransients = false for this assert
1331 
1332         // mix super and sub types: NOT equals
1333         assertFalse(EqualsBuilder.reflectionEquals(new TestObject(0), new TestEmptySubObject(1), testTransients));
1334         assertFalse(EqualsBuilder.reflectionEquals(new TestEmptySubObject(1), new TestObject(0), testTransients));
1335 
1336         assertFalse(EqualsBuilder.reflectionEquals(new TestObject(0), new TestTSubObject(1, 1), testTransients));
1337         assertFalse(EqualsBuilder.reflectionEquals(new TestTSubObject(1, 1), new TestObject(0), testTransients));
1338 
1339         assertFalse(EqualsBuilder.reflectionEquals(new TestObject(1), new TestSubObject(0, 10), testTransients));
1340         assertFalse(EqualsBuilder.reflectionEquals(new TestSubObject(0, 10), new TestObject(1), testTransients));
1341 
1342         assertFalse(EqualsBuilder.reflectionEquals(to1, ttlo));
1343         assertFalse(EqualsBuilder.reflectionEquals(tso1, this));
1344     }
1345 
1346     @Test
1347     public void testReset() {
1348         final EqualsBuilder equalsBuilder = new EqualsBuilder();
1349         assertTrue(equalsBuilder.isEquals());
1350         equalsBuilder.setEquals(false);
1351         assertFalse(equalsBuilder.isEquals());
1352         equalsBuilder.reset();
1353         assertTrue(equalsBuilder.isEquals());
1354     }
1355 
1356     @Test
1357     public void testShort() {
1358         final short o1 = 1;
1359         final short o2 = 2;
1360         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
1361         assertFalse(new EqualsBuilder().append(o1, o2).isEquals());
1362         assertFalse(new EqualsBuilder().append(o1, o2).append(o1, o1).isEquals());
1363     }
1364 
1365     @Test
1366     public void testShortArray() {
1367         final short[] obj1 = new short[2];
1368         obj1[0] = 5;
1369         obj1[1] = 6;
1370         final short[] obj2 = new short[2];
1371         obj2[0] = 5;
1372         obj2[1] = 6;
1373         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
1374         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
1375         obj1[1] = 7;
1376         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
1377         assertFalse(new EqualsBuilder().append(obj1, obj2).append(obj1, obj1).isEquals());
1378 
1379         final short[] nullArr1 = null;
1380         final short[] nullArr2 = null;
1381         assertFalse(new EqualsBuilder().append(obj1, nullArr2).isEquals());
1382         assertFalse(new EqualsBuilder().append(nullArr1, obj2).isEquals());
1383         assertTrue(new EqualsBuilder().append(nullArr1, nullArr2).isEquals());
1384         assertTrue(new EqualsBuilder().append(nullArr1, nullArr1).isEquals());
1385     }
1386 
1387     @Test
1388     public void testShortArrayHiddenByObject() {
1389         final short[] array1 = new short[2];
1390         array1[0] = 5;
1391         array1[1] = 6;
1392         final short[] array2 = new short[2];
1393         array2[0] = 5;
1394         array2[1] = 6;
1395         final Object obj1 = array1;
1396         final Object obj2 = array2;
1397         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
1398         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
1399         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
1400         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
1401         array1[1] = 7;
1402         assertFalse(new EqualsBuilder().append(obj1, obj2).isEquals());
1403     }
1404 
1405     @Test
1406     public void testSuper() {
1407         final TestObject o1 = new TestObject(4);
1408         final TestObject o2 = new TestObject(5);
1409         assertTrue(new EqualsBuilder().appendSuper(true).append(o1, o1).isEquals());
1410         assertFalse(new EqualsBuilder().appendSuper(false).append(o1, o1).isEquals());
1411         assertFalse(new EqualsBuilder().appendSuper(true).append(o1, o2).isEquals());
1412         assertFalse(new EqualsBuilder().appendSuper(false).append(o1, o2).isEquals());
1413         assertFalse(new EqualsBuilder().appendSuper(false).append(o1, o2).isEquals());
1414         assertFalse(new EqualsBuilder().append(o1, o2).appendSuper(false).isEquals());
1415     }
1416 
1417     @Test
1418     public void testToEqualsExclude() {
1419         TestObjectEqualsExclude one = new TestObjectEqualsExclude(1, 2);
1420         TestObjectEqualsExclude two = new TestObjectEqualsExclude(1, 3);
1421 
1422         assertFalse(EqualsBuilder.reflectionEquals(one, two));
1423 
1424         one = new TestObjectEqualsExclude(1, 2);
1425         two = new TestObjectEqualsExclude(2, 2);
1426 
1427         assertTrue(EqualsBuilder.reflectionEquals(one, two));
1428     }
1429 
1430     /**
1431      * Tests two instances of classes that can be equal and that are not "related". The two classes are not subclasses
1432      * of each other and do not share a parent aside from Object.
1433      * See https://issues.apache.org/jira/browse/LANG-6
1434      */
1435     @Test
1436     public void testUnrelatedClasses() {
1437         final Object[] x = {new TestACanEqualB(1)};
1438         final Object[] y = {new TestBCanEqualA(1)};
1439 
1440         // sanity checks:
1441         assertArrayEquals(x, x);
1442         assertArrayEquals(y, y);
1443         assertArrayEquals(x, y);
1444         assertArrayEquals(y, x);
1445         // real tests:
1446         assertEquals(x[0], x[0]);
1447         assertEquals(y[0], y[0]);
1448         assertEquals(x[0], y[0]);
1449         assertEquals(y[0], x[0]);
1450         assertTrue(new EqualsBuilder().append(x, x).isEquals());
1451         assertTrue(new EqualsBuilder().append(y, y).isEquals());
1452         assertTrue(new EqualsBuilder().append(x, y).isEquals());
1453         assertTrue(new EqualsBuilder().append(y, x).isEquals());
1454     }
1455 }
1456