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