blob: 243c87464e9fb2e40d5aad006650926b278ad8a2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2020 IBM Corporation.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.core.tests.model;
import java.io.File;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IOrdinaryClassFile;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IProblemRequestor;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.tests.util.AbstractCompilerTest;
import org.eclipse.jdt.core.tests.util.Util;
import junit.framework.Test;
public class SealedTypeModelTests extends AbstractJavaModelTests {
static {
// TESTS_NAMES = new String[] {"test001"};
}
ProblemRequestor problemRequestor;
public SealedTypeModelTests(String name) {
super(name);
}
@Override
public void setUp() throws Exception {
super.setUp();
this.problemRequestor = new ProblemRequestor();
this.wcOwner = new WorkingCopyOwner() {
public IProblemRequestor getProblemRequestor(ICompilationUnit unit) {
return SealedTypeModelTests.this.problemRequestor;
}
};
}
public static Test suite() {
return buildModelTestSuite(AbstractCompilerTest.F_15, SealedTypeModelTests.class);
}
protected IJavaProject createJavaProject(String projectName) throws CoreException {
IJavaProject createJavaProject = super.createJavaProject(projectName, new String[] {"src"}, new String[] {"JCL14_LIB"}, "bin", "15");
createJavaProject.setOption(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED);
return createJavaProject;
}
// Check types with neither sealed nor non-sealed don't return those modifiers
public void test001() throws Exception {
try {
IJavaProject project = createJavaProject("SealedTypes");
project.open(null);
String fileContent = "@SuppressWarnings(\"preview\")\n" +
"interface I {}\n" +
"public class X implements I {}\n" +
"interface Y extends I {}\n";
createFile( "/SealedTypes/src/X.java", fileContent);
ICompilationUnit unit = getCompilationUnit("/SealedTypes/src/X.java");
IType[] types = unit.getTypes();
assertEquals("Incorret no of types", 3, types.length);
for (IType iType : types) {
assertFalse("modifier should not contain sealed : " + iType.getElementName(), iType.isSealed());
}
}
finally {
deleteProject("SealedTypes");
}
}
public void test002() throws Exception {
try {
IJavaProject project = createJavaProject("SealedTypes");
project.open(null);
String fileContent = "sealed interface I permits X, Y {}\n" +
"public non-sealed class X implements I {}\n" +
"non-sealed interface Y extends I {}\n";
createFile( "/SealedTypes/src/X.java", fileContent);
ICompilationUnit unit = getCompilationUnit("/SealedTypes/src/X.java");
IType[] types = unit.getTypes();
assertEquals("Incorret no of types", 3, types.length);
for (IType iType : types) {
if (iType.getElementName().equals("I")) {
assertTrue("modifier should contain sealed", iType.isSealed());
} else {
assertFalse("modifier should not contain sealed : " + iType.getElementName(), iType.isSealed());
}
}
}
finally {
deleteProject("SealedTypes");
}
}
// Test explicitly permitted sub types in Source Type
public void test003() throws Exception {
String[] permitted = new String[] {"X", "Y"};
try {
IJavaProject project = createJavaProject("SealedTypes");
project.open(null);
String fileContent = "sealed interface I permits X, Y {}\n" +
"public non-sealed class X implements I {}\n" +
"non-sealed interface Y extends I {}\n";
createFile( "/SealedTypes/src/X.java", fileContent);
ICompilationUnit unit = getCompilationUnit("/SealedTypes/src/X.java");
IType[] types = unit.getTypes();
assertEquals("Incorret no of types", 3, types.length);
for (IType iType : types) {
if (iType.getElementName().equals("I")) {
assertTrue("modifier should contain sealed", iType.isSealed());
String[] permittedSubtypeNames = iType.getPermittedSubtypeNames();
assertEquals("incorrect permitted sub types", permitted.length, permittedSubtypeNames.length);
for (int i = 0; i < permitted.length; i++) {
assertEquals("incorrect permitted sub type", permitted[i], permittedSubtypeNames[i]);
}
}
}
}
finally {
deleteProject("SealedTypes");
}
}
// Test implicitly permitted sub types in Source Type
public void test004() throws Exception {
String[] permitted = new String[] {"X", "Y"};
try {
IJavaProject project = createJavaProject("SealedTypes");
project.open(null);
String fileContent = "sealed interface I {}\n" +
"public non-sealed class X implements I {}\n" +
"non-sealed interface Y extends I {}\n";
createFile( "/SealedTypes/src/X.java", fileContent);
ICompilationUnit unit = getCompilationUnit("/SealedTypes/src/X.java");
IType[] types = unit.getTypes();
assertEquals("Incorret no of types", 3, types.length);
for (IType iType : types) {
if (iType.getElementName().equals("I")) {
assertTrue("modifier should contain sealed", iType.isSealed());
String[] permittedSubtypeNames = iType.getPermittedSubtypeNames();
assertEquals("incorrect permitted sub types", permitted.length, permittedSubtypeNames.length);
for (int i = 0; i < permitted.length; i++) {
assertEquals("incorrect permitted sub type", permitted[i], permittedSubtypeNames[i]);
}
}
}
}
finally {
deleteProject("SealedTypes");
}
}
// Test explicitly permitted sub types in binary
public void test005() throws Exception {
String[] permitted = new String[] {"p.X", "p.Y"};
try {
String[] sources = {
"p/X.java",
"package p;\n;" +
"sealed interface I permits X, Y {}\n" +
"public non-sealed class X implements I {}\n" +
"non-sealed interface Y extends I {}\n"
};
String outputDirectory = Util.getOutputDirectory();
String jarPath = outputDirectory + File.separator + "sealed.jar";
Util.createJar(sources, jarPath, "15", true);
IJavaProject project = createJavaProject("SealedTypes");
addClasspathEntry(project, JavaCore.newLibraryEntry(new Path(jarPath), null, null, null, null, false));
project.open(null);
project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
IPackageFragmentRoot[] roots = project.getPackageFragmentRoots();
IPackageFragmentRoot root = null;
for (IPackageFragmentRoot iRoot : roots) {
if (iRoot.getRawClasspathEntry().getPath().toString().endsWith("sealed.jar")) {
root = iRoot;
}
}
assertNotNull("root should not be null", root);
IPackageFragment packageFragment = root.getPackageFragment("p");
assertNotNull("package is null", packageFragment);
IOrdinaryClassFile classFile = packageFragment.getOrdinaryClassFile("I.class");
assertNotNull("class is null", classFile);
IType type = classFile.getType();
assertNotNull("type is null", type);
String[] permittedSubtypeNames = type.getPermittedSubtypeNames();
assertEquals("incorrect permitted sub types", permitted.length, permittedSubtypeNames.length);
for (int i = 0; i < permitted.length; i++) {
assertEquals("incorrect permitted sub type", permitted[i], permittedSubtypeNames[i]);
}
assertTrue("modifier should contain sealed", type.isSealed());
classFile = packageFragment.getOrdinaryClassFile("X.class");
assertNotNull("class is null", classFile);
type = classFile.getType();
assertNotNull("type is null", type);
permittedSubtypeNames = type.getPermittedSubtypeNames();
assertEquals("incorrect permitted sub types", 0, permittedSubtypeNames.length);
assertFalse("modifier should not contain sealed", type.isSealed());
classFile = packageFragment.getOrdinaryClassFile("Y.class");
assertNotNull("class is null", classFile);
type = classFile.getType();
assertNotNull("type is null", type);
permittedSubtypeNames = type.getPermittedSubtypeNames();
assertEquals("incorrect permitted sub types", 0, permittedSubtypeNames.length);
assertFalse("modifier should not contain sealed", type.isSealed());
}
finally {
deleteProject("SealedTypes");
}
}
// Test implicitly permitted sub types in binary
public void test006() throws Exception {
String[] permitted = new String[] {"p.X", "p.Y"};
try {
String[] sources = {
"p/X.java",
"package p;\n;" +
"sealed interface I {}\n" +
"public non-sealed class X implements I {}\n" +
"non-sealed interface Y extends I {}\n"
};
String outputDirectory = Util.getOutputDirectory();
String jarPath = outputDirectory + File.separator + "sealed.jar";
Util.createJar(sources, jarPath, "15", true);
IJavaProject project = createJavaProject("SealedTypes");
addClasspathEntry(project, JavaCore.newLibraryEntry(new Path(jarPath), null, null, null, null, false));
project.open(null);
project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
IPackageFragmentRoot[] roots = project.getPackageFragmentRoots();
IPackageFragmentRoot root = null;
for (IPackageFragmentRoot iRoot : roots) {
if (iRoot.getRawClasspathEntry().getPath().toString().endsWith("sealed.jar")) {
root = iRoot;
}
}
assertNotNull("root should not be null", root);
IPackageFragment packageFragment = root.getPackageFragment("p");
assertNotNull("package is null", packageFragment);
IOrdinaryClassFile classFile = packageFragment.getOrdinaryClassFile("I.class");
assertNotNull("class is null", classFile);
IType type = classFile.getType();
assertNotNull("type is null", type);
String[] permittedSubtypeNames = type.getPermittedSubtypeNames();
assertEquals("incorrect permitted sub types", permitted.length, permittedSubtypeNames.length);
for (int i = 0; i < permitted.length; i++) {
assertEquals("incorrect permitted sub type", permitted[i], permittedSubtypeNames[i]);
}
assertTrue("modifier should contain sealed", type.isSealed());
classFile = packageFragment.getOrdinaryClassFile("X.class");
assertNotNull("class is null", classFile);
type = classFile.getType();
assertNotNull("type is null", type);
permittedSubtypeNames = type.getPermittedSubtypeNames();
assertEquals("incorrect permitted sub types", 0, permittedSubtypeNames.length);
assertFalse("modifier should not contain sealed", type.isSealed());
classFile = packageFragment.getOrdinaryClassFile("Y.class");
assertNotNull("class is null", classFile);
type = classFile.getType();
assertNotNull("type is null", type);
permittedSubtypeNames = type.getPermittedSubtypeNames();
assertEquals("incorrect permitted sub types", 0, permittedSubtypeNames.length);
assertFalse("modifier should not contain sealed", type.isSealed());
}
finally {
deleteProject("SealedTypes");
}
}
// Test sealed types for reconciler
public void test007() throws Exception {
String[] permitted = new String[] {"p.X"};
try {
IJavaProject project = createJavaProject("SealedTypes");
project.open(null);
String fileContent = "package p;\n" +
"sealed interface I permits p.X {}\n";
createFolder("/SealedTypes/src/p");
createFile("/SealedTypes/src/p/I.java", fileContent);
fileContent = "package p;\n" +
"public non-sealed class X implements p.I {}\n";
createFile( "/SealedTypes/src/p/X.java", fileContent);
ICompilationUnit unit = getCompilationUnit("/SealedTypes/src/p/I.java");
this.workingCopies = new ICompilationUnit[1];
char[] sourceChars = fileContent.toCharArray();
this.problemRequestor.initialize(sourceChars);
this.workingCopies[0] = unit.getWorkingCopy(this.wcOwner, null);
assertProblems(
"Unexpected problems",
"----------\n" +
"----------\n",
this.problemRequestor);
IType[] types = unit.getTypes();
assertEquals("Incorret no of types", 1, types.length);
for (IType iType : types) {
if (iType.getElementName().equals("I")) {
assertTrue("modifier should contain sealed", iType.isSealed());
String[] permittedSubtypeNames = iType.getPermittedSubtypeNames();
assertEquals("incorrect permitted sub types", permitted.length, permittedSubtypeNames.length);
for (int i = 0; i < permitted.length; i++) {
assertEquals("incorrect permitted sub type", permitted[i], permittedSubtypeNames[i]);
}
}
}
}
finally {
deleteProject("SealedTypes");
}
}
// Test sealed types for reconciler
public void test008() throws Exception {
try {
IJavaProject project = createJavaProject("SealedTypes");
project.open(null);
String fileContent = "package p;\n" +
"sealed interface I permits p.X {}\n";
createFolder("/SealedTypes/src/p");
createFile( "/SealedTypes/src/p/I.java", fileContent);
this.workingCopies = new ICompilationUnit[1];
char[] sourceChars = fileContent.toCharArray();
this.problemRequestor.initialize(sourceChars);
this.workingCopies[0] = getCompilationUnit("/SealedTypes/src/p/I.java").getWorkingCopy(this.wcOwner, null);
assertProblems(
"Unexpected problems",
"----------\n" +
"1. ERROR in /SealedTypes/src/p/I.java (at line 2)\n" +
" sealed interface I permits p.X {}\n" +
" ^^^\n" +
"p.X cannot be resolved to a type\n" +
"----------\n",
this.problemRequestor);
}
finally {
deleteProject("SealedTypes");
}
}
// Test sealed types for reconciler
public void test009() throws Exception {
try {
IJavaProject project = createJavaProject("SealedTypes");
project.open(null);
String fileContent = "package p;\n" +
"sealed interface I permits p.X {}\n";
createFolder("/SealedTypes/src/p");
createFile( "/SealedTypes/src/p/I.java", fileContent);
fileContent = "package p;\n" +
"public non-sealed class X {}\n";
createFile( "/SealedTypes/src/p/X.java", fileContent);
this.workingCopies = new ICompilationUnit[1];
char[] sourceChars = fileContent.toCharArray();
this.problemRequestor.initialize(sourceChars);
this.workingCopies[0] = getCompilationUnit("/SealedTypes/src/p/X.java").getWorkingCopy(this.wcOwner, null);
assertProblems(
"Unexpected problems",
"----------\n" +
"1. ERROR in /SealedTypes/src/p/X.java (at line 2)\n" +
" public non-sealed class X {}\n" +
" ^\n" +
"A class X declared as non-sealed should have either a sealed direct superclass or a sealed direct superinterface\n" +
"----------\n",
this.problemRequestor);
}
finally {
deleteProject("SealedTypes");
}
}
}