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