changeset 57908:4e67cff3547b records-and-sealed

More test cases for sealed classes
author briangoetz
date Thu, 10 Oct 2019 15:36:25 -0400
parents 4e5c9c683088
children 2fe9842c2913
files test/langtools/lib/combo/tools/javac/combo/CompilationTestCase.java test/langtools/tools/javac/sealed/SealedCompilationTests.java
diffstat 2 files changed, 177 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/test/langtools/lib/combo/tools/javac/combo/CompilationTestCase.java	Thu Oct 10 13:31:31 2019 -0400
+++ b/test/langtools/lib/combo/tools/javac/combo/CompilationTestCase.java	Thu Oct 10 15:36:25 2019 -0400
@@ -28,7 +28,6 @@
 
 import org.testng.ITestResult;
 import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import static java.util.stream.Collectors.toList;
@@ -65,10 +64,10 @@
         defaultFileName = name;
     }
 
-    private String expand(String... constructs) {
+    protected String expandMarkers(String... constructs) {
         String s = programShell;
         for (String c : constructs)
-            s = s.replace("#", c);
+            s = s.replaceFirst("#", c);
         return s;
     }
 
@@ -86,14 +85,14 @@
     }
 
     protected void assertOK(String... constructs) {
-        assertCompile(expand(constructs), this::assertCompileSucceeded);
+        assertCompile(expandMarkers(constructs), this::assertCompileSucceeded);
     }
 
     protected void assertOKWithWarning(String warning, String... constructs) {
-        assertCompile(expand(constructs), () -> assertCompileSucceededWithWarning(warning));
+        assertCompile(expandMarkers(constructs), () -> assertCompileSucceededWithWarning(warning));
     }
 
     protected void assertFail(String expectedDiag, String... constructs) {
-        assertCompile(expand(constructs), () -> assertCompileFailed(expectedDiag));
+        assertCompile(expandMarkers(constructs), () -> assertCompileFailed(expectedDiag));
     }
 }
--- a/test/langtools/tools/javac/sealed/SealedCompilationTests.java	Thu Oct 10 13:31:31 2019 -0400
+++ b/test/langtools/tools/javac/sealed/SealedCompilationTests.java	Thu Oct 10 15:36:25 2019 -0400
@@ -30,9 +30,11 @@
  * @summary Negative compilation tests, and positive compilation (smoke) tests for sealed types
  * @library /lib/combo
  * @modules jdk.compiler/com.sun.tools.javac.util
- * @run testng SealedCompilationTests
+ * @compile --enable-preview -source 14 SealedCompilationTests.java
+ * @run testng/othervm --enable-preview SealedCompilationTests
  */
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.testng.annotations.Test;
@@ -50,120 +52,199 @@
         setCompileOptions(PREVIEW_OPTIONS);
     }
 
