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