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