1
2
3
4
5
6
7
8
9 package com.codebox.bean;
10
11 import java.io.ByteArrayInputStream;
12 import java.io.ByteArrayOutputStream;
13 import java.io.IOException;
14 import java.io.NotSerializableException;
15 import java.io.ObjectInputStream;
16 import java.io.ObjectOutputStream;
17 import java.util.Date;
18 import java.util.Objects;
19
20 import net.bytebuddy.description.type.TypeDescription;
21
22 import org.junit.jupiter.api.Assertions;
23 import org.junit.jupiter.api.BeforeEach;
24 import org.junit.jupiter.api.Test;
25 import org.opentest4j.AssertionFailedError;
26 import org.powermock.reflect.Whitebox;
27
28
29
30
31 class JavaBeanTesterTest {
32
33
34 private SampleBean sampleBean;
35
36
37 private SampleBean expectedBean;
38
39
40
41
42 @BeforeEach
43 void init() {
44 this.sampleBean = new SampleBean(null);
45 this.expectedBean = new SampleBean(null);
46 }
47
48
49
50
51 @Test
52 void loadFullBean() {
53 JavaBeanTester.builder(SampleBean.class).loadData().testInstance(this.sampleBean);
54 Assertions.assertNotNull(this.sampleBean.getDoubleWrapper());
55 }
56
57
58
59
60 @Test
61 void loadFullBeanEquals() {
62 JavaBeanTester.builder(SampleBean.class).loadData().testInstance(this.sampleBean);
63 JavaBeanTester.builder(SampleBean.class).loadData().testInstance(this.expectedBean);
64
65 this.sampleBean.setSampleDepthBean(new SampleDepthBean());
66 this.expectedBean.setSampleDepthBean(new SampleDepthBean());
67 this.sampleBean.setEmptyBean(new EmptyBean());
68 this.expectedBean.setEmptyBean(new EmptyBean());
69 JavaBeanTester.builder(SampleDepthBean.class).loadData().testInstance(this.sampleBean.getSampleDepthBean());
70 JavaBeanTester.builder(SampleDepthBean.class).loadData().testInstance(this.expectedBean.getSampleDepthBean());
71
72 JavaBeanTester.builder(SampleBean.class).loadData().testEquals(this.sampleBean, this.expectedBean);
73 }
74
75
76
77
78 @Test
79 void loadFullBeanEqualsShort() {
80 JavaBeanTester.builder(SampleBean.class).loadData().testInstance(this.sampleBean);
81 JavaBeanTester.builder(SampleBean.class).loadData().testInstance(this.expectedBean);
82 JavaBeanTester.builder(SampleBean.class).loadData().testEquals(this.sampleBean, this.expectedBean);
83 }
84
85
86
87
88 @Test
89 void loadFullBeanEqualsSkipUnderlying() {
90 JavaBeanTester.builder(SampleBean.class).testInstance(this.sampleBean);
91 JavaBeanTester.builder(SampleBean.class).testInstance(this.expectedBean);
92 JavaBeanTester.builder(SampleBean.class).testEquals(this.sampleBean, this.expectedBean);
93 }
94
95
96
97
98 @Test
99 void loadFullBeanSkipUnderlyingData() {
100 JavaBeanTester.builder(SampleBean.class).testInstance(this.sampleBean);
101 Assertions.assertNotNull(this.sampleBean.getDoubleWrapper());
102 }
103
104
105
106
107 @Test
108 void loadPartialBeanEquals() {
109 JavaBeanTester.builder(SampleBean.class).loadData().testInstance(this.sampleBean);
110 JavaBeanTester.builder(SampleBean.class).loadData().testInstance(this.expectedBean);
111
112 this.sampleBean.setSampleDepthBean(new SampleDepthBean());
113 this.expectedBean.setSampleDepthBean(new SampleDepthBean());
114 JavaBeanTester.builder(SampleDepthBean.class).loadData().testInstance(this.sampleBean.getSampleDepthBean());
115 JavaBeanTester.builder(SampleDepthBean.class).loadData().testInstance(this.expectedBean.getSampleDepthBean());
116
117 JavaBeanTester.builder(SampleBean.class).loadData().testEquals(this.sampleBean, this.expectedBean);
118 }
119
120
121
122
123 @Test
124 void loadSkipBeanProperties() {
125 JavaBeanTester.builder(SampleBean.class).loadData().skip("string").testInstance(this.sampleBean);
126 Assertions.assertNotNull(this.sampleBean.getDoubleWrapper());
127 Assertions.assertNull(this.sampleBean.getString());
128 }
129
130
131
132
133 @Test
134 void testFullBean() {
135 JavaBeanTester.builder(SampleBean.class).checkEquals().loadData().test();
136 }
137
138
139
140
141 @Test
142 void testFullBeanWithExtension() {
143 JavaBeanTester.builder(SampleBean.class, SampleExtensionBean.class).checkEquals().loadData().test();
144 }
145
146
147
148
149 @Test
150 void testFullBeanNullExt() {
151 JavaBeanTester.builder(SampleBean.class).checkEquals().loadData().test();
152 JavaBeanTester.builder(SampleValueObject.class).checkEquals().loadData().test();
153 }
154
155
156
157
158 @Test
159 void testFullBeanSkipUnderlyingData() {
160 JavaBeanTester.builder(SampleBean.class).checkEquals().test();
161 }
162
163
164
165
166 @Test
167 void testFullBeanSkipUnderlyingDataWithExtension() {
168 JavaBeanTester.builder(SampleBean.class, SampleExtensionBean.class).checkEquals().test();
169 }
170
171
172
173
174 @Test
175 void testSkipBeanProperties() {
176 JavaBeanTester.builder(SampleBean.class).checkEquals().loadData().skip("string").test();
177 }
178
179
180
181
182 @Test
183 void testSkipBeanPropertiesWithExtension() {
184 JavaBeanTester.builder(SampleBean.class, SampleExtensionBean.class).checkEquals().loadData().skip("string")
185 .test();
186 }
187
188
189
190
191 @Test
192 void testSkipBeanPropertiesNull() {
193 JavaBeanTester.builder(SampleBean.class).checkEquals().loadData().skip((String[]) null).test();
194 }
195
196
197
198
199 @Test
200 void testSkipBeanPropertiesNullWithExtension() {
201 JavaBeanTester.builder(SampleBean.class, SampleExtensionBean.class).checkEquals().loadData()
202 .skip((String[]) null).test();
203 }
204
205
206
207
208 @Test
209 void testSkipCanEquals() {
210 JavaBeanTester.builder(SampleBean.class).loadData().test();
211 }
212
213
214
215
216 @Test
217 void testSkipCanEqualsWithExtension() {
218 JavaBeanTester.builder(SampleBean.class, SampleExtensionBean.class).loadData().test();
219 }
220
221
222
223
224 @Test
225 void testSkipCanEqualsFalse() {
226 JavaBeanTester.builder(SampleBean.class).checkEquals(false).checkSerializable(false).loadData(false).test();
227 }
228
229
230
231
232 @Test
233 void testSkipCanEqualsFalseWithExtension() {
234 JavaBeanTester.builder(SampleBean.class, SampleExtensionBean.class).checkEquals(false).checkSerializable(false)
235 .loadData(false).test();
236 }
237
238
239
240
241 @Test
242 void testSerializable() {
243 JavaBeanTester.builder(SerializableBean.class).checkSerializable().test();
244 }
245
246
247
248
249 @Test
250 void testNonSerializableInternallyFails() {
251 JavaBeanTester.builder(NonSerializableBean.class).checkSerializable().skipStrictSerializable().test();
252 }
253
254
255
256
257
258
259
260 @Test
261 void testNonSerializable() throws Exception {
262 final NonDeserializableBean bean = new NonDeserializableBean();
263 bean.getList().add(new Object());
264
265 Assertions.assertThrows(NotSerializableException.class, () -> {
266 JavaBeanTesterTest.serialize(bean);
267 });
268 }
269
270
271
272
273 @Test
274 void testClear() {
275 JavaBeanTester.builder(SerializableBean.class).checkClear().test();
276 }
277
278
279
280
281 @Test
282 void testClearFalse() {
283 JavaBeanTester.builder(SerializableBean.class).checkClear(false).test();
284 }
285
286
287
288
289 @Test
290 void testConstructor() {
291 JavaBeanTester.builder(SerializableBean.class).checkConstructor().test();
292 }
293
294
295
296
297 @Test
298 void testConstructorFalse() {
299 JavaBeanTester.builder(SerializableBean.class).checkConstructor(false).test();
300 }
301
302
303
304
305 @Test
306 void testMultiConstructor() {
307 JavaBeanTester.builder(MultiConstructorBean.class).test();
308 }
309
310
311
312
313 @Test
314 void testMultiConstructorNullExtension() {
315 JavaBeanTester.builder(MultiConstructorBean.class, null).checkEquals().test();
316 }
317
318
319
320
321
322 @Test
323 void testTemporarySingleMode() {
324 final JavaBeanTesterBuilder<String, Object> builder = new JavaBeanTesterBuilder<>(String.class);
325 final JavaBeanTesterWorker<String, Object> worker = Whitebox.getInternalState(builder, "worker");
326 Assertions.assertEquals(String.class, worker.getClazz());
327 }
328
329
330
331
332 @Test
333 void testSampleLombokBuilder() {
334 JavaBeanTester.builder(SampleLombokBuilder.class).checkEquals().checkConstructor().checkClear().loadData()
335 .test();
336 }
337
338
339
340
341 @Test
342 void testSampleLombokBuilderNullExtension() {
343 JavaBeanTester.builder(SampleLombokBuilder.class, null).checkEquals().checkConstructor().checkClear().loadData()
344 .test();
345 }
346
347 @Test
348 void testCanEqualInterceptor() {
349 final JavaBeanTester.CanEqualInterceptor interceptor = new JavaBeanTester.CanEqualInterceptor();
350 Assertions.assertNotNull(interceptor);
351 Assertions.assertTrue(
352 JavaBeanTester.CanEqualInterceptor.canEqual(new TypeDescription.ForLoadedType(SampleBean.class)));
353 Assertions.assertFalse(JavaBeanTester.CanEqualInterceptor.canEqual(new Object()));
354 }
355
356 @Test
357 void testInstanceOfEqualsInterceptor() {
358 final JavaBeanTester.InstanceOfEqualsInterceptor interceptor = new JavaBeanTester.InstanceOfEqualsInterceptor();
359 Assertions.assertNotNull(interceptor);
360
361 final HashValue sameLeft = new HashValue(10);
362 final HashValue sameRight = new HashValue(10);
363 final HashValue different = new HashValue(11);
364
365 Assertions.assertTrue(JavaBeanTester.InstanceOfEqualsInterceptor.equals(sameLeft, sameLeft));
366 Assertions.assertFalse(JavaBeanTester.InstanceOfEqualsInterceptor.equals(sameLeft, null));
367 Assertions.assertFalse(JavaBeanTester.InstanceOfEqualsInterceptor.equals(sameLeft, "other-type"));
368 Assertions.assertTrue(JavaBeanTester.InstanceOfEqualsInterceptor.equals(sameLeft, sameRight));
369 Assertions.assertFalse(JavaBeanTester.InstanceOfEqualsInterceptor.equals(sameLeft, different));
370 }
371
372
373
374
375
376 @Test
377 void testCheckSerializableOnNonSerializableClassFails() {
378 Assertions.assertThrows(AssertionFailedError.class,
379 () -> JavaBeanTester.builder(SimpleNonSerializableBean.class, null).checkSerializable().test());
380 }
381
382
383
384
385 @Test
386 void testCheckEqualsSwallowsEqualsVerifierFailure() {
387
388
389
390
391 JavaBeanTester.builder(IdentityEqualsStringBean.class, null).checkEquals().loadData().test();
392 }
393
394
395
396
397
398 @Test
399 void testExternalizableBean() {
400
401
402
403 JavaBeanTester.builder(SampleExternalizableBean.class).checkSerializable().skipStrictSerializable().test();
404 }
405
406
407
408
409 @Test
410 void testSerializableWithNonSerializableFieldFails() {
411 Assertions.assertThrows(AssertionFailedError.class,
412 () -> JavaBeanTester.builder(SerializableWithThreadFieldBean.class).checkSerializable().test());
413 }
414
415
416
417
418 @Test
419 void testDateBeanGetterSetter() {
420
421 JavaBeanTester.builder(Date.class, null).loadData().test();
422 }
423
424 @Test
425 void testGetterSetterFailureIsReported() {
426 Assertions.assertThrows(AssertionFailedError.class,
427 () -> JavaBeanTester.builder(GetterSetterThrowingBean.class, null).loadData().checkEquals(false)
428 .checkConstructor(false).checkClear(false).checkSerializable(false).test());
429 }
430
431 @Test
432 void testClearFailureIsReported() {
433 Assertions.assertThrows(AssertionFailedError.class, () -> JavaBeanTester.builder(ClearThrowingBean.class, null)
434 .checkClear().checkEquals(false).checkConstructor(false).checkSerializable(false).test());
435 }
436
437 @Test
438 void testConstructorFailureIsReported() {
439 Assertions.assertThrows(AssertionFailedError.class,
440 () -> JavaBeanTester.builder(ConstructorThrowingBean.class, null).checkConstructor().checkEquals(false)
441 .checkClear(false).checkSerializable(false).test());
442 }
443
444 @Test
445 void testCheckSerializableFailureBranch() {
446 Assertions.assertThrows(AssertionFailedError.class, () -> JavaBeanTester.builder(Object.class, null)
447 .checkSerializable().checkEquals(false).checkConstructor(false).checkClear(false).test());
448 }
449
450 @Test
451 void testDeserializeFailureIsReported() {
452 Assertions.assertThrows(AssertionFailedError.class,
453 () -> JavaBeanTester.builder(SerializableWithFailingReadObject.class, null).checkSerializable()
454 .checkEquals(false).checkConstructor(false).checkClear(false).test());
455 }
456
457 @Test
458 void testProcessClassCopyFailureIsSwallowed() throws Exception {
459 CopyFailureAfterLoadBean.resetSetCalls();
460 final JavaBeanTesterWorker<CopyFailureAfterLoadBean, Object> worker = new JavaBeanTesterWorker<>(
461 CopyFailureAfterLoadBean.class);
462 worker.setLoadData(com.codebox.enums.LoadData.ON);
463 Whitebox.invokeMethod(worker, "processClassEqualsHashCodeToStringSymmetricTest", new CopyFailureAfterLoadBean(),
464 new CopyFailureAfterLoadBean());
465 }
466
467 @Test
468 void testProcessExtensionCopyFailureIsSwallowed() throws Exception {
469 final JavaBeanTesterWorker<NoSetterBaseBean, ExtensionCopyFailureBean> worker = new JavaBeanTesterWorker<>(
470 NoSetterBaseBean.class, ExtensionCopyFailureBean.class);
471 worker.setLoadData(com.codebox.enums.LoadData.ON);
472 Whitebox.invokeMethod(worker, "processExtensionEqualsHashCodeToStringSymmetricTest", new NoSetterBaseBean(),
473 new ExtensionCopyFailureBean());
474 }
475
476 @Test
477 void testEqualsSetterFailureIsReported() {
478 final JavaBeanTesterWorker<EqualsSetterThrowingBean, Object> worker = new JavaBeanTesterWorker<>(
479 EqualsSetterThrowingBean.class);
480 worker.setLoadData(com.codebox.enums.LoadData.ON);
481 Assertions.assertThrows(AssertionFailedError.class,
482 () -> worker.equalsTests(new EqualsSetterThrowingBean(), new EqualsSetterThrowingBean()));
483 }
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498 @SuppressWarnings("unchecked")
499 private static <T> T serialize(final T object) throws Exception {
500 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
501 new ObjectOutputStream(baos).writeObject(object);
502
503 final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
504 return (T) new ObjectInputStream(bais).readObject();
505 }
506
507
508
509
510
511 @Test
512 void testEqualsWithSetterOnlyProperty() {
513 var instance = new SetterOnlyBean();
514 var expected = new SetterOnlyBean();
515 JavaBeanTester.builder(SetterOnlyBean.class, null).testEquals(instance, expected);
516 }
517
518
519
520
521 static class SetterOnlyBean {
522
523 @SuppressWarnings("unused")
524 private String value;
525
526
527
528
529
530
531
532 public void setValue(final String value) {
533 this.value = value;
534 }
535 }
536
537 public static class GetterSetterThrowingBean {
538 private String value;
539
540 public GetterSetterThrowingBean() {
541 }
542
543 public String getValue() {
544 return this.value;
545 }
546
547 public void setValue(final String value) {
548 throw new IllegalStateException("setter-failure");
549 }
550 }
551
552 public static class ClearThrowingBean {
553 public ClearThrowingBean() {
554 }
555
556 public void clear() {
557 throw new IllegalStateException("clear-failure");
558 }
559 }
560
561 public static class ConstructorThrowingBean {
562 public ConstructorThrowingBean() {
563 }
564
565 public ConstructorThrowingBean(final String value) {
566 throw new IllegalStateException(value);
567 }
568 }
569
570 public static class SerializableWithFailingReadObject implements java.io.Serializable {
571 private static final long serialVersionUID = 1L;
572
573 private String value = "ok";
574
575 public SerializableWithFailingReadObject() {
576 }
577
578 public String getValue() {
579 return this.value;
580 }
581
582 public void setValue(final String value) {
583 this.value = value;
584 }
585
586 @SuppressWarnings("unused")
587 private void readObject(final ObjectInputStream stream) throws IOException {
588 throw new IOException("deserialize-failure");
589 }
590 }
591
592 public static class CopyFailureAfterLoadBean {
593 private static int setCalls;
594
595 private String value;
596
597 public CopyFailureAfterLoadBean() {
598 }
599
600 static void resetSetCalls() {
601 setCalls = 0;
602 }
603
604 public String getValue() {
605 return this.value;
606 }
607
608 public void setValue(final String value) {
609 setCalls++;
610 if (setCalls >= 5) {
611 throw new IllegalStateException("copy-failure");
612 }
613 this.value = value;
614 }
615
616 @Override
617 public int hashCode() {
618 return Objects.hash(this.value);
619 }
620
621 @Override
622 public boolean equals(final Object obj) {
623 if (this == obj) {
624 return true;
625 }
626 if (!(obj instanceof CopyFailureAfterLoadBean)) {
627 return false;
628 }
629 final CopyFailureAfterLoadBean other = (CopyFailureAfterLoadBean) obj;
630 return Objects.equals(this.value, other.value);
631 }
632 }
633
634 public static class NoSetterBaseBean {
635 public NoSetterBaseBean() {
636 }
637 }
638
639 public static class ExtensionCopyFailureBean {
640 public ExtensionCopyFailureBean() {
641 }
642
643 public String getValue() {
644 return "value";
645 }
646
647 public void setValue(final String value) {
648 throw new IllegalStateException("extension-copy-failure");
649 }
650 }
651
652 public static class EqualsSetterThrowingBean {
653 private String value;
654
655 public EqualsSetterThrowingBean() {
656 }
657
658 public String getValue() {
659 return this.value;
660 }
661
662 public void setValue(final String value) {
663 throw new IllegalStateException("equals-failure");
664 }
665 }
666
667
668
669
670 static final class HashValue {
671 private final int hashCode;
672
673 HashValue(final int hashCode) {
674 this.hashCode = hashCode;
675 }
676
677 @Override
678 public int hashCode() {
679 return this.hashCode;
680 }
681 }
682
683 }