• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 import static com.google.common.truth.Truth.assertThat;
21 import static org.junit.Assert.assertThrows;
22 
23 import com.google.common.base.Functions;
24 import com.google.common.base.Optional;
25 import com.google.common.collect.ImmutableList;
26 import com.google.common.testing.ClassSanityTester.FactoryMethodReturnsNullException;
27 import com.google.common.testing.ClassSanityTester.ParameterHasNoDistinctValueException;
28 import com.google.common.testing.ClassSanityTester.ParameterNotInstantiableException;
29 import com.google.common.testing.NullPointerTester.Visibility;
30 import java.io.Serializable;
31 import java.lang.reflect.InvocationTargetException;
32 import java.util.AbstractList;
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.concurrent.TimeUnit;
38 import java.util.stream.Collectors;
39 import java.util.stream.Stream;
40 import junit.framework.AssertionFailedError;
41 import junit.framework.TestCase;
42 import org.checkerframework.checker.nullness.qual.Nullable;
43 
44 /**
45  * Unit tests for {@link ClassSanityTester}.
46  *
47  * @author Ben Yu
48  */
49 public class ClassSanityTesterTest extends TestCase {
50 
51   private final ClassSanityTester tester = new ClassSanityTester();
52 
testEqualsOnReturnValues_good()53   public void testEqualsOnReturnValues_good() throws Exception {
54     tester.forAllPublicStaticMethods(GoodEqualsFactory.class).testEquals();
55   }
56 
57   public static class GoodEqualsFactory {
good( String a, int b, @SuppressWarnings("unused") OneConstantEnum oneConstantOnly, @SuppressWarnings("unused") @Nullable NoConstantEnum noConstant)58     public static Object good(
59         String a,
60         int b,
61         // oneConstantOnly doesn't matter since it's not nullable and can be only 1 value.
62         @SuppressWarnings("unused") OneConstantEnum oneConstantOnly,
63         // noConstant doesn't matter since it can only be null
64         @SuppressWarnings("unused") @Nullable NoConstantEnum noConstant) {
65       return new GoodEquals(a, b);
66     }
67 
68     // instance method ignored
badIgnored()69     public Object badIgnored() {
70       return new BadEquals();
71     }
72 
73     // primitive ignored
returnsInt()74     public int returnsInt() {
75       throw new UnsupportedOperationException();
76     }
77 
78     // void ignored
voidMethod()79     public void voidMethod() {
80       throw new UnsupportedOperationException();
81     }
82 
83     // non-public method ignored
badButNotPublic()84     static Object badButNotPublic() {
85       return new BadEquals();
86     }
87   }
88 
testForAllPublicStaticMethods_noPublicStaticMethods()89   public void testForAllPublicStaticMethods_noPublicStaticMethods() throws Exception {
90     try {
91       tester.forAllPublicStaticMethods(NoPublicStaticMethods.class).testEquals();
92     } catch (AssertionFailedError expected) {
93       assertThat(expected)
94           .hasMessageThat()
95           .isEqualTo(
96               "No public static methods that return java.lang.Object or subtype are found in "
97                   + NoPublicStaticMethods.class
98                   + ".");
99       return;
100     }
101     fail();
102   }
103 
testEqualsOnReturnValues_bad()104   public void testEqualsOnReturnValues_bad() throws Exception {
105     try {
106       tester.forAllPublicStaticMethods(BadEqualsFactory.class).testEquals();
107     } catch (AssertionFailedError expected) {
108       return;
109     }
110     fail();
111   }
112 
113   private static class BadEqualsFactory {
114     /** oneConstantOnly matters now since it can be either null or the constant. */
115     @SuppressWarnings("unused") // Called by reflection
bad(String a, int b, @Nullable OneConstantEnum oneConstantOnly)116     public static Object bad(String a, int b, @Nullable OneConstantEnum oneConstantOnly) {
117       return new GoodEquals(a, b);
118     }
119   }
120 
testNullsOnReturnValues_good()121   public void testNullsOnReturnValues_good() throws Exception {
122     tester.forAllPublicStaticMethods(GoodNullsFactory.class).testNulls();
123   }
124 
125   private static class GoodNullsFactory {
126     @SuppressWarnings("unused") // Called by reflection
good(String s)127     public static Object good(String s) {
128       return new GoodNulls(s);
129     }
130   }
131 
testNullsOnReturnValues_bad()132   public void testNullsOnReturnValues_bad() throws Exception {
133     try {
134       tester.forAllPublicStaticMethods(BadNullsFactory.class).thatReturn(Object.class).testNulls();
135     } catch (AssertionFailedError expected) {
136       return;
137     }
138     fail();
139   }
140 
testNullsOnReturnValues_returnTypeFiltered()141   public void testNullsOnReturnValues_returnTypeFiltered() throws Exception {
142     try {
143       tester
144           .forAllPublicStaticMethods(BadNullsFactory.class)
145           .thatReturn(Iterable.class)
146           .testNulls();
147     } catch (AssertionFailedError expected) {
148       assertThat(expected)
149           .hasMessageThat()
150           .isEqualTo(
151               "No public static methods that return java.lang.Iterable or subtype are found in "
152                   + BadNullsFactory.class
153                   + ".");
154       return;
155     }
156     fail();
157   }
158 
159   public static class BadNullsFactory {
bad(@uppressWarnings"unused") String a)160     public static Object bad(@SuppressWarnings("unused") String a) {
161       return new BadNulls();
162     }
163   }
164 
165   @AndroidIncompatible // TODO(cpovirk): ClassNotFoundException... ClassSanityTesterTest$AnInterface
testSerializableOnReturnValues_good()166   public void testSerializableOnReturnValues_good() throws Exception {
167     tester.forAllPublicStaticMethods(GoodSerializableFactory.class).testSerializable();
168   }
169 
170   public static class GoodSerializableFactory {
good(Runnable r)171     public static Object good(Runnable r) {
172       return r;
173     }
174 
good(AnInterface i)175     public static Object good(AnInterface i) {
176       return i;
177     }
178   }
179 
testSerializableOnReturnValues_bad()180   public void testSerializableOnReturnValues_bad() throws Exception {
181     try {
182       tester.forAllPublicStaticMethods(BadSerializableFactory.class).testSerializable();
183     } catch (AssertionFailedError expected) {
184       return;
185     }
186     fail();
187   }
188 
189   public static class BadSerializableFactory {
bad()190     public static Object bad() {
191       return new Serializable() {
192         @SuppressWarnings("unused")
193         private final Object notSerializable = new Object();
194       };
195     }
196   }
197 
testEqualsAndSerializableOnReturnValues_equalsIsGoodButNotSerializable()198   public void testEqualsAndSerializableOnReturnValues_equalsIsGoodButNotSerializable()
199       throws Exception {
200     try {
201       tester.forAllPublicStaticMethods(GoodEqualsFactory.class).testEqualsAndSerializable();
202     } catch (AssertionFailedError expected) {
203       return;
204     }
205     fail("should have failed");
206   }
207 
testEqualsAndSerializableOnReturnValues_serializableButNotEquals()208   public void testEqualsAndSerializableOnReturnValues_serializableButNotEquals() throws Exception {
209     try {
210       tester.forAllPublicStaticMethods(GoodSerializableFactory.class).testEqualsAndSerializable();
211     } catch (AssertionFailedError expected) {
212       return;
213     }
214     fail("should have failed");
215   }
216 
217   @AndroidIncompatible // TODO(cpovirk): ClassNotFoundException... ClassSanityTesterTest$AnInterface
testEqualsAndSerializableOnReturnValues_good()218   public void testEqualsAndSerializableOnReturnValues_good() throws Exception {
219     tester
220         .forAllPublicStaticMethods(GoodEqualsAndSerializableFactory.class)
221         .testEqualsAndSerializable();
222   }
223 
224   public static class GoodEqualsAndSerializableFactory {
good(AnInterface s)225     public static Object good(AnInterface s) {
226       return Functions.constant(s);
227     }
228   }
229 
testEqualsForReturnValues_factoryReturnsNullButNotAnnotated()230   public void testEqualsForReturnValues_factoryReturnsNullButNotAnnotated() throws Exception {
231     try {
232       tester.forAllPublicStaticMethods(FactoryThatReturnsNullButNotAnnotated.class).testEquals();
233     } catch (AssertionFailedError expected) {
234       return;
235     }
236     fail();
237   }
238 
testNullsForReturnValues_factoryReturnsNullButNotAnnotated()239   public void testNullsForReturnValues_factoryReturnsNullButNotAnnotated() throws Exception {
240     try {
241       tester.forAllPublicStaticMethods(FactoryThatReturnsNullButNotAnnotated.class).testNulls();
242     } catch (AssertionFailedError expected) {
243       return;
244     }
245     fail();
246   }
247 
testSerializableForReturnValues_factoryReturnsNullButNotAnnotated()248   public void testSerializableForReturnValues_factoryReturnsNullButNotAnnotated() throws Exception {
249     try {
250       tester
251           .forAllPublicStaticMethods(FactoryThatReturnsNullButNotAnnotated.class)
252           .testSerializable();
253     } catch (AssertionFailedError expected) {
254       return;
255     }
256     fail();
257   }
258 
testEqualsAndSerializableForReturnValues_factoryReturnsNullButNotAnnotated()259   public void testEqualsAndSerializableForReturnValues_factoryReturnsNullButNotAnnotated()
260       throws Exception {
261     try {
262       tester
263           .forAllPublicStaticMethods(FactoryThatReturnsNullButNotAnnotated.class)
264           .testEqualsAndSerializable();
265     } catch (AssertionFailedError expected) {
266       return;
267     }
268     fail();
269   }
270 
271   public static class FactoryThatReturnsNullButNotAnnotated {
bad()272     public static Object bad() {
273       return null;
274     }
275   }
276 
testEqualsForReturnValues_factoryReturnsNullAndAnnotated()277   public void testEqualsForReturnValues_factoryReturnsNullAndAnnotated() throws Exception {
278     tester.forAllPublicStaticMethods(FactoryThatReturnsNullAndAnnotated.class).testEquals();
279   }
280 
testNullsForReturnValues_factoryReturnsNullAndAnnotated()281   public void testNullsForReturnValues_factoryReturnsNullAndAnnotated() throws Exception {
282     tester.forAllPublicStaticMethods(FactoryThatReturnsNullAndAnnotated.class).testNulls();
283   }
284 
testSerializableForReturnValues_factoryReturnsNullAndAnnotated()285   public void testSerializableForReturnValues_factoryReturnsNullAndAnnotated() throws Exception {
286     tester.forAllPublicStaticMethods(FactoryThatReturnsNullAndAnnotated.class).testSerializable();
287   }
288 
testEqualsAndSerializableForReturnValues_factoryReturnsNullAndAnnotated()289   public void testEqualsAndSerializableForReturnValues_factoryReturnsNullAndAnnotated()
290       throws Exception {
291     tester
292         .forAllPublicStaticMethods(FactoryThatReturnsNullAndAnnotated.class)
293         .testEqualsAndSerializable();
294   }
295 
296   public static class FactoryThatReturnsNullAndAnnotated {
bad()297     public static @Nullable Object bad() {
298       return null;
299     }
300   }
301 
testGoodEquals()302   public void testGoodEquals() throws Exception {
303     tester.testEquals(GoodEquals.class);
304   }
305 
testEquals_interface()306   public void testEquals_interface() {
307     tester.testEquals(AnInterface.class);
308   }
309 
testEquals_abstractClass()310   public void testEquals_abstractClass() {
311     tester.testEquals(AnAbstractClass.class);
312   }
313 
testEquals_enum()314   public void testEquals_enum() {
315     tester.testEquals(OneConstantEnum.class);
316   }
317 
testBadEquals()318   public void testBadEquals() throws Exception {
319     try {
320       tester.testEquals(BadEquals.class);
321     } catch (AssertionFailedError expected) {
322       assertThat(expected).hasMessageThat().contains("create(null)");
323       return;
324     }
325     fail("should have failed");
326   }
327 
testBadEquals_withParameterizedType()328   public void testBadEquals_withParameterizedType() throws Exception {
329     try {
330       tester.testEquals(BadEqualsWithParameterizedType.class);
331     } catch (AssertionFailedError expected) {
332       assertThat(expected).hasMessageThat().contains("create([[1]])");
333       return;
334     }
335     fail("should have failed");
336   }
337 
testBadEquals_withSingleParameterValue()338   public void testBadEquals_withSingleParameterValue() throws Exception {
339     assertThrows(
340         ParameterHasNoDistinctValueException.class,
341         () -> tester.doTestEquals(ConstructorParameterWithOptionalNotInstantiable.class));
342   }
343 
testGoodReferentialEqualityComparison()344   public void testGoodReferentialEqualityComparison() throws Exception {
345     tester.testEquals(UsesEnum.class);
346     tester.testEquals(UsesReferentialEquality.class);
347     tester.testEquals(SameListInstance.class);
348   }
349 
testStreamParameterSkippedForNullTesting()350   public void testStreamParameterSkippedForNullTesting() throws Exception {
351     tester.testNulls(WithStreamParameter.class);
352   }
353 
354   @AndroidIncompatible // problem with equality of Type objects?
testEqualsUsingReferentialEquality()355   public void testEqualsUsingReferentialEquality() throws Exception {
356     assertBadUseOfReferentialEquality(SameIntegerInstance.class);
357     assertBadUseOfReferentialEquality(SameLongInstance.class);
358     assertBadUseOfReferentialEquality(SameFloatInstance.class);
359     assertBadUseOfReferentialEquality(SameDoubleInstance.class);
360     assertBadUseOfReferentialEquality(SameShortInstance.class);
361     assertBadUseOfReferentialEquality(SameByteInstance.class);
362     assertBadUseOfReferentialEquality(SameCharacterInstance.class);
363     assertBadUseOfReferentialEquality(SameBooleanInstance.class);
364     assertBadUseOfReferentialEquality(SameObjectInstance.class);
365     assertBadUseOfReferentialEquality(SameStringInstance.class);
366     assertBadUseOfReferentialEquality(SameInterfaceInstance.class);
367   }
368 
assertBadUseOfReferentialEquality(Class<?> cls)369   private void assertBadUseOfReferentialEquality(Class<?> cls) throws Exception {
370     try {
371       tester.testEquals(cls);
372     } catch (AssertionFailedError expected) {
373       assertThat(expected).hasMessageThat().contains(cls.getSimpleName() + "(");
374       return;
375     }
376     fail("should have failed for " + cls);
377   }
378 
testParameterNotInstantiableForEqualsTest()379   public void testParameterNotInstantiableForEqualsTest() throws Exception {
380     assertThrows(
381         ParameterNotInstantiableException.class,
382         () -> tester.doTestEquals(ConstructorParameterNotInstantiable.class));
383   }
384 
testNoDistinctValueForEqualsTest()385   public void testNoDistinctValueForEqualsTest() throws Exception {
386     assertThrows(
387         ParameterHasNoDistinctValueException.class,
388         () -> tester.doTestEquals(ConstructorParameterSingleValue.class));
389   }
390 
testConstructorThrowsForEqualsTest()391   public void testConstructorThrowsForEqualsTest() throws Exception {
392     assertThrows(
393         InvocationTargetException.class, () -> tester.doTestEquals(ConstructorThrows.class));
394   }
395 
testFactoryMethodReturnsNullForEqualsTest()396   public void testFactoryMethodReturnsNullForEqualsTest() throws Exception {
397     assertThrows(
398         FactoryMethodReturnsNullException.class,
399         () -> tester.doTestEquals(FactoryMethodReturnsNullAndAnnotated.class));
400   }
401 
testFactoryMethodReturnsNullButNotAnnotatedInEqualsTest()402   public void testFactoryMethodReturnsNullButNotAnnotatedInEqualsTest() throws Exception {
403     try {
404       tester.testEquals(FactoryMethodReturnsNullButNotAnnotated.class);
405     } catch (AssertionFailedError expected) {
406       return;
407     }
408     fail("should have failed");
409   }
410 
testNoEqualsChecksOnEnum()411   public void testNoEqualsChecksOnEnum() throws Exception {
412     tester.testEquals(OneConstantEnum.class);
413     tester.testEquals(NoConstantEnum.class);
414     tester.testEquals(TimeUnit.class);
415   }
416 
testNoEqualsChecksOnInterface()417   public void testNoEqualsChecksOnInterface() throws Exception {
418     tester.testEquals(Runnable.class);
419   }
420 
testNoEqualsChecksOnAnnotation()421   public void testNoEqualsChecksOnAnnotation() throws Exception {
422     tester.testEquals(MyAnnotation.class);
423   }
424 
testGoodNulls()425   public void testGoodNulls() throws Exception {
426     tester.testNulls(GoodNulls.class);
427   }
428 
testNoNullCheckNeededDespiteNotInstantiable()429   public void testNoNullCheckNeededDespiteNotInstantiable() throws Exception {
430     tester.doTestNulls(NoNullCheckNeededDespiteNotInstantiable.class, Visibility.PACKAGE);
431   }
432 
testNulls_interface()433   public void testNulls_interface() {
434     tester.testNulls(AnInterface.class);
435   }
436 
testNulls_abstractClass()437   public void testNulls_abstractClass() {
438     tester.testNulls(AnAbstractClass.class);
439   }
440 
testNulls_enum()441   public void testNulls_enum() throws Exception {
442     tester.testNulls(OneConstantEnum.class);
443     tester.testNulls(NoConstantEnum.class);
444     tester.testNulls(TimeUnit.class);
445   }
446 
testNulls_parameterOptionalNotInstantiable()447   public void testNulls_parameterOptionalNotInstantiable() throws Exception {
448     tester.testNulls(ConstructorParameterWithOptionalNotInstantiable.class);
449   }
450 
testEnumFailsToCheckNull()451   public void testEnumFailsToCheckNull() throws Exception {
452     try {
453       tester.testNulls(EnumFailsToCheckNull.class);
454     } catch (AssertionFailedError expected) {
455       return;
456     }
457     fail("should have failed");
458   }
459 
testNoNullChecksOnInterface()460   public void testNoNullChecksOnInterface() throws Exception {
461     tester.testNulls(Runnable.class);
462   }
463 
testNoNullChecksOnAnnotation()464   public void testNoNullChecksOnAnnotation() throws Exception {
465     tester.testNulls(MyAnnotation.class);
466   }
467 
testBadNulls()468   public void testBadNulls() throws Exception {
469     try {
470       tester.testNulls(BadNulls.class);
471     } catch (AssertionFailedError expected) {
472       return;
473     }
474     fail("should have failed");
475   }
476 
testInstantiate_factoryMethodReturnsNullButNotAnnotated()477   public void testInstantiate_factoryMethodReturnsNullButNotAnnotated() throws Exception {
478     try {
479       FactoryMethodReturnsNullButNotAnnotated unused =
480           tester.instantiate(FactoryMethodReturnsNullButNotAnnotated.class);
481     } catch (AssertionFailedError expected) {
482       assertThat(expected).hasMessageThat().contains("@Nullable");
483       return;
484     }
485     fail("should have failed");
486   }
487 
testInstantiate_factoryMethodReturnsNullAndAnnotated()488   public void testInstantiate_factoryMethodReturnsNullAndAnnotated() throws Exception {
489     assertThrows(
490         FactoryMethodReturnsNullException.class,
491         () -> tester.instantiate(FactoryMethodReturnsNullAndAnnotated.class));
492   }
493 
testInstantiate_factoryMethodAcceptsNull()494   public void testInstantiate_factoryMethodAcceptsNull() throws Exception {
495     assertNull(tester.instantiate(FactoryMethodAcceptsNull.class).name);
496   }
497 
testInstantiate_factoryMethodDoesNotAcceptNull()498   public void testInstantiate_factoryMethodDoesNotAcceptNull() throws Exception {
499     assertNotNull(tester.instantiate(FactoryMethodDoesNotAcceptNull.class).name);
500   }
501 
testInstantiate_constructorAcceptsNull()502   public void testInstantiate_constructorAcceptsNull() throws Exception {
503     assertNull(tester.instantiate(ConstructorAcceptsNull.class).name);
504   }
505 
testInstantiate_constructorDoesNotAcceptNull()506   public void testInstantiate_constructorDoesNotAcceptNull() throws Exception {
507     assertNotNull(tester.instantiate(ConstructorDoesNotAcceptNull.class).name);
508   }
509 
testInstantiate_notInstantiable()510   public void testInstantiate_notInstantiable() throws Exception {
511     assertNull(tester.instantiate(NotInstantiable.class));
512   }
513 
testInstantiate_noConstantEnum()514   public void testInstantiate_noConstantEnum() throws Exception {
515     assertNull(tester.instantiate(NoConstantEnum.class));
516   }
517 
testInstantiate_oneConstantEnum()518   public void testInstantiate_oneConstantEnum() throws Exception {
519     assertEquals(OneConstantEnum.A, tester.instantiate(OneConstantEnum.class));
520   }
521 
testInstantiate_interface()522   public void testInstantiate_interface() throws Exception {
523     assertNull(tester.instantiate(Runnable.class));
524   }
525 
testInstantiate_abstractClass()526   public void testInstantiate_abstractClass() throws Exception {
527     assertNull(tester.instantiate(AbstractList.class));
528   }
529 
testInstantiate_annotation()530   public void testInstantiate_annotation() throws Exception {
531     assertNull(tester.instantiate(MyAnnotation.class));
532   }
533 
testInstantiate_setDefault()534   public void testInstantiate_setDefault() throws Exception {
535     NotInstantiable x = new NotInstantiable();
536     tester.setDefault(NotInstantiable.class, x);
537     assertNotNull(tester.instantiate(ConstructorParameterNotInstantiable.class));
538   }
539 
testSetDistinctValues_equalInstances()540   public void testSetDistinctValues_equalInstances() {
541     assertThrows(
542         IllegalArgumentException.class, () -> tester.setDistinctValues(String.class, "", ""));
543   }
544 
testInstantiate_setDistinctValues()545   public void testInstantiate_setDistinctValues() throws Exception {
546     NotInstantiable x = new NotInstantiable();
547     NotInstantiable y = new NotInstantiable();
548     tester.setDistinctValues(NotInstantiable.class, x, y);
549     assertNotNull(tester.instantiate(ConstructorParameterNotInstantiable.class));
550     tester.testEquals(ConstructorParameterMapOfNotInstantiable.class);
551   }
552 
testInstantiate_constructorThrows()553   public void testInstantiate_constructorThrows() throws Exception {
554     assertThrows(
555         InvocationTargetException.class, () -> tester.instantiate(ConstructorThrows.class));
556   }
557 
testInstantiate_factoryMethodThrows()558   public void testInstantiate_factoryMethodThrows() throws Exception {
559     assertThrows(
560         InvocationTargetException.class, () -> tester.instantiate(FactoryMethodThrows.class));
561   }
562 
testInstantiate_constructorParameterNotInstantiable()563   public void testInstantiate_constructorParameterNotInstantiable() throws Exception {
564     assertThrows(
565         ParameterNotInstantiableException.class,
566         () -> tester.instantiate(ConstructorParameterNotInstantiable.class));
567   }
568 
testInstantiate_factoryMethodParameterNotInstantiable()569   public void testInstantiate_factoryMethodParameterNotInstantiable() throws Exception {
570     assertThrows(
571         ParameterNotInstantiableException.class,
572         () -> tester.instantiate(FactoryMethodParameterNotInstantiable.class));
573   }
574 
testInstantiate_instantiableFactoryMethodChosen()575   public void testInstantiate_instantiableFactoryMethodChosen() throws Exception {
576     assertEquals("good", tester.instantiate(InstantiableFactoryMethodChosen.class).name);
577   }
578 
579   @AndroidIncompatible // TODO(cpovirk): ClassNotFoundException... ClassSanityTesterTest$AnInterface
testInterfaceProxySerializable()580   public void testInterfaceProxySerializable() throws Exception {
581     SerializableTester.reserializeAndAssert(tester.instantiate(HasAnInterface.class));
582   }
583 
testReturnValuesFromAnotherPackageIgnoredForNullTests()584   public void testReturnValuesFromAnotherPackageIgnoredForNullTests() throws Exception {
585     new ClassSanityTester().forAllPublicStaticMethods(JdkObjectFactory.class).testNulls();
586   }
587 
588   /** String doesn't check nulls as we expect. But the framework should ignore. */
589   private static class JdkObjectFactory {
590     @SuppressWarnings("unused") // Called by reflection
create()591     public static Object create() {
592       return new ArrayList<>();
593     }
594   }
595 
596   static class HasAnInterface implements Serializable {
597     private final AnInterface i;
598 
HasAnInterface(AnInterface i)599     public HasAnInterface(AnInterface i) {
600       this.i = i;
601     }
602 
603     @Override
equals(@ullable Object obj)604     public boolean equals(@Nullable Object obj) {
605       if (obj instanceof HasAnInterface) {
606         HasAnInterface that = (HasAnInterface) obj;
607         return i.equals(that.i);
608       } else {
609         return false;
610       }
611     }
612 
613     @Override
hashCode()614     public int hashCode() {
615       return i.hashCode();
616     }
617   }
618 
619   static class InstantiableFactoryMethodChosen {
620     final String name;
621 
InstantiableFactoryMethodChosen(String name)622     private InstantiableFactoryMethodChosen(String name) {
623       this.name = name;
624     }
625 
InstantiableFactoryMethodChosen(NotInstantiable x)626     public InstantiableFactoryMethodChosen(NotInstantiable x) {
627       checkNotNull(x);
628       this.name = "x1";
629     }
630 
create(NotInstantiable x)631     public static InstantiableFactoryMethodChosen create(NotInstantiable x) {
632       return new InstantiableFactoryMethodChosen(x);
633     }
634 
create(String s)635     public static InstantiableFactoryMethodChosen create(String s) {
636       checkNotNull(s);
637       return new InstantiableFactoryMethodChosen("good");
638     }
639   }
640 
testInstantiate_instantiableConstructorChosen()641   public void testInstantiate_instantiableConstructorChosen() throws Exception {
642     assertEquals("good", tester.instantiate(InstantiableConstructorChosen.class).name);
643   }
644 
testEquals_setOfNonInstantiable()645   public void testEquals_setOfNonInstantiable() throws Exception {
646     assertThrows(
647         ParameterNotInstantiableException.class,
648         () -> new ClassSanityTester().doTestEquals(SetWrapper.class));
649   }
650 
651   private abstract static class Wrapper {
652     private final Object wrapped;
653 
Wrapper(Object wrapped)654     Wrapper(Object wrapped) {
655       this.wrapped = checkNotNull(wrapped);
656     }
657 
658     @Override
equals(@ullable Object obj)659     public boolean equals(@Nullable Object obj) {
660       // In general getClass().isInstance() is bad for equals.
661       // But here we fully control the subclasses to ensure symmetry.
662       if (getClass().isInstance(obj)) {
663         Wrapper that = (Wrapper) obj;
664         return wrapped.equals(that.wrapped);
665       }
666       return false;
667     }
668 
669     @Override
hashCode()670     public int hashCode() {
671       return wrapped.hashCode();
672     }
673 
674     @Override
toString()675     public String toString() {
676       return wrapped.toString();
677     }
678   }
679 
680   private static class SetWrapper extends Wrapper {
SetWrapper(Set<NotInstantiable> wrapped)681     public SetWrapper(Set<NotInstantiable> wrapped) {
682       super(wrapped);
683     }
684   }
685 
686   static class InstantiableConstructorChosen {
687     final String name;
688 
InstantiableConstructorChosen(String name)689     public InstantiableConstructorChosen(String name) {
690       checkNotNull(name);
691       this.name = "good";
692     }
693 
InstantiableConstructorChosen(NotInstantiable x)694     public InstantiableConstructorChosen(NotInstantiable x) {
695       checkNotNull(x);
696       this.name = "x1";
697     }
698 
create(NotInstantiable x)699     public static InstantiableFactoryMethodChosen create(NotInstantiable x) {
700       return new InstantiableFactoryMethodChosen(x);
701     }
702   }
703 
704   static class GoodEquals {
705 
706     private final String a;
707     private final int b;
708 
GoodEquals(String a, int b)709     private GoodEquals(String a, int b) {
710       this.a = checkNotNull(a);
711       this.b = b;
712     }
713 
714     // ignored by testEquals()
GoodEquals(@uppressWarnings"unused") NotInstantiable x)715     GoodEquals(@SuppressWarnings("unused") NotInstantiable x) {
716       this.a = "x";
717       this.b = -1;
718     }
719 
720     // will keep trying
GoodEquals(@uppressWarnings"unused") NotInstantiable x, int b)721     public GoodEquals(@SuppressWarnings("unused") NotInstantiable x, int b) {
722       this.a = "x";
723       this.b = b;
724     }
725 
726     // keep trying
727     @SuppressWarnings("unused")
create(int a, int b)728     static GoodEquals create(int a, int b) {
729       throw new RuntimeException();
730     }
731 
732     // Good!
create(String a, int b)733     static GoodEquals create(String a, int b) {
734       return new GoodEquals(a, b);
735     }
736 
737     // keep trying
738     @SuppressWarnings("unused")
createMayReturnNull(int a, int b)739     public static @Nullable GoodEquals createMayReturnNull(int a, int b) {
740       return null;
741     }
742 
743     @Override
equals(@ullable Object obj)744     public boolean equals(@Nullable Object obj) {
745       if (obj instanceof GoodEquals) {
746         GoodEquals that = (GoodEquals) obj;
747         return a.equals(that.a) && b == that.b;
748       } else {
749         return false;
750       }
751     }
752 
753     @Override
hashCode()754     public int hashCode() {
755       return 0;
756     }
757   }
758 
759   static class BadEquals {
760 
BadEquals()761     public BadEquals() {} // ignored by testEquals() since it has less parameters.
762 
create(@uppressWarnings"unused") @ullable String s)763     public static BadEquals create(@SuppressWarnings("unused") @Nullable String s) {
764       return new BadEquals();
765     }
766 
767     @Override
equals(@ullable Object obj)768     public boolean equals(@Nullable Object obj) {
769       return obj instanceof BadEquals;
770     }
771 
772     @Override
hashCode()773     public int hashCode() {
774       return 0;
775     }
776   }
777 
778   static class SameIntegerInstance {
779     private final Integer i;
780 
SameIntegerInstance(Integer i)781     public SameIntegerInstance(Integer i) {
782       this.i = checkNotNull(i);
783     }
784 
785     @Override
hashCode()786     public int hashCode() {
787       return i.hashCode();
788     }
789 
790     @Override
791     @SuppressWarnings({"BoxedPrimitiveEquality", "NumericEquality"})
equals(@ullable Object obj)792     public boolean equals(@Nullable Object obj) {
793       if (obj instanceof SameIntegerInstance) {
794         SameIntegerInstance that = (SameIntegerInstance) obj;
795         return i == that.i;
796       }
797       return false;
798     }
799   }
800 
801   static class SameLongInstance {
802     private final Long i;
803 
SameLongInstance(Long i)804     public SameLongInstance(Long i) {
805       this.i = checkNotNull(i);
806     }
807 
808     @Override
hashCode()809     public int hashCode() {
810       return i.hashCode();
811     }
812 
813     @Override
814     @SuppressWarnings({"BoxedPrimitiveEquality", "NumericEquality"})
equals(@ullable Object obj)815     public boolean equals(@Nullable Object obj) {
816       if (obj instanceof SameLongInstance) {
817         SameLongInstance that = (SameLongInstance) obj;
818         return i == that.i;
819       }
820       return false;
821     }
822   }
823 
824   static class SameFloatInstance {
825     private final Float i;
826 
SameFloatInstance(Float i)827     public SameFloatInstance(Float i) {
828       this.i = checkNotNull(i);
829     }
830 
831     @Override
hashCode()832     public int hashCode() {
833       return i.hashCode();
834     }
835 
836     @Override
837     @SuppressWarnings({"BoxedPrimitiveEquality", "NumericEquality"})
equals(@ullable Object obj)838     public boolean equals(@Nullable Object obj) {
839       if (obj instanceof SameFloatInstance) {
840         SameFloatInstance that = (SameFloatInstance) obj;
841         return i == that.i;
842       }
843       return false;
844     }
845   }
846 
847   static class SameDoubleInstance {
848     private final Double i;
849 
SameDoubleInstance(Double i)850     public SameDoubleInstance(Double i) {
851       this.i = checkNotNull(i);
852     }
853 
854     @Override
hashCode()855     public int hashCode() {
856       return i.hashCode();
857     }
858 
859     @Override
860     @SuppressWarnings({"BoxedPrimitiveEquality", "NumericEquality"})
equals(@ullable Object obj)861     public boolean equals(@Nullable Object obj) {
862       if (obj instanceof SameDoubleInstance) {
863         SameDoubleInstance that = (SameDoubleInstance) obj;
864         return i == that.i;
865       }
866       return false;
867     }
868   }
869 
870   static class SameShortInstance {
871     private final Short i;
872 
SameShortInstance(Short i)873     public SameShortInstance(Short i) {
874       this.i = checkNotNull(i);
875     }
876 
877     @Override
hashCode()878     public int hashCode() {
879       return i.hashCode();
880     }
881 
882     @Override
883     @SuppressWarnings({"BoxedPrimitiveEquality", "NumericEquality"})
equals(@ullable Object obj)884     public boolean equals(@Nullable Object obj) {
885       if (obj instanceof SameShortInstance) {
886         SameShortInstance that = (SameShortInstance) obj;
887         return i == that.i;
888       }
889       return false;
890     }
891   }
892 
893   static class SameByteInstance {
894     private final Byte i;
895 
SameByteInstance(Byte i)896     public SameByteInstance(Byte i) {
897       this.i = checkNotNull(i);
898     }
899 
900     @Override
hashCode()901     public int hashCode() {
902       return i.hashCode();
903     }
904 
905     @Override
906     @SuppressWarnings({"BoxedPrimitiveEquality", "NumericEquality"})
equals(@ullable Object obj)907     public boolean equals(@Nullable Object obj) {
908       if (obj instanceof SameByteInstance) {
909         SameByteInstance that = (SameByteInstance) obj;
910         return i == that.i;
911       }
912       return false;
913     }
914   }
915 
916   static class SameCharacterInstance {
917     private final Character i;
918 
SameCharacterInstance(Character i)919     public SameCharacterInstance(Character i) {
920       this.i = checkNotNull(i);
921     }
922 
923     @Override
hashCode()924     public int hashCode() {
925       return i.hashCode();
926     }
927 
928     @Override
929     @SuppressWarnings("BoxedPrimitiveEquality")
equals(@ullable Object obj)930     public boolean equals(@Nullable Object obj) {
931       if (obj instanceof SameCharacterInstance) {
932         SameCharacterInstance that = (SameCharacterInstance) obj;
933         return i == that.i;
934       }
935       return false;
936     }
937   }
938 
939   static class SameBooleanInstance {
940     private final Boolean i;
941 
SameBooleanInstance(Boolean i)942     public SameBooleanInstance(Boolean i) {
943       this.i = checkNotNull(i);
944     }
945 
946     @Override
hashCode()947     public int hashCode() {
948       return i.hashCode();
949     }
950 
951     @Override
952     @SuppressWarnings("BoxedPrimitiveEquality")
equals(@ullable Object obj)953     public boolean equals(@Nullable Object obj) {
954       if (obj instanceof SameBooleanInstance) {
955         SameBooleanInstance that = (SameBooleanInstance) obj;
956         return i == that.i;
957       }
958       return false;
959     }
960   }
961 
962   static class SameStringInstance {
963     private final String s;
964 
SameStringInstance(String s)965     public SameStringInstance(String s) {
966       this.s = checkNotNull(s);
967     }
968 
969     @Override
hashCode()970     public int hashCode() {
971       return s.hashCode();
972     }
973 
974     @Override
equals(@ullable Object obj)975     public boolean equals(@Nullable Object obj) {
976       if (obj instanceof SameStringInstance) {
977         SameStringInstance that = (SameStringInstance) obj;
978         return s == that.s;
979       }
980       return false;
981     }
982   }
983 
984   static class SameObjectInstance {
985     private final Object s;
986 
SameObjectInstance(Object s)987     public SameObjectInstance(Object s) {
988       this.s = checkNotNull(s);
989     }
990 
991     @Override
hashCode()992     public int hashCode() {
993       return s.hashCode();
994     }
995 
996     @Override
equals(@ullable Object obj)997     public boolean equals(@Nullable Object obj) {
998       if (obj instanceof SameObjectInstance) {
999         SameObjectInstance that = (SameObjectInstance) obj;
1000         return s == that.s;
1001       }
1002       return false;
1003     }
1004   }
1005 
1006   static class SameInterfaceInstance {
1007     private final Runnable s;
1008 
SameInterfaceInstance(Runnable s)1009     public SameInterfaceInstance(Runnable s) {
1010       this.s = checkNotNull(s);
1011     }
1012 
1013     @Override
hashCode()1014     public int hashCode() {
1015       return s.hashCode();
1016     }
1017 
1018     @Override
equals(@ullable Object obj)1019     public boolean equals(@Nullable Object obj) {
1020       if (obj instanceof SameInterfaceInstance) {
1021         SameInterfaceInstance that = (SameInterfaceInstance) obj;
1022         return s == that.s;
1023       }
1024       return false;
1025     }
1026   }
1027 
1028   static class SameListInstance {
1029     private final List<?> s;
1030 
SameListInstance(List<?> s)1031     public SameListInstance(List<?> s) {
1032       this.s = checkNotNull(s);
1033     }
1034 
1035     @Override
hashCode()1036     public int hashCode() {
1037       return System.identityHashCode(s);
1038     }
1039 
1040     @Override
equals(@ullable Object obj)1041     public boolean equals(@Nullable Object obj) {
1042       if (obj instanceof SameListInstance) {
1043         SameListInstance that = (SameListInstance) obj;
1044         return s == that.s;
1045       }
1046       return false;
1047     }
1048   }
1049 
1050   static class WithStreamParameter {
1051     private final List<?> list;
1052 
1053     // This should be ignored.
WithStreamParameter(Stream<?> s, String str)1054     public WithStreamParameter(Stream<?> s, String str) {
1055       this.list = s.collect(Collectors.toList());
1056       checkNotNull(str);
1057     }
1058   }
1059 
1060   static class UsesReferentialEquality {
1061     private final ReferentialEquality s;
1062 
UsesReferentialEquality(ReferentialEquality s)1063     public UsesReferentialEquality(ReferentialEquality s) {
1064       this.s = checkNotNull(s);
1065     }
1066 
1067     @Override
hashCode()1068     public int hashCode() {
1069       return s.hashCode();
1070     }
1071 
1072     @Override
equals(@ullable Object obj)1073     public boolean equals(@Nullable Object obj) {
1074       if (obj instanceof UsesReferentialEquality) {
1075         UsesReferentialEquality that = (UsesReferentialEquality) obj;
1076         return s == that.s;
1077       }
1078       return false;
1079     }
1080   }
1081 
1082   static class UsesEnum {
1083     private final TimeUnit s;
1084 
UsesEnum(TimeUnit s)1085     public UsesEnum(TimeUnit s) {
1086       this.s = checkNotNull(s);
1087     }
1088 
1089     @Override
hashCode()1090     public int hashCode() {
1091       return s.hashCode();
1092     }
1093 
1094     @Override
equals(@ullable Object obj)1095     public boolean equals(@Nullable Object obj) {
1096       if (obj instanceof UsesEnum) {
1097         UsesEnum that = (UsesEnum) obj;
1098         return s == that.s;
1099       }
1100       return false;
1101     }
1102   }
1103 
1104   public static class ReferentialEquality {
ReferentialEquality()1105     public ReferentialEquality() {}
1106   }
1107 
1108   static class BadEqualsWithParameterizedType {
1109 
1110     // ignored by testEquals() since it has less parameters.
BadEqualsWithParameterizedType()1111     public BadEqualsWithParameterizedType() {}
1112 
create( @uppressWarnings"unused") ImmutableList<Iterable<? extends String>> s)1113     public static BadEqualsWithParameterizedType create(
1114         @SuppressWarnings("unused") ImmutableList<Iterable<? extends String>> s) {
1115       return new BadEqualsWithParameterizedType();
1116     }
1117 
1118     @Override
equals(@ullable Object obj)1119     public boolean equals(@Nullable Object obj) {
1120       return obj instanceof BadEqualsWithParameterizedType;
1121     }
1122 
1123     @Override
hashCode()1124     public int hashCode() {
1125       return 0;
1126     }
1127   }
1128 
1129   static class GoodNulls {
GoodNulls(String s)1130     public GoodNulls(String s) {
1131       checkNotNull(s);
1132     }
1133 
rejectNull(String s)1134     public void rejectNull(String s) {
1135       checkNotNull(s);
1136     }
1137   }
1138 
1139   public static class BadNulls {
failsToRejectNull(@uppressWarnings"unused") String s)1140     public void failsToRejectNull(@SuppressWarnings("unused") String s) {}
1141   }
1142 
1143   public static class NoNullCheckNeededDespiteNotInstantiable {
1144 
NoNullCheckNeededDespiteNotInstantiable(NotInstantiable x)1145     public NoNullCheckNeededDespiteNotInstantiable(NotInstantiable x) {
1146       checkNotNull(x);
1147     }
1148 
1149     @SuppressWarnings("unused") // reflected
primitiveOnly(int i)1150     void primitiveOnly(int i) {}
1151 
1152     @SuppressWarnings("unused") // reflected
nullableOnly(@ullable String s)1153     void nullableOnly(@Nullable String s) {}
1154 
noParameter()1155     public void noParameter() {}
1156 
1157     @SuppressWarnings("unused") // reflected
primitiveAndNullable(@ullable String s, int i)1158     void primitiveAndNullable(@Nullable String s, int i) {}
1159   }
1160 
1161   static class FactoryMethodReturnsNullButNotAnnotated {
FactoryMethodReturnsNullButNotAnnotated()1162     private FactoryMethodReturnsNullButNotAnnotated() {}
1163 
returnsNull()1164     static FactoryMethodReturnsNullButNotAnnotated returnsNull() {
1165       return null;
1166     }
1167   }
1168 
1169   static class FactoryMethodReturnsNullAndAnnotated {
FactoryMethodReturnsNullAndAnnotated()1170     private FactoryMethodReturnsNullAndAnnotated() {}
1171 
returnsNull()1172     public static @Nullable FactoryMethodReturnsNullAndAnnotated returnsNull() {
1173       return null;
1174     }
1175   }
1176 
1177   static class FactoryMethodAcceptsNull {
1178 
1179     final String name;
1180 
FactoryMethodAcceptsNull(String name)1181     private FactoryMethodAcceptsNull(String name) {
1182       this.name = name;
1183     }
1184 
create(@ullable String name)1185     static FactoryMethodAcceptsNull create(@Nullable String name) {
1186       return new FactoryMethodAcceptsNull(name);
1187     }
1188   }
1189 
1190   static class FactoryMethodDoesNotAcceptNull {
1191 
1192     final String name;
1193 
FactoryMethodDoesNotAcceptNull(String name)1194     private FactoryMethodDoesNotAcceptNull(String name) {
1195       this.name = checkNotNull(name);
1196     }
1197 
create(String name)1198     public static FactoryMethodDoesNotAcceptNull create(String name) {
1199       return new FactoryMethodDoesNotAcceptNull(name);
1200     }
1201   }
1202 
1203   static class ConstructorAcceptsNull {
1204 
1205     final String name;
1206 
ConstructorAcceptsNull(@ullable String name)1207     public ConstructorAcceptsNull(@Nullable String name) {
1208       this.name = name;
1209     }
1210   }
1211 
1212   static class ConstructorDoesNotAcceptNull {
1213 
1214     final String name;
1215 
ConstructorDoesNotAcceptNull(String name)1216     ConstructorDoesNotAcceptNull(String name) {
1217       this.name = checkNotNull(name);
1218     }
1219   }
1220 
1221   static class ConstructorParameterNotInstantiable {
ConstructorParameterNotInstantiable(@uppressWarnings"unused") NotInstantiable x)1222     public ConstructorParameterNotInstantiable(@SuppressWarnings("unused") NotInstantiable x) {}
1223   }
1224 
1225   static class ConstructorParameterMapOfNotInstantiable {
1226     private final Map<NotInstantiable, NotInstantiable> m;
1227 
ConstructorParameterMapOfNotInstantiable(Map<NotInstantiable, NotInstantiable> m)1228     public ConstructorParameterMapOfNotInstantiable(Map<NotInstantiable, NotInstantiable> m) {
1229       this.m = checkNotNull(m);
1230     }
1231 
1232     @Override
equals(@ullable Object obj)1233     public boolean equals(@Nullable Object obj) {
1234       if (obj instanceof ConstructorParameterMapOfNotInstantiable) {
1235         return m.equals(((ConstructorParameterMapOfNotInstantiable) obj).m);
1236       } else {
1237         return false;
1238       }
1239     }
1240 
1241     @Override
hashCode()1242     public int hashCode() {
1243       return m.hashCode();
1244     }
1245   }
1246 
1247   // Test that we should get a distinct parameter error when doing equals test.
1248   static class ConstructorParameterWithOptionalNotInstantiable {
ConstructorParameterWithOptionalNotInstantiable(Optional<NotInstantiable> x)1249     public ConstructorParameterWithOptionalNotInstantiable(Optional<NotInstantiable> x) {
1250       checkNotNull(x);
1251     }
1252 
1253     @Override
equals(@ullable Object obj)1254     public boolean equals(@Nullable Object obj) {
1255       throw new UnsupportedOperationException();
1256     }
1257 
1258     @Override
hashCode()1259     public int hashCode() {
1260       throw new UnsupportedOperationException();
1261     }
1262   }
1263 
1264   static class ConstructorParameterSingleValue {
ConstructorParameterSingleValue(@uppressWarnings"unused") Singleton s)1265     public ConstructorParameterSingleValue(@SuppressWarnings("unused") Singleton s) {}
1266 
1267     @Override
equals(@ullable Object obj)1268     public boolean equals(@Nullable Object obj) {
1269       return obj instanceof ConstructorParameterSingleValue;
1270     }
1271 
1272     @Override
hashCode()1273     public int hashCode() {
1274       return 1;
1275     }
1276 
1277     public static class Singleton {
1278       public static final Singleton INSTANCE = new Singleton();
1279 
Singleton()1280       private Singleton() {}
1281     }
1282   }
1283 
1284   static class FactoryMethodParameterNotInstantiable {
1285 
FactoryMethodParameterNotInstantiable()1286     private FactoryMethodParameterNotInstantiable() {}
1287 
create( @uppressWarnings"unused") NotInstantiable x)1288     static FactoryMethodParameterNotInstantiable create(
1289         @SuppressWarnings("unused") NotInstantiable x) {
1290       return new FactoryMethodParameterNotInstantiable();
1291     }
1292   }
1293 
1294   static class ConstructorThrows {
ConstructorThrows()1295     public ConstructorThrows() {
1296       throw new RuntimeException();
1297     }
1298   }
1299 
1300   static class FactoryMethodThrows {
FactoryMethodThrows()1301     private FactoryMethodThrows() {}
1302 
create()1303     public static FactoryMethodThrows create() {
1304       throw new RuntimeException();
1305     }
1306   }
1307 
1308   static class NotInstantiable {
NotInstantiable()1309     private NotInstantiable() {}
1310   }
1311 
1312   private enum NoConstantEnum {}
1313 
1314   private enum OneConstantEnum {
1315     A
1316   }
1317 
1318   private enum EnumFailsToCheckNull {
1319     A;
1320 
1321     @SuppressWarnings("unused")
failToCheckNull(String s)1322     public void failToCheckNull(String s) {}
1323   }
1324 
1325   private interface AnInterface {}
1326 
1327   private abstract static class AnAbstractClass {
1328     @SuppressWarnings("unused")
AnAbstractClass(String s)1329     public AnAbstractClass(String s) {}
1330 
1331     @SuppressWarnings("unused")
failsToCheckNull(String s)1332     public void failsToCheckNull(String s) {}
1333   }
1334 
1335   private static class NoPublicStaticMethods {
1336     @SuppressWarnings("unused") // To test non-public factory isn't used.
notPublic()1337     static String notPublic() {
1338       return "";
1339     }
1340   }
1341 
1342   @interface MyAnnotation {}
1343 }
1344