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.CLASS_PATH_WITHOUT_GUAVA_OPTION; 21 import static dagger.internal.codegen.Compilers.compilerWithOptions; 22 import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS; 23 import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION; 24 25 import com.google.testing.compile.Compilation; 26 import com.google.testing.compile.Compiler; 27 import com.google.testing.compile.JavaFileObjects; 28 import java.util.Collection; 29 import javax.tools.JavaFileObject; 30 import org.junit.Test; 31 import org.junit.runner.RunWith; 32 import org.junit.runners.Parameterized; 33 import org.junit.runners.Parameterized.Parameters; 34 35 @RunWith(Parameterized.class) 36 public class SetBindingRequestFulfillmentTest { 37 @Parameters(name = "{0}") parameters()38 public static Collection<Object[]> parameters() { 39 return CompilerMode.TEST_PARAMETERS; 40 } 41 42 private final CompilerMode compilerMode; 43 SetBindingRequestFulfillmentTest(CompilerMode compilerMode)44 public SetBindingRequestFulfillmentTest(CompilerMode compilerMode) { 45 this.compilerMode = compilerMode; 46 } 47 48 @Test setBindings()49 public void setBindings() { 50 JavaFileObject emptySetModuleFile = JavaFileObjects.forSourceLines("test.EmptySetModule", 51 "package test;", 52 "", 53 "import dagger.Module;", 54 "import dagger.Provides;", 55 "import dagger.multibindings.ElementsIntoSet;", 56 "import dagger.multibindings.Multibinds;", 57 "import java.util.Collections;", 58 "import java.util.Set;", 59 "", 60 "@Module", 61 "abstract class EmptySetModule {", 62 " @Multibinds abstract Set<Object> objects();", 63 "", 64 " @Provides @ElementsIntoSet", 65 " static Set<String> emptySet() { ", 66 " return Collections.emptySet();", 67 " }", 68 "}"); 69 JavaFileObject setModuleFile = JavaFileObjects.forSourceLines("test.SetModule", 70 "package test;", 71 "", 72 "import dagger.Module;", 73 "import dagger.Provides;", 74 "import dagger.multibindings.IntoSet;", 75 "", 76 "@Module", 77 "final class SetModule {", 78 " @Provides @IntoSet static String string() { return \"\"; }", 79 "}"); 80 JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent", 81 "package test;", 82 "", 83 "import dagger.Component;", 84 "import java.util.Set;", 85 "import javax.inject.Provider;", 86 "", 87 "@Component(modules = {EmptySetModule.class, SetModule.class})", 88 "interface TestComponent {", 89 " Set<String> strings();", 90 " Set<Object> objects();", 91 "}"); 92 JavaFileObject generatedComponent = 93 JavaFileObjects.forSourceLines( 94 "test.DaggerTestComponent", 95 "package test;", 96 "", 97 "import dagger.internal.SetBuilder;", 98 "", 99 GENERATED_CODE_ANNOTATIONS, 100 "final class DaggerTestComponent implements TestComponent {", 101 " @Override", 102 " public Set<String> strings() {", 103 " return SetBuilder.<String>newSetBuilder(2)", 104 " .addAll(EmptySetModule_EmptySetFactory.emptySet())", 105 " .add(SetModule_StringFactory.string())", 106 " .build();", 107 " }", 108 "", 109 " @Override", 110 " public Set<Object> objects() {", 111 " return Collections.<Object>emptySet();", 112 " }", 113 "}"); 114 Compilation compilation = 115 daggerCompilerWithoutGuava().compile(emptySetModuleFile, setModuleFile, componentFile); 116 assertThat(compilation).succeeded(); 117 assertThat(compilation) 118 .generatedSourceFile("test.DaggerTestComponent") 119 .containsElementsIn(generatedComponent); 120 } 121 122 @Test inaccessible()123 public void inaccessible() { 124 JavaFileObject inaccessible = 125 JavaFileObjects.forSourceLines( 126 "other.Inaccessible", 127 "package other;", 128 "", 129 "class Inaccessible {}"); 130 JavaFileObject inaccessible2 = 131 JavaFileObjects.forSourceLines( 132 "other.Inaccessible2", 133 "package other;", 134 "", 135 "class Inaccessible2 {}"); 136 JavaFileObject usesInaccessible = 137 JavaFileObjects.forSourceLines( 138 "other.UsesInaccessible", 139 "package other;", 140 "", 141 "import java.util.Set;", 142 "import javax.inject.Inject;", 143 "", 144 "public class UsesInaccessible {", 145 " @Inject UsesInaccessible(Set<Inaccessible> set1, Set<Inaccessible2> set2) {}", 146 "}"); 147 148 JavaFileObject module = 149 JavaFileObjects.forSourceLines( 150 "other.TestModule", 151 "package other;", 152 "", 153 "import dagger.Module;", 154 "import dagger.Provides;", 155 "import dagger.multibindings.ElementsIntoSet;", 156 "import dagger.multibindings.Multibinds;", 157 "import java.util.Collections;", 158 "import java.util.Set;", 159 "", 160 "@Module", 161 "public abstract class TestModule {", 162 " @Multibinds abstract Set<Inaccessible> objects();", 163 "", 164 " @Provides @ElementsIntoSet", 165 " static Set<Inaccessible2> emptySet() { ", 166 " return Collections.emptySet();", 167 " }", 168 "}"); 169 JavaFileObject componentFile = 170 JavaFileObjects.forSourceLines( 171 "test.TestComponent", 172 "package test;", 173 "", 174 "import dagger.Component;", 175 "import java.util.Set;", 176 "import javax.inject.Provider;", 177 "import other.TestModule;", 178 "import other.UsesInaccessible;", 179 "", 180 "@Component(modules = TestModule.class)", 181 "interface TestComponent {", 182 " UsesInaccessible usesInaccessible();", 183 "}"); 184 JavaFileObject generatedComponent = 185 JavaFileObjects.forSourceLines( 186 "test.DaggerTestComponent", 187 "package test;", 188 "", 189 "import dagger.internal.SetBuilder;", 190 "import other.TestModule_EmptySetFactory;", 191 "import other.UsesInaccessible;", 192 "import other.UsesInaccessible_Factory;", 193 "", 194 GENERATED_CODE_ANNOTATIONS, 195 "final class DaggerTestComponent implements TestComponent {", 196 " private Set setOfInaccessible2() {", 197 " return SetBuilder.newSetBuilder(1)", 198 " .addAll(TestModule_EmptySetFactory.emptySet())", 199 " .build();", 200 " }", 201 "", 202 " @Override", 203 " public UsesInaccessible usesInaccessible() {", 204 " return UsesInaccessible_Factory.newInstance(", 205 " (Set) Collections.emptySet(),", 206 " (Set) setOfInaccessible2());", 207 " }", 208 "}"); 209 Compilation compilation = 210 daggerCompilerWithoutGuava() 211 .compile(module, inaccessible, inaccessible2, usesInaccessible, componentFile); 212 assertThat(compilation).succeeded(); 213 assertThat(compilation) 214 .generatedSourceFile("test.DaggerTestComponent") 215 .containsElementsIn(generatedComponent); 216 } 217 218 @Test subcomponentOmitsInheritedBindings()219 public void subcomponentOmitsInheritedBindings() { 220 JavaFileObject parent = 221 JavaFileObjects.forSourceLines( 222 "test.Parent", 223 "package test;", 224 "", 225 "import dagger.Component;", 226 "", 227 "@Component(modules = ParentModule.class)", 228 "interface Parent {", 229 " Child child();", 230 "}"); 231 JavaFileObject parentModule = 232 JavaFileObjects.forSourceLines( 233 "test.ParentModule", 234 "package test;", 235 "", 236 "import dagger.Module;", 237 "import dagger.Provides;", 238 "import dagger.multibindings.IntoSet;", 239 "import dagger.multibindings.StringKey;", 240 "", 241 "@Module", 242 "class ParentModule {", 243 " @Provides @IntoSet static Object parentObject() {", 244 " return \"parent object\";", 245 " }", 246 "}"); 247 JavaFileObject child = 248 JavaFileObjects.forSourceLines( 249 "test.Child", 250 "package test;", 251 "", 252 "import dagger.Subcomponent;", 253 "import java.util.Set;", 254 "", 255 "@Subcomponent", 256 "interface Child {", 257 " Set<Object> objectSet();", 258 "}"); 259 JavaFileObject generatedComponent = 260 JavaFileObjects.forSourceLines( 261 "test.DaggerParent", 262 "package test;", 263 "", 264 "import dagger.internal.Preconditions;", 265 "import java.util.Collections;", 266 "import java.util.Set;", 267 IMPORT_GENERATED_ANNOTATION, 268 "", 269 GENERATED_CODE_ANNOTATIONS, 270 "final class DaggerParent implements Parent {", 271 " private DaggerParent() {}", 272 "", 273 " public static Builder builder() {", 274 " return new Builder();", 275 " }", 276 "", 277 " public static Parent create() {", 278 " return new Builder().build();", 279 " }", 280 "", 281 " @Override", 282 " public Child child() {", 283 " return new ChildImpl();", 284 " }", 285 "", 286 " static final class Builder {", 287 " private Builder() {}", 288 "", 289 " @Deprecated", 290 " public Builder parentModule(ParentModule parentModule) {", 291 " Preconditions.checkNotNull(parentModule);", 292 " return this;", 293 " }", 294 "", 295 " public Parent build() {", 296 " return new DaggerParent();", 297 " }", 298 " }", 299 "", 300 " private final class ChildImpl implements Child {", 301 " private ChildImpl() {}", 302 "", 303 " @Override", 304 " public Set<Object> objectSet() {", 305 " return Collections.<Object>singleton(", 306 " ParentModule_ParentObjectFactory.parentObject());", 307 " }", 308 " }", 309 "}"); 310 311 Compilation compilation = daggerCompilerWithoutGuava().compile(parent, parentModule, child); 312 assertThat(compilation).succeeded(); 313 assertThat(compilation) 314 .generatedSourceFile("test.DaggerParent") 315 .hasSourceEquivalentTo(generatedComponent); 316 } 317 daggerCompilerWithoutGuava()318 private Compiler daggerCompilerWithoutGuava() { 319 return compilerWithOptions(compilerMode.javacopts()) 320 .withClasspath(CLASS_PATH_WITHOUT_GUAVA_OPTION); 321 } 322 } 323