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