Update test framework

* Expose the actual subtype of TestRunResult
* Add some getters and "map"

For use in an upcoming CL.

Change-Id: I44e98a735c7f513f0386f1aa79fa69d764fa9a2b
diff --git a/src/test/java/com/android/tools/r8/D8TestRunResult.java b/src/test/java/com/android/tools/r8/D8TestRunResult.java
index d14f12d..1aa095a 100644
--- a/src/test/java/com/android/tools/r8/D8TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/D8TestRunResult.java
@@ -7,9 +7,14 @@
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.utils.AndroidApp;
 
-public class D8TestRunResult extends TestRunResult {
+public class D8TestRunResult extends TestRunResult<D8TestRunResult> {
 
   public D8TestRunResult(AndroidApp app, ProcessResult result) {
     super(app, result);
   }
+
+  @Override
+  protected D8TestRunResult self() {
+    return this;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/DXTestRunResult.java b/src/test/java/com/android/tools/r8/DXTestRunResult.java
index c1df193..830cbd8 100644
--- a/src/test/java/com/android/tools/r8/DXTestRunResult.java
+++ b/src/test/java/com/android/tools/r8/DXTestRunResult.java
@@ -7,9 +7,14 @@
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.utils.AndroidApp;
 
-public class DXTestRunResult extends TestRunResult {
+public class DXTestRunResult extends TestRunResult<DXTestRunResult> {
 
   public DXTestRunResult(AndroidApp app, ProcessResult result) {
     super(app, result);
   }
+
+  @Override
+  protected DXTestRunResult self() {
+    return this;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
index 4e0bedf..44a3bed 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -24,7 +24,7 @@
 import java.util.List;
 import java.util.Set;
 
-public class JvmTestBuilder extends TestBuilder<JvmTestBuilder> {
+public class JvmTestBuilder extends TestBuilder<JvmTestRunResult, JvmTestBuilder> {
 
   private static class ClassFileResource implements ProgramResource {
 
@@ -107,9 +107,9 @@
   }
 
   @Override
-  public TestRunResult run(String mainClass) throws IOException {
+  public JvmTestRunResult run(String mainClass) throws IOException {
     ProcessResult result = ToolHelper.runJava(classpath, mainClass);
-    return new TestRunResult(builder.build(), result);
+    return new JvmTestRunResult(builder.build(), result);
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/JvmTestRunResult.java b/src/test/java/com/android/tools/r8/JvmTestRunResult.java
new file mode 100644
index 0000000..b7a71fd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/JvmTestRunResult.java
@@ -0,0 +1,20 @@
+// 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 com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.AndroidApp;
+
+public class JvmTestRunResult extends TestRunResult<JvmTestRunResult> {
+
+  public JvmTestRunResult(AndroidApp app, ProcessResult result) {
+    super(app, result);
+  }
+
+  @Override
+  protected JvmTestRunResult self() {
+    return this;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ProguardTestRunResult.java b/src/test/java/com/android/tools/r8/ProguardTestRunResult.java
index 9e0d875..e242a38 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestRunResult.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestRunResult.java
@@ -12,7 +12,7 @@
 import java.io.IOException;
 import java.util.concurrent.ExecutionException;
 
-public class ProguardTestRunResult extends TestRunResult {
+public class ProguardTestRunResult extends TestRunResult<ProguardTestRunResult> {
 
   private final String proguardMap;
 
@@ -22,6 +22,11 @@
   }
 
   @Override
+  protected ProguardTestRunResult self() {
+    return this;
+  }
+
+  @Override
   public CodeInspector inspector() throws IOException, ExecutionException {
     // See comment in base class.
     assertSuccess();
diff --git a/src/test/java/com/android/tools/r8/R8TestRunResult.java b/src/test/java/com/android/tools/r8/R8TestRunResult.java
index 2c42b95..ddea062 100644
--- a/src/test/java/com/android/tools/r8/R8TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestRunResult.java
@@ -12,7 +12,7 @@
 import java.io.IOException;
 import java.util.concurrent.ExecutionException;
 
-public class R8TestRunResult extends TestRunResult {
+public class R8TestRunResult extends TestRunResult<R8TestRunResult> {
 
   private final String proguardMap;
 
@@ -22,10 +22,19 @@
   }
 
   @Override
+  protected R8TestRunResult self() {
+    return this;
+  }
+
+  @Override
   public CodeInspector inspector() throws IOException, ExecutionException {
     // See comment in base class.
     assertSuccess();
     assertNotNull(app);
     return new CodeInspector(app, proguardMap);
   }
+
+  public String proguardMap() {
+    return proguardMap;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 4977d94..0675118 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -14,7 +14,7 @@
 import java.util.HashSet;
 import java.util.Set;
 
-public abstract class TestBuilder<T extends TestBuilder<T>> {
+public abstract class TestBuilder<RR extends TestRunResult, T extends TestBuilder<RR, T>> {
 
   private final TestState state;
 
@@ -28,10 +28,10 @@
 
   abstract T self();
 
-  public abstract TestRunResult run(String mainClass)
+  public abstract RR run(String mainClass)
       throws IOException, CompilationFailedException;
 
-  public TestRunResult run(Class mainClass) throws IOException, CompilationFailedException {
+  public RR run(Class mainClass) throws IOException, CompilationFailedException {
     return run(mainClass.getTypeName());
   }
 
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 810d292..f60db7f 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -22,7 +22,7 @@
         CR extends TestCompileResult<RR>,
         RR extends TestRunResult,
         T extends TestCompilerBuilder<C, B, CR, RR, T>>
-    extends TestBuilder<T> {
+    extends TestBuilder<RR, T> {
 
   public static final Consumer<InternalOptions> DEFAULT_OPTIONS =
       new Consumer<InternalOptions>() {
@@ -71,7 +71,7 @@
   }
 
   @Override
-  public TestRunResult run(String mainClass) throws IOException, CompilationFailedException {
+  public RR run(String mainClass) throws IOException, CompilationFailedException {
     return compile().run(mainClass);
   }
 
diff --git a/src/test/java/com/android/tools/r8/TestRunResult.java b/src/test/java/com/android/tools/r8/TestRunResult.java
index 46dc4cc..f3ec339 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -15,9 +15,10 @@
 import java.io.IOException;
 import java.io.PrintStream;
 import java.util.concurrent.ExecutionException;
+import java.util.function.Function;
 import org.hamcrest.Matcher;
 
-public class TestRunResult {
+public abstract class TestRunResult<RR extends TestRunResult<?>> {
   protected final AndroidApp app;
   private final ProcessResult result;
 
@@ -26,33 +27,51 @@
     this.result = result;
   }
 
-  public TestRunResult assertSuccess() {
+  abstract RR self();
+
+  public String getStdOut() {
+    return result.stdout;
+  }
+
+  public String getStdErr() {
+    return result.stderr;
+  }
+
+  public int getExitCode() {
+    return result.exitCode;
+  }
+
+  public RR assertSuccess() {
     assertEquals(errorMessage("Expected run to succeed."), 0, result.exitCode);
-    return this;
+    return self();
   }
 
-  public TestRunResult assertFailure() {
+  public RR assertFailure() {
     assertNotEquals(errorMessage("Expected run to fail."), 0, result.exitCode);
-    return this;
+    return self();
   }
 
-  public TestRunResult assertFailureWithOutput(String expected) {
+  public RR assertFailureWithOutput(String expected) {
     assertFailure();
     assertEquals(errorMessage("Run stdout incorrect.", expected), expected, result.stdout);
-    return this;
+    return self();
   }
 
-  public TestRunResult assertFailureWithErrorThatMatches(Matcher<String> matcher) {
+  public RR assertFailureWithErrorThatMatches(Matcher<String> matcher) {
     assertFailure();
     assertThat(
         errorMessage("Run stderr incorrect.", matcher.toString()), result.stderr, matcher);
-    return this;
+    return self();
   }
 
-  public TestRunResult assertSuccessWithOutput(String expected) {
+  public RR assertSuccessWithOutput(String expected) {
     assertSuccess();
     assertEquals(errorMessage("Run stdout incorrect.", expected), expected, result.stdout);
-    return this;
+    return self();
+  }
+
+  public <R> R map(Function<RR, R> mapper) {
+    return mapper.apply(self());
   }
 
   public CodeInspector inspector() throws IOException, ExecutionException {
@@ -63,10 +82,10 @@
     return new CodeInspector(app);
   }
 
-  public TestRunResult inspect(Consumer<CodeInspector> consumer)
+  public RR inspect(Consumer<CodeInspector> consumer)
       throws IOException, ExecutionException {
     consumer.accept(inspector());
-    return this;
+    return self();
   }
 
   private String errorMessage(String message) {
@@ -102,24 +121,24 @@
     builder.append("COMMAND: ").append(result.command).append('\n').append(result);
   }
 
-  public TestRunResult writeInfo(PrintStream ps) {
+  public RR writeInfo(PrintStream ps) {
     StringBuilder sb = new StringBuilder();
     appendInfo(sb);
     ps.println(sb.toString());
-    return this;
+    return self();
   }
 
-  public TestRunResult writeApplicaion(PrintStream ps) {
+  public RR writeApplicaion(PrintStream ps) {
     StringBuilder sb = new StringBuilder();
     appendApplication(sb);
     ps.println(sb.toString());
-    return this;
+    return self();
   }
 
-  public TestRunResult writeProcessResult(PrintStream ps) {
+  public RR writeProcessResult(PrintStream ps) {
     StringBuilder sb = new StringBuilder();
     appendProcessResult(sb);
     ps.println(sb.toString());
-    return this;
+    return self();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java b/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java
index 010f903..a9eef53 100644
--- a/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java
+++ b/src/test/java/com/android/tools/r8/d8/IncompatiblePrimitiveTypesTest.java
@@ -64,8 +64,8 @@
 
   @Test
   public void dexTest() throws Exception {
-    TestRunResult d8Result = testForD8().addProgramFiles(inputJar).run("TestClass");
-    TestRunResult dxResult = testForDX().addProgramFiles(inputJar).run("TestClass");
+    TestRunResult<?> d8Result = testForD8().addProgramFiles(inputJar).run("TestClass");
+    TestRunResult<?> dxResult = testForDX().addProgramFiles(inputJar).run("TestClass");
     if (ToolHelper.getDexVm().getVersion().isNewerThan(Version.V4_4_4)) {
       d8Result.assertSuccessWithOutput(expectedOutput);
       dxResult.assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
index 2e065ed..5362c38 100644
--- a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
@@ -126,15 +126,15 @@
     jasminBuilder.writeJar(inputJar);
 
     if (backend == Backend.CF) {
-      TestRunResult jvmResult = testForJvm().addClasspath(inputJar).run(mainClass.name);
+      TestRunResult<?> jvmResult = testForJvm().addClasspath(inputJar).run(mainClass.name);
       checkTestRunResult(jvmResult, false);
     } else {
       assert backend == Backend.DEX;
 
-      TestRunResult dxResult = testForDX().addProgramFiles(inputJar).run(mainClass.name);
+      TestRunResult<?> dxResult = testForDX().addProgramFiles(inputJar).run(mainClass.name);
       checkTestRunResult(dxResult, false);
 
-      TestRunResult d8Result = testForD8().addProgramFiles(inputJar).run(mainClass.name);
+      TestRunResult<?> d8Result = testForD8().addProgramFiles(inputJar).run(mainClass.name);
       checkTestRunResult(d8Result, false);
     }
 
@@ -147,7 +147,7 @@
     checkTestRunResult(r8Result, true);
   }
 
-  private void checkTestRunResult(TestRunResult result, boolean isR8) {
+  private void checkTestRunResult(TestRunResult<?> result, boolean isR8) {
     switch (mode) {
       case NO_INVOKE:
         result.assertSuccessWithOutput(getExpectedOutput(isR8));