1 /* 2 * Copyright (C) 2022 The Dagger Authors. 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 dagger.functional.kotlinsrc.builder 18 19 import com.google.common.truth.Truth.assertThat 20 import dagger.Component 21 import dagger.Module 22 import dagger.Provides 23 import dagger.Subcomponent 24 import java.lang.annotation.Retention 25 import java.lang.annotation.RetentionPolicy 26 import javax.inject.Inject 27 import javax.inject.Provider 28 import javax.inject.Scope 29 import javax.inject.Singleton 30 import org.junit.Assert.fail 31 import org.junit.Test 32 import org.junit.runner.RunWith 33 import org.junit.runners.JUnit4 34 35 @RunWith(JUnit4::class) 36 class BuilderTest { 37 @Subcomponent( 38 modules = 39 [ 40 StringModule::class, 41 IntModuleIncludingDoubleAndFloat::class, 42 LongModule::class, 43 ByteModule::class 44 ] 45 ) 46 internal interface TestChildComponentWithBuilderAbstractClass { snull47 fun s(): String 48 fun i(): Int 49 fun l(): Long 50 fun f(): Float 51 fun d(): Double 52 fun b(): Byte 53 abstract class SharedBuilder<B, C, M1, M2> { 54 abstract fun build(): C // Test resolving return type of build() 55 abstract fun setM1(m1: M1): B // Test resolving return type & param of setter 56 abstract fun setM2(m2: M2): SharedBuilder<B, C, M1, M2> // Test being overridden 57 abstract fun setM3(doubleModule: DoubleModule) // Test being overridden 58 abstract fun set( 59 floatModule: FloatModule 60 ): SharedBuilder<B, C, M1, M2> // Test returning supertype. 61 } 62 63 @Subcomponent.Builder 64 abstract class Builder : 65 TestChildComponentWithBuilderAbstractClass.SharedBuilder< 66 Builder, 67 TestChildComponentWithBuilderAbstractClass, 68 StringModule, 69 IntModuleIncludingDoubleAndFloat 70 >() { setM2null71 abstract override fun setM2(m2: IntModuleIncludingDoubleAndFloat): Builder // Test covariance 72 abstract override fun setM3(doubleModule: DoubleModule) // Test simple overrides allowed 73 abstract fun set(byteModule: ByteModule) // Note we're missing LongModule -- it's implicit 74 } 75 } 76 77 @Subcomponent( 78 modules = 79 [ 80 StringModule::class, 81 IntModuleIncludingDoubleAndFloat::class, 82 LongModule::class, 83 ByteModule::class 84 ] 85 ) 86 internal interface TestChildComponentWithBuilderInterface { 87 fun s(): String 88 fun i(): Int 89 fun l(): Long 90 fun f(): Float 91 fun d(): Double 92 fun b(): Byte 93 interface SharedBuilder<B, C, M1, M2> { 94 fun build(): C // Test resolving return type of build() 95 fun setM1(m1: M1): B // Test resolving return type & param of setter 96 fun setM2(m2: M2): SharedBuilder<B, C, M1, M2> // Test being overridden 97 fun setM3(doubleModule: DoubleModule) // Test being overridden 98 fun set( 99 floatModule: FloatModule 100 ): SharedBuilder<B, C, M1, M2> // Test return type is supertype. 101 } 102 103 @Subcomponent.Builder 104 interface Builder : 105 TestChildComponentWithBuilderInterface.SharedBuilder< 106 Builder, 107 TestChildComponentWithBuilderInterface, 108 StringModule, 109 IntModuleIncludingDoubleAndFloat 110 > { 111 override fun setM2(m2: IntModuleIncludingDoubleAndFloat): Builder // Test covariant overrides 112 override fun setM3(doubleModule: DoubleModule) // Test simple overrides allowed 113 fun set(byteModule: ByteModule) // Note we're missing LongModule -- it's implicit 114 } 115 } 116 117 @Component( 118 modules = [StringModule::class, IntModuleIncludingDoubleAndFloat::class, LongModule::class], 119 dependencies = [DepComponent::class] 120 ) 121 internal abstract class TestComponentWithBuilderAbstractClass { snull122 abstract fun s(): String 123 abstract fun i(): Int 124 abstract fun l(): Long 125 abstract fun f(): Float 126 abstract fun d(): Double 127 internal abstract class SharedBuilder { 128 // Make sure we use the overriding signature. 129 abstract fun build(): Any 130 open fun stringModule(stringModule: StringModule): Any? = null 131 @Suppress("UNUSED_PARAMETER") 132 fun ignoredLongModule(longModule: LongModule): SharedBuilder? = null 133 } 134 135 @Component.Builder 136 internal abstract class Builder : TestComponentWithBuilderAbstractClass.SharedBuilder() { buildnull137 abstract override fun build(): TestComponentWithBuilderAbstractClass // Narrowing return type 138 abstract override fun stringModule(stringModule: StringModule): Builder // Abstract & narrow 139 abstract fun intModule(intModule: IntModuleIncludingDoubleAndFloat): Builder 140 abstract fun doubleModule(doubleModule: DoubleModule) // Module w/o args 141 abstract fun depComponent(depComponent: DepComponent) 142 // Note we're missing LongModule & FloatModule -- they/re implicit 143 @Suppress("UNUSED_PARAMETER") 144 fun ignoredIntModule(intModule: IntModuleIncludingDoubleAndFloat): Builder? = null 145 } 146 147 companion object { 148 fun builder(): Builder = DaggerBuilderTest_TestComponentWithBuilderAbstractClass.builder() 149 } 150 } 151 152 @Component( 153 modules = [StringModule::class, IntModuleIncludingDoubleAndFloat::class, LongModule::class], 154 dependencies = [DepComponent::class] 155 ) 156 internal interface TestComponentWithBuilderInterface { snull157 fun s(): String 158 fun i(): Int 159 fun l(): Long 160 fun f(): Float 161 fun d(): Double 162 interface SharedBuilder { 163 // Make sure we use the overriding signature. 164 fun build(): Any 165 fun stringModule(m1: StringModule): Any 166 } 167 168 @Component.Builder 169 interface Builder : TestComponentWithBuilderInterface.SharedBuilder { buildnull170 override fun build(): TestComponentWithBuilderInterface // Narrowing return type 171 override fun stringModule(m1: StringModule): Builder // Narrowing return type 172 fun intModule(intModule: IntModuleIncludingDoubleAndFloat): Builder 173 fun doubleModule(doubleModule: DoubleModule) // Module w/o args 174 fun depComponent( 175 depComponent: DepComponent 176 ) // Note we're missing LongModule & FloatModule -- they/re implicit 177 } 178 } 179 180 @Component( 181 modules = [StringModule::class, IntModuleIncludingDoubleAndFloat::class, LongModule::class], 182 dependencies = [DepComponent::class] 183 ) 184 internal interface TestComponentWithGenericBuilderAbstractClass { 185 fun s(): String 186 fun i(): Int 187 fun l(): Long 188 fun f(): Float 189 fun d(): Double 190 abstract class SharedBuilder<B, C, M1, M2> { 191 abstract fun build(): C // Test resolving return type of build() 192 abstract fun setM1(m1: M1): B // Test resolving return type & param of setter 193 abstract fun setM2(m2: M2): SharedBuilder<B, C, M1, M2> // Test being overridden 194 abstract fun doubleModule(doubleModule: DoubleModule) // Test being overridden 195 abstract fun depComponent( 196 floatModule: FloatModule 197 ): SharedBuilder<B, C, M1, M2> // Test return type 198 } 199 200 @Component.Builder 201 abstract class Builder : 202 TestComponentWithGenericBuilderAbstractClass.SharedBuilder< 203 Builder, 204 TestComponentWithGenericBuilderAbstractClass, 205 StringModule, 206 IntModuleIncludingDoubleAndFloat 207 >() { 208 abstract override fun setM2( 209 m2: IntModuleIncludingDoubleAndFloat 210 ): Builder // Test covariant overrides 211 abstract override fun doubleModule( 212 doubleModule: DoubleModule 213 ) // Test simple overrides allowed 214 abstract fun depComponent( 215 depComponent: DepComponent 216 ) // Note we're missing LongModule & FloatModule -- they're implicit 217 } 218 } 219 220 @Component( 221 modules = [StringModule::class, IntModuleIncludingDoubleAndFloat::class, LongModule::class], 222 dependencies = [DepComponent::class] 223 ) 224 internal interface TestComponentWithGenericBuilderInterface { snull225 fun s(): String 226 fun i(): Int 227 fun l(): Long 228 fun f(): Float 229 fun d(): Double 230 interface SharedBuilder<B, C, M1, M2> { 231 fun build(): C // Test resolving return type of build() 232 fun setM1(m1: M1): B // Test resolving return type & param of setter 233 fun setM2(m2: M2): SharedBuilder<B, C, M1, M2> // Test being overridden 234 fun doubleModule(doubleModule: DoubleModule) // Test being overridden 235 fun set( 236 floatModule: FloatModule 237 ): SharedBuilder<B, C, M1, M2> // Test return type is supertype. 238 } 239 240 @Component.Builder 241 interface Builder : 242 TestComponentWithGenericBuilderInterface.SharedBuilder< 243 Builder, 244 TestComponentWithGenericBuilderInterface, 245 StringModule, 246 IntModuleIncludingDoubleAndFloat 247 > { setM2null248 override fun setM2( 249 m2: IntModuleIncludingDoubleAndFloat 250 ): Builder // Test covariant overrides allowed 251 override fun doubleModule(doubleModule: DoubleModule) // Test simple overrides allowed 252 fun depComponent(depComponent: DepComponent) // Note we're missing M5 -- that's implicit. 253 } 254 } 255 256 @Component internal interface DepComponent 257 258 @Singleton 259 @Component 260 internal interface ParentComponent { 261 fun childAbstractClassBuilder(): TestChildComponentWithBuilderAbstractClass.Builder 262 fun childInterfaceBuilder(): TestChildComponentWithBuilderInterface.Builder 263 fun middleBuilder(): MiddleChild.Builder 264 fun otherBuilder(): OtherMiddleChild.Builder 265 fun requiresMiddleChildBuilder(): RequiresSubcomponentBuilder<MiddleChild.Builder> 266 } 267 268 @Scope internal annotation class MiddleScope 269 270 @MiddleScope 271 @Subcomponent(modules = [StringModule::class]) 272 internal interface MiddleChild { snull273 fun s(): String 274 fun grandchildBuilder(): Grandchild.Builder 275 fun requiresGrandchildBuilder(): RequiresSubcomponentBuilder<Grandchild.Builder> 276 277 @Subcomponent.Builder 278 interface Builder { 279 fun build(): MiddleChild 280 fun set(stringModule: StringModule): Builder 281 } 282 } 283 284 internal class RequiresSubcomponentBuilder<B> 285 @Inject 286 constructor( 287 private val subcomponentBuilderProvider: Provider<B>, 288 private val subcomponentBuilder: B 289 ) { subcomponentBuilderProvidernull290 fun subcomponentBuilderProvider() = subcomponentBuilderProvider 291 fun subcomponentBuilder() = subcomponentBuilder 292 } 293 294 @MiddleScope 295 @Subcomponent(modules = [StringModule::class, LongModule::class]) 296 internal interface OtherMiddleChild { 297 fun l(): Long 298 fun s(): String 299 fun grandchildBuilder(): Grandchild.Builder 300 301 @Subcomponent.Builder 302 interface Builder { 303 fun build(): OtherMiddleChild 304 fun set(stringModule: StringModule): Builder 305 } 306 } 307 308 @Component(modules = [StringModule::class]) 309 @Singleton 310 internal interface ParentOfGenericComponent : GenericParent<Grandchild.Builder> 311 312 @Subcomponent(modules = [IntModuleIncludingDoubleAndFloat::class]) 313 internal interface Grandchild { inull314 fun i(): Int 315 fun s(): String 316 317 @Subcomponent.Builder 318 interface Builder { 319 fun build(): Grandchild 320 fun set(intModule: IntModuleIncludingDoubleAndFloat): Builder 321 } 322 } 323 324 internal interface GenericParent<B> { subcomponentBuildernull325 fun subcomponentBuilder(): B 326 } 327 328 @Module 329 internal class ByteModule(private val b: Byte) { 330 @Provides fun b(): Byte = b 331 } 332 333 @Module 334 internal class DoubleModule { dnull335 @Provides fun d(): Double = 4.2 336 } 337 338 @Module 339 internal class LongModule { 340 @Provides fun l(): Long = 6L 341 } 342 343 @Module 344 internal class FloatModule { fnull345 @Provides fun f(): Float = 5.5f 346 } 347 348 @Module 349 internal class StringModule(private val string: String) { 350 @Provides fun string(): String = string 351 } 352 353 @Module(includes = [DoubleModule::class, FloatModule::class]) 354 internal class IntModuleIncludingDoubleAndFloat(private val integer: Int) { integernull355 @Provides fun integer(): Int = integer 356 } 357 358 @Test 359 fun interfaceBuilder() { 360 val builder = DaggerBuilderTest_TestComponentWithBuilderInterface.builder() 361 362 // Make sure things fail if we don't set our required modules. 363 try { 364 builder.build() 365 fail() 366 } catch (expected: IllegalStateException) {} 367 368 builder 369 .intModule(IntModuleIncludingDoubleAndFloat(1)) 370 .stringModule(StringModule("sam")) 371 .depComponent(object : DepComponent {}) 372 builder.doubleModule(DoubleModule()) 373 374 // Don't set other modules -- make sure it works. 375 val component = builder.build() 376 assertThat(component.s()).isEqualTo("sam") 377 assertThat(component.i()).isEqualTo(1) 378 assertThat(component.d()).isEqualTo(4.2) 379 assertThat(component.f()).isEqualTo(5.5f) 380 assertThat(component.l()).isEqualTo(6L) 381 } 382 383 @Test abstractClassBuildernull384 fun abstractClassBuilder() { 385 val builder = TestComponentWithBuilderAbstractClass.builder() 386 387 // Make sure things fail if we don't set our required modules. 388 try { 389 builder.build() 390 fail() 391 } catch (expected: IllegalStateException) {} 392 393 builder 394 .intModule(IntModuleIncludingDoubleAndFloat(1)) 395 .stringModule(StringModule("sam")) 396 .depComponent(object : DepComponent {}) 397 builder.doubleModule(DoubleModule()) 398 399 // Don't set other modules -- make sure it works. 400 val component = builder.build() 401 assertThat(component.s()).isEqualTo("sam") 402 assertThat(component.i()).isEqualTo(1) 403 assertThat(component.d()).isEqualTo(4.2) 404 assertThat(component.f()).isEqualTo(5.5f) 405 assertThat(component.l()).isEqualTo(6L) 406 } 407 408 @Test interfaceGenericBuildernull409 fun interfaceGenericBuilder() { 410 val builder = DaggerBuilderTest_TestComponentWithGenericBuilderInterface.builder() 411 412 // Make sure things fail if we don't set our required modules. 413 try { 414 builder.build() 415 fail() 416 } catch (expected: IllegalStateException) {} 417 418 builder 419 .setM2(IntModuleIncludingDoubleAndFloat(1)) 420 .setM1(StringModule("sam")) 421 .depComponent(object : DepComponent {}) 422 builder.doubleModule(DoubleModule()) 423 424 // Don't set other modules -- make sure it works. 425 val component = builder.build() 426 assertThat(component.s()).isEqualTo("sam") 427 assertThat(component.i()).isEqualTo(1) 428 assertThat(component.d()).isEqualTo(4.2) 429 assertThat(component.f()).isEqualTo(5.5f) 430 assertThat(component.l()).isEqualTo(6L) 431 } 432 433 @Test abstractClassGenericBuildernull434 fun abstractClassGenericBuilder() { 435 val builder = DaggerBuilderTest_TestComponentWithGenericBuilderAbstractClass.builder() 436 437 // Make sure things fail if we don't set our required modules. 438 try { 439 builder.build() 440 fail() 441 } catch (expected: IllegalStateException) {} 442 443 builder 444 .setM2(IntModuleIncludingDoubleAndFloat(1)) 445 .setM1(StringModule("sam")) 446 .depComponent(object : DepComponent {}) 447 builder.doubleModule(DoubleModule()) 448 449 // Don't set other modules -- make sure it works. 450 val component = builder.build() 451 assertThat(component.s()).isEqualTo("sam") 452 assertThat(component.i()).isEqualTo(1) 453 assertThat(component.d()).isEqualTo(4.2) 454 assertThat(component.f()).isEqualTo(5.5f) 455 assertThat(component.l()).isEqualTo(6L) 456 } 457 458 @Test subcomponents_interfacenull459 fun subcomponents_interface() { 460 val parent = DaggerBuilderTest_ParentComponent.create() 461 val builder1 = parent.childInterfaceBuilder() 462 463 try { 464 builder1.build() 465 fail() 466 } catch (expected: IllegalStateException) {} 467 468 builder1 469 .setM2(IntModuleIncludingDoubleAndFloat(1)) 470 .setM1(StringModule("sam")) 471 .set(ByteModule(7.toByte())) 472 builder1.set(FloatModule()) 473 474 val child1 = builder1.build() 475 assertThat(child1.s()).isEqualTo("sam") 476 assertThat(child1.i()).isEqualTo(1) 477 assertThat(child1.d()).isEqualTo(4.2) 478 assertThat(child1.f()).isEqualTo(5.5f) 479 assertThat(child1.l()).isEqualTo(6L) 480 assertThat(child1.b()).isEqualTo(7.toByte()) 481 } 482 483 @Test subcomponents_abstractclassnull484 fun subcomponents_abstractclass() { 485 val parent = DaggerBuilderTest_ParentComponent.create() 486 val builder2 = parent.childAbstractClassBuilder() 487 488 try { 489 builder2.build() 490 fail() 491 } catch (expected: IllegalStateException) {} 492 493 builder2 494 .setM2(IntModuleIncludingDoubleAndFloat(10)) 495 .setM1(StringModule("tara")) 496 .set(ByteModule(70.toByte())) 497 builder2.set(FloatModule()) 498 499 val child2 = builder2.build() 500 assertThat(child2.s()).isEqualTo("tara") 501 assertThat(child2.i()).isEqualTo(10) 502 assertThat(child2.d()).isEqualTo(4.2) 503 assertThat(child2.f()).isEqualTo(5.5f) 504 assertThat(child2.l()).isEqualTo(6L) 505 assertThat(child2.b()).isEqualTo(70.toByte()) 506 } 507 508 @Test grandchildrennull509 fun grandchildren() { 510 val parent = DaggerBuilderTest_ParentComponent.create() 511 val middle1 = parent.middleBuilder().set(StringModule("sam")).build() 512 val grandchild1 = middle1.grandchildBuilder().set(IntModuleIncludingDoubleAndFloat(21)).build() 513 val grandchild2 = middle1.grandchildBuilder().set(IntModuleIncludingDoubleAndFloat(22)).build() 514 assertThat(middle1.s()).isEqualTo("sam") 515 assertThat(grandchild1.i()).isEqualTo(21) 516 assertThat(grandchild1.s()).isEqualTo("sam") 517 assertThat(grandchild2.i()).isEqualTo(22) 518 assertThat(grandchild2.s()).isEqualTo("sam") 519 520 // Make sure grandchildren from newer children have no relation to the older ones. 521 val middle2 = parent.middleBuilder().set(StringModule("tara")).build() 522 val grandchild3 = middle2.grandchildBuilder().set(IntModuleIncludingDoubleAndFloat(23)).build() 523 val grandchild4 = middle2.grandchildBuilder().set(IntModuleIncludingDoubleAndFloat(24)).build() 524 assertThat(middle2.s()).isEqualTo("tara") 525 assertThat(grandchild3.i()).isEqualTo(23) 526 assertThat(grandchild3.s()).isEqualTo("tara") 527 assertThat(grandchild4.i()).isEqualTo(24) 528 assertThat(grandchild4.s()).isEqualTo("tara") 529 } 530 531 @Test diamondGrandchildrennull532 fun diamondGrandchildren() { 533 val parent = DaggerBuilderTest_ParentComponent.create() 534 val middle = parent.middleBuilder().set(StringModule("sam")).build() 535 val other = parent.otherBuilder().set(StringModule("tara")).build() 536 val middlegrand = middle.grandchildBuilder().set(IntModuleIncludingDoubleAndFloat(21)).build() 537 val othergrand = other.grandchildBuilder().set(IntModuleIncludingDoubleAndFloat(22)).build() 538 assertThat(middle.s()).isEqualTo("sam") 539 assertThat(other.s()).isEqualTo("tara") 540 assertThat(middlegrand.s()).isEqualTo("sam") 541 assertThat(othergrand.s()).isEqualTo("tara") 542 assertThat(middlegrand.i()).isEqualTo(21) 543 assertThat(othergrand.i()).isEqualTo(22) 544 } 545 546 @Test genericSubcomponentMethodnull547 fun genericSubcomponentMethod() { 548 val parent = 549 DaggerBuilderTest_ParentOfGenericComponent.builder().stringModule(StringModule("sam")).build() 550 val builder = parent.subcomponentBuilder() 551 val child = builder.set(IntModuleIncludingDoubleAndFloat(21)).build() 552 assertThat(child.s()).isEqualTo("sam") 553 assertThat(child.i()).isEqualTo(21) 554 } 555 556 @Test requireSubcomponentBuilderProvidersnull557 fun requireSubcomponentBuilderProviders() { 558 val parent = DaggerBuilderTest_ParentComponent.create() 559 val middle = 560 parent 561 .requiresMiddleChildBuilder() 562 .subcomponentBuilderProvider() 563 .get() 564 .set(StringModule("sam")) 565 .build() 566 val grandchild = 567 middle 568 .requiresGrandchildBuilder() 569 .subcomponentBuilderProvider() 570 .get() 571 .set(IntModuleIncludingDoubleAndFloat(12)) 572 .build() 573 assertThat(middle.s()).isEqualTo("sam") 574 assertThat(grandchild.i()).isEqualTo(12) 575 assertThat(grandchild.s()).isEqualTo("sam") 576 } 577 578 @Test requireSubcomponentBuildersnull579 fun requireSubcomponentBuilders() { 580 val parent = DaggerBuilderTest_ParentComponent.create() 581 val middle = 582 parent.requiresMiddleChildBuilder().subcomponentBuilder().set(StringModule("sam")).build() 583 val grandchild = 584 middle 585 .requiresGrandchildBuilder() 586 .subcomponentBuilder() 587 .set(IntModuleIncludingDoubleAndFloat(12)) 588 .build() 589 assertThat(middle.s()).isEqualTo("sam") 590 assertThat(grandchild.i()).isEqualTo(12) 591 assertThat(grandchild.s()).isEqualTo("sam") 592 } 593 } 594