blob: 3b3590466dfa2893ab8425356ec9ba89294ac901 [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.ProcessResult;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.DescriptorUtils;
import com.google.common.io.ByteStreams;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutionException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.junit.Assert;
public class AsmTestBase extends TestBase {
protected void ensureException(String main, Class<? extends Throwable> exceptionClass,
byte[]... classes) throws Exception {
ensureExceptionThrown(runOnJava(main, classes), exceptionClass);
AndroidApp app = buildAndroidApp(classes);
ensureExceptionThrown(runOnArtRaw(compileWithD8(app), main), exceptionClass);
ensureExceptionThrown(runOnArtRaw(compileWithR8(app), main), exceptionClass);
ensureExceptionThrown(
runOnArtRaw(compileWithR8(app, keepMainProguardConfiguration(main) + "-dontobfuscate\n"),
main),
exceptionClass);
}
protected void ensureSameOutput(String main, byte[]... classes) throws Exception {
AndroidApp app = buildAndroidApp(classes);
ensureSameOutput(main, app, classes);
}
private void ensureSameOutput(String main, AndroidApp app, byte[]... classes)
throws IOException, CompilationException, ExecutionException, CompilationFailedException,
ProguardRuleParserException {
ProcessResult javaResult = runOnJava(main, classes);
ProcessResult d8Result = runOnArtRaw(compileWithD8(app), main);
ProcessResult r8Result = runOnArtRaw(compileWithR8(app), main);
ProcessResult r8ShakenResult = runOnArtRaw(
compileWithR8(app, keepMainProguardConfiguration(main) + "-dontobfuscate\n"), main);
Assert.assertEquals(javaResult.stdout, d8Result.stdout);
Assert.assertEquals(javaResult.stdout, r8Result.stdout);
Assert.assertEquals(javaResult.stdout, r8ShakenResult.stdout);
}
protected void ensureSameOutputD8R8(String main, byte[]... classes) throws Exception {
AndroidApp app = buildAndroidApp(classes);
ProcessResult d8Result = runOnArtRaw(compileWithD8(app), main);
ProcessResult r8Result = runOnArtRaw(compileWithR8(app), main);
ProcessResult r8ShakenResult = runOnArtRaw(
compileWithR8(app, keepMainProguardConfiguration(main) + "-dontobfuscate\n"), main);
Assert.assertEquals(d8Result.stdout, r8Result.stdout);
Assert.assertEquals(d8Result.stdout, r8ShakenResult.stdout);
}
protected void ensureR8FailsWithCompilationError(String main, byte[]... classes)
throws Exception {
// TODO(zerny): Port this to use diagnostics handler.
AndroidApp app = buildAndroidApp(classes);
CompilationError r8Error = null;
CompilationError r8ShakenError = null;
try {
runOnArtRaw(compileWithR8(app), main);
} catch (CompilationError e) {
r8Error = e;
}
try {
runOnArtRaw(compileWithR8(app, keepMainProguardConfiguration(main) + "-dontobfuscate\n"),
main);
} catch (CompilationError e) {
r8ShakenError = e;
}
Assert.assertNotNull(r8Error);
Assert.assertNotNull(r8ShakenError);
}
protected void ensureSameOutputAfterMerging(String main, byte[]... classes)
throws IOException, CompilationException, ExecutionException,
CompilationFailedException, ProguardRuleParserException {
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, classes);
}
protected byte[] asBytes(Class clazz) throws IOException {
return ByteStreams
.toByteArray(clazz.getResourceAsStream(clazz.getSimpleName() + ".class"));
}
private AndroidApp buildAndroidApp(byte[]... classes) throws IOException {
AndroidApp.Builder builder = AndroidApp.builder();
for (byte[] clazz : classes) {
builder.addClassProgramData(clazz, Origin.unknown());
}
builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.N.getLevel()));
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()));
}
protected ProcessResult runOnJava(String main, byte[]... classes) throws IOException {
Path file = writeToZip(classes);
return ToolHelper.runJavaNoVerify(file, main);
}
private Path writeToZip(byte[]... classes) throws IOException {
NameExtrator nameExtrator = new NameExtrator();
File result = temp.newFile();
try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(result.toPath(),
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
for (byte[] clazz : classes) {
String name = nameExtrator.getName(clazz);
ZipEntry zipEntry = new ZipEntry(DescriptorUtils.getPathFromJavaType(name));
zipEntry.setSize(clazz.length);
out.putNextEntry(zipEntry);
out.write(clazz);
out.closeEntry();
}
}
return result.toPath();
}
private static class NameExtrator extends ClassLoader {
public String getName(byte[] clazz) {
Class loaded = defineClass(clazz, 0, clazz.length);
return loaded.getTypeName();
}
}
}