1 /* 2 * Copyright (C) 2024 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.internal.codegen; 18 19 import static com.google.testing.compile.CompilationSubject.assertThat; 20 21 import androidx.room.compiler.processing.util.Source; 22 import com.google.testing.compile.Compilation; 23 import com.google.testing.compile.JavaFileObjects; 24 import dagger.testing.compile.CompilerTests; 25 import dagger.testing.golden.GoldenFileRule; 26 import java.util.Collection; 27 import javax.tools.JavaFileObject; 28 import org.junit.Rule; 29 import org.junit.Test; 30 import org.junit.runner.RunWith; 31 import org.junit.runners.Parameterized; 32 import org.junit.runners.Parameterized.Parameters; 33 34 @RunWith(Parameterized.class) 35 public class LazyClassKeyMapBindingComponentProcessorTest { 36 @Parameters(name = "{0}") parameters()37 public static Collection<Object[]> parameters() { 38 return CompilerMode.TEST_PARAMETERS; 39 } 40 41 @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule(); 42 43 private final CompilerMode compilerMode; 44 LazyClassKeyMapBindingComponentProcessorTest(CompilerMode compilerMode)45 public LazyClassKeyMapBindingComponentProcessorTest(CompilerMode compilerMode) { 46 this.compilerMode = compilerMode; 47 } 48 49 // Cannot convert to use ksp as this test relies on AutoAnnotationProcessor. 50 @Test mapBindingsWithInaccessibleKeys()51 public void mapBindingsWithInaccessibleKeys() throws Exception { 52 JavaFileObject mapKeys = 53 JavaFileObjects.forSourceLines( 54 "mapkeys.MapKeys", 55 "package mapkeys;", 56 "", 57 "import dagger.MapKey;", 58 "import dagger.multibindings.LazyClassKey;", 59 "", 60 "public class MapKeys {", 61 " @MapKey(unwrapValue = false)", 62 " public @interface ComplexKey {", 63 " Class<?>[] manyClasses();", 64 " Class<?> oneClass();", 65 " LazyClassKey annotation();", 66 " }", 67 "", 68 " interface Inaccessible {}", 69 "}"); 70 JavaFileObject moduleFile = 71 JavaFileObjects.forSourceLines( 72 "mapkeys.MapModule", 73 "package mapkeys;", 74 "", 75 "import dagger.Binds;", 76 "import dagger.Module;", 77 "import dagger.Provides;", 78 "import dagger.multibindings.LazyClassKey;", 79 "import dagger.multibindings.IntoMap;", 80 "import java.util.Map;", 81 "import javax.inject.Provider;", 82 "", 83 "@Module", 84 "public interface MapModule {", 85 " @Provides @IntoMap @LazyClassKey(MapKeys.Inaccessible.class)", 86 " static int classKey() { return 1; }", 87 "", 88 " @Provides @IntoMap", 89 " @MapKeys.ComplexKey(", 90 " manyClasses = {java.lang.Object.class, java.lang.String.class},", 91 " oneClass = MapKeys.Inaccessible.class,", 92 " annotation = @LazyClassKey(java.lang.Object.class)", 93 " )", 94 " static int complexKeyWithInaccessibleValue() { return 1; }", 95 "", 96 " @Provides @IntoMap", 97 " @MapKeys.ComplexKey(", 98 " manyClasses = {MapKeys.Inaccessible.class, java.lang.String.class},", 99 " oneClass = java.lang.String.class,", 100 " annotation = @LazyClassKey(java.lang.Object.class)", 101 " )", 102 " static int complexKeyWithInaccessibleArrayValue() { return 1; }", 103 "", 104 " @Provides @IntoMap", 105 " @MapKeys.ComplexKey(", 106 " manyClasses = {java.lang.String.class},", 107 " oneClass = java.lang.String.class,", 108 " annotation = @LazyClassKey(MapKeys.Inaccessible.class)", 109 " )", 110 " static int complexKeyWithInaccessibleAnnotationValue() { return 1; }", 111 "}"); 112 JavaFileObject componentFile = 113 JavaFileObjects.forSourceLines( 114 "test.TestComponent", 115 "package test;", 116 "", 117 "import dagger.Component;", 118 "import java.util.Map;", 119 "import javax.inject.Provider;", 120 "import mapkeys.MapKeys;", 121 "import mapkeys.MapModule;", 122 "", 123 "@Component(modules = MapModule.class)", 124 "interface TestComponent {", 125 " Map<Class<?>, Integer> classKey();", 126 " Provider<Map<Class<?>, Integer>> classKeyProvider();", 127 "", 128 " Map<MapKeys.ComplexKey, Integer> complexKey();", 129 " Provider<Map<MapKeys.ComplexKey, Integer>> complexKeyProvider();", 130 "}"); 131 Compilation compilation = 132 Compilers.compilerWithOptions(compilerMode.javacopts()) 133 .compile(mapKeys, moduleFile, componentFile); 134 assertThat(compilation).succeeded(); 135 assertThat(compilation) 136 .generatedSourceFile("test.DaggerTestComponent") 137 .hasSourceEquivalentTo(goldenFileRule.goldenFile("test.DaggerTestComponent")); 138 assertThat(compilation) 139 .generatedSourceFile( 140 "mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey") 141 .hasSourceEquivalentTo( 142 goldenFileRule.goldenFile( 143 "mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey")); 144 assertThat(compilation) 145 .generatedSourceFile("mapkeys.MapModule_ClassKeyMapKey") 146 .hasSourceEquivalentTo(goldenFileRule.goldenFile("mapkeys.MapModule_ClassKeyMapKey")); 147 } 148 149 @Test lazyClassKeySimilarQualifiedName_doesNotConflict()150 public void lazyClassKeySimilarQualifiedName_doesNotConflict() throws Exception { 151 Source fooBar = 152 CompilerTests.javaSource("test.Foo_Bar", "package test;", "", "interface Foo_Bar {}"); 153 Source fooBar2 = 154 CompilerTests.javaSource( 155 "test.Foo", "package test;", "", "interface Foo { interface Bar {} }"); 156 Source mapKeyBindingsModule = 157 CompilerTests.javaSource( 158 "test.MapKeyBindingsModule", 159 "package test;", 160 "", 161 "import dagger.Module;", 162 "import dagger.Provides;", 163 "import dagger.multibindings.LazyClassKey;", 164 "import dagger.multibindings.IntoMap;", 165 "", 166 "@Module", 167 "public interface MapKeyBindingsModule {", 168 " @Provides @IntoMap @LazyClassKey(test.Foo_Bar.class)", 169 " static int classKey() { return 1; }", 170 "", 171 " @Provides @IntoMap @LazyClassKey(test.Foo.Bar.class)", 172 " static int classKey2() { return 1; }", 173 "}"); 174 175 Source componentFile = 176 CompilerTests.javaSource( 177 "test.TestComponent", 178 "package test;", 179 "", 180 "import dagger.Component;", 181 "import java.util.Map;", 182 "", 183 "@Component(modules = MapKeyBindingsModule.class)", 184 "interface TestComponent {", 185 " Map<Class<?>, Integer> classKey();", 186 "}"); 187 CompilerTests.daggerCompiler(fooBar, fooBar2, mapKeyBindingsModule, componentFile) 188 .withProcessingOptions(compilerMode.processorOptions()) 189 .compile(subject -> subject.hasErrorCount(0)); 190 } 191 } 192