1 /* 2 * Copyright (C) 2015 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 import static dagger.internal.codegen.ComponentCreatorAnnotation.COMPONENT_BUILDER; 22 import static dagger.internal.codegen.ErrorMessages.creatorMessagesFor; 23 import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION; 24 25 import com.google.testing.compile.Compilation; 26 import com.google.testing.compile.JavaFileObjects; 27 import java.util.Collection; 28 import javax.tools.JavaFileObject; 29 import org.junit.Test; 30 import org.junit.runner.RunWith; 31 import org.junit.runners.Parameterized; 32 import org.junit.runners.Parameterized.Parameters; 33 34 /** Tests for {@link dagger.Component.Builder} */ 35 @RunWith(Parameterized.class) 36 public class ComponentBuilderTest { 37 @Parameters(name = "{0}") parameters()38 public static Collection<Object[]> parameters() { 39 return CompilerMode.TEST_PARAMETERS; 40 } 41 42 private final CompilerMode compilerMode; 43 ComponentBuilderTest(CompilerMode compilerMode)44 public ComponentBuilderTest(CompilerMode compilerMode) { 45 this.compilerMode = compilerMode; 46 } 47 48 private static final ErrorMessages.ComponentCreatorMessages MSGS = 49 creatorMessagesFor(COMPONENT_BUILDER); 50 51 @Test testUsesBuildAndSetterNames()52 public void testUsesBuildAndSetterNames() { 53 JavaFileObject moduleFile = 54 JavaFileObjects.forSourceLines( 55 "test.TestModule", 56 "package test;", 57 "", 58 "import dagger.Module;", 59 "import dagger.Provides;", 60 "", 61 "@Module", 62 "final class TestModule {", 63 " @Provides String string() { return null; }", 64 "}"); 65 66 JavaFileObject componentFile = 67 JavaFileObjects.forSourceLines( 68 "test.TestComponent", 69 "package test;", 70 "", 71 "import dagger.Component;", 72 "", 73 "@Component(modules = TestModule.class)", 74 "interface TestComponent {", 75 " String string();", 76 "", 77 " @Component.Builder", 78 " interface Builder {", 79 " Builder setTestModule(TestModule testModule);", 80 " TestComponent create();", 81 " }", 82 "}"); 83 JavaFileObject generatedComponent = 84 JavaFileObjects.forSourceLines( 85 "test.DaggerTestComponent", 86 "package test;", 87 "", 88 "import dagger.internal.Preconditions;", 89 "", 90 GENERATED_ANNOTATION, 91 "final class DaggerTestComponent implements TestComponent {", 92 " private static final class Builder implements TestComponent.Builder {", 93 " private TestModule testModule;", 94 "", 95 " @Override", 96 " public Builder setTestModule(TestModule testModule) {", 97 " this.testModule = Preconditions.checkNotNull(testModule);", 98 " return this;", 99 " }", 100 "", 101 " @Override", 102 " public TestComponent create() {", 103 " if (testModule == null) {", 104 " this.testModule = new TestModule();", 105 " }", 106 " return new DaggerTestComponent(testModule);", 107 " }", 108 " }", 109 "}"); 110 Compilation compilation = 111 daggerCompiler().withOptions(compilerMode.javacopts()).compile(moduleFile, componentFile); 112 assertThat(compilation).succeeded(); 113 assertThat(compilation) 114 .generatedSourceFile("test.DaggerTestComponent") 115 .containsElementsIn(generatedComponent); 116 } 117 118 @Test testSetterMethodWithMoreThanOneArgFails()119 public void testSetterMethodWithMoreThanOneArgFails() { 120 JavaFileObject componentFile = 121 JavaFileObjects.forSourceLines( 122 "test.SimpleComponent", 123 "package test;", 124 "", 125 "import dagger.Component;", 126 "import javax.inject.Provider;", 127 "", 128 "@Component", 129 "abstract class SimpleComponent {", 130 " @Component.Builder", 131 " interface Builder {", 132 " SimpleComponent build();", 133 " Builder set(String s, Integer i);", 134 " Builder set(Number n, Double d);", 135 " }", 136 "}"); 137 Compilation compilation = 138 daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile); 139 assertThat(compilation).failed(); 140 assertThat(compilation) 141 .hadErrorContaining(MSGS.setterMethodsMustTakeOneArg()) 142 .inFile(componentFile) 143 .onLineContaining("Builder set(String s, Integer i);"); 144 assertThat(compilation) 145 .hadErrorContaining(MSGS.setterMethodsMustTakeOneArg()) 146 .inFile(componentFile) 147 .onLineContaining("Builder set(Number n, Double d);"); 148 } 149 150 @Test testInheritedSetterMethodWithMoreThanOneArgFails()151 public void testInheritedSetterMethodWithMoreThanOneArgFails() { 152 JavaFileObject componentFile = 153 JavaFileObjects.forSourceLines( 154 "test.SimpleComponent", 155 "package test;", 156 "", 157 "import dagger.Component;", 158 "import javax.inject.Provider;", 159 "", 160 "@Component", 161 "abstract class SimpleComponent {", 162 " interface Parent {", 163 " SimpleComponent build();", 164 " Builder set1(String s, Integer i);", 165 " }", 166 "", 167 " @Component.Builder", 168 " interface Builder extends Parent {}", 169 "}"); 170 Compilation compilation = 171 daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile); 172 assertThat(compilation).failed(); 173 assertThat(compilation) 174 .hadErrorContaining( 175 String.format( 176 MSGS.inheritedSetterMethodsMustTakeOneArg(), 177 "set1(java.lang.String,java.lang.Integer)")) 178 .inFile(componentFile) 179 .onLineContaining("interface Builder"); 180 } 181 182 @Test testSetterReturningNonVoidOrBuilderFails()183 public void testSetterReturningNonVoidOrBuilderFails() { 184 JavaFileObject componentFile = 185 JavaFileObjects.forSourceLines( 186 "test.SimpleComponent", 187 "package test;", 188 "", 189 "import dagger.Component;", 190 "import javax.inject.Provider;", 191 "", 192 "@Component", 193 "abstract class SimpleComponent {", 194 " @Component.Builder", 195 " interface Builder {", 196 " SimpleComponent build();", 197 " String set(Integer i);", 198 " }", 199 "}"); 200 Compilation compilation = 201 daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile); 202 assertThat(compilation).failed(); 203 assertThat(compilation) 204 .hadErrorContaining(MSGS.setterMethodsMustReturnVoidOrBuilder()) 205 .inFile(componentFile) 206 .onLineContaining("String set(Integer i);"); 207 } 208 209 @Test testInheritedSetterReturningNonVoidOrBuilderFails()210 public void testInheritedSetterReturningNonVoidOrBuilderFails() { 211 JavaFileObject componentFile = 212 JavaFileObjects.forSourceLines( 213 "test.SimpleComponent", 214 "package test;", 215 "", 216 "import dagger.Component;", 217 "import javax.inject.Provider;", 218 "", 219 "@Component", 220 "abstract class SimpleComponent {", 221 " interface Parent {", 222 " SimpleComponent build();", 223 " String set(Integer i);", 224 " }", 225 "", 226 " @Component.Builder", 227 " interface Builder extends Parent {}", 228 "}"); 229 Compilation compilation = 230 daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile); 231 assertThat(compilation).failed(); 232 assertThat(compilation) 233 .hadErrorContaining( 234 String.format( 235 MSGS.inheritedSetterMethodsMustReturnVoidOrBuilder(), "set(java.lang.Integer)")) 236 .inFile(componentFile) 237 .onLineContaining("interface Builder"); 238 } 239 240 @Test testGenericsOnSetterMethodFails()241 public void testGenericsOnSetterMethodFails() { 242 JavaFileObject componentFile = 243 JavaFileObjects.forSourceLines( 244 "test.SimpleComponent", 245 "package test;", 246 "", 247 "import dagger.Component;", 248 "import javax.inject.Provider;", 249 "", 250 "@Component", 251 "abstract class SimpleComponent {", 252 " @Component.Builder", 253 " interface Builder {", 254 " SimpleComponent build();", 255 " <T> Builder set(T t);", 256 " }", 257 "}"); 258 Compilation compilation = 259 daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile); 260 assertThat(compilation).failed(); 261 assertThat(compilation) 262 .hadErrorContaining(MSGS.methodsMayNotHaveTypeParameters()) 263 .inFile(componentFile) 264 .onLineContaining("<T> Builder set(T t);"); 265 } 266 267 @Test testGenericsOnInheritedSetterMethodFails()268 public void testGenericsOnInheritedSetterMethodFails() { 269 JavaFileObject componentFile = 270 JavaFileObjects.forSourceLines( 271 "test.SimpleComponent", 272 "package test;", 273 "", 274 "import dagger.Component;", 275 "import javax.inject.Provider;", 276 "", 277 "@Component", 278 "abstract class SimpleComponent {", 279 " interface Parent {", 280 " SimpleComponent build();", 281 " <T> Builder set(T t);", 282 " }", 283 "", 284 " @Component.Builder", 285 " interface Builder extends Parent {}", 286 "}"); 287 Compilation compilation = 288 daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile); 289 assertThat(compilation).failed(); 290 assertThat(compilation) 291 .hadErrorContaining( 292 String.format(MSGS.inheritedMethodsMayNotHaveTypeParameters(), "<T>set(T)")) 293 .inFile(componentFile) 294 .onLineContaining("interface Builder"); 295 } 296 297 @Test testBindsInstanceNotAllowedOnBothSetterAndParameter()298 public void testBindsInstanceNotAllowedOnBothSetterAndParameter() { 299 JavaFileObject componentFile = 300 JavaFileObjects.forSourceLines( 301 "test.SimpleComponent", 302 "package test;", 303 "", 304 "import dagger.BindsInstance;", 305 "import dagger.Component;", 306 "", 307 "@Component", 308 "abstract class SimpleComponent {", 309 " abstract String s();", 310 "", 311 " @Component.Builder", 312 " interface Builder {", 313 " @BindsInstance", 314 " Builder s(@BindsInstance String s);", 315 "", 316 " SimpleComponent build();", 317 " }", 318 "}"); 319 320 Compilation compilation = 321 daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile); 322 assertThat(compilation).failed(); 323 assertThat(compilation) 324 .hadErrorContaining(MSGS.bindsInstanceNotAllowedOnBothSetterMethodAndParameter()) 325 .inFile(componentFile) 326 .onLineContaining("Builder s("); 327 } 328 329 @Test testBindsInstanceNotAllowedOnBothSetterAndParameter_inherited()330 public void testBindsInstanceNotAllowedOnBothSetterAndParameter_inherited() { 331 JavaFileObject componentFile = 332 JavaFileObjects.forSourceLines( 333 "test.SimpleComponent", 334 "package test;", 335 "", 336 "import dagger.BindsInstance;", 337 "import dagger.Component;", 338 "", 339 "@Component", 340 "abstract class SimpleComponent {", 341 " abstract String s();", 342 "", 343 " interface BuilderParent<B extends BuilderParent> {", 344 " @BindsInstance", 345 " B s(@BindsInstance String s);", 346 " }", 347 "", 348 " @Component.Builder", 349 " interface Builder extends BuilderParent<Builder> {", 350 " SimpleComponent build();", 351 " }", 352 "}"); 353 354 Compilation compilation = 355 daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile); 356 assertThat(compilation).failed(); 357 assertThat(compilation) 358 .hadErrorContaining( 359 String.format( 360 MSGS.inheritedBindsInstanceNotAllowedOnBothSetterMethodAndParameter(), 361 "s(java.lang.String)")) 362 .inFile(componentFile) 363 .onLineContaining("Builder extends BuilderParent<Builder>"); 364 } 365 } 366