View Javadoc
1   /*
2    * Copyright (C) 2005 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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   * Unit test for {@link NullPointerTester}.
55   *
56   * @author Kevin Bourrillion
57   * @author Mick Killianey
58   */
59  public class NullPointerTesterTest extends TestCase {
60  
61    /** Non-NPE RuntimeException. */
62    public static class FooException extends RuntimeException {
63      private static final long serialVersionUID = 1L;
64    }
65  
66    /**
67     * Class for testing all permutations of static/non-static one-argument
68     * methods using methodParameter().
69     */
70    @SuppressWarnings("unused") // used by reflection
71    public static class OneArg {
72  
73      public static void staticOneArgCorrectlyThrowsNpe(String s) {
74        checkNotNull(s); // expect NPE here on null
75      }
76      public static void staticOneArgThrowsOtherThanNpe(String s) {
77        throw new FooException();  // should catch as failure
78      }
79      public static void staticOneArgShouldThrowNpeButDoesnt(String s) {
80        // should catch as failure
81      }
82      public static void
83      staticOneArgNullableCorrectlyDoesNotThrowNPE(@Nullable String s) {
84        // null?  no problem
85      }
86      public static void
87      staticOneArgNullableCorrectlyThrowsOtherThanNPE(@Nullable String s) {
88        throw new FooException(); // ok, as long as it's not NullPointerException
89      }
90      public static void
91      staticOneArgNullableThrowsNPE(@Nullable String s) {
92        checkNotNull(s); // doesn't check if you said you'd accept null, but you don't
93      }
94  
95      public void oneArgCorrectlyThrowsNpe(String s) {
96        checkNotNull(s); // expect NPE here on null
97      }
98      public void oneArgThrowsOtherThanNpe(String s) {
99        throw new FooException();  // should catch as failure
100     }
101     public void oneArgShouldThrowNpeButDoesnt(String s) {
102       // should catch as failure
103     }
104     public void oneArgNullableCorrectlyDoesNotThrowNPE(@Nullable String s) {
105       // null?  no problem
106     }
107     public void oneArgNullableCorrectlyThrowsOtherThanNPE(@Nullable String s) {
108       throw new FooException(); // ok, as long as it's not NullPointerException
109     }
110     public void oneArgNullableThrowsNPE(@Nullable String s) {
111       checkNotNull(s); // doesn't check if you said you'd accept null, but you don't
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    * Class for testing all permutations of nullable/non-nullable two-argument
224    * methods using testMethod().
225    *
226    *   normalNormal:  two params, neither is Nullable
227    *   nullableNormal:  only first param is Nullable
228    *   normalNullable:  only second param is Nullable
229    *   nullableNullable:  both params are Nullable
230    */
231   public static class TwoArg {
232     /** Action to take on a null param. */
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     /** Method that decides how to react to parameters. */
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     /** Two-arg method with no Nullable params. */
271     public void normalNormal(String first, Integer second) {
272       reactToNullParameters(first, second);
273     }
274 
275     /** Two-arg method with the second param Nullable. */
276     public void normalNullable(String first, @Nullable Integer second) {
277       reactToNullParameters(first, second);
278     }
279 
280     /** Two-arg method with the first param Nullable. */
281     public void nullableNormal(@Nullable String first, Integer second) {
282       reactToNullParameters(first, second);
283     }
284 
285     /** Two-arg method with the both params Nullable. */
286     public void nullableNullable(
287         @Nullable String first, @Nullable Integer second) {
288       reactToNullParameters(first, second);
289     }
290 
291     /** To provide sanity during debugging. */
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; // good...we wanted a failure
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); // require both params to throw NPE
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); // only pass if 1st param throws NPE
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); // only pass if 2nd param throws NPE
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); // All args nullable:  anything goes!
372       }
373     }
374   }
375 
376   /*
377    * This next part consists of several sample classes that provide
378    * demonstrations of conditions that cause NullPointerTester
379    * to succeed/fail.
380    */
381 
382   /** Lots of well-behaved methods. */
383   @SuppressWarnings("unused") // used by reflection
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       // Fail:  missing NPE for s
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); // Fail:  throwing non-NPE exception for null 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); // ok to throw NPE
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       // Fail: missing NPE for s
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); // Fail:  throwing non-NPE exception for null 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       // Fail: missing NPE for i
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); // Fail:  throwing non-NPE exception for null 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       // Fail: missing NPE for s
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); // Fail:  throwing non-NPE exception for null 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(); // ok to throw NPE?
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); // ok to throw non-NPE exception for null 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       // Fail: missing NPE for null s
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); // Fail:  throwing non-NPE exception for null 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); // ok to throw NPE?
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); // ok to throw non-NPE exception for null 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(); // ok to throw NPE?
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); // ok to throw non-NPE exception for null 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       // ok to do nothing
617     }
618   }
619 
620   public void testPassTwoNullableArgsNeitherThrowsAnything() {
621     shouldPass(new PassTwoNullableArgsNeitherThrowsAnything());
622   }
623 
624   @SuppressWarnings("unused") // for NullPointerTester
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") // for NullPointerTester
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") // for NullPointerTester
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") // for NullPointerTester
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") // for NullPointerTester
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") // used by reflection
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") // used by reflection
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   // TODO(cpovirk): eliminate surprising Object/Class overloading of shouldFail
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") // used by reflection
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); // to fulfill null check
832       }
833     }
834   }
835 
836   private enum Gender {
837     MALE, FEMALE
838   }
839 
840   private static class AllDefaultValuesChecker extends DefaultValueChecker {
841 
842     @SuppressWarnings("unused") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
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") // called by NullPointerTester
1193     public void checkArray(Converter<String, Integer> c, String s) {
1194       calledWith(c, s);
1195     }
1196 
1197     void check() {
1198       runTester();
1199       @SuppressWarnings("unchecked") // We are checking it anyway
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") // Called by reflection
1216     private void privateMethod() {}
1217 
1218     @SuppressWarnings("unused") // Called by reflection
1219     void packagePrivateMethod() {}
1220 
1221     @SuppressWarnings("unused") // Called by reflection
1222     protected void protectedMethod() {}
1223 
1224     @SuppressWarnings("unused") // Called by reflection
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 }