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