• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 
22 import com.google.testing.compile.Compilation;
23 import com.google.testing.compile.JavaFileObjects;
24 import javax.tools.JavaFileObject;
25 import org.junit.Test;
26 import org.junit.runner.RunWith;
27 import org.junit.runners.JUnit4;
28 
29 @RunWith(JUnit4.class)
30 public class MultibindingTest {
31 
32   @Test
providesWithTwoMultibindingAnnotations_failsToCompile()33   public void providesWithTwoMultibindingAnnotations_failsToCompile() {
34     JavaFileObject module =
35         JavaFileObjects.forSourceLines(
36             "test.MultibindingModule",
37             "package test;",
38             "",
39             "import dagger.Module;",
40             "import dagger.Provides;",
41             "import dagger.multibindings.IntoSet;",
42             "import dagger.multibindings.IntoMap;",
43             "",
44             "@Module",
45             "class MultibindingModule {",
46             "  @Provides @IntoSet @IntoMap Integer provideInt() { ",
47             "    return 1;",
48             "  }",
49             "}");
50 
51     Compilation compilation = daggerCompiler().compile(module);
52     assertThat(compilation).failed();
53     assertThat(compilation)
54         .hadErrorContaining("@Provides methods cannot have more than one multibinding annotation")
55         .inFile(module)
56         .onLine(10);
57   }
58 
59   @Test
appliedOnInvalidMethods_failsToCompile()60   public void appliedOnInvalidMethods_failsToCompile() {
61     JavaFileObject someType =
62         JavaFileObjects.forSourceLines(
63             "test.SomeType",
64             "package test;",
65             "",
66             "import java.util.Set;",
67             "import java.util.Map;",
68             "import dagger.Component;",
69             "import dagger.multibindings.IntoSet;",
70             "import dagger.multibindings.ElementsIntoSet;",
71             "import dagger.multibindings.IntoMap;",
72             "",
73             "interface SomeType {",
74             "  @IntoSet Set<Integer> ints();",
75             "  @ElementsIntoSet Set<Double> doubles();",
76             "  @IntoMap Map<Integer, Double> map();",
77             "}");
78 
79     Compilation compilation = daggerCompiler().compile(someType);
80     assertThat(compilation).failed();
81     assertThat(compilation)
82         .hadErrorContaining(
83             "Multibinding annotations may only be on @Provides, @Produces, or @Binds methods")
84         .inFile(someType)
85         .onLineContaining("ints();");
86     assertThat(compilation)
87         .hadErrorContaining(
88             "Multibinding annotations may only be on @Provides, @Produces, or @Binds methods")
89         .inFile(someType)
90         .onLineContaining("doubles();");
91     assertThat(compilation)
92         .hadErrorContaining(
93             "Multibinding annotations may only be on @Provides, @Produces, or @Binds methods")
94         .inFile(someType)
95         .onLineContaining("map();");
96   }
97 
98   @Test
concreteBindingForMultibindingAlias()99   public void concreteBindingForMultibindingAlias() {
100     JavaFileObject module =
101         JavaFileObjects.forSourceLines(
102             "test.TestModule",
103             "package test;",
104             "",
105             "import dagger.Module;",
106             "import dagger.Provides;",
107             "import java.util.Collections;",
108             "import java.util.Map;",
109             "import javax.inject.Provider;",
110             "",
111             "@Module",
112             "class TestModule {",
113             "  @Provides",
114             "  Map<String, Provider<String>> mapOfStringToProviderOfString() {",
115             "    return Collections.emptyMap();",
116             "  }",
117             "}");
118     JavaFileObject component =
119         JavaFileObjects.forSourceLines(
120             "test.TestComponent",
121             "package test;",
122             "",
123             "import dagger.Component;",
124             "import java.util.Map;",
125             "",
126             "@Component(modules = TestModule.class)",
127             "interface TestComponent {",
128             "  Map<String, String> mapOfStringToString();",
129             "}");
130     Compilation compilation = daggerCompiler().compile(module, component);
131     assertThat(compilation).failed();
132     assertThat(compilation)
133         .hadErrorContaining(
134             "Map<String,String> "
135                 + "cannot be provided without an @Provides-annotated method")
136         .inFile(component)
137         .onLineContaining("interface TestComponent");
138   }
139 
140   @Test
produceConcreteSet_andRequestSetOfProduced()141   public void produceConcreteSet_andRequestSetOfProduced() {
142     JavaFileObject module =
143         JavaFileObjects.forSourceLines(
144             "test.TestModule",
145             "package test;",
146             "",
147             "import dagger.producers.ProducerModule;",
148             "import dagger.producers.Produces;",
149             "import java.util.Collections;",
150             "import java.util.Set;",
151             "",
152             "@ProducerModule",
153             "class TestModule {",
154             "  @Produces",
155             "  Set<String> setOfString() {",
156             "    return Collections.emptySet();",
157             "  }",
158             "}");
159     JavaFileObject component =
160         JavaFileObjects.forSourceLines(
161             "test.TestComponent",
162             "package test;",
163             "",
164             "import com.google.common.util.concurrent.ListenableFuture;",
165             "import dagger.BindsInstance;",
166             "import dagger.producers.Produced;",
167             "import dagger.producers.Production;",
168             "import dagger.producers.ProductionComponent;",
169             "import java.util.concurrent.Executor;",
170             "import java.util.Set;",
171             "",
172             "@ProductionComponent(modules = TestModule.class)",
173             "interface TestComponent {",
174             "  ListenableFuture<Set<Produced<String>>> setOfProduced();",
175             "",
176             "  @ProductionComponent.Builder",
177             "  interface Builder {",
178             "    @BindsInstance Builder executor(@Production Executor executor);",
179             "    TestComponent build();",
180             "  }",
181             "}");
182     Compilation compilation = daggerCompiler().compile(module, component);
183     assertThat(compilation).failed();
184     assertThat(compilation)
185         .hadErrorContaining(
186             "Set<Produced<String>> "
187                 + "cannot be provided without an @Provides- or @Produces-annotated method")
188         .inFile(component)
189         .onLineContaining("interface TestComponent");
190   }
191 
192   @Test
provideExplicitSetInParent_AndMultibindingContributionInChild()193   public void provideExplicitSetInParent_AndMultibindingContributionInChild() {
194     JavaFileObject parent =
195         JavaFileObjects.forSourceLines(
196             "test.Parent",
197             "package test;",
198             "",
199             "import dagger.Component;",
200             "import java.util.Set;",
201             "",
202             "@Component(modules = ParentModule.class)",
203             "interface Parent {",
204             "  Set<String> set();",
205             "  Child child();",
206             "}");
207     JavaFileObject parentModule =
208         JavaFileObjects.forSourceLines(
209             "test.ParentModule",
210             "package test;",
211             "",
212             "import dagger.Module;",
213             "import dagger.Provides;",
214             "import java.util.HashSet;",
215             "import java.util.Set;",
216             "",
217             "@Module",
218             "class ParentModule {",
219             "  @Provides",
220             "  Set<String> set() {",
221             "    return new HashSet();",
222             "  }",
223             "}");
224 
225     JavaFileObject child =
226         JavaFileObjects.forSourceLines(
227             "test.Child",
228             "package test;",
229             "",
230             "import dagger.Subcomponent;",
231             "import java.util.Set;",
232             "",
233             "@Subcomponent(modules = ChildModule.class)",
234             "interface Child {",
235             "  Set<String> set();",
236             "}");
237     JavaFileObject childModule =
238         JavaFileObjects.forSourceLines(
239             "test.ChildModule",
240             "package test;",
241             "",
242             "import dagger.Module;",
243             "import dagger.multibindings.IntoSet;",
244             "import dagger.Provides;",
245             "",
246             "@Module",
247             "class ChildModule {",
248             "  @Provides",
249             "  @IntoSet",
250             "  String setContribution() {",
251             "    return new String();",
252             "  }",
253             "}");
254 
255     Compilation compilation = daggerCompiler().compile(parent, parentModule, child, childModule);
256     assertThat(compilation).failed();
257     assertThat(compilation)
258         .hadErrorContaining("incompatible bindings or declarations")
259         .inFile(parent)
260         .onLineContaining("interface Parent");
261   }
262 }
263