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 static com.google.testing.compile.CompilationSubject.assertThat; 20 import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE; 21 import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE; 22 import static dagger.internal.codegen.Compilers.compilerWithOptions; 23 24 import com.google.testing.compile.Compilation; 25 import com.google.testing.compile.JavaFileObjects; 26 import java.util.Collection; 27 import javax.tools.JavaFileObject; 28 import org.junit.Test; 29 import org.junit.runner.RunWith; 30 import org.junit.runners.Parameterized; 31 import org.junit.runners.Parameterized.Parameters; 32 33 @RunWith(Parameterized.class) 34 public class ComponentRequirementFieldTest { 35 @Parameters(name = "{0}") parameters()36 public static Collection<Object[]> parameters() { 37 return CompilerMode.TEST_PARAMETERS; 38 } 39 40 private final CompilerMode compilerMode; 41 ComponentRequirementFieldTest(CompilerMode compilerMode)42 public ComponentRequirementFieldTest(CompilerMode compilerMode) { 43 this.compilerMode = compilerMode; 44 } 45 46 @Test bindsInstance()47 public void bindsInstance() { 48 JavaFileObject component = 49 JavaFileObjects.forSourceLines( 50 "test.TestComponent", 51 "package test;", 52 "", 53 "import dagger.BindsInstance;", 54 "import dagger.Component;", 55 "import java.util.List;", 56 "", 57 "@Component", 58 "interface TestComponent {", 59 " int i();", 60 " List<String> list();", 61 "", 62 " @Component.Builder", 63 " interface Builder {", 64 " @BindsInstance Builder i(int i);", 65 " @BindsInstance Builder list(List<String> list);", 66 " TestComponent build();", 67 " }", 68 "}"); 69 Compilation compilation = 70 compilerWithOptions(compilerMode.javacopts()).compile(component); 71 assertThat(compilation).succeeded(); 72 assertThat(compilation) 73 .generatedSourceFile("test.DaggerTestComponent") 74 .containsElementsIn( 75 JavaFileObjects.forSourceLines( 76 "test.DaggerTestComponent", 77 "package test;", 78 "", 79 GeneratedLines.generatedAnnotations(), 80 "final class DaggerTestComponent implements TestComponent {", 81 " private final Integer i;", 82 " private final List<String> list;", 83 "", 84 " private DaggerTestComponent(Integer iParam, List<String> listParam) {", 85 " this.i = iParam;", 86 " this.list = listParam;", 87 " }", 88 "", 89 " @Override", 90 " public int i() {", 91 " return i;", 92 " }", 93 "", 94 " @Override", 95 " public List<String> list() {", 96 " return list;", 97 " }", 98 "", 99 " private static final class Builder implements TestComponent.Builder {", 100 " private Integer i;", 101 " private List<String> list;", 102 "", 103 " @Override", 104 " public Builder i(int i) {", 105 " this.i = Preconditions.checkNotNull(i);", 106 " return this;", 107 " }", 108 "", 109 " @Override", 110 " public Builder list(List<String> list) {", 111 " this.list = Preconditions.checkNotNull(list);", 112 " return this;", 113 " }", 114 "", 115 " @Override", 116 " public TestComponent build() {", 117 " Preconditions.checkBuilderRequirement(i, Integer.class);", 118 " Preconditions.checkBuilderRequirement(list, List.class);", 119 " return new DaggerTestComponent(i, list);", 120 " }", 121 " }", 122 "}")); 123 } 124 125 @Test instanceModuleMethod()126 public void instanceModuleMethod() { 127 JavaFileObject module = 128 JavaFileObjects.forSourceLines( 129 "test.ParentModule", 130 "package test;", 131 "", 132 "import dagger.Module;", 133 "import dagger.Provides;", 134 "", 135 "@Module", 136 "class ParentModule {", 137 " @Provides int i() { return 0; }", 138 "}"); 139 JavaFileObject otherPackageModule = 140 JavaFileObjects.forSourceLines( 141 "other.OtherPackageModule", 142 "package other;", 143 "", 144 "import dagger.Module;", 145 "import dagger.Provides;", 146 "", 147 "@Module", 148 "public class OtherPackageModule {", 149 " @Provides long l() { return 0L; }", 150 "}"); 151 JavaFileObject component = 152 JavaFileObjects.forSourceLines( 153 "test.TestComponent", 154 "package test;", 155 "", 156 "import dagger.Component;", 157 "import other.OtherPackageModule;", 158 "", 159 "@Component(modules = {ParentModule.class, OtherPackageModule.class})", 160 "interface TestComponent {", 161 " int i();", 162 " long l();", 163 "}"); 164 Compilation compilation = 165 compilerWithOptions(compilerMode.javacopts()) 166 .compile(module, otherPackageModule, component); 167 assertThat(compilation).succeeded(); 168 JavaFileObject generatedComponent = 169 JavaFileObjects.forSourceLines( 170 "test.DaggerTestComponent", 171 "package test;", 172 "", 173 "import other.OtherPackageModule;", 174 "import other.OtherPackageModule_LFactory;", 175 "", 176 GeneratedLines.generatedAnnotations(), 177 "final class DaggerTestComponent implements TestComponent {", 178 " private final ParentModule parentModule;", 179 " private final OtherPackageModule otherPackageModule;", 180 "", 181 " @Override", 182 " public int i() {", 183 " return parentModule.i();", 184 " }", 185 "", 186 " @Override", 187 " public long l() {", 188 " return OtherPackageModule_LFactory.l(otherPackageModule);", 189 " }", 190 "}"); 191 assertThat(compilation) 192 .generatedSourceFile("test.DaggerTestComponent") 193 .containsElementsIn(generatedComponent); 194 } 195 196 @Test componentInstances()197 public void componentInstances() { 198 JavaFileObject dependency = 199 JavaFileObjects.forSourceLines( 200 "test.Dep", 201 "package test;", 202 "", 203 "interface Dep {", 204 " String string();", 205 " Object object();", 206 "}"); 207 208 JavaFileObject component = 209 JavaFileObjects.forSourceLines( 210 "test.TestComponent", 211 "package test;", 212 "", 213 "import dagger.Component;", 214 "", 215 "@Component(dependencies = Dep.class)", 216 "interface TestComponent {", 217 " TestComponent self();", 218 " TestSubcomponent subcomponent();", 219 "", 220 " Dep dep();", 221 " String methodOnDep();", 222 " Object otherMethodOnDep();", 223 "}"); 224 JavaFileObject subcomponent = 225 JavaFileObjects.forSourceLines( 226 "test.TestComponent", 227 "package test;", 228 "", 229 "import dagger.Subcomponent;", 230 "", 231 "@Subcomponent", 232 "interface TestSubcomponent {", 233 " TestComponent parent();", 234 " Dep depFromSubcomponent();", 235 "}"); 236 237 Compilation compilation = 238 compilerWithOptions(compilerMode.javacopts()) 239 .compile(dependency, component, subcomponent); 240 assertThat(compilation).succeeded(); 241 assertThat(compilation) 242 .generatedSourceFile("test.DaggerTestComponent") 243 .containsElementsIn( 244 JavaFileObjects.forSourceLines( 245 "test.DaggerTestComponent", 246 "package test;", 247 "", 248 GeneratedLines.generatedAnnotations(), 249 "final class DaggerTestComponent implements TestComponent {", 250 " private final Dep dep;", 251 "", 252 " private DaggerTestComponent(Dep depParam) {", 253 " this.dep = depParam;", 254 " }", 255 "", 256 " @Override", 257 " public TestComponent self() {", 258 " return this;", 259 " }", 260 "", 261 " @Override", 262 " public Dep dep() {", 263 " return dep;", 264 " }", 265 "", 266 " @Override", 267 " public String methodOnDep() {", 268 " return Preconditions.checkNotNullFromComponent(", 269 " dep.string());", 270 " }", 271 "", 272 " @Override", 273 " public Object otherMethodOnDep() {", 274 " return Preconditions.checkNotNullFromComponent(dep.object());", 275 " }", 276 "", 277 " private static final class TestSubcomponentImpl implements TestSubcomponent {", 278 " @Override", 279 " public TestComponent parent() {", 280 " return testComponent;", 281 " }", 282 "", 283 " @Override", 284 " public Dep depFromSubcomponent() {", 285 " return testComponent.dep;", 286 " }", 287 " }", 288 "}")); 289 } 290 291 @Test componentRequirementNeededInFactoryCreationOfSubcomponent()292 public void componentRequirementNeededInFactoryCreationOfSubcomponent() { 293 JavaFileObject parentModule = 294 JavaFileObjects.forSourceLines( 295 "test.ParentModule", 296 "package test;", 297 "", 298 "import dagger.Module;", 299 "import dagger.multibindings.IntoSet;", 300 "import dagger.Provides;", 301 "import java.util.Set;", 302 "", 303 "@Module", 304 "class ParentModule {", 305 " @Provides", 306 // intentionally non-static. this needs to require the module when the subcompnent 307 // adds to the Set binding 308 " Object reliesOnMultibinding(Set<Object> set) { return set; }", 309 "", 310 " @Provides @IntoSet static Object contribution() { return new Object(); }", 311 "}"); 312 313 JavaFileObject childModule = 314 JavaFileObjects.forSourceLines( 315 "test.ChildModule", 316 "package test;", 317 "", 318 "import dagger.Module;", 319 "import dagger.multibindings.IntoSet;", 320 "import dagger.Provides;", 321 "", 322 "@Module", 323 "class ChildModule {", 324 " @Provides @IntoSet static Object contribution() { return new Object(); }", 325 "}"); 326 327 JavaFileObject component = 328 JavaFileObjects.forSourceLines( 329 "test.TestComponent", 330 "package test;", 331 "", 332 "import dagger.Component;", 333 "import javax.inject.Provider;", 334 "", 335 "@Component(modules = ParentModule.class)", 336 "interface TestComponent {", 337 " Provider<Object> dependsOnMultibinding();", 338 " TestSubcomponent subcomponent();", 339 "}"); 340 341 JavaFileObject subcomponent = 342 JavaFileObjects.forSourceLines( 343 "test.TestSubcomponent", 344 "package test;", 345 "", 346 "import dagger.Subcomponent;", 347 "import javax.inject.Provider;", 348 "", 349 "@Subcomponent(modules = ChildModule.class)", 350 "interface TestSubcomponent {", 351 " Provider<Object> dependsOnMultibinding();", 352 "}"); 353 354 Compilation compilation = 355 compilerWithOptions(compilerMode.javacopts()) 356 .compile(parentModule, childModule, component, subcomponent); 357 assertThat(compilation).succeeded(); 358 assertThat(compilation) 359 .generatedSourceFile("test.DaggerTestComponent") 360 .containsElementsIn( 361 compilerMode 362 .javaFileBuilder("test.DaggerSimpleComponent") 363 .addLines( 364 "package test;", 365 "", 366 GeneratedLines.generatedAnnotations(), 367 "final class DaggerTestComponent implements TestComponent {", 368 " private final ParentModule parentModule;", 369 "", 370 " private DaggerTestComponent(ParentModule parentModuleParam) {", 371 " this.parentModule = parentModuleParam;", 372 " initialize(parentModuleParam);", 373 " }") 374 .addLinesIn( 375 DEFAULT_MODE, 376 " @SuppressWarnings(\"unchecked\")", 377 " private void initialize(final ParentModule parentModuleParam) {", 378 " this.setOfObjectProvider =", 379 " SetFactory.<Object>builder(1, 0)", 380 " .addProvider(ParentModule_ContributionFactory.create())", 381 " .build();", 382 " this.reliesOnMultibindingProvider =", 383 " ParentModule_ReliesOnMultibindingFactory", 384 " .create(parentModuleParam, setOfObjectProvider);", 385 " }") 386 .addLinesIn( 387 FAST_INIT_MODE, 388 "", 389 " private Set<Object> setOfObject() {", 390 " return ImmutableSet.<Object>of(", 391 " ParentModule_ContributionFactory.contribution());", 392 " }", 393 "", 394 " @SuppressWarnings(\"unchecked\")", 395 " private void initialize(final ParentModule parentModuleParam) {", 396 " this.reliesOnMultibindingProvider =", 397 " new SwitchingProvider<>(testComponent, 0);", 398 " }") 399 .addLines( 400 " @Override", 401 " public Provider<Object> dependsOnMultibinding() {", 402 " return reliesOnMultibindingProvider;", 403 " }", 404 "", 405 " @Override", 406 " public TestSubcomponent subcomponent() {", 407 " return new TestSubcomponentImpl(testComponent);", 408 " }", 409 "", 410 " private static final class TestSubcomponentImpl", 411 " implements TestSubcomponent {") 412 .addLinesIn( 413 DEFAULT_MODE, 414 " @SuppressWarnings(\"unchecked\")", 415 " private void initialize() {", 416 " this.setOfObjectProvider =", 417 " SetFactory.<Object>builder(2, 0)", 418 " .addProvider(ParentModule_ContributionFactory.create())", 419 " .addProvider(ChildModule_ContributionFactory.create())", 420 " .build();", 421 " this.reliesOnMultibindingProvider =", 422 " ParentModule_ReliesOnMultibindingFactory", 423 " .create(testComponent.parentModule, setOfObjectProvider);", 424 " }") 425 .addLinesIn( 426 FAST_INIT_MODE, 427 " private Set<Object> setOfObject() {", 428 " return ImmutableSet.<Object>of(", 429 " ParentModule_ContributionFactory.contribution(),", 430 " ChildModule_ContributionFactory.contribution());", 431 " }", 432 "", 433 " @SuppressWarnings(\"unchecked\")", 434 " private void initialize() {", 435 " this.reliesOnMultibindingProvider =", 436 " new SwitchingProvider<>(testComponent, testSubcomponentImpl, 0);", 437 " }") 438 .addLines( 439 " @Override", 440 " public Provider<Object> dependsOnMultibinding() {", 441 " return reliesOnMultibindingProvider;", 442 " }") 443 .addLinesIn( 444 FAST_INIT_MODE, 445 " private static final class SwitchingProvider<T> implements Provider<T> {", 446 " @SuppressWarnings(\"unchecked\")", 447 " @Override", 448 " public T get() {", 449 " switch (id) {", 450 " case 0:", 451 " return (T) ParentModule_ReliesOnMultibindingFactory", 452 " .reliesOnMultibinding(", 453 " testComponent.parentModule,", 454 " testSubcomponentImpl.setOfObject());", 455 " default: throw new AssertionError(id);", 456 " }", 457 " }", 458 " }", 459 " }", 460 "", 461 " private static final class SwitchingProvider<T> implements Provider<T> {", 462 " @SuppressWarnings(\"unchecked\")", 463 " @Override", 464 " public T get() {", 465 " switch (id) {", 466 " case 0:", 467 " return (T) ParentModule_ReliesOnMultibindingFactory", 468 " .reliesOnMultibinding(", 469 " testComponent.parentModule, testComponent.setOfObject());", 470 " default: throw new AssertionError(id);", 471 " }", 472 " }", 473 " }", 474 "}") 475 .build()); 476 } 477 } 478