| // 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()); |
| } |
| } |
| } |