• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, "\"&#9992;\"");
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