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