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