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