blob: 6fb1820159d11e68838f5fb39336ed0874fe7099 [file] [log] [blame]
/*
* Copyright (C) 2016 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.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.TestUtils.message;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {ComponentHierarchyValidator}. */
@RunWith(JUnit4.class)
public class ComponentHierarchyValidationTest {
@Test
public void singletonSubcomponent() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.Parent",
"package test;",
"",
"import dagger.Component;",
"import javax.inject.Singleton;",
"",
"@Singleton",
"@Component",
"interface Parent {",
" Child child();",
"}");
JavaFileObject subcomponent =
JavaFileObjects.forSourceLines(
"test.Child",
"package test;",
"",
"import dagger.Subcomponent;",
"import javax.inject.Singleton;",
"",
"@Singleton",
"@Subcomponent",
"interface Child {}");
Compilation compilation = daggerCompiler().compile(component, subcomponent);
assertThat(compilation).failed();
assertThat(compilation).hadErrorContaining("conflicting scopes");
assertThat(compilation).hadErrorContaining("test.Parent also has @Singleton");
Compilation withoutScopeValidation =
compilerWithOptions("-Adagger.disableInterComponentScopeValidation=none")
.compile(component, subcomponent);
assertThat(withoutScopeValidation).succeeded();
}
@Test
public void productionComponents_productionScopeImplicitOnBoth() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.Parent",
"package test;",
"",
"import dagger.producers.ProductionComponent;",
"",
"@ProductionComponent(modules = ParentModule.class)",
"interface Parent {",
" Child child();",
" Object productionScopedObject();",
"}");
JavaFileObject parentModule =
JavaFileObjects.forSourceLines(
"test.ParentModule",
"package test;",
"",
"import dagger.Provides;",
"import dagger.producers.ProducerModule;",
"import dagger.producers.ProductionScope;",
"",
"@ProducerModule",
"class ParentModule {",
" @Provides @ProductionScope Object parentScopedObject() { return new Object(); }",
"}");
JavaFileObject subcomponent =
JavaFileObjects.forSourceLines(
"test.Child",
"package test;",
"",
"import dagger.producers.ProductionSubcomponent;",
"",
"@ProductionSubcomponent(modules = ChildModule.class)",
"interface Child {",
" String productionScopedString();",
"}");
JavaFileObject childModule =
JavaFileObjects.forSourceLines(
"test.ChildModule",
"package test;",
"",
"import dagger.Provides;",
"import dagger.producers.ProducerModule;",
"import dagger.producers.ProductionScope;",
"",
"@ProducerModule",
"class ChildModule {",
" @Provides @ProductionScope String childScopedString() { return new String(); }",
"}");
Compilation compilation =
daggerCompiler().compile(component, subcomponent, parentModule, childModule);
assertThat(compilation).succeeded();
}
@Test
public void producerModuleRepeated() {
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.Parent",
"package test;",
"",
"import dagger.producers.ProductionComponent;",
"",
"@ProductionComponent(modules = RepeatedProducerModule.class)",
"interface Parent {",
" Child child();",
"}");
JavaFileObject repeatedModule =
JavaFileObjects.forSourceLines(
"test.RepeatedProducerModule",
"package test;",
"",
"import dagger.producers.ProducerModule;",
"",
"@ProducerModule",
"interface RepeatedProducerModule {}");
JavaFileObject subcomponent =
JavaFileObjects.forSourceLines(
"test.Child",
"package test;",
"",
"import dagger.producers.ProductionSubcomponent;",
"",
"@ProductionSubcomponent(modules = RepeatedProducerModule.class)",
"interface Child {}");
Compilation compilation = daggerCompiler().compile(component, subcomponent, repeatedModule);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
"test.Child repeats @ProducerModules:",
" test.Parent also installs: test.RepeatedProducerModule"))
.inFile(component)
.onLineContaining("interface Parent");
}
@Test
public void factoryMethodForSubcomponentWithBuilder_isNotAllowed() {
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.TestModule",
"package test;",
"",
"import dagger.Module;",
"import dagger.Provides;",
"",
"@Module(subcomponents = Sub.class)",
"class TestModule {",
"}");
JavaFileObject subcomponent =
JavaFileObjects.forSourceLines(
"test.Sub",
"package test;",
"",
"import dagger.Subcomponent;",
"",
"@Subcomponent",
"interface Sub {",
" @Subcomponent.Builder",
" interface Builder {",
" Sub build();",
" }",
"}");
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.Sub",
"package test;",
"",
"import dagger.Component;",
"",
"@Component(modules = TestModule.class)",
"interface C {",
" Sub newSub();",
"}");
Compilation compilation = daggerCompiler().compile(module, component, subcomponent);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
"Components may not have factory methods for subcomponents that define a builder.");
}
@Test
public void repeatedModulesWithScopes() {
JavaFileObject testScope =
JavaFileObjects.forSourceLines(
"test.TestScope",
"package test;",
"",
"import javax.inject.Scope;",
"",
"@Scope",
"@interface TestScope {}");
JavaFileObject moduleWithScopedProvides =
JavaFileObjects.forSourceLines(
"test.ModuleWithScopedProvides",
"package test;",
"",
"import dagger.Module;",
"import dagger.Provides;",
"",
"@Module",
"class ModuleWithScopedProvides {",
" @Provides",
" @TestScope",
" static Object o() { return new Object(); }",
"}");
JavaFileObject moduleWithScopedBinds =
JavaFileObjects.forSourceLines(
"test.ModuleWithScopedBinds",
"package test;",
"",
"import dagger.Binds;",
"import dagger.Module;",
"",
"@Module",
"interface ModuleWithScopedBinds {",
" @Binds",
" @TestScope",
" Object o(String s);",
"}");
JavaFileObject parent =
JavaFileObjects.forSourceLines(
"test.Parent",
"package test;",
"",
"import dagger.Component;",
"",
"@Component(modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})",
"interface Parent {",
" Child child();",
"}");
JavaFileObject child =
JavaFileObjects.forSourceLines(
"test.Child",
"package test;",
"",
"import dagger.Subcomponent;",
"",
"@Subcomponent(",
" modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})",
"interface Child {}");
Compilation compilation =
daggerCompiler()
.compile(testScope, moduleWithScopedProvides, moduleWithScopedBinds, parent, child);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
"test.Child repeats modules with scoped bindings or declarations:",
" - test.Parent also includes:",
" - test.ModuleWithScopedProvides with scopes: @test.TestScope",
" - test.ModuleWithScopedBinds with scopes: @test.TestScope"));
}
@Test
public void repeatedModulesWithReusableScope() {
JavaFileObject moduleWithScopedProvides =
JavaFileObjects.forSourceLines(
"test.ModuleWithScopedProvides",
"package test;",
"",
"import dagger.Module;",
"import dagger.Provides;",
"import dagger.Reusable;",
"",
"@Module",
"class ModuleWithScopedProvides {",
" @Provides",
" @Reusable",
" static Object o() { return new Object(); }",
"}");
JavaFileObject moduleWithScopedBinds =
JavaFileObjects.forSourceLines(
"test.ModuleWithScopedBinds",
"package test;",
"",
"import dagger.Binds;",
"import dagger.Module;",
"import dagger.Reusable;",
"",
"@Module",
"interface ModuleWithScopedBinds {",
" @Binds",
" @Reusable",
" Object o(String s);",
"}");
JavaFileObject parent =
JavaFileObjects.forSourceLines(
"test.Parent",
"package test;",
"",
"import dagger.Component;",
"",
"@Component(modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})",
"interface Parent {",
" Child child();",
"}");
JavaFileObject child =
JavaFileObjects.forSourceLines(
"test.Child",
"package test;",
"",
"import dagger.Subcomponent;",
"",
"@Subcomponent(",
" modules = {ModuleWithScopedProvides.class, ModuleWithScopedBinds.class})",
"interface Child {}");
Compilation compilation =
daggerCompiler()
.compile(moduleWithScopedProvides, moduleWithScopedBinds, parent, child);
assertThat(compilation).succeededWithoutWarnings();
}
}