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, "\"&#9992;\"");
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