[Retrace] Build an external retrace library and run tests on it
Change-Id: Icf95d17ac0410597e60631f8c5f9bd4d57bbfb78
diff --git a/build.gradle b/build.gradle
index be64cba..33dfc26 100644
--- a/build.gradle
+++ b/build.gradle
@@ -293,6 +293,7 @@
def r8LibGeneratedKeepRulesPath = "$buildDir/generated/keep.txt"
def r8LibTestPath = "$buildDir/classes/r8libtest"
def java11ClassFiles = "$buildDir/classes/java/mainJava11"
+def r8RetracePath = "$buildDir/libs/r8retrace.jar"
def osString = OperatingSystem.current().isLinux() ? "linux" :
OperatingSystem.current().isMacOsX() ? "mac" : "windows"
@@ -1070,6 +1071,17 @@
outputs.file r8DesugaredPath
}
+task R8Retrace {
+ dependsOn R8Lib
+ dependsOn r8LibCreateTask(
+ "Retrace",
+ ["src/main/keep_retrace.txt"],
+ R8Lib,
+ r8RetracePath,
+ ).dependsOn(R8Lib)
+ outputs.file r8RetracePath
+}
+
task sourceJar(type: Jar, dependsOn: classes) {
classifier = 'src'
from sourceSets.main.allSource
diff --git a/src/main/keep_retrace.txt b/src/main/keep_retrace.txt
new file mode 100644
index 0000000..6a71f9e
--- /dev/null
+++ b/src/main/keep_retrace.txt
@@ -0,0 +1,15 @@
+# Copyright (c) 2021, 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.
+
+# The retrace api is separated out without repackaging which is why this broad
+# rule is used.
+-keep public class com.android.tools.r8.retrace.* {
+ public <methods>;
+ public <fields>;
+ }
+-keepattributes SourceFile, LineNumberTable, InnerClasses, EnclosingMethod, Exceptions, Signature
+-keepparameternames
+# This is run on r8lib so keep everything in lib that is traced. That way
+# we only need a single mapping file
+-keep,allowshrinking class * { *; }
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index ad512cd..a85ae6a 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -176,6 +176,7 @@
public static final Path R8LIB_EXCLUDE_DEPS_MAP =
Paths.get(LIBS_DIR, "r8lib-exclude-deps.jar.map");
public static final Path DEPS = Paths.get(LIBS_DIR, "deps_all.jar");
+ public static final Path R8_RETRACE_JAR = Paths.get(LIBS_DIR, "r8retrace.jar");
public static final Path DESUGAR_LIB_CONVERSIONS =
Paths.get(LIBS_DIR, "library_desugar_conversions.zip");
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
index 2074afa..cd839f1 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
@@ -9,6 +9,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
@@ -17,6 +18,7 @@
import com.android.tools.r8.retrace.stacktraces.ActualRetraceBotStackTraceWithInfo;
import com.android.tools.r8.retrace.stacktraces.FoundMethodVerboseStackTrace;
import com.android.tools.r8.retrace.stacktraces.PGStackTrace;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.base.Charsets;
import java.io.ByteArrayOutputStream;
@@ -36,16 +38,30 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+@RunWith(Parameterized.class)
public class RetraceCommandLineTests {
- private static final boolean testExternal = false;
+ private static String SMILEY_EMOJI = "\uD83D\uDE00";
+
private static final String WAITING_MESSAGE =
"Waiting for stack-trace input..." + StringUtils.LINE_SEPARATOR;
@Rule public TemporaryFolder folder = new TemporaryFolder();
- private static String SMILEY_EMOJI = "\uD83D\uDE00";
+ private final boolean testExternal;
+
+ @Parameters(name = "{0}")
+ public static Boolean[] data() {
+ return BooleanUtils.values();
+ }
+
+ public RetraceCommandLineTests(boolean testExternal) {
+ this.testExternal = testExternal;
+ }
@Test
public void testPrintIdentityStackTraceFile() throws IOException {
@@ -233,11 +249,14 @@
private ProcessResult runRetraceCommandLine(File stdInput, Collection<String> args)
throws IOException {
if (testExternal) {
+ // The external dependency is built on top of R8Lib. If test.py is run with
+ // no r8lib, do not try and run the external R8 Retrace since it has not been built.
+ assumeTrue(Files.exists(ToolHelper.R8LIB_JAR));
List<String> command = new ArrayList<>();
command.add(ToolHelper.getSystemJavaExecutable());
command.add("-ea");
command.add("-cp");
- command.add(ToolHelper.R8_JAR.toString());
+ command.add(ToolHelper.R8_RETRACE_JAR.toString());
command.add("com.android.tools.r8.retrace.Retrace");
command.addAll(args);
ProcessBuilder builder = new ProcessBuilder(command);
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
index 34d4b0f..64979ea 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
@@ -10,10 +10,13 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessagesImpl;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.retrace.internal.RetraceAbortException;
import com.android.tools.r8.retrace.stacktraces.ActualBotStackTraceBase;
import com.android.tools.r8.retrace.stacktraces.ActualIdentityStackTrace;
@@ -46,8 +49,12 @@
import com.android.tools.r8.retrace.stacktraces.SuppressedStackTrace;
import com.android.tools.r8.retrace.stacktraces.UnicodeInFileNameStackTrace;
import com.android.tools.r8.retrace.stacktraces.UnknownSourceStackTrace;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
@@ -60,44 +67,50 @@
@RunWith(Parameterized.class)
public class RetraceTests extends TestBase {
- @Parameters(name = "{0}, use regular expression: {1}")
+ @Parameters(name = "{0}, use regular expression: {1}, external: {2}")
public static Collection<Object[]> data() {
- return buildParameters(getTestParameters().withNoneRuntime().build(), BooleanUtils.values());
+ TestParameters noneRuntime = getTestParameters().withNoneRuntime().build().iterator().next();
+ return ImmutableList.of(
+ new Object[] {noneRuntime, false, false},
+ new Object[] {noneRuntime, true, false},
+ new Object[] {noneRuntime, true, true});
}
private final boolean useRegExpParsing;
+ private final boolean external;
- public RetraceTests(TestParameters parameters, boolean useRegExpParsing) {
+ public RetraceTests(TestParameters parameters, boolean useRegExpParsing, boolean external) {
this.useRegExpParsing = useRegExpParsing;
+ this.external = external;
}
@Test
- public void testCanMapExceptionClass() {
+ public void testCanMapExceptionClass() throws Exception {
runRetraceTest(new ObfucatedExceptionClassStackTrace());
}
@Test
- public void testSuppressedStackTrace() {
+ public void testSuppressedStackTrace() throws Exception {
runRetraceTest(new SuppressedStackTrace());
}
@Test
- public void testFileNameStackTrace() {
+ public void testFileNameStackTrace() throws Exception {
runRetraceTest(new FileNameExtensionStackTrace());
}
@Test
- public void testInlineFileNameStackTrace() {
+ public void testInlineFileNameStackTrace() throws Exception {
runRetraceTest(new InlineFileNameStackTrace());
}
@Test
- public void testInlineFileNameWithInnerClassesStackTrace() {
+ public void testInlineFileNameWithInnerClassesStackTrace() throws Exception {
runRetraceTest(new InlineFileNameWithInnerClassesStackTrace());
}
@Test
- public void testNoObfuscationRangeMappingWithStackTrace() {
+ public void testNoObfuscationRangeMappingWithStackTrace() throws Exception {
runRetraceTest(new NoObfuscationRangeMappingWithStackTrace());
}
@@ -124,18 +137,18 @@
}
@Test
- public void testInvalidStackTraceLineWarnings() {
+ public void testInvalidStackTraceLineWarnings() throws Exception {
InvalidStackTrace invalidStackTraceTest = new InvalidStackTrace();
runRetraceTest(invalidStackTraceTest).assertNoMessages();
}
@Test
- public void testAssertionErrorInRetrace() {
+ public void testAssertionErrorInRetrace() throws Exception {
runRetraceTest(new RetraceAssertionErrorStackTrace());
}
@Test
- public void testActualStackTraces() {
+ public void testActualStackTraces() throws Exception {
List<ActualBotStackTraceBase> stackTraces =
ImmutableList.of(new ActualIdentityStackTrace(), new ActualRetraceBotStackTrace());
for (ActualBotStackTraceBase stackTrace : stackTraces) {
@@ -145,37 +158,37 @@
}
@Test
- public void testAmbiguousStackTrace() {
+ public void testAmbiguousStackTrace() throws Exception {
runRetraceTest(new AmbiguousStackTrace());
}
@Test
- public void testAmbiguousMissingLineStackTrace() {
+ public void testAmbiguousMissingLineStackTrace() throws Exception {
runRetraceTest(new AmbiguousMissingLineStackTrace());
}
@Test
- public void testAmbiguousMissingLineNotVerbose() {
+ public void testAmbiguousMissingLineNotVerbose() throws Exception {
runRetraceTest(new AmbiguousWithSignatureNonVerboseStackTrace());
}
@Test
- public void testAmbiguousMultipleMappingsTest() {
+ public void testAmbiguousMultipleMappingsTest() throws Exception {
runRetraceTest(new AmbiguousWithMultipleLineMappingsStackTrace());
}
@Test
- public void testInliningWithLineNumbers() {
+ public void testInliningWithLineNumbers() throws Exception {
runRetraceTest(new InlineWithLineNumbersStackTrace());
}
@Test
- public void testInliningNoLineNumberInfoStackTraces() {
+ public void testInliningNoLineNumberInfoStackTraces() throws Exception {
runRetraceTest(new InlineNoLineNumberStackTrace());
}
@Test
- public void testCircularReferenceStackTrace() {
+ public void testCircularReferenceStackTrace() throws Exception {
// Proguard retrace (and therefore the default regular expression) will not retrace circular
// reference exceptions.
assumeFalse(useRegExpParsing);
@@ -183,61 +196,61 @@
}
@Test
- public void testObfuscatedRangeToSingleLine() {
+ public void testObfuscatedRangeToSingleLine() throws Exception {
runRetraceTest(new ObfuscatedRangeToSingleLineStackTrace());
}
@Test
@Ignore("b/170293908")
- public void testBootLoaderAndNamedModulesStackTrace() {
+ public void testBootLoaderAndNamedModulesStackTrace() throws Exception {
assumeFalse(useRegExpParsing);
runRetraceTest(new NamedModuleStackTrace());
}
@Test
- public void testUnknownSourceStackTrace() {
+ public void testUnknownSourceStackTrace() throws Exception {
runRetraceTest(new UnknownSourceStackTrace());
}
@Test
- public void testInlineSourceFileContext() {
+ public void testInlineSourceFileContext() throws Exception {
runRetraceTest(new InlineSourceFileContextStackTrace());
}
@Test
- public void testColonInSourceFileNameStackTrace() {
+ public void testColonInSourceFileNameStackTrace() throws Exception {
runRetraceTest(new ColonInFileNameStackTrace());
}
@Test
- public void testMultipleDotsInFileNameStackTrace() {
+ public void testMultipleDotsInFileNameStackTrace() throws Exception {
runRetraceTest(new MultipleDotsInFileNameStackTrace());
}
@Test
- public void testUnicodeInFileNameStackTrace() {
+ public void testUnicodeInFileNameStackTrace() throws Exception {
runRetraceTest(new UnicodeInFileNameStackTrace());
}
@Test
- public void testMemberFieldOverlapStackTrace() {
+ public void testMemberFieldOverlapStackTrace() throws Exception {
MemberFieldOverlapStackTrace stackTraceForTest = new MemberFieldOverlapStackTrace();
runRetraceTest(stackTraceForTest);
inspectRetraceTest(stackTraceForTest, stackTraceForTest::inspectField);
}
@Test
- public void testSourceFileWithNumberAndEmptyStackTrace() {
+ public void testSourceFileWithNumberAndEmptyStackTrace() throws Exception {
runRetraceTest(new SourceFileWithNumberAndEmptyStackTrace());
}
@Test
- public void testSourceFileNameSynthesizeStackTrace() {
+ public void testSourceFileNameSynthesizeStackTrace() throws Exception {
runRetraceTest(new SourceFileNameSynthesizeStackTrace());
}
@Test
- public void testAutoStackTrace() {
+ public void testAutoStackTrace() throws Exception {
runRetraceTest(new AutoStackTrace());
}
@@ -247,17 +260,50 @@
Retracer.createDefault(stackTraceForTest::mapping, new TestDiagnosticMessagesImpl()));
}
- private TestDiagnosticMessagesImpl runRetraceTest(StackTraceForTest stackTraceForTest) {
- TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
- RetraceCommand retraceCommand =
- RetraceCommand.builder(diagnosticsHandler)
- .setProguardMapProducer(stackTraceForTest::mapping)
- .setStackTrace(stackTraceForTest.obfuscatedStackTrace())
- .setRegularExpression(useRegExpParsing ? DEFAULT_REGULAR_EXPRESSION : null)
- .setRetracedStackTraceConsumer(
- retraced -> assertEquals(stackTraceForTest.retracedStackTrace(), retraced))
- .build();
- Retrace.run(retraceCommand);
- return diagnosticsHandler;
+ private TestDiagnosticMessagesImpl runRetraceTest(StackTraceForTest stackTraceForTest)
+ throws Exception {
+ if (external) {
+ // The external dependency is built on top of R8Lib. If test.py is run with
+ // no r8lib, do not try and run the external R8 Retrace since it has not been built.
+ assumeTrue(Files.exists(ToolHelper.R8LIB_JAR));
+ Path path = temp.newFolder().toPath();
+ Path mappingFile = path.resolve("mapping");
+ Files.write(mappingFile, stackTraceForTest.mapping().getBytes());
+ Path stackTraceFile = path.resolve("stacktrace.txt");
+ Files.write(
+ stackTraceFile,
+ StringUtils.joinLines(stackTraceForTest.obfuscatedStackTrace())
+ .getBytes(StandardCharsets.UTF_8));
+
+ List<String> command = new ArrayList<>();
+ command.add(ToolHelper.getSystemJavaExecutable());
+ command.add("-ea");
+ command.add("-cp");
+ command.add(ToolHelper.R8_RETRACE_JAR.toString());
+ command.add("com.android.tools.r8.retrace.Retrace");
+ command.add(mappingFile.toString());
+ command.add(stackTraceFile.toString());
+ command.add("-quiet");
+ ProcessBuilder builder = new ProcessBuilder(command);
+ ProcessResult processResult = ToolHelper.runProcess(builder);
+ assertEquals(
+ StringUtils.joinLines(stackTraceForTest.retracedStackTrace())
+ + StringUtils.LINE_SEPARATOR,
+ processResult.stdout);
+ // TODO(b/177204438): Parse diagnostics from stdErr
+ return new TestDiagnosticMessagesImpl();
+ } else {
+ TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
+ RetraceCommand retraceCommand =
+ RetraceCommand.builder(diagnosticsHandler)
+ .setProguardMapProducer(stackTraceForTest::mapping)
+ .setStackTrace(stackTraceForTest.obfuscatedStackTrace())
+ .setRegularExpression(useRegExpParsing ? DEFAULT_REGULAR_EXPRESSION : null)
+ .setRetracedStackTraceConsumer(
+ retraced -> assertEquals(stackTraceForTest.retracedStackTrace(), retraced))
+ .build();
+ Retrace.run(retraceCommand);
+ return diagnosticsHandler;
+ }
}
}
diff --git a/tools/test.py b/tools/test.py
index cf14685..dffc4565 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -253,6 +253,7 @@
# Force gradle to build a version of r8lib without dependencies for
# BootstrapCurrentEqualityTest.
gradle_args.append('R8LibNoDeps')
+ gradle_args.append('R8Retrace')
if options.r8lib_no_deps:
gradle_args.append('-Pr8lib_no_deps')
if options.worktree: