1279 lines
44 KiB
Java
1279 lines
44 KiB
Java
/*
|
|
* Copyright (C) 2015 The Dagger Authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package dagger.internal.codegen;
|
|
|
|
import static com.google.common.truth.TruthJUnit.assume;
|
|
import static com.google.testing.compile.CompilationSubject.assertThat;
|
|
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
|
|
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
|
|
import static dagger.internal.codegen.Compilers.compilerWithOptions;
|
|
import static dagger.internal.codegen.Compilers.daggerCompiler;
|
|
import static dagger.internal.codegen.ComponentCreatorTest.CompilerType.JAVAC;
|
|
import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.COMPONENT_BUILDER;
|
|
import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.COMPONENT_FACTORY;
|
|
import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
|
|
import static dagger.internal.codegen.binding.ComponentCreatorKind.FACTORY;
|
|
import static dagger.internal.codegen.binding.ComponentKind.COMPONENT;
|
|
import static dagger.internal.codegen.binding.ErrorMessages.componentMessagesFor;
|
|
|
|
import com.google.common.collect.ImmutableList;
|
|
import com.google.testing.compile.Compilation;
|
|
import com.google.testing.compile.JavaFileObjects;
|
|
import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
|
|
import java.util.Collection;
|
|
import javax.tools.JavaFileObject;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
import org.junit.runners.Parameterized;
|
|
import org.junit.runners.Parameterized.Parameters;
|
|
|
|
/** Tests for properties of component creators shared by both builders and factories. */
|
|
@RunWith(Parameterized.class)
|
|
public class ComponentCreatorTest extends ComponentCreatorTestHelper {
|
|
enum CompilerType {
|
|
JAVAC
|
|
}
|
|
|
|
private final CompilerType compilerType;
|
|
private final CompilerMode compilerMode;
|
|
|
|
@Parameters(name = "compilerMode={0}, creatorKind={1}")
|
|
public static Collection<Object[]> parameters() {
|
|
return ImmutableList.of(
|
|
new Object[]{DEFAULT_MODE, COMPONENT_BUILDER, JAVAC},
|
|
new Object[]{DEFAULT_MODE, COMPONENT_FACTORY, JAVAC},
|
|
new Object[]{FAST_INIT_MODE, COMPONENT_BUILDER, JAVAC},
|
|
new Object[]{FAST_INIT_MODE, COMPONENT_FACTORY, JAVAC});
|
|
}
|
|
|
|
public ComponentCreatorTest(
|
|
CompilerMode compilerMode,
|
|
ComponentCreatorAnnotation componentCreatorAnnotation,
|
|
CompilerType compilerType) {
|
|
super(compilerMode, componentCreatorAnnotation);
|
|
this.compilerMode = compilerMode;
|
|
this.compilerType = compilerType;
|
|
}
|
|
|
|
@Test
|
|
public void testEmptyCreator() {
|
|
assume().that(compilerType).isEqualTo(JAVAC);
|
|
JavaFileObject injectableTypeFile =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.SomeInjectableType",
|
|
"package test;",
|
|
"",
|
|
"import javax.inject.Inject;",
|
|
"",
|
|
"final class SomeInjectableType {",
|
|
" @Inject SomeInjectableType() {}",
|
|
"}");
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"interface SimpleComponent {",
|
|
" SomeInjectableType someInjectableType();",
|
|
"",
|
|
" @Component.Builder",
|
|
" static interface Builder {",
|
|
" SimpleComponent build();",
|
|
" }",
|
|
"}");
|
|
JavaFileObject generatedComponent =
|
|
preprocessedJavaFile(
|
|
"test.DaggerSimpleComponent",
|
|
"package test;",
|
|
"",
|
|
GeneratedLines.generatedAnnotations(),
|
|
"final class DaggerSimpleComponent implements SimpleComponent {",
|
|
" private static final class Builder implements SimpleComponent.Builder {",
|
|
" @Override",
|
|
" public SimpleComponent build() {",
|
|
" return new DaggerSimpleComponent();",
|
|
" }",
|
|
" }",
|
|
"}");
|
|
Compilation compilation = compile(injectableTypeFile, componentFile);
|
|
assertThat(compilation).succeeded();
|
|
assertThat(compilation)
|
|
.generatedSourceFile("test.DaggerSimpleComponent")
|
|
.containsElementsIn(generatedComponent);
|
|
}
|
|
|
|
@Test
|
|
public void testCanInstantiateModulesUserCannotSet() {
|
|
assume().that(compilerType).isEqualTo(JAVAC);
|
|
JavaFileObject module =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.TestModule",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Module;",
|
|
"import dagger.Provides;",
|
|
"",
|
|
"@Module",
|
|
"final class TestModule {",
|
|
" @Provides String string() { return null; }",
|
|
"}");
|
|
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.TestComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"",
|
|
"@Component(modules = TestModule.class)",
|
|
"interface TestComponent {",
|
|
" String string();",
|
|
"",
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" TestComponent build();",
|
|
" }",
|
|
"}");
|
|
JavaFileObject generatedComponent =
|
|
preprocessedJavaFile(
|
|
"test.DaggerTestComponent",
|
|
"package test;",
|
|
"",
|
|
GeneratedLines.generatedImports(),
|
|
"",
|
|
GeneratedLines.generatedAnnotations(),
|
|
"final class DaggerTestComponent implements TestComponent {",
|
|
" private final TestModule testModule;",
|
|
"",
|
|
" private DaggerTestComponent(TestModule testModuleParam) {",
|
|
" this.testModule = testModuleParam;",
|
|
" }",
|
|
"",
|
|
" public static TestComponent.Builder builder() {",
|
|
" return new Builder();",
|
|
" }",
|
|
"",
|
|
" public static TestComponent create() {",
|
|
" return new Builder().build();",
|
|
" }",
|
|
"",
|
|
" @Override",
|
|
" public String string() {",
|
|
" return TestModule_StringFactory.string(testModule);",
|
|
" }",
|
|
"",
|
|
" private static final class Builder implements TestComponent.Builder {",
|
|
" @Override",
|
|
" public TestComponent build() {",
|
|
" return new DaggerTestComponent(new TestModule());",
|
|
" }",
|
|
" }",
|
|
"}");
|
|
Compilation compilation = compile(module, componentFile);
|
|
assertThat(compilation).succeeded();
|
|
assertThat(compilation)
|
|
.generatedSourceFile("test.DaggerTestComponent")
|
|
.hasSourceEquivalentTo(generatedComponent);
|
|
}
|
|
|
|
@Test
|
|
public void testMoreThanOneCreatorOfSameTypeFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"interface SimpleComponent {",
|
|
" @Component.Builder",
|
|
" static interface Builder {",
|
|
" SimpleComponent build();",
|
|
" }",
|
|
"",
|
|
" @Component.Builder",
|
|
" interface Builder2 {",
|
|
" SimpleComponent build();",
|
|
" }",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(
|
|
String.format(
|
|
componentMessagesFor(COMPONENT).moreThanOne(),
|
|
process("[test.SimpleComponent.Builder, test.SimpleComponent.Builder2]")))
|
|
.inFile(componentFile);
|
|
}
|
|
|
|
@Test
|
|
public void testBothBuilderAndFactoryFails() {
|
|
JavaFileObject componentFile =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"interface SimpleComponent {",
|
|
" @Component.Builder",
|
|
" static interface Builder {",
|
|
" SimpleComponent build();",
|
|
" }",
|
|
"",
|
|
" @Component.Factory",
|
|
" interface Factory {",
|
|
" SimpleComponent create();",
|
|
" }",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(
|
|
String.format(
|
|
componentMessagesFor(COMPONENT).moreThanOne(),
|
|
"[test.SimpleComponent.Builder, test.SimpleComponent.Factory]"))
|
|
.inFile(componentFile);
|
|
}
|
|
|
|
@Test
|
|
public void testGenericCreatorTypeFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"interface SimpleComponent {",
|
|
" @Component.Builder",
|
|
" interface Builder<T> {",
|
|
" SimpleComponent build();",
|
|
" }",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation).hadErrorContaining(messages.generics()).inFile(componentFile);
|
|
}
|
|
|
|
@Test
|
|
public void testCreatorNotInComponentFails() {
|
|
JavaFileObject builder =
|
|
preprocessedJavaFile(
|
|
"test.Builder",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"",
|
|
"@Component.Builder",
|
|
"interface Builder {}");
|
|
Compilation compilation = compile(builder);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation).hadErrorContaining(messages.mustBeInComponent()).inFile(builder);
|
|
}
|
|
|
|
@Test
|
|
public void testCreatorMissingFactoryMethodFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"interface SimpleComponent {",
|
|
" @Component.Builder",
|
|
" interface Builder {}",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(messages.missingFactoryMethod())
|
|
.inFile(componentFile);
|
|
}
|
|
|
|
@Test
|
|
public void testCreatorWithBindsInstanceNoStaticCreateGenerated() {
|
|
assume().that(compilerType).isEqualTo(JAVAC);
|
|
JavaFileObject componentFile =
|
|
javaFileBuilder("test.SimpleComponent")
|
|
.addLines(
|
|
"package test;",
|
|
"",
|
|
"import dagger.BindsInstance;",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"interface SimpleComponent {",
|
|
" Object object();",
|
|
"")
|
|
.addLinesIf(
|
|
BUILDER,
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" @BindsInstance Builder object(Object object);",
|
|
" SimpleComponent build();",
|
|
" }")
|
|
.addLinesIf(
|
|
FACTORY,
|
|
" @Component.Factory",
|
|
" interface Factory {",
|
|
" SimpleComponent create(@BindsInstance Object object);",
|
|
" }")
|
|
.addLines("}")
|
|
.build();
|
|
|
|
JavaFileObject generatedComponent =
|
|
javaFileBuilder("test.DaggerSimpleComponent")
|
|
.addLines(
|
|
"package test;",
|
|
"",
|
|
GeneratedLines.generatedImports("import dagger.internal.Preconditions;"),
|
|
"",
|
|
GeneratedLines.generatedAnnotations(),
|
|
"final class DaggerSimpleComponent implements SimpleComponent {",
|
|
" private final Object object;",
|
|
"",
|
|
" private DaggerSimpleComponent(Object objectParam) {",
|
|
" this.object = objectParam;",
|
|
" }",
|
|
"")
|
|
.addLinesIf(
|
|
BUILDER,
|
|
" public static SimpleComponent.Builder builder() {",
|
|
" return new Builder();",
|
|
" }")
|
|
.addLinesIf(
|
|
FACTORY,
|
|
" public static SimpleComponent.Factory factory() {",
|
|
" return new Factory();",
|
|
" }")
|
|
.addLines(
|
|
"", //
|
|
" @Override",
|
|
" public Object object() {",
|
|
" return object;",
|
|
" }",
|
|
"")
|
|
.addLinesIf(
|
|
BUILDER,
|
|
" private static final class Builder implements SimpleComponent.Builder {",
|
|
" private Object object;",
|
|
"",
|
|
" @Override",
|
|
" public Builder object(Object object) {",
|
|
" this.object = Preconditions.checkNotNull(object);",
|
|
" return this;",
|
|
" }",
|
|
"",
|
|
" @Override",
|
|
" public SimpleComponent build() {",
|
|
" Preconditions.checkBuilderRequirement(object, Object.class);",
|
|
" return new DaggerSimpleComponent(object);",
|
|
" }",
|
|
" }")
|
|
.addLinesIf(
|
|
FACTORY,
|
|
" private static final class Factory implements SimpleComponent.Factory {",
|
|
" @Override",
|
|
" public SimpleComponent create(Object object) {",
|
|
" Preconditions.checkNotNull(object);",
|
|
" return new DaggerSimpleComponent(object);",
|
|
" }",
|
|
" }")
|
|
.addLines("}")
|
|
.build();
|
|
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).succeededWithoutWarnings();
|
|
assertThat(compilation)
|
|
.generatedSourceFile("test.DaggerSimpleComponent")
|
|
.hasSourceEquivalentTo(generatedComponent);
|
|
}
|
|
|
|
@Test
|
|
public void testCreatorWithPrimitiveBindsInstance() {
|
|
assume().that(compilerType).isEqualTo(JAVAC);
|
|
JavaFileObject componentFile =
|
|
javaFileBuilder("test.SimpleComponent")
|
|
.addLines(
|
|
"package test;",
|
|
"",
|
|
"import dagger.BindsInstance;",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"interface SimpleComponent {",
|
|
" int anInt();",
|
|
"")
|
|
.addLinesIf(
|
|
BUILDER,
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" @BindsInstance Builder i(int i);",
|
|
" SimpleComponent build();",
|
|
" }")
|
|
.addLinesIf(
|
|
FACTORY,
|
|
" @Component.Factory",
|
|
" interface Factory {",
|
|
" SimpleComponent create(@BindsInstance int i);",
|
|
" }")
|
|
.addLines(
|
|
"}")
|
|
.build();
|
|
|
|
JavaFileObject generatedComponent =
|
|
javaFileBuilder("test.DaggerSimpleComponent")
|
|
.addLines(
|
|
"package test;",
|
|
"",
|
|
GeneratedLines.generatedImports("import dagger.internal.Preconditions;"),
|
|
"",
|
|
GeneratedLines.generatedAnnotations(),
|
|
"final class DaggerSimpleComponent implements SimpleComponent {",
|
|
" private final Integer i;",
|
|
"",
|
|
" private DaggerSimpleComponent(Integer iParam) {",
|
|
" this.i = iParam;",
|
|
" }",
|
|
"",
|
|
" @Override",
|
|
" public int anInt() {",
|
|
" return i;",
|
|
" }",
|
|
"")
|
|
.addLinesIf(
|
|
BUILDER,
|
|
" private static final class Builder implements SimpleComponent.Builder {",
|
|
" private Integer i;",
|
|
"",
|
|
" @Override",
|
|
" public Builder i(int i) {",
|
|
" this.i = Preconditions.checkNotNull(i);",
|
|
" return this;",
|
|
" }",
|
|
"",
|
|
" @Override",
|
|
" public SimpleComponent build() {",
|
|
" Preconditions.checkBuilderRequirement(i, Integer.class);",
|
|
" return new DaggerSimpleComponent(i);",
|
|
" }",
|
|
" }")
|
|
.addLinesIf(
|
|
FACTORY,
|
|
" private static final class Factory implements SimpleComponent.Factory {",
|
|
" @Override",
|
|
" public SimpleComponent create(int i) {",
|
|
" Preconditions.checkNotNull(i);",
|
|
" return new DaggerSimpleComponent(i);",
|
|
" }",
|
|
" }")
|
|
.addLines(
|
|
"}")
|
|
.build();
|
|
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).succeededWithoutWarnings();
|
|
assertThat(compilation)
|
|
.generatedSourceFile("test.DaggerSimpleComponent")
|
|
.containsElementsIn(generatedComponent);
|
|
}
|
|
|
|
@Test
|
|
public void testPrivateCreatorFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" @Component.Builder",
|
|
" private interface Builder {}",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation).hadErrorContaining(messages.isPrivate()).inFile(componentFile);
|
|
}
|
|
|
|
@Test
|
|
public void testNonStaticCreatorFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" @Component.Builder",
|
|
" abstract class Builder {}",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation).hadErrorContaining(messages.mustBeStatic()).inFile(componentFile);
|
|
}
|
|
|
|
@Test
|
|
public void testNonAbstractCreatorFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" @Component.Builder",
|
|
" static class Builder {}",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation).hadErrorContaining(messages.mustBeAbstract()).inFile(componentFile);
|
|
}
|
|
|
|
@Test
|
|
public void testCreatorOneConstructorWithArgsFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" @Component.Builder",
|
|
" static abstract class Builder {",
|
|
" Builder(String unused) {}",
|
|
" }",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(messages.invalidConstructor())
|
|
.inFile(componentFile);
|
|
}
|
|
|
|
@Test
|
|
public void testCreatorMoreThanOneConstructorFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" @Component.Builder",
|
|
" static abstract class Builder {",
|
|
" Builder() {}",
|
|
" Builder(String unused) {}",
|
|
" }",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(messages.invalidConstructor())
|
|
.inFile(componentFile);
|
|
}
|
|
|
|
@Test
|
|
public void testCreatorEnumFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" @Component.Builder",
|
|
" enum Builder {}",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(messages.mustBeClassOrInterface())
|
|
.inFile(componentFile);
|
|
}
|
|
|
|
@Test
|
|
public void testCreatorFactoryMethodReturnsWrongTypeFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" String build();",
|
|
" }",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(messages.factoryMethodMustReturnComponentType())
|
|
.inFile(componentFile)
|
|
.onLineContaining(process("String build();"));
|
|
}
|
|
|
|
@Test
|
|
public void testCreatorSetterForNonBindsInstancePrimitiveFails() {
|
|
JavaFileObject component =
|
|
javaFileBuilder("test.TestComponent")
|
|
.addLines(
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"",
|
|
"@Component",
|
|
"interface TestComponent {",
|
|
" Object object();",
|
|
"")
|
|
.addLinesIf(
|
|
BUILDER,
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" Builder primitive(long l);",
|
|
" TestComponent build();",
|
|
" }")
|
|
.addLinesIf(
|
|
FACTORY,
|
|
" @Component.Factory",
|
|
" interface Factory {",
|
|
" TestComponent create(long l);",
|
|
" }")
|
|
.addLines( //
|
|
"}")
|
|
.build();
|
|
Compilation compilation = compile(component);
|
|
assertThat(compilation).failed();
|
|
|
|
assertThat(compilation)
|
|
.hadErrorContaining(messages.nonBindsInstanceParametersMayNotBePrimitives())
|
|
.inFile(component)
|
|
.onLineContaining("(long l)");
|
|
}
|
|
|
|
@Test
|
|
public void testInheritedBuilderBuildReturnsWrongTypeFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" interface Parent {",
|
|
" String build();",
|
|
" }",
|
|
"",
|
|
" @Component.Builder",
|
|
" interface Builder extends Parent {}",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(
|
|
String.format(
|
|
messages.inheritedFactoryMethodMustReturnComponentType(), process("build")))
|
|
.inFile(componentFile)
|
|
.onLineContaining(process("interface Builder"));
|
|
}
|
|
|
|
@Test
|
|
public void testTwoFactoryMethodsFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" SimpleComponent build();",
|
|
" SimpleComponent newSimpleComponent();",
|
|
" }",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(String.format(messages.twoFactoryMethods(), process("build")))
|
|
.inFile(componentFile)
|
|
.onLineContaining("SimpleComponent newSimpleComponent();");
|
|
}
|
|
|
|
@Test
|
|
public void testInheritedTwoFactoryMethodsFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" interface Parent {",
|
|
" SimpleComponent build();",
|
|
" SimpleComponent newSimpleComponent();",
|
|
" }",
|
|
"",
|
|
" @Component.Builder",
|
|
" interface Builder extends Parent {}",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(
|
|
String.format(
|
|
messages.inheritedTwoFactoryMethods(), process("build()"), "newSimpleComponent()"))
|
|
.inFile(componentFile)
|
|
.onLineContaining(process("interface Builder"));
|
|
}
|
|
|
|
@Test
|
|
public void testMultipleSettersPerTypeFails() {
|
|
assume().that(compilerType).isEqualTo(JAVAC);
|
|
JavaFileObject moduleFile =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.TestModule",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Module;",
|
|
"import dagger.Provides;",
|
|
"",
|
|
"@Module",
|
|
"final class TestModule {",
|
|
" @Provides String s() { return \"\"; }",
|
|
"}");
|
|
JavaFileObject componentFile =
|
|
javaFileBuilder("test.SimpleComponent")
|
|
.addLines(
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component(modules = TestModule.class)",
|
|
"abstract class SimpleComponent {",
|
|
" abstract String s();",
|
|
"")
|
|
.addLinesIf(
|
|
BUILDER,
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" SimpleComponent build();",
|
|
" void set1(TestModule s);",
|
|
" void set2(TestModule s);",
|
|
" }")
|
|
.addLinesIf(
|
|
FACTORY,
|
|
" @Component.Factory",
|
|
" interface Factory {",
|
|
" SimpleComponent create(TestModule m1, TestModule m2);",
|
|
" }")
|
|
.addLines( //
|
|
"}")
|
|
.build();
|
|
Compilation compilation = compile(moduleFile, componentFile);
|
|
assertThat(compilation).failed();
|
|
String elements =
|
|
creatorKind.equals(BUILDER)
|
|
? "[void test.SimpleComponent.Builder.set1(test.TestModule), "
|
|
+ "void test.SimpleComponent.Builder.set2(test.TestModule)]"
|
|
: "[test.TestModule m1, test.TestModule m2]";
|
|
assertThat(compilation)
|
|
.hadErrorContaining(
|
|
String.format(
|
|
messages.multipleSettersForModuleOrDependencyType(), "test.TestModule", elements))
|
|
.inFile(componentFile)
|
|
.onLineContaining(process("interface Builder"));
|
|
}
|
|
|
|
@Test
|
|
public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() {
|
|
assume().that(compilerType).isEqualTo(JAVAC);
|
|
JavaFileObject moduleFile =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.TestModule",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Module;",
|
|
"import dagger.Provides;",
|
|
"",
|
|
"@Module",
|
|
"final class TestModule {",
|
|
" @Provides String s() { return \"\"; }",
|
|
"}");
|
|
JavaFileObject componentFile =
|
|
javaFileBuilder("test.SimpleComponent")
|
|
.addLines(
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component(modules = TestModule.class)",
|
|
"abstract class SimpleComponent {",
|
|
" abstract String s();",
|
|
"")
|
|
.addLinesIf(
|
|
BUILDER,
|
|
" interface Parent<T> {",
|
|
" void set1(T t);",
|
|
" }",
|
|
"",
|
|
" @Component.Builder",
|
|
" interface Builder extends Parent<TestModule> {",
|
|
" SimpleComponent build();",
|
|
" void set2(TestModule s);",
|
|
" }")
|
|
.addLinesIf(
|
|
FACTORY,
|
|
" interface Parent<C, T> {",
|
|
" C create(TestModule m1, T t);",
|
|
" }",
|
|
"",
|
|
" @Component.Factory",
|
|
" interface Factory extends Parent<SimpleComponent, TestModule> {}")
|
|
.addLines( //
|
|
"}")
|
|
.build();
|
|
Compilation compilation = compile(moduleFile, componentFile);
|
|
assertThat(compilation).failed();
|
|
String elements =
|
|
creatorKind.equals(BUILDER)
|
|
? "[void test.SimpleComponent.Builder.set1(test.TestModule), "
|
|
+ "void test.SimpleComponent.Builder.set2(test.TestModule)]"
|
|
: "[test.TestModule m1, test.TestModule t]";
|
|
assertThat(compilation)
|
|
.hadErrorContaining(
|
|
String.format(
|
|
messages.multipleSettersForModuleOrDependencyType(), "test.TestModule", elements))
|
|
.inFile(componentFile)
|
|
.onLineContaining(process("interface Builder"));
|
|
}
|
|
|
|
@Test
|
|
public void testExtraSettersFails() {
|
|
assume().that(compilerType).isEqualTo(JAVAC);
|
|
JavaFileObject componentFile =
|
|
javaFileBuilder("test.SimpleComponent")
|
|
.addLines(
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component(modules = AbstractModule.class)",
|
|
"abstract class SimpleComponent {")
|
|
.addLinesIf(
|
|
BUILDER,
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" SimpleComponent build();",
|
|
" void abstractModule(AbstractModule abstractModule);",
|
|
" void other(String s);",
|
|
" }")
|
|
.addLinesIf(
|
|
FACTORY,
|
|
" @Component.Factory",
|
|
" interface Factory {",
|
|
" SimpleComponent create(AbstractModule abstractModule, String s);",
|
|
" }")
|
|
.addLines("}")
|
|
.build();
|
|
JavaFileObject abstractModule =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.AbstractModule",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Module;",
|
|
"",
|
|
"@Module",
|
|
"abstract class AbstractModule {}");
|
|
Compilation compilation = compile(componentFile, abstractModule);
|
|
assertThat(compilation).failed();
|
|
String elements =
|
|
creatorKind.equals(BUILDER)
|
|
? "[void test.SimpleComponent.Builder.abstractModule(test.AbstractModule), "
|
|
+ "void test.SimpleComponent.Builder.other(String)]"
|
|
: "[test.AbstractModule abstractModule, String s]";
|
|
assertThat(compilation)
|
|
.hadErrorContaining(String.format(messages.extraSetters(), elements))
|
|
.inFile(componentFile)
|
|
.onLineContaining(process("interface Builder"));
|
|
}
|
|
|
|
@Test
|
|
public void testMissingSettersFail() {
|
|
JavaFileObject moduleFile =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.TestModule",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Module;",
|
|
"import dagger.Provides;",
|
|
"",
|
|
"@Module",
|
|
"final class TestModule {",
|
|
" TestModule(String unused) {}",
|
|
" @Provides String s() { return null; }",
|
|
"}");
|
|
JavaFileObject module2File =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.Test2Module",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Module;",
|
|
"import dagger.Provides;",
|
|
"",
|
|
"@Module",
|
|
"final class Test2Module {",
|
|
" @Provides Integer i() { return null; }",
|
|
"}");
|
|
JavaFileObject module3File =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.Test3Module",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Module;",
|
|
"import dagger.Provides;",
|
|
"",
|
|
"@Module",
|
|
"final class Test3Module {",
|
|
" Test3Module(String unused) {}",
|
|
" @Provides Double d() { return null; }",
|
|
"}");
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.TestComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"",
|
|
"@Component(modules = {TestModule.class, Test2Module.class, Test3Module.class},",
|
|
" dependencies = OtherComponent.class)",
|
|
"interface TestComponent {",
|
|
" String string();",
|
|
" Integer integer();",
|
|
"",
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" TestComponent create();",
|
|
" }",
|
|
"}");
|
|
JavaFileObject otherComponent =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.OtherComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"",
|
|
"@Component",
|
|
"interface OtherComponent {}");
|
|
Compilation compilation =
|
|
daggerCompiler()
|
|
.compile(moduleFile, module2File, module3File, componentFile, otherComponent);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(
|
|
// Ignores Test2Module because we can construct it ourselves.
|
|
// TODO(sameb): Ignore Test3Module because it's not used within transitive dependencies.
|
|
String.format(
|
|
messages.missingSetters(),
|
|
"[test.TestModule, test.Test3Module, test.OtherComponent]"))
|
|
.inFile(componentFile)
|
|
.onLineContaining(process("interface Builder"));
|
|
}
|
|
|
|
@Test
|
|
public void covariantFactoryMethodReturnType() {
|
|
assume().that(compilerType).isEqualTo(JAVAC);
|
|
JavaFileObject foo =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.Foo",
|
|
"package test;",
|
|
"",
|
|
"import javax.inject.Inject;",
|
|
"",
|
|
"class Foo {",
|
|
" @Inject Foo() {}",
|
|
"}");
|
|
JavaFileObject supertype =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.Supertype",
|
|
"package test;",
|
|
"",
|
|
"interface Supertype {",
|
|
" Foo foo();",
|
|
"}");
|
|
|
|
JavaFileObject component =
|
|
preprocessedJavaFile(
|
|
"test.HasSupertype",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"",
|
|
"@Component",
|
|
"interface HasSupertype extends Supertype {",
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" Supertype build();",
|
|
" }",
|
|
"}");
|
|
|
|
Compilation compilation = compile(foo, supertype, component);
|
|
assertThat(compilation).succeededWithoutWarnings();
|
|
}
|
|
|
|
@Test
|
|
public void covariantFactoryMethodReturnType_hasNewMethod() {
|
|
assume().that(compilerType).isEqualTo(JAVAC);
|
|
JavaFileObject foo =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.Foo",
|
|
"package test;",
|
|
"",
|
|
"import javax.inject.Inject;",
|
|
"",
|
|
"class Foo {",
|
|
" @Inject Foo() {}",
|
|
"}");
|
|
JavaFileObject bar =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.Bar",
|
|
"package test;",
|
|
"",
|
|
"import javax.inject.Inject;",
|
|
"",
|
|
"class Bar {",
|
|
" @Inject Bar() {}",
|
|
"}");
|
|
JavaFileObject supertype =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.Supertype",
|
|
"package test;",
|
|
"",
|
|
"interface Supertype {",
|
|
" Foo foo();",
|
|
"}");
|
|
|
|
JavaFileObject component =
|
|
preprocessedJavaFile(
|
|
"test.HasSupertype",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"",
|
|
"@Component",
|
|
"interface HasSupertype extends Supertype {",
|
|
" Bar bar();",
|
|
"",
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" Supertype build();",
|
|
" }",
|
|
"}");
|
|
|
|
Compilation compilation = compile(foo, bar, supertype, component);
|
|
assertThat(compilation).succeeded();
|
|
assertThat(compilation)
|
|
.hadWarningContaining(
|
|
process(
|
|
"test.HasSupertype.Builder.build() returns test.Supertype, but test.HasSupertype "
|
|
+ "declares additional component method(s): bar(). In order to provide "
|
|
+ "type-safe access to these methods, override build() to return "
|
|
+ "test.HasSupertype"))
|
|
.inFile(component)
|
|
.onLine(11);
|
|
}
|
|
|
|
@Test
|
|
public void covariantFactoryMethodReturnType_hasNewMethod_factoryMethodInherited() {
|
|
assume().that(compilerType).isEqualTo(JAVAC);
|
|
JavaFileObject foo =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.Foo",
|
|
"package test;",
|
|
"",
|
|
"import javax.inject.Inject;",
|
|
"",
|
|
"class Foo {",
|
|
" @Inject Foo() {}",
|
|
"}");
|
|
JavaFileObject bar =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.Bar",
|
|
"package test;",
|
|
"",
|
|
"import javax.inject.Inject;",
|
|
"",
|
|
"class Bar {",
|
|
" @Inject Bar() {}",
|
|
"}");
|
|
JavaFileObject supertype =
|
|
JavaFileObjects.forSourceLines(
|
|
"test.Supertype",
|
|
"package test;",
|
|
"",
|
|
"interface Supertype {",
|
|
" Foo foo();",
|
|
"}");
|
|
|
|
JavaFileObject creatorSupertype =
|
|
preprocessedJavaFile(
|
|
"test.CreatorSupertype",
|
|
"package test;",
|
|
"",
|
|
"interface CreatorSupertype {",
|
|
" Supertype build();",
|
|
"}");
|
|
|
|
JavaFileObject component =
|
|
preprocessedJavaFile(
|
|
"test.HasSupertype",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"",
|
|
"@Component",
|
|
"interface HasSupertype extends Supertype {",
|
|
" Bar bar();",
|
|
"",
|
|
" @Component.Builder",
|
|
" interface Builder extends CreatorSupertype {}",
|
|
"}");
|
|
|
|
Compilation compilation = compile(foo, bar, supertype, creatorSupertype, component);
|
|
assertThat(compilation).succeeded();
|
|
assertThat(compilation)
|
|
.hadWarningContaining(
|
|
process(
|
|
"test.HasSupertype.Builder.build() returns test.Supertype, but test.HasSupertype "
|
|
+ "declares additional component method(s): bar(). In order to provide "
|
|
+ "type-safe access to these methods, override build() to return "
|
|
+ "test.HasSupertype"));
|
|
}
|
|
|
|
@Test
|
|
public void testGenericsOnFactoryMethodFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" @Component.Builder",
|
|
" interface Builder {",
|
|
" <T> SimpleComponent build();",
|
|
" }",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(messages.methodsMayNotHaveTypeParameters())
|
|
.inFile(componentFile)
|
|
.onLineContaining(process("<T> SimpleComponent build();"));
|
|
}
|
|
|
|
@Test
|
|
public void testGenericsOnInheritedFactoryMethodFails() {
|
|
JavaFileObject componentFile =
|
|
preprocessedJavaFile(
|
|
"test.SimpleComponent",
|
|
"package test;",
|
|
"",
|
|
"import dagger.Component;",
|
|
"import javax.inject.Provider;",
|
|
"",
|
|
"@Component",
|
|
"abstract class SimpleComponent {",
|
|
" interface Parent {",
|
|
" <T> SimpleComponent build();",
|
|
" }",
|
|
"",
|
|
" @Component.Builder",
|
|
" interface Builder extends Parent {}",
|
|
"}");
|
|
Compilation compilation = compile(componentFile);
|
|
assertThat(compilation).failed();
|
|
assertThat(compilation)
|
|
.hadErrorContaining(
|
|
String.format(
|
|
messages.inheritedMethodsMayNotHaveTypeParameters(), process("<T>build()")))
|
|
.inFile(componentFile)
|
|
.onLineContaining(process("interface Builder"));
|
|
}
|
|
|
|
/** Compiles the given files with the set compiler mode's javacopts. */
|
|
@Override
|
|
Compilation compile(JavaFileObject... files) {
|
|
ImmutableList.Builder<String> options =
|
|
ImmutableList.<String>builder().addAll(compilerMode.javacopts());
|
|
|
|
return compilerWithOptions(options.build()).compile(files);
|
|
}
|
|
}
|