1 /*
2  * Copyright (C) 2017 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 com.android.tools.metalava
18 
19 import org.intellij.lang.annotations.Language
20 import org.junit.Test
21 
22 class ApiFromTextTest : DriverTest() {
23 
24     @Test
Loading a signature file and writing the API back outnull25     fun `Loading a signature file and writing the API back out`() {
26         val source = """
27                 package test.pkg {
28                   public class MyTest {
29                     ctor public MyTest();
30                     method public int clamp(int);
31                     method public java.lang.Double convert(java.lang.Float);
32                     field public static final java.lang.String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
33                     field public java.lang.Number myNumber;
34                   }
35                 }
36                 """
37 
38         check(
39             compatibilityMode = true,
40             signatureSource = source,
41             api = source
42         )
43     }
44 
45     @Test
Handle lambdas as default valuesnull46     fun `Handle lambdas as default values`() {
47         val source = """
48             // Signature format: 3.0
49             package androidx.collection {
50               public final class LruCacheKt {
51                 ctor public LruCacheKt();
52                 method public static <K, V> androidx.collection.LruCache<K,V> lruCache(int maxSize, kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf = { _, _ -> 1 }, kotlin.jvm.functions.Function1<? super K,? extends V> create = { null as V? }, kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved = { _, _, _, _ -> });
53               }
54             }
55         """
56 
57         check(
58             format = FileFormat.V3,
59             compatibilityMode = false,
60             inputKotlinStyleNulls = true,
61             signatureSource = source,
62             includeSignatureVersion = true,
63             api = source
64         )
65     }
66 
67     @Test
Invoking function with multiple parameters as parameter default valuenull68     fun `Invoking function with multiple parameters as parameter default value`() {
69         val source = """
70             // Signature format: 3.0
71             package abc {
72               public final class PopupKt {
73                 method public static void DropdownPopup(Type ident = SomeFunc(SomeVal, SomeVal));
74               }
75             }
76         """
77 
78         check(
79             format = FileFormat.V3,
80             compatibilityMode = false,
81             inputKotlinStyleNulls = true,
82             signatureSource = source,
83             includeSignatureVersion = true,
84             api = source
85         )
86     }
87 
88     @Test
Handle enum constants as default valuesnull89     fun `Handle enum constants as default values`() {
90         val source = """
91             // Signature format: 3.0
92             package test.pkg {
93               public final class Foo {
94                 ctor public Foo();
95                 method public android.graphics.Bitmap? drawToBitmap(android.view.View, android.graphics.Bitmap.Config config = android.graphics.Bitmap.Config.ARGB_8888);
96                 method public void emptyLambda(kotlin.jvm.functions.Function0<kotlin.Unit> sizeOf = {});
97                 method public void method1(int p = 42, Integer? int2 = null, int p1 = 42, String str = "hello world", java.lang.String... args);
98                 method public void method2(int p, int int2 = (2 * int) * some.other.pkg.Constants.Misc.SIZE);
99                 method public void method3(String str, int p, int int2 = double(int) + str.length);
100                 field public static final test.pkg.Foo.Companion! Companion;
101               }
102               public static final class Foo.Companion {
103                 method public int double(int p);
104                 method public void print(test.pkg.Foo foo = test.pkg.Foo());
105               }
106               public final class LruCacheKt {
107                 ctor public LruCacheKt();
108                 method public static <K, V> android.util.LruCache<K,V> lruCache(int maxSize, kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf = { _, _ -> 1 }, kotlin.jvm.functions.Function1<? super K,? extends V> create = { (V)null }, kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved = { _, _, _, _ ->  });
109               }
110             }
111             """
112 
113         check(
114             format = FileFormat.V3,
115             compatibilityMode = false,
116             inputKotlinStyleNulls = true,
117             signatureSource = source,
118             includeSignatureVersion = true,
119             api = source
120         )
121     }
122 
123     @Test
Handle complex expressions as default valuesnull124     fun `Handle complex expressions as default values`() {
125         val source = """
126             // Signature format: 3.0
127             package androidx.paging {
128               public final class PagedListConfigKt {
129                 ctor public PagedListConfigKt();
130                 method public static androidx.paging.PagedList.Config Config(int pageSize, int prefetchDistance = pageSize, boolean enablePlaceholders = true, int initialLoadSizeHint = pageSize * PagedList.Config.Builder.DEFAULT_INITIAL_PAGE_MULTIPLIER, int maxSize = PagedList.Config.MAX_SIZE_UNBOUNDED);
131               }
132               public final class PagedListKt {
133                 ctor public PagedListKt();
134                 method public static <Key, Value> androidx.paging.PagedList<Value> PagedList(androidx.paging.DataSource<Key,Value> dataSource, androidx.paging.PagedList.Config config, java.util.concurrent.Executor notifyExecutor, java.util.concurrent.Executor fetchExecutor, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, Key? initialKey = null);
135               }
136             }
137             package test.pkg {
138               public final class Foo {
139                 ctor public Foo();
140                 method public void method1(int p = 42, Integer? int2 = null, int p1 = 42, String str = "hello world", java.lang.String... args);
141                 method public void method2(int p, int int2 = (2 * int) * some.other.pkg.Constants.Misc.SIZE);
142                 method public void method3(str: String = "unbalanced), string", str2: String = ",");
143               }
144             }
145         """
146 
147         check(
148             format = FileFormat.V3,
149             compatibilityMode = false,
150             inputKotlinStyleNulls = true,
151             signatureSource = source,
152             includeSignatureVersion = true,
153             api = source
154         )
155     }
156 
157     @Test
Annotation signatures requiring more complicated token matchingnull158     fun `Annotation signatures requiring more complicated token matching`() {
159         val source = """
160                 package test {
161                   public class MyTest {
162                     method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public boolean addAccountExplicitly(android.accounts.Account, String, android.os.Bundle);
163                     method @CheckResult(suggest="#enforceCallingOrSelfPermission(String,\"foo\",String)") public abstract int checkCallingOrSelfPermission(@NonNull String);
164                     method @RequiresPermission(anyOf={"android.permission.MANAGE_ACCOUNTS", "android.permission.USE_CREDENTIALS"}, apis="..22") public void invalidateAuthToken(String, String);
165                   }
166                 }
167                 """
168         check(
169             compatibilityMode = false,
170             outputKotlinStyleNulls = false,
171             signatureSource = source,
172             api = source
173         )
174     }
175 
176     @Test
Multiple extendsnull177     fun `Multiple extends`() {
178         val source = """
179                 package test {
180                   public static interface PickConstructors extends test.pkg.PickConstructors.AutoCloseable {
181                   }
182                   public interface XmlResourceParser extends org.xmlpull.v1.XmlPullParser android.util.AttributeSet java.lang.AutoCloseable {
183                     method public void close();
184                   }
185                 }
186                 """
187         check(
188             compatibilityMode = false,
189             outputKotlinStyleNulls = false,
190             signatureSource = source,
191             api = source
192         )
193     }
194 
195     @Test
Native and strictfp keywordsnull196     fun `Native and strictfp keywords`() {
197         check(
198             compatibilityMode = false,
199             outputKotlinStyleNulls = false,
200             signatureSource = """
201                     package test.pkg {
202                       public class MyTest {
203                         method public native float dotWithNormal(float, float, float);
204                         method public static strictfp double toDegrees(double);
205                       }
206                     }
207                     """,
208             api = """
209                     package test.pkg {
210                       public class MyTest {
211                         method public float dotWithNormal(float, float, float);
212                         method public static double toDegrees(double);
213                       }
214                     }
215                     """
216         )
217     }
218 
219     @Test
Type use annotationsnull220     fun `Type use annotations`() {
221         check(
222             compatibilityMode = false,
223             outputKotlinStyleNulls = false,
224             signatureSource = """
225                 package test.pkg {
226                   public class MyTest {
227                     method public static int codePointAt(char @NonNull [], int);
228                     method @NonNull public java.util.Set<java.util.Map.@NonNull Entry<K,V>> entrySet();
229                     method @NonNull public java.lang.annotation.@NonNull Annotation @NonNull [] getAnnotations();
230                     method @NonNull public abstract java.lang.annotation.@NonNull Annotation @NonNull [] @NonNull [] getParameterAnnotations();
231                     method @NonNull public @NonNull String @NonNull [] split(@NonNull String, int);
232                     method public static char @NonNull [] toChars(int);
233                   }
234                 }
235                 """,
236             api = """
237                 package test.pkg {
238                   public class MyTest {
239                     method public static int codePointAt(char @NonNull [], int);
240                     method @NonNull public java.util.Set<java.util.Map.@NonNull Entry<K,V>> entrySet();
241                     method @NonNull public java.lang.annotation.Annotation @NonNull [] getAnnotations();
242                     method @NonNull public abstract java.lang.annotation.Annotation @NonNull [] @NonNull [] getParameterAnnotations();
243                     method @NonNull public String @NonNull [] split(@NonNull String, int);
244                     method public static char @NonNull [] toChars(int);
245                   }
246                 }
247             """
248         )
249     }
250 
251     @Test
Vararg modifiernull252     fun `Vararg modifier`() {
253         val source = """
254                 package test.pkg {
255                   public final class Foo {
256                     ctor public Foo();
257                     method public void error(int p = "42", Integer int2 = "null", int p1 = "42", vararg String args);
258                   }
259                 }
260                 """
261         check(
262             compatibilityMode = false,
263             outputKotlinStyleNulls = false,
264             signatureSource = source
265         )
266     }
267 
268     @Test
Infer fully qualified names from shorter namesnull269     fun `Infer fully qualified names from shorter names`() {
270         check(
271             compatibilityMode = true,
272             extraArguments = arrayOf("--annotations-in-signatures"),
273             signatureSource = """
274                 package test.pkg {
275                   public class MyTest {
276                     ctor public MyTest();
277                     method public int clamp(int);
278                     method public double convert(@Nullable Float, byte[], Iterable<java.io.File>);
279                   }
280                 }
281                 """,
282             api = """
283                 package test.pkg {
284                   public class MyTest {
285                     ctor public MyTest();
286                     method public int clamp(int);
287                     method public double convert(@androidx.annotation.Nullable java.lang.Float, byte[], java.lang.Iterable<java.io.File>);
288                   }
289                 }
290                 """
291         )
292     }
293 
294     @Test
Loading a signature file with alternate modifier ordernull295     fun `Loading a signature file with alternate modifier order`() {
296         // Regression test for https://github.com/android/android-ktx/issues/242
297         val source = """
298                 package test.pkg {
299                   deprecated public class MyTest {
300                     ctor deprecated public Foo(int, int);
301                     method deprecated public static final void edit(android.content.SharedPreferences, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
302                     field deprecated public static java.util.List<java.lang.String> LIST;
303                   }
304                 }
305                 """
306         check(
307             compatibilityMode = true,
308             signatureSource = source,
309             api = """
310                 package test.pkg {
311                   public deprecated class MyTest {
312                     ctor public deprecated MyTest(int, int);
313                     method public static final deprecated void edit(android.content.SharedPreferences, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit>);
314                     field public static deprecated java.util.List<java.lang.String> LIST;
315                   }
316                 }
317                 """
318         )
319     }
320 
321     @Test
Test generics, superclasses and interfacesnull322     fun `Test generics, superclasses and interfaces`() {
323         val source = """
324             package a.b.c {
325               public abstract interface MyStream<T, S extends a.b.c.MyStream<T, S>> {
326               }
327             }
328             package test.pkg {
329               public final class Foo extends java.lang.Enum {
330                 ctor public Foo(int);
331                 ctor public Foo(int, int);
332                 method public static test.pkg.Foo valueOf(java.lang.String);
333                 method public static final test.pkg.Foo[] values();
334                 enum_constant public static final test.pkg.Foo A;
335                 enum_constant public static final test.pkg.Foo B;
336               }
337               public abstract interface MyBaseInterface {
338               }
339               public abstract interface MyInterface<T> implements test.pkg.MyBaseInterface {
340               }
341               public abstract interface MyInterface2<T extends java.lang.Number> implements test.pkg.MyBaseInterface {
342               }
343               public static abstract class MyInterface2.Range<T extends java.lang.Comparable<? super T>> {
344                 ctor public MyInterface2.Range();
345               }
346               public static class MyInterface2.TtsSpan<C extends test.pkg.MyInterface<?>> {
347                 ctor public MyInterface2.TtsSpan();
348               }
349               public final class Test<T> {
350                 ctor public Test();
351                 method public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T);
352                 method public static <T & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>);
353                 method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
354                 field public static java.util.List<java.lang.String> LIST;
355               }
356             }
357             """
358 
359         check(
360             compatibilityMode = true,
361             signatureSource = source,
362             api = source
363         )
364     }
365 
366     @Test
Test constantsnull367     fun `Test constants`() {
368         val source = """
369                 package test.pkg {
370                   public class Foo2 {
371                     ctor public Foo2();
372                     field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
373                     field public static final char HEX_INPUT = 61184; // 0xef00 '\uef00'
374                     field protected int field00;
375                     field public static final boolean field01 = true;
376                     field public static final int field02 = 42; // 0x2a
377                     field public static final long field03 = 42L; // 0x2aL
378                     field public static final short field04 = 5; // 0x5
379                     field public static final byte field05 = 5; // 0x5
380                     field public static final char field06 = 99; // 0x0063 'c'
381                     field public static final float field07 = 98.5f;
382                     field public static final double field08 = 98.5;
383                     field public static final java.lang.String field09 = "String with \"escapes\" and \u00a9...";
384                     field public static final double field10 = (0.0/0.0);
385                     field public static final double field11 = (1.0/0.0);
386                   }
387                 }
388                 """
389 
390         check(
391             compatibilityMode = true,
392             signatureSource = source,
393             api = source
394         )
395     }
396 
397     @Test
Test inner classesnull398     fun `Test inner classes`() {
399         val source = """
400                 package test.pkg {
401                   public abstract class Foo {
402                     ctor public Foo();
403                     method public static final deprecated synchronized void method1();
404                     method public static final deprecated synchronized void method2();
405                   }
406                   protected static final deprecated class Foo.Inner1 {
407                     ctor protected Foo.Inner1();
408                   }
409                   protected static abstract deprecated class Foo.Inner2 {
410                     ctor protected Foo.Inner2();
411                   }
412                   protected static abstract deprecated interface Foo.Inner3 {
413                     method public default void method3();
414                     method public static abstract void method4(int);
415                   }
416                 }
417                 """
418 
419         check(
420             compatibilityMode = true,
421             signatureSource = source,
422             api = source
423         )
424     }
425 
426     @Test
Test throwsnull427     fun `Test throws`() {
428         val source = """
429                 package test.pkg {
430                   public final class Test<T> {
431                     ctor public Test();
432                     method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
433                   }
434                 }
435                 """
436 
437         check(
438             compatibilityMode = true,
439             signatureSource = source,
440             api = source
441         )
442     }
443 
444     @Test
Loading a signature file with annotations on classes, fields, methods and parametersnull445     fun `Loading a signature file with annotations on classes, fields, methods and parameters`() {
446         @Language("TEXT")
447         val source = """
448                 // Signature format: 3.0
449                 package test.pkg {
450                   @UiThread public class MyTest {
451                     ctor public MyTest();
452                     method @IntRange(from=10, to=20) public int clamp(int);
453                     method public Double? convert(Float myPublicName);
454                     field public Number? myNumber;
455                   }
456                 }
457                 """
458 
459         check(
460             format = FileFormat.V3,
461             signatureSource = source,
462             api = source
463         )
464     }
465 
466     @Test
Enums and annotationsnull467     fun `Enums and annotations`() {
468         // In non-compat mode we write interfaces out as "@interface" (instead of abstract class)
469         // and similarly for enums we write "enum" instead of "class extends java.lang.Enum".
470         // Make sure we can also read this back in.
471         val source = """
472                 package android.annotation {
473                   public @interface SuppressLint {
474                     method public abstract String[] value();
475                   }
476                 }
477                 package test.pkg {
478                   public enum Foo {
479                     enum_constant public static final test.pkg.Foo A;
480                     enum_constant public static final test.pkg.Foo B;
481                   }
482                 }
483                 """
484 
485         check(
486             compatibilityMode = false,
487             outputKotlinStyleNulls = false,
488             signatureSource = source,
489             api = source
490         )
491     }
492 
493     @Test
Annotations on packagesnull494     fun `Annotations on packages`() {
495         val source = """
496                 package @RestrictTo(androidx.annotation.RestrictTo.Scope.SUBCLASSES) @RestrictTo(androidx.annotation.RestrictTo.Scope.SUBCLASSES) test.pkg {
497                   public abstract class Class1 {
498                     ctor public Class1();
499                   }
500                 }
501                 """
502 
503         check(
504             compatibilityMode = false,
505             outputKotlinStyleNulls = false,
506             signatureSource = source,
507             api = source
508         )
509     }
510 
511     @Test
Enums and annotations exported to compatnull512     fun `Enums and annotations exported to compat`() {
513         val source = """
514                 package android.annotation {
515                   public @interface SuppressLint {
516                   }
517                 }
518                 package test.pkg {
519                   public final enum Foo {
520                     enum_constant public static final test.pkg.Foo A;
521                     enum_constant public static final test.pkg.Foo B;
522                   }
523                 }
524                 """
525 
526         check(
527             compatibilityMode = true,
528             signatureSource = source,
529             api = """
530                 package android.annotation {
531                   public abstract class SuppressLint implements java.lang.annotation.Annotation {
532                   }
533                 }
534                 package test.pkg {
535                   public final class Foo extends java.lang.Enum {
536                     enum_constant public static final test.pkg.Foo A;
537                     enum_constant public static final test.pkg.Foo B;
538                   }
539                 }
540                 """
541         )
542     }
543 
544     @Test
Sort throws list by full namenull545     fun `Sort throws list by full name`() {
546         check(
547             compatibilityMode = true,
548             signatureSource = """
549                     package android.accounts {
550                       public abstract interface AccountManagerFuture<V> {
551                         method public abstract boolean cancel(boolean);
552                         method public abstract V getResult() throws android.accounts.OperationCanceledException, java.io.IOException, android.accounts.AuthenticatorException;
553                         method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.OperationCanceledException, java.io.IOException, android.accounts.AuthenticatorException;
554                         method public abstract boolean isCancelled();
555                         method public abstract boolean isDone();
556                       }
557                       public class AuthenticatorException extends java.lang.Throwable {
558                       }
559                       public class OperationCanceledException extends java.lang.Throwable {
560                       }
561                     }
562                     """,
563             api = """
564                     package android.accounts {
565                       public abstract interface AccountManagerFuture<V> {
566                         method public abstract boolean cancel(boolean);
567                         method public abstract V getResult() throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
568                         method public abstract V getResult(long, java.util.concurrent.TimeUnit) throws android.accounts.AuthenticatorException, java.io.IOException, android.accounts.OperationCanceledException;
569                         method public abstract boolean isCancelled();
570                         method public abstract boolean isDone();
571                       }
572                       public class AuthenticatorException extends java.lang.Throwable {
573                       }
574                       public class OperationCanceledException extends java.lang.Throwable {
575                       }
576                     }
577                     """
578         )
579     }
580 
581     @Test
Loading a signature file with default valuesnull582     fun `Loading a signature file with default values`() {
583         @Language("TEXT")
584         val source = """
585                 // Signature format: 3.0
586                 package test.pkg {
587                   public final class Foo {
588                     ctor public Foo();
589                     method public final void error(int p = 42, Integer? int2 = null);
590                   }
591                   public class Foo2 {
592                     ctor public Foo2();
593                     method public void foo(String! = null, String! = "(Hello) World", int = 42);
594                   }
595                 }
596                 """
597 
598         check(
599             format = FileFormat.V3,
600             signatureSource = source,
601             api = source
602         )
603     }
604 
605     @Test
Signatures with default annotation method valuesnull606     fun `Signatures with default annotation method values`() {
607         val source = """
608                 // Signature format: 3.0
609                 package libcore.util {
610                   public @interface NonNull {
611                     method public abstract int from() default java.lang.Integer.MIN_VALUE;
612                     method public abstract double fromWithCast() default (double)java.lang.Float.NEGATIVE_INFINITY;
613                     method public abstract String myString() default "This is a \"string\"";
614                     method public abstract int to() default java.lang.Integer.MAX_VALUE;
615                   }
616                 }
617                 """
618 
619         check(
620             format = FileFormat.V3,
621             signatureSource = source,
622             api = source
623         )
624     }
625 
626     @Test
Signatures with many annotationsnull627     fun `Signatures with many annotations`() {
628         val source = """
629             // Signature format: 2.0
630             package libcore.util {
631               @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public @interface NonNull {
632                 method public abstract int from() default java.lang.Integer.MIN_VALUE;
633                 method public abstract int to() default java.lang.Integer.MAX_VALUE;
634               }
635             }
636             package test.pkg {
637               public class Test {
638                 ctor public Test();
639                 method @NonNull public Object compute();
640               }
641             }
642         """
643 
644         check(
645             format = FileFormat.V2,
646             compatibilityMode = false,
647             signatureSource = source,
648             api = source
649         )
650     }
651 
652     @Test
Kotlin Propertiesnull653     fun `Kotlin Properties`() {
654         val source = """
655                 // Signature format: 2.0
656                 package test.pkg {
657                   public final class Kotlin {
658                     ctor public Kotlin(String property1, int arg2);
659                     method public String getProperty1();
660                     method public String getProperty2();
661                     method public void setProperty2(String p);
662                     property public final String property2;
663                   }
664                 }
665                 """
666 
667         check(
668             format = FileFormat.V2,
669             signatureSource = source,
670             api = source
671         )
672     }
673 
674     @Test
Deprecated enum constantnull675     fun `Deprecated enum constant`() {
676         val source = """
677                 // Signature format: 3.0
678                 package androidx.annotation {
679                   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PACKAGE}) public @interface RestrictTo {
680                     method public abstract androidx.annotation.RestrictTo.Scope[] value();
681                   }
682                   public enum RestrictTo.Scope {
683                     enum_constant @Deprecated public static final androidx.annotation.RestrictTo.Scope GROUP_ID;
684                     enum_constant public static final androidx.annotation.RestrictTo.Scope LIBRARY;
685                     enum_constant public static final androidx.annotation.RestrictTo.Scope LIBRARY_GROUP;
686                     enum_constant public static final androidx.annotation.RestrictTo.Scope SUBCLASSES;
687                     enum_constant public static final androidx.annotation.RestrictTo.Scope TESTS;
688                   }
689                 }
690                 """
691 
692         check(
693             compatibilityMode = false,
694             inputKotlinStyleNulls = true,
695             outputKotlinStyleNulls = true,
696             signatureSource = source,
697             api = source
698         )
699     }
700 
701     @Test
Type parameters in v3 formatnull702     fun `Type parameters in v3 format`() {
703         val source = """
704                 // Signature format: 3.0
705                 package androidx.collection {
706                   public class Constants {
707                     field public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
708                     field public static final char HEX_INPUT = 61184; // 0xef00 '\uef00'
709                     field protected int field00;
710                     field public static final boolean field01 = true;
711                     field public static final int field02 = 42; // 0x2a
712                     field public static final String field09 = "String with \"escapes\" and \u00a9...";
713                   }
714                   public class MyMap<Key, Value> {
715                     method public Key! getReplacement(Key!);
716                   }
717                 }
718                 package androidx.paging {
719                   public abstract class DataSource<Key, Value> {
720                     method @AnyThread public void addInvalidatedCallback(androidx.paging.DataSource.InvalidatedCallback);
721                     method @AnyThread public void invalidate();
722                     method @WorkerThread public boolean isInvalid();
723                     method public abstract <ToValue> androidx.paging.DataSource<Key,ToValue> map(androidx.arch.core.util.Function<Value,ToValue>);
724                     method public abstract <ToValue> androidx.paging.DataSource<Key,ToValue> mapByPage(androidx.arch.core.util.Function<java.util.List<Value>,java.util.List<ToValue>>);
725                     method @AnyThread public void removeInvalidatedCallback(androidx.paging.DataSource.InvalidatedCallback);
726                   }
727                   public abstract class ItemKeyedDataSource<Key, Value> extends androidx.paging.DataSource<Key, Value> {
728                     method public abstract Key getKey(Value);
729                     method public boolean isContiguous();
730                     method public abstract void loadAfter(androidx.paging.ItemKeyedDataSource.LoadParams<Key>, androidx.paging.ItemKeyedDataSource.LoadCallback<Value>);
731                     method public abstract void loadBefore(androidx.paging.ItemKeyedDataSource.LoadParams<Key>, androidx.paging.ItemKeyedDataSource.LoadCallback<Value>);
732                     method public abstract void loadInitial(androidx.paging.ItemKeyedDataSource.LoadInitialParams<Key>, androidx.paging.ItemKeyedDataSource.LoadInitialCallback<Value>);
733                     method public final <ToValue> androidx.paging.ItemKeyedDataSource<Key,ToValue> map(androidx.arch.core.util.Function<Value,ToValue>);
734                     method public final <ToValue> androidx.paging.ItemKeyedDataSource<Key,ToValue> mapByPage(androidx.arch.core.util.Function<java.util.List<Value>,java.util.List<ToValue>>);
735                   }
736                 }
737                 """
738         check(
739             compatibilityMode = false,
740             inputKotlinStyleNulls = true,
741             outputKotlinStyleNulls = true,
742             signatureSource = source,
743             api = source
744         )
745     }
746 
747     @Test
Signatures with reified in type parametersnull748     fun `Signatures with reified in type parameters`() {
749         val source = """
750                 package test.pkg {
751                   public final class TestKt {
752                     ctor public TestKt();
753                     method public static inline <T> void a(T);
754                     method public static inline <reified T> void b(T);
755                     method public static inline <reified T> void e(T);
756                     method public static inline <reified T> void f(T, T);
757                   }
758                 }
759                 """
760 
761         check(
762             compatibilityMode = true,
763             signatureSource = source,
764             api = source
765         )
766     }
767 
768     @Test
Suspended methodsnull769     fun `Suspended methods`() {
770         val source = """
771                 package test.pkg {
772                   public final class TestKt {
773                     ctor public TestKt();
774                     method public static suspend inline java.lang.Object hello(kotlin.coroutines.experimental.Continuation<? super kotlin.Unit>);
775                   }
776                 }
777                 """
778 
779         check(
780             compatibilityMode = true,
781             signatureSource = source,
782             api = source
783         )
784     }
785 
786     @Test
Complicated annotationsnull787     fun `Complicated annotations`() {
788         val source = """
789                 package android.app {
790                   public static class ActionBar {
791                     field @android.view.ViewDebug.ExportedProperty(category="layout", mapping={@android.view.ViewDebug.IntToString(from=0xffffffff, to="NONE"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.NO_GRAVITY, to="NONE"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.TOP, to="TOP"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.BOTTOM, to="BOTTOM"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.LEFT, to="LEFT"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.RIGHT, to="RIGHT"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.START, to="START"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.END, to="END"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.CENTER_VERTICAL, to="CENTER_VERTICAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.FILL_VERTICAL, to="FILL_VERTICAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.CENTER_HORIZONTAL, to="CENTER_HORIZONTAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.FILL_HORIZONTAL, to="FILL_HORIZONTAL"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.CENTER, to="CENTER"), @android.view.ViewDebug.IntToString(from=android.view.Gravity.FILL, to="FILL")}) public int gravity;
792                   }
793                 }
794                 """
795 
796         val expectedApi = """
797                 package android.app {
798                   public static class ActionBar {
799                     field public int gravity;
800                   }
801                 }
802                 """
803 
804         check(
805             compatibilityMode = false,
806             signatureSource = source,
807             api = expectedApi
808         )
809     }
810 }