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