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 import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION; 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 SetBindingRequestFulfillmentWithGuavaTest { 35 @Parameters(name = "{0}") parameters()36 public static Collection<Object[]> parameters() { 37 return CompilerMode.TEST_PARAMETERS; 38 } 39 40 private final CompilerMode compilerMode; 41 SetBindingRequestFulfillmentWithGuavaTest(CompilerMode compilerMode)42 public SetBindingRequestFulfillmentWithGuavaTest(CompilerMode compilerMode) { 43 this.compilerMode = compilerMode; 44 } 45 46 @Test setBindings()47 public void setBindings() { 48 JavaFileObject emptySetModuleFile = JavaFileObjects.forSourceLines("test.EmptySetModule", 49 "package test;", 50 "", 51 "import dagger.Module;", 52 "import dagger.Provides;", 53 "import dagger.multibindings.ElementsIntoSet;", 54 "import dagger.multibindings.Multibinds;", 55 "import java.util.Collections;", 56 "import java.util.Set;", 57 "", 58 "@Module", 59 "abstract class EmptySetModule {", 60 " @Multibinds abstract Set<Object> objects();", 61 "", 62 " @Provides @ElementsIntoSet", 63 " static Set<String> emptySet() { ", 64 " return Collections.emptySet();", 65 " }", 66 " @Provides @ElementsIntoSet", 67 " static Set<Integer> onlyContributionIsElementsIntoSet() { ", 68 " return Collections.emptySet();", 69 " }", 70 "}"); 71 JavaFileObject setModuleFile = JavaFileObjects.forSourceLines("test.SetModule", 72 "package test;", 73 "", 74 "import dagger.Module;", 75 "import dagger.Provides;", 76 "import dagger.multibindings.IntoSet;", 77 "", 78 "@Module", 79 "final class SetModule {", 80 " @Provides @IntoSet static String string() { return \"\"; }", 81 "}"); 82 JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent", 83 "package test;", 84 "", 85 "import dagger.Component;", 86 "import java.util.Set;", 87 "import javax.inject.Provider;", 88 "", 89 "@Component(modules = {EmptySetModule.class, SetModule.class})", 90 "interface TestComponent {", 91 " Set<String> strings();", 92 " Set<Object> objects();", 93 " Set<Integer> onlyContributionIsElementsIntoSet();", 94 "}"); 95 JavaFileObject generatedComponent = 96 JavaFileObjects.forSourceLines( 97 "test.DaggerTestComponent", 98 "package test;", 99 "", 100 "import com.google.common.collect.ImmutableSet;", 101 "", 102 GENERATED_CODE_ANNOTATIONS, 103 "final class DaggerTestComponent implements TestComponent {", 104 " @Override", 105 " public Set<String> strings() {", 106 " return ImmutableSet.<String>builderWithExpectedSize(2)", 107 " .addAll(EmptySetModule_EmptySetFactory.emptySet())", 108 " .add(SetModule_StringFactory.string())", 109 " .build();", 110 " }", 111 "", 112 " @Override", 113 " public Set<Object> objects() {", 114 " return ImmutableSet.<Object>of();", 115 " }", 116 "", 117 " @Override", 118 " public Set<Integer> onlyContributionIsElementsIntoSet() {", 119 " return ImmutableSet.<Integer>copyOf(", 120 " EmptySetModule_OnlyContributionIsElementsIntoSetFactory", 121 " .onlyContributionIsElementsIntoSet());", 122 " }", 123 "}"); 124 Compilation compilation = 125 compilerWithOptions(compilerMode.javacopts()) 126 .compile(emptySetModuleFile, setModuleFile, componentFile); 127 assertThat(compilation).succeeded(); 128 assertThat(compilation) 129 .generatedSourceFile("test.DaggerTestComponent") 130 .containsElementsIn(generatedComponent); 131 } 132 133 @Test inaccessible()134 public void inaccessible() { 135 JavaFileObject inaccessible = 136 JavaFileObjects.forSourceLines( 137 "other.Inaccessible", 138 "package other;", 139 "", 140 "class Inaccessible {}"); 141 JavaFileObject inaccessible2 = 142 JavaFileObjects.forSourceLines( 143 "other.Inaccessible2", 144 "package other;", 145 "", 146 "class Inaccessible2 {}"); 147 JavaFileObject usesInaccessible = 148 JavaFileObjects.forSourceLines( 149 "other.UsesInaccessible", 150 "package other;", 151 "", 152 "import java.util.Set;", 153 "import javax.inject.Inject;", 154 "", 155 "public class UsesInaccessible {", 156 " @Inject UsesInaccessible(Set<Inaccessible> set1, Set<Inaccessible2> set2) {}", 157 "}"); 158 159 JavaFileObject module = 160 JavaFileObjects.forSourceLines( 161 "other.TestModule", 162 "package other;", 163 "", 164 "import dagger.Module;", 165 "import dagger.Provides;", 166 "import dagger.multibindings.ElementsIntoSet;", 167 "import dagger.multibindings.Multibinds;", 168 "import java.util.Collections;", 169 "import java.util.Set;", 170 "", 171 "@Module", 172 "public abstract class TestModule {", 173 " @Multibinds abstract Set<Inaccessible> objects();", 174 "", 175 " @Provides @ElementsIntoSet", 176 " static Set<Inaccessible2> emptySet() { ", 177 " return Collections.emptySet();", 178 " }", 179 "}"); 180 JavaFileObject componentFile = 181 JavaFileObjects.forSourceLines( 182 "test.TestComponent", 183 "package test;", 184 "", 185 "import dagger.Component;", 186 "import java.util.Set;", 187 "import javax.inject.Provider;", 188 "import other.TestModule;", 189 "import other.UsesInaccessible;", 190 "", 191 "@Component(modules = TestModule.class)", 192 "interface TestComponent {", 193 " UsesInaccessible usesInaccessible();", 194 "}"); 195 JavaFileObject generatedComponent = 196 JavaFileObjects.forSourceLines( 197 "test.DaggerTestComponent", 198 "package test;", 199 "", 200 "import com.google.common.collect.ImmutableSet;", 201 "import other.TestModule_EmptySetFactory;", 202 "import other.UsesInaccessible;", 203 "import other.UsesInaccessible_Factory;", 204 "", 205 GENERATED_CODE_ANNOTATIONS, 206 "final class DaggerTestComponent implements TestComponent {", 207 " private Set setOfInaccessible2() {", 208 " return ImmutableSet.copyOf(TestModule_EmptySetFactory.emptySet());", 209 " }", 210 "", 211 " @Override", 212 " public UsesInaccessible usesInaccessible() {", 213 " return UsesInaccessible_Factory.newInstance(", 214 " (Set) ImmutableSet.of(),", 215 " (Set) setOfInaccessible2());", 216 " }", 217 "}"); 218 Compilation compilation = 219 compilerWithOptions(compilerMode.javacopts()) 220 .compile(module, inaccessible, inaccessible2, usesInaccessible, componentFile); 221 assertThat(compilation).succeeded(); 222 assertThat(compilation) 223 .generatedSourceFile("test.DaggerTestComponent") 224 .containsElementsIn(generatedComponent); 225 } 226 227 @Test subcomponentOmitsInheritedBindings()228 public void subcomponentOmitsInheritedBindings() { 229 JavaFileObject parent = 230 JavaFileObjects.forSourceLines( 231 "test.Parent", 232 "package test;", 233 "", 234 "import dagger.Component;", 235 "", 236 "@Component(modules = ParentModule.class)", 237 "interface Parent {", 238 " Child child();", 239 "}"); 240 JavaFileObject parentModule = 241 JavaFileObjects.forSourceLines( 242 "test.ParentModule", 243 "package test;", 244 "", 245 "import dagger.Module;", 246 "import dagger.Provides;", 247 "import dagger.multibindings.IntoSet;", 248 "import dagger.multibindings.StringKey;", 249 "", 250 "@Module", 251 "class ParentModule {", 252 " @Provides @IntoSet static Object parentObject() {", 253 " return \"parent object\";", 254 " }", 255 "}"); 256 JavaFileObject child = 257 JavaFileObjects.forSourceLines( 258 "test.Child", 259 "package test;", 260 "", 261 "import dagger.Subcomponent;", 262 "import java.util.Set;", 263 "", 264 "@Subcomponent", 265 "interface Child {", 266 " Set<Object> objectSet();", 267 "}"); 268 JavaFileObject generatedComponent = 269 JavaFileObjects.forSourceLines( 270 "test.DaggerParent", 271 "package test;", 272 "", 273 "import com.google.common.collect.ImmutableSet;", 274 "", 275 GENERATED_CODE_ANNOTATIONS, 276 "final class DaggerParent implements Parent {", 277 " private final class ChildImpl implements Child {", 278 " @Override", 279 " public Set<Object> objectSet() {", 280 " return ImmutableSet.<Object>of(", 281 " ParentModule_ParentObjectFactory.parentObject());", 282 " }", 283 " }", 284 "}"); 285 Compilation compilation = 286 compilerWithOptions(compilerMode.javacopts()).compile(parent, parentModule, child); 287 assertThat(compilation).succeeded(); 288 assertThat(compilation) 289 .generatedSourceFile("test.DaggerParent") 290 .containsElementsIn(generatedComponent); 291 } 292 293 @Test productionComponents()294 public void productionComponents() { 295 JavaFileObject emptySetModuleFile = JavaFileObjects.forSourceLines("test.EmptySetModule", 296 "package test;", 297 "", 298 "import dagger.Module;", 299 "import dagger.Provides;", 300 "import dagger.multibindings.ElementsIntoSet;", 301 "import java.util.Collections;", 302 "import java.util.Set;", 303 "", 304 "@Module", 305 "abstract class EmptySetModule {", 306 " @Provides @ElementsIntoSet", 307 " static Set<String> emptySet() { ", 308 " return Collections.emptySet();", 309 " }", 310 "}"); 311 JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent", 312 "package test;", 313 "", 314 "import com.google.common.util.concurrent.ListenableFuture;", 315 "import dagger.producers.ProductionComponent;", 316 "import java.util.Set;", 317 "", 318 "@ProductionComponent(modules = EmptySetModule.class)", 319 "interface TestComponent {", 320 " ListenableFuture<Set<String>> strings();", 321 "}"); 322 JavaFileObject generatedComponent = 323 JavaFileObjects.forSourceLines( 324 "test.DaggerTestComponent", 325 "package test;", 326 "", 327 "import com.google.common.collect.ImmutableSet;", 328 "import com.google.common.util.concurrent.Futures;", 329 "import com.google.common.util.concurrent.ListenableFuture;", 330 "import dagger.producers.internal.CancellationListener;", 331 "import java.util.Set;", 332 IMPORT_GENERATED_ANNOTATION, 333 "", 334 GENERATED_CODE_ANNOTATIONS, 335 "final class DaggerTestComponent implements TestComponent, " 336 + "CancellationListener {", 337 " private DaggerTestComponent() {}", 338 "", 339 " public static Builder builder() {", 340 " return new Builder();", 341 " }", 342 "", 343 " public static TestComponent create() {", 344 " return new Builder().build();", 345 " }", 346 "", 347 " private Set<String> setOfString() {", 348 " return ImmutableSet.<String>copyOf(", 349 " EmptySetModule_EmptySetFactory.emptySet());", 350 " }", 351 "", 352 " @Override", 353 " public ListenableFuture<Set<String>> strings() {", 354 " return Futures.immediateFuture(setOfString());", 355 " }", 356 "", 357 " @Override", 358 " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {}", 359 "", 360 " static final class Builder {", 361 " private Builder() {}", 362 "", 363 " public TestComponent build() {", 364 " return new DaggerTestComponent();", 365 " }", 366 " }", 367 "}"); 368 369 Compilation compilation = 370 compilerWithOptions(compilerMode.javacopts()) 371 .compile(emptySetModuleFile, componentFile); 372 assertThat(compilation).succeeded(); 373 assertThat(compilation) 374 .generatedSourceFile("test.DaggerTestComponent") 375 .hasSourceEquivalentTo(generatedComponent); 376 } 377 } 378