• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.hilt.android.testing.compile;
18 
19 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
20 import static java.util.stream.Collectors.toMap;
21 
22 import androidx.room.compiler.processing.XProcessingEnv;
23 import androidx.room.compiler.processing.util.CompilationResultSubject;
24 import androidx.room.compiler.processing.util.ProcessorTestExtKt;
25 import androidx.room.compiler.processing.util.Source;
26 import androidx.room.compiler.processing.util.compiler.TestCompilationArguments;
27 import androidx.room.compiler.processing.util.compiler.TestCompilationResult;
28 import androidx.room.compiler.processing.util.compiler.TestKotlinCompilerKt;
29 import com.google.auto.value.AutoValue;
30 import com.google.common.collect.ImmutableCollection;
31 import com.google.common.collect.ImmutableList;
32 import com.google.common.collect.ImmutableMap;
33 import com.google.devtools.ksp.processing.SymbolProcessorProvider;
34 import com.google.testing.compile.Compiler;
35 import dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointProcessor;
36 import dagger.hilt.android.processor.internal.androidentrypoint.KspAndroidEntryPointProcessor;
37 import dagger.hilt.android.processor.internal.customtestapplication.CustomTestApplicationProcessor;
38 import dagger.hilt.android.processor.internal.customtestapplication.KspCustomTestApplicationProcessor;
39 import dagger.hilt.processor.internal.BaseProcessingStep;
40 import dagger.hilt.processor.internal.HiltProcessingEnvConfigs;
41 import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsProcessor;
42 import dagger.hilt.processor.internal.aggregateddeps.KspAggregatedDepsProcessor;
43 import dagger.hilt.processor.internal.aliasof.AliasOfProcessor;
44 import dagger.hilt.processor.internal.aliasof.KspAliasOfProcessor;
45 import dagger.hilt.processor.internal.definecomponent.DefineComponentProcessor;
46 import dagger.hilt.processor.internal.definecomponent.KspDefineComponentProcessor;
47 import dagger.hilt.processor.internal.earlyentrypoint.EarlyEntryPointProcessor;
48 import dagger.hilt.processor.internal.earlyentrypoint.KspEarlyEntryPointProcessor;
49 import dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputProcessor;
50 import dagger.hilt.processor.internal.generatesrootinput.KspGeneratesRootInputProcessor;
51 import dagger.hilt.processor.internal.originatingelement.KspOriginatingElementProcessor;
52 import dagger.hilt.processor.internal.originatingelement.OriginatingElementProcessor;
53 import dagger.hilt.processor.internal.root.ComponentTreeDepsProcessor;
54 import dagger.hilt.processor.internal.root.KspComponentTreeDepsProcessor;
55 import dagger.hilt.processor.internal.root.KspRootProcessor;
56 import dagger.hilt.processor.internal.root.RootProcessor;
57 import dagger.hilt.processor.internal.uninstallmodules.KspUninstallModulesProcessor;
58 import dagger.hilt.processor.internal.uninstallmodules.UninstallModulesProcessor;
59 import dagger.internal.codegen.ComponentProcessor;
60 import dagger.internal.codegen.KspComponentProcessor;
61 import dagger.testing.compile.CompilerTests;
62 import java.util.Arrays;
63 import java.util.Collection;
64 import java.util.List;
65 import java.util.Map;
66 import java.util.function.Consumer;
67 import java.util.function.Function;
68 import javax.annotation.processing.Processor;
69 import org.junit.rules.TemporaryFolder;
70 
71 /** {@link Compiler} instances for testing Android Hilt. */
72 public final class HiltCompilerTests {
73   /** Returns the {@link XProcessingEnv.Backend} for the given {@link CompilationResultSubject}. */
backend(CompilationResultSubject subject)74   public static XProcessingEnv.Backend backend(CompilationResultSubject subject) {
75     return CompilerTests.backend(subject);
76   }
77 
78   /** Returns a {@link Source.KotlinSource} with the given file name and content. */
kotlinSource( String fileName, ImmutableCollection<String> srcLines)79   public static Source.KotlinSource kotlinSource(
80       String fileName, ImmutableCollection<String> srcLines) {
81     return CompilerTests.kotlinSource(fileName, srcLines);
82   }
83 
84   /** Returns a {@link Source.KotlinSource} with the given file name and content. */
kotlinSource(String fileName, String... srcLines)85   public static Source.KotlinSource kotlinSource(String fileName, String... srcLines) {
86     return CompilerTests.kotlinSource(fileName, srcLines);
87   }
88 
89   /** Returns a {@link Source.JavaSource} with the given file name and content. */
javaSource( String fileName, ImmutableCollection<String> srcLines)90   public static Source.JavaSource javaSource(
91       String fileName, ImmutableCollection<String> srcLines) {
92     return CompilerTests.javaSource(fileName, srcLines);
93   }
94 
95   /** Returns a {@link Source.JavaSource} with the given file name and content. */
javaSource(String fileName, String... srcLines)96   public static Source.JavaSource javaSource(String fileName, String... srcLines) {
97     return CompilerTests.javaSource(fileName, srcLines);
98   }
99 
100   /** Returns a {@link Compiler} instance with the given sources. */
hiltCompiler(Source... sources)101   public static HiltCompiler hiltCompiler(Source... sources) {
102     return hiltCompiler(ImmutableList.copyOf(sources));
103   }
104 
105   /** Returns a {@link Compiler} instance with the given sources. */
hiltCompiler(ImmutableCollection<Source> sources)106   public static HiltCompiler hiltCompiler(ImmutableCollection<Source> sources) {
107     return HiltCompiler.builder().sources(sources).build();
108   }
109 
compiler(Processor... extraProcessors)110   public static Compiler compiler(Processor... extraProcessors) {
111     return compiler(Arrays.asList(extraProcessors));
112   }
113 
compiler(Collection<? extends Processor> extraProcessors)114   public static Compiler compiler(Collection<? extends Processor> extraProcessors) {
115     Map<Class<?>, Processor> processors =
116         defaultProcessors().stream()
117             .collect(toMap((Processor e) -> e.getClass(), (Processor e) -> e));
118 
119     // Adds extra processors, and allows overriding any processors of the same class.
120     extraProcessors.forEach(processor -> processors.put(processor.getClass(), processor));
121 
122     return CompilerTests.compiler().withProcessors(processors.values());
123   }
124 
compileWithKapt( List<Source> sources, TemporaryFolder tempFolder, Consumer<TestCompilationResult> onCompilationResult)125   public static void compileWithKapt(
126       List<Source> sources,
127       TemporaryFolder tempFolder,
128       Consumer<TestCompilationResult> onCompilationResult) {
129     compileWithKapt(
130         sources, ImmutableMap.of(), ImmutableList.of(), tempFolder, onCompilationResult);
131   }
132 
compileWithKapt( List<Source> sources, Map<String, String> processorOptions, TemporaryFolder tempFolder, Consumer<TestCompilationResult> onCompilationResult)133   public static void compileWithKapt(
134       List<Source> sources,
135       Map<String, String> processorOptions,
136       TemporaryFolder tempFolder,
137       Consumer<TestCompilationResult> onCompilationResult) {
138     compileWithKapt(
139         sources, processorOptions, ImmutableList.of(), tempFolder, onCompilationResult);
140   }
141 
compileWithKapt( List<Source> sources, List<Processor> additionalProcessors, TemporaryFolder tempFolder, Consumer<TestCompilationResult> onCompilationResult)142   public static void compileWithKapt(
143       List<Source> sources,
144       List<Processor> additionalProcessors,
145       TemporaryFolder tempFolder,
146       Consumer<TestCompilationResult> onCompilationResult) {
147     compileWithKapt(
148         sources, ImmutableMap.of(), additionalProcessors, tempFolder, onCompilationResult);
149   }
150 
compileWithKapt( List<Source> sources, Map<String, String> processorOptions, List<Processor> additionalProcessors, TemporaryFolder tempFolder, Consumer<TestCompilationResult> onCompilationResult)151   public static void compileWithKapt(
152       List<Source> sources,
153       Map<String, String> processorOptions,
154       List<Processor> additionalProcessors,
155       TemporaryFolder tempFolder,
156       Consumer<TestCompilationResult> onCompilationResult) {
157     TestCompilationResult result =
158         TestKotlinCompilerKt.compile(
159             tempFolder.getRoot(),
160             new TestCompilationArguments(
161                 sources,
162                 /* classpath= */ ImmutableList.of(CompilerTests.compilerDepsJar()),
163                 /* inheritClasspath= */ false,
164                 /* javacArguments= */ ImmutableList.of(),
165                 /* kotlincArguments= */ ImmutableList.of(),
166                 /* kaptProcessors= */ ImmutableList.<Processor>builder()
167                     .addAll(defaultProcessors())
168                     .addAll(additionalProcessors)
169                     .build(),
170                 /* symbolProcessorProviders= */ ImmutableList.of(),
171                 /* processorOptions= */ processorOptions));
172     onCompilationResult.accept(result);
173   }
174 
defaultProcessors()175   static ImmutableList<Processor> defaultProcessors() {
176     return ImmutableList.of(
177         new AggregatedDepsProcessor(),
178         new AliasOfProcessor(),
179         new AndroidEntryPointProcessor(),
180         new ComponentProcessor(),
181         new ComponentTreeDepsProcessor(),
182         new CustomTestApplicationProcessor(),
183         new DefineComponentProcessor(),
184         new EarlyEntryPointProcessor(),
185         new GeneratesRootInputProcessor(),
186         new OriginatingElementProcessor(),
187         new RootProcessor(),
188         new UninstallModulesProcessor());
189   }
190 
kspDefaultProcessors()191   private static ImmutableList<SymbolProcessorProvider> kspDefaultProcessors() {
192     // TODO(bcorso): Add the rest of the KSP processors here.
193     return ImmutableList.of(
194         new KspAggregatedDepsProcessor.Provider(),
195         new KspAliasOfProcessor.Provider(),
196         new KspAndroidEntryPointProcessor.Provider(),
197         new KspComponentProcessor.Provider(),
198         new KspComponentTreeDepsProcessor.Provider(),
199         new KspCustomTestApplicationProcessor.Provider(),
200         new KspDefineComponentProcessor.Provider(),
201         new KspEarlyEntryPointProcessor.Provider(),
202         new KspGeneratesRootInputProcessor.Provider(),
203         new KspOriginatingElementProcessor.Provider(),
204         new KspRootProcessor.Provider(),
205         new KspUninstallModulesProcessor.Provider());
206   }
207 
208   /** Used to compile Hilt sources and inspect the compiled results. */
209   @AutoValue
210   public abstract static class HiltCompiler {
builder()211     static Builder builder() {
212       return new AutoValue_HiltCompilerTests_HiltCompiler.Builder()
213           // Set the builder defaults.
214           .processorOptions(ImmutableMap.of())
215           .additionalJavacProcessors(ImmutableList.of())
216           .additionalKspProcessors(ImmutableList.of())
217           .processingSteps(ImmutableList.of())
218           .javacArguments(ImmutableList.of());
219     }
220 
221     /** Returns the sources being compiled */
sources()222     abstract ImmutableCollection<Source> sources();
223 
224     /** Returns the annotation processors options. */
processorOptions()225     abstract ImmutableMap<String, String> processorOptions();
226 
227     /** Returns the extra Javac processors. */
additionalJavacProcessors()228     abstract ImmutableCollection<Processor> additionalJavacProcessors();
229 
230     /** Returns the extra KSP processors. */
additionalKspProcessors()231     abstract ImmutableCollection<SymbolProcessorProvider> additionalKspProcessors();
232 
233     /** Returns the command-line options */
javacArguments()234     abstract ImmutableCollection<String> javacArguments();
235 
236     /** Returns a new {@link HiltCompiler} instance with the annotation processors options. */
withProcessorOptions(ImmutableMap<String, String> processorOptions)237     public HiltCompiler withProcessorOptions(ImmutableMap<String, String> processorOptions) {
238       return toBuilder().processorOptions(processorOptions).build();
239     }
240 
241     /** Returns the processing steps suppliers. */
processingSteps()242     abstract ImmutableCollection<Function<XProcessingEnv, BaseProcessingStep>> processingSteps();
243 
withProcessingSteps( Function<XProcessingEnv, BaseProcessingStep>.... mapping)244     public HiltCompiler withProcessingSteps(
245         Function<XProcessingEnv, BaseProcessingStep>... mapping) {
246       return toBuilder().processingSteps(ImmutableList.copyOf(mapping)).build();
247     }
248 
249     /** Returns a new {@link HiltCompiler} instance with the additional Javac processors. */
withAdditionalJavacProcessors(Processor... processors)250     public HiltCompiler withAdditionalJavacProcessors(Processor... processors) {
251       return toBuilder().additionalJavacProcessors(ImmutableList.copyOf(processors)).build();
252     }
253 
254     /** Returns a new {@link HiltCompiler} instance with the additional KSP processors. */
withAdditionalKspProcessors(SymbolProcessorProvider... processors)255     public HiltCompiler withAdditionalKspProcessors(SymbolProcessorProvider... processors) {
256       return toBuilder().additionalKspProcessors(ImmutableList.copyOf(processors)).build();
257     }
258 
259     /** Returns a new {@link HiltCompiler} instance with command-line options. */
withJavacArguments(String... arguments)260     public HiltCompiler withJavacArguments(String... arguments) {
261       return toBuilder().javacArguments(ImmutableList.copyOf(arguments)).build();
262     }
263 
264     /** Returns a new {@link HiltCompiler} instance with command-line options. */
withJavacArguments(ImmutableCollection<String> arguments)265     public HiltCompiler withJavacArguments(ImmutableCollection<String> arguments) {
266       return toBuilder().javacArguments(arguments).build();
267     }
268 
269     /** Returns a builder with the current values of this {@link Compiler} as default. */
toBuilder()270     abstract Builder toBuilder();
271 
compile(Consumer<CompilationResultSubject> onCompilationResult)272     public void compile(Consumer<CompilationResultSubject> onCompilationResult) {
273       ProcessorTestExtKt.runProcessorTest(
274           sources().asList(),
275           /* classpath= */ ImmutableList.of(CompilerTests.compilerDepsJar()),
276           /* options= */ processorOptions(),
277           /* javacArguments= */ javacArguments().asList(),
278           /* kotlincArguments= */ ImmutableList.of(
279               "-P", "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true"),
280           /* config= */ HiltProcessingEnvConfigs.CONFIGS,
281           /* javacProcessors= */ ImmutableList.<Processor>builder()
282               .addAll(mergeProcessors(defaultProcessors(), additionalJavacProcessors()))
283               .addAll(
284                   processingSteps().stream()
285                       .map(HiltCompilerProcessors.JavacProcessor::new)
286                       .collect(toImmutableList()))
287               .build(),
288           /* symbolProcessorProviders= */ ImmutableList.<SymbolProcessorProvider>builder()
289               .addAll(mergeProcessors(kspDefaultProcessors(), additionalKspProcessors()))
290               .addAll(
291                   processingSteps().stream()
292                       .map(HiltCompilerProcessors.KspProcessor.Provider::new)
293                       .collect(toImmutableList()))
294               .build(),
295           result -> {
296             onCompilationResult.accept(result);
297             return null;
298           });
299     }
300 
mergeProcessors( Collection<T> defaultProcessors, Collection<T> extraProcessors)301     private static <T> ImmutableList<T> mergeProcessors(
302         Collection<T> defaultProcessors, Collection<T> extraProcessors) {
303       Map<Class<?>, T> processors =
304           defaultProcessors.stream().collect(toMap((T e) -> e.getClass(), (T e) -> e));
305       // Adds extra processors, and allows overriding any processors of the same class.
306       extraProcessors.forEach(processor -> processors.put(processor.getClass(), processor));
307       return ImmutableList.copyOf(processors.values());
308     }
309 
310     /** Used to build a {@link HiltCompiler}. */
311     @AutoValue.Builder
312     public abstract static class Builder {
sources(ImmutableCollection<Source> sources)313       abstract Builder sources(ImmutableCollection<Source> sources);
processorOptions(ImmutableMap<String, String> processorOptions)314       abstract Builder processorOptions(ImmutableMap<String, String> processorOptions);
additionalJavacProcessors(ImmutableCollection<Processor> processors)315       abstract Builder additionalJavacProcessors(ImmutableCollection<Processor> processors);
additionalKspProcessors( ImmutableCollection<SymbolProcessorProvider> processors)316       abstract Builder additionalKspProcessors(
317           ImmutableCollection<SymbolProcessorProvider> processors);
javacArguments(ImmutableCollection<String> arguments)318       abstract Builder javacArguments(ImmutableCollection<String> arguments);
319 
processingSteps( ImmutableCollection<Function<XProcessingEnv, BaseProcessingStep>> processingSteps)320       abstract Builder processingSteps(
321           ImmutableCollection<Function<XProcessingEnv, BaseProcessingStep>> processingSteps);
322 
build()323       abstract HiltCompiler build();
324     }
325   }
326 
HiltCompilerTests()327   private HiltCompilerTests() {}
328 }
329