1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.testing;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static com.google.common.truth.Truth.assertThat;
22
23 import com.google.common.base.Converter;
24 import com.google.common.base.Function;
25 import com.google.common.base.Supplier;
26 import com.google.common.collect.ImmutableList;
27 import com.google.common.collect.ImmutableMap;
28 import com.google.common.collect.ImmutableMultimap;
29 import com.google.common.collect.ImmutableMultiset;
30 import com.google.common.collect.ImmutableSet;
31 import com.google.common.collect.ImmutableSortedSet;
32 import com.google.common.collect.ImmutableTable;
33 import com.google.common.collect.Maps;
34 import com.google.common.collect.Multimap;
35 import com.google.common.collect.Multiset;
36 import com.google.common.collect.Table;
37 import com.google.common.reflect.TypeToken;
38 import com.google.common.testing.NullPointerTester.Visibility;
39 import com.google.common.testing.anotherpackage.SomeClassThatDoesNotUseNullable;
40
41 import junit.framework.AssertionFailedError;
42 import junit.framework.TestCase;
43
44 import java.lang.reflect.Constructor;
45 import java.lang.reflect.Method;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Set;
49 import java.util.SortedSet;
50
51 import javax.annotation.Nullable;
52
53
54
55
56
57
58
59 public class NullPointerTesterTest extends TestCase {
60
61
62 public static class FooException extends RuntimeException {
63 private static final long serialVersionUID = 1L;
64 }
65
66
67
68
69
70 @SuppressWarnings("unused")
71 public static class OneArg {
72
73 public static void staticOneArgCorrectlyThrowsNpe(String s) {
74 checkNotNull(s);
75 }
76 public static void staticOneArgThrowsOtherThanNpe(String s) {
77 throw new FooException();
78 }
79 public static void staticOneArgShouldThrowNpeButDoesnt(String s) {
80
81 }
82 public static void
83 staticOneArgNullableCorrectlyDoesNotThrowNPE(@Nullable String s) {
84
85 }
86 public static void
87 staticOneArgNullableCorrectlyThrowsOtherThanNPE(@Nullable String s) {
88 throw new FooException();
89 }
90 public static void
91 staticOneArgNullableThrowsNPE(@Nullable String s) {
92 checkNotNull(s);
93 }
94
95 public void oneArgCorrectlyThrowsNpe(String s) {
96 checkNotNull(s);
97 }
98 public void oneArgThrowsOtherThanNpe(String s) {
99 throw new FooException();
100 }
101 public void oneArgShouldThrowNpeButDoesnt(String s) {
102
103 }
104 public void oneArgNullableCorrectlyDoesNotThrowNPE(@Nullable String s) {
105
106 }
107 public void oneArgNullableCorrectlyThrowsOtherThanNPE(@Nullable String s) {
108 throw new FooException();
109 }
110 public void oneArgNullableThrowsNPE(@Nullable String s) {
111 checkNotNull(s);
112 }
113 }
114
115 private static final String[] STATIC_ONE_ARG_METHODS_SHOULD_PASS = {
116 "staticOneArgCorrectlyThrowsNpe",
117 "staticOneArgNullableCorrectlyDoesNotThrowNPE",
118 "staticOneArgNullableCorrectlyThrowsOtherThanNPE",
119 "staticOneArgNullableThrowsNPE",
120 };
121 private static final String[] STATIC_ONE_ARG_METHODS_SHOULD_FAIL = {
122 "staticOneArgThrowsOtherThanNpe",
123 "staticOneArgShouldThrowNpeButDoesnt",
124 };
125 private static final String[] NONSTATIC_ONE_ARG_METHODS_SHOULD_PASS = {
126 "oneArgCorrectlyThrowsNpe",
127 "oneArgNullableCorrectlyDoesNotThrowNPE",
128 "oneArgNullableCorrectlyThrowsOtherThanNPE",
129 "oneArgNullableThrowsNPE",
130 };
131 private static final String[] NONSTATIC_ONE_ARG_METHODS_SHOULD_FAIL = {
132 "oneArgThrowsOtherThanNpe",
133 "oneArgShouldThrowNpeButDoesnt",
134 };
135
136 private static class ThrowsIae {
137 public static void christenPoodle(String name) {
138 checkArgument(name != null);
139 }
140 }
141
142 private static class ThrowsNpe {
143 public static void christenPoodle(String name) {
144 checkNotNull(name);
145 }
146 }
147
148 private static class ThrowsUoe {
149 public static void christenPoodle(String name) {
150 throw new UnsupportedOperationException();
151 }
152 }
153
154 private static class ThrowsSomethingElse {
155 public static void christenPoodle(String name) {
156 throw new RuntimeException();
157 }
158 }
159
160 public void testDontAcceptIae() {
161 NullPointerTester tester = new NullPointerTester();
162 tester.testAllPublicStaticMethods(ThrowsNpe.class);
163 tester.testAllPublicStaticMethods(ThrowsUoe.class);
164 try {
165 tester.testAllPublicStaticMethods(ThrowsIae.class);
166 } catch (AssertionFailedError expected) {
167 return;
168 }
169 fail();
170 }
171
172 public void testStaticOneArgMethodsThatShouldPass() throws Exception {
173 for (String methodName : STATIC_ONE_ARG_METHODS_SHOULD_PASS) {
174 Method method = OneArg.class.getMethod(methodName, String.class);
175 try {
176 new NullPointerTester().testMethodParameter(new OneArg(), method, 0);
177 } catch (AssertionFailedError unexpected) {
178 fail("Should not have flagged method " + methodName);
179 }
180 }
181 }
182
183 public void testStaticOneArgMethodsThatShouldFail() throws Exception {
184 for (String methodName : STATIC_ONE_ARG_METHODS_SHOULD_FAIL) {
185 Method method = OneArg.class.getMethod(methodName, String.class);
186 boolean foundProblem = false;
187 try {
188 new NullPointerTester().testMethodParameter(new OneArg(), method, 0);
189 } catch (AssertionFailedError expected) {
190 foundProblem = true;
191 }
192 assertTrue("Should report error in method " + methodName, foundProblem);
193 }
194 }
195
196 public void testNonStaticOneArgMethodsThatShouldPass() throws Exception {
197 OneArg foo = new OneArg();
198 for (String methodName : NONSTATIC_ONE_ARG_METHODS_SHOULD_PASS) {
199 Method method = OneArg.class.getMethod(methodName, String.class);
200 try {
201 new NullPointerTester().testMethodParameter(foo, method, 0);
202 } catch (AssertionFailedError unexpected) {
203 fail("Should not have flagged method " + methodName);
204 }
205 }
206 }
207
208 public void testNonStaticOneArgMethodsThatShouldFail() throws Exception {
209 OneArg foo = new OneArg();
210 for (String methodName : NONSTATIC_ONE_ARG_METHODS_SHOULD_FAIL) {
211 Method method = OneArg.class.getMethod(methodName, String.class);
212 boolean foundProblem = false;
213 try {
214 new NullPointerTester().testMethodParameter(foo, method, 0);
215 } catch (AssertionFailedError expected) {
216 foundProblem = true;
217 }
218 assertTrue("Should report error in method " + methodName, foundProblem);
219 }
220 }
221
222
223
224
225
226
227
228
229
230
231 public static class TwoArg {
232
233 public enum Action {
234 THROW_A_NPE {
235 @Override public void act() {
236 throw new NullPointerException();
237 }
238 },
239 THROW_OTHER {
240 @Override public void act() {
241 throw new FooException();
242 }
243 },
244 JUST_RETURN {
245 @Override public void act() {}
246 };
247
248 public abstract void act();
249 }
250 Action actionWhenFirstParamIsNull;
251 Action actionWhenSecondParamIsNull;
252
253 public TwoArg(
254 Action actionWhenFirstParamIsNull,
255 Action actionWhenSecondParamIsNull) {
256 this.actionWhenFirstParamIsNull = actionWhenFirstParamIsNull;
257 this.actionWhenSecondParamIsNull = actionWhenSecondParamIsNull;
258 }
259
260
261 public void reactToNullParameters(Object first, Object second) {
262 if (first == null) {
263 actionWhenFirstParamIsNull.act();
264 }
265 if (second == null) {
266 actionWhenSecondParamIsNull.act();
267 }
268 }
269
270
271 public void normalNormal(String first, Integer second) {
272 reactToNullParameters(first, second);
273 }
274
275
276 public void normalNullable(String first, @Nullable Integer second) {
277 reactToNullParameters(first, second);
278 }
279
280
281 public void nullableNormal(@Nullable String first, Integer second) {
282 reactToNullParameters(first, second);
283 }
284
285
286 public void nullableNullable(
287 @Nullable String first, @Nullable Integer second) {
288 reactToNullParameters(first, second);
289 }
290
291
292 @Override public String toString() {
293 return String.format("Bar(%s, %s)",
294 actionWhenFirstParamIsNull, actionWhenSecondParamIsNull);
295 }
296 }
297
298 public void verifyBarPass(Method method, TwoArg bar) {
299 try {
300 new NullPointerTester().testMethod(bar, method);
301 } catch (AssertionFailedError incorrectError) {
302 String errorMessage = String.format(
303 "Should not have flagged method %s for %s", method.getName(), bar);
304 assertNull(errorMessage, incorrectError);
305 }
306 }
307
308 public void verifyBarFail(Method method, TwoArg bar) {
309 try {
310 new NullPointerTester().testMethod(bar, method);
311 } catch (AssertionFailedError expected) {
312 return;
313 }
314 String errorMessage = String.format(
315 "Should have flagged method %s for %s", method.getName(), bar);
316 fail(errorMessage);
317 }
318
319 public void testTwoArgNormalNormal() throws Exception {
320 Method method = TwoArg.class.getMethod(
321 "normalNormal", String.class, Integer.class);
322 for (TwoArg.Action first : TwoArg.Action.values()) {
323 for (TwoArg.Action second : TwoArg.Action.values()) {
324 TwoArg bar = new TwoArg(first, second);
325 if (first.equals(TwoArg.Action.THROW_A_NPE)
326 && second.equals(TwoArg.Action.THROW_A_NPE)) {
327 verifyBarPass(method, bar);
328 } else {
329 verifyBarFail(method, bar);
330 }
331 }
332 }
333 }
334
335 public void testTwoArgNormalNullable() throws Exception {
336 Method method = TwoArg.class.getMethod(
337 "normalNullable", String.class, Integer.class);
338 for (TwoArg.Action first : TwoArg.Action.values()) {
339 for (TwoArg.Action second : TwoArg.Action.values()) {
340 TwoArg bar = new TwoArg(first, second);
341 if (first.equals(TwoArg.Action.THROW_A_NPE)) {
342 verifyBarPass(method, bar);
343 } else {
344 verifyBarFail(method, bar);
345 }
346 }
347 }
348 }
349
350 public void testTwoArgNullableNormal() throws Exception {
351 Method method = TwoArg.class.getMethod(
352 "nullableNormal", String.class, Integer.class);
353 for (TwoArg.Action first : TwoArg.Action.values()) {
354 for (TwoArg.Action second : TwoArg.Action.values()) {
355 TwoArg bar = new TwoArg(first, second);
356 if (second.equals(TwoArg.Action.THROW_A_NPE)) {
357 verifyBarPass(method, bar);
358 } else {
359 verifyBarFail(method, bar);
360 }
361 }
362 }
363 }
364
365 public void testTwoArgNullableNullable() throws Exception {
366 Method method = TwoArg.class.getMethod(
367 "nullableNullable", String.class, Integer.class);
368 for (TwoArg.Action first : TwoArg.Action.values()) {
369 for (TwoArg.Action second : TwoArg.Action.values()) {
370 TwoArg bar = new TwoArg(first, second);
371 verifyBarPass(method, bar);
372 }
373 }
374 }
375
376
377
378
379
380
381
382
383 @SuppressWarnings("unused")
384 private static class PassObject extends SomeClassThatDoesNotUseNullable {
385 public static void doThrow(Object arg) {
386 if (arg == null) {
387 throw new FooException();
388 }
389 }
390 public void noArg() {}
391 public void oneArg(String s) { checkNotNull(s); }
392 void packagePrivateOneArg(String s) { checkNotNull(s); }
393 protected void protectedOneArg(String s) { checkNotNull(s); }
394 public void oneNullableArg(@Nullable String s) {}
395 public void oneNullableArgThrows(@Nullable String s) { doThrow(s); }
396
397 public void twoArg(String s, Integer i) { checkNotNull(s); i.intValue(); }
398 public void twoMixedArgs(String s, @Nullable Integer i) { checkNotNull(s); }
399 public void twoMixedArgsThrows(String s, @Nullable Integer i) {
400 checkNotNull(s); doThrow(i);
401 }
402 public void twoMixedArgs(@Nullable Integer i, String s) { checkNotNull(s); }
403 public void twoMixedArgsThrows(@Nullable Integer i, String s) {
404 checkNotNull(s); doThrow(i);
405 }
406 public void twoNullableArgs(@Nullable String s,
407 @javax.annotation.Nullable Integer i) {}
408 public void twoNullableArgsThrowsFirstArg(
409 @Nullable String s, @Nullable Integer i) {
410 doThrow(s);
411 }
412 public void twoNullableArgsThrowsSecondArg(
413 @Nullable String s, @Nullable Integer i) {
414 doThrow(i);
415 }
416 public static void staticOneArg(String s) { checkNotNull(s); }
417 public static void staticOneNullableArg(@Nullable String s) {}
418 public static void staticOneNullableArgThrows(@Nullable String s) {
419 doThrow(s);
420 }
421 }
422
423 public void testGoodClass() {
424 shouldPass(new PassObject());
425 }
426
427 private static class FailOneArgDoesntThrowNPE extends PassObject {
428 @Override public void oneArg(String s) {
429
430 }
431 }
432
433 public void testFailOneArgDoesntThrowNpe() {
434 shouldFail(new FailOneArgDoesntThrowNPE());
435 }
436
437 private static class FailOneArgThrowsWrongType extends PassObject {
438 @Override public void oneArg(String s) {
439 doThrow(s);
440 }
441 }
442
443 public void testFailOneArgThrowsWrongType() {
444 shouldFail(new FailOneArgThrowsWrongType());
445 }
446
447 private static class PassOneNullableArgThrowsNPE extends PassObject {
448 @Override public void oneNullableArg(@Nullable String s) {
449 checkNotNull(s);
450 }
451 }
452
453 public void testPassOneNullableArgThrowsNPE() {
454 shouldPass(new PassOneNullableArgThrowsNPE());
455 }
456
457 private static class FailTwoArgsFirstArgDoesntThrowNPE extends PassObject {
458 @Override public void twoArg(String s, Integer i) {
459
460 i.intValue();
461 }
462 }
463
464 public void testFailTwoArgsFirstArgDoesntThrowNPE() {
465 shouldFail(new FailTwoArgsFirstArgDoesntThrowNPE());
466 }
467
468 private static class FailTwoArgsFirstArgThrowsWrongType extends PassObject {
469 @Override public void twoArg(String s, Integer i) {
470 doThrow(s);
471 i.intValue();
472 }
473 }
474
475 public void testFailTwoArgsFirstArgThrowsWrongType() {
476 shouldFail(new FailTwoArgsFirstArgThrowsWrongType());
477 }
478
479 private static class FailTwoArgsSecondArgDoesntThrowNPE extends PassObject {
480 @Override public void twoArg(String s, Integer i) {
481 checkNotNull(s);
482
483 }
484 }
485
486 public void testFailTwoArgsSecondArgDoesntThrowNPE() {
487 shouldFail(new FailTwoArgsSecondArgDoesntThrowNPE());
488 }
489
490 private static class FailTwoArgsSecondArgThrowsWrongType extends PassObject {
491 @Override public void twoArg(String s, Integer i) {
492 checkNotNull(s);
493 doThrow(i);
494 }
495 }
496
497 public void testFailTwoArgsSecondArgThrowsWrongType() {
498 shouldFail(new FailTwoArgsSecondArgThrowsWrongType());
499 }
500
501 private static class FailTwoMixedArgsFirstArgDoesntThrowNPE
502 extends PassObject {
503 @Override public void twoMixedArgs(String s, @Nullable Integer i) {
504
505 }
506 }
507
508 public void testFailTwoMixedArgsFirstArgDoesntThrowNPE() {
509 shouldFail(new FailTwoMixedArgsFirstArgDoesntThrowNPE());
510 }
511
512 private static class FailTwoMixedArgsFirstArgThrowsWrongType
513 extends PassObject {
514 @Override public void twoMixedArgs(String s, @Nullable Integer i) {
515 doThrow(s);
516 }
517 }
518
519 public void testFailTwoMixedArgsFirstArgThrowsWrongType() {
520 shouldFail(new FailTwoMixedArgsFirstArgThrowsWrongType());
521 }
522
523 private static class PassTwoMixedArgsNullableArgThrowsNPE extends PassObject {
524 @Override public void twoMixedArgs(String s, @Nullable Integer i) {
525 checkNotNull(s);
526 i.intValue();
527 }
528 }
529
530 public void testPassTwoMixedArgsNullableArgThrowsNPE() {
531 shouldPass(new PassTwoMixedArgsNullableArgThrowsNPE());
532 }
533
534 private static class PassTwoMixedArgSecondNullableArgThrowsOther
535 extends PassObject {
536 @Override public void twoMixedArgs(String s, @Nullable Integer i) {
537 checkNotNull(s);
538 doThrow(i);
539 }
540 }
541
542 public void testPassTwoMixedArgSecondNullableArgThrowsOther() {
543 shouldPass(new PassTwoMixedArgSecondNullableArgThrowsOther());
544 }
545
546 private static class FailTwoMixedArgsSecondArgDoesntThrowNPE
547 extends PassObject {
548 @Override public void twoMixedArgs(@Nullable Integer i, String s) {
549
550 }
551 }
552
553 public void testFailTwoMixedArgsSecondArgDoesntThrowNPE() {
554 shouldFail(new FailTwoMixedArgsSecondArgDoesntThrowNPE());
555 }
556
557 private static class FailTwoMixedArgsSecondArgThrowsWrongType
558 extends PassObject {
559 @Override public void twoMixedArgs(@Nullable Integer i, String s) {
560 doThrow(s);
561 }
562 }
563
564 public void testFailTwoMixedArgsSecondArgThrowsWrongType() {
565 shouldFail(new FailTwoMixedArgsSecondArgThrowsWrongType());
566 }
567
568 private static class PassTwoNullableArgsFirstThrowsNPE extends PassObject {
569 @Override public void twoNullableArgs(
570 @Nullable String s, @Nullable Integer i) {
571 checkNotNull(s);
572 }
573 }
574
575 public void testPassTwoNullableArgsFirstThrowsNPE() {
576 shouldPass(new PassTwoNullableArgsFirstThrowsNPE());
577 }
578
579 private static class PassTwoNullableArgsFirstThrowsOther extends PassObject {
580 @Override public void twoNullableArgs(
581 @Nullable String s, @Nullable Integer i) {
582 doThrow(s);
583 }
584 }
585
586 public void testPassTwoNullableArgsFirstThrowsOther() {
587 shouldPass(new PassTwoNullableArgsFirstThrowsOther());
588 }
589
590 private static class PassTwoNullableArgsSecondThrowsNPE extends PassObject {
591 @Override public void twoNullableArgs(
592 @Nullable String s, @Nullable Integer i) {
593 i.intValue();
594 }
595 }
596
597 public void testPassTwoNullableArgsSecondThrowsNPE() {
598 shouldPass(new PassTwoNullableArgsSecondThrowsNPE());
599 }
600
601 private static class PassTwoNullableArgsSecondThrowsOther extends PassObject {
602 @Override public void twoNullableArgs(
603 @Nullable String s, @Nullable Integer i) {
604 doThrow(i);
605 }
606 }
607
608 public void testPassTwoNullableArgsSecondThrowsOther() {
609 shouldPass(new PassTwoNullableArgsSecondThrowsOther());
610 }
611
612 private static class PassTwoNullableArgsNeitherThrowsAnything
613 extends PassObject {
614 @Override public void twoNullableArgs(
615 @Nullable String s, @Nullable Integer i) {
616
617 }
618 }
619
620 public void testPassTwoNullableArgsNeitherThrowsAnything() {
621 shouldPass(new PassTwoNullableArgsNeitherThrowsAnything());
622 }
623
624 @SuppressWarnings("unused")
625 private static abstract class BaseClassThatFailsToThrow {
626 public void oneArg(String s) {}
627 }
628
629 private static class SubclassWithBadSuperclass
630 extends BaseClassThatFailsToThrow {}
631
632 public void testSubclassWithBadSuperclass() {
633 shouldFail(new SubclassWithBadSuperclass());
634 }
635
636 @SuppressWarnings("unused")
637 private static abstract class BaseClassThatFailsToThrowForPackagePrivate {
638 void packagePrivateOneArg(String s) {}
639 }
640
641 private static class SubclassWithBadSuperclassForPackagePrivate
642 extends BaseClassThatFailsToThrowForPackagePrivate {}
643
644 public void testSubclassWithBadSuperclassForPackagePrivateMethod() {
645 shouldFail(
646 new SubclassWithBadSuperclassForPackagePrivate(), Visibility.PACKAGE);
647 }
648
649 @SuppressWarnings("unused")
650 private static abstract class BaseClassThatFailsToThrowForProtected {
651 protected void protectedOneArg(String s) {}
652 }
653
654 private static class SubclassWithBadSuperclassForProtected
655 extends BaseClassThatFailsToThrowForProtected {}
656
657 public void testSubclassWithBadSuperclassForPackageProtectedMethod() {
658 shouldFail(
659 new SubclassWithBadSuperclassForProtected(), Visibility.PROTECTED);
660 }
661
662 private static class SubclassThatOverridesBadSuperclassMethod
663 extends BaseClassThatFailsToThrow {
664 @Override public void oneArg(@Nullable String s) {}
665 }
666
667 public void testSubclassThatOverridesBadSuperclassMethod() {
668 shouldPass(new SubclassThatOverridesBadSuperclassMethod());
669 }
670
671 @SuppressWarnings("unused")
672 private static class SubclassOverridesTheWrongMethod
673 extends BaseClassThatFailsToThrow {
674 public void oneArg(@Nullable CharSequence s) {}
675 }
676
677 public void testSubclassOverridesTheWrongMethod() {
678 shouldFail(new SubclassOverridesTheWrongMethod());
679 }
680
681 @SuppressWarnings("unused")
682 private static class ClassThatFailsToThrowForStatic {
683 static void staticOneArg(String s) {}
684 }
685
686 public void testClassThatFailsToThrowForStatic() {
687 shouldFail(ClassThatFailsToThrowForStatic.class);
688 }
689
690 private static class SubclassThatFailsToThrowForStatic
691 extends ClassThatFailsToThrowForStatic {}
692
693 public void testSubclassThatFailsToThrowForStatic() {
694 shouldFail(SubclassThatFailsToThrowForStatic.class);
695 }
696
697 private static class SubclassThatTriesToOverrideBadStaticMethod
698 extends ClassThatFailsToThrowForStatic {
699 static void staticOneArg(@Nullable String s) {}
700 }
701
702 public void testSubclassThatTriesToOverrideBadStaticMethod() {
703 shouldFail(SubclassThatTriesToOverrideBadStaticMethod.class);
704 }
705
706 private static final class HardToCreate {
707 private HardToCreate(HardToCreate x) {}
708 }
709
710 @SuppressWarnings("unused")
711 private static class CanCreateDefault {
712 public void foo(@Nullable HardToCreate ignored, String required) {
713 checkNotNull(required);
714 }
715 }
716
717 public void testCanCreateDefault() {
718 shouldPass(new CanCreateDefault());
719 }
720
721 @SuppressWarnings("unused")
722 private static class CannotCreateDefault {
723 public void foo(HardToCreate ignored, String required) {
724 checkNotNull(ignored);
725 checkNotNull(required);
726 }
727 }
728
729 public void testCannotCreateDefault() {
730 shouldFail(new CannotCreateDefault());
731 }
732
733 private static void shouldPass(Object instance, Visibility visibility) {
734 new NullPointerTester().testInstanceMethods(instance, visibility);
735 }
736
737 private static void shouldPass(Object instance) {
738 shouldPass(instance, Visibility.PACKAGE);
739 shouldPass(instance, Visibility.PROTECTED);
740 shouldPass(instance, Visibility.PUBLIC);
741 }
742
743
744
745 private static void shouldFail(Object instance, Visibility visibility) {
746 try {
747 new NullPointerTester().testInstanceMethods(instance, visibility);
748 } catch (AssertionFailedError expected) {
749 return;
750 }
751 fail("Should detect problem in " + instance.getClass().getSimpleName());
752 }
753
754 private static void shouldFail(Object instance) {
755 shouldFail(instance, Visibility.PACKAGE);
756 shouldFail(instance, Visibility.PROTECTED);
757 shouldFail(instance, Visibility.PUBLIC);
758 }
759
760 private static void shouldFail(Class<?> cls, Visibility visibility) {
761 try {
762 new NullPointerTester().testStaticMethods(cls, visibility);
763 } catch (AssertionFailedError expected) {
764 return;
765 }
766 fail("Should detect problem in " + cls.getSimpleName());
767 }
768
769 private static void shouldFail(Class<?> cls) {
770 shouldFail(cls, Visibility.PACKAGE);
771 }
772
773 @SuppressWarnings("unused")
774 private static class PrivateClassWithPrivateConstructor {
775 private PrivateClassWithPrivateConstructor(@Nullable Integer argument) {}
776 }
777
778 public void testPrivateClass() {
779 NullPointerTester tester = new NullPointerTester();
780 for (Constructor<?> constructor
781 : PrivateClassWithPrivateConstructor.class.getDeclaredConstructors()) {
782 tester.testConstructor(constructor);
783 }
784 }
785
786 private interface Foo<T> {
787 void doSomething(T bar, Integer baz);
788 }
789
790 private static class StringFoo implements Foo<String> {
791
792 @Override public void doSomething(String bar, Integer baz) {
793 checkNotNull(bar);
794 checkNotNull(baz);
795 }
796 }
797
798 public void testBridgeMethodIgnored() {
799 new NullPointerTester().testAllPublicInstanceMethods(new StringFoo());
800 }
801
802 private static abstract class DefaultValueChecker {
803
804 private final Map<Integer, Object> arguments = Maps.newHashMap();
805
806 final DefaultValueChecker runTester() {
807 new NullPointerTester()
808 .testInstanceMethods(this, Visibility.PACKAGE);
809 return this;
810 }
811
812 final void assertNonNullValues(Object... expectedValues) {
813 assertEquals(expectedValues.length, arguments.size());
814 for (int i = 0; i < expectedValues.length; i++) {
815 assertEquals("Default value for parameter #" + i,
816 expectedValues[i], arguments.get(i));
817 }
818 }
819
820 final Object getDefaultParameterValue(int position) {
821 return arguments.get(position);
822 }
823
824 final void calledWith(Object... args) {
825 for (int i = 0; i < args.length; i++) {
826 if (args[i] != null) {
827 arguments.put(i, args[i]);
828 }
829 }
830 for (Object arg : args) {
831 checkNotNull(arg);
832 }
833 }
834 }
835
836 private enum Gender {
837 MALE, FEMALE
838 }
839
840 private static class AllDefaultValuesChecker extends DefaultValueChecker {
841
842 @SuppressWarnings("unused")
843 public void checkDefaultValuesForTheseTypes(
844 Gender gender,
845 Integer integer, int i,
846 String string, CharSequence charSequence,
847 List<String> list,
848 ImmutableList<Integer> immutableList,
849 Map<String, Integer> map,
850 ImmutableMap<String, String> immutableMap,
851 Set<String> set,
852 ImmutableSet<Integer> immutableSet,
853 SortedSet<Number> sortedSet,
854 ImmutableSortedSet<Number> immutableSortedSet,
855 Multiset<String> multiset,
856 ImmutableMultiset<Integer> immutableMultiset,
857 Multimap<String, Integer> multimap,
858 ImmutableMultimap<String, Integer> immutableMultimap,
859 Table<String, Integer, Exception> table,
860 ImmutableTable<Integer, String, Exception> immutableTable) {
861 calledWith(
862 gender,
863 integer, i,
864 string, charSequence,
865 list, immutableList,
866 map, immutableMap,
867 set, immutableSet,
868 sortedSet, immutableSortedSet,
869 multiset, immutableMultiset,
870 multimap, immutableMultimap,
871 table, immutableTable);
872 }
873
874 final void check() {
875 runTester().assertNonNullValues(
876 Gender.MALE,
877 Integer.valueOf(0), 0,
878 "", "",
879 ImmutableList.of(), ImmutableList.of(),
880 ImmutableMap.of(), ImmutableMap.of(),
881 ImmutableSet.of(), ImmutableSet.of(),
882 ImmutableSortedSet.of(), ImmutableSortedSet.of(),
883 ImmutableMultiset.of(), ImmutableMultiset.of(),
884 ImmutableMultimap.of(), ImmutableMultimap.of(),
885 ImmutableTable.of(), ImmutableTable.of());
886 }
887 }
888
889 public void testDefaultValues() {
890 new AllDefaultValuesChecker().check();
891 }
892
893 private static class ObjectArrayDefaultValueChecker
894 extends DefaultValueChecker {
895
896 @SuppressWarnings("unused")
897 public void checkArray(Object[] array, String s) {
898 calledWith(array, s);
899 }
900
901 void check() {
902 runTester();
903 Object[] defaultArray = (Object[]) getDefaultParameterValue(0);
904 assertEquals(0, defaultArray.length);
905 }
906 }
907
908 public void testObjectArrayDefaultValue() {
909 new ObjectArrayDefaultValueChecker().check();
910 }
911
912 private static class StringArrayDefaultValueChecker
913 extends DefaultValueChecker {
914
915 @SuppressWarnings("unused")
916 public void checkArray(String[] array, String s) {
917 calledWith(array, s);
918 }
919
920 void check() {
921 runTester();
922 String[] defaultArray = (String[]) getDefaultParameterValue(0);
923 assertEquals(0, defaultArray.length);
924 }
925 }
926
927 public void testStringArrayDefaultValue() {
928 new StringArrayDefaultValueChecker().check();
929 }
930
931 private static class IntArrayDefaultValueChecker
932 extends DefaultValueChecker {
933
934 @SuppressWarnings("unused")
935 public void checkArray(int[] array, String s) {
936 calledWith(array, s);
937 }
938
939 void check() {
940 runTester();
941 int[] defaultArray = (int[]) getDefaultParameterValue(0);
942 assertEquals(0, defaultArray.length);
943 }
944 }
945
946 public void testIntArrayDefaultValue() {
947 new IntArrayDefaultValueChecker().check();
948 }
949
950 private enum EmptyEnum {}
951
952 private static class EmptyEnumDefaultValueChecker
953 extends DefaultValueChecker {
954
955 @SuppressWarnings("unused")
956 public void checkArray(EmptyEnum object, String s) {
957 calledWith(object, s);
958 }
959
960 void check() {
961 try {
962 runTester();
963 } catch (AssertionError expected) {
964 return;
965 }
966 fail("Should have failed because enum has no constant");
967 }
968 }
969
970 public void testEmptyEnumDefaultValue() {
971 new EmptyEnumDefaultValueChecker().check();
972 }
973
974 private static class GenericClassTypeDefaultValueChecker
975 extends DefaultValueChecker {
976
977 @SuppressWarnings("unused")
978 public void checkArray(Class<? extends List<?>> cls, String s) {
979 calledWith(cls, s);
980 }
981
982 void check() {
983 runTester();
984 Class<?> defaultClass = (Class<?>) getDefaultParameterValue(0);
985 assertEquals(List.class, defaultClass);
986 }
987 }
988
989 public void testGenericClassDefaultValue() {
990 new GenericClassTypeDefaultValueChecker().check();
991 }
992
993 private static class NonGenericClassTypeDefaultValueChecker
994 extends DefaultValueChecker {
995
996 @SuppressWarnings("unused")
997 public void checkArray(@SuppressWarnings("rawtypes") Class cls, String s) {
998 calledWith(cls, s);
999 }
1000
1001 void check() {
1002 runTester();
1003 Class<?> defaultClass = (Class<?>) getDefaultParameterValue(0);
1004 assertEquals(Object.class, defaultClass);
1005 }
1006 }
1007
1008 public void testNonGenericClassDefaultValue() {
1009 new NonGenericClassTypeDefaultValueChecker().check();
1010 }
1011
1012 private static class GenericTypeTokenDefaultValueChecker
1013 extends DefaultValueChecker {
1014
1015 @SuppressWarnings("unused")
1016 public void checkArray(
1017 TypeToken<? extends List<? super Number>> type, String s) {
1018 calledWith(type, s);
1019 }
1020
1021 void check() {
1022 runTester();
1023 TypeToken<?> defaultType = (TypeToken<?>) getDefaultParameterValue(0);
1024 assertTrue(new TypeToken<List<? super Number>>() {}
1025 .isAssignableFrom(defaultType));
1026 }
1027 }
1028
1029 public void testGenericTypeTokenDefaultValue() {
1030 new GenericTypeTokenDefaultValueChecker().check();
1031 }
1032
1033 private static class NonGenericTypeTokenDefaultValueChecker
1034 extends DefaultValueChecker {
1035
1036 @SuppressWarnings("unused")
1037 public void checkArray(
1038 @SuppressWarnings("rawtypes") TypeToken type, String s) {
1039 calledWith(type, s);
1040 }
1041
1042 void check() {
1043 runTester();
1044 TypeToken<?> defaultType = (TypeToken<?>) getDefaultParameterValue(0);
1045 assertEquals(new TypeToken<Object>() {}, defaultType);
1046 }
1047 }
1048
1049 public void testNonGenericTypeTokenDefaultValue() {
1050 new NonGenericTypeTokenDefaultValueChecker().check();
1051 }
1052
1053 private interface FromTo<F, T> extends Function<F, T> {}
1054
1055 private static class GenericInterfaceDefaultValueChecker
1056 extends DefaultValueChecker {
1057
1058 @SuppressWarnings("unused")
1059 public void checkArray(FromTo<String, Integer> f, String s) {
1060 calledWith(f, s);
1061 }
1062
1063 void check() {
1064 runTester();
1065 FromTo<?, ?> defaultFunction = (FromTo<?, ?>) getDefaultParameterValue(0);
1066 assertEquals(0, defaultFunction.apply(null));
1067 }
1068 }
1069
1070 public void testGenericInterfaceDefaultValue() {
1071 new GenericInterfaceDefaultValueChecker().check();
1072 }
1073
1074 private interface NullRejectingFromTo<F, T> extends Function<F, T> {
1075 @Override public abstract T apply(F from);
1076 }
1077
1078 private static class NullRejectingInterfaceDefaultValueChecker
1079 extends DefaultValueChecker {
1080
1081 @SuppressWarnings("unused")
1082 public void checkArray(NullRejectingFromTo<String, Integer> f, String s) {
1083 calledWith(f, s);
1084 }
1085
1086 void check() {
1087 runTester();
1088 NullRejectingFromTo<?, ?> defaultFunction = (NullRejectingFromTo<?, ?>)
1089 getDefaultParameterValue(0);
1090 assertNotNull(defaultFunction);
1091 try {
1092 defaultFunction.apply(null);
1093 fail("Proxy Should have rejected null");
1094 } catch (NullPointerException expected) {}
1095 }
1096 }
1097
1098 public void testNullRejectingInterfaceDefaultValue() {
1099 new NullRejectingInterfaceDefaultValueChecker().check();
1100 }
1101
1102 private static class MultipleInterfacesDefaultValueChecker
1103 extends DefaultValueChecker {
1104
1105 @SuppressWarnings("unused")
1106 public <T extends FromTo<String, Integer> & Supplier<Long>> void checkArray(
1107 T f, String s) {
1108 calledWith(f, s);
1109 }
1110
1111 void check() {
1112 runTester();
1113 FromTo<?, ?> defaultFunction = (FromTo<?, ?>) getDefaultParameterValue(0);
1114 assertEquals(0, defaultFunction.apply(null));
1115 Supplier<?> defaultSupplier = (Supplier<?>) defaultFunction;
1116 assertEquals(Long.valueOf(0), defaultSupplier.get());
1117 }
1118 }
1119
1120 public void testMultipleInterfacesDefaultValue() {
1121 new MultipleInterfacesDefaultValueChecker().check();
1122 }
1123
1124 private static class GenericInterface2DefaultValueChecker
1125 extends DefaultValueChecker {
1126
1127 @SuppressWarnings("unused")
1128 public void checkArray(FromTo<String, FromTo<Integer, String>> f, String s) {
1129 calledWith(f, s);
1130 }
1131
1132 void check() {
1133 runTester();
1134 FromTo<?, ?> defaultFunction = (FromTo<?, ?>) getDefaultParameterValue(0);
1135 FromTo<?, ?> returnValue = (FromTo<?, ?>) defaultFunction.apply(null);
1136 assertEquals("", returnValue.apply(null));
1137 }
1138 }
1139
1140 public void testGenericInterfaceReturnedByGenericMethod() {
1141 new GenericInterface2DefaultValueChecker().check();
1142 }
1143
1144 private static abstract class AbstractGenericDefaultValueChecker<T>
1145 extends DefaultValueChecker {
1146
1147 @SuppressWarnings("unused")
1148 public void checkGeneric(T value, String s) {
1149 calledWith(value, s);
1150 }
1151 }
1152
1153 private static class GenericDefaultValueResolvedToStringChecker
1154 extends AbstractGenericDefaultValueChecker<String> {
1155 void check() {
1156 runTester();
1157 assertEquals("", getDefaultParameterValue(0));
1158 }
1159 }
1160
1161 public void testGenericTypeResolvedForDefaultValue() {
1162 new GenericDefaultValueResolvedToStringChecker().check();
1163 }
1164
1165 private static abstract
1166 class AbstractGenericDefaultValueForPackagePrivateMethodChecker<T>
1167 extends DefaultValueChecker {
1168
1169 @SuppressWarnings("unused")
1170 void checkGeneric(T value, String s) {
1171 calledWith(value, s);
1172 }
1173 }
1174
1175 private static
1176 class DefaultValueForPackagePrivateMethodResolvedToStringChecker
1177 extends AbstractGenericDefaultValueForPackagePrivateMethodChecker<String>
1178 {
1179 void check() {
1180 runTester();
1181 assertEquals("", getDefaultParameterValue(0));
1182 }
1183 }
1184
1185 public void testDefaultValueResolvedForPackagePrivateMethod() {
1186 new DefaultValueForPackagePrivateMethodResolvedToStringChecker().check();
1187 }
1188
1189 private static class ConverterDefaultValueChecker
1190 extends DefaultValueChecker {
1191
1192 @SuppressWarnings("unused")
1193 public void checkArray(Converter<String, Integer> c, String s) {
1194 calledWith(c, s);
1195 }
1196
1197 void check() {
1198 runTester();
1199 @SuppressWarnings("unchecked")
1200 Converter<String, Integer> defaultConverter = (Converter<String, Integer>)
1201 getDefaultParameterValue(0);
1202 assertEquals(Integer.valueOf(0), defaultConverter.convert("anything"));
1203 assertEquals("", defaultConverter.reverse().convert(123));
1204 assertNull(defaultConverter.convert(null));
1205 assertNull(defaultConverter.reverse().convert(null));
1206 }
1207 }
1208
1209 public void testConverterDefaultValue() {
1210 new ConverterDefaultValueChecker().check();
1211 }
1212
1213 private static class VisibilityMethods {
1214
1215 @SuppressWarnings("unused")
1216 private void privateMethod() {}
1217
1218 @SuppressWarnings("unused")
1219 void packagePrivateMethod() {}
1220
1221 @SuppressWarnings("unused")
1222 protected void protectedMethod() {}
1223
1224 @SuppressWarnings("unused")
1225 public void publicMethod() {}
1226 }
1227
1228 public void testVisibility_public() throws Exception {
1229 assertFalse(Visibility.PUBLIC.isVisible(
1230 VisibilityMethods.class.getDeclaredMethod("privateMethod")));
1231 assertFalse(Visibility.PUBLIC.isVisible(
1232 VisibilityMethods.class.getDeclaredMethod("packagePrivateMethod")));
1233 assertFalse(Visibility.PUBLIC.isVisible(
1234 VisibilityMethods.class.getDeclaredMethod("protectedMethod")));
1235 assertTrue(Visibility.PUBLIC.isVisible(
1236 VisibilityMethods.class.getDeclaredMethod("publicMethod")));
1237 }
1238
1239 public void testVisibility_protected() throws Exception {
1240 assertFalse(Visibility.PROTECTED.isVisible(
1241 VisibilityMethods.class.getDeclaredMethod("privateMethod")));
1242 assertFalse(Visibility.PROTECTED.isVisible(
1243 VisibilityMethods.class.getDeclaredMethod("packagePrivateMethod")));
1244 assertTrue(Visibility.PROTECTED.isVisible(
1245 VisibilityMethods.class.getDeclaredMethod("protectedMethod")));
1246 assertTrue(Visibility.PROTECTED.isVisible(
1247 VisibilityMethods.class.getDeclaredMethod("publicMethod")));
1248 }
1249
1250 public void testVisibility_package() throws Exception {
1251 assertFalse(Visibility.PACKAGE.isVisible(
1252 VisibilityMethods.class.getDeclaredMethod("privateMethod")));
1253 assertTrue(Visibility.PACKAGE.isVisible(
1254 VisibilityMethods.class.getDeclaredMethod("packagePrivateMethod")));
1255 assertTrue(Visibility.PACKAGE.isVisible(
1256 VisibilityMethods.class.getDeclaredMethod("protectedMethod")));
1257 assertTrue(Visibility.PACKAGE.isVisible(
1258 VisibilityMethods.class.getDeclaredMethod("publicMethod")));
1259 }
1260
1261 private class Inner {
1262 public Inner(String s) {
1263 checkNotNull(s);
1264 }
1265 }
1266
1267 public void testNonStaticInnerClass() {
1268 try {
1269 new NullPointerTester().testAllPublicConstructors(Inner.class);
1270 fail();
1271 } catch (IllegalArgumentException expected) {
1272 assertThat(expected.getMessage()).contains("inner class");
1273 }
1274 }
1275 }