blob: 901c7a3b0d5a94e36e40a977fb532076ce857ca0 [file] [log] [blame]
/*
* Copyright (C) 2019 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.hilt.processor.internal.definecomponent;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static com.google.testing.compile.Compiler.javac;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.Compiler;
import com.google.testing.compile.JavaFileObjects;
import dagger.hilt.processor.internal.GeneratedImport;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public final class DefineComponentProcessorTest {
@Test
public void testDefineComponentOutput() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.FooComponent",
"package test;",
"",
"import dagger.hilt.components.SingletonComponent;",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent(parent = SingletonComponent.class)",
"interface FooComponent {",
" static int staticField = 1;",
" static int staticMethod() { return staticField; }",
"}");
JavaFileObject builder =
JavaFileObjects.forSourceLines(
"test.FooComponentBuilder",
"package test;",
"",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent.Builder",
"interface FooComponentBuilder {",
" static int staticField = 1;",
" static int staticMethod() { return staticField; }",
"",
" FooComponent create();",
"}");
JavaFileObject componentOutput =
JavaFileObjects.forSourceLines(
"dagger.hilt.processor.internal.definecomponent.codegen.test_FooComponent",
"package dagger.hilt.processor.internal.definecomponent.codegen;",
"",
"import dagger.hilt.internal.definecomponent.DefineComponentClasses;",
GeneratedImport.IMPORT_GENERATED_ANNOTATION,
"",
"@DefineComponentClasses(component = \"test.FooComponent\")",
"@Generated(\"" + DefineComponentProcessor.class.getName() + "\")",
"interface test_FooComponent {}");
JavaFileObject builderOutput =
JavaFileObjects.forSourceLines(
"dagger.hilt.processor.internal.definecomponent.codegen.test_FooComponentBuilder",
"package dagger.hilt.processor.internal.definecomponent.codegen;",
"",
"import dagger.hilt.internal.definecomponent.DefineComponentClasses;",
GeneratedImport.IMPORT_GENERATED_ANNOTATION,
"",
"@DefineComponentClasses(builder = \"test.FooComponentBuilder\")",
"@Generated(\"" + DefineComponentProcessor.class.getName() + "\")",
"interface test_FooComponentBuilder {}");
Compilation compilation = compiler().compile(component, builder);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile(sourceName(componentOutput))
.hasSourceEquivalentTo(componentOutput);
assertThat(compilation)
.generatedSourceFile(sourceName(builderOutput))
.hasSourceEquivalentTo(builderOutput);
}
private static String sourceName(JavaFileObject fileObject) {
return fileObject.getName().replace(".java", "").replace('.', '/');
}
@Test
public void testDefineComponentClass_fails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.FooComponent",
"package test;",
"",
"import dagger.hilt.components.SingletonComponent;",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent( parent = SingletonComponent.class )",
"abstract class FooComponent {}");
Compilation compilation = compiler().compile(component);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent is only allowed on interfaces. Found: test.FooComponent");
}
@Test
public void testDefineComponentWithTypeParameters_fails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.FooComponent",
"package test;",
"",
"import dagger.hilt.components.SingletonComponent;",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent( parent = SingletonComponent.class )",
"interface FooComponent<T> {}");
Compilation compilation = compiler().compile(component);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining("@DefineComponent test.FooComponent<T>, cannot have type parameters.");
}
@Test
public void testDefineComponentWithInvalidComponent_fails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.FooComponent",
"package test;",
"",
"import dagger.hilt.DefineComponent;",
"import dagger.hilt.android.qualifiers.ApplicationContext;",
"",
"@DefineComponent( parent = ApplicationContext.class )",
"interface FooComponent {}");
Compilation compilation = compiler().compile(component);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent test.FooComponent, references a type not annotated with "
+ "@DefineComponent: dagger.hilt.android.qualifiers.ApplicationContext")
.inFile(component);
}
@Test
public void testDefineComponentExtendsInterface_fails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.FooComponent",
"package test;",
"",
"import dagger.hilt.components.SingletonComponent;",
"import dagger.hilt.DefineComponent;",
"",
"interface Foo {}",
"",
"@DefineComponent( parent = SingletonComponent.class )",
"interface FooComponent extends Foo {}");
Compilation compilation = compiler().compile(component);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent test.FooComponent, cannot extend a super class or interface."
+ " Found: test.Foo");
}
@Test
public void testDefineComponentNonStaticMethod_fails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.FooComponent",
"package test;",
"",
"import dagger.hilt.components.SingletonComponent;",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent( parent = SingletonComponent.class )",
"interface FooComponent {",
" int nonStaticMethod();",
"}");
Compilation compilation = compiler().compile(component);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent test.FooComponent, cannot have non-static methods. "
+ "Found: [nonStaticMethod()]");
}
@Test
public void testDefineComponentDependencyCycle_fails() {
JavaFileObject component1 =
JavaFileObjects.forSourceLines(
"test.Component1",
"package test;",
"",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent(parent = Component2.class)",
"interface Component1 {}");
JavaFileObject component2 =
JavaFileObjects.forSourceLines(
"test.Component2",
"package test;",
"",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent(parent = Component1.class)",
"interface Component2 {}");
Compilation compilation = compiler().compile(component1, component2);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(2);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent cycle: test.Component1 -> test.Component2 -> test.Component1");
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent cycle: test.Component2 -> test.Component1 -> test.Component2");
}
@Test
public void testDefineComponentNoParent_fails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.FooComponent",
"package test;",
"",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent",
"interface FooComponent {}");
Compilation compilation = compiler().compile(component);
assertThat(compilation)
.hadErrorContaining("@DefineComponent test.FooComponent is missing a parent declaration.");
}
@Test
public void testDefineComponentBuilderClass_fails() {
JavaFileObject builder =
JavaFileObjects.forSourceLines(
"test.FooComponentBuilder",
"package test;",
"",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent.Builder",
"abstract class FooComponentBuilder {}");
Compilation compilation = compiler().compile(builder);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent.Builder is only allowed on interfaces. "
+ "Found: test.FooComponentBuilder");
}
@Test
public void testDefineComponentBuilderWithTypeParameters_fails() {
JavaFileObject builder =
JavaFileObjects.forSourceLines(
"test.FooComponentBuilder",
"package test;",
"",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent.Builder",
"interface FooComponentBuilder<T> {}");
Compilation compilation = compiler().compile(builder);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent.Builder test.FooComponentBuilder<T>, cannot have type "
+ "parameters.");
}
@Test
public void testDefineComponentBuilderExtendsInterface_fails() {
JavaFileObject builder =
JavaFileObjects.forSourceLines(
"test.FooComponentBuilder",
"package test;",
"",
"import dagger.hilt.DefineComponent;",
"",
"interface Foo {}",
"",
"@DefineComponent.Builder",
"interface FooComponentBuilder extends Foo {}");
Compilation compilation = compiler().compile(builder);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent.Builder test.FooComponentBuilder, cannot extend a super class "
+ "or interface. Found: test.Foo");
}
@Test
public void testDefineComponentBuilderNoBuilderMethod_fails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.FooComponent",
"package test;",
"",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent.Builder",
"interface FooComponentBuilder {}");
Compilation compilation = compiler().compile(component);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent.Builder test.FooComponentBuilder, must have exactly 1 build "
+ "method that takes no parameters. Found: []");
}
@Test
public void testDefineComponentBuilderPrimitiveReturnType_fails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.FooComponent",
"package test;",
"",
"import dagger.hilt.DefineComponent;",
"",
"@DefineComponent.Builder",
"interface FooComponentBuilder {",
" int nonStaticMethod();",
"}");
Compilation compilation = compiler().compile(component);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent.Builder method, test.FooComponentBuilder#nonStaticMethod(), "
+ "must return a @DefineComponent type. Found: int");
}
@Test
public void testDefineComponentBuilderWrongReturnType_fails() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.FooComponent",
"package test;",
"",
"import dagger.hilt.DefineComponent;",
"",
"interface Foo {}",
"",
"@DefineComponent.Builder",
"interface FooComponentBuilder {",
" Foo build();",
"}");
Compilation compilation = compiler().compile(component);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent.Builder method, test.FooComponentBuilder#build(), must return "
+ "a @DefineComponent type. Found: test.Foo");
}
private static Compiler compiler() {
return javac().withProcessors(new DefineComponentProcessor());
}
}