Introduce a RelocatorTestBuilder to better write tests
This will help out when expanding the language for relocation.
Bug: b/155618698
Change-Id: I2336c519b0c324dc8f0094f412839b99673f9dbb
diff --git a/src/main/java/com/android/tools/r8/relocator/RelocatorCommandLine.java b/src/main/java/com/android/tools/r8/relocator/RelocatorCommandLine.java
index dc11daa..f065d5e 100644
--- a/src/main/java/com/android/tools/r8/relocator/RelocatorCommandLine.java
+++ b/src/main/java/com/android/tools/r8/relocator/RelocatorCommandLine.java
@@ -27,7 +27,7 @@
ExceptionUtils.withMainProgramHandler(() -> run(args));
}
- static void run(String[] args) throws CompilationFailedException {
+ public static void run(String[] args) throws CompilationFailedException {
RelocatorCommand command =
RelocatorCommand.Builder.parse(args, CommandLineOrigin.INSTANCE).build();
if (command.isPrintHelp()) {
diff --git a/src/test/java/com/android/tools/r8/RelocatorTestBuilder.java b/src/test/java/com/android/tools/r8/RelocatorTestBuilder.java
new file mode 100644
index 0000000..4d221c9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/RelocatorTestBuilder.java
@@ -0,0 +1,158 @@
+// Copyright (c) 2023, 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;
+
+import static com.android.tools.r8.TestBase.extractClassDescriptor;
+
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.PackageReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.relocator.Relocator;
+import com.android.tools.r8.relocator.RelocatorCommand;
+import com.android.tools.r8.relocator.RelocatorCommandLine;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+public class RelocatorTestBuilder
+ extends TestBuilder<RelocatorTestCompileResult, RelocatorTestBuilder> {
+
+ private final boolean isExternal;
+ private final List<String> commandLineArgs = new ArrayList<>();
+ private final RelocatorCommand.Builder commandBuilder = RelocatorCommand.builder();
+ private Path output = null;
+
+ private RelocatorTestBuilder(TestState state, boolean isExternal) {
+ super(state);
+ this.isExternal = isExternal;
+ }
+
+ public static RelocatorTestBuilder create(TestState state, boolean external) {
+ return new RelocatorTestBuilder(state, external);
+ }
+
+ @Override
+ RelocatorTestBuilder self() {
+ return this;
+ }
+
+ public RelocatorTestCompileResult run() throws Exception {
+ if (output == null) {
+ setOutputPath(getState().getNewTempFolder().resolve("output.jar"));
+ }
+ if (isExternal) {
+ RelocatorCommandLine.run(commandLineArgs.toArray(new String[0]));
+ } else {
+ Relocator.run(commandBuilder.build());
+ }
+ return new RelocatorTestCompileResult(output);
+ }
+
+ public RelocatorTestBuilder setOutputPath(Path path) {
+ assert output == null;
+ output = path;
+ if (isExternal) {
+ commandLineArgs.add("--output");
+ commandLineArgs.add(path.toString());
+ } else {
+ commandBuilder.setOutputPath(path);
+ }
+ return self();
+ }
+
+ @Override
+ public RelocatorTestCompileResult run(TestRuntime runtime, String mainClass, String... args)
+ throws CompilationFailedException, ExecutionException, IOException {
+ throw new Unreachable("Not implemented - use run()");
+ }
+
+ @Override
+ public RelocatorTestBuilder addProgramFiles(Collection<Path> files) {
+ if (isExternal) {
+ files.forEach(
+ file -> {
+ commandLineArgs.add("--input");
+ commandLineArgs.add(file.toString());
+ });
+ } else {
+ commandBuilder.addProgramFiles(files);
+ }
+ return self();
+ }
+
+ @Override
+ public RelocatorTestBuilder addProgramClassFileData(Collection<byte[]> classes) {
+ try {
+ Path resolve = getState().getNewTempFolder().resolve("input.jar");
+ ClassFileConsumer inputConsumer = new ClassFileConsumer.ArchiveConsumer(resolve);
+ for (byte[] clazz : classes) {
+ inputConsumer.accept(ByteDataView.of(clazz), extractClassDescriptor(clazz), null);
+ }
+ inputConsumer.finished(null);
+ addProgramFiles(resolve);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return self();
+ }
+
+ @Override
+ public RelocatorTestBuilder addProgramDexFileData(Collection<byte[]> data) {
+ throw new Unimplemented("No support for adding dex file data directly");
+ }
+
+ @Override
+ public RelocatorTestBuilder addLibraryFiles(Collection<Path> files) {
+ throw new Unimplemented("No support for adding library");
+ }
+
+ @Override
+ public RelocatorTestBuilder addLibraryClasses(Collection<Class<?>> classes) {
+ throw new Unimplemented("No support for adding library");
+ }
+
+ @Override
+ public RelocatorTestBuilder addClasspathClasses(Collection<Class<?>> classes) {
+ throw new Unimplemented("No support for adding classpath");
+ }
+
+ @Override
+ public RelocatorTestBuilder addClasspathFiles(Collection<Path> files) {
+ throw new Unimplemented("No support for adding classpath");
+ }
+
+ @Override
+ public RelocatorTestBuilder addRunClasspathFiles(Collection<Path> files) {
+ throw new Unimplemented("No support for adding run classpath");
+ }
+
+ public RelocatorTestBuilder addPackageMapping(PackageReference from, PackageReference to) {
+ if (isExternal) {
+ commandLineArgs.add("--map");
+ commandLineArgs.add(from.getPackageName() + "->" + to.getPackageName());
+ } else {
+ commandBuilder.addPackageMapping(from, to);
+ }
+ return self();
+ }
+
+ public RelocatorTestBuilder addClassMapping(ClassReference from, ClassReference to) {
+ if (isExternal) {
+ commandLineArgs.add("--map");
+ commandLineArgs.add(from.getDescriptor() + "->" + to.getDescriptor());
+ } else {
+ commandBuilder.addClassMapping(from, to);
+ }
+ return self();
+ }
+
+ public RelocatorTestBuilder addPackageMapping(String from, String to) {
+ return addPackageMapping(Reference.packageFromString(from), Reference.packageFromString(to));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/RelocatorTestCompileResult.java b/src/test/java/com/android/tools/r8/RelocatorTestCompileResult.java
new file mode 100644
index 0000000..1f58f84
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/RelocatorTestCompileResult.java
@@ -0,0 +1,115 @@
+// Copyright (c) 2023, 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;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.ThrowingConsumer;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import com.android.tools.r8.utils.codeinspector.FoundFieldSubject;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.concurrent.ExecutionException;
+import org.hamcrest.Matcher;
+
+public class RelocatorTestCompileResult extends TestRunResult<RelocatorTestCompileResult> {
+
+ private final Path output;
+
+ public RelocatorTestCompileResult(Path output) {
+ this.output = output;
+ }
+
+ @Override
+ RelocatorTestCompileResult self() {
+ return this;
+ }
+
+ @Override
+ public RelocatorTestCompileResult assertSuccess() {
+ // If we produced a RelocatorTestRunResult the compilation was a success.
+ return self();
+ }
+
+ @Override
+ public RelocatorTestCompileResult assertStdoutMatches(Matcher<String> matcher) {
+ throw new Unreachable("Not implemented");
+ }
+
+ @Override
+ public RelocatorTestCompileResult assertFailure() {
+ throw new Unreachable("Not implemented");
+ }
+
+ @Override
+ public RelocatorTestCompileResult assertStderrMatches(Matcher<String> matcher) {
+ throw new Unreachable("Not implemented");
+ }
+
+ @Override
+ public <E extends Throwable> RelocatorTestCompileResult inspect(
+ ThrowingConsumer<CodeInspector, E> consumer) throws IOException, ExecutionException, E {
+ consumer.accept(new CodeInspector(output));
+ return self();
+ }
+
+ @Override
+ public <E extends Throwable> RelocatorTestCompileResult inspectFailure(
+ ThrowingConsumer<CodeInspector, E> consumer) throws IOException, E {
+ throw new Unreachable("NOT IMPLEMENTED");
+ }
+
+ @Override
+ public RelocatorTestCompileResult disassemble() throws IOException, ExecutionException {
+ throw new Unreachable("NOT IMPLEMENTED");
+ }
+
+ public RelocatorTestCompileResult inspectAllClassesRelocated(
+ Path original, String originalPrefix, String newPrefix) throws Exception {
+ CodeInspector originalInspector = new CodeInspector(original);
+ inspect(
+ relocatedInspector -> {
+ for (FoundClassSubject clazz : originalInspector.allClasses()) {
+ if (originalPrefix.isEmpty()
+ || clazz
+ .getFinalName()
+ .startsWith(originalPrefix + DescriptorUtils.JAVA_PACKAGE_SEPARATOR)) {
+ String relocatedName =
+ newPrefix + clazz.getFinalName().substring(originalPrefix.length());
+ ClassSubject relocatedClass = relocatedInspector.clazz(relocatedName);
+ assertThat(relocatedClass, isPresent());
+ }
+ }
+ });
+ return self();
+ }
+
+ public void inspectAllSignaturesNotContainingString(String originalPrefix) throws Exception {
+ inspect(
+ inspector -> {
+ for (FoundClassSubject clazz : inspector.allClasses()) {
+ assertThat(clazz.getFinalSignatureAttribute(), not(containsString(originalPrefix)));
+ for (FoundMethodSubject method : clazz.allMethods()) {
+ assertThat(
+ method.getJvmMethodSignatureAsString(), not(containsString(originalPrefix)));
+ }
+ for (FoundFieldSubject field : clazz.allFields()) {
+ assertThat(field.getJvmFieldSignatureAsString(), not(containsString(originalPrefix)));
+ }
+ }
+ });
+ }
+
+ public Path getOutput() {
+ return output;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 3bad712..b5f533d 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -223,6 +223,10 @@
return testForD8(temp, backend);
}
+ public RelocatorTestBuilder testForRelocator(boolean external) {
+ return RelocatorTestBuilder.create(new TestState(temp), external);
+ }
+
public JvmTestBuilder testForJvm(TestParameters parameters) {
parameters.assertCfRuntime();
parameters.assertIsRepresentativeApiLevelForRuntime();
diff --git a/src/test/java/com/android/tools/r8/relocator/RelocatorPathExpansionTest.java b/src/test/java/com/android/tools/r8/relocator/RelocatorPathExpansionTest.java
index 5f5de97..9216acb 100644
--- a/src/test/java/com/android/tools/r8/relocator/RelocatorPathExpansionTest.java
+++ b/src/test/java/com/android/tools/r8/relocator/RelocatorPathExpansionTest.java
@@ -8,8 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertThrows;
-import com.android.tools.r8.ByteDataView;
-import com.android.tools.r8.ClassFileConsumer;
+import com.android.tools.r8.RelocatorTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.references.ClassReference;
@@ -19,11 +18,7 @@
import com.android.tools.r8.relocator.foo.bar.BazImpl;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import java.nio.file.Path;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -46,80 +41,70 @@
@Test
public void testRewritingSingleClassWithSubPackageMatch() throws Exception {
- Path testJarPath = temp.newFile("test.jar").toPath();
- writeClassesToPath(
- testJarPath,
- Baz.dump(),
- BazImpl.dump(),
- transformer(Base.class).setClassDescriptor("Lfoo/Base;").transform());
- Path relocatedJar = temp.newFile("out.jar").toPath();
ClassReference destination =
Reference.classFromDescriptor("Lcom/android/tools/r8/foo/bar/Baz;");
- Map<String, String> mapping = new LinkedHashMap<>();
- mapping.put("foo", "com.android.tools.r8.foo");
- mapping.put("Lfoo/bar/Baz;", destination.getDescriptor());
- RelocatorUtils.runRelocator(testJarPath, mapping, relocatedJar, external);
- CodeInspector inspector = new CodeInspector(relocatedJar);
- assertThat(inspector.clazz("com.android.tools.r8.foo.Base"), isPresent());
- assertThat(inspector.clazz(destination), isPresent());
- assertThat(inspector.clazz("com.android.tools.r8.foo.bar.BazImpl"), isPresent());
+ testForRelocator(external)
+ .addProgramClassFileData(
+ Baz.dump(),
+ BazImpl.dump(),
+ transformer(Base.class).setClassDescriptor("Lfoo/Base;").transform())
+ .addPackageMapping("foo", "com.android.tools.r8.foo")
+ .addClassMapping(
+ destination, Reference.classFromDescriptor("Lcom/android/tools/r8/foo/bar/Baz;"))
+ .run()
+ .inspect(
+ inspector -> {
+ assertThat(inspector.clazz("com.android.tools.r8.foo.Base"), isPresent());
+ assertThat(inspector.clazz(destination), isPresent());
+ assertThat(inspector.clazz("com.android.tools.r8.foo.bar.BazImpl"), isPresent());
+ });
}
@Test
public void rewriteTopLevelClass() throws Exception {
- Path testJarPath = temp.newFile("test.jar").toPath();
- writeClassesToPath(
- testJarPath,
- Baz.dump(),
- BazImpl.dump(),
- transformer(Base.class).setClassDescriptor("LBase;").transform());
- Path relocatedJar = temp.newFile("out.jar").toPath();
+ ClassReference base = Reference.classFromDescriptor("LBase;");
ClassReference destination = Reference.classFromDescriptor("Lcom/android/tools/r8/Base;");
- Map<String, String> mapping = new LinkedHashMap<>();
- mapping.put("LBase;", destination.getDescriptor());
- RelocatorUtils.runRelocator(testJarPath, mapping, relocatedJar, external);
- CodeInspector inspector = new CodeInspector(relocatedJar);
- assertThat(inspector.clazz(destination), isPresent());
- // Assert that we did not rename a class in a package that is under root.
- ClassSubject relocatedBaz = inspector.clazz("foo.bar.Baz");
- assertThat(relocatedBaz, isPresent());
+ testForRelocator(external)
+ .addProgramClassFileData(
+ Baz.dump(),
+ BazImpl.dump(),
+ transformer(Base.class).setClassDescriptor(base.getDescriptor()).transform())
+ .addClassMapping(base, destination)
+ .run()
+ .inspect(
+ inspector -> {
+ assertThat(inspector.clazz(destination), isPresent());
+ // Assert that we did not rename a class in a package that is under root.
+ ClassSubject relocatedBaz = inspector.clazz("foo.bar.Baz");
+ assertThat(relocatedBaz, isPresent());
+ });
}
@Test
public void rewriteSingleClassDifferentlyFromPackage() throws Exception {
- Path testJarPath = temp.newFile("test.jar").toPath();
- writeClassesToPath(testJarPath, Baz.dump(), BazImpl.dump());
- Path relocatedJar = temp.newFile("out.jar").toPath();
ClassReference destination =
Reference.classFromDescriptor("Lcom/android/tools/r8/foo1/bar/Baz;");
- Map<String, String> mapping = new LinkedHashMap<>();
- mapping.put("foo.bar", "com.android.tools.r8.foo2.bar");
- // Relocation of specific classes should take precedence over relocation of packages.
- mapping.put("Lfoo/bar/Baz;", destination.getDescriptor());
- RelocatorUtils.runRelocator(testJarPath, mapping, relocatedJar, external);
- CodeInspector inspector = new CodeInspector(relocatedJar);
- assertThat(inspector.clazz(destination), isPresent());
- assertThat(inspector.clazz("com.android.tools.r8.foo2.bar.BazImpl"), isPresent());
+ String destinationPackage = "com.android.tools.r8.foo2.bar";
+ testForRelocator(external)
+ .addProgramClassFileData(Baz.dump(), BazImpl.dump())
+ .addPackageMapping("foo.bar", destinationPackage)
+ .addClassMapping(Reference.classFromDescriptor("Lfoo/bar/Baz;"), destination)
+ .run()
+ .inspect(
+ inspector -> {
+ // Relocation of specific classes should take precedence over relocation of packages.
+ assertThat(inspector.clazz(destination), isPresent());
+ assertThat(inspector.clazz(destinationPackage + ".BazImpl"), isPresent());
+ });
}
@Test
- public void rewriteAllSubPackages() throws Exception {
- Path testJarPath = temp.newFile("test.jar").toPath();
- writeClassesToPath(testJarPath, Baz.dump(), BazImpl.dump());
- Path relocatedJar = temp.newFile("out.jar").toPath();
- Map<String, String> mapping = new LinkedHashMap<>();
+ public void rewriteAllSubPackages() {
+ RelocatorTestBuilder relocatorTestBuilder =
+ testForRelocator(external).addProgramClassFileData(Baz.dump(), BazImpl.dump());
// The language as input is very simple and ** to match sub-packages would be a feature request.
- mapping.put("foo/**", "com.android.tools.r8.foo");
assertThrows(
IllegalArgumentException.class,
- () -> RelocatorUtils.runRelocator(testJarPath, mapping, relocatedJar, external));
- }
-
- private void writeClassesToPath(Path inputJar, byte[]... classes) {
- ClassFileConsumer inputConsumer = new ClassFileConsumer.ArchiveConsumer(inputJar);
- for (byte[] clazz : classes) {
- inputConsumer.accept(ByteDataView.of(clazz), extractClassDescriptor(clazz), null);
- }
- inputConsumer.finished(null);
+ () -> relocatorTestBuilder.addPackageMapping("foo/**", "com.android.tools.r8.foo"));
}
}
diff --git a/src/test/java/com/android/tools/r8/relocator/RelocatorTest.java b/src/test/java/com/android/tools/r8/relocator/RelocatorTest.java
index bbb6172..9a0a971 100644
--- a/src/test/java/com/android/tools/r8/relocator/RelocatorTest.java
+++ b/src/test/java/com/android/tools/r8/relocator/RelocatorTest.java
@@ -4,22 +4,24 @@
package com.android.tools.r8.relocator;
-import static com.android.tools.r8.relocator.RelocatorUtils.inspectAllClassesRelocated;
-import static com.android.tools.r8.relocator.RelocatorUtils.inspectAllSignaturesNotContainingString;
-import static com.android.tools.r8.relocator.RelocatorUtils.runRelocator;
+import static com.android.tools.r8.ToolHelper.CHECKED_IN_R8_17_WITH_DEPS;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static junit.framework.TestCase.assertFalse;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.RelocatorTestBuilder;
+import com.android.tools.r8.RelocatorTestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.references.PackageReference;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -31,11 +33,8 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -59,140 +58,145 @@
@Test
public void testRelocatorIdentity() throws Exception {
- Path output = temp.newFile("output.jar").toPath();
- runRelocator(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, new HashMap<>(), output, external);
- inspectAllClassesRelocated(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, output, "", "");
+ testForRelocator(external)
+ .addProgramFiles(CHECKED_IN_R8_17_WITH_DEPS)
+ .run()
+ .inspectAllClassesRelocated(CHECKED_IN_R8_17_WITH_DEPS, "", "");
}
@Test
public void testRelocatorEmptyToSomething() throws Exception {
String originalPrefix = "";
String newPrefix = "foo.bar.baz";
- Path output = temp.newFile("output.jar").toPath();
- Map<String, String> mapping = new HashMap<>();
- mapping.put(originalPrefix, newPrefix);
- runRelocator(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, mapping, output, external);
+ RelocatorTestCompileResult compileResult =
+ testForRelocator(external)
+ .addPackageMapping(
+ Reference.packageFromString(originalPrefix), Reference.packageFromString(newPrefix))
+ .addProgramFiles(CHECKED_IN_R8_17_WITH_DEPS)
+ .run();
// TODO(b/155618698): Extend relocator with a richer language such that java.lang.Object is not
// relocated.
RuntimeException compilationError =
assertThrows(
RuntimeException.class,
() ->
- inspectAllClassesRelocated(
- ToolHelper.CHECKED_IN_R8_17_WITH_DEPS,
- output,
- originalPrefix,
- newPrefix + "."));
+ compileResult.inspectAllClassesRelocated(
+ CHECKED_IN_R8_17_WITH_DEPS, originalPrefix, newPrefix + "."));
assertThat(compilationError.getMessage(), containsString("must extend class java.lang.Object"));
}
@Test
public void testRelocatorSomethingToEmpty() throws Exception {
String originalPrefix = "com.android.tools.r8";
- String newPrefix = "";
- Path output = temp.newFile("output.jar").toPath();
- Map<String, String> mapping = new HashMap<>();
- mapping.put(originalPrefix, newPrefix);
- runRelocator(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, mapping, output, external);
- inspectAllSignaturesNotContainingString(output, originalPrefix);
+ testForRelocator(external)
+ .addProgramFiles(CHECKED_IN_R8_17_WITH_DEPS)
+ .addPackageMapping(
+ Reference.packageFromString(originalPrefix), Reference.packageFromString(""))
+ .run()
+ .inspectAllSignaturesNotContainingString(originalPrefix);
}
@Test
public void testRelocateKeepsDebugInfo() throws Exception {
- String originalPrefix = "com.android.tools.r8";
- String newPrefix = "com.android.tools.r8";
- Path output = temp.newFile("output.jar").toPath();
- Map<String, String> mapping = new HashMap<>();
- mapping.put(originalPrefix, newPrefix);
- runRelocator(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, mapping, output, external);
- // Assert that all classes are the same, have the same methods and debug info:
- CodeInspector originalInspector = new CodeInspector(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS);
- CodeInspector relocatedInspector = new CodeInspector(output);
- for (FoundClassSubject clazz : originalInspector.allClasses()) {
- ClassSubject relocatedClass = relocatedInspector.clazz(clazz.getFinalName());
- assertThat(relocatedClass, isPresent());
- assertEquals(
- clazz.getDexProgramClass().sourceFile, relocatedClass.getDexProgramClass().sourceFile);
- for (FoundMethodSubject originalMethod : clazz.allMethods()) {
- MethodSubject relocatedMethod = relocatedClass.method(originalMethod.asMethodReference());
- assertThat(relocatedMethod, isPresent());
- assertEquals(originalMethod.hasLineNumberTable(), relocatedMethod.hasLineNumberTable());
- if (originalMethod.hasLineNumberTable()) {
- // TODO(b/155303677): Figure out why we cannot assert the same lines.
- // assertEquals(
- // originalMethod.getLineNumberTable().getLines().size(),
- // relocatedMethod.getLineNumberTable().getLines().size());
- }
- assertEquals(
- originalMethod.hasLocalVariableTable(), relocatedMethod.hasLocalVariableTable());
- if (originalMethod.hasLocalVariableTable()) {
- LocalVariableTable originalVariableTable = originalMethod.getLocalVariableTable();
- LocalVariableTable relocatedVariableTable = relocatedMethod.getLocalVariableTable();
- assertEquals(originalVariableTable.size(), relocatedVariableTable.size());
- for (int i = 0; i < originalVariableTable.getEntries().size(); i++) {
- LocalVariableTableEntry originalEntry = originalVariableTable.get(i);
- LocalVariableTableEntry relocatedEntry = relocatedVariableTable.get(i);
- assertEquals(originalEntry.name, relocatedEntry.name);
- assertEquals(originalEntry.signature, relocatedEntry.signature);
- assertEquals(originalEntry.type.toString(), relocatedEntry.type.toString());
- }
- }
- }
- }
+ PackageReference pkg = Reference.packageFromString("com.android.tools.r8");
+ testForRelocator(external)
+ .addProgramFiles(CHECKED_IN_R8_17_WITH_DEPS)
+ .addPackageMapping(pkg, pkg)
+ .run()
+ .inspect(
+ inspector -> {
+ // Assert that all classes are the same, have the same methods and debug info:
+ CodeInspector originalInspector = new CodeInspector(CHECKED_IN_R8_17_WITH_DEPS);
+ for (FoundClassSubject clazz : originalInspector.allClasses()) {
+ ClassSubject relocatedClass = inspector.clazz(clazz.getFinalName());
+ assertThat(relocatedClass, isPresent());
+ assertEquals(
+ clazz.getDexProgramClass().sourceFile,
+ relocatedClass.getDexProgramClass().sourceFile);
+ for (FoundMethodSubject originalMethod : clazz.allMethods()) {
+ MethodSubject relocatedMethod =
+ relocatedClass.method(originalMethod.asMethodReference());
+ assertThat(relocatedMethod, isPresent());
+ assertEquals(
+ originalMethod.hasLineNumberTable(), relocatedMethod.hasLineNumberTable());
+ if (originalMethod.hasLineNumberTable()) {
+ // TODO(b/155303677): Figure out why we cannot assert the same lines.
+ // assertEquals(
+ // originalMethod.getLineNumberTable().getLines().size(),
+ // relocatedMethod.getLineNumberTable().getLines().size());
+ }
+ assertEquals(
+ originalMethod.hasLocalVariableTable(),
+ relocatedMethod.hasLocalVariableTable());
+ if (originalMethod.hasLocalVariableTable()) {
+ LocalVariableTable originalVariableTable =
+ originalMethod.getLocalVariableTable();
+ LocalVariableTable relocatedVariableTable =
+ relocatedMethod.getLocalVariableTable();
+ assertEquals(originalVariableTable.size(), relocatedVariableTable.size());
+ for (int i = 0; i < originalVariableTable.getEntries().size(); i++) {
+ LocalVariableTableEntry originalEntry = originalVariableTable.get(i);
+ LocalVariableTableEntry relocatedEntry = relocatedVariableTable.get(i);
+ assertEquals(originalEntry.name, relocatedEntry.name);
+ assertEquals(originalEntry.signature, relocatedEntry.signature);
+ assertEquals(originalEntry.type.toString(), relocatedEntry.type.toString());
+ }
+ }
+ }
+ }
+ });
}
@Test
public void testRelocateAll() throws Exception {
String originalPrefix = "com.android.tools.r8";
String newPrefix = "foo.bar.baz";
- Map<String, String> mapping = new HashMap<>();
- mapping.put("some.package.that.does.not.exist", "foo");
- mapping.put(originalPrefix, newPrefix);
- Path output = temp.newFile("output.jar").toPath();
- runRelocator(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, mapping, output, external);
- inspectAllClassesRelocated(
- ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, output, originalPrefix, newPrefix);
+ testForRelocator(external)
+ .addProgramFiles(CHECKED_IN_R8_17_WITH_DEPS)
+ .addPackageMapping(
+ Reference.packageFromString(originalPrefix), Reference.packageFromString(newPrefix))
+ .addPackageMapping("some.package.that.does.not.exist", "foo")
+ .run()
+ .inspectAllClassesRelocated(CHECKED_IN_R8_17_WITH_DEPS, originalPrefix, newPrefix);
}
@Test
public void testOrderingOfPrefixes() throws Exception {
- String originalPrefix = "com.android";
- String newPrefix = "foo.bar.baz";
- Path output = temp.newFile("output.jar").toPath();
- Map<String, String> mapping = new LinkedHashMap<>();
- mapping.put(originalPrefix, newPrefix);
- mapping.put("com.android.tools.r8", "qux");
- runRelocator(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, mapping, output, external);
- // Because we see "com.android.tools.r8" before seeing "com.android" we always choose qux.
- inspectAllClassesRelocated(
- ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, output, "com.android.tools.r8", "qux");
- inspectAllSignaturesNotContainingString(output, "foo.bar.baz");
+ testForRelocator(external)
+ .addProgramFiles(CHECKED_IN_R8_17_WITH_DEPS)
+ .addPackageMapping("com.android", "foo.bar.baz")
+ .addPackageMapping("com.android.tools.r8", "qux")
+ .run()
+ // Because we see "com.android.tools.r8" before seeing "com.android" we always choose qux.
+ .inspectAllClassesRelocated(
+ ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, "com.android.tools.r8", "qux")
+ .inspectAllSignaturesNotContainingString("foo.bar.baz");
}
@Test
public void testNoReEntry() throws Exception {
// TODO(b/154909222): Check if this is the behavior we would like.
- String originalPrefix = "com.android";
- String newPrefix = "foo.bar.baz";
- Map<String, String> mapping = new LinkedHashMap<>();
- mapping.put(originalPrefix, newPrefix);
- mapping.put(newPrefix, "qux");
- Path output = temp.newFile("output.jar").toPath();
- runRelocator(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, mapping, output, external);
- inspectAllClassesRelocated(
- ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, output, originalPrefix, newPrefix);
- // Assert that no mappings of com.android.tools.r8 -> qux exists.
- CodeInspector inspector = new CodeInspector(output);
- assertFalse(
- inspector.allClasses().stream().anyMatch(clazz -> clazz.getFinalName().startsWith("qux")));
+ testForRelocator(external)
+ .addProgramFiles(CHECKED_IN_R8_17_WITH_DEPS)
+ .addPackageMapping("com.android", "foo.bar.baz")
+ .addPackageMapping("foo.bar.baz", "qux")
+ .run()
+ .inspect(
+ inspector -> {
+ // Assert that no mappings of com.android.tools.r8 -> qux exists.
+ assertTrue(
+ inspector.allClasses().stream()
+ .noneMatch(clazz -> clazz.getFinalName().startsWith("qux")));
+ });
}
@Test
public void testMultiplePackages() throws Exception {
+ RelocatorTestBuilder testBuilder =
+ testForRelocator(external).addProgramFiles(CHECKED_IN_R8_17_WITH_DEPS);
Set<String> seenPackages = new HashSet<>();
List<Pair<String, String>> packageMappings = new ArrayList<>();
- Map<String, String> mapping = new LinkedHashMap<>();
- CodeInspector inspector = new CodeInspector(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS);
+ CodeInspector inspector = new CodeInspector(CHECKED_IN_R8_17_WITH_DEPS);
int packageNameCounter = 0;
// Generate a mapping for each package name directly below com.android.tools.r8.
for (FoundClassSubject clazz : inspector.allClasses()) {
@@ -208,49 +212,43 @@
if (seenPackages.add(mappedPackageName)) {
String relocatedPackageName = "number" + packageNameCounter++;
packageMappings.add(new Pair<>(mappedPackageName, relocatedPackageName));
- mapping.put(mappedPackageName, relocatedPackageName);
+ testBuilder.addPackageMapping(mappedPackageName, relocatedPackageName);
}
}
}
- Path output = temp.newFile("output.jar").toPath();
- runRelocator(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, mapping, output, external);
+ RelocatorTestCompileResult result = testBuilder.run();
for (Pair<String, String> packageMapping : packageMappings) {
- inspectAllClassesRelocated(
- ToolHelper.CHECKED_IN_R8_17_WITH_DEPS,
- output,
- packageMapping.getFirst(),
- packageMapping.getSecond());
+ result.inspectAllClassesRelocated(
+ CHECKED_IN_R8_17_WITH_DEPS, packageMapping.getFirst(), packageMapping.getSecond());
}
}
@Test
public void testPartialPrefix() throws Exception {
String originalPrefix = "com.android.tools.r";
- String newPrefix = "i_cannot_w";
- Map<String, String> mapping = new LinkedHashMap<>();
- mapping.put(originalPrefix, newPrefix);
- Path output = temp.newFile("output.jar").toPath();
- runRelocator(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, mapping, output, external);
- inspectAllClassesRelocated(
- ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, output, originalPrefix, originalPrefix);
+ testForRelocator(external)
+ .addProgramFiles(CHECKED_IN_R8_17_WITH_DEPS)
+ .addPackageMapping(originalPrefix, "i_cannot_w")
+ .run()
+ .inspectAllClassesRelocated(CHECKED_IN_R8_17_WITH_DEPS, originalPrefix, originalPrefix);
}
@Test
public void testBootstrap() throws Exception {
String originalPrefix = "com.android.tools.r8";
String newPrefix = "relocated_r8";
- Map<String, String> mapping = new LinkedHashMap<>();
- mapping.put(originalPrefix, newPrefix);
- Path output = temp.newFile("output.jar").toPath();
- runRelocator(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, mapping, output, external);
+ RelocatorTestCompileResult result =
+ testForRelocator(external)
+ .addProgramFiles(CHECKED_IN_R8_17_WITH_DEPS)
+ .addPackageMapping(originalPrefix, newPrefix)
+ .run();
// Check that all classes has been remapped.
- inspectAllClassesRelocated(
- ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, output, originalPrefix, newPrefix);
- inspectAllSignaturesNotContainingString(output, originalPrefix);
+ result.inspectAllClassesRelocated(CHECKED_IN_R8_17_WITH_DEPS, originalPrefix, newPrefix);
+ result.inspectAllSignaturesNotContainingString(originalPrefix);
// We should be able to call the relocated relocator.
Path bootstrapOutput = temp.newFile("bootstrap.jar").toPath();
List<Path> classPath = new ArrayList<>();
- classPath.add(output);
+ classPath.add(result.getOutput());
ProcessResult processResult =
ToolHelper.runJava(
CfRuntime.getCheckedInJdk17(),
@@ -258,42 +256,46 @@
newPrefix + ".SwissArmyKnife",
"relocator",
"--input",
- output.toString(),
+ result.getOutput().toString(),
"--output",
bootstrapOutput.toString(),
"--map",
newPrefix + "->" + originalPrefix);
System.out.println(processResult.stderr);
assertEquals(0, processResult.exitCode);
- inspectAllClassesRelocated(output, bootstrapOutput, newPrefix, originalPrefix);
- inspectAllSignaturesNotContainingString(bootstrapOutput, newPrefix);
+ RelocatorTestCompileResult bootstrapResult = new RelocatorTestCompileResult(bootstrapOutput);
+ bootstrapResult.inspectAllClassesRelocated(result.getOutput(), newPrefix, originalPrefix);
+ bootstrapResult.inspectAllSignaturesNotContainingString(newPrefix);
// Assert that this is in fact an identity transformation.
- inspectAllClassesRelocated(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, bootstrapOutput, "", "");
+ bootstrapResult.inspectAllClassesRelocated(CHECKED_IN_R8_17_WITH_DEPS, "", "");
}
@Test
public void testNest() throws Exception {
String originalPrefix = "com.android.tools.r8";
String newPrefix = "com.android.tools.r8";
- Path output = temp.newFile("output.jar").toPath();
- Map<String, String> mapping = new HashMap<>();
- mapping.put(originalPrefix, newPrefix);
- runRelocator(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS, mapping, output, external);
+ CodeInspector originalInspector = new CodeInspector(CHECKED_IN_R8_17_WITH_DEPS);
// Assert that all classes are the same, have the same methods and nest info.
- CodeInspector originalInspector = new CodeInspector(ToolHelper.CHECKED_IN_R8_17_WITH_DEPS);
- CodeInspector relocatedInspector = new CodeInspector(output);
- for (FoundClassSubject originalSubject : originalInspector.allClasses()) {
- ClassSubject relocatedSubject = relocatedInspector.clazz(originalSubject.getFinalName());
- assertThat(relocatedSubject, isPresent());
- DexClass originalClass = originalSubject.getDexProgramClass();
- DexClass relocatedClass = relocatedSubject.getDexProgramClass();
- assertEquals(originalClass.isNestHost(), relocatedClass.isNestHost());
- assertEquals(originalClass.isNestMember(), relocatedClass.isNestMember());
- if (originalClass.isInANest()) {
- assertEquals(
- originalClass.getNestHost().descriptor, relocatedClass.getNestHost().descriptor);
- }
- }
+ testForRelocator(external)
+ .addProgramFiles(CHECKED_IN_R8_17_WITH_DEPS)
+ .addPackageMapping(originalPrefix, newPrefix)
+ .run()
+ .inspect(
+ relocatedInspector -> {
+ for (FoundClassSubject originalSubject : originalInspector.allClasses()) {
+ ClassSubject relocatedSubject =
+ relocatedInspector.clazz(originalSubject.getFinalName());
+ assertThat(relocatedSubject, isPresent());
+ DexClass originalClass = originalSubject.getDexProgramClass();
+ DexClass relocatedClass = relocatedSubject.getDexProgramClass();
+ assertEquals(originalClass.isNestHost(), relocatedClass.isNestHost());
+ assertEquals(originalClass.isNestMember(), relocatedClass.isNestMember());
+ if (originalClass.isInANest()) {
+ assertEquals(
+ originalClass.getNestHost().descriptor,
+ relocatedClass.getNestHost().descriptor);
+ }
+ }
+ });
}
-
}
diff --git a/src/test/java/com/android/tools/r8/relocator/RelocatorUtils.java b/src/test/java/com/android/tools/r8/relocator/RelocatorUtils.java
deleted file mode 100644
index d13c5c0..0000000
--- a/src/test/java/com/android/tools/r8/relocator/RelocatorUtils.java
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) 2023, 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.relocator;
-
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
-import com.android.tools.r8.utils.codeinspector.FoundFieldSubject;
-import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-public class RelocatorUtils {
-
- public static void runRelocator(
- Path input, Map<String, String> mapping, Path output, boolean external)
- throws CompilationFailedException {
- if (external) {
- List<String> args = new ArrayList<>();
- args.add("--input");
- args.add(input.toString());
- args.add("--output");
- args.add(output.toString());
- mapping.forEach(
- (key, value) -> {
- args.add("--map");
- args.add(key + "->" + value);
- });
- RelocatorCommandLine.run(args.toArray(new String[0]));
- } else {
- RelocatorCommand.Builder builder =
- RelocatorCommand.builder().addProgramFiles(input).setOutputPath(output);
- mapping.forEach(
- (key, value) -> {
- if (DescriptorUtils.isClassDescriptor(key)) {
- builder.addClassMapping(
- Reference.classFromDescriptor(key), Reference.classFromDescriptor(value));
- } else {
- builder.addPackageMapping(
- Reference.packageFromString(key), Reference.packageFromString(value));
- }
- });
- Relocator.run(builder.build());
- }
- }
-
- public static void inspectAllClassesRelocated(
- Path original, Path relocated, String originalPrefix, String newPrefix) throws IOException {
- CodeInspector originalInspector = new CodeInspector(original);
- CodeInspector relocatedInspector = new CodeInspector(relocated);
- for (FoundClassSubject clazz : originalInspector.allClasses()) {
- if (originalPrefix.isEmpty()
- || clazz
- .getFinalName()
- .startsWith(originalPrefix + DescriptorUtils.JAVA_PACKAGE_SEPARATOR)) {
- String relocatedName = newPrefix + clazz.getFinalName().substring(originalPrefix.length());
- ClassSubject relocatedClass = relocatedInspector.clazz(relocatedName);
- assertThat(relocatedClass, isPresent());
- }
- }
- }
-
- public static void inspectAllSignaturesNotContainingString(Path relocated, String originalPrefix)
- throws IOException {
- CodeInspector relocatedInspector = new CodeInspector(relocated);
- for (FoundClassSubject clazz : relocatedInspector.allClasses()) {
- assertThat(clazz.getFinalSignatureAttribute(), not(containsString(originalPrefix)));
- for (FoundMethodSubject method : clazz.allMethods()) {
- assertThat(method.getJvmMethodSignatureAsString(), not(containsString(originalPrefix)));
- }
- for (FoundFieldSubject field : clazz.allFields()) {
- assertThat(field.getJvmFieldSignatureAsString(), not(containsString(originalPrefix)));
- }
- }
- }
-}