blob: 893e309b52330f4cacd8e9b1119a79bf716be3c7 [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.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IOrdinaryClassFile;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.tests.util.AbstractCompilerTest;
import org.eclipse.jdt.core.tests.util.Util;
import junit.framework.Test;
public class RecordsElementTests extends AbstractJavaModelTests {
static {
// TESTS_NAMES = new String[] {"test001"};
}
public RecordsElementTests(String name) {
super(name);
}
public static Test suite() {
return buildModelTestSuite(AbstractCompilerTest.F_15, RecordsElementTests.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;
}
// Test a simple class for record oriented attributes
public void test001() throws Exception {
try {
IJavaProject project = createJavaProject("RecordsElement");
project.open(null);
String fileContent = "@SuppressWarnings(\"preview\")\n" +
"public class Point {\n" +
" public Point(int x1, int x2) {\n" +
" x1 = 10;\n" +
" x2 = 11;\n" +
" }\n" +
"}\n";
createFile( "/RecordsElement/src/X.java", fileContent);
ICompilationUnit unit = getCompilationUnit("/RecordsElement/src/X.java");
IType[] types = unit.getTypes();
assertEquals("Incorret no of types", 1, types.length);
assertEquals("type should be a record", IJavaElement.TYPE, types[0].getElementType());
assertFalse("type should be a record", types[0].isRecord());
IField[] recordComponents = types[0].getRecordComponents();
assertNotNull("should not be null", recordComponents);
assertEquals("Incorret no of components", 0, recordComponents.length);
}
finally {
deleteProject("RecordsElement");
}
}
// Test that with preview disabled, model doesn't see/create record elements
public void test002() throws Exception {
try {
IJavaProject project = createJavaProject("RecordsElement");
project.setOption(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.DISABLED);
project.open(null);
String fileContent = "@SuppressWarnings(\"preview\")\n" +
"public class Point {\n" +
" public Point(int x1, int x2) {\n" +
" x1 = 10;\n" +
" x2 = 11;\n" +
" }\n" +
"}\n";
createFile( "/RecordsElement/src/X.java", fileContent);
ICompilationUnit unit = getCompilationUnit("/RecordsElement/src/X.java");
IType[] types = unit.getTypes();
assertEquals("Incorret no of types", 1, types.length);
}
finally {
deleteProject("RecordsElement");
}
}
// Test a simple record and record components
public void test003() throws Exception {
try {
IJavaProject project = createJavaProject("RecordsElement");
project.open(null);
String fileContent = "@SuppressWarnings(\"preview\")\n" +
"public record Point(int x1, int x2) {\n" +
" public Point {\n" +
" this.x1 = 10;\n" +
" this.x2 = 11;\n" +
" }\n" +
"}\n";
createFile( "/RecordsElement/src/X.java", fileContent);
ICompilationUnit unit = getCompilationUnit("/RecordsElement/src/X.java");
IType[] types = unit.getTypes();
assertEquals("Incorret no of types", 1, types.length);
assertTrue("type should be a record", types[0].isRecord());
assertEquals("type should be a record", IJavaElement.TYPE, types[0].getElementType());
IField[] fields = types[0].getFields();
assertEquals("Incorret no of fields", 0, fields.length);
IField[] recordComponents = types[0].getRecordComponents();
assertNotNull("should be null", recordComponents);
assertEquals("Incorret no of components", 2, recordComponents.length);
IField comp = recordComponents[0];
assertEquals("type should be a record component", IJavaElement.FIELD, comp.getElementType());
assertEquals("incorrect element name", "x1", comp.getElementName());
comp = recordComponents[1];
assertEquals("type should be a record component", IJavaElement.FIELD, comp.getElementType());
assertEquals("incorrect element name", "x2", comp.getElementName());
IMethod[] methods = types[0].getMethods();
assertNotNull("should not be null", methods);
assertEquals("Incorret no of methods", 1, methods.length);
IMethod iMethod = methods[0];
assertEquals("type should be a record component", IJavaElement.METHOD, iMethod.getElementType());
assertEquals("incorrect element name", "Point", iMethod.getElementName());
String[] parameterNames = iMethod.getParameterNames();
assertEquals("parameters not matching", 2, parameterNames.length);
}
finally {
deleteProject("RecordsElement");
}
}
public void test004() throws Exception {
try {
IJavaProject project = createJavaProject("RecordsElement");
project.open(null);
String fileContent = "@SuppressWarnings(\"preview\")\n" +
"public record Point(int x1, int x2) {\n" +
"}\n";
createFile( "/RecordsElement/src/X.java", fileContent);
ICompilationUnit unit = getCompilationUnit("/RecordsElement/src/X.java");
IType[] types = unit.getTypes();
assertEquals("Incorret no of types", 1, types.length);
assertTrue("type should be a record", types[0].isRecord());
assertEquals("type should be a record", IJavaElement.TYPE, types[0].getElementType());
IMethod[] methods = types[0].getMethods();
assertNotNull("should not be null", methods);
assertEquals("Incorret no of elements", 0, methods.length);
}
finally {
deleteProject("RecordsElement");
}
}
// Test record with compact canonical constructor
public void test005() throws Exception {
try {
this.workingCopies = new ICompilationUnit[1];
IJavaProject project = createJavaProject("RecordsElement");
project.open(null);
String fileContent = "public record Point(int x1, int x2) {\n" +
" public Point {\n" +
" x1 = 1;\n" +
" }\n" +
"}\n";
createFile( "/RecordsElement/src/X.java", fileContent);
ICompilationUnit unit = getCompilationUnit("/RecordsElement/src/X.java");
IType[] types = unit.getTypes();
assertEquals("Incorret no of types", 1, types.length);
assertTrue("type should be a record", types[0].isRecord());
assertEquals("type should be a record", IJavaElement.TYPE, types[0].getElementType());
IMethod[] methods = types[0].getMethods();
assertNotNull("should not be null", methods);
assertEquals("Incorret no of elements", 1, methods.length);
IMethod constructor = methods[0];
assertTrue("should be a constructor", constructor.isConstructor());
//assertTrue("should be a canonical constructor", constructor.isCanonicalConstructor());
assertEquals("incorrect number of parameters", 2, constructor.getNumberOfParameters());
String[] parameterNames = constructor.getParameterNames();
assertEquals("incorrect numer of names", 2, parameterNames.length);
assertEquals("incorrect parameter names", "x1", parameterNames[0]);
assertEquals("incorrect parameter names", "x2", parameterNames[1]);
this.workingCopies[0] = getWorkingCopy("/RecordsElement/src/X.java", fileContent);
// Test code select
String str = this.workingCopies[0].getSource();
String selection = "x1";
int start = str.lastIndexOf(selection);
int length = selection.length();
IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
assertEquals("Incorret no of types", 1, elements.length);
IJavaElement element = elements[0];
assertEquals("type should be a record", IJavaElement.LOCAL_VARIABLE, element.getElementType());
element = element.getParent();
assertNotNull("should not be null", element);
// unlike constructors whose parameters are explicitly declared,
// in case of compact constructors, the element is attached as a child of
// the field that represents the record component.
assertEquals("should be a method", IJavaElement.FIELD, element.getElementType());
}
finally {
deleteProject("RecordsElement");
}
}
//Test record with canonical constructor
public void test006() throws Exception {
try {
this.workingCopies = new ICompilationUnit[1];
IJavaProject project = createJavaProject("RecordsElement");
project.open(null);
String fileContent = "public record Point(int x1, int x2) {\n" +
" public Point(int x1, int x2) {\n" +
" this.x1 = x1;\n" +
" this.x2 = x2;\n" +
" }\n" +
"}\n";
createFile( "/RecordsElement/src/X.java", fileContent);
ICompilationUnit unit = getCompilationUnit("/RecordsElement/src/X.java");
IType[] types = unit.getTypes();
assertEquals("Incorret no of types", 1, types.length);
assertTrue("type should be a record", types[0].isRecord());
assertEquals("type should be a record", IJavaElement.TYPE, types[0].getElementType());
IMethod[] methods = types[0].getMethods();
assertNotNull("should not be null", methods);
assertEquals("Incorret no of elements", 1, methods.length);
IMethod constructor = methods[0];
assertTrue("should be a constructor", constructor.isConstructor());
// assertTrue("should be a canonical constructor", constructor.isCanonicalConstructor());
assertEquals("incorrect number of parameters", 2, constructor.getNumberOfParameters());
String[] parameterNames = constructor.getParameterNames();
assertEquals("incorrect numer of names", 2, parameterNames.length);
assertEquals("incorrect parameter names", "x1", parameterNames[0]);
assertEquals("incorrect parameter names", "x2", parameterNames[1]);
this.workingCopies[0] = getWorkingCopy("/RecordsElement/src/X.java", fileContent);
// Test code select
String str = this.workingCopies[0].getSource();
String selection = "x1";
int start = str.lastIndexOf(selection);
int length = selection.length();
IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
assertEquals("Incorret no of types", 1, elements.length);
IJavaElement element = elements[0];
assertEquals("type should be a record", IJavaElement.LOCAL_VARIABLE, element.getElementType());
element = element.getParent();
assertNotNull("should not be null", element);
assertEquals("type should be a method", IJavaElement.METHOD, element.getElementType());
}
finally {
deleteProject("RecordsElement");
}
}
// Test things from a binary
public void test007() throws Exception {
try {
String[] sources = {
"p/Point.java",
"package p;\n;" +
"public record Point(int x1, int x2) {\n" +
" public Point(int x1, int x2) {\n" +
" this.x1 = x1;\n" +
" this.x2 = x2;\n" +
" }\n" +
" public Point(int x1, int x2, int x3) {\n" +
" this(x1, x2);\n" +
" }\n" +
" public Point(int x1, float f2) {\n" +
" this(0, 0);\n" +
" }\n" +
"}\n"
};
String outputDirectory = Util.getOutputDirectory();
String jarPath = outputDirectory + File.separator + "records.jar";
Util.createJar(sources, jarPath, "15", true);
IJavaProject project = createJavaProject("RecordsElement");
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("records.jar")) {
root = iRoot;
}
}
assertNotNull("root should not be null", root);
IPackageFragment packageFragment = root.getPackageFragment("p");
assertNotNull("package is null", packageFragment);
IOrdinaryClassFile classFile = packageFragment.getOrdinaryClassFile("Point.class");
assertNotNull("class is null", classFile);
IType type = classFile.getType();
assertNotNull("type is null", type);
assertTrue("should be a record", type.isRecord());
assertEquals("type should be a record", IJavaElement.TYPE, type.getElementType());
IField[] fields = type.getFields();
assertEquals("Incorret no of fields", 0, fields.length);
IMethod[] methods = type.getMethods();
assertNotNull("should not be null", methods);
assertEquals("Incorret no of elements", 8, methods.length); // Point(), Point(), x1(), x2(), toString(), hashCode(), equals()
IMethod constructor = methods[0];
assertTrue("should be a constructor", constructor.isConstructor());
// assertTrue("should be a canonical constructor", constructor.isCanonicalConstructor());
assertEquals("incorrect number of parameters", 2, constructor.getNumberOfParameters());
String[] parameterNames = constructor.getParameterNames();
assertEquals("incorrect numer of names", 2, parameterNames.length);
assertEquals("incorrect parameter names", "x1", parameterNames[0]);
assertEquals("incorrect parameter names", "x2", parameterNames[1]);
constructor = methods[1];
assertTrue("should be a constructor", constructor.isConstructor());
// assertFalse("should not be a canonical constructor", constructor.isCanonicalConstructor());
assertEquals("incorrect number of parameters", 3, constructor.getNumberOfParameters());
constructor = methods[2];
assertTrue("should be a constructor", constructor.isConstructor());
// assertFalse("should not be a canonical constructor", constructor.isCanonicalConstructor());
assertEquals("incorrect number of parameters", 2, constructor.getNumberOfParameters());
}
finally {
deleteProject("RecordsElement");
}
}
// Test things from a binary
public void test008() throws Exception {
try {
String[] sources = {
"p/Point.java",
"package p;\n;" +
"public record Point(int x1, int x2) {\n" +
" public Point {\n" +
" x1 = 1;\n" +
" x2 = 2;\n" +
" }\n" +
"}\n"
};
String outputDirectory = Util.getOutputDirectory();
String jarPath = outputDirectory + File.separator + "records.jar";
Util.createJar(sources, jarPath, "15", true);
IJavaProject project = createJavaProject("RecordsElement");
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("records.jar")) {
root = iRoot;
}
}
assertNotNull("root should not be null", root);
IPackageFragment packageFragment = root.getPackageFragment("p");
assertNotNull("package is null", packageFragment);
IOrdinaryClassFile classFile = packageFragment.getOrdinaryClassFile("Point.class");
assertNotNull("class is null", classFile);
IType type = classFile.getType();
assertNotNull("type is null", type);
assertTrue("should be a record", type.isRecord());
assertEquals("type should be a record", IJavaElement.TYPE, type.getElementType());
IMethod[] methods = type.getMethods();
assertNotNull("should not be null", methods);
assertEquals("Incorret no of elements", 6, methods.length);
IMethod constructor = methods[0];
assertTrue("should be a constructor", constructor.isConstructor());
// assertTrue("should be a canonical constructor", constructor.isCanonicalConstructor());
assertEquals("incorrect number of parameters", 2, constructor.getNumberOfParameters());
String[] parameterNames = constructor.getParameterNames();
assertEquals("incorrect numer of names", 2, parameterNames.length);
assertEquals("incorrect parameter names", "x1", parameterNames[0]);
assertEquals("incorrect parameter names", "x2", parameterNames[1]);
}
finally {
deleteProject("RecordsElement");
}
}
}