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