Add a sealed class test with illegal subclass of sealed class

Bug: b/227160052
Change-Id: I8b5a336fb6dc1b9ea3db760c9f2306be7cb03af7
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeIllegalSubclassTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeIllegalSubclassTest.java
new file mode 100644
index 0000000..3dfdc3d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeIllegalSubclassTest.java
@@ -0,0 +1,118 @@
+// Copyright (c) 2023, 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.desugar.sealed;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.DesugarTestConfiguration;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SealedAttributeIllegalSubclassTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  static final String EXPECTED = StringUtils.lines("Success!");
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
+  }
+
+  private void addTestClasses(TestBuilder<?, ?> builder) throws Exception {
+    builder
+        .addProgramClasses(TestClass.class, Sub1.class, Sub2.class, Sub3.class)
+        .addProgramClassFileData(getTransformedClasses());
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    parameters.assumeJvmTestParameters();
+    assumeTrue(parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK17));
+    testForJvm(parameters)
+        .apply(this::addTestClasses)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertFailureWithErrorThatMatches(containsString("cannot inherit from sealed class"));
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    testForDesugaring(parameters)
+        .apply(this::addTestClasses)
+        .run(parameters.getRuntime(), TestClass.class)
+        .applyIf(
+            DesugarTestConfiguration::isNotJavac,
+            r -> r.assertSuccessWithOutput(EXPECTED),
+            c -> parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK17),
+            r ->
+                r.assertFailureWithErrorThatMatches(
+                    containsString("cannot inherit from sealed class")),
+            r -> r.assertFailureWithErrorThatThrows(UnsupportedClassVersionError.class));
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    parameters.assumeR8TestParameters();
+    R8FullTestBuilder builder =
+        testForR8(parameters.getBackend())
+            .apply(this::addTestClasses)
+            .setMinApi(parameters)
+            .addKeepMainRule(TestClass.class);
+    if (parameters.isCfRuntime()) {
+      // TODO(b/227160052): Support sealed classes for R8 class file output.
+      assertThrows(
+          CompilationFailedException.class,
+          () ->
+              builder.compileWithExpectedDiagnostics(
+                  diagnostics ->
+                      diagnostics.assertErrorThatMatches(
+                          diagnosticMessage(
+                              containsString(
+                                  "Sealed classes are not supported as program classes")))));
+    } else {
+      builder
+          .run(parameters.getRuntime(), TestClass.class)
+          .assertSuccessWithOutputLines("Success!");
+    }
+  }
+
+  public byte[] getTransformedClasses() throws Exception {
+    return transformer(C.class).setPermittedSubclasses(C.class, Sub1.class, Sub2.class).transform();
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      new Sub1();
+      new Sub2();
+      new Sub3();
+      System.out.println("Success!");
+    }
+  }
+
+  abstract static class C /* permits Sub1, Sub2 */ {}
+
+  static class Sub1 extends C {}
+
+  static class Sub2 extends C {}
+
+  static class Sub3 extends C {}
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java
index d44c81b..a508238 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java
@@ -75,7 +75,7 @@
             .setMinApi(parameters)
             .addKeepMainRule(TestClass.class);
     if (parameters.isCfRuntime()) {
-      // TODO(b/227160052): Support sealed classes for R( class file output.
+      // TODO(b/227160052): Support sealed classes for R8 class file output.
       assertThrows(
           CompilationFailedException.class,
           () ->