1 /* 2 * Copyright (C) 2021 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.common.truth.Truth.assertThat; 20 import static com.google.testing.compile.CompilationSubject.assertThat; 21 import static dagger.internal.codegen.Compilers.compilerWithOptions; 22 import static dagger.internal.codegen.Compilers.daggerCompiler; 23 import static java.util.stream.Collectors.joining; 24 25 import com.google.testing.compile.Compilation; 26 import com.google.testing.compile.JavaFileObjects; 27 import javax.tools.JavaFileObject; 28 import org.junit.Test; 29 import org.junit.runner.RunWith; 30 import org.junit.runners.JUnit4; 31 32 @RunWith(JUnit4.class) 33 public final class UnresolvableDependencyTest { 34 35 @Test referencesUnresolvableDependency()36 public void referencesUnresolvableDependency() { 37 JavaFileObject fooComponent = 38 JavaFileObjects.forSourceLines( 39 "test.FooComponent", 40 "package test;", 41 "", 42 "import dagger.Component;", 43 "", 44 "@Component", 45 "interface FooComponent {", 46 " Foo foo();", 47 "}"); 48 49 JavaFileObject foo = 50 JavaFileObjects.forSourceLines( 51 "test.Foo", 52 "package test;", 53 "", 54 "import javax.inject.Inject;", 55 "", 56 "class Foo {", 57 " @Inject", 58 " Foo(Bar bar) {}", 59 "}"); 60 61 JavaFileObject bar = 62 JavaFileObjects.forSourceLines( 63 "test.Bar", 64 "package test;", 65 "", 66 "import javax.inject.Inject;", 67 "", 68 "class Bar {", 69 " @Inject", 70 " Bar(UnresolvableDependency dep) {}", 71 "}"); 72 73 Compilation compilation = daggerCompiler().compile(fooComponent, foo, bar); 74 assertThat(compilation).failed(); 75 assertThat(compilation).hadErrorCount(3); 76 assertThat(compilation).hadErrorContaining( 77 "cannot find symbol" 78 + "\n symbol: class UnresolvableDependency" 79 + "\n location: class test.Bar"); 80 String trace = "\n " 81 + "\n Dependency trace:" 82 + "\n => element (CLASS): test.Bar" 83 + "\n => element (CONSTRUCTOR): Bar(UnresolvableDependency)" 84 + "\n => type (EXECUTABLE constructor): (UnresolvableDependency)void" 85 + "\n => type (ERROR parameter type): UnresolvableDependency"; 86 assertThat(compilation).hadErrorContaining( 87 "InjectProcessingStep was unable to process 'Bar(UnresolvableDependency)' because " 88 + "'UnresolvableDependency' could not be resolved." + trace); 89 assertThat(compilation).hadErrorContaining( 90 "ComponentProcessingStep was unable to process 'test.FooComponent' because " 91 + "'UnresolvableDependency' could not be resolved." + trace); 92 93 // Only include a minimal portion of the stacktrace to minimize breaking tests due to refactors. 94 String stacktraceErrorMessage = 95 "dagger.internal.codegen.base" 96 + ".DaggerSuperficialValidation$ValidationException$KnownErrorType"; 97 98 // Check that the stacktrace is not included in the error message by default. 99 assertThat( 100 compilation.errors().stream() 101 .map(error -> error.getMessage(null)) 102 .collect(joining("\n"))) 103 .doesNotContain(stacktraceErrorMessage); 104 105 // Recompile with the option enabled and check that the stacktrace is now included 106 compilation = 107 compilerWithOptions("-Adagger.includeStacktraceWithDeferredErrorMessages=ENABLED") 108 .compile(fooComponent, foo, bar); 109 assertThat(compilation).failed(); 110 assertThat(compilation).hadErrorCount(3); 111 assertThat(compilation).hadErrorContaining(stacktraceErrorMessage); 112 } 113 114 @Test referencesUnresolvableAnnotationOnType()115 public void referencesUnresolvableAnnotationOnType() { 116 JavaFileObject fooComponent = 117 JavaFileObjects.forSourceLines( 118 "test.FooComponent", 119 "package test;", 120 "", 121 "import dagger.Component;", 122 "", 123 "@Component", 124 "interface FooComponent {", 125 " Foo foo();", 126 "}"); 127 128 JavaFileObject foo = 129 JavaFileObjects.forSourceLines( 130 "test.Foo", 131 "package test;", 132 "", 133 "import javax.inject.Inject;", 134 "", 135 "class Foo {", 136 " @Inject", 137 " Foo(Bar bar) {}", 138 "}"); 139 140 JavaFileObject bar = 141 JavaFileObjects.forSourceLines( 142 "test.Bar", 143 "package test;", 144 "", 145 "import javax.inject.Inject;", 146 "", 147 "@UnresolvableAnnotation", 148 "class Bar {", 149 " @Inject", 150 " Bar(String dep) {}", 151 "}"); 152 153 Compilation compilation = daggerCompiler().compile(fooComponent, foo, bar); 154 assertThat(compilation).failed(); 155 assertThat(compilation).hadErrorCount(3); 156 assertThat(compilation).hadErrorContaining( 157 "cannot find symbol" 158 + "\n symbol: class UnresolvableAnnotation"); 159 String trace = "\n " 160 + "\n Dependency trace:" 161 + "\n => element (CLASS): test.Bar" 162 + "\n => annotation: @UnresolvableAnnotation" 163 + "\n => type (ERROR annotation type): UnresolvableAnnotation"; 164 assertThat(compilation).hadErrorContaining( 165 "InjectProcessingStep was unable to process 'Bar(java.lang.String)' because " 166 + "'UnresolvableAnnotation' could not be resolved." + trace); 167 assertThat(compilation).hadErrorContaining( 168 "ComponentProcessingStep was unable to process 'test.FooComponent' because " 169 + "'UnresolvableAnnotation' could not be resolved." + trace); 170 } 171 172 @Test referencesUnresolvableAnnotationOnTypeOnParameter()173 public void referencesUnresolvableAnnotationOnTypeOnParameter() { 174 JavaFileObject fooComponent = 175 JavaFileObjects.forSourceLines( 176 "test.FooComponent", 177 "package test;", 178 "", 179 "import dagger.Component;", 180 "", 181 "@Component", 182 "interface FooComponent {", 183 " Foo foo();", 184 "}"); 185 186 JavaFileObject foo = 187 JavaFileObjects.forSourceLines( 188 "test.Foo", 189 "package test;", 190 "", 191 "import javax.inject.Inject;", 192 "", 193 "class Foo {", 194 " @Inject", 195 " Foo(Bar bar) {}", 196 "}"); 197 198 JavaFileObject bar = 199 JavaFileObjects.forSourceLines( 200 "test.Bar", 201 "package test;", 202 "", 203 "import javax.inject.Inject;", 204 "", 205 "class Bar {", 206 " @Inject", 207 " Bar(@UnresolvableAnnotation String dep) {}", 208 "}"); 209 210 Compilation compilation = daggerCompiler().compile(fooComponent, foo, bar); 211 assertThat(compilation).failed(); 212 assertThat(compilation).hadErrorCount(3); 213 assertThat(compilation).hadErrorContaining( 214 "cannot find symbol" 215 + "\n symbol: class UnresolvableAnnotation" 216 + "\n location: class test.Bar"); 217 String trace = "\n " 218 + "\n Dependency trace:" 219 + "\n => element (CLASS): test.Bar" 220 + "\n => element (CONSTRUCTOR): Bar(java.lang.String)" 221 + "\n => element (PARAMETER): dep" 222 + "\n => annotation: @UnresolvableAnnotation" 223 + "\n => type (ERROR annotation type): UnresolvableAnnotation"; 224 assertThat(compilation).hadErrorContaining( 225 "InjectProcessingStep was unable to process 'Bar(java.lang.String)' because " 226 + "'UnresolvableAnnotation' could not be resolved." + trace); 227 assertThat(compilation).hadErrorContaining( 228 "ComponentProcessingStep was unable to process 'test.FooComponent' because " 229 + "'UnresolvableAnnotation' could not be resolved." + trace); 230 } 231 } 232