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  
18  package org.apache.commons.lang3.builder;
19  
20  import static org.apache.commons.lang3.LangAssertions.assertIllegalArgumentException;
21  import static org.apache.commons.lang3.LangAssertions.assertNullPointerException;
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertNotEquals;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  
26  import org.apache.commons.lang3.AbstractLangTest;
27  import org.junit.jupiter.api.Test;
28  
29  /**
30   * Tests {@link HashCodeBuilder}.
31   */
32  class HashCodeBuilderTest extends AbstractLangTest {
33  
34      /**
35       * Holds a {@link ReflectionHashCodeMember} and is itself reflection hashed.
36       */
37      static final class ReflectionHashCodeHolder {
38          final ReflectionHashCodeMember member;
39  
40          ReflectionHashCodeHolder(final ReflectionHashCodeMember member) {
41              this.member = member;
42          }
43  
44          @Override
45          public boolean equals(final Object o) {
46              return EqualsBuilder.reflectionEquals(this, o);
47          }
48  
49          @Override
50          public int hashCode() {
51              return HashCodeBuilder.reflectionHashCode(this);
52          }
53      }
54      /**
55       * A reflection test fixture whose {@code hashCode()} is reflection based.
56       */
57      static final class ReflectionHashCodeMember {
58          final int value;
59  
60          ReflectionHashCodeMember(final int value) {
61              this.value = value;
62          }
63  
64          @Override
65          public boolean equals(final Object o) {
66              return EqualsBuilder.reflectionEquals(this, o);
67          }
68  
69          @Override
70          public int hashCode() {
71              return HashCodeBuilder.reflectionHashCode(this);
72          }
73      }
74  
75      /**
76       * A reflection test fixture.
77       */
78      static class ReflectionTestCycleA {
79          ReflectionTestCycleB b;
80  
81          @Override
82          public boolean equals(final Object o) {
83              // Pairs with hashCode()
84              return super.equals(o);
85          }
86  
87          @Override
88          public int hashCode() {
89              return HashCodeBuilder.reflectionHashCode(this);
90          }
91      }
92  
93      /**
94       * A reflection test fixture.
95       */
96      static class ReflectionTestCycleB {
97          ReflectionTestCycleA a;
98  
99          @Override
100         public boolean equals(final Object o) {
101             // Pairs with hashCode()
102             return super.equals(o);
103         }
104 
105         @Override
106         public int hashCode() {
107             return HashCodeBuilder.reflectionHashCode(this);
108         }
109     }
110 
111     static class TestObject {
112         private int a;
113 
114         TestObject(final int a) {
115             this.a = a;
116         }
117 
118         @Override
119         public boolean equals(final Object o) {
120             if (o == this) {
121                 return true;
122             }
123             if (!(o instanceof TestObject)) {
124                 return false;
125             }
126             final TestObject rhs = (TestObject) o;
127             return a == rhs.a;
128         }
129 
130         public int getA() {
131             return a;
132         }
133 
134         @Override
135         public int hashCode() {
136             return a;
137         }
138 
139         public void setA(final int a) {
140             this.a = a;
141         }
142     }
143 
144     static class TestObjectHashCodeExclude {
145         @HashCodeExclude
146         private final int a;
147         private final int b;
148 
149         TestObjectHashCodeExclude(final int a, final int b) {
150             this.a = a;
151             this.b = b;
152         }
153 
154         public int getA() {
155             return a;
156         }
157 
158         public int getB() {
159             return b;
160         }
161     }
162 
163     static class TestObjectHashCodeExclude2 {
164         @HashCodeExclude
165         private final int a;
166         @HashCodeExclude
167         private final int b;
168 
169         TestObjectHashCodeExclude2(final int a, final int b) {
170             this.a = a;
171             this.b = b;
172         }
173 
174         public int getA() {
175             return a;
176         }
177 
178         public int getB() {
179             return b;
180         }
181     }
182 
183     static class TestObjectWithMultipleFields {
184         @SuppressWarnings("unused")
185         private final int one;
186 
187         @SuppressWarnings("unused")
188         private final int two;
189 
190         @SuppressWarnings("unused")
191         private final int three;
192 
193         TestObjectWithMultipleFields(final int one, final int two, final int three) {
194             this.one = one;
195             this.two = two;
196             this.three = three;
197         }
198     }
199 
200     static class TestSubObject extends TestObject {
201         private int b;
202 
203         @SuppressWarnings("unused")
204         private transient int t;
205 
206         TestSubObject() {
207             super(0);
208         }
209 
210         TestSubObject(final int a, final int b, final int t) {
211             super(a);
212             this.b = b;
213             this.t = t;
214         }
215 
216         @Override
217         public boolean equals(final Object o) {
218             if (o == this) {
219                 return true;
220             }
221             if (!(o instanceof TestSubObject)) {
222                 return false;
223             }
224             final TestSubObject rhs = (TestSubObject) o;
225             return super.equals(o) && b == rhs.b;
226         }
227 
228         @Override
229         public int hashCode() {
230             return b * INITIAL + super.hashCode();
231         }
232 
233     }
234 
235     private static final int INITIAL = 17;
236 
237     private static final int CONSTANT = 37;
238 
239     /**
240      * {@code append(Object)} must not collapse an object whose own {@code hashCode()} is reflection based to the bare
241      * initial value. Regression for the cycle guard leaking into the reflection registry.
242      */
243     @Test
244     void testAppendObjectReflectionHashCodeNotPoisoned() {
245         final ReflectionHashCodeMember member = new ReflectionHashCodeMember(42);
246         assertEquals(INITIAL * CONSTANT + member.hashCode(),
247             new HashCodeBuilder(INITIAL, CONSTANT).append((Object) member).toHashCode());
248 
249         // The same defect reached through a normal, acyclic graph: a nested object's content must still influence
250         // the enclosing reflection hash.
251         final int h1 = new ReflectionHashCodeHolder(new ReflectionHashCodeMember(1)).hashCode();
252         final int h2 = new ReflectionHashCodeHolder(new ReflectionHashCodeMember(2)).hashCode();
253         assertNotEquals(h1, h2);
254 
255         assertTrue(HashCodeBuilder.getRegistry().isEmpty());
256     }
257 
258     @Test
259     void testBoolean() {
260         assertEquals(INITIAL * CONSTANT + 0, new HashCodeBuilder(INITIAL, CONSTANT).append(true).toHashCode());
261         assertEquals(INITIAL * CONSTANT + 1, new HashCodeBuilder(INITIAL, CONSTANT).append(false).toHashCode());
262     }
263 
264     @Test
265     void testBooleanArray() {
266         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((boolean[]) null).toHashCode());
267         final boolean[] obj = new boolean[2];
268         assertEquals((INITIAL * CONSTANT + 1) * CONSTANT + 1, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
269         obj[0] = true;
270         assertEquals((INITIAL * CONSTANT + 0) * CONSTANT + 1, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
271         obj[1] = false;
272         assertEquals((INITIAL * CONSTANT + 0) * CONSTANT + 1, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
273     }
274 
275     @Test
276     void testBooleanArrayAsObject() {
277         final boolean[] obj = new boolean[2];
278         assertEquals((INITIAL * CONSTANT + 1) * CONSTANT + 1, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
279         obj[0] = true;
280         assertEquals((INITIAL * CONSTANT + 0) * CONSTANT + 1, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
281         obj[1] = false;
282         assertEquals((INITIAL * CONSTANT + 0) * CONSTANT + 1, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
283     }
284 
285     @Test
286     void testBooleanMultiArray() {
287         final boolean[][] obj = new boolean[2][];
288         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
289         obj[0] = new boolean[0];
290         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
291         obj[0] = new boolean[1];
292         assertEquals((INITIAL * CONSTANT + 1) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
293         obj[0] = new boolean[2];
294         assertEquals(((INITIAL * CONSTANT + 1) * CONSTANT + 1) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
295         obj[0][0] = true;
296         assertEquals(((INITIAL * CONSTANT + 0) * CONSTANT + 1) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
297         obj[1] = new boolean[1];
298         assertEquals(((INITIAL * CONSTANT + 0) * CONSTANT + 1) * CONSTANT + 1, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
299     }
300 
301     @Test
302     void testByte() {
303         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((byte) 0).toHashCode());
304         assertEquals(INITIAL * CONSTANT + 123, new HashCodeBuilder(INITIAL, CONSTANT).append((byte) 123).toHashCode());
305     }
306 
307     @Test
308     void testByteArray() {
309         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((byte[]) null).toHashCode());
310         final byte[] obj = new byte[2];
311         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
312         obj[0] = (byte) 5;
313         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
314         obj[1] = (byte) 6;
315         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT + 6, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
316     }
317 
318     @Test
319     void testByteArrayAsObject() {
320         final byte[] obj = new byte[2];
321         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
322         obj[0] = (byte) 5;
323         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
324         obj[1] = (byte) 6;
325         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT + 6, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
326     }
327 
328     @Test
329     void testChar() {
330         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((char) 0).toHashCode());
331         assertEquals(INITIAL * CONSTANT + 1234, new HashCodeBuilder(INITIAL, CONSTANT).append((char) 1234).toHashCode());
332     }
333 
334     @Test
335     void testCharArray() {
336         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((char[]) null).toHashCode());
337         final char[] obj = new char[2];
338         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
339         obj[0] = (char) 5;
340         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
341         obj[1] = (char) 6;
342         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT + 6, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
343     }
344 
345     @Test
346     void testCharArrayAsObject() {
347         final char[] obj = new char[2];
348         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
349         obj[0] = (char) 5;
350         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
351         obj[1] = (char) 6;
352         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT + 6, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
353     }
354 
355     @Test
356     void testConstructorExEvenFirst() {
357         assertIllegalArgumentException(() -> new HashCodeBuilder(2, 3));
358     }
359 
360     @Test
361     void testConstructorExEvenNegative() {
362         assertIllegalArgumentException(() -> new HashCodeBuilder(-2, -2));
363     }
364 
365     @Test
366     void testConstructorExEvenSecond() {
367         assertIllegalArgumentException(() -> new HashCodeBuilder(3, 2));
368     }
369 
370     @Test
371     void testConstructorExZero() {
372         assertIllegalArgumentException(() -> new HashCodeBuilder(0, 0));
373     }
374 
375     @Test
376     void testDouble() {
377         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(0d).toHashCode());
378         final double d = 1234567.89;
379         final long l = Double.doubleToLongBits(d);
380         assertEquals(INITIAL * CONSTANT + (int) (l ^ l >> 32), new HashCodeBuilder(INITIAL, CONSTANT).append(d).toHashCode());
381     }
382 
383     @Test
384     void testDoubleArray() {
385         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((double[]) null).toHashCode());
386         final double[] obj = new double[2];
387         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
388         obj[0] = 5.4d;
389         final long l1 = Double.doubleToLongBits(5.4d);
390         final int h1 = (int) (l1 ^ l1 >> 32);
391         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
392         obj[1] = 6.3d;
393         final long l2 = Double.doubleToLongBits(6.3d);
394         final int h2 = (int) (l2 ^ l2 >> 32);
395         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT + h2, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
396     }
397 
398     @Test
399     void testDoubleArrayAsObject() {
400         final double[] obj = new double[2];
401         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
402         obj[0] = 5.4d;
403         final long l1 = Double.doubleToLongBits(5.4d);
404         final int h1 = (int) (l1 ^ l1 >> 32);
405         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
406         obj[1] = 6.3d;
407         final long l2 = Double.doubleToLongBits(6.3d);
408         final int h2 = (int) (l2 ^ l2 >> 32);
409         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT + h2, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
410     }
411 
412     @Test
413     void testEquals() {
414         final HashCodeBuilder hcb1 = new HashCodeBuilder(INITIAL, CONSTANT).append(1).append('a');
415         final HashCodeBuilder hcb2 = new HashCodeBuilder(INITIAL, CONSTANT).append(1).append('a');
416         final HashCodeBuilder hcb3 = new HashCodeBuilder(INITIAL, CONSTANT).append(2).append('c');
417         assertEquals(hcb1, hcb1);
418         assertEquals(hcb1, hcb2);
419         assertEquals(hcb2, hcb1);
420         assertNotEquals(hcb1, hcb3);
421         assertNotEquals(hcb2, hcb3);
422     }
423 
424     @Test
425     void testFloat() {
426         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(0f).toHashCode());
427         final float f = 1234.89f;
428         final int i = Float.floatToIntBits(f);
429         assertEquals(INITIAL * CONSTANT + i, new HashCodeBuilder(INITIAL, CONSTANT).append(f).toHashCode());
430     }
431 
432     @Test
433     void testFloatArray() {
434         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((float[]) null).toHashCode());
435         final float[] obj = new float[2];
436         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
437         obj[0] = 5.4f;
438         final int h1 = Float.floatToIntBits(5.4f);
439         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
440         obj[1] = 6.3f;
441         final int h2 = Float.floatToIntBits(6.3f);
442         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT + h2, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
443     }
444 
445     @Test
446     void testFloatArrayAsObject() {
447         final float[] obj = new float[2];
448         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
449         obj[0] = 5.4f;
450         final int h1 = Float.floatToIntBits(5.4f);
451         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
452         obj[1] = 6.3f;
453         final int h2 = Float.floatToIntBits(6.3f);
454         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT + h2, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
455     }
456 
457     @Test
458     void testInt() {
459         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(0).toHashCode());
460         assertEquals(INITIAL * CONSTANT + 123456, new HashCodeBuilder(INITIAL, CONSTANT).append(123456).toHashCode());
461     }
462 
463     @Test
464     void testIntArray() {
465         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((int[]) null).toHashCode());
466         final int[] obj = new int[2];
467         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
468         obj[0] = 5;
469         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
470         obj[1] = 6;
471         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT + 6, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
472     }
473 
474     @Test
475     void testIntArrayAsObject() {
476         final int[] obj = new int[2];
477         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
478         obj[0] = 5;
479         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
480         obj[1] = 6;
481         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT + 6, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
482     }
483 
484     @Test
485     void testLong() {
486         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(0L).toHashCode());
487         assertEquals(INITIAL * CONSTANT + (int) (123456789L ^ 123456789L >> 32), new HashCodeBuilder(INITIAL, CONSTANT).append(
488                 123456789L).toHashCode());
489     }
490 
491     @Test
492     void testLongArray() {
493         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((long[]) null).toHashCode());
494         final long[] obj = new long[2];
495         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
496         obj[0] = 5L;
497         final int h1 = (int) (5L ^ 5L >> 32);
498         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
499         obj[1] = 6L;
500         final int h2 = (int) (6L ^ 6L >> 32);
501         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT + h2, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
502     }
503 
504     @Test
505     void testLongArrayAsObject() {
506         final long[] obj = new long[2];
507         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
508         obj[0] = 5L;
509         final int h1 = (int) (5L ^ 5L >> 32);
510         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
511         obj[1] = 6L;
512         final int h2 = (int) (6L ^ 6L >> 32);
513         assertEquals((INITIAL * CONSTANT + h1) * CONSTANT + h2, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
514     }
515 
516     @Test
517     void testObject() {
518         Object obj = null;
519         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
520         obj = new Object();
521         assertEquals(INITIAL * CONSTANT + obj.hashCode(), new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
522     }
523 
524     @Test
525     void testObjectArray() {
526         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object[]) null).toHashCode());
527         final Object[] obj = new Object[2];
528         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
529         obj[0] = new Object();
530         assertEquals((INITIAL * CONSTANT + obj[0].hashCode()) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
531         obj[1] = new Object();
532         assertEquals((INITIAL * CONSTANT + obj[0].hashCode()) * CONSTANT + obj[1].hashCode(), new HashCodeBuilder(INITIAL, CONSTANT).append(obj)
533                 .toHashCode());
534     }
535 
536     @Test
537     void testObjectArrayAsObject() {
538         final Object[] obj = new Object[2];
539         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
540         obj[0] = new Object();
541         assertEquals((INITIAL * CONSTANT + obj[0].hashCode()) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
542         obj[1] = new Object();
543         assertEquals((INITIAL * CONSTANT + obj[0].hashCode()) * CONSTANT + obj[1].hashCode(), new HashCodeBuilder(INITIAL, CONSTANT).append(
544                 (Object) obj).toHashCode());
545     }
546 
547     @Test
548     void testObjectBuild() {
549         Object obj = null;
550         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).build().intValue());
551         obj = new Object();
552         assertEquals(INITIAL * CONSTANT + obj.hashCode(), new HashCodeBuilder(INITIAL, CONSTANT).append(obj).build().intValue());
553     }
554 
555     @Test
556     void testReflectionHashCode() {
557         assertEquals(INITIAL * CONSTANT, HashCodeBuilder.reflectionHashCode(new TestObject(0)));
558         assertEquals(INITIAL * CONSTANT + 123456, HashCodeBuilder.reflectionHashCode(new TestObject(123456)));
559     }
560 
561     @Test
562     void testReflectionHashCodeEx1() {
563         assertIllegalArgumentException(() -> HashCodeBuilder.reflectionHashCode(0, 0, new TestObject(0), true));
564     }
565 
566     @Test
567     void testReflectionHashCodeEx2() {
568         assertIllegalArgumentException(() -> HashCodeBuilder.reflectionHashCode(2, 2, new TestObject(0), true));
569     }
570 
571     @Test
572     void testReflectionHashCodeEx3() {
573         assertNullPointerException(() -> HashCodeBuilder.reflectionHashCode(13, 19, null, true));
574     }
575 
576     @Test
577     void testReflectionHashCodeExcludeFields() {
578         final TestObjectWithMultipleFields x = new TestObjectWithMultipleFields(1, 2, 3);
579 
580         assertEquals(((INITIAL * CONSTANT + 1) * CONSTANT + 3) * CONSTANT + 2, HashCodeBuilder.reflectionHashCode(x));
581 
582         assertEquals(((INITIAL * CONSTANT + 1) * CONSTANT + 3) * CONSTANT + 2, HashCodeBuilder.reflectionHashCode(x, (String[]) null));
583         assertEquals(((INITIAL * CONSTANT + 1) * CONSTANT + 3) * CONSTANT + 2, HashCodeBuilder.reflectionHashCode(x));
584         assertEquals(((INITIAL * CONSTANT + 1) * CONSTANT + 3) * CONSTANT + 2, HashCodeBuilder.reflectionHashCode(x, "xxx"));
585 
586         assertEquals((INITIAL * CONSTANT + 1) * CONSTANT + 3, HashCodeBuilder.reflectionHashCode(x, "two"));
587         assertEquals((INITIAL * CONSTANT + 1) * CONSTANT + 2, HashCodeBuilder.reflectionHashCode(x, "three"));
588 
589         assertEquals(INITIAL * CONSTANT + 1, HashCodeBuilder.reflectionHashCode(x, "two", "three"));
590 
591         assertEquals(INITIAL, HashCodeBuilder.reflectionHashCode(x, "one", "two", "three"));
592         assertEquals(INITIAL, HashCodeBuilder.reflectionHashCode(x, "one", "two", "three", "xxx"));
593     }
594 
595     @Test
596     void testReflectionHierarchyHashCode() {
597         assertEquals(INITIAL * CONSTANT * CONSTANT, HashCodeBuilder.reflectionHashCode(new TestSubObject(0, 0, 0)));
598         assertEquals(INITIAL * CONSTANT * CONSTANT * CONSTANT, HashCodeBuilder.reflectionHashCode(new TestSubObject(0, 0, 0), true));
599         assertEquals((INITIAL * CONSTANT + 7890) * CONSTANT + 123456, HashCodeBuilder.reflectionHashCode(new TestSubObject(123456, 7890,
600                 0)));
601         assertEquals(((INITIAL * CONSTANT + 7890) * CONSTANT + 0) * CONSTANT + 123456, HashCodeBuilder.reflectionHashCode(new TestSubObject(
602                 123456, 7890, 0), true));
603     }
604 
605     @Test
606     void testReflectionHierarchyHashCodeEx1() {
607         assertIllegalArgumentException(() -> HashCodeBuilder.reflectionHashCode(0, 0, new TestSubObject(0, 0, 0), true));
608     }
609 
610     @Test
611     void testReflectionHierarchyHashCodeEx2() {
612         assertIllegalArgumentException(() -> HashCodeBuilder.reflectionHashCode(2, 2, new TestSubObject(0, 0, 0), true));
613     }
614 
615     /**
616      * Test Objects pointing to each other.
617      */
618     @Test
619     void testReflectionObjectCycle() {
620         final ReflectionTestCycleA a = new ReflectionTestCycleA();
621         final ReflectionTestCycleB b = new ReflectionTestCycleB();
622         a.b = b;
623         b.a = a;
624 
625         // Used to caused:
626         // java.lang.StackOverflowError
627         // at java.lang.ClassLoader.getCallerClassLoader(Native Method)
628         // at java.lang.Class.getDeclaredFields(Class.java:992)
629         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionAppend(HashCodeBuilder.java:373)
630         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:349)
631         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:155)
632         // at
633         // org.apache.commons.lang.builder.HashCodeBuilderTest$ReflectionTestCycleB.hashCode(HashCodeBuilderTest.java:53)
634         // at org.apache.commons.lang.builder.HashCodeBuilder.append(HashCodeBuilder.java:422)
635         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionAppend(HashCodeBuilder.java:383)
636         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:349)
637         // at org.apache.commons.lang.builder.HashCodeBuilder.reflectionHashCode(HashCodeBuilder.java:155)
638         // at
639         // org.apache.commons.lang.builder.HashCodeBuilderTest$ReflectionTestCycleA.hashCode(HashCodeBuilderTest.java:42)
640         // at org.apache.commons.lang.builder.HashCodeBuilder.append(HashCodeBuilder.java:422)
641 
642         a.hashCode();
643         assertTrue(HashCodeBuilder.getRegistry().isEmpty());
644         b.hashCode();
645         assertTrue(HashCodeBuilder.getRegistry().isEmpty());
646     }
647 
648     @Test
649     void testShort() {
650         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((short) 0).toHashCode());
651         assertEquals(INITIAL * CONSTANT + 12345, new HashCodeBuilder(INITIAL, CONSTANT).append((short) 12345).toHashCode());
652     }
653 
654     @Test
655     void testShortArray() {
656         assertEquals(INITIAL * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((short[]) null).toHashCode());
657         final short[] obj = new short[2];
658         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
659         obj[0] = (short) 5;
660         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
661         obj[1] = (short) 6;
662         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT + 6, new HashCodeBuilder(INITIAL, CONSTANT).append(obj).toHashCode());
663     }
664 
665     @Test
666     void testShortArrayAsObject() {
667         final short[] obj = new short[2];
668         assertEquals(INITIAL * CONSTANT * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
669         obj[0] = (short) 5;
670         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
671         obj[1] = (short) 6;
672         assertEquals((INITIAL * CONSTANT + 5) * CONSTANT + 6, new HashCodeBuilder(INITIAL, CONSTANT).append((Object) obj).toHashCode());
673     }
674 
675     @Test
676     void testSuper() {
677         final Object obj = new Object();
678         assertEquals(INITIAL * CONSTANT + 19 * 41 + obj.hashCode(), new HashCodeBuilder(INITIAL, CONSTANT).appendSuper(
679                 new HashCodeBuilder(19, 41).append(obj).toHashCode()).toHashCode());
680     }
681 
682     /**
683      * Ensures LANG-520 remains true
684      */
685     @Test
686     void testToHashCodeEqualsHashCode() {
687         final HashCodeBuilder hcb = new HashCodeBuilder(INITIAL, CONSTANT).append(new Object()).append('a');
688         assertEquals(hcb.toHashCode(), hcb.hashCode(),
689             "hashCode() is no longer returning the same value as toHashCode() - see LANG-520");
690     }
691 
692     @Test
693     void testToHashCodeExclude() {
694         final TestObjectHashCodeExclude one = new TestObjectHashCodeExclude(1, 2);
695         final TestObjectHashCodeExclude2 two = new TestObjectHashCodeExclude2(1, 2);
696         assertEquals(INITIAL * CONSTANT + 2, HashCodeBuilder.reflectionHashCode(one));
697         assertEquals(INITIAL, HashCodeBuilder.reflectionHashCode(two));
698     }
699 
700 }