• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.hilt.processor.internal.aggregateddeps;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import androidx.room.compiler.processing.util.Source;
22 import com.google.common.collect.ImmutableList;
23 import dagger.hilt.android.testing.compile.HiltCompilerTests;
24 import dagger.hilt.processor.internal.GeneratedImport;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.junit.rules.TemporaryFolder;
28 import org.junit.runner.RunWith;
29 import org.junit.runners.JUnit4;
30 
31 /** Tests for errors generated by {@link AggregatedDepsProcessor} */
32 @RunWith(JUnit4.class)
33 public class AggregatedDepsProcessorErrorsTest {
34 
35   @Rule public TemporaryFolder tempFolderRule = new TemporaryFolder();
36 
37   @Test
reportMultipleAnnotationTypeKindErrors()38   public void reportMultipleAnnotationTypeKindErrors() {
39     Source source =
40         HiltCompilerTests.javaSource(
41             "foo.bar.AnnotationsOnWrongTypeKind",
42             "package foo.bar;",
43             "",
44             "import dagger.hilt.EntryPoint;",
45             "import dagger.hilt.InstallIn;",
46             "import dagger.Module;",
47             "import dagger.hilt.components.SingletonComponent;",
48             "import dagger.hilt.internal.ComponentEntryPoint;",
49             "import dagger.hilt.internal.GeneratedEntryPoint;",
50             "",
51             "@InstallIn(SingletonComponent.class)",
52             "@Module",
53             "enum FooModule { VALUE }",
54             "",
55             "@InstallIn(SingletonComponent.class)",
56             "@EntryPoint",
57             "final class BarEntryPoint {}",
58             "",
59             "@InstallIn(SingletonComponent.class)",
60             "@ComponentEntryPoint",
61             "final class BazComponentEntryPoint {}",
62             "",
63             "@EntryPoint",
64             "interface QuxEntryPoint {}",
65             "",
66             "@EntryPoint",
67             "@Module",
68             "interface DontMix{}",
69             "");
70 
71     HiltCompilerTests.hiltCompiler(source)
72         .compile(
73             subject -> {
74               subject.compilationDidFail();
75               subject
76                   .hasErrorContaining("Only classes and interfaces can be annotated with @Module")
77                   .onSource(source)
78                   .onLine(12);
79               subject
80                   .hasErrorContaining("Only interfaces can be annotated with @EntryPoint")
81                   .onSource(source)
82                   .onLine(16);
83               subject
84                   .hasErrorContaining("Only interfaces can be annotated with @ComponentEntryPoint")
85                   .onSource(source)
86                   .onLine(20);
87               subject
88                   .hasErrorContaining(
89                       "@EntryPoint foo.bar.QuxEntryPoint must also be annotated with @InstallIn")
90                   .onSource(source)
91                   .onLine(23);
92               subject
93                   .hasErrorContaining(
94                       "@Module and @EntryPoint cannot be used on the same interface")
95                   .onSource(source)
96                   .onLine(27);
97             });
98   }
99 
100   @Test
testInvalidComponentInInstallInAnnotation()101   public void testInvalidComponentInInstallInAnnotation() {
102     Source module =
103         HiltCompilerTests.javaSource(
104             "test.FooModule",
105             "package test;",
106             "",
107             "import dagger.Module;",
108             "import dagger.hilt.InstallIn;",
109             "import dagger.hilt.android.qualifiers.ApplicationContext;",
110             "",
111             "@InstallIn(ApplicationContext.class)", // Error: Not a Hilt component
112             "@Module",
113             "final class FooModule {}");
114 
115     HiltCompilerTests.hiltCompiler(module)
116         .compile(
117             subject -> {
118               subject.compilationDidFail();
119               subject
120                   .hasErrorContaining(
121                       "@InstallIn, can only be used with @DefineComponent-annotated classes, but"
122                           + " found: [dagger.hilt.android.qualifiers.ApplicationContext]")
123                   .onSource(module)
124                   .onLine(9);
125             });
126   }
127 
128   @Test
testMissingInstallInAnnotation()129   public void testMissingInstallInAnnotation() {
130     Source source =
131         HiltCompilerTests.javaSource(
132             "foo.bar.AnnotationsOnWrongTypeKind",
133             "package foo.bar;",
134             "",
135             "import dagger.Module;",
136             "",
137             "@Module", // Error: Doesn't have InstallIn annotation
138             "final class FooModule {}");
139 
140     HiltCompilerTests.hiltCompiler(source)
141         .compile(
142             subject -> {
143               subject.compilationDidFail();
144               subject
145                   .hasErrorContaining("foo.bar.FooModule is missing an @InstallIn annotation")
146                   .onSource(source)
147                   .onLine(6);
148             });
149   }
150 
151   @Test
testNoErrorOnDaggerGeneratedModules()152   public void testNoErrorOnDaggerGeneratedModules() {
153     Source source =
154         HiltCompilerTests.javaSource(
155             "foo.bar.BarModule",
156             "package foo.bar;",
157             "",
158             GeneratedImport.IMPORT_GENERATED_ANNOTATION,
159             "import dagger.Module;",
160             "",
161             "@Module",
162             "@Generated(value = \"something\")", // Error: Isn't Dagger-generated but missing
163             // InstallIn
164             "final class FooModule {}",
165             "",
166             "@Module",
167             "@Generated(value = \"dagger\")", // No error because the module is dagger generated
168             "final class BarModule {}");
169 
170     HiltCompilerTests.hiltCompiler(source)
171         .compile(
172             subject -> {
173               subject.compilationDidFail();
174               subject.hasErrorCount(1);
175               subject
176                   .hasErrorContaining("foo.bar.FooModule is missing an @InstallIn annotation")
177                   .onSource(source)
178                   .onLine(8);
179             });
180   }
181 
182   @Test
testModuleWithOnlyParamConstructor_fails()183   public void testModuleWithOnlyParamConstructor_fails() {
184     Source source =
185         HiltCompilerTests.javaSource(
186             "foo.bar.FooModule",
187             "package foo.bar;",
188             "",
189             "import dagger.Module;",
190             "import dagger.Provides;",
191             "import dagger.hilt.InstallIn;",
192             "import dagger.hilt.components.SingletonComponent;",
193             "",
194             "@Module",
195             "@InstallIn(SingletonComponent.class)",
196             "final class FooModule {",
197             "  FooModule(String arg) {}",
198             "",
199             "  @Provides",
200             "  String provideString() {",
201             "    return \"\";",
202             "  }",
203             "}");
204 
205     HiltCompilerTests.hiltCompiler(source)
206         .compile(
207             subject -> {
208               subject.compilationDidFail();
209               subject.hasErrorCount(1);
210               subject.hasErrorContaining(
211                   "Modules that need to be instantiated by Hilt must have a visible, empty"
212                       + " constructor.");
213             });
214   }
215 
216   @Test
testInnerModule()217   public void testInnerModule() {
218     Source source =
219         HiltCompilerTests.javaSource(
220             "foo.bar.Outer",
221             "package foo.bar;",
222             "",
223             "import dagger.Module;",
224             "import dagger.hilt.InstallIn;",
225             "import dagger.hilt.components.SingletonComponent;",
226             "",
227             "final class Outer {",
228             "  @Module",
229             "  @InstallIn(SingletonComponent.class)",
230             "  final class InnerModule {}",
231             "}");
232 
233     HiltCompilerTests.hiltCompiler(source)
234         .compile(
235             subject -> {
236               subject.compilationDidFail();
237               subject.hasErrorCount(1);
238               subject.hasErrorContaining(
239                   "Nested @InstallIn modules must be static unless they are directly nested within"
240                       + " a test. Found: foo.bar.Outer.InnerModule");
241             });
242   }
243 
244   @Test
testInnerModuleInTest()245   public void testInnerModuleInTest() {
246     Source source =
247         HiltCompilerTests.javaSource(
248             "foo.bar.Outer",
249             "package foo.bar;",
250             "",
251             "import dagger.Module;",
252             "import dagger.hilt.InstallIn;",
253             "import dagger.hilt.components.SingletonComponent;",
254             "import dagger.hilt.android.testing.HiltAndroidTest;",
255             "",
256             "@HiltAndroidTest",
257             "final class Outer {",
258             "  static class Nested {",
259             "    @Module",
260             "    @InstallIn(SingletonComponent.class)",
261             "    final class InnerModule {}",
262             "  }",
263             "}");
264 
265     HiltCompilerTests.hiltCompiler(source)
266         .compile(
267             subject -> {
268               subject.compilationDidFail();
269               subject.hasErrorCount(1);
270               subject.hasErrorContaining(
271                   "Nested @InstallIn modules must be static unless they are directly nested within"
272                       + " a test. Found: foo.bar.Outer.Nested.InnerModule");
273             });
274   }
275 
276   @Test
testInnerModuleInTest_succeeds()277   public void testInnerModuleInTest_succeeds() {
278     Source source =
279         HiltCompilerTests.javaSource(
280             "foo.bar.Outer",
281             "package foo.bar;",
282             "",
283             "import dagger.Module;",
284             "import dagger.hilt.InstallIn;",
285             "import dagger.hilt.components.SingletonComponent;",
286             "import dagger.hilt.android.testing.HiltAndroidTest;",
287             "",
288             "@HiltAndroidTest",
289             "public final class Outer {",
290             "  @Module",
291             "  @InstallIn(SingletonComponent.class)",
292             "  static final class InnerModule {}",
293             "}");
294 
295     // TODO(danysantiago): Add KSP test once b/288966076 is resolved.
296     HiltCompilerTests.compileWithKapt(
297         ImmutableList.of(source),
298         tempFolderRule,
299         result -> assertThat(result.getSuccess()).isTrue());
300   }
301 }
302