Update tests of DEX with identifiers with white space characters

Add test of Proguard, mapping file output and JVM stack trace.

Bug: b/269089718
Change-Id: I8548930776de12464da33a6104645079a2a4b3c3
diff --git a/src/test/java/com/android/tools/r8/dex/whitespaceinidentifiers/WhiteSpaceInIdentifiersTest.java b/src/test/java/com/android/tools/r8/dex/whitespaceinidentifiers/WhiteSpaceInIdentifiersTest.java
index 9092ea4..0dc670b 100644
--- a/src/test/java/com/android/tools/r8/dex/whitespaceinidentifiers/WhiteSpaceInIdentifiersTest.java
+++ b/src/test/java/com/android/tools/r8/dex/whitespaceinidentifiers/WhiteSpaceInIdentifiersTest.java
@@ -7,15 +7,21 @@
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.ProguardVersion;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestCompilerBuilder;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.naming.ProguardMapReader.ParseException;
+import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
 import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.DexVersion;
@@ -36,7 +42,7 @@
 
   @Parameters(name = "{0}")
   public static List<Object[]> data() {
-    return buildParameters(getTestParameters().withDexRuntimesAndAllApiLevels().build());
+    return buildParameters(getTestParameters().withAllRuntimes().withAllApiLevels().build());
   }
 
   private static final String EXPECTED_OUTPUT =
@@ -44,12 +50,25 @@
           "0x20", "0xa0", "0x1680", "0x2000", "0x2001", "0x2002", "0x2003", "0x2004", "0x2005",
           "0x2006", "0x2007", "0x2008", "0x2009", "0x200a", "0x202f", "0x205f", "0x3000");
 
