1 /* <lambda>null2 * Copyright (C) 2021 Square, Inc. 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 * https://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 package com.squareup.moshi.kotlin.codegen.ksp 17 18 import com.google.common.truth.Truth.assertThat 19 import com.squareup.moshi.kotlin.codegen.api.Options.OPTION_GENERATED 20 import com.squareup.moshi.kotlin.codegen.api.Options.OPTION_GENERATE_PROGUARD_RULES 21 import com.tschuchort.compiletesting.KotlinCompilation 22 import com.tschuchort.compiletesting.SourceFile 23 import com.tschuchort.compiletesting.SourceFile.Companion.java 24 import com.tschuchort.compiletesting.SourceFile.Companion.kotlin 25 import com.tschuchort.compiletesting.kspArgs 26 import com.tschuchort.compiletesting.kspIncremental 27 import com.tschuchort.compiletesting.kspSourcesDir 28 import com.tschuchort.compiletesting.symbolProcessorProviders 29 import org.junit.Ignore 30 import org.junit.Rule 31 import org.junit.Test 32 import org.junit.rules.TemporaryFolder 33 34 /** Execute kotlinc to confirm that either files are generated or errors are printed. */ 35 class JsonClassSymbolProcessorTest { 36 37 @Rule @JvmField var temporaryFolder: TemporaryFolder = TemporaryFolder() 38 39 @Test 40 fun privateConstructor() { 41 val result = compile( 42 kotlin( 43 "source.kt", 44 """ 45 package test 46 import com.squareup.moshi.JsonClass 47 48 @JsonClass(generateAdapter = true) 49 class PrivateConstructor private constructor(var a: Int, var b: Int) { 50 fun a() = a 51 fun b() = b 52 companion object { 53 fun newInstance(a: Int, b: Int) = PrivateConstructor(a, b) 54 } 55 } 56 """ 57 ) 58 ) 59 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 60 assertThat(result.messages).contains("constructor is not internal or public") 61 } 62 63 @Test 64 fun privateConstructorParameter() { 65 val result = compile( 66 kotlin( 67 "source.kt", 68 """ 69 package test 70 import com.squareup.moshi.JsonClass 71 72 @JsonClass(generateAdapter = true) 73 class PrivateConstructorParameter(private var a: Int) 74 """ 75 ) 76 ) 77 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 78 assertThat(result.messages).contains("property a is not visible") 79 } 80 81 @Test 82 fun privateProperties() { 83 val result = compile( 84 kotlin( 85 "source.kt", 86 """ 87 package test 88 import com.squareup.moshi.JsonClass 89 90 @JsonClass(generateAdapter = true) 91 class PrivateProperties { 92 private var a: Int = -1 93 private var b: Int = -1 94 } 95 """ 96 ) 97 ) 98 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 99 assertThat(result.messages).contains("property a is not visible") 100 } 101 102 @Test 103 fun interfacesNotSupported() { 104 val result = compile( 105 kotlin( 106 "source.kt", 107 """ 108 package test 109 import com.squareup.moshi.JsonClass 110 111 @JsonClass(generateAdapter = true) 112 interface Interface 113 """ 114 ) 115 ) 116 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 117 assertThat(result.messages).contains( 118 "@JsonClass can't be applied to test.Interface: must be a Kotlin class" 119 ) 120 } 121 122 @Test 123 fun interfacesDoNotErrorWhenGeneratorNotSet() { 124 val result = compile( 125 kotlin( 126 "source.kt", 127 """ 128 package test 129 import com.squareup.moshi.JsonClass 130 131 @JsonClass(generateAdapter = true, generator="customGenerator") 132 interface Interface 133 """ 134 ) 135 ) 136 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK) 137 } 138 139 @Test 140 fun abstractClassesNotSupported() { 141 val result = compile( 142 kotlin( 143 "source.kt", 144 """ 145 package test 146 import com.squareup.moshi.JsonClass 147 148 @JsonClass(generateAdapter = true) 149 abstract class AbstractClass(val a: Int) 150 """ 151 ) 152 ) 153 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 154 assertThat(result.messages).contains( 155 "@JsonClass can't be applied to test.AbstractClass: must not be abstract" 156 ) 157 } 158 159 @Test 160 fun sealedClassesNotSupported() { 161 val result = compile( 162 kotlin( 163 "source.kt", 164 """ 165 package test 166 import com.squareup.moshi.JsonClass 167 168 @JsonClass(generateAdapter = true) 169 sealed class SealedClass(val a: Int) 170 """ 171 ) 172 ) 173 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 174 assertThat(result.messages).contains( 175 "@JsonClass can't be applied to test.SealedClass: must not be sealed" 176 ) 177 } 178 179 @Test 180 fun innerClassesNotSupported() { 181 val result = compile( 182 kotlin( 183 "source.kt", 184 """ 185 package test 186 import com.squareup.moshi.JsonClass 187 188 class Outer { 189 @JsonClass(generateAdapter = true) 190 inner class InnerClass(val a: Int) 191 } 192 """ 193 ) 194 ) 195 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 196 assertThat(result.messages).contains( 197 "@JsonClass can't be applied to test.Outer.InnerClass: must not be an inner class" 198 ) 199 } 200 201 @Test 202 fun enumClassesNotSupported() { 203 val result = compile( 204 kotlin( 205 "source.kt", 206 """ 207 package test 208 import com.squareup.moshi.JsonClass 209 210 @JsonClass(generateAdapter = true) 211 enum class KotlinEnum { 212 A, B 213 } 214 """ 215 ) 216 ) 217 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 218 assertThat(result.messages).contains( 219 "@JsonClass with 'generateAdapter = \"true\"' can't be applied to test.KotlinEnum: code gen for enums is not supported or necessary" 220 ) 221 } 222 223 // Annotation processors don't get called for local classes, so we don't have the opportunity to 224 @Ignore 225 @Test 226 fun localClassesNotSupported() { 227 val result = compile( 228 kotlin( 229 "source.kt", 230 """ 231 package test 232 import com.squareup.moshi.JsonClass 233 234 fun outer() { 235 @JsonClass(generateAdapter = true) 236 class LocalClass(val a: Int) 237 } 238 """ 239 ) 240 ) 241 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 242 assertThat(result.messages).contains( 243 "@JsonClass can't be applied to LocalClass: must not be local" 244 ) 245 } 246 247 @Test 248 fun privateClassesNotSupported() { 249 val result = compile( 250 kotlin( 251 "source.kt", 252 """ 253 package test 254 import com.squareup.moshi.JsonClass 255 256 @JsonClass(generateAdapter = true) 257 private class PrivateClass(val a: Int) 258 """ 259 ) 260 ) 261 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 262 assertThat(result.messages).contains( 263 "@JsonClass can't be applied to test.PrivateClass: must be internal or public" 264 ) 265 } 266 267 @Test 268 fun objectDeclarationsNotSupported() { 269 val result = compile( 270 kotlin( 271 "source.kt", 272 """ 273 package test 274 import com.squareup.moshi.JsonClass 275 276 @JsonClass(generateAdapter = true) 277 object ObjectDeclaration { 278 var a = 5 279 } 280 """ 281 ) 282 ) 283 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 284 assertThat(result.messages).contains( 285 "@JsonClass can't be applied to test.ObjectDeclaration: must be a Kotlin class" 286 ) 287 } 288 289 @Test 290 fun objectExpressionsNotSupported() { 291 val result = compile( 292 kotlin( 293 "source.kt", 294 """ 295 package test 296 import com.squareup.moshi.JsonClass 297 298 @JsonClass(generateAdapter = true) 299 val expression = object : Any() { 300 var a = 5 301 } 302 """ 303 ) 304 ) 305 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 306 assertThat(result.messages).contains( 307 "@JsonClass can't be applied to test.expression: must be a Kotlin class" 308 ) 309 } 310 311 @Test 312 fun requiredTransientConstructorParameterFails() { 313 val result = compile( 314 kotlin( 315 "source.kt", 316 """ 317 package test 318 import com.squareup.moshi.JsonClass 319 320 @JsonClass(generateAdapter = true) 321 class RequiredTransientConstructorParameter(@Transient var a: Int) 322 """ 323 ) 324 ) 325 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 326 assertThat(result.messages).contains( 327 "No default value for transient/ignored property a" 328 ) 329 } 330 331 @Test 332 fun requiredIgnoredConstructorParameterFails() { 333 val result = compile( 334 kotlin( 335 "source.kt", 336 """ 337 package test 338 import com.squareup.moshi.Json 339 import com.squareup.moshi.JsonClass 340 341 @JsonClass(generateAdapter = true) 342 class RequiredTransientConstructorParameter(@Json(ignore = true) var a: Int) 343 """ 344 ) 345 ) 346 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 347 assertThat(result.messages).contains( 348 "No default value for transient/ignored property a" 349 ) 350 } 351 352 @Test 353 fun nonPropertyConstructorParameter() { 354 val result = compile( 355 kotlin( 356 "source.kt", 357 """ 358 package test 359 import com.squareup.moshi.JsonClass 360 361 @JsonClass(generateAdapter = true) 362 class NonPropertyConstructorParameter(a: Int, val b: Int) 363 """ 364 ) 365 ) 366 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 367 assertThat(result.messages).contains( 368 "No property for required constructor parameter a" 369 ) 370 } 371 372 @Test 373 fun badGeneratedAnnotation() { 374 val result = prepareCompilation( 375 kotlin( 376 "source.kt", 377 """ 378 package test 379 import com.squareup.moshi.JsonClass 380 381 @JsonClass(generateAdapter = true) 382 data class Foo(val a: Int) 383 """ 384 ) 385 ).apply { 386 kspArgs[OPTION_GENERATED] = "javax.annotation.GeneratedBlerg" 387 }.compile() 388 assertThat(result.messages).contains( 389 "Invalid option value for $OPTION_GENERATED" 390 ) 391 } 392 393 @Test 394 fun disableProguardGeneration() { 395 val compilation = prepareCompilation( 396 kotlin( 397 "source.kt", 398 """ 399 package test 400 import com.squareup.moshi.JsonClass 401 402 @JsonClass(generateAdapter = true) 403 data class Foo(val a: Int) 404 """ 405 ) 406 ).apply { 407 kspArgs[OPTION_GENERATE_PROGUARD_RULES] = "false" 408 } 409 val result = compilation.compile() 410 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK) 411 assertThat(compilation.kspSourcesDir.walkTopDown().filter { it.extension == "pro" }.toList()).isEmpty() 412 } 413 414 @Test 415 fun multipleErrors() { 416 val result = compile( 417 kotlin( 418 "source.kt", 419 """ 420 package test 421 import com.squareup.moshi.JsonClass 422 423 @JsonClass(generateAdapter = true) 424 class Class1(private var a: Int, private var b: Int) 425 426 @JsonClass(generateAdapter = true) 427 class Class2(private var c: Int) 428 """ 429 ) 430 ) 431 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 432 assertThat(result.messages).contains("property a is not visible") 433 assertThat(result.messages).contains("property c is not visible") 434 } 435 436 @Test 437 fun extendPlatformType() { 438 val result = compile( 439 kotlin( 440 "source.kt", 441 """ 442 package test 443 import com.squareup.moshi.JsonClass 444 import java.util.Date 445 446 @JsonClass(generateAdapter = true) 447 class ExtendsPlatformClass(var a: Int) : Date() 448 """ 449 ) 450 ) 451 assertThat(result.messages).contains("supertype java.util.Date is not a Kotlin type") 452 } 453 454 @Test 455 fun extendJavaType() { 456 val result = compile( 457 kotlin( 458 "source.kt", 459 """ 460 package test 461 import com.squareup.moshi.JsonClass 462 import com.squareup.moshi.kotlin.codegen.JavaSuperclass 463 464 @JsonClass(generateAdapter = true) 465 class ExtendsJavaType(var b: Int) : JavaSuperclass() 466 """ 467 ), 468 java( 469 "JavaSuperclass.java", 470 """ 471 package com.squareup.moshi.kotlin.codegen; 472 public class JavaSuperclass { 473 public int a = 1; 474 } 475 """ 476 ) 477 ) 478 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 479 assertThat(result.messages) 480 .contains("supertype com.squareup.moshi.kotlin.codegen.JavaSuperclass is not a Kotlin type") 481 } 482 483 @Test 484 fun nonFieldApplicableQualifier() { 485 val result = compile( 486 kotlin( 487 "source.kt", 488 """ 489 package test 490 import com.squareup.moshi.JsonClass 491 import com.squareup.moshi.JsonQualifier 492 import kotlin.annotation.AnnotationRetention.RUNTIME 493 import kotlin.annotation.AnnotationTarget.PROPERTY 494 import kotlin.annotation.Retention 495 import kotlin.annotation.Target 496 497 @Retention(RUNTIME) 498 @Target(PROPERTY) 499 @JsonQualifier 500 annotation class UpperCase 501 502 @JsonClass(generateAdapter = true) 503 class ClassWithQualifier(@UpperCase val a: Int) 504 """ 505 ) 506 ) 507 // We instantiate directly, no FIELD site target necessary 508 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK) 509 } 510 511 @Test 512 fun nonRuntimeQualifier() { 513 val result = compile( 514 kotlin( 515 "source.kt", 516 """ 517 package test 518 import com.squareup.moshi.JsonClass 519 import com.squareup.moshi.JsonQualifier 520 import kotlin.annotation.AnnotationRetention.BINARY 521 import kotlin.annotation.AnnotationTarget.FIELD 522 import kotlin.annotation.AnnotationTarget.PROPERTY 523 import kotlin.annotation.Retention 524 import kotlin.annotation.Target 525 526 @Retention(BINARY) 527 @Target(PROPERTY, FIELD) 528 @JsonQualifier 529 annotation class UpperCase 530 531 @JsonClass(generateAdapter = true) 532 class ClassWithQualifier(@UpperCase val a: Int) 533 """ 534 ) 535 ) 536 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 537 assertThat(result.messages).contains("JsonQualifier @UpperCase must have RUNTIME retention") 538 } 539 540 @Test 541 fun invalidGenericSyntaxErrorMessaging() { 542 val result = compile( 543 kotlin( 544 "source.kt", 545 """ 546 package test 547 import com.squareup.moshi.JsonClass 548 549 @JsonClass(generateAdapter = true) 550 data class ElementEnvelope(val elements: List) 551 """, 552 ), 553 ) 554 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.COMPILATION_ERROR) 555 assertThat(result.messages).contains("Error preparing ElementEnvelope") 556 } 557 558 @Test 559 fun `TypeAliases with the same backing type should share the same adapter`() { 560 val result = compile( 561 kotlin( 562 "source.kt", 563 """ 564 package test 565 import com.squareup.moshi.JsonClass 566 567 typealias FirstName = String 568 typealias LastName = String 569 570 @JsonClass(generateAdapter = true) 571 data class Person(val firstName: FirstName, val lastName: LastName, val hairColor: String) 572 """ 573 ) 574 ) 575 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK) 576 577 // We're checking here that we only generate one `stringAdapter` that's used for both the 578 // regular string properties as well as the the aliased ones. 579 // TODO loading compiled classes from results not supported in KSP yet 580 // val adapterClass = result.classLoader.loadClass("PersonJsonAdapter").kotlin 581 // assertThat(adapterClass.declaredMemberProperties.map { it.returnType }).containsExactly( 582 // JsonReader.Options::class.createType(), 583 // JsonAdapter::class.parameterizedBy(String::class) 584 // ) 585 } 586 587 @Test 588 fun `Processor should generate comprehensive proguard rules`() { 589 val compilation = prepareCompilation( 590 kotlin( 591 "source.kt", 592 """ 593 package testPackage 594 import com.squareup.moshi.JsonClass 595 import com.squareup.moshi.JsonQualifier 596 597 typealias FirstName = String 598 typealias LastName = String 599 600 @JsonClass(generateAdapter = true) 601 data class Aliases(val firstName: FirstName, val lastName: LastName, val hairColor: String) 602 603 @JsonClass(generateAdapter = true) 604 data class Simple(val firstName: String) 605 606 @JsonClass(generateAdapter = true) 607 data class Generic<T>(val firstName: T, val lastName: String) 608 609 @JsonQualifier 610 annotation class MyQualifier 611 612 @JsonClass(generateAdapter = true) 613 data class UsingQualifiers(val firstName: String, @MyQualifier val lastName: String) 614 615 @JsonClass(generateAdapter = true) 616 data class MixedTypes(val firstName: String, val otherNames: MutableList<String>) 617 618 @JsonClass(generateAdapter = true) 619 data class DefaultParams(val firstName: String = "") 620 621 @JsonClass(generateAdapter = true) 622 data class Complex<T>(val firstName: FirstName = "", @MyQualifier val names: MutableList<String>, val genericProp: T) 623 624 object NestedType { 625 @JsonQualifier 626 annotation class NestedQualifier 627 628 @JsonClass(generateAdapter = true) 629 data class NestedSimple(@NestedQualifier val firstName: String) 630 } 631 632 @JsonClass(generateAdapter = true) 633 class MultipleMasks( 634 val arg0: Long = 0, 635 val arg1: Long = 1, 636 val arg2: Long = 2, 637 val arg3: Long = 3, 638 val arg4: Long = 4, 639 val arg5: Long = 5, 640 val arg6: Long = 6, 641 val arg7: Long = 7, 642 val arg8: Long = 8, 643 val arg9: Long = 9, 644 val arg10: Long = 10, 645 val arg11: Long, 646 val arg12: Long = 12, 647 val arg13: Long = 13, 648 val arg14: Long = 14, 649 val arg15: Long = 15, 650 val arg16: Long = 16, 651 val arg17: Long = 17, 652 val arg18: Long = 18, 653 val arg19: Long = 19, 654 @Suppress("UNUSED_PARAMETER") arg20: Long = 20, 655 val arg21: Long = 21, 656 val arg22: Long = 22, 657 val arg23: Long = 23, 658 val arg24: Long = 24, 659 val arg25: Long = 25, 660 val arg26: Long = 26, 661 val arg27: Long = 27, 662 val arg28: Long = 28, 663 val arg29: Long = 29, 664 val arg30: Long = 30, 665 val arg31: Long = 31, 666 val arg32: Long = 32, 667 val arg33: Long = 33, 668 val arg34: Long = 34, 669 val arg35: Long = 35, 670 val arg36: Long = 36, 671 val arg37: Long = 37, 672 val arg38: Long = 38, 673 @Transient val arg39: Long = 39, 674 val arg40: Long = 40, 675 val arg41: Long = 41, 676 val arg42: Long = 42, 677 val arg43: Long = 43, 678 val arg44: Long = 44, 679 val arg45: Long = 45, 680 val arg46: Long = 46, 681 val arg47: Long = 47, 682 val arg48: Long = 48, 683 val arg49: Long = 49, 684 val arg50: Long = 50, 685 val arg51: Long = 51, 686 val arg52: Long = 52, 687 @Transient val arg53: Long = 53, 688 val arg54: Long = 54, 689 val arg55: Long = 55, 690 val arg56: Long = 56, 691 val arg57: Long = 57, 692 val arg58: Long = 58, 693 val arg59: Long = 59, 694 val arg60: Long = 60, 695 val arg61: Long = 61, 696 val arg62: Long = 62, 697 val arg63: Long = 63, 698 val arg64: Long = 64, 699 val arg65: Long = 65 700 ) 701 """ 702 ) 703 ) 704 val result = compilation.compile() 705 assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK) 706 707 compilation.kspSourcesDir.walkTopDown().filter { it.extension == "pro" }.forEach { generatedFile -> 708 when (generatedFile.nameWithoutExtension) { 709 "moshi-testPackage.Aliases" -> assertThat(generatedFile.readText()).contains( 710 """ 711 -if class testPackage.Aliases 712 -keepnames class testPackage.Aliases 713 -if class testPackage.Aliases 714 -keep class testPackage.AliasesJsonAdapter { 715 public <init>(com.squareup.moshi.Moshi); 716 } 717 """.trimIndent() 718 ) 719 "moshi-testPackage.Simple" -> assertThat(generatedFile.readText()).contains( 720 """ 721 -if class testPackage.Simple 722 -keepnames class testPackage.Simple 723 -if class testPackage.Simple 724 -keep class testPackage.SimpleJsonAdapter { 725 public <init>(com.squareup.moshi.Moshi); 726 } 727 """.trimIndent() 728 ) 729 "moshi-testPackage.Generic" -> assertThat(generatedFile.readText()).contains( 730 """ 731 -if class testPackage.Generic 732 -keepnames class testPackage.Generic 733 -if class testPackage.Generic 734 -keep class testPackage.GenericJsonAdapter { 735 public <init>(com.squareup.moshi.Moshi,java.lang.reflect.Type[]); 736 } 737 """.trimIndent() 738 ) 739 "moshi-testPackage.UsingQualifiers" -> { 740 assertThat(generatedFile.readText()).contains( 741 """ 742 -if class testPackage.UsingQualifiers 743 -keepnames class testPackage.UsingQualifiers 744 -if class testPackage.UsingQualifiers 745 -keep class testPackage.UsingQualifiersJsonAdapter { 746 public <init>(com.squareup.moshi.Moshi); 747 } 748 """.trimIndent() 749 ) 750 } 751 "moshi-testPackage.MixedTypes" -> assertThat(generatedFile.readText()).contains( 752 """ 753 -if class testPackage.MixedTypes 754 -keepnames class testPackage.MixedTypes 755 -if class testPackage.MixedTypes 756 -keep class testPackage.MixedTypesJsonAdapter { 757 public <init>(com.squareup.moshi.Moshi); 758 } 759 """.trimIndent() 760 ) 761 "moshi-testPackage.DefaultParams" -> assertThat(generatedFile.readText()).contains( 762 """ 763 -if class testPackage.DefaultParams 764 -keepnames class testPackage.DefaultParams 765 -if class testPackage.DefaultParams 766 -keep class testPackage.DefaultParamsJsonAdapter { 767 public <init>(com.squareup.moshi.Moshi); 768 } 769 -if class testPackage.DefaultParams 770 -keepnames class kotlin.jvm.internal.DefaultConstructorMarker 771 -if class testPackage.DefaultParams 772 -keepclassmembers class testPackage.DefaultParams { 773 public synthetic <init>(java.lang.String,int,kotlin.jvm.internal.DefaultConstructorMarker); 774 } 775 """.trimIndent() 776 ) 777 "moshi-testPackage.Complex" -> { 778 assertThat(generatedFile.readText()).contains( 779 """ 780 -if class testPackage.Complex 781 -keepnames class testPackage.Complex 782 -if class testPackage.Complex 783 -keep class testPackage.ComplexJsonAdapter { 784 public <init>(com.squareup.moshi.Moshi,java.lang.reflect.Type[]); 785 } 786 -if class testPackage.Complex 787 -keepnames class kotlin.jvm.internal.DefaultConstructorMarker 788 -if class testPackage.Complex 789 -keepclassmembers class testPackage.Complex { 790 public synthetic <init>(java.lang.String,java.util.List,java.lang.Object,int,kotlin.jvm.internal.DefaultConstructorMarker); 791 } 792 """.trimIndent() 793 ) 794 } 795 "moshi-testPackage.MultipleMasks" -> assertThat(generatedFile.readText()).contains( 796 """ 797 -if class testPackage.MultipleMasks 798 -keepnames class testPackage.MultipleMasks 799 -if class testPackage.MultipleMasks 800 -keep class testPackage.MultipleMasksJsonAdapter { 801 public <init>(com.squareup.moshi.Moshi); 802 } 803 -if class testPackage.MultipleMasks 804 -keepnames class kotlin.jvm.internal.DefaultConstructorMarker 805 -if class testPackage.MultipleMasks 806 -keepclassmembers class testPackage.MultipleMasks { 807 public synthetic <init>(long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,long,int,int,int,kotlin.jvm.internal.DefaultConstructorMarker); 808 } 809 """.trimIndent() 810 ) 811 "moshi-testPackage.NestedType.NestedSimple" -> { 812 assertThat(generatedFile.readText()).contains( 813 """ 814 -if class testPackage.NestedType${'$'}NestedSimple 815 -keepnames class testPackage.NestedType${'$'}NestedSimple 816 -if class testPackage.NestedType${'$'}NestedSimple 817 -keep class testPackage.NestedType_NestedSimpleJsonAdapter { 818 public <init>(com.squareup.moshi.Moshi); 819 } 820 """.trimIndent() 821 ) 822 } 823 else -> error("Unexpected proguard file! ${generatedFile.name}") 824 } 825 } 826 } 827 828 private fun prepareCompilation(vararg sourceFiles: SourceFile): KotlinCompilation { 829 return KotlinCompilation() 830 .apply { 831 workingDir = temporaryFolder.root 832 inheritClassPath = true 833 symbolProcessorProviders = listOf(JsonClassSymbolProcessorProvider()) 834 sources = sourceFiles.asList() 835 verbose = false 836 kspIncremental = true // The default now 837 } 838 } 839 840 private fun compile(vararg sourceFiles: SourceFile): KotlinCompilation.Result { 841 return prepareCompilation(*sourceFiles).compile() 842 } 843 } 844