/* * Copyright (C) 2020 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.android.processor.internal.aggregateddeps; import static com.google.testing.compile.CompilationSubject.assertThat; import static dagger.hilt.android.processor.AndroidCompilers.compiler; 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; @RunWith(JUnit4.class) public class TestInstallInTest { @Test public void testMissingValues() { JavaFileObject testInstallInModule = JavaFileObjects.forSourceLines( "test.TestInstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.testing.TestInstallIn;", "", "@Module", "@TestInstallIn", "interface TestInstallInModule {}"); Compilation compilation = compiler().compile(testInstallInModule); assertThat(compilation).failed(); assertThat(compilation).hadErrorCount(1); assertThat(compilation) .hadErrorContaining( "@dagger.hilt.testing.TestInstallIn is missing default values for elements " + "components,replaces") .inFile(testInstallInModule) .onLine(7); } @Test public void testEmptyComponentValues() { JavaFileObject installInModule = JavaFileObjects.forSourceLines( "test.InstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.InstallIn;", "import dagger.hilt.components.SingletonComponent;", "", "@Module", "@InstallIn(SingletonComponent.class)", "interface InstallInModule {}"); JavaFileObject testInstallInModule = JavaFileObjects.forSourceLines( "test.TestInstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.testing.TestInstallIn;", "", "@Module", "@TestInstallIn(components = {}, replaces = InstallInModule.class)", "interface TestInstallInModule {}"); Compilation compilation = compiler().compile(installInModule, testInstallInModule); assertThat(compilation).failed(); assertThat(compilation).hadErrorCount(1); // TODO(bcorso): Add inFile().onLine() whenever we've fixed Processors.getAnnotationClassValues assertThat(compilation) .hadErrorContaining( "@TestInstallIn, 'components' class is invalid or missing: " + "@dagger.hilt.testing.TestInstallIn(" + "components={}, replaces={test.InstallInModule.class})"); } @Test public void testEmptyReplacesValues() { JavaFileObject testInstallInModule = JavaFileObjects.forSourceLines( "test.TestInstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.testing.TestInstallIn;", "import dagger.hilt.components.SingletonComponent;", "", "@Module", "@TestInstallIn(components = SingletonComponent.class, replaces = {})", "interface TestInstallInModule {}"); Compilation compilation = compiler().compile(testInstallInModule); assertThat(compilation).failed(); assertThat(compilation).hadErrorCount(1); // TODO(bcorso): Add inFile().onLine() whenever we've fixed Processors.getAnnotationClassValues assertThat(compilation) .hadErrorContaining( "@TestInstallIn, 'replaces' class is invalid or missing: " + "@dagger.hilt.testing.TestInstallIn(" + "components={dagger.hilt.components.SingletonComponent.class}, replaces={})"); } @Test public void testMissingModuleAnnotation() { JavaFileObject installInModule = JavaFileObjects.forSourceLines( "test.InstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.InstallIn;", "import dagger.hilt.components.SingletonComponent;", "", "@Module", "@InstallIn(SingletonComponent.class)", "interface InstallInModule {}"); JavaFileObject testInstallInModule = JavaFileObjects.forSourceLines( "test.TestInstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.components.SingletonComponent;", "import dagger.hilt.testing.TestInstallIn;", "", "@TestInstallIn(", " components = SingletonComponent.class,", " replaces = InstallInModule.class)", "interface TestInstallInModule {}"); Compilation compilation = compiler().compile(installInModule, testInstallInModule); assertThat(compilation).failed(); assertThat(compilation).hadErrorCount(1); assertThat(compilation) .hadErrorContaining( "@TestInstallIn-annotated classes must also be annotated with @Module or @EntryPoint: " + "test.TestInstallInModule") .inFile(testInstallInModule) .onLine(10); } @Test public void testInvalidUsageOnEntryPoint() { JavaFileObject installInModule = JavaFileObjects.forSourceLines( "test.InstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.InstallIn;", "import dagger.hilt.components.SingletonComponent;", "", "@Module", "@InstallIn(SingletonComponent.class)", "interface InstallInModule {}"); JavaFileObject testInstallInEntryPoint = JavaFileObjects.forSourceLines( "test.TestInstallInEntryPoint", "package test;", "", "import dagger.hilt.EntryPoint;", "import dagger.hilt.components.SingletonComponent;", "import dagger.hilt.testing.TestInstallIn;", "", "@EntryPoint", "@TestInstallIn(", " components = SingletonComponent.class,", " replaces = InstallInModule.class)", "interface TestInstallInEntryPoint {}"); Compilation compilation = compiler().compile(installInModule, testInstallInEntryPoint); assertThat(compilation).failed(); assertThat(compilation).hadErrorCount(1); assertThat(compilation) .hadErrorContaining("@TestInstallIn can only be used with modules") .inFile(testInstallInEntryPoint) .onLine(11); } @Test public void testInvalidReplaceModules() { JavaFileObject foo = JavaFileObjects.forSourceLines("test.Foo", "package test;", "", "class Foo {}"); JavaFileObject testInstallInModule = JavaFileObjects.forSourceLines( "test.TestInstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.components.SingletonComponent;", "import dagger.hilt.testing.TestInstallIn;", "", "@Module", "@TestInstallIn(", " components = SingletonComponent.class,", " replaces = Foo.class)", "interface TestInstallInModule {}"); Compilation compilation = compiler().compile(foo, testInstallInModule); assertThat(compilation).failed(); assertThat(compilation).hadErrorCount(1); assertThat(compilation) .hadErrorContaining( "@TestInstallIn#replaces() can only contain @InstallIn modules, but found: [test.Foo]") .inFile(testInstallInModule) .onLine(11); } @Test public void testInternalDaggerReplaceModules() { JavaFileObject testInstallInModule = JavaFileObjects.forSourceLines( "test.TestInstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.components.SingletonComponent;", "import dagger.hilt.testing.TestInstallIn;", "", "@Module", "@TestInstallIn(", " components = SingletonComponent.class,", " replaces = dagger.hilt.android.internal.modules.ApplicationContextModule.class)", "interface TestInstallInModule {}"); Compilation compilation = compiler().compile(testInstallInModule); assertThat(compilation).failed(); assertThat(compilation).hadErrorCount(1); assertThat(compilation) .hadErrorContaining( "@TestInstallIn#replaces() cannot contain internal Hilt modules, but found: " + "[dagger.hilt.android.internal.modules.ApplicationContextModule]") .inFile(testInstallInModule) .onLine(11); } @Test public void testHiltWrapperDaggerReplaceModules() { JavaFileObject testInstallInModule = JavaFileObjects.forSourceLines( "test.TestInstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.components.SingletonComponent;", "import dagger.hilt.testing.TestInstallIn;", "import" + " dagger.hilt.android.processor.internal.aggregateddeps.HiltWrapper_InstallInModule;", "", "@Module", "@TestInstallIn(", " components = SingletonComponent.class,", // Note: this module is built in a separate library since AggregatedDepsProcessor can't // handle modules generated in the same round. " replaces = HiltWrapper_InstallInModule.class)", "interface TestInstallInModule {}"); Compilation compilation = compiler().compile(testInstallInModule); assertThat(compilation).failed(); assertThat(compilation).hadErrorCount(1); assertThat(compilation) .hadErrorContaining( "@TestInstallIn#replaces() cannot contain Hilt generated public wrapper modules, " + "but found: [dagger.hilt.android.processor.internal.aggregateddeps." + "HiltWrapper_InstallInModule]") .inFile(testInstallInModule) .onLine(12); } @Test public void testCannotReplaceLocalInstallInModule() { JavaFileObject test = JavaFileObjects.forSourceLines( "test.MyTest", "package test;", "", "import dagger.Module;", "import dagger.hilt.InstallIn;", "import dagger.hilt.components.SingletonComponent;", "import dagger.hilt.testing.TestInstallIn;", "import dagger.hilt.android.testing.HiltAndroidTest;", "", "@HiltAndroidTest", "public class MyTest {", " @Module", " @InstallIn(SingletonComponent.class)", " interface LocalInstallInModule {}", "}"); JavaFileObject testInstallIn = JavaFileObjects.forSourceLines( "test.TestInstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.components.SingletonComponent;", "import dagger.hilt.testing.TestInstallIn;", "", "@Module", "@TestInstallIn(", " components = SingletonComponent.class,", " replaces = MyTest.LocalInstallInModule.class)", "interface TestInstallInModule {}"); Compilation compilation = compiler().compile(test, testInstallIn); assertThat(compilation).failed(); assertThat(compilation).hadErrorCount(1); assertThat(compilation) .hadErrorContaining( "TestInstallIn#replaces() cannot replace test specific @InstallIn modules, but found: " + "[test.MyTest.LocalInstallInModule].") .inFile(testInstallIn) .onLine(11); } @Test public void testThatTestInstallInCannotOriginateFromTest() { JavaFileObject installInModule = JavaFileObjects.forSourceLines( "test.InstallInModule", "package test;", "", "import dagger.Module;", "import dagger.hilt.InstallIn;", "import dagger.hilt.components.SingletonComponent;", "", "@Module", "@InstallIn(SingletonComponent.class)", "interface InstallInModule {}"); JavaFileObject test = JavaFileObjects.forSourceLines( "test.MyTest", "package test;", "", "import dagger.Module;", "import dagger.hilt.components.SingletonComponent;", "import dagger.hilt.testing.TestInstallIn;", "import dagger.hilt.android.testing.HiltAndroidTest;", "", "@HiltAndroidTest", "public class MyTest {", " @Module", " @TestInstallIn(", " components = SingletonComponent.class,", " replaces = InstallInModule.class)", " interface TestInstallInModule {}", "}"); Compilation compilation = compiler().compile(test, installInModule); assertThat(compilation).failed(); assertThat(compilation).hadErrorCount(1); assertThat(compilation) .hadErrorContaining( "@TestInstallIn modules cannot be nested in (or originate from) a " + "@HiltAndroidTest-annotated class: test.MyTest") .inFile(test) .onLine(14); } }