/* * Copyright (C) 2014 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 androidx.room.compiler.processing.util.Source; import com.google.common.collect.ImmutableMap; import dagger.testing.compile.CompilerTests; import dagger.testing.golden.GoldenFileRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @RunWith(JUnit4.class) // TODO(gak): add tests for generation in the default package. public final class InjectConstructorFactoryGeneratorTest { private static final Source QUALIFIER_A = CompilerTests.javaSource("test.QualifierA", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier @interface QualifierA {}"); private static final Source QUALIFIER_B = CompilerTests.javaSource("test.QualifierB", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier @interface QualifierB {}"); private static final Source SCOPE_A = CompilerTests.javaSource("test.ScopeA", "package test;", "", "import javax.inject.Scope;", "", "@Scope @interface ScopeA {}"); private static final Source SCOPE_B = CompilerTests.javaSource("test.ScopeB", "package test;", "", "import javax.inject.Scope;", "", "@Scope @interface ScopeB {}"); @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule(); @Test public void injectOnPrivateConstructor() { Source file = CompilerTests.javaSource( "test.PrivateConstructor", "package test;", "", "import javax.inject.Inject;", "", "class PrivateConstructor {", " @Inject private PrivateConstructor() {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining( "Dagger does not support injection into private constructors") .onSource(file) .onLine(6); }); } @Test public void injectConstructorOnInnerClass() { Source file = CompilerTests.javaSource( "test.OuterClass", "package test;", "", "import javax.inject.Inject;", "", "class OuterClass {", " class InnerClass {", " @Inject InnerClass() {}", " }", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining( "@Inject constructors are invalid on inner classes. " + "Did you mean to make the class static?") .onSource(file) .onLine(7); }); } @Test public void injectConstructorOnAbstractClass() { Source file = CompilerTests.javaSource( "test.AbstractClass", "package test;", "", "import javax.inject.Inject;", "", "abstract class AbstractClass {", " @Inject AbstractClass() {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining( "@Inject is nonsense on the constructor of an abstract class") .onSource(file) .onLine(6); }); } @Test public void injectConstructorOnGenericClass() { Source file = CompilerTests.javaSource( "test.GenericClass", "package test;", "", "import javax.inject.Inject;", "", "class GenericClass {", " @Inject GenericClass(T t) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); }); } @Test public void fieldAndMethodGenerics() { Source file = CompilerTests.javaSource( "test.GenericClass", "package test;", "", "import javax.inject.Inject;", "", "class GenericClass {", " @Inject A a;", "", " @Inject GenericClass() {}", "", " @Inject void register(B b) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); }); } @Test public void genericClassWithNoDependencies() { Source file = CompilerTests.javaSource( "test.GenericClass", "package test;", "", "import javax.inject.Inject;", "", "class GenericClass {", " @Inject GenericClass() {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); }); } @Test public void twoGenericTypes() { Source file = CompilerTests.javaSource( "test.GenericClass", "package test;", "", "import javax.inject.Inject;", "", "class GenericClass {", " @Inject GenericClass(A a, B b) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); }); } @Test public void boundedGenerics() { Source file = CompilerTests.javaSource( "test.GenericClass", "package test;", "", "import javax.inject.Inject;", "import java.util.List;", "", "class GenericClass,", " B extends List,", " C extends List> {", " @Inject GenericClass(A a, B b, C c) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); }); } @Test public void multipleSameTypesWithGenericsAndQualifiersAndLazies() { Source file = CompilerTests.javaSource( "test.GenericClass", "package test;", "", "import javax.inject.Inject;", "import javax.inject.Provider;", "import dagger.Lazy;", "", "class GenericClass {", " @Inject GenericClass(A a, A a2, Provider pa, @QualifierA A qa, Lazy la, ", " String s, String s2, Provider ps, ", " @QualifierA String qs, Lazy ls,", " B b, B b2, Provider pb, @QualifierA B qb, Lazy lb) {}", "}"); CompilerTests.daggerCompiler(file, QUALIFIER_A) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/GenericClass_Factory")); }); } @Test public void multipleInjectConstructors() { Source file = CompilerTests.javaSource( "test.TooManyInjectConstructors", "package test;", "", "import javax.inject.Inject;", "", "class TooManyInjectConstructors {", " @Inject TooManyInjectConstructors() {}", " TooManyInjectConstructors(int i) {}", " @Inject TooManyInjectConstructors(String s) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining( "Type test.TooManyInjectConstructors may only contain one injected " + "constructor. Found: [" + "@Inject test.TooManyInjectConstructors(), " + "@Inject test.TooManyInjectConstructors(String)" + "]") .onSource(file) .onLine(5); }); } @Test public void multipleQualifiersOnInjectConstructorParameter() { Source file = CompilerTests.javaSource( "test.MultipleQualifierConstructorParam", "package test;", "", "import javax.inject.Inject;", "", "class MultipleQualifierConstructorParam {", " @Inject MultipleQualifierConstructorParam(", " @QualifierA", " @QualifierB", " String s) {}", "}"); CompilerTests.daggerCompiler(file, QUALIFIER_A, QUALIFIER_B) .compile( subject -> { subject.hasErrorCount(2); subject.hasErrorContaining( "A single dependency request may not use more than one @Qualifier") .onSource(file) .onLine(7); subject.hasErrorContaining( "A single dependency request may not use more than one @Qualifier") .onSource(file) .onLine(8); }); } @Test public void injectConstructorOnClassWithMultipleScopes() { Source file = CompilerTests.javaSource( "test.MultipleScopeClass", "package test;", "", "import javax.inject.Inject;", "", "@ScopeA", "@ScopeB", "class MultipleScopeClass {", " @Inject MultipleScopeClass() {}", "}"); CompilerTests.daggerCompiler(file, SCOPE_A, SCOPE_B) .compile( subject -> { subject.hasErrorCount(2); subject.hasErrorContaining("A single binding may not declare more than one @Scope") .onSource(file) .onLine(5); subject.hasErrorContaining("A single binding may not declare more than one @Scope") .onSource(file) .onLine(6); }); } @Test public void injectConstructorWithQualifier() { Source file = CompilerTests.javaSource( "test.MultipleScopeClass", "package test;", "", "import javax.inject.Inject;", "", "class MultipleScopeClass {", " @Inject", " @QualifierA", " @QualifierB", " MultipleScopeClass() {}", "}"); CompilerTests.daggerCompiler(file, QUALIFIER_A, QUALIFIER_B) .compile( subject -> { subject.hasErrorCount(2); subject.hasErrorContaining( "@Qualifier annotations are not allowed on @Inject constructors") .onSource(file) .onLine(7); subject.hasErrorContaining( "@Qualifier annotations are not allowed on @Inject constructors") .onSource(file) .onLine(8); }); } @Test public void injectConstructorWithCheckedExceptionsError() { Source file = CompilerTests.javaSource( "test.CheckedExceptionClass", "package test;", "", "import javax.inject.Inject;", "", "class CheckedExceptionClass {", " @Inject CheckedExceptionClass() throws Exception {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining( "Dagger does not support checked exceptions on @Inject constructors") .onSource(file) .onLine(6); }); } @Test public void injectConstructorWithCheckedExceptionsWarning() { Source file = CompilerTests.javaSource( "test.CheckedExceptionClass", "package test;", "", "import javax.inject.Inject;", "", "class CheckedExceptionClass {", " @Inject CheckedExceptionClass() throws Exception {}", "}"); CompilerTests.daggerCompiler(file) .withProcessingOptions(ImmutableMap.of("dagger.privateMemberValidation", "WARNING")) .compile( subject -> { subject.hasErrorCount(0); subject.hasWarningCount(1); subject.hasWarningContaining( "Dagger does not support checked exceptions on @Inject constructors") .onSource(file) .onLine(6); }); } @Test public void privateInjectClassError() { Source file = CompilerTests.javaSource( "test.OuterClass", "package test;", "", "import javax.inject.Inject;", "", "final class OuterClass {", " private static final class InnerClass {", " @Inject InnerClass() {}", " }", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Dagger does not support injection into private classes") .onSource(file) .onLine(7); }); } @Test public void privateInjectClassWarning() { Source file = CompilerTests.javaSource( "test.OuterClass", "package test;", "", "import javax.inject.Inject;", "", "final class OuterClass {", " private static final class InnerClass {", " @Inject InnerClass() {}", " }", "}"); CompilerTests.daggerCompiler(file) .withProcessingOptions(ImmutableMap.of("dagger.privateMemberValidation", "WARNING")) .compile( subject -> { subject.hasErrorCount(0); subject.hasWarningCount(1); subject.hasWarningContaining("Dagger does not support injection into private classes") .onSource(file) .onLine(7); }); } @Test public void nestedInPrivateInjectClassError() { Source file = CompilerTests.javaSource( "test.OuterClass", "package test;", "", "import javax.inject.Inject;", "", "final class OuterClass {", " private static final class MiddleClass {", " static final class InnerClass {", " @Inject InnerClass() {}", " }", " }", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Dagger does not support injection into private classes") .onSource(file) .onLine(8); }); } @Test public void nestedInPrivateInjectClassWarning() { Source file = CompilerTests.javaSource( "test.OuterClass", "package test;", "", "import javax.inject.Inject;", "", "final class OuterClass {", " private static final class MiddleClass {", " static final class InnerClass {", " @Inject InnerClass() {}", " }", " }", "}"); CompilerTests.daggerCompiler(file) .withProcessingOptions(ImmutableMap.of("dagger.privateMemberValidation", "WARNING")) .compile( subject -> { subject.hasErrorCount(0); subject.hasWarningCount(1); subject.hasWarningContaining("Dagger does not support injection into private classes") .onSource(file) .onLine(8); }); } @Test public void finalInjectField() { Source file = CompilerTests.javaSource( "test.FinalInjectField", "package test;", "", "import javax.inject.Inject;", "", "class FinalInjectField {", " @Inject final String s;", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("@Inject fields may not be final") .onSource(file) .onLine(6); }); } @Test public void privateInjectFieldError() { Source file = CompilerTests.javaSource( "test.PrivateInjectField", "package test;", "", "import javax.inject.Inject;", "", "class PrivateInjectField {", " @Inject private String s;", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Dagger does not support injection into private fields") .onSource(file) .onLine(6); }); } @Test public void privateInjectFieldWarning() { Source file = CompilerTests.javaSource( "test.PrivateInjectField", "package test;", "", "import javax.inject.Inject;", "", "class PrivateInjectField {", " @Inject private String s;", "}"); CompilerTests.daggerCompiler(file) .withProcessingOptions(ImmutableMap.of("dagger.privateMemberValidation", "WARNING")) .compile( subject -> { subject.hasErrorCount(0); // TODO: Verify warning message when supported // subject.hasWarningCount(1); }); } @Test public void staticInjectFieldError() { Source file = CompilerTests.javaSource( "test.StaticInjectField", "package test;", "", "import javax.inject.Inject;", "", "class StaticInjectField {", " @Inject static String s;", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Dagger does not support injection into static fields") .onSource(file) .onLine(6); }); } @Test public void staticInjectFieldWarning() { Source file = CompilerTests.javaSource( "test.StaticInjectField", "package test;", "", "import javax.inject.Inject;", "", "class StaticInjectField {", " @Inject static String s;", "}"); CompilerTests.daggerCompiler(file) .withProcessingOptions(ImmutableMap.of("dagger.staticMemberValidation", "WARNING")) .compile( subject -> { subject.hasErrorCount(0); // TODO: Verify warning message when supported // subject.hasWarningCount(1); }); } @Test public void multipleQualifiersOnField() { Source file = CompilerTests.javaSource( "test.MultipleQualifierInjectField", "package test;", "", "import javax.inject.Inject;", "", "class MultipleQualifierInjectField {", " @Inject", " @QualifierA", " @QualifierB", " String s;", "}"); CompilerTests.daggerCompiler(file, QUALIFIER_A, QUALIFIER_B) .compile( subject -> { subject.hasErrorCount(2); subject.hasErrorContaining( "A single dependency request may not use more than one @Qualifier") .onSource(file) .onLine(7); subject.hasErrorContaining( "A single dependency request may not use more than one @Qualifier") .onSource(file) .onLine(8); }); } @Test public void abstractInjectMethod() { Source file = CompilerTests.javaSource( "test.AbstractInjectMethod", "package test;", "", "import javax.inject.Inject;", "", "abstract class AbstractInjectMethod {", " @Inject abstract void method();", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Methods with @Inject may not be abstract") .onSource(file) .onLine(6); }); } @Test public void privateInjectMethodError() { Source file = CompilerTests.javaSource( "test.PrivateInjectMethod", "package test;", "", "import javax.inject.Inject;", "", "class PrivateInjectMethod {", " @Inject private void method(){}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Dagger does not support injection into private methods") .onSource(file) .onLine(6); }); } @Test public void privateInjectMethodWarning() { Source file = CompilerTests.javaSource( "test.PrivateInjectMethod", "package test;", "", "import javax.inject.Inject;", "", "class PrivateInjectMethod {", " @Inject private void method(){}", "}"); CompilerTests.daggerCompiler(file) .withProcessingOptions(ImmutableMap.of("dagger.privateMemberValidation", "WARNING")) .compile( subject -> { subject.hasErrorCount(0); // TODO: Verify warning message when supported // subject.hasWarningCount(1); }); } @Test public void staticInjectMethodError() { Source file = CompilerTests.javaSource( "test.StaticInjectMethod", "package test;", "", "import javax.inject.Inject;", "", "class StaticInjectMethod {", " @Inject static void method(){}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Dagger does not support injection into static methods") .onSource(file) .onLine(6); }); } @Test public void staticInjectMethodWarning() { Source file = CompilerTests.javaSource( "test.StaticInjectMethod", "package test;", "", "import javax.inject.Inject;", "", "class StaticInjectMethod {", " @Inject static void method(){}", "}"); CompilerTests.daggerCompiler(file) .withProcessingOptions(ImmutableMap.of("dagger.staticMemberValidation", "WARNING")) .compile( subject -> { subject.hasErrorCount(0); // TODO: Verify warning message when supported // subject.hasWarningCount(1); }); } @Test public void genericInjectMethod() { Source file = CompilerTests.javaSource( "test.GenericInjectMethod", "package test;", "", "import javax.inject.Inject;", "", "class AbstractInjectMethod {", " @Inject void method();", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Methods with @Inject may not declare type parameters") .onSource(file) .onLine(6); }); } @Test public void multipleQualifiersOnInjectMethodParameter() { Source file = CompilerTests.javaSource( "test.MultipleQualifierMethodParam", "package test;", "", "import javax.inject.Inject;", "", "class MultipleQualifierMethodParam {", " @Inject void method(", " @QualifierA", " @QualifierB", " String s) {}", "}"); CompilerTests.daggerCompiler(file, QUALIFIER_A, QUALIFIER_B) .compile( subject -> { subject.hasErrorCount(2); subject.hasErrorContaining( "A single dependency request may not use more than one @Qualifier") .onSource(file) .onLine(7); subject.hasErrorContaining( "A single dependency request may not use more than one @Qualifier") .onSource(file) .onLine(8); }); } @Test public void injectConstructorDependsOnProduced() { Source file = CompilerTests.javaSource( "test.A", "package test;", "", "import dagger.producers.Produced;", "import javax.inject.Inject;", "", "final class A {", " @Inject A(Produced str) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Produced may only be injected in @Produces methods"); }); } @Test public void injectConstructorDependsOnProducer() { Source file = CompilerTests.javaSource( "test.A", "package test;", "", "import dagger.producers.Producer;", "import javax.inject.Inject;", "", "final class A {", " @Inject A(Producer str) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Producer may only be injected in @Produces methods"); }); } @Test public void injectFieldDependsOnProduced() { Source file = CompilerTests.javaSource( "test.A", "package test;", "", "import dagger.producers.Produced;", "import javax.inject.Inject;", "", "final class A {", " @Inject Produced str;", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Produced may only be injected in @Produces methods"); }); } @Test public void injectFieldDependsOnProducer() { Source file = CompilerTests.javaSource( "test.A", "package test;", "", "import dagger.producers.Producer;", "import javax.inject.Inject;", "", "final class A {", " @Inject Producer str;", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Producer may only be injected in @Produces methods"); }); } @Test public void injectMethodDependsOnProduced() { Source file = CompilerTests.javaSource( "test.A", "package test;", "", "import dagger.producers.Produced;", "import javax.inject.Inject;", "", "final class A {", " @Inject void inject(Produced str) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Produced may only be injected in @Produces methods"); }); } @Test public void injectMethodDependsOnProducer() { Source file = CompilerTests.javaSource( "test.A", "package test;", "", "import dagger.producers.Producer;", "import javax.inject.Inject;", "", "final class A {", " @Inject void inject(Producer str) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(1); subject.hasErrorContaining("Producer may only be injected in @Produces methods"); }); } @Test public void injectConstructor() { Source file = CompilerTests.javaSource("test.InjectConstructor", "package test;", "", "import javax.inject.Inject;", "", "class InjectConstructor {", " @Inject InjectConstructor(String s) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/InjectConstructor_Factory")); }); } @Test public void injectConstructorAndMembersInjection() { Source file = CompilerTests.javaSource("test.AllInjections", "package test;", "", "import javax.inject.Inject;", "", "class AllInjections {", " @Inject String s;", " @Inject AllInjections(String s) {}", " @Inject void s(String s) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/AllInjections_Factory")); }); } @Test public void wildcardDependency() { Source file = CompilerTests.javaSource("test.InjectConstructor", "package test;", "", "import java.util.List;", "import javax.inject.Inject;", "", "class InjectConstructor {", " @Inject InjectConstructor(List objects) {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/InjectConstructor_Factory")); }); } @Test public void basicNameCollision() { Source factoryFile = CompilerTests.javaSource("other.pkg.Factory", "package other.pkg;", "", "public class Factory {}"); Source file = CompilerTests.javaSource("test.InjectConstructor", "package test;", "", "import javax.inject.Inject;", "import other.pkg.Factory;", "", "class InjectConstructor {", " @Inject InjectConstructor(Factory factory) {}", "}"); CompilerTests.daggerCompiler(factoryFile, file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/InjectConstructor_Factory")); }); } @Test public void nestedNameCollision() { Source factoryFile = CompilerTests.javaSource("other.pkg.Outer", "package other.pkg;", "", "public class Outer {", " public class Factory {}", "}"); Source file = CompilerTests.javaSource("test.InjectConstructor", "package test;", "", "import javax.inject.Inject;", "import other.pkg.Outer;", "", "class InjectConstructor {", " @Inject InjectConstructor(Outer.Factory factory) {}", "}"); CompilerTests.daggerCompiler(factoryFile, file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/InjectConstructor_Factory")); }); } @Test public void samePackageNameCollision() { Source samePackageInterface = CompilerTests.javaSource( "test.CommonName", "package test;", "", "public interface CommonName {}"); Source differentPackageInterface = CompilerTests.javaSource( "other.pkg.CommonName", "package other.pkg;", "", "public interface CommonName {}"); Source file = CompilerTests.javaSource( "test.InjectConstructor", "package test;", "", "import javax.inject.Inject;", "", "class InjectConstructor implements CommonName {", " @Inject InjectConstructor(" + "other.pkg.CommonName otherPackage, CommonName samePackage) {}", "}"); CompilerTests.daggerCompiler(samePackageInterface, differentPackageInterface, file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/InjectConstructor_Factory")); }); } @Test public void noDeps() { Source file = CompilerTests.javaSource( "test.SimpleType", "package test;", "", "import javax.inject.Inject;", "", "final class SimpleType {", " @Inject SimpleType() {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/SimpleType_Factory")); }); } @Test public void simpleComponentWithNesting() { Source file = CompilerTests.javaSource( "test.OuterType", "package test;", "", "import dagger.Component;", "import javax.inject.Inject;", "", "final class OuterType {", " static class A {", " @Inject A() {}", " }", " static class B {", " @Inject A a;", " }", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/OuterType_A_Factory")); }); } @Test public void testScopedMetadata() throws Exception { Source file = CompilerTests.javaSource( "test.ScopedBinding", "package test;", "", "import javax.inject.Inject;", "import javax.inject.Singleton;", "", "@Singleton", "class ScopedBinding {", " @Inject", " ScopedBinding() {}", "}"); CompilerTests.daggerCompiler(file) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/ScopedBinding_Factory")); }); } @Test public void testScopedMetadataWithCustomScope() throws Exception { Source customScope = CompilerTests.javaSource( "test.CustomScope", "package test;", "", "import javax.inject.Scope;", "", "@Scope", "@interface CustomScope {", " String value();", "}"); Source customAnnotation = CompilerTests.javaSource( "test.CustomAnnotation", "package test;", "", "@interface CustomAnnotation {", " String value();", "}"); Source scopedBinding = CompilerTests.javaSource( "test.ScopedBinding", "package test;", "", "import javax.inject.Inject;", "import javax.inject.Singleton;", "", "@CustomAnnotation(\"someValue\")", "@CustomScope(\"someOtherValue\")", "class ScopedBinding {", " @Inject", " ScopedBinding() {}", "}"); CompilerTests.daggerCompiler(scopedBinding, customScope, customAnnotation) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/ScopedBinding_Factory")); }); } @Test public void testQualifierMetadata() throws Exception { Source someBinding = CompilerTests.javaSource( "test.SomeBinding", "package test;", "", "import javax.inject.Inject;", "import javax.inject.Singleton;", "", "@NonQualifier", "@MisplacedQualifier", "class SomeBinding {", " @NonQualifier @FieldQualifier @Inject String injectField;", " @NonQualifier @MisplacedQualifier String nonDaggerField;", "", " @NonQualifier", " @Inject", " SomeBinding(@NonQualifier @ConstructorParameterQualifier Double d) {}", "", " @NonQualifier", " @MisplacedQualifier", " SomeBinding(@NonQualifier @MisplacedQualifier Double d, int i) {}", "", " @NonQualifier", " @MisplacedQualifier", " @Inject", " void injectMethod(@NonQualifier @MethodParameterQualifier Float f) {}", "", " @NonQualifier", " @MisplacedQualifier", " void nonDaggerMethod(@NonQualifier @MisplacedQualifier Float f) {}", "}"); Source fieldQualifier = CompilerTests.javaSource( "test.FieldQualifier", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "@interface FieldQualifier {}"); Source constructorParameterQualifier = CompilerTests.javaSource( "test.ConstructorParameterQualifier", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "@interface ConstructorParameterQualifier {}"); Source methodParameterQualifier = CompilerTests.javaSource( "test.MethodParameterQualifier", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "@interface MethodParameterQualifier {}"); Source misplacedQualifier = CompilerTests.javaSource( "test.MisplacedQualifier", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "@interface MisplacedQualifier {}"); Source nonQualifier = CompilerTests.javaSource( "test.NonQualifier", "package test;", "", "@interface NonQualifier {}"); CompilerTests.daggerCompiler( someBinding, fieldQualifier, constructorParameterQualifier, methodParameterQualifier, misplacedQualifier, nonQualifier) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/SomeBinding_Factory")); subject.generatedSource( goldenFileRule.goldenSource("test/SomeBinding_MembersInjector")); }); } @Test public void testComplexQualifierMetadata() throws Exception { Source someBinding = CompilerTests.javaSource( "test.SomeBinding", "package test;", "", "import javax.inject.Inject;", "import javax.inject.Inject;", "", "class SomeBinding {", " @QualifierWithValue(1) @Inject String injectField;", "", " @Inject", " SomeBinding(", " @pkg1.SameNameQualifier String str1,", " @pkg2.SameNameQualifier String str2) {}", "", " @Inject", " void injectMethod(@test.Outer.NestedQualifier Float f) {}", "}"); Source qualifierWithValue = CompilerTests.javaSource( "test.QualifierWithValue", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "@interface QualifierWithValue {", " int value();", "}"); Source pkg1SameNameQualifier = CompilerTests.javaSource( "pkg1.SameNameQualifier", "package pkg1;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "public @interface SameNameQualifier {}"); Source pkg2SameNameQualifier = CompilerTests.javaSource( "pkg2.SameNameQualifier", "package pkg2;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "public @interface SameNameQualifier {}"); Source nestedQualifier = CompilerTests.javaSource( "test.Outer", "package test;", "", "import javax.inject.Qualifier;", "", "interface Outer {", " @Qualifier", " @interface NestedQualifier {}", "}"); CompilerTests.daggerCompiler( someBinding, qualifierWithValue, pkg1SameNameQualifier, pkg2SameNameQualifier, nestedQualifier) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/SomeBinding_Factory")); subject.generatedSource( goldenFileRule.goldenSource("test/SomeBinding_MembersInjector")); }); } @Test public void testBaseClassQualifierMetadata() throws Exception { Source foo = CompilerTests.javaSource( "test.Foo", "package test;", "", "import javax.inject.Inject;", "import javax.inject.Singleton;", "", "class Foo extends FooBase {", " @FooFieldQualifier @Inject String injectField;", "", " @Inject", " Foo(@FooConstructorQualifier int i) { super(i); }", "", " @Inject", " void injectMethod(@FooMethodQualifier float f) {}", "}"); Source fooFieldQualifier = CompilerTests.javaSource( "test.FooFieldQualifier", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "@interface FooFieldQualifier {}"); Source fooConstructorQualifier = CompilerTests.javaSource( "test.FooConstructorQualifier", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "@interface FooConstructorQualifier {}"); Source fooMethodQualifier = CompilerTests.javaSource( "test.FooMethodQualifier", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "@interface FooMethodQualifier {}"); Source fooBase = CompilerTests.javaSource( "test.FooBase", "package test;", "", "import javax.inject.Inject;", "import javax.inject.Singleton;", "", "class FooBase {", " @FooBaseFieldQualifier @Inject String injectField;", "", " @Inject", " FooBase(@FooBaseConstructorQualifier int i) {}", "", " @Inject", " void injectMethod(@FooBaseMethodQualifier float f) {}", "}"); Source fooBaseFieldQualifier = CompilerTests.javaSource( "test.FooBaseFieldQualifier", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "@interface FooBaseFieldQualifier {}"); Source fooBaseConstructorQualifier = CompilerTests.javaSource( "test.FooBaseConstructorQualifier", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "@interface FooBaseConstructorQualifier {}"); Source fooBaseMethodQualifier = CompilerTests.javaSource( "test.FooBaseMethodQualifier", "package test;", "", "import javax.inject.Qualifier;", "", "@Qualifier", "@interface FooBaseMethodQualifier {}"); CompilerTests.daggerCompiler( foo, fooBase, fooFieldQualifier, fooConstructorQualifier, fooMethodQualifier, fooBaseFieldQualifier, fooBaseConstructorQualifier, fooBaseMethodQualifier) .compile( subject -> { subject.hasErrorCount(0); subject.generatedSource(goldenFileRule.goldenSource("test/Foo_Factory")); subject.generatedSource(goldenFileRule.goldenSource("test/Foo_MembersInjector")); subject.generatedSource(goldenFileRule.goldenSource("test/FooBase_Factory")); subject.generatedSource(goldenFileRule.goldenSource("test/FooBase_MembersInjector")); }); } }