• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.CompilerMode.DEFAULT_MODE;
21 import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
22 import static dagger.internal.codegen.Compilers.CLASS_PATH_WITHOUT_GUAVA_OPTION;
23 import static dagger.internal.codegen.Compilers.compilerWithOptions;
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 MapRequestRepresentationTest {
37   @Parameters(name = "{0}")
parameters()38   public static Collection<Object[]> parameters() {
39     return CompilerMode.TEST_PARAMETERS;
40   }
41 
42   private final CompilerMode compilerMode;
43 
MapRequestRepresentationTest(CompilerMode compilerMode)44   public MapRequestRepresentationTest(CompilerMode compilerMode) {
45     this.compilerMode = compilerMode;
46   }
47 
48   @Test
mapBindings()49   public void mapBindings() {
50     JavaFileObject mapModuleFile = JavaFileObjects.forSourceLines("test.MapModule",
51         "package test;",
52         "",
53         "import dagger.Module;",
54         "import dagger.Provides;",
55         "import dagger.multibindings.IntKey;",
56         "import dagger.multibindings.IntoMap;",
57         "import dagger.multibindings.LongKey;",
58         "import dagger.multibindings.Multibinds;",
59         "import java.util.Map;",
60         "",
61         "@Module",
62         "interface MapModule {",
63         "  @Multibinds Map<String, String> stringMap();",
64         "  @Provides @IntoMap @IntKey(0) static int provideInt() { return 0; }",
65         "  @Provides @IntoMap @LongKey(0) static long provideLong0() { return 0; }",
66         "  @Provides @IntoMap @LongKey(1) static long provideLong1() { return 1; }",
67         "  @Provides @IntoMap @LongKey(2) static long provideLong2() { return 2; }",
68         "}");
69     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
70         "package test;",
71         "",
72         "import dagger.Component;",
73         "import java.util.Map;",
74         "import javax.inject.Provider;",
75         "",
76         "@Component(modules = MapModule.class)",
77         "interface TestComponent {",
78         "  Map<String, String> strings();",
79         "  Map<String, Provider<String>> providerStrings();",
80         "",
81         "  Map<Integer, Integer> ints();",
82         "  Map<Integer, Provider<Integer>> providerInts();",
83         "  Map<Long, Long> longs();",
84         "  Map<Long, Provider<Long>> providerLongs();",
85         "}");
86     JavaFileObject generatedComponent =
87         compilerMode
88             .javaFileBuilder("test.DaggerTestComponent")
89             .addLines(
90                 "package test;",
91                 "",
92                 GeneratedLines.generatedAnnotations(),
93                 "final class DaggerTestComponent implements TestComponent {")
94             .addLinesIn(
95                 FAST_INIT_MODE,
96                 "  private Provider<Integer> provideIntProvider;",
97                 "  private Provider<Long> provideLong0Provider;",
98                 "  private Provider<Long> provideLong1Provider;",
99                 "  private Provider<Long> provideLong2Provider;",
100                 "",
101                 "  @SuppressWarnings(\"unchecked\")",
102                 "  private void initialize() {",
103                 "    this.provideIntProvider = new SwitchingProvider<>(testComponent, 0);",
104                 "    this.provideLong0Provider = new SwitchingProvider<>(testComponent, 1);",
105                 "    this.provideLong1Provider = new SwitchingProvider<>(testComponent, 2);",
106                 "    this.provideLong2Provider = new SwitchingProvider<>(testComponent, 3);",
107                 "  }")
108             .addLines(
109                 "  @Override",
110                 "  public Map<String, String> strings() {",
111                 "    return Collections.<String, String>emptyMap();",
112                 "  }",
113                 "",
114                 "  @Override",
115                 "  public Map<String, Provider<String>> providerStrings() {",
116                 "    return Collections.<String, Provider<String>>emptyMap();",
117                 "  }",
118                 "")
119             .addLinesIn(
120                 DEFAULT_MODE,
121                 "  @Override",
122                 "  public Map<Integer, Integer> ints() {",
123                 "    return Collections.<Integer, Integer>",
124                 "        singletonMap(0, MapModule.provideInt());",
125                 "  }")
126             .addLinesIn(
127                 FAST_INIT_MODE,
128                 "  @Override",
129                 "  public Map<Integer, Integer> ints() {",
130                 "    return Collections.<Integer, Integer>singletonMap(0,"
131                     + " provideIntProvider.get());",
132                 "  }")
133             .addLines(
134                 "  @Override",
135                 "  public Map<Integer, Provider<Integer>> providerInts() {",
136                 "    return Collections.<Integer, Provider<Integer>>singletonMap(")
137             .addLinesIn(
138                 DEFAULT_MODE, //
139                 "        0, MapModule_ProvideIntFactory.create());")
140             .addLinesIn(FAST_INIT_MODE, "        0, provideIntProvider;")
141             .addLinesIn(
142                 DEFAULT_MODE,
143                 "  }",
144                 "",
145                 "  @Override",
146                 "  public Map<Long, Long> longs() {",
147                 "    return MapBuilder.<Long, Long>newMapBuilder(3)",
148                 "        .put(0L, MapModule.provideLong0())",
149                 "        .put(1L, MapModule.provideLong1())",
150                 "        .put(2L, MapModule.provideLong2())",
151                 "        .build();",
152                 "  }")
153             .addLinesIn(
154                 FAST_INIT_MODE,
155                 "  }",
156                 "",
157                 "  @Override",
158                 "  public Map<Long, Long> longs() {",
159                 "    return MapBuilder.<Long, Long>newMapBuilder(3)",
160                 "        .put(0L, provideLong0Provider.get())",
161                 "        .put(1L, provideLong1Provider.get())",
162                 "        .put(2L, provideLong2Provider.get())",
163                 "        .build();",
164                 "  }")
165             .addLines(
166                 "  @Override",
167                 "  public Map<Long, Provider<Long>> providerLongs() {",
168                 "    return MapBuilder.<Long, Provider<Long>>newMapBuilder(3)")
169             .addLinesIn(
170                 DEFAULT_MODE,
171                 "        .put(0L, MapModule_ProvideLong0Factory.create())",
172                 "        .put(1L, MapModule_ProvideLong1Factory.create())",
173                 "        .put(2L, MapModule_ProvideLong2Factory.create())")
174             .addLinesIn(
175                 FAST_INIT_MODE,
176                 "        .put(0L, provideLong0Provider)",
177                 "        .put(1L, provideLong1Provider)",
178                 "        .put(2L, provideLong2Provider)")
179             .addLines( //
180                 "        .build();", "  }")
181             .addLinesIn(
182                 FAST_INIT_MODE,
183                 "  private static final class SwitchingProvider<T> implements Provider<T> {",
184                 "    @SuppressWarnings(\"unchecked\")",
185                 "    @Override",
186                 "    public T get() {",
187                 "      switch (id) {",
188                 "        case 0: return (T) (Integer) MapModule.provideInt();",
189                 "        case 1: return (T) (Long) MapModule.provideLong0();",
190                 "        case 2: return (T) (Long) MapModule.provideLong1();",
191                 "        case 3: return (T) (Long) MapModule.provideLong2();",
192                 "        default: throw new AssertionError(id);",
193                 "      }",
194                 "    }",
195                 "  }",
196                 "}")
197             .build();
198     Compilation compilation = daggerCompilerWithoutGuava().compile(mapModuleFile, componentFile);
199     assertThat(compilation).succeeded();
200     assertThat(compilation)
201         .generatedSourceFile("test.DaggerTestComponent")
202         .containsElementsIn(generatedComponent);
203   }
204 
205   @Test
inaccessible()206   public void inaccessible() {
207     JavaFileObject inaccessible =
208         JavaFileObjects.forSourceLines(
209             "other.Inaccessible",
210             "package other;",
211             "",
212             "class Inaccessible {}");
213     JavaFileObject usesInaccessible =
214         JavaFileObjects.forSourceLines(
215             "other.UsesInaccessible",
216             "package other;",
217             "",
218             "import java.util.Map;",
219             "import javax.inject.Inject;",
220             "",
221             "public class UsesInaccessible {",
222             "  @Inject UsesInaccessible(Map<Integer, Inaccessible> map) {}",
223             "}");
224 
225     JavaFileObject module =
226         JavaFileObjects.forSourceLines(
227             "other.TestModule",
228             "package other;",
229             "",
230             "import dagger.Module;",
231             "import dagger.multibindings.Multibinds;",
232             "import java.util.Map;",
233             "",
234             "@Module",
235             "public abstract class TestModule {",
236             "  @Multibinds abstract Map<Integer, Inaccessible> ints();",
237             "}");
238     JavaFileObject componentFile =
239         JavaFileObjects.forSourceLines(
240             "test.TestComponent",
241             "package test;",
242             "",
243             "import dagger.Component;",
244             "import java.util.Map;",
245             "import javax.inject.Provider;",
246             "import other.TestModule;",
247             "import other.UsesInaccessible;",
248             "",
249             "@Component(modules = TestModule.class)",
250             "interface TestComponent {",
251             "  UsesInaccessible usesInaccessible();",
252             "}");
253     JavaFileObject generatedComponent =
254         JavaFileObjects.forSourceLines(
255             "test.DaggerTestComponent",
256             "package test;",
257             "",
258             "import other.UsesInaccessible;",
259             "import other.UsesInaccessible_Factory;",
260             "",
261             GeneratedLines.generatedAnnotations(),
262             "final class DaggerTestComponent implements TestComponent {",
263             "  @Override",
264             "  public UsesInaccessible usesInaccessible() {",
265             "    return UsesInaccessible_Factory.newInstance(",
266             "        (Map) Collections.emptyMap());",
267             "  }",
268             "}");
269     Compilation compilation =
270         daggerCompilerWithoutGuava().compile(module, inaccessible, usesInaccessible, componentFile);
271     assertThat(compilation).succeeded();
272     assertThat(compilation)
273         .generatedSourceFile("test.DaggerTestComponent")
274         .containsElementsIn(generatedComponent);
275   }
276 
277   @Test
subcomponentOmitsInheritedBindings()278   public void subcomponentOmitsInheritedBindings() {
279     JavaFileObject parent =
280         JavaFileObjects.forSourceLines(
281             "test.Parent",
282             "package test;",
283             "",
284             "import dagger.Component;",
285             "",
286             "@Component(modules = ParentModule.class)",
287             "interface Parent {",
288             "  Child child();",
289             "}");
290     JavaFileObject parentModule =
291         JavaFileObjects.forSourceLines(
292             "test.ParentModule",
293             "package test;",
294             "",
295             "import dagger.Module;",
296             "import dagger.Provides;",
297             "import dagger.multibindings.IntoMap;",
298             "import dagger.multibindings.StringKey;",
299             "",
300             "@Module",
301             "class ParentModule {",
302             "  @Provides @IntoMap @StringKey(\"parent key\") Object parentKeyObject() {",
303             "    return \"parent value\";",
304             "  }",
305             "}");
306     JavaFileObject child =
307         JavaFileObjects.forSourceLines(
308             "test.Child",
309             "package test;",
310             "",
311             "import dagger.Subcomponent;",
312             "import java.util.Map;",
313             "import java.util.Map;",
314             "",
315             "@Subcomponent",
316             "interface Child {",
317             "  Map<String, Object> objectMap();",
318             "}");
319     JavaFileObject generatedComponent =
320         JavaFileObjects.forSourceLines(
321             "test.DaggerParent",
322             "package test;",
323             "",
324             GeneratedLines.generatedAnnotations(),
325             "final class DaggerParent implements Parent {",
326             "  private final ParentModule parentModule;",
327             "",
328             "  private static final class ChildImpl implements Child {",
329             "    @Override",
330             "    public Map<String, Object> objectMap() {",
331             "      return Collections.<String, Object>singletonMap(",
332             "          \"parent key\",",
333             "          ParentModule_ParentKeyObjectFactory.parentKeyObject(parent.parentModule));",
334             "    }",
335             "  }",
336             "}");
337 
338     Compilation compilation = daggerCompilerWithoutGuava().compile(parent, parentModule, child);
339     assertThat(compilation).succeeded();
340     assertThat(compilation)
341         .generatedSourceFile("test.DaggerParent")
342         .containsElementsIn(generatedComponent);
343   }
344 
daggerCompilerWithoutGuava()345   private Compiler daggerCompilerWithoutGuava() {
346     return compilerWithOptions(compilerMode.javacopts())
347         .withClasspath(CLASS_PATH_WITHOUT_GUAVA_OPTION);
348   }
349 }
350