1 /* 2 * Copyright (C) 2020 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 java.util.stream.Collectors.joining; 20 21 import androidx.room.compiler.processing.util.Source; 22 import com.google.common.collect.ImmutableList; 23 import com.google.common.collect.ImmutableMap; 24 import dagger.testing.compile.CompilerTests; 25 import dagger.testing.golden.GoldenFileRule; 26 import java.util.Arrays; 27 import org.junit.Rule; 28 import org.junit.Test; 29 import org.junit.runner.RunWith; 30 import org.junit.runners.Parameterized; 31 import org.junit.runners.Parameterized.Parameters; 32 33 @RunWith(Parameterized.class) 34 public class ComponentShardTest { 35 private static final int BINDINGS_PER_SHARD = 2; 36 37 @Parameters(name = "{0}") parameters()38 public static ImmutableList<Object[]> parameters() { 39 return CompilerMode.TEST_PARAMETERS; 40 } 41 42 @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule(); 43 44 private final CompilerMode compilerMode; 45 ComponentShardTest(CompilerMode compilerMode)46 public ComponentShardTest(CompilerMode compilerMode) { 47 this.compilerMode = compilerMode; 48 } 49 50 @Test testNewShardCreated()51 public void testNewShardCreated() throws Exception { 52 // Add all bindings. 53 // 54 // 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 55 // ^--------/ 56 // 57 ImmutableList.Builder<Source> sources = ImmutableList.builder(); 58 sources 59 // Shard 2: Bindings (1) 60 .add(createBinding("Binding1", "Binding2 binding2")) 61 // Shard 1: Bindings (2, 3, 4, 5). Contains more than 2 bindings due to cycle. 62 .add(createBinding("Binding2", "Binding3 binding3")) 63 .add(createBinding("Binding3", "Binding4 binding4")) 64 .add(createBinding("Binding4", "Binding5 binding5, Provider<Binding2> binding2Provider")) 65 .add(createBinding("Binding5", "Binding6 binding6")) 66 // Component shard: Bindings (6, 7) 67 .add(createBinding("Binding6", "Binding7 binding7")) 68 .add(createBinding("Binding7")); 69 70 // Add the component with entry points for each binding and its provider. 71 sources.add( 72 CompilerTests.javaSource( 73 "dagger.internal.codegen.TestComponent", 74 "package dagger.internal.codegen;", 75 "", 76 "import dagger.Component;", 77 "import javax.inject.Provider;", 78 "import javax.inject.Singleton;", 79 "", 80 "@Singleton", 81 "@Component", 82 "interface TestComponent {", 83 " Binding1 binding1();", 84 " Binding2 binding2();", 85 " Binding3 binding3();", 86 " Binding4 binding4();", 87 " Binding5 binding5();", 88 " Binding6 binding6();", 89 " Binding7 binding7();", 90 " Provider<Binding1> providerBinding1();", 91 " Provider<Binding2> providerBinding2();", 92 " Provider<Binding3> providerBinding3();", 93 " Provider<Binding4> providerBinding4();", 94 " Provider<Binding5> providerBinding5();", 95 " Provider<Binding6> providerBinding6();", 96 " Provider<Binding7> providerBinding7();", 97 "}")); 98 99 CompilerTests.daggerCompiler(sources.build()) 100 .withProcessingOptions(compilerOptions()) 101 .compile( 102 subject -> { 103 subject.hasErrorCount(0); 104 subject.generatedSource( 105 goldenFileRule.goldenSource("dagger/internal/codegen/DaggerTestComponent")); 106 }); 107 } 108 109 @Test testNewShardCreatedWithDependencies()110 public void testNewShardCreatedWithDependencies() throws Exception { 111 ImmutableList.Builder<Source> sources = ImmutableList.builder(); 112 sources.add( 113 createBinding("Binding1"), 114 createBinding("Binding2"), 115 CompilerTests.javaSource( 116 "dagger.internal.codegen.Binding3", 117 "package dagger.internal.codegen;", 118 "", 119 "class Binding3 {}"), 120 CompilerTests.javaSource( 121 "dagger.internal.codegen.Dependency", 122 "package dagger.internal.codegen;", 123 "", 124 "interface Dependency {", 125 " Binding3 binding3();", 126 "}"), 127 CompilerTests.javaSource( 128 "dagger.internal.codegen.TestComponent", 129 "package dagger.internal.codegen;", 130 "", 131 "import dagger.Component;", 132 "import javax.inject.Provider;", 133 "import javax.inject.Singleton;", 134 "", 135 "@Singleton", 136 "@Component(dependencies = Dependency.class)", 137 "interface TestComponent {", 138 " Binding1 binding1();", 139 " Binding2 binding2();", 140 " Binding3 binding3();", 141 " Provider<Binding1> providerBinding1();", 142 " Provider<Binding2> providerBinding2();", 143 " Provider<Binding3> providerBinding3();", 144 "}")); 145 146 CompilerTests.daggerCompiler(sources.build()) 147 .withProcessingOptions(compilerOptions()) 148 .compile( 149 subject -> { 150 subject.hasErrorCount(0); 151 subject.generatedSource( 152 goldenFileRule.goldenSource("dagger/internal/codegen/DaggerTestComponent")); 153 }); 154 } 155 156 @Test testNewShardSubcomponentCreated()157 public void testNewShardSubcomponentCreated() throws Exception { 158 ImmutableList.Builder<Source> sources = ImmutableList.builder(); 159 sources.add( 160 CompilerTests.javaSource( 161 "dagger.internal.codegen.SubcomponentScope", 162 "package dagger.internal.codegen;", 163 "", 164 "import javax.inject.Scope;", 165 "", 166 "@Scope", 167 "public @interface SubcomponentScope {}"), 168 CompilerTests.javaSource( 169 "dagger.internal.codegen.Binding1", 170 "package dagger.internal.codegen;", 171 "", 172 "@SubcomponentScope", 173 "final class Binding1 {", 174 " @javax.inject.Inject Binding1() {}", 175 "}"), 176 CompilerTests.javaSource( 177 "dagger.internal.codegen.Binding2", 178 "package dagger.internal.codegen;", 179 "", 180 "@SubcomponentScope", 181 "final class Binding2 {", 182 " @javax.inject.Inject Binding2() {}", 183 "}"), 184 CompilerTests.javaSource( 185 "dagger.internal.codegen.Binding3", 186 "package dagger.internal.codegen;", 187 "", 188 "@SubcomponentScope", 189 "final class Binding3 {", 190 " @javax.inject.Inject Binding3() {}", 191 "}"), 192 CompilerTests.javaSource( 193 "dagger.internal.codegen.TestComponent", 194 "package dagger.internal.codegen;", 195 "", 196 "import dagger.Component;", 197 "", 198 "@Component", 199 "interface TestComponent {", 200 " TestSubcomponent subcomponent();", 201 "}"), 202 CompilerTests.javaSource( 203 "dagger.internal.codegen.TestSubcomponent", 204 "package dagger.internal.codegen;", 205 "", 206 "import dagger.Subcomponent;", 207 "import javax.inject.Provider;", 208 "", 209 "@SubcomponentScope", 210 "@Subcomponent", 211 "interface TestSubcomponent {", 212 " Binding1 binding1();", 213 " Binding2 binding2();", 214 " Binding3 binding3();", 215 " Provider<Binding1> providerBinding1();", 216 " Provider<Binding2> providerBinding2();", 217 " Provider<Binding3> providerBinding3();", 218 "}")); 219 220 CompilerTests.daggerCompiler(sources.build()) 221 .withProcessingOptions(compilerOptions()) 222 .compile( 223 subject -> { 224 subject.hasErrorCount(0); 225 subject.generatedSource( 226 goldenFileRule.goldenSource("dagger/internal/codegen/DaggerTestComponent")); 227 }); 228 } 229 createBinding(String bindingName, String... deps)230 private static Source createBinding(String bindingName, String... deps) { 231 return CompilerTests.javaSource( 232 "dagger.internal.codegen." + bindingName, 233 "package dagger.internal.codegen;", 234 "", 235 "import javax.inject.Inject;", 236 "import javax.inject.Provider;", 237 "import javax.inject.Singleton;", 238 "", 239 "@Singleton", 240 "final class " + bindingName + " {", 241 " @Inject", 242 " " + bindingName + "(" + Arrays.stream(deps).collect(joining(", ")) + ") {}", 243 "}"); 244 } 245 compilerOptions()246 private ImmutableMap<String, String> compilerOptions() { 247 return ImmutableMap.<String, String>builder() 248 .putAll(compilerMode.processorOptions()) 249 .put("dagger.generatedClassExtendsComponent", "DISABLED") 250 .put("dagger.keysPerComponentShard", Integer.toString(BINDINGS_PER_SHARD)) 251 .buildOrThrow(); 252 } 253 } 254