| // Copyright (c) 2018, 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.hamcrest.MatcherAssert.assertThat; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotEquals; |
| |
| import com.android.tools.r8.ToolHelper.DexVm; |
| import com.android.tools.r8.ToolHelper.ProcessResult; |
| import com.android.tools.r8.debug.DebugTestConfig; |
| import com.android.tools.r8.naming.retrace.StackTrace; |
| import com.android.tools.r8.utils.AndroidApp; |
| import com.android.tools.r8.utils.internal.StringUtils; |
| import com.android.tools.r8.utils.internal.ThrowingConsumer; |
| import java.io.IOException; |
| import java.io.PrintStream; |
| import java.nio.file.Path; |
| import java.util.function.Predicate; |
| import org.hamcrest.Matcher; |
| |
| public class SingleTestRunResult extends TestRunResult<SingleTestRunResult> { |
| private final TestRuntime runtime; |
| private final ProcessResult result; |
| |
| public SingleTestRunResult( |
| AndroidApp app, TestRuntime runtime, ProcessResult result, TestState state) { |
| this(app, runtime, result, null, state); |
| } |
| |
| public SingleTestRunResult( |
| AndroidApp app, |
| TestRuntime runtime, |
| ProcessResult result, |
| String proguardMap, |
| TestState state) { |
| super(app, proguardMap, state); |
| this.runtime = runtime; |
| this.result = result; |
| } |
| |
| @Override |
| protected SingleTestRunResult self() { |
| return this; |
| } |
| |
| @Override |
| public SingleTestRunResult asSingleRuntimeResult() { |
| return self(); |
| } |
| |
| public TestRuntime runtime() { |
| return runtime; |
| } |
| |
| public ProcessResult getResult() { |
| return result; |
| } |
| |
| public String getStdOut() { |
| return result.stdout; |
| } |
| |
| public String getStdErr() { |
| return result.stderr; |
| } |
| |
| public int getExitCode() { |
| return result.exitCode; |
| } |
| |
| public StackTrace getStackTrace() { |
| StackTrace original = getOriginalStackTrace(); |
| return proguardMap == null ? original : original.retraceAllowExperimentalMapping(proguardMap); |
| } |
| |
| public StackTrace getOriginalStackTrace() { |
| if (runtime.isDex()) { |
| return StackTrace.extractFromArt(getStdErr(), runtime.asDex().getVm()); |
| } else { |
| return StackTrace.extractFromJvm(getStdErr()); |
| } |
| } |
| |
| @Override |
| public <E extends Throwable> SingleTestRunResult inspectStdOut( |
| ThrowingConsumer<String, E> consumer) throws E { |
| consumer.accept(getStdOut()); |
| return self(); |
| } |
| |
| @Override |
| public <E extends Throwable> SingleTestRunResult inspectStackTrace( |
| ThrowingConsumer<StackTrace, E> consumer) throws E { |
| consumer.accept(getStackTrace()); |
| return self(); |
| } |
| |
| @Override |
| public <E extends Throwable> SingleTestRunResult inspectOriginalStackTrace( |
| ThrowingConsumer<StackTrace, E> consumer) throws E { |
| consumer.accept(getOriginalStackTrace()); |
| return self(); |
| } |
| |
| @Override |
| public SingleTestRunResult assertSuccess() { |
| assertEquals(errorMessage("Expected run to succeed."), 0, result.exitCode); |
| return self(); |
| } |
| |
| @Override |
| public SingleTestRunResult assertStdoutMatches(Matcher<String> matcher) { |
| assertThat(errorMessage("Run stdout incorrect.", matcher.toString()), result.stdout, matcher); |
| return self(); |
| } |
| |
| @Override |
| public SingleTestRunResult assertStdoutLinesMatchesUnordered(Iterable<Matcher<String>> lines) { |
| assertThat( |
| StringUtils.splitLines(result.stdout), UnorderedCollectionMatcher.matchesOneToOne(lines)); |
| return self(); |
| } |
| |
| @Override |
| public SingleTestRunResult assertFailure() { |
| assertNotEquals(errorMessage("Expected run to fail."), 0, result.exitCode); |
| return self(); |
| } |
| |
| @Override |
| public SingleTestRunResult assertStderrMatches(Matcher<String> matcher) { |
| assertThat(errorMessage("Run stderr incorrect.", matcher.toString()), result.stderr, matcher); |
| return self(); |
| } |
| |
| @Override |
| void appendProcessResult(StringBuilder builder) { |
| builder.append("COMMAND: ").append(result.command).append('\n').append(result); |
| } |
| |
| @Override |
| public SingleTestRunResult writeProcessResult(PrintStream ps) { |
| StringBuilder sb = new StringBuilder(); |
| appendProcessResult(sb); |
| ps.println(sb.toString()); |
| return self(); |
| } |
| |
| private boolean matchesDexVersion(Predicate<DexVm.Version> predicate) { |
| return runtime.isDex() && predicate.test(runtime.asDex().getVm().getVersion()); |
| } |
| |
| @Override |
| public < |
| S extends Throwable, |
| T extends Throwable, |
| U extends Throwable, |
| V extends Throwable, |
| W extends Throwable> |
| SingleTestRunResult applyIfDexRuntime( |
| Predicate<DexVm.Version> condition1, |
| ThrowingConsumer<? super SingleTestRunResult, S> thenConsumer1, |
| Predicate<DexVm.Version> condition2, |
| ThrowingConsumer<? super SingleTestRunResult, T> thenConsumer2, |
| Predicate<DexVm.Version> condition3, |
| ThrowingConsumer<? super SingleTestRunResult, U> thenConsumer3, |
| Predicate<DexVm.Version> condition4, |
| ThrowingConsumer<? super SingleTestRunResult, W> thenConsumer4, |
| ThrowingConsumer<? super SingleTestRunResult, V> elseConsumer) |
| throws S, T, U, V, W { |
| if (matchesDexVersion(condition1)) { |
| thenConsumer1.accept(this); |
| } else if (matchesDexVersion(condition2)) { |
| thenConsumer2.accept(this); |
| } else if (matchesDexVersion(condition3)) { |
| thenConsumer3.accept(this); |
| } else if (matchesDexVersion(condition4)) { |
| thenConsumer4.accept(this); |
| } else { |
| elseConsumer.accept(this); |
| } |
| return self(); |
| } |
| |
| @Override |
| public <E extends Throwable> SingleTestRunResult debugger( |
| ThrowingConsumer<DebugTestConfig, E> consumer) throws E, IOException { |
| Path out = getState().getNewTempFolder().resolve("out.zip"); |
| app.writeToZipForTesting(out, runtime.isCf() ? OutputMode.ClassFile : OutputMode.DexIndexed); |
| DebugTestConfig config = DebugTestConfig.create(runtime, out); |
| consumer.accept(config); |
| return self(); |
| } |
| } |