1 /* 2 * Copyright (C) 2017 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.internal.codegen; 18 19 import androidx.room.compiler.processing.util.Source; 20 import dagger.testing.compile.CompilerTests; 21 import dagger.testing.golden.GoldenFileRule; 22 import java.util.Collection; 23 import org.junit.Rule; 24 import org.junit.Test; 25 import org.junit.runner.RunWith; 26 import org.junit.runners.Parameterized; 27 import org.junit.runners.Parameterized.Parameters; 28 29 @RunWith(Parameterized.class) 30 public class DelegateRequestRepresentationTest { 31 @Parameters(name = "{0}") parameters()32 public static Collection<Object[]> parameters() { 33 return CompilerMode.TEST_PARAMETERS; 34 } 35 36 @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule(); 37 38 private final CompilerMode compilerMode; 39 DelegateRequestRepresentationTest(CompilerMode compilerMode)40 public DelegateRequestRepresentationTest(CompilerMode compilerMode) { 41 this.compilerMode = compilerMode; 42 } 43 44 private static final Source REGULAR_SCOPED = 45 CompilerTests.javaSource( 46 "test.RegularScoped", 47 "package test;", 48 "", 49 "import javax.inject.Scope;", 50 "import javax.inject.Inject;", 51 "", 52 "@RegularScoped.CustomScope", 53 "class RegularScoped {", 54 " @Inject RegularScoped() {}", 55 "", 56 " @Scope @interface CustomScope {}", 57 "}"); 58 59 private static final Source REUSABLE_SCOPED = 60 CompilerTests.javaSource( 61 "test.ReusableScoped", 62 "package test;", 63 "", 64 "import dagger.Reusable;", 65 "import javax.inject.Inject;", 66 "", 67 "@Reusable", 68 "class ReusableScoped {", 69 " @Inject ReusableScoped() {}", 70 "}"); 71 72 private static final Source UNSCOPED = 73 CompilerTests.javaSource( 74 "test.Unscoped", 75 "package test;", 76 "", 77 "import javax.inject.Inject;", 78 "", 79 "class Unscoped {", 80 " @Inject Unscoped() {}", 81 "}"); 82 83 private static final Source COMPONENT = 84 CompilerTests.javaSource( 85 "test.TestComponent", 86 "package test;", 87 "", 88 "import dagger.Component;", 89 "", 90 "@Component(modules = TestModule.class)", 91 "@RegularScoped.CustomScope", 92 "interface TestComponent {", 93 " @Qualifier(RegularScoped.class)", 94 " Object regular();", 95 "", 96 " @Qualifier(ReusableScoped.class)", 97 " Object reusable();", 98 "", 99 " @Qualifier(Unscoped.class)", 100 " Object unscoped();", 101 "}"); 102 103 private static final Source QUALIFIER = 104 CompilerTests.javaSource( 105 "test.Qualifier", 106 "package test;", 107 "", 108 "@javax.inject.Qualifier", 109 "@interface Qualifier {", 110 " Class<?> value();", 111 "}"); 112 113 @Test toDoubleCheck()114 public void toDoubleCheck() throws Exception { 115 Source module = 116 CompilerTests.javaSource( 117 "test.TestModule", 118 "package test;", 119 "", 120 "import dagger.Binds;", 121 "import dagger.Module;", 122 "", 123 "@Module", 124 "interface TestModule {", 125 " @Binds @RegularScoped.CustomScope @Qualifier(RegularScoped.class)", 126 " Object regular(RegularScoped delegate);", 127 "", 128 " @Binds @RegularScoped.CustomScope @Qualifier(ReusableScoped.class)", 129 " Object reusable(ReusableScoped delegate);", 130 "", 131 " @Binds @RegularScoped.CustomScope @Qualifier(Unscoped.class)", 132 " Object unscoped(Unscoped delegate);", 133 "}"); 134 135 CompilerTests.daggerCompiler( 136 module, COMPONENT, QUALIFIER, REGULAR_SCOPED, REUSABLE_SCOPED, UNSCOPED) 137 .withProcessingOptions(compilerMode.processorOptions()) 138 .compile( 139 subject -> { 140 subject.hasErrorCount(0); 141 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 142 }); 143 } 144 145 @Test toSingleCheck()146 public void toSingleCheck() throws Exception { 147 Source module = 148 CompilerTests.javaSource( 149 "test.TestModule", 150 "package test;", 151 "", 152 "import dagger.Binds;", 153 "import dagger.Module;", 154 "import dagger.Reusable;", 155 "", 156 "@Module", 157 "interface TestModule {", 158 " @Binds @Reusable @Qualifier(RegularScoped.class)", 159 " Object regular(RegularScoped delegate);", 160 "", 161 " @Binds @Reusable @Qualifier(ReusableScoped.class)", 162 " Object reusable(ReusableScoped delegate);", 163 "", 164 " @Binds @Reusable @Qualifier(Unscoped.class)", 165 " Object unscoped(Unscoped delegate);", 166 "}"); 167 168 CompilerTests.daggerCompiler( 169 module, COMPONENT, QUALIFIER, REGULAR_SCOPED, REUSABLE_SCOPED, UNSCOPED) 170 .withProcessingOptions(compilerMode.processorOptions()) 171 .compile( 172 subject -> { 173 subject.hasErrorCount(0); 174 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 175 }); 176 } 177 178 @Test toUnscoped()179 public void toUnscoped() throws Exception { 180 Source module = 181 CompilerTests.javaSource( 182 "test.TestModule", 183 "package test;", 184 "", 185 "import dagger.Binds;", 186 "import dagger.Module;", 187 "", 188 "@Module", 189 "interface TestModule {", 190 " @Binds @Qualifier(RegularScoped.class)", 191 " Object regular(RegularScoped delegate);", 192 "", 193 " @Binds @Qualifier(ReusableScoped.class)", 194 " Object reusable(ReusableScoped delegate);", 195 "", 196 " @Binds @Qualifier(Unscoped.class)", 197 " Object unscoped(Unscoped delegate);", 198 "}"); 199 200 CompilerTests.daggerCompiler( 201 module, COMPONENT, QUALIFIER, REGULAR_SCOPED, REUSABLE_SCOPED, UNSCOPED) 202 .withProcessingOptions(compilerMode.processorOptions()) 203 .compile( 204 subject -> { 205 subject.hasErrorCount(0); 206 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 207 }); 208 } 209 210 @Test castNeeded_rawTypes_Provider_get()211 public void castNeeded_rawTypes_Provider_get() throws Exception { 212 Source accessibleSupertype = 213 CompilerTests.javaSource( 214 "other.Supertype", 215 "package other;", 216 "", 217 // accessible from the component, but the subtype is not 218 "public interface Supertype {}"); 219 Source inaccessibleSubtype = 220 CompilerTests.javaSource( 221 "other.Subtype", 222 "package other;", 223 "", 224 "import javax.inject.Inject;", 225 "import javax.inject.Singleton;", 226 "", 227 "@Singleton", 228 "class Subtype implements Supertype {", 229 " @Inject Subtype() {}", 230 "}"); 231 Source module = 232 CompilerTests.javaSource( 233 "other.SupertypeModule", 234 "package other;", 235 "", 236 "import dagger.Binds;", 237 "import dagger.Module;", 238 "", 239 "@Module", 240 "public interface SupertypeModule {", 241 " @Binds Supertype to(Subtype subtype);", 242 "}"); 243 Source component = 244 CompilerTests.javaSource( 245 "test.TestComponent", 246 "package test;", 247 "", 248 "import dagger.Component;", 249 "import javax.inject.Singleton;", 250 "", 251 "@Singleton", 252 "@Component(modules = other.SupertypeModule.class)", 253 "interface TestComponent {", 254 " other.Supertype supertype();", 255 "}"); 256 257 CompilerTests.daggerCompiler(accessibleSupertype, inaccessibleSubtype, module, component) 258 .withProcessingOptions(compilerMode.processorOptions()) 259 .compile( 260 subject -> { 261 subject.hasErrorCount(0); 262 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 263 }); 264 } 265 266 @Test noCast_rawTypes_Provider_get_toInaccessibleType()267 public void noCast_rawTypes_Provider_get_toInaccessibleType() throws Exception { 268 Source supertype = 269 CompilerTests.javaSource( 270 "other.Supertype", 271 "package other;", 272 "", 273 "interface Supertype {}"); 274 Source subtype = 275 CompilerTests.javaSource( 276 "other.Subtype", 277 "package other;", 278 "", 279 "import javax.inject.Inject;", 280 "import javax.inject.Singleton;", 281 "", 282 "@Singleton", 283 "class Subtype implements Supertype {", 284 " @Inject Subtype() {}", 285 "}"); 286 Source usesSupertype = 287 CompilerTests.javaSource( 288 "other.UsesSupertype", 289 "package other;", 290 "", 291 "import javax.inject.Inject;", 292 "", 293 "public class UsesSupertype {", 294 " @Inject UsesSupertype(Supertype supertype) {}", 295 "}"); 296 Source module = 297 CompilerTests.javaSource( 298 "other.SupertypeModule", 299 "package other;", 300 "", 301 "import dagger.Binds;", 302 "import dagger.Module;", 303 "", 304 "@Module", 305 "public interface SupertypeModule {", 306 " @Binds Supertype to(Subtype subtype);", 307 "}"); 308 Source component = 309 CompilerTests.javaSource( 310 "test.TestComponent", 311 "package test;", 312 "", 313 "import dagger.Component;", 314 "import javax.inject.Singleton;", 315 "", 316 "@Singleton", 317 "@Component(modules = other.SupertypeModule.class)", 318 "interface TestComponent {", 319 " other.UsesSupertype usesSupertype();", 320 "}"); 321 322 CompilerTests.daggerCompiler(supertype, subtype, usesSupertype, module, component) 323 .withProcessingOptions(compilerMode.processorOptions()) 324 .compile( 325 subject -> { 326 subject.hasErrorCount(0); 327 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 328 }); 329 } 330 331 @Test castedToRawType()332 public void castedToRawType() throws Exception { 333 Source module = 334 CompilerTests.javaSource( 335 "test.TestModule", 336 "package test;", 337 "", 338 "import dagger.Binds;", 339 "import dagger.Module;", 340 "import dagger.Provides;", 341 "import javax.inject.Named;", 342 "", 343 "@Module", 344 "interface TestModule {", 345 " @Provides", 346 " static String provideString() { return new String(); }", 347 "", 348 " @Binds", 349 " CharSequence charSequence(String string);", 350 "", 351 " @Binds", 352 " @Named(\"named\")", 353 " String namedString(String string);", 354 "}"); 355 Source component = 356 CompilerTests.javaSource( 357 "test.TestComponent", 358 "package test;", 359 "", 360 "import dagger.Component;", 361 "import javax.inject.Named;", 362 "import javax.inject.Provider;", 363 "", 364 "@Component(modules = TestModule.class)", 365 "interface TestComponent {", 366 " Provider<CharSequence> charSequence();", 367 " CharSequence charSequenceInstance();", 368 "", 369 " @Named(\"named\") Provider<String> namedString();", 370 "}"); 371 372 CompilerTests.daggerCompiler(module, component) 373 .withProcessingOptions(compilerMode.processorOptions()) 374 .compile( 375 subject -> { 376 subject.hasErrorCount(0); 377 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 378 }); 379 } 380 381 @Test doubleBinds()382 public void doubleBinds() throws Exception { 383 Source module = 384 CompilerTests.javaSource( 385 "test.TestModule", 386 "package test;", 387 "", 388 "import dagger.Binds;", 389 "import dagger.Module;", 390 "import dagger.Provides;", 391 "", 392 "@Module", 393 "interface TestModule {", 394 " @Provides", 395 " static String provideString() { return new String(); }", 396 "", 397 " @Binds", 398 " CharSequence charSequence(String string);", 399 "", 400 " @Binds", 401 " Object object(CharSequence charSequence);", 402 "}"); 403 Source component = 404 CompilerTests.javaSource( 405 "test.TestComponent", 406 "package test;", 407 "", 408 "import dagger.Component;", 409 "import javax.inject.Named;", 410 "import javax.inject.Provider;", 411 "", 412 "@Component(modules = TestModule.class)", 413 "interface TestComponent {", 414 " Provider<CharSequence> charSequence();", 415 " Provider<Object> object();", 416 "}"); 417 418 CompilerTests.daggerCompiler(module, component) 419 .withProcessingOptions(compilerMode.processorOptions()) 420 .compile( 421 subject -> { 422 subject.hasErrorCount(0); 423 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 424 }); 425 } 426 427 @Test inlineFactoryOfInacessibleType()428 public void inlineFactoryOfInacessibleType() throws Exception { 429 Source supertype = 430 CompilerTests.javaSource( 431 "other.Supertype", 432 "package other;", 433 "", 434 "public interface Supertype {}"); 435 Source injectableSubtype = 436 CompilerTests.javaSource( 437 "other.Subtype", 438 "package other;", 439 "", 440 "import javax.inject.Inject;", 441 "", 442 "final class Subtype implements Supertype {", 443 // important: this doesn't have any dependencies and therefore the factory will be able 444 // to be referenced with an inline Subtype_Factory.create() 445 " @Inject Subtype() {}", 446 "}"); 447 Source module = 448 CompilerTests.javaSource( 449 "other.TestModule", 450 "package other;", 451 "", 452 "import dagger.Binds;", 453 "import dagger.Module;", 454 "", 455 "@Module", 456 "public interface TestModule {", 457 " @Binds Supertype to(Subtype subtype);", 458 "}"); 459 Source component = 460 CompilerTests.javaSource( 461 "test.RequestsSubtypeAsProvider", 462 "package test;", 463 "", 464 "import dagger.Component;", 465 "import javax.inject.Provider;", 466 "", 467 "@Component(modules = other.TestModule.class)", 468 "interface RequestsSubtypeAsProvider {", 469 " Provider<other.Supertype> supertypeProvider();", 470 "}"); 471 472 CompilerTests.daggerCompiler(supertype, injectableSubtype, module, component) 473 .withProcessingOptions(compilerMode.processorOptions()) 474 .compile( 475 subject -> { 476 subject.hasErrorCount(0); 477 subject.generatedSource( 478 goldenFileRule.goldenSource("test/DaggerRequestsSubtypeAsProvider")); 479 }); 480 } 481 482 @Test providerWhenBindsScopeGreaterThanDependencyScope()483 public void providerWhenBindsScopeGreaterThanDependencyScope() throws Exception { 484 Source module = 485 CompilerTests.javaSource( 486 "test.TestModule", 487 "package test;", 488 "", 489 "import dagger.Binds;", 490 "import dagger.Module;", 491 "import dagger.Provides;", 492 "import dagger.Reusable;", 493 "import javax.inject.Singleton;", 494 "", 495 "@Module", 496 "public abstract class TestModule {", 497 " @Reusable", 498 " @Provides", 499 " static String provideString() {", 500 " return \"\";", 501 " }", 502 "", 503 " @Binds", 504 " @Singleton", 505 " abstract Object bindString(String str);", 506 "}"); 507 Source component = 508 CompilerTests.javaSource( 509 "test.TestComponent", 510 "package test;", 511 "", 512 "import dagger.Component;", 513 "import javax.inject.Singleton;", 514 "import javax.inject.Provider;", 515 "", 516 "@Singleton", 517 "@Component(modules = TestModule.class)", 518 "interface TestComponent {", 519 " Provider<Object> object();", 520 "}"); 521 522 CompilerTests.daggerCompiler(module, component) 523 .withProcessingOptions(compilerMode.processorOptions()) 524 .compile( 525 subject -> { 526 subject.hasErrorCount(0); 527 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 528 }); 529 } 530 } 531