blob: 480f7b428e495cbbc7a0228289db6e3b8d35e83e [file] [log] [blame]
// Copyright (c) 2017, 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 org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.QuadConsumer;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import org.junit.Assert;
public class AsmTestBase extends TestBase {
protected void ensureSameOutput(String main, AndroidApiLevel apiLevel, byte[]... classes)
throws Exception {
ensureSameOutput(main, apiLevel, Collections.emptyList(), classes);
}
protected void ensureSameOutput(String main, AndroidApiLevel apiLevel,
List<String> args, byte[]... classes) throws Exception {
AndroidApp app = buildAndroidApp(classes);
Consumer<InternalOptions> setMinApiLevel = o -> o.setMinApiLevel(apiLevel);
ProcessResult javaResult = runOnJavaRaw(main, Arrays.asList(classes), args);
Consumer<ArtCommandBuilder> cmdBuilder = builder -> {
for (String arg : args) {
builder.appendProgramArgument(arg);
}
};
ProcessResult d8Result = runOnArtRaw(
compileWithD8(app, setMinApiLevel), main, cmdBuilder, null);
ProcessResult r8Result = runOnArtRaw(
compileWithR8(app, setMinApiLevel), main, cmdBuilder, null);
ProcessResult r8ShakenResult = runOnArtRaw(
compileWithR8(app, keepMainProguardConfiguration(main) + "-dontobfuscate\n",
setMinApiLevel), main, cmdBuilder, null);
Assert.assertEquals(javaResult.stdout, d8Result.stdout);
Assert.assertEquals(javaResult.stdout, r8Result.stdout);
Assert.assertEquals(javaResult.stdout, r8ShakenResult.stdout);
}
protected void ensureCustomCheck(
QuadConsumer<ProcessResult, ProcessResult, ProcessResult, ProcessResult> checker,
String main,
AndroidApiLevel apiLevel,
List<String> args,
byte[]... classes)
throws Exception {
AndroidApp app = buildAndroidApp(classes);
Consumer<InternalOptions> setMinApiLevel = o -> o.setMinApiLevel(apiLevel);
ProcessResult javaResult = runOnJavaRaw(main, Arrays.asList(classes), args);
Consumer<ArtCommandBuilder> cmdBuilder =
builder -> {
for (String arg : args) {
builder.appendProgramArgument(arg);
}
};
ProcessResult d8Result =
runOnArtRaw(compileWithD8(app, setMinApiLevel), main, cmdBuilder, null);
ProcessResult r8Result =
runOnArtRaw(compileWithR8(app, setMinApiLevel), main, cmdBuilder, null);
ProcessResult r8ShakenResult =
runOnArtRaw(
compileWithR8(
app, keepMainProguardConfiguration(main) + "-dontobfuscate\n", setMinApiLevel),
main,
cmdBuilder,
null);
checker.accept(javaResult, d8Result, r8Result, r8ShakenResult);
}
protected void ensureSameOutput(String main, byte[]... classes) throws Exception {
AndroidApp app = buildAndroidApp(classes);
ensureSameOutput(main, app, false, classes);
}
protected void ensureSameOutputJavaNoVerify(String main, byte[]... classes) throws Exception {
AndroidApp app = buildAndroidApp(classes);
ensureSameOutput(main, app, true, classes);
}
private void ensureSameOutput(
String main, AndroidApp app, boolean useJavaNoVerify, byte[]... classes)
throws IOException, CompilationFailedException {
ProcessResult javaResult =
useJavaNoVerify ? runOnJavaRawNoVerify(main, classes) : runOnJavaRaw(main, classes);
ProcessResult d8Result = runOnArtRaw(compileWithD8(app), main);
ProcessResult r8NonShakenResult =
runOnArtRaw(compileWithR8(app, "-dontshrink\n-dontobfuscate\n"), main);
ProcessResult r8ShakenResult =
runOnArtRaw(
compileWithR8(app, keepMainProguardConfiguration(main) + "-dontobfuscate\n"), main);
Assert.assertEquals(javaResult.stdout, d8Result.stdout);
Assert.assertEquals(javaResult.stdout, r8NonShakenResult.stdout);
Assert.assertEquals(javaResult.stdout, r8ShakenResult.stdout);
Assert.assertEquals(0, javaResult.exitCode);
Assert.assertEquals(0, d8Result.exitCode);
Assert.assertEquals(0, r8NonShakenResult.exitCode);
Assert.assertEquals(0, r8ShakenResult.exitCode);
}
protected void ensureR8FailsWithCompilationError(String main, byte[]... classes)
throws Exception {
// TODO(zerny): Port this to use diagnostics handler.
AndroidApp app = buildAndroidApp(classes);
CompilationFailedException r8Error = null;
CompilationFailedException r8ShakenError = null;
try {
runOnArtRaw(compileWithR8(app, "-dontshrink\n-dontobfuscate\n"), main);
} catch (CompilationFailedException e) {
r8Error = e;
}
try {
runOnArtRaw(compileWithR8(app, keepMainProguardConfiguration(main) + "-dontobfuscate\n"),
main);
} catch (CompilationFailedException e) {
r8ShakenError = e;
}
Assert.assertNotNull(r8Error);
Assert.assertNotNull(r8ShakenError);
}
protected void ensureSameOutputAfterMerging(String main, byte[]... classes)
throws IOException, CompilationFailedException {
AndroidApp app = buildAndroidApp(classes);
// Compile to dex files with D8.
AndroidApp dexApp = compileWithD8(app);
// Perform dex merging with D8 to read the dex files.
AndroidApp mergedApp = compileWithD8(dexApp);
ensureSameOutput(main, mergedApp, false, classes);
}
protected static AndroidApp readClassesAndAsmDump(List<Class<?>> classes, List<byte[]> asmClasses)
throws IOException {
AndroidApp.Builder builder = AndroidApp.builder();
for (Class clazz : classes) {
builder.addProgramFiles(ToolHelper.getClassFileForTestClass(clazz));
}
for (byte[] clazz : asmClasses) {
builder.addClassProgramData(clazz, Origin.unknown());
}
return builder.build();
}
private void ensureExceptionThrown(ProcessResult result, Class<? extends Throwable> exception) {
assertFalse(result.stdout, result.exitCode == 0);
assertTrue(result.stderr, result.stderr.contains(exception.getCanonicalName()));
}
@FunctionalInterface
protected interface AsmDump {
byte[] dump() throws Exception;
}
protected static byte[] getBytesFromAsmClass(AsmDump asmDump) {
try {
return asmDump.dump();
} catch (Exception e) {
throw new ClassFormatError(e.toString());
}
}
}