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.Compilers.daggerCompiler; 21 import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION; 22 import static dagger.internal.codegen.GeneratedLines.NPE_FROM_COMPONENT_METHOD; 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 daggerCompiler().withOptions(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 GENERATED_ANNOTATION, 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 daggerCompiler() 166 .withOptions(compilerMode.javacopts()) 167 .compile(module, otherPackageModule, component); 168 assertThat(compilation).succeeded(); 169 JavaFileObject generatedComponent = 170 JavaFileObjects.forSourceLines( 171 "test.DaggerTestComponent", 172 "package test;", 173 "", 174 "import other.OtherPackageModule;", 175 "import other.OtherPackageModule_LFactory;", 176 "", 177 GENERATED_ANNOTATION, 178 "final class DaggerTestComponent implements TestComponent {", 179 " private final ParentModule parentModule;", 180 " private final OtherPackageModule otherPackageModule;", 181 "", 182 " @Override", 183 " public int i() {", 184 " return parentModule.i();", 185 " }", 186 "", 187 " @Override", 188 " public long l() {", 189 " return OtherPackageModule_LFactory.l(otherPackageModule);", 190 " }", 191 "}"); 192 assertThat(compilation) 193 .generatedSourceFile("test.DaggerTestComponent") 194 .containsElementsIn(generatedComponent); 195 } 196 197 @Test componentInstances()198 public void componentInstances() { 199 JavaFileObject dependency = 200 JavaFileObjects.forSourceLines( 201 "test.Dep", 202 "package test;", 203 "", 204 "interface Dep {", 205 " String string();", 206 " Object object();", 207 "}"); 208 209 JavaFileObject component = 210 JavaFileObjects.forSourceLines( 211 "test.TestComponent", 212 "package test;", 213 "", 214 "import dagger.Component;", 215 "", 216 "@Component(dependencies = Dep.class)", 217 "interface TestComponent {", 218 " TestComponent self();", 219 " TestSubcomponent subcomponent();", 220 "", 221 " Dep dep();", 222 " String methodOnDep();", 223 " Object otherMethodOnDep();", 224 "}"); 225 JavaFileObject subcomponent = 226 JavaFileObjects.forSourceLines( 227 "test.TestComponent", 228 "package test;", 229 "", 230 "import dagger.Subcomponent;", 231 "", 232 "@Subcomponent", 233 "interface TestSubcomponent {", 234 " TestComponent parent();", 235 " Dep depFromSubcomponent();", 236 "}"); 237 238 Compilation compilation = 239 daggerCompiler() 240 .withOptions(compilerMode.javacopts()) 241 .compile(dependency, component, subcomponent); 242 assertThat(compilation).succeeded(); 243 assertThat(compilation) 244 .generatedSourceFile("test.DaggerTestComponent") 245 .containsElementsIn( 246 JavaFileObjects.forSourceLines( 247 "test.DaggerTestComponent", 248 "package test;", 249 "", 250 GENERATED_ANNOTATION, 251 "final class DaggerTestComponent implements TestComponent {", 252 " private final Dep dep;", 253 "", 254 " private DaggerTestComponent(Dep depParam) {", 255 " this.dep = depParam;", 256 " }", 257 "", 258 " @Override", 259 " public TestComponent self() {", 260 " return this;", 261 " }", 262 "", 263 " @Override", 264 " public Dep dep() {", 265 " return dep;", 266 " }", 267 "", 268 " @Override", 269 " public String methodOnDep() {", 270 " return Preconditions.checkNotNull(", 271 " dep.string(), " + NPE_FROM_COMPONENT_METHOD + " );", 272 " }", 273 "", 274 " @Override", 275 " public Object otherMethodOnDep() {", 276 " return Preconditions.checkNotNull(", 277 " dep.object(), " + NPE_FROM_COMPONENT_METHOD + " );", 278 " }", 279 "", 280 " private final class TestSubcomponentImpl implements TestSubcomponent {", 281 " @Override", 282 " public TestComponent parent() {", 283 " return DaggerTestComponent.this;", 284 " }", 285 "", 286 " @Override", 287 " public Dep depFromSubcomponent() {", 288 " return DaggerTestComponent.this.dep;", 289 " }", 290 " }", 291 "}")); 292 } 293 294 @Test componentRequirementNeededInFactoryCreationOfSubcomponent()295 public void componentRequirementNeededInFactoryCreationOfSubcomponent() { 296 JavaFileObject parentModule = 297 JavaFileObjects.forSourceLines( 298 "test.ParentModule", 299 "package test;", 300 "", 301 "import dagger.Module;", 302 "import dagger.multibindings.IntoSet;", 303 "import dagger.Provides;", 304 "import java.util.Set;", 305 "", 306 "@Module", 307 "class ParentModule {", 308 " @Provides", 309 // intentionally non-static. this needs to require the module when the subcompnent 310 // adds to the Set binding 311 " Object reliesOnMultibinding(Set<Object> set) { return set; }", 312 "", 313 " @Provides @IntoSet static Object contribution() { return new Object(); }", 314 "}"); 315 316 JavaFileObject childModule = 317 JavaFileObjects.forSourceLines( 318 "test.ChildModule", 319 "package test;", 320 "", 321 "import dagger.Module;", 322 "import dagger.multibindings.IntoSet;", 323 "import dagger.Provides;", 324 "", 325 "@Module", 326 "class ChildModule {", 327 " @Provides @IntoSet static Object contribution() { return new Object(); }", 328 "}"); 329 330 JavaFileObject component = 331 JavaFileObjects.forSourceLines( 332 "test.TestComponent", 333 "package test;", 334 "", 335 "import dagger.Component;", 336 "import javax.inject.Provider;", 337 "", 338 "@Component(modules = ParentModule.class)", 339 "interface TestComponent {", 340 " Provider<Object> dependsOnMultibinding();", 341 " TestSubcomponent subcomponent();", 342 "}"); 343 344 JavaFileObject subcomponent = 345 JavaFileObjects.forSourceLines( 346 "test.TestSubcomponent", 347 "package test;", 348 "", 349 "import dagger.Subcomponent;", 350 "import javax.inject.Provider;", 351 "", 352 "@Subcomponent(modules = ChildModule.class)", 353 "interface TestSubcomponent {", 354 " Provider<Object> dependsOnMultibinding();", 355 "}"); 356 JavaFileObject generatedComponent; 357 switch (compilerMode) { 358 case FAST_INIT_MODE: 359 generatedComponent = 360 JavaFileObjects.forSourceLines( 361 "test.DaggerTestComponent", 362 "package test;", 363 "", 364 GENERATED_ANNOTATION, 365 "final class DaggerTestComponent implements TestComponent {", 366 " private final ParentModule parentModule;", 367 "", 368 " private DaggerTestComponent(ParentModule parentModuleParam) {", 369 " this.parentModule = parentModuleParam;", 370 " }", 371 "", 372 " private final class TestSubcomponentImpl implements TestSubcomponent {", 373 " private Set<Object> getSetOfObject() {", 374 " return ImmutableSet.<Object>of(", 375 " ParentModule_ContributionFactory.contribution(),", 376 " ChildModule_ContributionFactory.contribution());", 377 " }", 378 "", 379 " private Object getObject() {", 380 " return ParentModule_ReliesOnMultibindingFactory.reliesOnMultibinding(", 381 " DaggerTestComponent.this.parentModule, getSetOfObject());", 382 " }", 383 " }", 384 "}"); 385 break; 386 default: 387 generatedComponent = 388 JavaFileObjects.forSourceLines( 389 "test.DaggerTestComponent", 390 "package test;", 391 "", 392 GENERATED_ANNOTATION, 393 "final class DaggerTestComponent implements TestComponent {", 394 " private final ParentModule parentModule;", 395 "", 396 " private DaggerTestComponent(ParentModule parentModuleParam) {", 397 " this.parentModule = parentModuleParam;", 398 " initialize(parentModuleParam);", 399 " }", 400 "", 401 " @SuppressWarnings(\"unchecked\")", 402 " private void initialize(final ParentModule parentModuleParam) {", 403 " this.setOfObjectProvider =", 404 " SetFactory.<Object>builder(1, 0)", 405 " .addProvider(ParentModule_ContributionFactory.create())", 406 " .build();", 407 " this.reliesOnMultibindingProvider =", 408 " ParentModule_ReliesOnMultibindingFactory.create(", 409 " parentModuleParam, setOfObjectProvider);", 410 " }", 411 "", 412 " private final class TestSubcomponentImpl implements TestSubcomponent {", 413 " @SuppressWarnings(\"unchecked\")", 414 " private void initialize() {", 415 " this.setOfObjectProvider =", 416 " SetFactory.<Object>builder(2, 0)", 417 " .addProvider(ParentModule_ContributionFactory.create())", 418 " .addProvider(ChildModule_ContributionFactory.create())", 419 " .build();", 420 " this.reliesOnMultibindingProvider =", 421 " ParentModule_ReliesOnMultibindingFactory.create(", 422 " DaggerTestComponent.this.parentModule, setOfObjectProvider);", 423 " }", 424 " }", 425 "}"); 426 } 427 Compilation compilation = 428 daggerCompiler() 429 .withOptions(compilerMode.javacopts()) 430 .compile(parentModule, childModule, component, subcomponent); 431 assertThat(compilation).succeeded(); 432 assertThat(compilation) 433 .generatedSourceFile("test.DaggerTestComponent") 434 .containsElementsIn(generatedComponent); 435 } 436 } 437