1 /* 2 * Copyright (C) 2007 The Android Open Source Project 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 android.signature.cts.tests; 18 19 import static org.junit.Assert.assertEquals; 20 21 import android.signature.cts.ApiComplianceChecker; 22 import android.signature.cts.ClassProvider; 23 import android.signature.cts.FailureType; 24 import android.signature.cts.JDiffClassDescription; 25 import android.signature.cts.ResultObserver; 26 import android.signature.cts.tests.data.AbstractClass; 27 import android.signature.cts.tests.data.AbstractClassWithCtor; 28 import android.signature.cts.tests.data.ComplexEnum; 29 import android.signature.cts.tests.data.ExtendedNormalInterface; 30 import android.signature.cts.tests.data.NormalClass; 31 import android.signature.cts.tests.data.NormalInterface; 32 33 import org.junit.Test; 34 import org.junit.runner.RunWith; 35 import org.junit.runners.JUnit4; 36 37 import java.lang.reflect.Modifier; 38 import java.util.function.Consumer; 39 40 /** 41 * Test class for JDiffClassDescription. 42 */ 43 @RunWith(JUnit4.class) 44 public class ApiComplianceCheckerTest extends ApiPresenceCheckerTest<ApiComplianceChecker> { 45 46 @Override createChecker(ResultObserver resultObserver, ClassProvider provider)47 protected ApiComplianceChecker createChecker(ResultObserver resultObserver, 48 ClassProvider provider) { 49 return new ApiComplianceChecker(resultObserver, provider); 50 } 51 52 @Override runWithApiChecker( ResultObserver resultObserver, Consumer<ApiComplianceChecker> consumer, String... excludedRuntimeClasses)53 void runWithApiChecker( 54 ResultObserver resultObserver, Consumer<ApiComplianceChecker> consumer, String... excludedRuntimeClasses) { 55 super.runWithApiChecker( 56 resultObserver, 57 checker -> { 58 consumer.accept(checker); 59 checker.checkDeferred(); 60 }, 61 excludedRuntimeClasses); 62 } 63 64 @Test testNormalClassCompliance()65 public void testNormalClassCompliance() { 66 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 67 checkSignatureCompliance(clz); 68 assertEquals(clz.toSignatureString(), "public class NormalClass"); 69 } 70 71 @Test testMissingClass()72 public void testMissingClass() { 73 try (ExpectFailure observer = new ExpectFailure(FailureType.MISSING_CLASS)) { 74 JDiffClassDescription clz = new JDiffClassDescription( 75 "android.signature.cts.tests.data", "NoSuchClass"); 76 clz.setType(JDiffClassDescription.JDiffType.CLASS); 77 checkSignatureCompliance(clz, observer); 78 } 79 } 80 81 @Test testSimpleConstructor()82 public void testSimpleConstructor() { 83 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 84 JDiffClassDescription.JDiffConstructor constructor = ctor("NormalClass", Modifier.PUBLIC); 85 clz.addConstructor(constructor); 86 checkSignatureCompliance(clz); 87 assertEquals(constructor.toSignatureString(), "public NormalClass()"); 88 } 89 90 @Test testOneArgConstructor()91 public void testOneArgConstructor() { 92 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 93 JDiffClassDescription.JDiffConstructor constructor = ctor("NormalClass", Modifier.PRIVATE); 94 constructor.addParam("java.lang.String"); 95 clz.addConstructor(constructor); 96 checkSignatureCompliance(clz); 97 assertEquals(constructor.toSignatureString(), "private NormalClass(java.lang.String)"); 98 } 99 100 @Test testConstructorThrowsException()101 public void testConstructorThrowsException() { 102 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 103 JDiffClassDescription.JDiffConstructor constructor = 104 ctor("NormalClass", Modifier.PROTECTED); 105 constructor.addParam("java.lang.String"); 106 constructor.addParam("java.lang.String"); 107 constructor.addException("android.signature.cts.tests.data.NormalException"); 108 clz.addConstructor(constructor); 109 checkSignatureCompliance(clz); 110 assertEquals(constructor.toSignatureString(), 111 "protected NormalClass(java.lang.String, java.lang.String) " + 112 "throws android.signature.cts.tests.data.NormalException"); 113 } 114 115 @Test testPackageProtectedConstructor()116 public void testPackageProtectedConstructor() { 117 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 118 JDiffClassDescription.JDiffConstructor constructor = ctor("NormalClass", 0); 119 constructor.addParam("java.lang.String"); 120 constructor.addParam("java.lang.String"); 121 constructor.addParam("java.lang.String"); 122 clz.addConstructor(constructor); 123 checkSignatureCompliance(clz); 124 assertEquals(constructor.toSignatureString(), 125 "NormalClass(java.lang.String, java.lang.String, java.lang.String)"); 126 } 127 128 @Test testStaticMethod()129 public void testStaticMethod() { 130 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 131 JDiffClassDescription.JDiffMethod method = method("staticMethod", 132 Modifier.STATIC | Modifier.PUBLIC, "void"); 133 clz.addMethod(method); 134 checkSignatureCompliance(clz); 135 assertEquals(method.toSignatureString(), "public static void staticMethod()"); 136 } 137 138 @Test testSyncMethod()139 public void testSyncMethod() { 140 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 141 JDiffClassDescription.JDiffMethod method = method("syncMethod", 142 Modifier.SYNCHRONIZED | Modifier.PUBLIC, "void"); 143 clz.addMethod(method); 144 checkSignatureCompliance(clz); 145 assertEquals(method.toSignatureString(), "public synchronized void syncMethod()"); 146 } 147 148 @Test testPackageProtectMethod()149 public void testPackageProtectMethod() { 150 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 151 JDiffClassDescription.JDiffMethod method = method("packageProtectedMethod", 0, "boolean"); 152 clz.addMethod(method); 153 checkSignatureCompliance(clz); 154 assertEquals(method.toSignatureString(), "boolean packageProtectedMethod()"); 155 } 156 157 @Test testPrivateMethod()158 public void testPrivateMethod() { 159 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 160 JDiffClassDescription.JDiffMethod method = method("privateMethod", Modifier.PRIVATE, 161 "void"); 162 clz.addMethod(method); 163 checkSignatureCompliance(clz); 164 assertEquals(method.toSignatureString(), "private void privateMethod()"); 165 } 166 167 @Test testProtectedMethod()168 public void testProtectedMethod() { 169 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 170 JDiffClassDescription.JDiffMethod method = method("protectedMethod", Modifier.PROTECTED, 171 "java.lang.String"); 172 clz.addMethod(method); 173 checkSignatureCompliance(clz); 174 assertEquals(method.toSignatureString(), "protected java.lang.String protectedMethod()"); 175 } 176 177 @Test testThrowsMethod()178 public void testThrowsMethod() { 179 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 180 JDiffClassDescription.JDiffMethod method = method("throwsMethod", Modifier.PUBLIC, "void"); 181 method.addException("android.signature.cts.tests.data.NormalException"); 182 clz.addMethod(method); 183 checkSignatureCompliance(clz); 184 assertEquals(method.toSignatureString(), "public void throwsMethod() " + 185 "throws android.signature.cts.tests.data.NormalException"); 186 } 187 188 @Test testNativeMethod()189 public void testNativeMethod() { 190 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 191 JDiffClassDescription.JDiffMethod method = method("nativeMethod", 192 Modifier.PUBLIC | Modifier.NATIVE, "void"); 193 clz.addMethod(method); 194 checkSignatureCompliance(clz); 195 assertEquals(method.toSignatureString(), "public native void nativeMethod()"); 196 } 197 198 /** 199 * Check that a varargs method is treated as compliant. 200 */ 201 @Test testVarargsMethod()202 public void testVarargsMethod() { 203 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 204 JDiffClassDescription.JDiffMethod method = method("varargs", 205 Modifier.PUBLIC, "void"); 206 method.addParam("java.lang.String..."); 207 clz.addMethod(method); 208 assertEquals(method.toSignatureString(), "public void varargs(java.lang.String...)"); 209 210 checkSignatureCompliance(clz); 211 } 212 213 /** 214 * Check that a clone method (which produces a special method that is marked as {@code bridge} 215 * and {@code synthetic}) is treated as compliant. 216 */ 217 @Test testCloneMethod()218 public void testCloneMethod() { 219 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 220 // The generic method: 221 // NormalClass clone() throws CloneNotSupportedException 222 JDiffClassDescription.JDiffMethod method = method("clone", 223 Modifier.PUBLIC, NormalClass.class.getName()); 224 method.addException(CloneNotSupportedException.class.getName()); 225 clz.addMethod(method); 226 assertEquals(method.toSignatureString(), 227 "public android.signature.cts.tests.data.NormalClass clone()" 228 + " throws java.lang.CloneNotSupportedException"); 229 230 // The synthetic bridge method: 231 // Object clone() throws CloneNotSupportedException 232 method = method("clone", 233 Modifier.PUBLIC, Object.class.getName()); 234 method.addException(CloneNotSupportedException.class.getName()); 235 clz.addMethod(method); 236 assertEquals(method.toSignatureString(), 237 "public java.lang.Object clone()" 238 + " throws java.lang.CloneNotSupportedException"); 239 240 checkSignatureCompliance(clz); 241 } 242 243 @Test testFinalField()244 public void testFinalField() { 245 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 246 JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField( 247 "FINAL_FIELD", "java.lang.String", Modifier.PUBLIC | Modifier.FINAL, VALUE); 248 clz.addField(field); 249 checkSignatureCompliance(clz); 250 assertEquals(field.toSignatureString(), "public final java.lang.String FINAL_FIELD"); 251 } 252 253 @Test testStaticField()254 public void testStaticField() { 255 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 256 JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField( 257 "STATIC_FIELD", "java.lang.String", Modifier.PUBLIC | Modifier.STATIC, VALUE); 258 clz.addField(field); 259 checkSignatureCompliance(clz); 260 assertEquals(field.toSignatureString(), "public static java.lang.String STATIC_FIELD"); 261 } 262 263 @Test testVolatileFiled()264 public void testVolatileFiled() { 265 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 266 JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField( 267 "VOLATILE_FIELD", "java.lang.String", Modifier.PUBLIC | Modifier.VOLATILE, VALUE); 268 clz.addField(field); 269 checkSignatureCompliance(clz); 270 assertEquals(field.toSignatureString(), "public volatile java.lang.String VOLATILE_FIELD"); 271 } 272 273 @Test testTransientField()274 public void testTransientField() { 275 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 276 JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField( 277 "TRANSIENT_FIELD", "java.lang.String", 278 Modifier.PUBLIC | Modifier.TRANSIENT, VALUE); 279 clz.addField(field); 280 checkSignatureCompliance(clz); 281 assertEquals(field.toSignatureString(), 282 "public transient java.lang.String TRANSIENT_FIELD"); 283 } 284 285 @Test testPackageField()286 public void testPackageField() { 287 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 288 JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField( 289 "PACAKGE_FIELD", "java.lang.String", 0, VALUE); 290 clz.addField(field); 291 checkSignatureCompliance(clz); 292 assertEquals(field.toSignatureString(), "java.lang.String PACAKGE_FIELD"); 293 } 294 295 @Test testPrivateField()296 public void testPrivateField() { 297 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 298 JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField( 299 "PRIVATE_FIELD", "java.lang.String", Modifier.PRIVATE, VALUE); 300 clz.addField(field); 301 checkSignatureCompliance(clz); 302 assertEquals(field.toSignatureString(), "private java.lang.String PRIVATE_FIELD"); 303 } 304 305 @Test testProtectedField()306 public void testProtectedField() { 307 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 308 JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField( 309 "PROTECTED_FIELD", "java.lang.String", Modifier.PROTECTED, VALUE); 310 clz.addField(field); 311 checkSignatureCompliance(clz); 312 assertEquals(field.toSignatureString(), "protected java.lang.String PROTECTED_FIELD"); 313 } 314 315 @Test testFieldValue()316 public void testFieldValue() { 317 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 318 JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField( 319 "VALUE_FIELD", "java.lang.String", 320 Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC, "\u2708"); 321 clz.addField(field); 322 checkSignatureCompliance(clz); 323 assertEquals(field.toSignatureString(), "public static final java.lang.String VALUE_FIELD"); 324 } 325 326 @Test testFieldValueChanged()327 public void testFieldValueChanged() { 328 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_FIELD)) { 329 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 330 JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField( 331 "VALUE_FIELD", "java.lang.String", 332 Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC, "\"✈\""); 333 clz.addField(field); 334 checkSignatureCompliance(clz, observer); 335 assertEquals(field.toSignatureString(), 336 "public static final java.lang.String VALUE_FIELD"); 337 } 338 } 339 340 @Test testInnerClass()341 public void testInnerClass() { 342 JDiffClassDescription clz = createClass("NormalClass.InnerClass"); 343 JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField( 344 "innerClassData", "java.lang.String", Modifier.PRIVATE, VALUE); 345 clz.addField(field); 346 checkSignatureCompliance(clz); 347 assertEquals(clz.toSignatureString(), "public class NormalClass.InnerClass"); 348 } 349 350 @Test testInnerInnerClass()351 public void testInnerInnerClass() { 352 JDiffClassDescription clz = createClass( 353 "NormalClass.InnerClass.InnerInnerClass"); 354 JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField( 355 "innerInnerClassData", "java.lang.String", Modifier.PRIVATE, VALUE); 356 clz.addField(field); 357 checkSignatureCompliance(clz); 358 assertEquals(clz.toSignatureString(), 359 "public class NormalClass.InnerClass.InnerInnerClass"); 360 } 361 362 @Test testInnerInterface()363 public void testInnerInterface() { 364 JDiffClassDescription clz = new JDiffClassDescription( 365 "android.signature.cts.tests.data", "NormalClass.InnerInterface"); 366 clz.setType(JDiffClassDescription.JDiffType.INTERFACE); 367 clz.setModifier(Modifier.PUBLIC | Modifier.STATIC | Modifier.ABSTRACT); 368 clz.addMethod( 369 method("doSomething", Modifier.PUBLIC | Modifier.ABSTRACT, "void")); 370 checkSignatureCompliance(clz); 371 assertEquals(clz.toSignatureString(), "public interface NormalClass.InnerInterface"); 372 } 373 374 @Test testInterface()375 public void testInterface() { 376 JDiffClassDescription clz = createInterface("NormalInterface"); 377 clz.addMethod( 378 method("doSomething", Modifier.ABSTRACT | Modifier.PUBLIC, "void")); 379 checkSignatureCompliance(clz); 380 assertEquals(clz.toSignatureString(), "public interface NormalInterface"); 381 } 382 383 /** 384 * Always treat interfaces as if they are abstract, even when the modifiers do not specify that. 385 */ 386 @Test testInterfaceAlwaysTreatAsAbstract()387 public void testInterfaceAlwaysTreatAsAbstract() { 388 JDiffClassDescription clz = createInterface("NormalInterface"); 389 clz.setModifier(Modifier.PUBLIC); 390 clz.addMethod(method("doSomething", Modifier.ABSTRACT | Modifier.PUBLIC, "void")); 391 checkSignatureCompliance(clz); 392 } 393 394 @Test testComplexEnum()395 public void testComplexEnum() { 396 JDiffClassDescription clz = createClass(ComplexEnum.class.getSimpleName()); 397 clz.setExtendsClass(Enum.class.getName()); 398 clz.setModifier(Modifier.PUBLIC | Modifier.FINAL); 399 checkSignatureCompliance(clz); 400 } 401 402 @Test testFinalClass()403 public void testFinalClass() { 404 JDiffClassDescription clz = new JDiffClassDescription( 405 "android.signature.cts.tests.data", "FinalClass"); 406 clz.setType(JDiffClassDescription.JDiffType.CLASS); 407 clz.setModifier(Modifier.PUBLIC | Modifier.FINAL); 408 checkSignatureCompliance(clz); 409 assertEquals(clz.toSignatureString(), "public final class FinalClass"); 410 } 411 412 @Test testRemovingFinalFromAClass()413 public void testRemovingFinalFromAClass() { 414 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 415 clz.setModifier(Modifier.PUBLIC | Modifier.FINAL); 416 checkSignatureCompliance(clz); 417 } 418 419 @Test testRemovingFinalFromAClass_PreviousApi()420 public void testRemovingFinalFromAClass_PreviousApi() { 421 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 422 clz.setModifier(Modifier.PUBLIC | Modifier.FINAL); 423 clz.setPreviousApiFlag(true); 424 checkSignatureCompliance(clz); 425 } 426 427 /** 428 * Test that if the API class is final but the runtime is abstract (and not final) that it is 429 * an error. 430 * 431 * http://b/181019981 432 */ 433 @Test testRemovingFinalFromAClassSwitchToAbstract()434 public void testRemovingFinalFromAClassSwitchToAbstract() { 435 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) { 436 JDiffClassDescription clz = createClass(AbstractClass.class.getSimpleName()); 437 clz.setModifier(Modifier.PUBLIC | Modifier.FINAL); 438 checkSignatureCompliance(clz, observer); 439 } 440 } 441 442 /** 443 * Test that if the API class in a previous release is final but the runtime is abstract (and 444 * not final) that it is not an error. 445 * 446 * http://b/181019981 447 */ 448 @Test testRemovingFinalFromAClassSwitchToAbstract_PreviousApi()449 public void testRemovingFinalFromAClassSwitchToAbstract_PreviousApi() { 450 JDiffClassDescription clz = createClass(AbstractClass.class.getSimpleName()); 451 clz.setModifier(Modifier.PUBLIC | Modifier.FINAL); 452 clz.setPreviousApiFlag(true); 453 checkSignatureCompliance(clz); 454 } 455 456 /** 457 * Test that if the API class in a previous release is final but the runtime is abstract (and 458 * not final) and has constructors then it is an error. 459 * 460 * http://b/181019981 461 */ 462 @Test testRemovingFinalFromAClassWithCtorSwitchToAbstract_PreviousApi()463 public void testRemovingFinalFromAClassWithCtorSwitchToAbstract_PreviousApi() { 464 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) { 465 String simpleName = AbstractClassWithCtor.class.getSimpleName(); 466 JDiffClassDescription clz = createClass(simpleName); 467 clz.setModifier(Modifier.PUBLIC | Modifier.FINAL); 468 clz.setPreviousApiFlag(true); 469 clz.addConstructor(ctor(simpleName, Modifier.PUBLIC)); 470 checkSignatureCompliance(clz, observer); 471 } 472 } 473 474 /** 475 * Test the case where the API declares the method is synchronized, but it 476 * actually is not. 477 */ 478 @Test testRemovingSync()479 public void testRemovingSync() { 480 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 481 JDiffClassDescription.JDiffMethod method = method("notSyncMethod", 482 Modifier.SYNCHRONIZED | Modifier.PUBLIC, "void"); 483 clz.addMethod(method); 484 checkSignatureCompliance(clz); 485 } 486 487 /** 488 * API says method is not native, but it actually is. http://b/1839558 489 */ 490 @Test testAddingNative()491 public void testAddingNative() { 492 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 493 JDiffClassDescription.JDiffMethod method = method("nativeMethod", Modifier.PUBLIC, "void"); 494 clz.addMethod(method); 495 checkSignatureCompliance(clz); 496 } 497 498 /** 499 * API says method is native, but actually isn't. http://b/1839558 500 */ 501 @Test testRemovingNative()502 public void testRemovingNative() { 503 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 504 JDiffClassDescription.JDiffMethod method = method("notNativeMethod", 505 Modifier.NATIVE | Modifier.PUBLIC, "void"); 506 clz.addMethod(method); 507 checkSignatureCompliance(clz); 508 } 509 510 @Test testAbstractClass()511 public void testAbstractClass() { 512 JDiffClassDescription clz = new JDiffClassDescription( 513 "android.signature.cts.tests.data", "AbstractClass"); 514 clz.setType(JDiffClassDescription.JDiffType.CLASS); 515 clz.setModifier(Modifier.PUBLIC | Modifier.ABSTRACT); 516 checkSignatureCompliance(clz); 517 assertEquals(clz.toSignatureString(), "public abstract class AbstractClass"); 518 } 519 520 /** 521 * API lists class as abstract, reflection does not. http://b/1839622 522 */ 523 @Test testRemovingAbstractFromAClass()524 public void testRemovingAbstractFromAClass() { 525 JDiffClassDescription clz = 526 new JDiffClassDescription("android.signature.cts.tests.data", "NormalClass"); 527 clz.setType(JDiffClassDescription.JDiffType.CLASS); 528 clz.setModifier(Modifier.PUBLIC | Modifier.ABSTRACT); 529 checkSignatureCompliance(clz); 530 } 531 532 /** 533 * Previous API lists class as abstract, reflection does not. http://b/1839622 534 */ 535 @Test testRemovingAbstractFromAClass_PreviousApi()536 public void testRemovingAbstractFromAClass_PreviousApi() { 537 JDiffClassDescription clz = new JDiffClassDescription( 538 "android.signature.cts.tests.data", "NormalClass"); 539 clz.setType(JDiffClassDescription.JDiffType.CLASS); 540 clz.setModifier(Modifier.PUBLIC | Modifier.ABSTRACT); 541 clz.setPreviousApiFlag(true); 542 checkSignatureCompliance(clz); 543 } 544 545 /** 546 * reflection lists class as abstract, api does not. http://b/1839622 547 */ 548 @Test testAddingAbstractToAClass()549 public void testAddingAbstractToAClass() { 550 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) { 551 JDiffClassDescription clz = createClass("AbstractClass"); 552 checkSignatureCompliance(clz, observer); 553 } 554 } 555 556 /** 557 * The current API lists the class as being final but the runtime class does not so they are 558 * incompatible. 559 */ 560 @Test testAddingFinalToAClass()561 public void testAddingFinalToAClass() { 562 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) { 563 JDiffClassDescription clz = createClass("FinalClass"); 564 checkSignatureCompliance(clz, observer); 565 } 566 } 567 568 /** 569 * A previously released API lists the class as being final but the runtime class does not. 570 * 571 * <p>While adding a final modifier to a class is not strictly backwards compatible it is when 572 * the class has no accessible constructors and so cannot be instantiated or extended, as is the 573 * case in this test.</p> 574 */ 575 @Test testAddingFinalToAClassNoCtor_PreviousApi()576 public void testAddingFinalToAClassNoCtor_PreviousApi() { 577 JDiffClassDescription clz = createClass("FinalClass"); 578 clz.setPreviousApiFlag(true); 579 checkSignatureCompliance(clz); 580 } 581 582 /** 583 * A previously released API lists the class as being final but the runtime class does not. 584 * 585 * <p>Adding a final modifier to a class is not backwards compatible when the class has some 586 * accessible constructors and so could be instantiated and/or extended, as is the case of this 587 * class.</p> 588 */ 589 @Test testAddingFinalToAClassWithCtor_PreviousApi()590 public void testAddingFinalToAClassWithCtor_PreviousApi() { 591 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) { 592 String simpleName = "FinalClassWithCtor"; 593 JDiffClassDescription clz = createClass(simpleName); 594 clz.setPreviousApiFlag(true); 595 clz.addConstructor(ctor(simpleName, Modifier.PUBLIC)); 596 checkSignatureCompliance(clz, observer); 597 } 598 } 599 600 /** 601 * The current API lists the class as being static but the runtime class does not so they are 602 * incompatible. 603 */ 604 @Test testAddingStaticToInnerClass()605 public void testAddingStaticToInnerClass() { 606 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) { 607 JDiffClassDescription clz = createClass("AbstractClass.StaticNestedClass"); 608 checkSignatureCompliance(clz, observer); 609 } 610 } 611 612 /** 613 * A previously released API lists the class as being static but the runtime class does not. 614 * 615 * <p>While adding a static modifier to a class is not strictly backwards compatible it is when 616 * the class has no accessible constructors and so cannot be instantiated or extended, as is the 617 * case in this test.</p> 618 */ 619 @Test testAddingStaticToInnerClassNoCtor_PreviousApi()620 public void testAddingStaticToInnerClassNoCtor_PreviousApi() { 621 JDiffClassDescription clz = createClass("AbstractClass.StaticNestedClass"); 622 clz.setPreviousApiFlag(true); 623 checkSignatureCompliance(clz); 624 } 625 626 /** 627 * A previously released API lists the class as being static but the runtime class does not. 628 * 629 * <p>Adding a static modifier to a class is not backwards compatible when the class has some 630 * accessible constructors and so could be instantiated and/or extended, as is the case of this 631 * class.</p> 632 */ 633 @Test testAddingStaticToInnerClassWithCtor_PreviousApi()634 public void testAddingStaticToInnerClassWithCtor_PreviousApi() { 635 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_CLASS)) { 636 String simpleName = "AbstractClass.StaticNestedClassWithCtor"; 637 JDiffClassDescription clz = createClass(simpleName); 638 clz.setPreviousApiFlag(true); 639 clz.addConstructor(ctor(simpleName, Modifier.PUBLIC)); 640 checkSignatureCompliance(clz, observer); 641 } 642 } 643 644 /** 645 * Compatible (no change): 646 * 647 * public abstract void AbstractClass#abstractMethod() 648 * -> public abstract void AbstractClass#abstractMethod() 649 */ 650 @Test testAbstractMethod()651 public void testAbstractMethod() { 652 JDiffClassDescription clz = createAbstractClass(AbstractClass.class.getSimpleName()); 653 JDiffClassDescription.JDiffMethod method = method("abstractMethod", 654 Modifier.PUBLIC | Modifier.ABSTRACT, "void"); 655 clz.addMethod(method); 656 checkSignatureCompliance(clz); 657 } 658 659 /** 660 * Incompatible (provide implementation for abstract method): 661 * 662 * public abstract void Normal#notSyncMethod() 663 * -> public void Normal#notSyncMethod() 664 */ 665 @Test testRemovingAbstractFromMethod()666 public void testRemovingAbstractFromMethod() { 667 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 668 JDiffClassDescription.JDiffMethod method = 669 method("notSyncMethod", Modifier.PUBLIC | Modifier.ABSTRACT, "void"); 670 clz.addMethod(method); 671 checkSignatureCompliance(clz); 672 } 673 674 /** 675 * A previously released API lists the method as being abstract but the runtime class does not. 676 * 677 * <p>While adding an abstract modifier to a method is not strictly backwards compatible it is 678 * when the class has no accessible constructors and so cannot be instantiated or extended, as 679 * is the case in this test.</p> 680 */ 681 @Test testRemovingAbstractFromMethodOnClassNoCtor_PreviousApi()682 public void testRemovingAbstractFromMethodOnClassNoCtor_PreviousApi() { 683 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 684 JDiffClassDescription.JDiffMethod method = method("notSyncMethod", 685 Modifier.PUBLIC | Modifier.ABSTRACT, "void"); 686 clz.addMethod(method); 687 clz.setPreviousApiFlag(true); 688 checkSignatureCompliance(clz); 689 } 690 691 /** 692 * Not compatible (overridden method is not overridable anymore): 693 * 694 * public abstract void AbstractClass#finalMethod() 695 * -> public final void AbstractClass#finalMethod() 696 */ 697 @Test testAbstractToFinalMethod()698 public void testAbstractToFinalMethod() { 699 JDiffClassDescription clz = createAbstractClass(AbstractClass.class.getSimpleName()); 700 JDiffClassDescription.JDiffMethod method = method("finalMethod", 701 Modifier.PUBLIC | Modifier.ABSTRACT, "void"); 702 clz.addMethod(method); 703 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD)) { 704 checkSignatureCompliance(clz, observer); 705 } 706 } 707 708 /** 709 * Not compatible (previously implemented method becomes abstract): 710 * 711 * public void AbstractClass#abstractMethod() 712 * -> public abstract void AbstractClass#abstractMethod() 713 */ 714 @Test testAddingAbstractToMethod()715 public void testAddingAbstractToMethod() { 716 JDiffClassDescription clz = createAbstractClass(AbstractClass.class.getSimpleName()); 717 JDiffClassDescription.JDiffMethod method = method("abstractMethod", 718 Modifier.PUBLIC, "void"); 719 clz.addMethod(method); 720 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD)) { 721 checkSignatureCompliance(clz, observer); 722 } 723 } 724 725 @Test testFinalMethod()726 public void testFinalMethod() { 727 JDiffClassDescription clz = createClass(NormalClass.class.getSimpleName()); 728 JDiffClassDescription.JDiffMethod method = method("finalMethod", 729 Modifier.PUBLIC | Modifier.FINAL, "void"); 730 clz.addMethod(method); 731 checkSignatureCompliance(clz); 732 assertEquals(method.toSignatureString(), "public final void finalMethod()"); 733 } 734 735 /** 736 * Final Class, API lists methods as non-final, reflection has it as final. 737 * http://b/1839589 738 */ 739 @Test testAddingFinalToAMethodInAFinalClass()740 public void testAddingFinalToAMethodInAFinalClass() { 741 JDiffClassDescription clz = new JDiffClassDescription( 742 "android.signature.cts.tests.data", "FinalClass"); 743 clz.setType(JDiffClassDescription.JDiffType.CLASS); 744 clz.setModifier(Modifier.PUBLIC | Modifier.FINAL); 745 JDiffClassDescription.JDiffMethod method = method("finalMethod", Modifier.PUBLIC, "void"); 746 clz.addMethod(method); 747 checkSignatureCompliance(clz); 748 } 749 750 /** 751 * Final Class, API lists methods as final, reflection has it as non-final. 752 * http://b/1839589 753 */ 754 @Test testRemovingFinalToAMethodInAFinalClass()755 public void testRemovingFinalToAMethodInAFinalClass() { 756 JDiffClassDescription clz = new JDiffClassDescription( 757 "android.signature.cts.tests.data", "FinalClass"); 758 clz.setType(JDiffClassDescription.JDiffType.CLASS); 759 clz.setModifier(Modifier.PUBLIC | Modifier.FINAL); 760 JDiffClassDescription.JDiffMethod method = method("nonFinalMethod", 761 Modifier.PUBLIC | Modifier.FINAL, "void"); 762 clz.addMethod(method); 763 checkSignatureCompliance(clz); 764 } 765 766 /** 767 * non-final Class, API lists methods as non-final, reflection has it as 768 * final. http://b/1839589 769 */ 770 @Test testAddingFinalToAMethodInANonFinalClass()771 public void testAddingFinalToAMethodInANonFinalClass() { 772 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_METHOD)) { 773 JDiffClassDescription clz = createClass("NormalClass"); 774 JDiffClassDescription.JDiffMethod method = method("finalMethod", Modifier.PUBLIC, 775 "void"); 776 clz.addMethod(method); 777 checkSignatureCompliance(clz, observer); 778 } 779 } 780 781 @Test testExtendedNormalInterface()782 public void testExtendedNormalInterface() { 783 try (NoFailures observer = new NoFailures()) { 784 runWithApiChecker(observer, checker -> { 785 JDiffClassDescription iface = createInterface( 786 NormalInterface.class.getSimpleName()); 787 iface.addMethod(method("doSomething", Modifier.PUBLIC, "void")); 788 checker.addBaseClass(iface); 789 790 JDiffClassDescription clz = 791 createInterface(ExtendedNormalInterface.class.getSimpleName()); 792 clz.addMethod( 793 method("doSomethingElse", Modifier.PUBLIC | Modifier.ABSTRACT, "void")); 794 clz.addImplInterface(iface.getAbsoluteClassName()); 795 checker.checkSignatureCompliance(clz); 796 }); 797 } 798 } 799 800 @Test testAddingRuntimeMethodToInterface()801 public void testAddingRuntimeMethodToInterface() { 802 try (ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_INTERFACE_METHOD)) { 803 runWithApiChecker(observer, checker -> { 804 JDiffClassDescription iface = createInterface( 805 ExtendedNormalInterface.class.getSimpleName()); 806 iface.addMethod(method("doSomething", Modifier.PUBLIC | Modifier.ABSTRACT, "void")); 807 checker.checkSignatureCompliance(iface); 808 }); 809 } 810 } 811 812 @Test testAddingRuntimeMethodToInterface_PreviousApi()813 public void testAddingRuntimeMethodToInterface_PreviousApi() { 814 try (NoFailures observer = new NoFailures()) { 815 runWithApiChecker(observer, checker -> { 816 JDiffClassDescription iface = createInterface( 817 ExtendedNormalInterface.class.getSimpleName()); 818 iface.addMethod(method("doSomething", Modifier.PUBLIC | Modifier.ABSTRACT, "void")); 819 iface.setPreviousApiFlag(true); 820 checker.checkSignatureCompliance(iface); 821 }); 822 } 823 } 824 } 825