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