Add testForAssistant support in test framework
This will d8 compile the input and then run this through the R8Assistant instrumentation.
Bug: b/393265921
Change-Id: Ieaf777cb3164f0a68129c3d81121f33de7c7e1ec
diff --git a/src/test/java/com/android/tools/r8/assistant/R8AssistentReflectiveInstrumentationTest.java b/src/test/java/com/android/tools/r8/assistant/R8AssistentReflectiveInstrumentationTest.java
index bb9b78c..3a578c3 100644
--- a/src/test/java/com/android/tools/r8/assistant/R8AssistentReflectiveInstrumentationTest.java
+++ b/src/test/java/com/android/tools/r8/assistant/R8AssistentReflectiveInstrumentationTest.java
@@ -4,15 +4,11 @@
package com.android.tools.r8.assistant;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.R8Assistant;
-import com.android.tools.r8.R8AssistantCommand;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -24,7 +20,6 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.io.IOException;
import java.io.UncheckedIOException;
-import java.nio.file.Path;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -63,41 +58,16 @@
@Test
public void testInstrumentation() throws Exception {
- Path d8Compilation =
- testForD8(parameters.getBackend())
- .addInnerClasses(getClass())
- .setMinApi(parameters)
- .compile()
- .inspect(codeInspector -> inspectStaticCallsInReflectOn(0, codeInspector))
- .writeToZip();
- R8AssistantCommand.Builder builder = R8AssistantCommand.builder();
- Path outputPath = temp.newFile("instrumented.jar").toPath();
- // TODO(b/393265921): Add testForR8Assistant and avoid building up the command here
- R8AssistantCommand command =
- builder
- .addProgramFiles(d8Compilation)
- .setMinApiLevel(parameters.getApiLevel().getLevel())
- .setOutput(outputPath, OutputMode.DexIndexed)
- .build();
- R8Assistant.run(command);
- inspectStaticCallsInReflectOn(outputPath, 2);
-
- String artOutput =
- ToolHelper.runArtNoVerificationErrors(
- outputPath.toString(),
- TestClass.class
- .getName()); // For now, just test that the printed logs are what we expect
- String expectedNewInstanceString =
- "Reflectively created new instance of " + Bar.class.getName();
- assertThat(artOutput, containsString(expectedNewInstanceString));
- String expectedGetDeclaredMethod =
- "Reflectively got declared method callMe on " + Bar.class.getName();
- assertThat(artOutput, containsString(expectedGetDeclaredMethod));
- }
-
- private static void inspectStaticCallsInReflectOn(Path outputPath, int count) throws IOException {
- CodeInspector inspector = new CodeInspector(outputPath);
- inspectStaticCallsInReflectOn(count, inspector);
+ testForAssistant()
+ .addInnerClasses(getClass())
+ .setMinApi(parameters)
+ .compile()
+ .inspectOriginalDex(inspector -> inspectStaticCallsInReflectOn(0, inspector))
+ .inspect(inspector -> inspectStaticCallsInReflectOn(2, inspector))
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines(
+ "Reflectively created new instance of " + Bar.class.getName(),
+ "Reflectively got declared method callMe on " + Bar.class.getName());
}
private static void inspectStaticCallsInReflectOn(int count, CodeInspector inspector) {
diff --git a/src/test/testbase/java/com/android/tools/r8/AssistantTestBuilder.java b/src/test/testbase/java/com/android/tools/r8/AssistantTestBuilder.java
new file mode 100644
index 0000000..abecb6b
--- /dev/null
+++ b/src/test/testbase/java/com/android/tools/r8/AssistantTestBuilder.java
@@ -0,0 +1,89 @@
+// Copyright (c) 2025, 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.testForD8;
+
+import com.android.tools.r8.TestBase.Backend;
+import com.android.tools.r8.benchmarks.BenchmarkResults;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class AssistantTestBuilder
+ extends TestCompilerBuilder<
+ R8AssistantCommand,
+ R8AssistantCommand.Builder,
+ AssistantTestCompileResult,
+ AssistantTestRunResult,
+ AssistantTestBuilder> {
+
+ private final D8TestBuilder initialCompileBuilder;
+ private Path output;
+
+ private AssistantTestBuilder(TestState state) {
+ super(state, R8AssistantCommand.builder(state.getDiagnosticsHandler()), Backend.DEX);
+ initialCompileBuilder = testForD8(state.getTempFolder());
+ }
+
+ public static AssistantTestBuilder create(TestState state) {
+ return new AssistantTestBuilder(state);
+ }
+
+ @Override
+ AssistantTestBuilder self() {
+ return this;
+ }
+
+ @Override
+ public AssistantTestBuilder addClasspathClasses(Collection<Class<?>> classes) {
+ throw new Unimplemented("No classpath for assistant");
+ }
+
+ @Override
+ public AssistantTestBuilder addClasspathFiles(Collection<Path> files) {
+ throw new Unimplemented("No classpath for assistant");
+ }
+
+ @Override
+ public AssistantTestBuilder addProgramFiles(Collection<Path> files) {
+ initialCompileBuilder.addProgramFiles(files);
+ return self();
+ }
+
+ @Override
+ AssistantTestCompileResult internalCompile(
+ R8AssistantCommand.Builder builder,
+ Consumer<InternalOptions> optionsConsumer,
+ Supplier<AndroidApp> app,
+ BenchmarkResults benchmarkResults)
+ throws CompilationFailedException {
+ Path initialCompilation;
+ try {
+ initialCompilation = initialCompileBuilder.setMinApi(getMinApiLevel()).compile().writeToZip();
+ if (output == null) {
+ output = getState().getNewTempFile("assistant_output.jar");
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ builder
+ .addProgramFiles(initialCompilation)
+ .setOutput(output, OutputMode.DexIndexed)
+ .setMinApiLevel(getMinApiLevel());
+
+ R8Assistant.run(builder.build());
+ return new AssistantTestCompileResult(
+ initialCompilation,
+ getState(),
+ AndroidApp.builder().addProgramFiles(output).build(),
+ getMinApiLevel());
+ }
+}
diff --git a/src/test/testbase/java/com/android/tools/r8/AssistantTestCompileResult.java b/src/test/testbase/java/com/android/tools/r8/AssistantTestCompileResult.java
new file mode 100644
index 0000000..b0b2c99
--- /dev/null
+++ b/src/test/testbase/java/com/android/tools/r8/AssistantTestCompileResult.java
@@ -0,0 +1,61 @@
+// Copyright (c) 2025, 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 com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.ThrowingConsumer;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Set;
+
+public class AssistantTestCompileResult
+ extends TestCompileResult<AssistantTestCompileResult, AssistantTestRunResult> {
+
+ private final Path initialOutput;
+
+ public AssistantTestCompileResult(
+ Path initialOutput, TestState testState, AndroidApp androidApp, int minApi) {
+ super(testState, androidApp, minApi, OutputMode.DexIndexed);
+ this.initialOutput = initialOutput;
+ }
+
+ @Override
+ public AssistantTestCompileResult self() {
+ return this;
+ }
+
+ @Override
+ public TestDiagnosticMessages getDiagnosticMessages() {
+ return state.getDiagnosticsMessages();
+ }
+
+ @Override
+ public Set<String> getMainDexClasses() {
+ throw new Unimplemented("No support for main dex in assistant");
+ }
+
+ @Override
+ public String getStdout() {
+ return state.getStdout();
+ }
+
+ @Override
+ public String getStderr() {
+ return state.getStderr();
+ }
+
+ @Override
+ protected AssistantTestRunResult createRunResult(TestRuntime runtime, ProcessResult result) {
+ return new AssistantTestRunResult(app, runtime, result, state);
+ }
+
+ public <E extends Throwable> AssistantTestCompileResult inspectOriginalDex(
+ ThrowingConsumer<CodeInspector, E> consumer) throws IOException, E {
+ consumer.accept(new CodeInspector(initialOutput));
+ return self();
+ }
+}
diff --git a/src/test/testbase/java/com/android/tools/r8/AssistantTestRunResult.java b/src/test/testbase/java/com/android/tools/r8/AssistantTestRunResult.java
new file mode 100644
index 0000000..f1054cf
--- /dev/null
+++ b/src/test/testbase/java/com/android/tools/r8/AssistantTestRunResult.java
@@ -0,0 +1,21 @@
+// Copyright (c) 2025, 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 com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.AndroidApp;
+
+public class AssistantTestRunResult extends SingleTestRunResult<AssistantTestRunResult> {
+
+ public AssistantTestRunResult(
+ AndroidApp app, TestRuntime runtime, ProcessResult result, TestState state) {
+ super(app, runtime, result, state);
+ }
+
+ @Override
+ protected AssistantTestRunResult self() {
+ return this;
+ }
+}
diff --git a/src/test/testbase/java/com/android/tools/r8/RelocatorTestCompileResult.java b/src/test/testbase/java/com/android/tools/r8/RelocatorTestCompileResult.java
index f3c624c..635c37d 100644
--- a/src/test/testbase/java/com/android/tools/r8/RelocatorTestCompileResult.java
+++ b/src/test/testbase/java/com/android/tools/r8/RelocatorTestCompileResult.java
@@ -3,10 +3,8 @@
// 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;
diff --git a/src/test/testbase/java/com/android/tools/r8/TestBase.java b/src/test/testbase/java/com/android/tools/r8/TestBase.java
index 9722064..2f6a150 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestBase.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestBase.java
@@ -238,6 +238,10 @@
return testForD8(temp, backend);
}
+ public AssistantTestBuilder testForAssistant() {
+ return AssistantTestBuilder.create(new TestState(temp));
+ }
+
public RelocatorTestBuilder testForRelocator(boolean external) {
return RelocatorTestBuilder.create(new TestState(temp), external);
}