• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.checkNotNull;
20 
21 import com.google.common.collect.Lists;
22 import com.google.common.collect.Sets;
23 
24 import junit.framework.AssertionFailedError;
25 import junit.framework.TestCase;
26 
27 import java.lang.reflect.Constructor;
28 import java.lang.reflect.Method;
29 import java.util.List;
30 import java.util.Set;
31 
32 import javax.annotation.Nullable;
33 
34 /**
35  * Unit test for {@link NullPointerTester}.
36  *
37  * @author Kevin Bourrillion
38  * @author Mick Killianey
39  */
40 public class NullPointerTesterTest extends TestCase {
41 
42   private NullPointerTester tester;
43 
setUp()44   @Override protected void setUp() throws Exception {
45     super.setUp();
46     tester = new NullPointerTester();
47   }
48 
49   /** Non-NPE RuntimeException. */
50   public static class FooException extends RuntimeException {
51     private static final long serialVersionUID = 1L;
52   }
53 
54   /**
55    * Class for testing all permutations of static/non-static one-argument
56    * methods using methodParameter().
57    */
58   public static class OneArg {
59 
staticOneArgCorrectlyThrowsNpe(String s)60     public static void staticOneArgCorrectlyThrowsNpe(String s) {
61       checkNotNull(s); // expect NPE here on null
62     }
staticOneArgThrowsOtherThanNpe(String s)63     public static void staticOneArgThrowsOtherThanNpe(String s) {
64       throw new FooException();  // should catch as failure
65     }
staticOneArgShouldThrowNpeButDoesnt(String s)66     public static void staticOneArgShouldThrowNpeButDoesnt(String s) {
67       // should catch as failure
68     }
69     public static void
staticOneArgNullableCorrectlyDoesNotThrowNPE(@ullable String s)70     staticOneArgNullableCorrectlyDoesNotThrowNPE(@Nullable String s) {
71       // null?  no problem
72     }
73     public static void
staticOneArgNullableCorrectlyThrowsOtherThanNPE(@ullable String s)74     staticOneArgNullableCorrectlyThrowsOtherThanNPE(@Nullable String s) {
75       throw new FooException(); // ok, as long as it's not NullPointerException
76     }
77     public static void
staticOneArgNullableThrowsNPE(@ullable String s)78     staticOneArgNullableThrowsNPE(@Nullable String s) {
79       checkNotNull(s); // doesn't check if you said you'd accept null, but you don't
80     }
81 
oneArgCorrectlyThrowsNpe(String s)82     public void oneArgCorrectlyThrowsNpe(String s) {
83       checkNotNull(s); // expect NPE here on null
84     }
oneArgThrowsOtherThanNpe(String s)85     public void oneArgThrowsOtherThanNpe(String s) {
86       throw new FooException();  // should catch as failure
87     }
oneArgShouldThrowNpeButDoesnt(String s)88     public void oneArgShouldThrowNpeButDoesnt(String s) {
89       // should catch as failure
90     }
oneArgNullableCorrectlyDoesNotThrowNPE(@ullable String s)91     public void oneArgNullableCorrectlyDoesNotThrowNPE(@Nullable String s) {
92       // null?  no problem
93     }
oneArgNullableCorrectlyThrowsOtherThanNPE(@ullable String s)94     public void oneArgNullableCorrectlyThrowsOtherThanNPE(@Nullable String s) {
95       throw new FooException(); // ok, as long as it's not NullPointerException
96     }
oneArgNullableThrowsNPE(@ullable String s)97     public void oneArgNullableThrowsNPE(@Nullable String s) {
98       checkNotNull(s); // doesn't check if you said you'd accept null, but you don't
99     }
100   }
101 
102   private static final String[] STATIC_ONE_ARG_METHODS_SHOULD_PASS = {
103     "staticOneArgCorrectlyThrowsNpe",
104     "staticOneArgNullableCorrectlyDoesNotThrowNPE",
105     "staticOneArgNullableCorrectlyThrowsOtherThanNPE",
106     "staticOneArgNullableThrowsNPE",
107   };
108   private static final String[] STATIC_ONE_ARG_METHODS_SHOULD_FAIL = {
109     "staticOneArgThrowsOtherThanNpe",
110     "staticOneArgShouldThrowNpeButDoesnt",
111   };
112   private static final String[] NONSTATIC_ONE_ARG_METHODS_SHOULD_PASS = {
113     "oneArgCorrectlyThrowsNpe",
114     "oneArgNullableCorrectlyDoesNotThrowNPE",
115     "oneArgNullableCorrectlyThrowsOtherThanNPE",
116     "oneArgNullableThrowsNPE",
117   };
118   private static final String[] NONSTATIC_ONE_ARG_METHODS_SHOULD_FAIL = {
119     "oneArgThrowsOtherThanNpe",
120     "oneArgShouldThrowNpeButDoesnt",
121   };
122 
testStaticOneArgMethodsThatShouldPass()123   public void testStaticOneArgMethodsThatShouldPass() throws Exception {
124     for (String methodName : STATIC_ONE_ARG_METHODS_SHOULD_PASS) {
125       Method method = OneArg.class.getMethod(methodName, String.class);
126       try {
127         tester.testMethodParameter(OneArg.class, method, 0);
128       } catch (AssertionFailedError unexpected) {
129         fail("Should not have flagged method " + methodName);
130       }
131     }
132   }
133 
testStaticOneArgMethodsThatShouldFail()134   public void testStaticOneArgMethodsThatShouldFail() throws Exception {
135     for (String methodName : STATIC_ONE_ARG_METHODS_SHOULD_FAIL) {
136       Method method = OneArg.class.getMethod(methodName, String.class);
137       boolean foundProblem = false;
138       try {
139         tester.testMethodParameter(OneArg.class, method, 0);
140       } catch (AssertionFailedError expected) {
141         foundProblem = true;
142       }
143       assertTrue("Should report error in method " + methodName, foundProblem);
144     }
145   }
146 
testNonStaticOneArgMethodsThatShouldPass()147   public void testNonStaticOneArgMethodsThatShouldPass() throws Exception {
148     OneArg foo = new OneArg();
149     for (String methodName : NONSTATIC_ONE_ARG_METHODS_SHOULD_PASS) {
150       Method method = OneArg.class.getMethod(methodName, String.class);
151       try {
152         tester.testMethodParameter(foo, method, 0);
153       } catch (AssertionFailedError unexpected) {
154         fail("Should not have flagged method " + methodName);
155       }
156     }
157   }
158 
testNonStaticOneArgMethodsThatShouldFail()159   public void testNonStaticOneArgMethodsThatShouldFail() throws Exception {
160     OneArg foo = new OneArg();
161     for (String methodName : NONSTATIC_ONE_ARG_METHODS_SHOULD_FAIL) {
162       Method method = OneArg.class.getMethod(methodName, String.class);
163       boolean foundProblem = false;
164       try {
165         tester.testMethodParameter(foo, method, 0);
166       } catch (AssertionFailedError expected) {
167         foundProblem = true;
168       }
169       assertTrue("Should report error in method " + methodName, foundProblem);
170     }
171   }
172 
173   /**
174    * Class for testing all permutations of nullable/non-nullable two-argument
175    * methods using testMethod().
176    *
177    *   normalNormal:  two params, neither is Nullable
178    *   nullableNormal:  only first param is Nullable
179    *   normalNullable:  only second param is Nullable
180    *   nullableNullable:  both params are Nullable
181    */
182   public static class TwoArg {
183     /** Action to take on a null param. */
184     public enum Action {
185       THROW_A_NPE {
act()186         @Override public void act() {
187           throw new NullPointerException();
188         }
189       },
190       THROW_OTHER {
act()191         @Override public void act() {
192           throw new FooException();
193         }
194       },
195       JUST_RETURN {
act()196         @Override public void act() {}
197       };
198 
act()199       public abstract void act();
200     }
201     Action actionWhenFirstParamIsNull;
202     Action actionWhenSecondParamIsNull;
203 
TwoArg( Action actionWhenFirstParamIsNull, Action actionWhenSecondParamIsNull)204     public TwoArg(
205         Action actionWhenFirstParamIsNull,
206         Action actionWhenSecondParamIsNull) {
207       this.actionWhenFirstParamIsNull = actionWhenFirstParamIsNull;
208       this.actionWhenSecondParamIsNull = actionWhenSecondParamIsNull;
209     }
210 
211     /** Method that decides how to react to parameters. */
reactToNullParameters(Object first, Object second)212     public void reactToNullParameters(Object first, Object second) {
213       if (first == null) {
214         actionWhenFirstParamIsNull.act();
215       }
216       if (second == null) {
217         actionWhenSecondParamIsNull.act();
218       }
219     }
220 
221     /** Two-arg method with no Nullable params. */
normalNormal(String first, Integer second)222     public void normalNormal(String first, Integer second) {
223       reactToNullParameters(first, second);
224     }
225 
226     /** Two-arg method with the second param Nullable. */
normalNullable(String first, @Nullable Integer second)227     public void normalNullable(String first, @Nullable Integer second) {
228       reactToNullParameters(first, second);
229     }
230 
231     /** Two-arg method with the first param Nullable. */
nullableNormal(@ullable String first, Integer second)232     public void nullableNormal(@Nullable String first, Integer second) {
233       reactToNullParameters(first, second);
234     }
235 
236     /** Two-arg method with the both params Nullable. */
nullableNullable( @ullable String first, @Nullable Integer second)237     public void nullableNullable(
238         @Nullable String first, @Nullable Integer second) {
239       reactToNullParameters(first, second);
240     }
241 
242     /** To provide sanity during debugging. */
toString()243     @Override public String toString() {
244       return String.format("Bar(%s, %s)",
245           actionWhenFirstParamIsNull, actionWhenSecondParamIsNull);
246     }
247   }
248 
verifyBarPass(Method method, TwoArg bar)249   public void verifyBarPass(Method method, TwoArg bar) throws Exception {
250     try {
251       tester.testMethod(bar, method);
252     } catch (AssertionFailedError incorrectError) {
253       String errorMessage = String.format(
254           "Should not have flagged method %s for %s", method.getName(), bar);
255       assertNull(errorMessage, incorrectError);
256     }
257   }
258 
verifyBarFail(Method method, TwoArg bar)259   public void verifyBarFail(Method method, TwoArg bar) throws Exception {
260     try {
261       tester.testMethod(bar, method);
262     } catch (AssertionFailedError expected) {
263       return; // good...we wanted a failure
264     }
265     String errorMessage = String.format(
266         "Should have flagged method %s for %s", method.getName(), bar);
267     fail(errorMessage);
268   }
269 
testTwoArgNormalNormal()270   public void testTwoArgNormalNormal() throws Exception {
271     Method method = TwoArg.class.getMethod(
272         "normalNormal", String.class, Integer.class);
273     for (TwoArg.Action first : TwoArg.Action.values()) {
274       for (TwoArg.Action second : TwoArg.Action.values()) {
275         TwoArg bar = new TwoArg(first, second);
276         if (first.equals(TwoArg.Action.THROW_A_NPE)
277             && second.equals(TwoArg.Action.THROW_A_NPE)) {
278           verifyBarPass(method, bar); // require both params to throw NPE
279         } else {
280           verifyBarFail(method, bar);
281         }
282       }
283     }
284   }
285 
testTwoArgNormalNullable()286   public void testTwoArgNormalNullable() throws Exception {
287     Method method = TwoArg.class.getMethod(
288         "normalNullable", String.class, Integer.class);
289     for (TwoArg.Action first : TwoArg.Action.values()) {
290       for (TwoArg.Action second : TwoArg.Action.values()) {
291         TwoArg bar = new TwoArg(first, second);
292         if (first.equals(TwoArg.Action.THROW_A_NPE)) {
293           verifyBarPass(method, bar); // only pass if 1st param throws NPE
294         } else {
295           verifyBarFail(method, bar);
296         }
297       }
298     }
299   }
300 
testTwoArgNullableNormal()301   public void testTwoArgNullableNormal() throws Exception {
302     Method method = TwoArg.class.getMethod(
303         "nullableNormal", String.class, Integer.class);
304     for (TwoArg.Action first : TwoArg.Action.values()) {
305       for (TwoArg.Action second : TwoArg.Action.values()) {
306         TwoArg bar = new TwoArg(first, second);
307         if (second.equals(TwoArg.Action.THROW_A_NPE)) {
308           verifyBarPass(method, bar); // only pass if 2nd param throws NPE
309         } else {
310           verifyBarFail(method, bar);
311         }
312       }
313     }
314   }
315 
testTwoArgNullableNullable()316   public void testTwoArgNullableNullable() throws Exception {
317     Method method = TwoArg.class.getMethod(
318         "nullableNullable", String.class, Integer.class);
319     for (TwoArg.Action first : TwoArg.Action.values()) {
320       for (TwoArg.Action second : TwoArg.Action.values()) {
321         TwoArg bar = new TwoArg(first, second);
322         verifyBarPass(method, bar); // All args nullable:  anything goes!
323       }
324     }
325   }
326 
327   /*
328    * This next part consists of several sample classes that provide
329    * demonstrations of conditions that cause NullPointerTester
330    * to succeed/fail.
331    *
332    * Add naughty classes to failClasses to verify that NullPointerTest
333    * raises an AssertionFailedError.
334    *
335    * Add acceptable classes to passClasses to verify that NullPointerTest
336    * doesn't complain.
337    */
338 
339   /** List of classes that NullPointerTester should pass as acceptable. */
340   static List<Class<?>> failClasses = Lists.newArrayList();
341 
342   /** List of classes that NullPointerTester should flag as problematic. */
343   static List<Class<?>> passClasses = Lists.newArrayList();
344 
345   /** Lots of well-behaved methods. */
346   public static class PassObject {
doThrow(Object arg)347     public static void doThrow(Object arg) {
348       if (arg == null) {
349         throw new FooException();
350       }
351     }
noArg()352     public void noArg() {}
oneArg(String s)353     public void oneArg(String s) { checkNotNull(s); }
oneNullableArg(@ullable String s)354     public void oneNullableArg(@Nullable String s) {}
oneNullableArgThrows(@ullable String s)355     public void oneNullableArgThrows(@Nullable String s) { doThrow(s); }
356 
twoArg(String s, Integer i)357     public void twoArg(String s, Integer i) { checkNotNull(s); i.intValue(); }
twoMixedArgs(String s, @Nullable Integer i)358     public void twoMixedArgs(String s, @Nullable Integer i) { checkNotNull(s); }
twoMixedArgsThrows(String s, @Nullable Integer i)359     public void twoMixedArgsThrows(String s, @Nullable Integer i) {
360       checkNotNull(s); doThrow(i);
361     }
twoMixedArgs(@ullable Integer i, String s)362     public void twoMixedArgs(@Nullable Integer i, String s) { checkNotNull(s); }
twoMixedArgsThrows(@ullable Integer i, String s)363     public void twoMixedArgsThrows(@Nullable Integer i, String s) {
364       checkNotNull(s); doThrow(i);
365     }
twoNullableArgs(@ullable String s, @javax.annotation.Nullable Integer i)366     public void twoNullableArgs(@Nullable String s,
367         @javax.annotation.Nullable Integer i) { }
twoNullableArgsThrowsFirstArg( @ullable String s, @Nullable Integer i)368     public void twoNullableArgsThrowsFirstArg(
369         @Nullable String s, @Nullable Integer i) {
370       doThrow(s);
371     }
twoNullableArgsThrowsSecondArg( @ullable String s, @Nullable Integer i)372     public void twoNullableArgsThrowsSecondArg(
373         @Nullable String s, @Nullable Integer i) {
374       doThrow(i);
375     }
staticOneArg(String s)376     public static void staticOneArg(String s) { checkNotNull(s); }
staticOneNullableArg(@ullable String s)377     public static void staticOneNullableArg(@Nullable String s) { }
staticOneNullableArgThrows(@ullable String s)378     public static void staticOneNullableArgThrows(@Nullable String s) {
379       doThrow(s);
380     }
381   }
382   static { passClasses.add(PassObject.class); }
383 
384   static class FailOneArgDoesntThrowNPE extends PassObject {
oneArg(String s)385     @Override public void oneArg(String s) {
386       // Fail:  missing NPE for s
387     }
388   }
389   static { failClasses.add(FailOneArgDoesntThrowNPE.class); }
390 
391   static class FailOneArgThrowsWrongType extends PassObject {
oneArg(String s)392     @Override public void oneArg(String s) {
393       doThrow(s); // Fail:  throwing non-NPE exception for null s
394     }
395   }
396   static { failClasses.add(FailOneArgThrowsWrongType.class); }
397 
398   static class PassOneNullableArgThrowsNPE extends PassObject {
oneNullableArg(@ullable String s)399     @Override public void oneNullableArg(@Nullable String s) {
400       checkNotNull(s); // ok to throw NPE
401     }
402   }
403   static { passClasses.add(PassOneNullableArgThrowsNPE.class); }
404 
405   static class FailTwoArgsFirstArgDoesntThrowNPE extends PassObject {
twoArg(String s, Integer i)406     @Override public void twoArg(String s, Integer i) {
407       // Fail: missing NPE for s
408       i.intValue();
409     }
410   }
411   static { failClasses.add(FailTwoArgsFirstArgDoesntThrowNPE.class); }
412 
413   static class FailTwoArgsFirstArgThrowsWrongType extends PassObject {
twoArg(String s, Integer i)414     @Override public void twoArg(String s, Integer i) {
415       doThrow(s); // Fail:  throwing non-NPE exception for null s
416       i.intValue();
417     }
418   }
419   static { failClasses.add(FailTwoArgsFirstArgThrowsWrongType.class); }
420 
421   static class FailTwoArgsSecondArgDoesntThrowNPE extends PassObject {
twoArg(String s, Integer i)422     @Override public void twoArg(String s, Integer i) {
423       checkNotNull(s);
424       // Fail: missing NPE for i
425     }
426   }
427   static { failClasses.add(FailTwoArgsSecondArgDoesntThrowNPE.class); }
428 
429   static class FailTwoArgsSecondArgThrowsWrongType extends PassObject {
twoArg(String s, Integer i)430     @Override public void twoArg(String s, Integer i) {
431       checkNotNull(s);
432       doThrow(i); // Fail:  throwing non-NPE exception for null i
433     }
434   }
435   static { failClasses.add(FailTwoArgsSecondArgThrowsWrongType.class); }
436 
437   static class FailTwoMixedArgsFirstArgDoesntThrowNPE extends PassObject {
twoMixedArgs(String s, @Nullable Integer i)438     @Override public void twoMixedArgs(String s, @Nullable Integer i) {
439       // Fail: missing NPE for s
440     }
441   }
442   static { failClasses.add(FailTwoMixedArgsFirstArgDoesntThrowNPE.class); }
443 
444   static class FailTwoMixedArgsFirstArgThrowsWrongType extends PassObject {
twoMixedArgs(String s, @Nullable Integer i)445     @Override public void twoMixedArgs(String s, @Nullable Integer i) {
446       doThrow(s); // Fail:  throwing non-NPE exception for null s
447     }
448   }
449   static { failClasses.add(FailTwoMixedArgsFirstArgThrowsWrongType.class); }
450 
451   static class PassTwoMixedArgsNullableArgThrowsNPE extends PassObject {
twoMixedArgs(String s, @Nullable Integer i)452     @Override public void twoMixedArgs(String s, @Nullable Integer i) {
453       checkNotNull(s);
454       i.intValue(); // ok to throw NPE?
455     }
456   }
457   static { passClasses.add(PassTwoMixedArgsNullableArgThrowsNPE.class); }
458 
459   static class PassTwoMixedArgSecondNullableArgThrowsOther extends PassObject {
twoMixedArgs(String s, @Nullable Integer i)460     @Override public void twoMixedArgs(String s, @Nullable Integer i) {
461       checkNotNull(s);
462       doThrow(i); // ok to throw non-NPE exception for null i
463     }
464   }
465   static { passClasses.add(PassTwoMixedArgSecondNullableArgThrowsOther.class); }
466 
467   static class FailTwoMixedArgsSecondArgDoesntThrowNPE extends PassObject {
twoMixedArgs(@ullable Integer i, String s)468     @Override public void twoMixedArgs(@Nullable Integer i, String s) {
469       // Fail: missing NPE for null s
470     }
471   }
472   static { failClasses.add(FailTwoMixedArgsSecondArgDoesntThrowNPE.class); }
473 
474   static class FailTwoMixedArgsSecondArgThrowsWrongType extends PassObject {
twoMixedArgs(@ullable Integer i, String s)475     @Override public void twoMixedArgs(@Nullable Integer i, String s) {
476       doThrow(s); // Fail:  throwing non-NPE exception for null s
477     }
478   }
479   static { failClasses.add(FailTwoMixedArgsSecondArgThrowsWrongType.class); }
480 
481   static class PassTwoNullableArgsFirstThrowsNPE extends PassObject {
twoNullableArgs( @ullable String s, @Nullable Integer i)482     @Override public void twoNullableArgs(
483         @Nullable String s, @Nullable Integer i) {
484       checkNotNull(s); // ok to throw NPE?
485     }
486   }
487   static { passClasses.add(PassTwoNullableArgsFirstThrowsNPE.class); }
488 
489   static class PassTwoNullableArgsFirstThrowsOther extends PassObject {
twoNullableArgs( @ullable String s, @Nullable Integer i)490     @Override public void twoNullableArgs(
491         @Nullable String s, @Nullable Integer i) {
492       doThrow(s); // ok to throw non-NPE exception for null s
493     }
494   }
495   static { passClasses.add(PassTwoNullableArgsFirstThrowsOther.class); }
496 
497   static class PassTwoNullableArgsSecondThrowsNPE extends PassObject {
twoNullableArgs( @ullable String s, @Nullable Integer i)498     @Override public void twoNullableArgs(
499         @Nullable String s, @Nullable Integer i) {
500       i.intValue(); // ok to throw NPE?
501     }
502   }
503   static { passClasses.add(PassTwoNullableArgsSecondThrowsNPE.class); }
504 
505   static class PassTwoNullableArgsSecondThrowsOther extends PassObject {
twoNullableArgs( @ullable String s, @Nullable Integer i)506     @Override public void twoNullableArgs(
507         @Nullable String s, @Nullable Integer i) {
508       doThrow(i); // ok to throw non-NPE exception for null i
509     }
510   }
511   static { passClasses.add(PassTwoNullableArgsSecondThrowsOther.class); }
512 
513   static class PassTwoNullableArgsNeitherThrowsAnything extends PassObject {
twoNullableArgs( @ullable String s, @Nullable Integer i)514     @Override public void twoNullableArgs(
515         @Nullable String s, @Nullable Integer i) {
516       // ok to do nothing
517     }
518   }
519   static { passClasses.add(PassTwoNullableArgsNeitherThrowsAnything.class); }
520 
521   /** Sanity check:  it's easy to make typos. */
checkClasses(String message, List<Class<?>> classes)522   private void checkClasses(String message, List<Class<?>> classes) {
523     Set<Class<?>> set = Sets.newHashSet(classes);
524     for (Class<?> clazz : classes) {
525       if (!set.remove(clazz)) {
526         fail(String.format("%s: %s appears twice. Typo?",
527             message, clazz.getSimpleName()));
528       }
529     }
530   }
531 
testDidntMakeTypoInTestCases()532   public void testDidntMakeTypoInTestCases() {
533     checkClasses("passClass", passClasses);
534     checkClasses("failClasses", failClasses);
535     List<Class<?>> allClasses = Lists.newArrayList(passClasses);
536     allClasses.addAll(failClasses);
537     checkClasses("allClasses", allClasses);
538   }
539 
testShouldNotFindProblemInPassClass()540   public void testShouldNotFindProblemInPassClass() throws Exception {
541     for (Class<?> passClass : passClasses) {
542       Object instance = passClass.newInstance();
543       try {
544         tester.testAllPublicInstanceMethods(instance);
545       } catch (AssertionFailedError e) {
546         assertNull("Should not detect problem in " + passClass.getSimpleName(),
547             e);
548       }
549     }
550   }
551 
testShouldFindProblemInFailClass()552   public void testShouldFindProblemInFailClass() throws Exception {
553     for (Class<?> failClass : failClasses) {
554       Object instance = failClass.newInstance();
555       boolean foundProblem = false;
556       try {
557         tester.testAllPublicInstanceMethods(instance);
558       } catch (AssertionFailedError e) {
559         foundProblem = true;
560       }
561       assertTrue("Should detect problem in " + failClass.getSimpleName(),
562           foundProblem);
563     }
564   }
565 
566   private static class PrivateClassWithPrivateConstructor {
PrivateClassWithPrivateConstructor(@ullable Integer argument)567     private PrivateClassWithPrivateConstructor(@Nullable Integer argument) {}
568   }
569 
testPrivateClass()570   public void testPrivateClass() throws Exception {
571     NullPointerTester tester = new NullPointerTester();
572     for (Constructor<?> constructor
573         : PrivateClassWithPrivateConstructor.class.getDeclaredConstructors()) {
574       tester.testConstructor(constructor);
575     }
576   }
577 
578   private interface Foo<T> {
doSomething(T bar, Integer baz)579     void doSomething(T bar, Integer baz);
580   }
581 
582   private static class StringFoo implements Foo<String> {
583 
doSomething(String bar, Integer baz)584     @Override public void doSomething(String bar, Integer baz) {
585       checkNotNull(bar);
586       checkNotNull(baz);
587     }
588   }
589 
testBidgeMethodIgnored()590   public void testBidgeMethodIgnored() throws Exception {
591     new NullPointerTester().testAllPublicInstanceMethods(new StringFoo());
592   }
593 
594   /*
595    *
596    * TODO(kevinb): This is only a very small start.
597    * Must come back and finish.
598    *
599    */
600 
601 }
602