blob: 3f56ab17282bd1be930569e63b58df89fcafdc00 [file] [log] [blame]
// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.dagger;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.transformers.ClassTransformer;
import com.android.tools.r8.transformers.MethodTransformer;
import com.android.tools.r8.utils.DaggerUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.ZipUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class DaggerBasicTestBase extends TestBase {
public static Path compiledProgramNotDependingOnDagger;
public static Path compiledProgramDependingOnDagger;
public static Path daggerGeneratedSourceFiles;
private static void compile(
List<Path> sourceNotDependingOnDagger,
List<Path> sourceDependingOnDagger,
BiFunction<String, byte[], byte[]> transformer)
throws Exception {
compiledProgramNotDependingOnDagger =
DaggerUtils.compileWithoutAnnotationProcessing(sourceNotDependingOnDagger);
// Use transformer on code not depending on Dagger.
if (transformer != null) {
compiledProgramNotDependingOnDagger =
ZipUtils.map(
compiledProgramNotDependingOnDagger,
getStaticTemp().newFolder().toPath().resolve("transformed.jar"),
(entry, bytes) ->
FileUtils.isClassFile(entry.getName())
? transformer.apply(
entry
.getName()
.substring(
0, entry.getName().length() - FileUtils.CLASS_EXTENSION.length()),
bytes)
: bytes);
}
// Compile with Dagger annotation processor. The part of the program not relying on dagger
// generated types are passed as class files (potentially after transformation) and on command
// line for being included in annotation processing.
compiledProgramDependingOnDagger =
DaggerUtils.compileWithAnnotationProcessing(
sourceDependingOnDagger, ImmutableList.of(compiledProgramNotDependingOnDagger));
daggerGeneratedSourceFiles =
ZipUtils.filter(
compiledProgramDependingOnDagger,
getStaticTemp().newFolder().toPath().resolve("source.jar"),
entry -> entry.getName().endsWith(".java"));
// Check the generated Dagger source files.
Set<String> generatedFiles = new HashSet<>();
ZipUtils.iter(
DaggerBasicTestBase.daggerGeneratedSourceFiles,
(entry, unused) -> generatedFiles.add(entry.getName()));
assertEquals(
ImmutableSet.of(
"basic/I1Impl1_Factory.java",
"basic/I2Impl1_Factory.java",
"basic/I3Impl1_Factory.java",
"basic/ModuleUsingProvides_I1Factory.java",
"basic/ModuleUsingProvides_I2Factory.java",
"basic/ModuleUsingProvides_I3Factory.java",
"basic/ModuleUsingProvides_Proxy.java",
"basic/DaggerMainComponentUsingBinds.java",
"basic/DaggerMainComponentUsingProvides.java"),
generatedFiles);
}
private static boolean sourceFileReferingDaggerGeneratedClasses(Path file) {
return file.getFileName().toString().startsWith("Main");
}
static void compileWithSingleton() throws Exception {
compile(
javaSourceFiles("basic", path -> !sourceFileReferingDaggerGeneratedClasses(path)),
javaSourceFiles("basic", DaggerBasicTestBase::sourceFileReferingDaggerGeneratedClasses),
DaggerBasicTestBase::transformAddSingleton);
}
static void compileWithoutSingleton() throws Exception {
compile(
javaSourceFiles("basic", path -> !sourceFileReferingDaggerGeneratedClasses(path)),
javaSourceFiles("basic", DaggerBasicTestBase::sourceFileReferingDaggerGeneratedClasses),
null);
}
private static byte[] transformAddSingleton(String binaryName, byte[] bytes) {
// Add @Singleton to the constructors used with @Bind.
if (binaryName.endsWith("Impl1")) {
return transformer(bytes, Reference.classFromBinaryName(binaryName))
.addClassTransformer(
new ClassTransformer() {
@Override
public void visitEnd() {
super.visitAnnotation("Ljavax/inject/Singleton;", true);
}
})
.transform();
}
// Add @Singleton to the methods annotated with @Provides.
if (binaryName.endsWith("ModuleUsingProvides")) {
return transformer(bytes, Reference.classFromBinaryName(binaryName))
.addMethodTransformer(
new MethodTransformer() {
@Override
public void visitEnd() {
super.visitAnnotation("Ljavax/inject/Singleton;", true);
}
})
.transform();
}
return bytes;
}
public static List<Path> javaSourceFiles(String testDir, Predicate<Path> filter)
throws Exception {
try (Stream<Path> walk =
Files.walk(Paths.get(ToolHelper.TESTS_DIR, "examplesDagger", testDir))) {
return walk.filter(filter).filter(FileUtils::isJavaFile).collect(Collectors.toList());
}
}
}