1 /* 2 * Copyright (C) 2019 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.definecomponent; 18 19 import androidx.room.compiler.processing.util.Source; 20 import dagger.hilt.android.testing.compile.HiltCompilerTests; 21 import org.junit.Test; 22 import org.junit.runner.RunWith; 23 import org.junit.runners.JUnit4; 24 25 @RunWith(JUnit4.class) 26 public final class DefineComponentProcessorTest { 27 28 @Test testDefineComponentOutput()29 public void testDefineComponentOutput() { 30 Source component = 31 HiltCompilerTests.javaSource( 32 "test.FooComponent", 33 "package test;", 34 "", 35 "import dagger.hilt.components.SingletonComponent;", 36 "import dagger.hilt.DefineComponent;", 37 "", 38 "@DefineComponent(parent = SingletonComponent.class)", 39 "interface FooComponent {", 40 " static int staticField = 1;", 41 " static int staticMethod() { return staticField; }", 42 "}"); 43 44 Source builder = 45 HiltCompilerTests.javaSource( 46 "test.FooComponentBuilder", 47 "package test;", 48 "", 49 "import dagger.hilt.DefineComponent;", 50 "", 51 "@DefineComponent.Builder", 52 "interface FooComponentBuilder {", 53 " static int staticField = 1;", 54 " static int staticMethod() { return staticField; }", 55 "", 56 " FooComponent create();", 57 "}"); 58 59 Source componentOutput = 60 HiltCompilerTests.javaSource( 61 "dagger.hilt.processor.internal.definecomponent.codegen._test_FooComponent", 62 "package dagger.hilt.processor.internal.definecomponent.codegen;", 63 "", 64 "import dagger.hilt.internal.definecomponent.DefineComponentClasses;", 65 "import javax.annotation.processing.Generated;", 66 "", 67 "/**", 68 " * This class should only be referenced by generated code! This class aggregates " 69 + "information across multiple compilations.", 70 " */", 71 "@DefineComponentClasses(", 72 " component = \"test.FooComponent\"", 73 ")", 74 "@Generated(\"dagger.hilt.processor.internal.definecomponent.DefineComponentProcessingStep\")", 75 "public class _test_FooComponent {", 76 "}"); 77 78 Source builderOutput = 79 HiltCompilerTests.javaSource( 80 "dagger.hilt.processor.internal.definecomponent.codegen._test_FooComponentBuilder", 81 "package dagger.hilt.processor.internal.definecomponent.codegen;", 82 "", 83 "import dagger.hilt.internal.definecomponent.DefineComponentClasses;", 84 "import javax.annotation.processing.Generated;", 85 "", 86 "/**", 87 " * This class should only be referenced by generated code! This class aggregates " 88 + "information across multiple compilations.", 89 " */", 90 "@DefineComponentClasses(", 91 " builder = \"test.FooComponentBuilder\"", 92 ")", 93 "@Generated(\"dagger.hilt.processor.internal.definecomponent.DefineComponentProcessingStep\")", 94 "public class _test_FooComponentBuilder {", 95 "}"); 96 97 HiltCompilerTests.hiltCompiler(component, builder) 98 .compile( 99 subject -> { 100 subject.hasErrorCount(0); 101 subject.generatedSource(componentOutput); 102 subject.generatedSource(builderOutput); 103 }); 104 } 105 106 @Test testDefineComponentClass_fails()107 public void testDefineComponentClass_fails() { 108 Source component = 109 HiltCompilerTests.javaSource( 110 "test.FooComponent", 111 "package test;", 112 "", 113 "import dagger.hilt.components.SingletonComponent;", 114 "import dagger.hilt.DefineComponent;", 115 "", 116 "@DefineComponent( parent = SingletonComponent.class )", 117 "abstract class FooComponent {}"); 118 119 HiltCompilerTests.hiltCompiler(component) 120 .compile( 121 subject -> { 122 subject.hasErrorCount(1); 123 subject.hasErrorContaining( 124 "@DefineComponent is only allowed on interfaces. Found: test.FooComponent"); 125 }); 126 } 127 128 @Test testDefineComponentWithTypeParameters_fails()129 public void testDefineComponentWithTypeParameters_fails() { 130 Source component = 131 HiltCompilerTests.javaSource( 132 "test.FooComponent", 133 "package test;", 134 "", 135 "import dagger.hilt.components.SingletonComponent;", 136 "import dagger.hilt.DefineComponent;", 137 "", 138 "@DefineComponent( parent = SingletonComponent.class )", 139 "interface FooComponent<T> {}"); 140 141 HiltCompilerTests.hiltCompiler(component) 142 .compile( 143 subject -> { 144 subject.hasErrorCount(1); 145 subject.hasErrorContaining( 146 "@DefineComponent test.FooComponent<T>, cannot have type parameters."); 147 }); 148 } 149 150 @Test testDefineComponentWithInvalidComponent_fails()151 public void testDefineComponentWithInvalidComponent_fails() { 152 Source component = 153 HiltCompilerTests.javaSource( 154 "test.FooComponent", 155 "package test;", 156 "", 157 "import dagger.hilt.DefineComponent;", 158 "import dagger.hilt.android.qualifiers.ApplicationContext;", 159 "", 160 "@DefineComponent( parent = ApplicationContext.class )", 161 "interface FooComponent {}"); 162 163 HiltCompilerTests.hiltCompiler(component) 164 .compile( 165 subject -> { 166 subject.hasErrorCount(1); 167 subject.hasErrorContaining( 168 "@DefineComponent test.FooComponent, references a type not annotated with " 169 + "@DefineComponent: dagger.hilt.android.qualifiers.ApplicationContext") 170 .onSource(component); 171 }); 172 } 173 174 @Test testDefineComponentExtendsInterface_fails()175 public void testDefineComponentExtendsInterface_fails() { 176 Source component = 177 HiltCompilerTests.javaSource( 178 "test.FooComponent", 179 "package test;", 180 "", 181 "import dagger.hilt.components.SingletonComponent;", 182 "import dagger.hilt.DefineComponent;", 183 "", 184 "interface Foo {}", 185 "", 186 "@DefineComponent( parent = SingletonComponent.class )", 187 "interface FooComponent extends Foo {}"); 188 189 HiltCompilerTests.hiltCompiler(component) 190 .compile( 191 subject -> { 192 subject.hasErrorCount(1); 193 subject.hasErrorContaining( 194 "@DefineComponent test.FooComponent, cannot extend a super class or interface." 195 + " Found: [test.Foo]"); 196 }); 197 } 198 199 @Test testDefineComponentNonStaticMethod_fails()200 public void testDefineComponentNonStaticMethod_fails() { 201 Source component = 202 HiltCompilerTests.javaSource( 203 "test.FooComponent", 204 "package test;", 205 "", 206 "import dagger.hilt.components.SingletonComponent;", 207 "import dagger.hilt.DefineComponent;", 208 "", 209 "@DefineComponent( parent = SingletonComponent.class )", 210 "interface FooComponent {", 211 " int nonStaticMethod();", 212 "}"); 213 214 HiltCompilerTests.hiltCompiler(component) 215 .compile( 216 subject -> { 217 subject.hasErrorCount(1); 218 subject.hasErrorContaining( 219 "@DefineComponent test.FooComponent, cannot have non-static methods. " 220 + "Found: [nonStaticMethod()]"); 221 }); 222 } 223 224 @Test testDefineComponentDependencyCycle_fails()225 public void testDefineComponentDependencyCycle_fails() { 226 Source component1 = 227 HiltCompilerTests.javaSource( 228 "test.Component1", 229 "package test;", 230 "", 231 "import dagger.hilt.DefineComponent;", 232 "", 233 "@DefineComponent(parent = Component2.class)", 234 "interface Component1 {}"); 235 236 Source component2 = 237 HiltCompilerTests.javaSource( 238 "test.Component2", 239 "package test;", 240 "", 241 "import dagger.hilt.DefineComponent;", 242 "", 243 "@DefineComponent(parent = Component1.class)", 244 "interface Component2 {}"); 245 246 HiltCompilerTests.hiltCompiler(component1, component2) 247 .compile( 248 subject -> { 249 subject.hasErrorCount(2); 250 subject.hasErrorContaining( 251 "@DefineComponent cycle: test.Component1 -> test.Component2 -> test.Component1"); 252 subject.hasErrorContaining( 253 "@DefineComponent cycle: test.Component2 -> test.Component1 -> test.Component2"); 254 }); 255 } 256 257 @Test testDefineComponentNoParent_fails()258 public void testDefineComponentNoParent_fails() { 259 Source component = 260 HiltCompilerTests.javaSource( 261 "test.FooComponent", 262 "package test;", 263 "", 264 "import dagger.hilt.DefineComponent;", 265 "", 266 "@DefineComponent", 267 "interface FooComponent {}"); 268 269 HiltCompilerTests.hiltCompiler(component) 270 .compile( 271 subject -> { 272 subject.hasErrorCount(1); 273 subject.hasErrorContaining( 274 "@DefineComponent test.FooComponent is missing a parent declaration."); 275 }); 276 } 277 278 @Test testDefineComponentBuilderClass_fails()279 public void testDefineComponentBuilderClass_fails() { 280 Source builder = 281 HiltCompilerTests.javaSource( 282 "test.FooComponentBuilder", 283 "package test;", 284 "", 285 "import dagger.hilt.DefineComponent;", 286 "", 287 "@DefineComponent.Builder", 288 "abstract class FooComponentBuilder {}"); 289 290 HiltCompilerTests.hiltCompiler(builder) 291 .compile( 292 subject -> { 293 subject.hasErrorCount(1); 294 subject.hasErrorContaining( 295 "@DefineComponent.Builder is only allowed on interfaces. " 296 + "Found: test.FooComponentBuilder"); 297 }); 298 } 299 300 @Test testDefineComponentBuilderWithTypeParameters_fails()301 public void testDefineComponentBuilderWithTypeParameters_fails() { 302 Source builder = 303 HiltCompilerTests.javaSource( 304 "test.FooComponentBuilder", 305 "package test;", 306 "", 307 "import dagger.hilt.DefineComponent;", 308 "", 309 "@DefineComponent.Builder", 310 "interface FooComponentBuilder<T> {}"); 311 312 HiltCompilerTests.hiltCompiler(builder) 313 .compile( 314 subject -> { 315 subject.hasErrorCount(1); 316 subject.hasErrorContaining( 317 "@DefineComponent.Builder test.FooComponentBuilder<T>, cannot have type " 318 + "parameters."); 319 }); 320 } 321 322 @Test testDefineComponentBuilderExtendsInterface_fails()323 public void testDefineComponentBuilderExtendsInterface_fails() { 324 Source builder = 325 HiltCompilerTests.javaSource( 326 "test.FooComponentBuilder", 327 "package test;", 328 "", 329 "import dagger.hilt.DefineComponent;", 330 "", 331 "interface Foo {}", 332 "", 333 "@DefineComponent.Builder", 334 "interface FooComponentBuilder extends Foo {}"); 335 336 HiltCompilerTests.hiltCompiler(builder) 337 .compile( 338 subject -> { 339 subject.hasErrorCount(1); 340 subject.hasErrorContaining( 341 "@DefineComponent.Builder test.FooComponentBuilder, cannot extend a super class " 342 + "or interface. Found: [test.Foo]"); 343 }); 344 } 345 346 @Test testDefineComponentBuilderNoBuilderMethod_fails()347 public void testDefineComponentBuilderNoBuilderMethod_fails() { 348 Source component = 349 HiltCompilerTests.javaSource( 350 "test.FooComponent", 351 "package test;", 352 "", 353 "import dagger.hilt.DefineComponent;", 354 "", 355 "@DefineComponent.Builder", 356 "interface FooComponentBuilder {}"); 357 358 HiltCompilerTests.hiltCompiler(component) 359 .compile( 360 subject -> { 361 subject.hasErrorCount(1); 362 subject.hasErrorContaining( 363 "@DefineComponent.Builder test.FooComponentBuilder, must have exactly 1 build " 364 + "method that takes no parameters. Found: []"); 365 }); 366 } 367 368 @Test testDefineComponentBuilderPrimitiveReturnType_fails()369 public void testDefineComponentBuilderPrimitiveReturnType_fails() { 370 Source component = 371 HiltCompilerTests.javaSource( 372 "test.FooComponent", 373 "package test;", 374 "", 375 "import dagger.hilt.DefineComponent;", 376 "", 377 "@DefineComponent.Builder", 378 "interface FooComponentBuilder {", 379 " int nonStaticMethod();", 380 "}"); 381 382 HiltCompilerTests.hiltCompiler(component) 383 .compile( 384 subject -> { 385 subject.hasErrorCount(1); 386 subject.hasErrorContaining( 387 "@DefineComponent.Builder method, test.FooComponentBuilder#nonStaticMethod(), " 388 + "must return a @DefineComponent type. Found: int"); 389 }); 390 } 391 392 @Test testDefineComponentBuilderWrongReturnType_fails()393 public void testDefineComponentBuilderWrongReturnType_fails() { 394 Source component = 395 HiltCompilerTests.javaSource( 396 "test.FooComponent", 397 "package test;", 398 "", 399 "import dagger.hilt.DefineComponent;", 400 "", 401 "interface Foo {}", 402 "", 403 "@DefineComponent.Builder", 404 "interface FooComponentBuilder {", 405 " Foo build();", 406 "}"); 407 408 HiltCompilerTests.hiltCompiler(component) 409 .compile( 410 subject -> { 411 subject.hasErrorCount(1); 412 subject.hasErrorContaining( 413 "@DefineComponent.Builder method, test.FooComponentBuilder#build(), must return " 414 + "a @DefineComponent type. Found: test.Foo"); 415 }); 416 } 417 } 418