-  public void test(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder) throws Exception {
+  private void assumeParametersWithSupportForWhitespaceInIdentifiers() {
+    assumeTrue(
+        parameters.isCfRuntime()
+            || (parameters.isDexRuntime()
+                && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.R)));
+  }
+
+  private void assumeDexRuntimeSupportingDexVersion039() {
+    assumeTrue(
+        parameters.isDexRuntime()
+            && parameters.getApiLevel().getDexVersion().isGreaterThanOrEqualTo(DexVersion.V39));
+  }
+
+  public void configure(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder) throws Exception {
     testBuilder
         .addProgramClassFileData(getTransformed())
-        .setMinApi(parameters.getApiLevel())
+        .applyIf(parameters.isDexRuntime(), b -> b.setMinApi(parameters.getApiLevel()))
         .applyIf(
-            parameters.getApiLevel().isLessThan(AndroidApiLevel.R),
+            parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(AndroidApiLevel.R),
             b -> {
               try {
                 b.compileWithExpectedDiagnostics(
@@ -69,25 +88,69 @@
 
   @Test
   public void testD8() throws Exception {
-    test(testForD8(parameters.getBackend()));
+    parameters.assumeDexRuntime();
+    configure(testForD8(parameters.getBackend()));
   }
 
   @Test
   public void testR8() throws Exception {
-    try {
-      test(testForR8(parameters.getBackend()).addKeepMainRule(TestClass.class));
-    } catch (RuntimeException e) {
-      // TODO(b/141287396): Proguard maps with spaces in identifiers are not supported. Running
-      //  on R8 always creates an inspector to find the name of the potentially renamed main class.
-      assertTrue(e.getCause() instanceof ExecutionException);
-      assertTrue(e.getCause().getCause() instanceof ParseException);
-    }
+    assumeParametersWithSupportForWhitespaceInIdentifiers();
+    Exception e =
+        assertThrows(
+            RuntimeException.class,
+            () -> configure(testForR8(parameters.getBackend()).addKeepMainRule(TestClass.class)));
+    // TODO(b/141287396): Proguard maps with spaces in identifiers are not supported. Running
+    //  on R8 always creates an inspector to find the name of the potentially renamed main class.
+    assertTrue(e.getCause() instanceof ExecutionException);
+    assertTrue(e.getCause().getCause() instanceof ParseException);
+  }
+
+  @Test
+  public void testR8Mapping() throws Exception {
+    assumeParametersWithSupportForWhitespaceInIdentifiers();
+    String map =
+        testForR8(parameters.getBackend())
+            .addProgramClassFileData(getTransformed())
+            .applyIf(parameters.isDexRuntime(), b -> b.setMinApi(parameters.getApiLevel()))
+            .addKeepMainRule(TestClass.class)
+            .compile()
+            .getProguardMap();
+    // R8 renames methods with white space, so they appear in the mapping file.
+    assertTrue(StringUtils.splitLines(map).size() > 40);
+  }
+
+  @Test
+  public void testProguard() throws Exception {
+    parameters.assumeCfRuntime();
+    configure(
+        testForProguard(ProguardVersion.V7_0_0)
+            .addKeepMainRule(TestClass.class)
+            .addDontWarn(TestClass.class.getTypeName()));
+  }
+
+  @Test
+  public void testProguardMapping() throws Exception {
+    parameters.assumeCfRuntime();
+    String map =
+        testForProguard(ProguardVersion.V7_0_0)
+            .addProgramClassFileData(getTransformed())
+            .addKeepMainRule(TestClass.class)
+            .addDontWarn(TestClass.class.getTypeName())
+            .compile()
+            .getProguardMap();
+    // Proguard leaves the methods with white space alone, so they don't need to appear in the
+    // mapping file.
+    assertEquals(
+        StringUtils.lines(
+            TestClass.class.getTypeName() + " -> " + TestClass.class.getTypeName() + ":",
+            "    void <init>() -> <init>",
+            "    void main(java.lang.String[]) -> main"),
+        map);
   }
 
   @Test
   public void testD8MergeWithSpaces() throws Exception {
-    assumeTrue(parameters.getApiLevel().getDexVersion().isGreaterThanOrEqualTo(DexVersion.V39));
-
+    assumeDexRuntimeSupportingDexVersion039();
     // Compile with API level 30 to allow white space in identifiers. This generates DEX
     // version 039.
     Path dex =
@@ -121,7 +184,7 @@
 
   @Test
   public void testD8RunWithSpaces() throws Exception {
-    assumeTrue(parameters.getApiLevel().getDexVersion().isGreaterThanOrEqualTo(DexVersion.V39));
+    assumeDexRuntimeSupportingDexVersion039();
     testForD8(parameters.getBackend())
         .addProgramClassFileData(getTransformed())
         .setMinApi(AndroidApiLevel.R)
@@ -134,7 +197,7 @@
 
   @Test
   public void testD8RunWithSpacesUsingDexV40() throws Exception {
-    assumeTrue(parameters.getApiLevel().getDexVersion().isGreaterThanOrEqualTo(DexVersion.V39));
+    assumeDexRuntimeSupportingDexVersion039();
     testForD8(parameters.getBackend())
         .addOptionsModification(options -> options.testing.dexVersion40FromApiLevel30 = true)
         .addProgramClassFileData(getTransformed())
@@ -148,6 +211,34 @@
             b -> b.assertSuccessWithOutput(EXPECTED_OUTPUT));
   }
 
+  @Test
+  public void testJvmStackTrace() throws Exception {
+    parameters.assumeCfRuntime();
+    testForJvm()
+        .addProgramClassFileData(getTransformed())
+        .run(parameters.asCfRuntime(), TestClass.class, "")
+        .assertFailureWithErrorThatThrows(RuntimeException.class)
+        .inspectOriginalStackTrace(
+            stackTrace ->
+                assertThat(
+                    stackTrace,
+                    StackTrace.isSameExceptForLineNumbers(
+                        StackTrace.builder()
+                            .add(
+                                StackTraceLine.builder()
+                                    .setMethodName(" ")
+                                    .setClassName(TestClass.class.getTypeName())
+                                    .setFileName("WhiteSpaceInIdentifiersTest.java")
+                                    .build())
+                            .add(
+                                StackTraceLine.builder()
+                                    .setMethodName("main")
+                                    .setClassName(TestClass.class.getTypeName())
+                                    .setFileName("WhiteSpaceInIdentifiersTest.java")
+                                    .build())
+                            .build())));
+  }
+
   private String rename(String name) {
     return new String(Character.toChars(Integer.parseInt(name.substring(1), 16)));
   }
@@ -172,8 +263,11 @@
   // Supported on Art in https://android-review.git.corp.google.com/c/platform/art/+/1106719.
   static class TestClass {
 
-    private static void t20() {
+    private static void t20(boolean throwException) {
       System.out.println("0x20");
+      if (throwException) {
+        throw new RuntimeException();
+      }
     }
 
     private static void ta0() {
@@ -241,7 +335,7 @@
     }
 
     public static void main(String[] args) {
-      t20();
+      t20(args.length > 0);
       ta0();
       t1680();
       t2000();