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 
23 import com.google.testing.compile.Compilation;
24 import com.google.testing.compile.Compiler;
25 import com.google.testing.compile.JavaFileObjects;
26 import dagger.testing.golden.GoldenFileRule;
27 import java.util.Collection;
28 import javax.tools.JavaFileObject;
29 import org.junit.Rule;
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   @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule();
43 
44   private final CompilerMode compilerMode;
45 
SetBindingRequestFulfillmentTest(CompilerMode compilerMode)46   public SetBindingRequestFulfillmentTest(CompilerMode compilerMode) {
47     this.compilerMode = compilerMode;
48   }
49 
50   @Test
setBindings()51   public void setBindings() throws Exception {
52     JavaFileObject emptySetModuleFile = JavaFileObjects.forSourceLines("test.EmptySetModule",
53         "package test;",
54         "",
55         "import dagger.Module;",
56         "import dagger.Provides;",
57         "import dagger.multibindings.ElementsIntoSet;",
58         "import dagger.multibindings.Multibinds;",
59         "import java.util.Collections;",
60         "import java.util.Set;",
61         "",
62         "@Module",
63         "abstract class EmptySetModule {",
64         "  @Multibinds abstract Set<Object> objects();",
65         "",
66         "  @Provides @ElementsIntoSet",
67         "  static Set<String> emptySet() { ",
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         "}");
94 
95     Compilation compilation =
96         daggerCompilerWithoutGuava().compile(emptySetModuleFile, setModuleFile, componentFile);
97     assertThat(compilation).succeeded();
98     assertThat(compilation)
99         .generatedSourceFile("test.DaggerTestComponent")
100         .hasSourceEquivalentTo(goldenFileRule.goldenFile("test.DaggerTestComponent"));
101   }
102 
103   @Test
inaccessible()104   public void inaccessible() throws Exception {
105     JavaFileObject inaccessible =
106         JavaFileObjects.forSourceLines(
107             "other.Inaccessible",
108             "package other;",
109             "",
110             "class Inaccessible {}");
111     JavaFileObject inaccessible2 =
112         JavaFileObjects.forSourceLines(
113             "other.Inaccessible2",
114             "package other;",
115             "",
116             "class Inaccessible2 {}");
117     JavaFileObject usesInaccessible =
118         JavaFileObjects.forSourceLines(
119             "other.UsesInaccessible",
120             "package other;",
121             "",
122             "import java.util.Set;",
123             "import javax.inject.Inject;",
124             "",
125             "public class UsesInaccessible {",
126             "  @Inject UsesInaccessible(Set<Inaccessible> set1, Set<Inaccessible2> set2) {}",
127             "}");
128 
129     JavaFileObject module =
130         JavaFileObjects.forSourceLines(
131             "other.TestModule",
132             "package other;",
133             "",
134             "import dagger.Module;",
135             "import dagger.Provides;",
136             "import dagger.multibindings.ElementsIntoSet;",
137             "import dagger.multibindings.Multibinds;",
138             "import java.util.Collections;",
139             "import java.util.Set;",
140             "",
141             "@Module",
142             "public abstract class TestModule {",
143             "  @Multibinds abstract Set<Inaccessible> objects();",
144             "",
145             "  @Provides @ElementsIntoSet",
146             "  static Set<Inaccessible2> emptySet() { ",
147             "    return Collections.emptySet();",
148             "  }",
149             "}");
150     JavaFileObject componentFile =
151         JavaFileObjects.forSourceLines(
152             "test.TestComponent",
153             "package test;",
154             "",
155             "import dagger.Component;",
156             "import java.util.Set;",
157             "import javax.inject.Provider;",
158             "import other.TestModule;",
159             "import other.UsesInaccessible;",
160             "",
161             "@Component(modules = TestModule.class)",
162             "interface TestComponent {",
163             "  UsesInaccessible usesInaccessible();",
164             "}");
165 
166     Compilation compilation =
167         daggerCompilerWithoutGuava()
168             .compile(module, inaccessible, inaccessible2, usesInaccessible, componentFile);
169     assertThat(compilation).succeeded();
170     assertThat(compilation)
171         .generatedSourceFile("test.DaggerTestComponent")
172         .hasSourceEquivalentTo(goldenFileRule.goldenFile("test.DaggerTestComponent"));
173   }
174 
175   @Test
subcomponentOmitsInheritedBindings()176   public void subcomponentOmitsInheritedBindings() throws Exception {
177     JavaFileObject parent =
178         JavaFileObjects.forSourceLines(
179             "test.Parent",
180             "package test;",
181             "",
182             "import dagger.Component;",
183             "",
184             "@Component(modules = ParentModule.class)",
185             "interface Parent {",
186             "  Child child();",
187             "}");
188     JavaFileObject parentModule =
189         JavaFileObjects.forSourceLines(
190             "test.ParentModule",
191             "package test;",
192             "",
193             "import dagger.Module;",
194             "import dagger.Provides;",
195             "import dagger.multibindings.IntoSet;",
196             "import dagger.multibindings.StringKey;",
197             "",
198             "@Module",
199             "class ParentModule {",
200             "  @Provides @IntoSet static Object parentObject() {",
201             "    return \"parent object\";",
202             "  }",
203             "}");
204     JavaFileObject child =
205         JavaFileObjects.forSourceLines(
206             "test.Child",
207             "package test;",
208             "",
209             "import dagger.Subcomponent;",
210             "import java.util.Set;",
211             "",
212             "@Subcomponent",
213             "interface Child {",
214             "  Set<Object> objectSet();",
215             "}");
216 
217     Compilation compilation = daggerCompilerWithoutGuava().compile(parent, parentModule, child);
218     assertThat(compilation).succeeded();
219     assertThat(compilation)
220         .generatedSourceFile("test.DaggerParent")
221         .hasSourceEquivalentTo(goldenFileRule.goldenFile("test.DaggerTestComponent"));
222   }
223 
daggerCompilerWithoutGuava()224   private Compiler daggerCompilerWithoutGuava() {
225     return compilerWithOptions(compilerMode.javacopts())
226         .withClasspath(CLASS_PATH_WITHOUT_GUAVA_OPTION);
227   }
228 }
229