Add tests for minifying non-member classes.
Bug: 132128436
Change-Id: Iffc31025c7fee3e6de68119c30130e538368d4e2
diff --git a/src/test/java/com/android/tools/r8/naming/NonMemberClassTest.java b/src/test/java/com/android/tools/r8/naming/NonMemberClassTest.java
new file mode 100644
index 0000000..9ef1a4a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/NonMemberClassTest.java
@@ -0,0 +1,143 @@
+// Copyright (c) 2019, 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.naming;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.util.Collection;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NonMemberClassTest extends TestBase {
+
+ static class Enclosing {
+ @NeverInline
+ void foo() {
+ class Local {
+ Local() {
+ if (this.getClass().getEnclosingClass() != null) {
+ System.out.println("I'm local.");
+ }
+ }
+ }
+ new Local();
+
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ if (this.getClass().isAnonymousClass()) {
+ System.out.println("I'm anonymous.");
+ }
+ }
+ };
+ r.run();
+ }
+ }
+
+ static class TestMain {
+ public static void main(String... args) {
+ new Enclosing().foo();
+ }
+ }
+
+ enum TestConfig {
+ KEEP_INNER_CLASSES,
+ KEEP_ALLOW_MINIFICATION,
+ NO_KEEP_NO_MINIFICATION,
+ NO_KEEP_MINIFICATION;
+
+ public String getKeepRules() {
+ switch (this) {
+ case KEEP_INNER_CLASSES:
+ return "-keep class " + Enclosing.class.getName() + "$*";
+ case KEEP_ALLOW_MINIFICATION:
+ return "-keep,allowobfuscation class " + Enclosing.class.getName() + "$*";
+ case NO_KEEP_NO_MINIFICATION:
+ return "-dontobfuscate";
+ case NO_KEEP_MINIFICATION:
+ return "";
+ default:
+ throw new Unreachable();
+ }
+ }
+ }
+
+ private static final Class<?> MAIN = TestMain.class;
+ private static final String EXPECTED_OUTPUT = StringUtils.lines(
+ "I'm local.",
+ "I'm anonymous."
+ );
+
+ private final TestParameters parameters;
+ private final TestConfig config;
+
+ @Parameterized.Parameters(name = "{0} {1}")
+ public static Collection<Object[]> data() {
+ return buildParameters(getTestParameters().withAllRuntimes().build(), TestConfig.values());
+ }
+
+ public NonMemberClassTest(TestParameters parameters, TestConfig config) {
+ this.parameters = parameters;
+ this.config = config;
+ }
+
+ @Test
+ public void testJVMOutput() throws Exception {
+ assumeTrue(
+ "Only run JVM reference on CF runtimes",
+ parameters.isCfRuntime() && config == TestConfig.NO_KEEP_NO_MINIFICATION);
+ testForJvm()
+ .addTestClasspath()
+ .run(parameters.getRuntime(), MAIN)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testR8Compat() throws Exception {
+ assumeTrue("b/132128436", config == TestConfig.NO_KEEP_NO_MINIFICATION);
+ testForR8Compat(parameters.getBackend())
+ .addInnerClasses(NonMemberClassTest.class)
+ .addKeepMainRule(MAIN)
+ .addKeepRules(config.getKeepRules())
+ .addKeepAttributes("InnerClasses", "EnclosingMethod")
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getRuntime())
+ .run(parameters.getRuntime(), MAIN)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT)
+ .inspect(this::inspect);
+ }
+
+ @Ignore("b/132128436")
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(NonMemberClassTest.class)
+ .addKeepMainRule(MAIN)
+ .addKeepRules(config.getKeepRules())
+ .addKeepAttributes("InnerClasses", "EnclosingMethod")
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getRuntime())
+ .run(parameters.getRuntime(), MAIN)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT)
+ .inspect(this::inspect);
+ }
+
+ private void inspect(CodeInspector inspector) {
+ assertEquals(2,
+ inspector.allClasses().stream()
+ .filter(classSubject ->
+ classSubject.getDexClass().isLocalClass()
+ || classSubject.getDexClass().isAnonymousClass()).count());
+ }
+}