1 /* 2 * Copyright (C) 2018 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 /** 30 * Tests that errors are reported for invalid members injection methods and {@link 31 * dagger.MembersInjector} dependency requests. 32 */ 33 @RunWith(JUnit4.class) 34 public class MembersInjectionValidationTest { 35 @Test membersInjectDependsOnUnboundedType()36 public void membersInjectDependsOnUnboundedType() { 37 JavaFileObject injectsUnboundedType = 38 JavaFileObjects.forSourceLines( 39 "test.InjectsUnboundedType", 40 "package test;", 41 "", 42 "import dagger.MembersInjector;", 43 "import java.util.ArrayList;", 44 "import javax.inject.Inject;", 45 "", 46 "class InjectsUnboundedType {", 47 " @Inject MembersInjector<ArrayList<?>> listInjector;", 48 "}"); 49 50 Compilation compilation = daggerCompiler().compile(injectsUnboundedType); 51 assertThat(compilation).failed(); 52 assertThat(compilation) 53 .hadErrorContaining( 54 "Cannot inject members into types with unbounded type arguments: " 55 + "java.util.ArrayList<?>") 56 .inFile(injectsUnboundedType) 57 .onLineContaining("@Inject MembersInjector<ArrayList<?>> listInjector;"); 58 } 59 60 @Test membersInjectPrimitive()61 public void membersInjectPrimitive() { 62 JavaFileObject component = 63 JavaFileObjects.forSourceLines( 64 "test.TestComponent", 65 "package test;", 66 "", 67 "import dagger.Component;", 68 "", 69 "@Component", 70 "interface TestComponent {", 71 " void inject(int primitive);", 72 "}"); 73 Compilation compilation = daggerCompiler().compile(component); 74 assertThat(compilation).failed(); 75 assertThat(compilation) 76 .hadErrorContaining("Cannot inject members into int") 77 .inFile(component) 78 .onLineContaining("void inject(int primitive);"); 79 } 80 81 @Test membersInjectArray()82 public void membersInjectArray() { 83 JavaFileObject component = 84 JavaFileObjects.forSourceLines( 85 "test.TestComponent", 86 "package test;", 87 "", 88 "import dagger.Component;", 89 "", 90 "@Component", 91 "interface TestComponent {", 92 " void inject(Object[] array);", 93 "}"); 94 Compilation compilation = daggerCompiler().compile(component); 95 assertThat(compilation).failed(); 96 assertThat(compilation) 97 .hadErrorContaining("Cannot inject members into java.lang.Object[]") 98 .inFile(component) 99 .onLineContaining("void inject(Object[] array);"); 100 } 101 102 @Test membersInjectorOfArray()103 public void membersInjectorOfArray() { 104 JavaFileObject component = 105 JavaFileObjects.forSourceLines( 106 "test.TestComponent", 107 "package test;", 108 "", 109 "import dagger.Component;", 110 "import dagger.MembersInjector;", 111 "", 112 "@Component", 113 "interface TestComponent {", 114 " MembersInjector<Object[]> objectArrayInjector();", 115 "}"); 116 Compilation compilation = daggerCompiler().compile(component); 117 assertThat(compilation).failed(); 118 assertThat(compilation) 119 .hadErrorContaining("Cannot inject members into java.lang.Object[]") 120 .inFile(component) 121 .onLineContaining("objectArrayInjector();"); 122 } 123 124 @Test membersInjectRawType()125 public void membersInjectRawType() { 126 JavaFileObject component = 127 JavaFileObjects.forSourceLines( 128 "test.TestComponent", 129 "package test;", 130 "", 131 "import dagger.Component;", 132 "import java.util.Set;", 133 "", 134 "@Component", 135 "interface TestComponent {", 136 " void inject(Set rawSet);", 137 "}"); 138 Compilation compilation = daggerCompiler().compile(component); 139 assertThat(compilation).failed(); 140 assertThat(compilation).hadErrorContaining("Cannot inject members into raw type java.util.Set"); 141 } 142 143 @Test qualifiedMembersInjector()144 public void qualifiedMembersInjector() { 145 JavaFileObject component = 146 JavaFileObjects.forSourceLines( 147 "test.TestComponent", 148 "package test;", 149 "", 150 "import dagger.Component;", 151 "import dagger.MembersInjector;", 152 "import javax.inject.Named;", 153 "", 154 "@Component", 155 "interface TestComponent {", 156 " @Named(\"foo\") MembersInjector<Object> objectInjector();", 157 "}"); 158 Compilation compilation = daggerCompiler().compile(component); 159 assertThat(compilation).failed(); 160 assertThat(compilation) 161 .hadErrorContaining("Cannot inject members into qualified types") 162 .inFile(component) 163 .onLineContaining("objectInjector();"); 164 } 165 166 @Test qualifiedMembersInjectionMethod()167 public void qualifiedMembersInjectionMethod() { 168 JavaFileObject component = 169 JavaFileObjects.forSourceLines( 170 "test.TestComponent", 171 "package test;", 172 "", 173 "import dagger.Component;", 174 "import dagger.MembersInjector;", 175 "import javax.inject.Named;", 176 "", 177 "@Component", 178 "interface TestComponent {", 179 " @Named(\"foo\") void injectObject(Object object);", 180 "}"); 181 Compilation compilation = daggerCompiler().compile(component); 182 assertThat(compilation).failed(); 183 assertThat(compilation) 184 .hadErrorContaining("Cannot inject members into qualified types") 185 .inFile(component) 186 .onLineContaining("injectObject(Object object);"); 187 } 188 189 @Test qualifiedMembersInjectionMethodParameter()190 public void qualifiedMembersInjectionMethodParameter() { 191 JavaFileObject component = 192 JavaFileObjects.forSourceLines( 193 "test.TestComponent", 194 "package test;", 195 "", 196 "import dagger.Component;", 197 "import dagger.MembersInjector;", 198 "import javax.inject.Named;", 199 "", 200 "@Component", 201 "interface TestComponent {", 202 " void injectObject(@Named(\"foo\") Object object);", 203 "}"); 204 Compilation compilation = daggerCompiler().compile(component); 205 assertThat(compilation).failed(); 206 assertThat(compilation) 207 .hadErrorContaining("Cannot inject members into qualified types") 208 .inFile(component) 209 .onLineContaining("injectObject(@Named(\"foo\") Object object);"); 210 } 211 212 @Test staticFieldInjection()213 public void staticFieldInjection() { 214 JavaFileObject injected = 215 JavaFileObjects.forSourceLines( 216 "test.Injected", 217 "package test;", 218 "", 219 "import javax.inject.Inject;", 220 "", 221 "final class Injected {", 222 " @Inject static Object object;", 223 "}"); 224 JavaFileObject component = 225 JavaFileObjects.forSourceLines( 226 "test.TestComponent", 227 "package test;", 228 "", 229 "import dagger.Component;", 230 "", 231 "@Component", 232 "interface TestComponent {", 233 " void inject(Injected injected);", 234 "}"); 235 Compilation compilation = daggerCompiler().compile(injected, component); 236 assertThat(compilation).failed(); 237 assertThat(compilation).hadErrorContaining("static fields").inFile(injected).onLine(6); 238 } 239 240 @Test missingMembersInjectorForKotlinProperty()241 public void missingMembersInjectorForKotlinProperty() { 242 JavaFileObject component = 243 JavaFileObjects.forSourceLines( 244 "test.TestComponent", 245 "package test;", 246 "", 247 "import dagger.Component;", 248 "import dagger.internal.codegen.KotlinInjectedQualifier;", 249 "", 250 "@Component(modules = TestModule.class)", 251 "interface TestComponent {", 252 " void inject(KotlinInjectedQualifier injected);", 253 "}"); 254 JavaFileObject module = 255 JavaFileObjects.forSourceLines( 256 "test.TestModule", 257 "package test;", 258 "", 259 "import dagger.Module;", 260 "import dagger.Provides;", 261 "import javax.inject.Named;", 262 "", 263 "@Module", 264 "class TestModule {", 265 " @Provides", 266 " @Named(\"TheString\")", 267 " String theString() { return \"\"; }", 268 "}"); 269 Compilation compilation = daggerCompiler().compile(component, module); 270 assertThat(compilation).failed(); 271 assertThat(compilation) 272 .hadErrorContaining("Unable to read annotations on an injected Kotlin property."); 273 } 274 275 @Test memberInjectionForKotlinObjectFails()276 public void memberInjectionForKotlinObjectFails() { 277 JavaFileObject component = 278 JavaFileObjects.forSourceLines( 279 "test.TestComponent", 280 "package test;", 281 "", 282 "import dagger.Component;", 283 "import dagger.internal.codegen.KotlinObjectWithMemberInjection;", 284 "", 285 "@Component(modules = TestModule.class)", 286 "interface TestComponent {", 287 " void inject(KotlinObjectWithMemberInjection injected);", 288 "}"); 289 Compilation compilation = daggerCompiler().compile(component, testModule); 290 assertThat(compilation).failed(); 291 assertThat(compilation) 292 .hadErrorContaining("Dagger does not support injection into Kotlin objects"); 293 } 294 295 @Test setterMemberInjectionForKotlinObjectFails()296 public void setterMemberInjectionForKotlinObjectFails() { 297 JavaFileObject component = 298 JavaFileObjects.forSourceLines( 299 "test.TestComponent", 300 "package test;", 301 "", 302 "import dagger.Component;", 303 "import dagger.internal.codegen.KotlinObjectWithSetterMemberInjection;", 304 "", 305 "@Component(modules = TestModule.class)", 306 "interface TestComponent {", 307 " void inject(KotlinObjectWithSetterMemberInjection injected);", 308 "}"); 309 Compilation compilation = daggerCompiler().compile(component, testModule); 310 assertThat(compilation).failed(); 311 assertThat(compilation) 312 .hadErrorContaining("Dagger does not support injection into Kotlin objects"); 313 } 314 315 @Test memberInjectionForKotlinClassWithCompanionObjectFails()316 public void memberInjectionForKotlinClassWithCompanionObjectFails() { 317 JavaFileObject component = 318 JavaFileObjects.forSourceLines( 319 "test.TestComponent", 320 "package test;", 321 "", 322 "import dagger.Component;", 323 "import dagger.internal.codegen.KotlinClassWithMemberInjectedCompanion;", 324 "", 325 "@Component(modules = TestModule.class)", 326 "interface TestComponent {", 327 " void inject(KotlinClassWithMemberInjectedCompanion injected);", 328 " void injectCompanion(KotlinClassWithMemberInjectedCompanion.Companion injected);", 329 "}"); 330 Compilation compilation = daggerCompiler().compile(component, testModule); 331 assertThat(compilation).failed(); 332 assertThat(compilation) 333 .hadErrorContaining("Dagger does not support injection into static fields"); 334 } 335 336 @Test setterMemberInjectionForKotlinClassWithCompanionObjectFails()337 public void setterMemberInjectionForKotlinClassWithCompanionObjectFails() { 338 JavaFileObject component = 339 JavaFileObjects.forSourceLines( 340 "test.TestComponent", 341 "package test;", 342 "", 343 "import dagger.Component;", 344 "import dagger.internal.codegen.KotlinClassWithSetterMemberInjectedCompanion;", 345 "", 346 "@Component(modules = TestModule.class)", 347 "interface TestComponent {", 348 " void inject(KotlinClassWithSetterMemberInjectedCompanion.Companion injected);", 349 "}"); 350 Compilation compilation = daggerCompiler().compile(component, testModule); 351 assertThat(compilation).failed(); 352 assertThat(compilation) 353 .hadErrorContaining("Dagger does not support injection into Kotlin objects"); 354 } 355 356 @Test memberInjectionForKotlinClassWithNamedCompanionObjectFails()357 public void memberInjectionForKotlinClassWithNamedCompanionObjectFails() { 358 JavaFileObject component = 359 JavaFileObjects.forSourceLines( 360 "test.TestComponent", 361 "package test;", 362 "", 363 "import dagger.Component;", 364 "import dagger.internal.codegen.KotlinClassWithMemberInjectedNamedCompanion;", 365 "", 366 "@Component(modules = TestModule.class)", 367 "interface TestComponent {", 368 " void inject(KotlinClassWithMemberInjectedNamedCompanion injected);", 369 " void injectCompanion(KotlinClassWithMemberInjectedNamedCompanion.TheCompanion" 370 + " injected);", 371 "}"); 372 Compilation compilation = daggerCompiler().compile(component, testModule); 373 assertThat(compilation).failed(); 374 assertThat(compilation) 375 .hadErrorContaining("Dagger does not support injection into static fields"); 376 } 377 378 @Test setterMemberInjectionForKotlinClassWithNamedCompanionObjectFails()379 public void setterMemberInjectionForKotlinClassWithNamedCompanionObjectFails() { 380 JavaFileObject component = 381 JavaFileObjects.forSourceLines( 382 "test.TestComponent", 383 "package test;", 384 "", 385 "import dagger.Component;", 386 "import dagger.internal.codegen.KotlinClassWithSetterMemberInjectedNamedCompanion;", 387 "", 388 "@Component(modules = TestModule.class)", 389 "interface TestComponent {", 390 " void inject(", 391 " KotlinClassWithSetterMemberInjectedNamedCompanion.TheCompanion injected);", 392 "}"); 393 Compilation compilation = daggerCompiler().compile(component, testModule); 394 assertThat(compilation).failed(); 395 assertThat(compilation) 396 .hadErrorContaining("Dagger does not support injection into Kotlin objects"); 397 } 398 399 private final JavaFileObject testModule = 400 JavaFileObjects.forSourceLines( 401 "test.TestModule", 402 "package test;", 403 "", 404 "import dagger.Module;", 405 "import dagger.Provides;", 406 "", 407 "@Module", 408 "class TestModule {", 409 " @Provides", 410 " String theString() { return \"\"; }", 411 "}"); 412 } 413