-    public void testSuccessExpected() {
-        // with permits
-        assertOK("class SealedTest {\n" +
-                "    sealed class SC permits C_SC { }\n" +
-                "    final class C_SC extends SC { }\n" +
-                "}");
-        assertOK("class SealedTest {\n" +
-                "    sealed abstract class SAC permits C_SAC { }\n" +
-                "    final class C_SAC extends SAC { }\n" +
-                "}");
-        assertOK("class SealedTest {\n" +
-                "    sealed interface SI permits C_SI, I_SI { }\n" +
-                "    final class C_SI implements SI { }\n" +
-                "    non-sealed interface I_SI extends SI { }\n" +
-                "}");
+    private static final String NO_SHELL = """
+                 #
+                 """;
+    private static final String NEST_SHELL = """
+                 class SealedTest {
+                     #
+                 }
+                 """;
+    private static final String AUX_SHELL = """
+                 class SealedTest {
+                 }
+                 #
+                 """;
+    private static final List<String> SHELLS = List.of(NO_SHELL, NEST_SHELL, AUX_SHELL);
 
-        // wo permits
-        assertOK("class SealedTest {\n" +
-                "    sealed class SC { }\n" +
-                "    final class C_SC extends SC { }\n" +
-                "}");
-        assertOK("class SealedTest {\n" +
-                "    sealed abstract class SAC { }\n" +
-                "    final class C_SAC extends SAC { }\n" +
-                "}");
-        assertOK("class SealedTest {\n" +
-                "    sealed interface SI { }\n" +
-                "    final class C_SI implements SI { }\n" +
-                "    non-sealed interface I_SI extends SI { }\n" +
-                "}");
+    public void testSimpleExtension() {
+        String CC1 =
+            """
+            sealed class Sup # { }
+            # class Sub extends Sup { }
+            """;
+        String AC1 =
+            """
+            sealed abstract class Sup # { }
+            # class Sub extends Sup { }
+            """;
+        String I1 =
+            """
+            sealed interface Sup # { }
+            # class Sub implements Sup { }
+            """;
+        String I2 =
+                """
+            sealed interface Sup # { }
+            # class Sub1 implements Sup { }
+            # class Sub2 implements Sup { }
+            """;
+
+        // Assert that all combinations work:
+        // { class, abs class, interface } x { implicit permits, explicit permits }
+        //                                 x { final, non-sealed subtype }
+        for (String shell : SHELLS)
+            for (String b : List.of(CC1, AC1, I1))
+                for (String p : List.of("", "permits Sub"))
+                    for (String m : List.of("sealed", "final", "non-sealed"))
+                        assertOK(shell, b, p, m);
+
+
+        // Same for type with two subtypes
+        for (String shell : SHELLS)
+            for (String p : List.of("", "permits Sub1, Sub2"))
+                for (String m : List.of("final", "non-sealed"))
+                    assertOK(shell, expandMarkers(I2, p, m, m));
+
+        // Expect failure if there is no explicit final / sealed / non-sealed
+        // @@@ Currently failing
+//        for (String shell : SHELLS)
+//            for (String b : List.of(CC1, AC1, I1))
+//                for (String p : List.of("", "permits Sub"))
+//                    for (String m : List.of(""))
+//                        assertFail("", shell, expandMarkers(b, p, m));
     }
 
-    public void testErrorExpected() {
-        assertFail("compiler.err.cant.inherit.from.sealed","class SealedTest {\n" +
-                "    sealed class SC permits C_SC { }\n" +
-                "    class C_SC extends SC { }\n" +
-                "    class C_SC2 extends SC { }\n" +
-                "}");
-        assertFail("compiler.err.cant.inherit.from.sealed","class SealedTest {\n" +
-                "    sealed abstract class SAC permits C_SAC {}\n" +
-                "    class C_SAC extends SAC {}\n" +
-                "    class C_SAC2 extends SAC {}\n" +
-                "}");
-        assertFail("compiler.err.cant.inherit.from.sealed","class SealedTest {\n" +
-                "    sealed interface SI permits C_SI, I_SI {}\n" +
-                "    class C_SI implements SI {}\n" +
-                "    interface I_SI extends SI {}\n" +
-                "    class C_SI2 implements SI {}\n" +
-                "    interface I_SI2 extends SI {}\n" +
-                "}");
+    public void testSealedAndRecords() {
+        String P =
+            """
+            sealed interface Sup # { }
+            record A(int a) implements Sup { }
+            record B(int b) implements Sup { }
+            record C(int c) implements Sup { }
+            """;
+
+        for (String shell : SHELLS)
+            for (String b : List.of(P))
+                for (String p : List.of("", "permits A, B, C"))
+                    assertOK(shell, b, p);
     }
 
-    public void testValidUsesOfSealed() {
+    // Test that a type that explicitly permits one type, can't be extended by another
+    public void testBadExtension() {
+        String CC2 =
+                """
+                sealed class Sup permits Sub1 { }
+                final class Sub1 extends Sup { }
+                final class Sub2 extends Sup { }
+                """;
+        String AC2 =
+                """
+                sealed abstract class Sup permits Sub1 { }
+                final class Sub1 extends Sup { }
+                final class Sub2 extends Sup { }
+                """;
+        String I2c =
+                """
+                sealed interface Sup permits Sub1 { }
+                final class Sub1 implements Sup { }
+                final class Sub2 implements Sup { }
+                """;
+        String I2i =
+                """
+                sealed interface Sup permits Sub1 { }
+                non-sealed interface Sub1 extends Sup { }
+                non-sealed interface Sub2 extends Sup { }
+                """;
+
+        for (String shell : SHELLS)
+            for (String b : List.of(CC2, AC2, I2c, I2i))
+                assertFail("compiler.err.cant.inherit.from.sealed", shell, b);
+    }
+
+    public void testRestrictedKeyword() {
         for (String s : List.of(
-                "class SealedTest {\n" +
-                "    String sealed;\n" +
-                "}",
-                "class SealedTest {\n" +
-                "    void test(String sealed) { }\n" +
-                "}",
-                "class SealedTest {\n" +
-                "    void test() {\n" +
-                "        String sealed = null;\n" +
-                "    }\n" +
-                "}",
+                "class SealedTest { String sealed; }",
+                "class SealedTest { int sealed = 0; int non = 0; int ns = non-sealed; }",
+                "class SealedTest { void test(String sealed) { } }",
+                "class SealedTest { void sealed(String sealed) { } }",
+                "class SealedTest { void test() { String sealed = null; } }",
                 "class sealed {}")) {
             assertOK(s);
         }
     }
 
-    public void testPermitsInNoSealedClass() {
+    public void testRejectPermitsInNonSealedClass() {
         assertFail("compiler.err.permits.in.no.sealed.class",
                 "class SealedTest {\n" +
                 "    class NotSealed permits Sub {}\n" +
                 "    class Sub extends NotSealed {}\n" +
                 "}");
+        assertFail("compiler.err.permits.in.no.sealed.class",
+                "class SealedTest {\n" +
+                "    interface NotSealed permits Sub {}\n" +
+                "    class Sub implements NotSealed {}\n" +
+                "}");
     }
 
-    public void testWrongUseOfModifiers() {
+    public void testBadModifiers() {
         assertFail("compiler.err.non.sealed.with.no.sealed.supertype",
+                "class SealedTest { non-sealed class NoSealedSuper {} }");
+        assertFail("compiler.err.mod.not.allowed.here",
+                   "class SealedTest { sealed public void m() {} }");
+        for (String s : List.of(
+                "class SealedTest { sealed non-sealed class Super {} }",
+                "class SealedTest { final non-sealed class Super {} }",
+                "class SealedTest { final sealed class Super {} }",
+                "class SealedTest { final sealed non-sealed class Super {} }",
                 "class SealedTest {\n" +
-                        "    non-sealed class NoSealedSuper {}\n" +
-                        "}");
-        assertFail("compiler.err.illegal.combination.of.modifiers",
-                "class SealedTest {\n" +
-                        "    final non-sealed class Super {}\n" +
-                        "}");
-        assertFail("compiler.err.illegal.combination.of.modifiers",
-                "class SealedTest {\n" +
-                        "    final sealed class Super {}\n" +
-                        "}");
-        assertFail("compiler.err.illegal.combination.of.modifiers",
-                "class SealedTest {\n" +
-                        "    final sealed non-sealed class Super {}\n" +
-                        "}");
-        assertFail("compiler.err.illegal.combination.of.modifiers",
-                "class SealedTest {\n" +
-                        "    sealed class Super {}\n" +
-                        "    sealed non-sealed class Sub extends Super {}\n" +
-                        "}");
-        assertFail("compiler.err.mod.not.allowed.here",
-                "class SealedTest {\n" +
-                        "    sealed public void m() {}\n" +
-                        "}");
+                "    sealed class Super {}\n" +
+                "    sealed non-sealed class Sub extends Super {}\n" +
+                "}"))
+            assertFail("compiler.err.illegal.combination.of.modifiers", s);
     }
 
     public void testAnonymousAndLambdaCantExtendSealed() {
-        assertFail("compiler.err.cant.inherit.from.sealed",
+        for (String s : List.of(
                 "sealed interface I1 extends Runnable {\n" +
-                        "    public static I1 i = () -> {};\n" +
-                        "}");
-        assertFail("compiler.err.cant.inherit.from.sealed",
+                "    public static I1 i = () -> {};\n" +
+                "}",
                 "sealed interface I2 extends Runnable {\n" +
-                        "    public static void foo() { new I2() { public void run() { } }; }\n" +
-                        "}");
+                "    public static void foo() { new I2() { public void run() { } }; }\n" +
+                "}"))
+            assertFail("compiler.err.cant.inherit.from.sealed", s);
+    }
+
+    public void testNoLocalSealedClasses() {
+        // @@@ Currently failing; probably wrong diag key as well
+//        for (String s : List.of(
+//                """
+//                sealed class C {
+//                    void m() {
+//                        sealed class C { }
+//                    }
+//                }
+//                """,
+//                """
+//                sealed class C {
+//                    void m() {
+//                        non-sealed class D { }
+//                    }
+//                }
+//                """))
+//            assertFail("compiler.err.cant.inherit.from.sealed", s);
+    }
+
+    public void testLocalCantExtendSealed() {
+        // @@@ Currently failing
+//        for (String s : List.of(
+//                """
+//                sealed class C {
+//                    void m() {
+//                        final class D extends C { }
+//                    }
+//                }
+//                """))
+//            assertFail("compiler.err.cant.inherit.from.sealed", s);
     }
 }