/******************************************************************************* * Copyright (c) 2000, 2018 IBM Corporation and others. * * 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.util.*; import junit.framework.Test; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.*; import org.eclipse.jdt.core.*; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; @SuppressWarnings({"rawtypes", "unchecked"}) public class JavaConventionTests extends AbstractJavaModelTests { public JavaConventionTests(String name) { super(name); } static { // TESTS_PREFIX = "testInvalidCompilerOptions"; // TESTS_NAMES = new String[] { "testValidCompilerOptions", "testInvalidCompilerOptions" }; } public static Test suite() { return buildModelTestSuite(JavaConventionTests.class); } /* * Verify status type and messages. */ protected void verifyStatus(IStatus status, String[] expectedMessages) { int length = expectedMessages.length; IStatus[] allStatus = status.getChildren(); switch (length) { case 0: assertTrue("Status should be OK!", status.isOK()); return; case 1: assertFalse("Unexpected type of status!", status.isMultiStatus()); assertEquals("Unexpected number of errors!", length, 1); allStatus = new IStatus[] { status }; break; default: assertTrue("Unexpected type of status!", status.isMultiStatus()); assertEquals("Unexpected number of errors!", length, allStatus.length); break; } List failuresMessages = new ArrayList(); for (int i=0; i 0) { System.out.println("Test "+getName()+" fails. Add this declaration to fix it:"); System.out.println(" String[] expectedMessages = {"); for (int i=0; i1?"are ":"is ")+count+" unexpected status!", count==0); } // Kind of validations static final int COMPILATION_UNIT_NAME = 1; static final int CLASS_FILE_NAME = 2; static final int FIELD_NAME = 3; static final int IDENTIFIER = 4; static final int IMPORT_DECLARATION = 5; static final int JAVA_TYPE_NAME = 6; static final int METHOD_NAME = 7; static final int PACKAGE_NAME = 8; static final int TYPE_VARIABLE_NAME = 9; // All possible compiler versions static final String[] VERSIONS = new String[] { CompilerOptions.VERSION_1_1, CompilerOptions.VERSION_1_2, CompilerOptions.VERSION_1_3, CompilerOptions.VERSION_1_4, CompilerOptions.VERSION_1_5, CompilerOptions.VERSION_1_6, CompilerOptions.VERSION_1_7, CompilerOptions.VERSION_1_8, CompilerOptions.VERSION_9, CompilerOptions.VERSION_10, CompilerOptions.VERSION_11, }; /* * Return the status for a string regarding a given kind of validation. * Use JavaConventions default source and compliance levels. */ int validate(String string, int kind) { return validate(string, kind, CompilerOptions.VERSION_1_3, CompilerOptions.VERSION_1_3); } /* * Return the status for a string regarding a given kind of validation. */ int validate(String string, int kind, String sourceLevel, String complianceLevel) { switch (kind) { case COMPILATION_UNIT_NAME: return JavaConventions.validateCompilationUnitName(string, sourceLevel, complianceLevel).getSeverity(); case CLASS_FILE_NAME: return JavaConventions.validateClassFileName(string, sourceLevel, complianceLevel).getSeverity(); case FIELD_NAME: return JavaConventions.validateFieldName(string, sourceLevel, complianceLevel).getSeverity(); case IDENTIFIER: return JavaConventions.validateIdentifier(string, sourceLevel, complianceLevel).getSeverity(); case IMPORT_DECLARATION: return JavaConventions.validateImportDeclaration(string, sourceLevel, complianceLevel).getSeverity(); case JAVA_TYPE_NAME: return JavaConventions.validateJavaTypeName(string, sourceLevel, complianceLevel).getSeverity(); case METHOD_NAME: return JavaConventions.validateMethodName(string, sourceLevel, complianceLevel).getSeverity(); case PACKAGE_NAME: return JavaConventions.validatePackageName(string, sourceLevel, complianceLevel).getSeverity(); case TYPE_VARIABLE_NAME: return JavaConventions.validateTypeVariableName(string, sourceLevel, complianceLevel).getSeverity(); } return -1; } void validateModuleName(String name, String sourceLevel, String complianceLevel, int sev, String message) { IStatus s = JavaConventions.validateModuleName(name, sourceLevel, complianceLevel); assertEquals("incorrect status", sev, s.getSeverity()); assertEquals("incorrect status message", message, s.getMessage()); } /** * @see JavaConventions */ public void testInvalidIdentifier() { String[] invalidIds = new String[] {" s\\u0069ze", " s\\u0069ze ", "", "1java", "Foo Bar", "#@$!", "Foo-Bar", "if", "InvalidEscapeSequence\\g", "true", "false", "null", null, " untrimmmed "}; for (int i = 0; i < invalidIds.length; i++) { assertEquals("identifier not recognized as invalid: " + invalidIds[i], IStatus.ERROR, validate(invalidIds[i], IDENTIFIER)); } } /** * @see JavaConventions */ public void testInvalidImportDeclaration1() { assertEquals("import not reconized as invalid; java.math.", IStatus.ERROR, validate("java.math.", IMPORT_DECLARATION)); } /** * @see JavaConventions */ public void testInvalidImportDeclaration2() { assertEquals("import not reconized as invalid; java.math*", IStatus.ERROR, validate("java.math*", IMPORT_DECLARATION)); } /** * @see JavaConventions */ public void testInvalidImportDeclaration3() { assertEquals("import not reconized as invalid; empty string", IStatus.ERROR, validate("", IMPORT_DECLARATION)); } /** * Test for package fragment root overlap * @deprecated isOverlappingRoots is deprecated */ public void testPackageFragmentRootOverlap() throws Exception { try { IJavaProject project = this.createJavaProject("P1", new String[] {"src"}, new String[] {"/P1/jclMin.jar"}, "bin"); // ensure the external JCL is copied setupExternalJCL("jclMin"); copy(new java.io.File(getExternalJCLPathString()), new java.io.File(getWorkspaceRoot().getLocation().toOSString() + java.io.File.separator + "P1" + java.io.File.separator + "jclMin.jar")); project.getProject().refreshLocal(IResource.DEPTH_INFINITE, null); IPackageFragmentRoot p1Zip= getPackageFragmentRoot("P1", "jclMin.jar"); IPackageFragmentRoot p1Src= getPackageFragmentRoot("P1", "src"); assertTrue("zip should not overlap source root", !JavaConventions.isOverlappingRoots(p1Zip.getUnderlyingResource().getFullPath(), p1Src.getUnderlyingResource().getFullPath())); this.createJavaProject("P2", new String[] {"src"}, "bin"); IPackageFragmentRoot p2Src= getPackageFragmentRoot("P2", "src"); assertTrue("source roots in different projects should not overlap ", !JavaConventions.isOverlappingRoots(p1Src.getUnderlyingResource().getFullPath(), p2Src.getUnderlyingResource().getFullPath())); assertTrue("The same root should overlap", JavaConventions.isOverlappingRoots(p2Src.getUnderlyingResource().getFullPath(), p2Src.getUnderlyingResource().getFullPath())); assertTrue("isOverLappingRoot does not handle null arguments", !JavaConventions.isOverlappingRoots(p2Src.getUnderlyingResource().getFullPath(), null)); assertTrue("isOverLappingRoot does not handle null arguments", !JavaConventions.isOverlappingRoots(null, null)); } finally { this.deleteProject("P1"); this.deleteProject("P2"); } } /** * @see JavaConventions */ public void testValidCompilationUnitName() { String[] invalidNames = new String[] {"java/lang/Object.java", "Object.class", ".java", "Object.javaaa", "A.B.java"}; for (int i = 0; i < invalidNames.length; i++) { assertEquals("compilation unit name not recognized as invalid: " + invalidNames[i], IStatus.ERROR, validate(invalidNames[i], COMPILATION_UNIT_NAME)); } invalidNames = new String[] {"module-package.class"}; for (int i = 0; i < invalidNames.length; i++) { assertEquals("compilation unit name not recognized as valid: " + invalidNames[i], IStatus.ERROR, validate(invalidNames[i], CLASS_FILE_NAME)); } String[] validNames = new String[] {"Object.java", "OBJECT.java", "object.java", "package-info.java", "module-info.java"}; for (int i = 0; i < validNames.length; i++) { assertEquals("compilation unit name not recognized as valid: " + validNames[i], IStatus.OK, validate(validNames[i], COMPILATION_UNIT_NAME)); } validNames = new String[] {"module-info.class"}; for (int i = 0; i < validNames.length; i++) { assertEquals("compilation unit name not recognized as valid: " + validNames[i], IStatus.OK, validate(validNames[i], CLASS_FILE_NAME)); } } /** * @see JavaConventions */ public void testValidFieldName() { assertEquals("unicode field name not handled", IStatus.OK, validate("s\\u0069ze", FIELD_NAME)); } /** * @see JavaConventions */ public void testValidIdentifier() { String[] validIds = new String[] {"s\\u0069ze", "Object", "An_Extremly_Long_Class_Name_With_Words_Separated_By_Undescores"}; for (int i = 0; i < validIds.length; i++) { assertEquals("identifier not recognized as valid: " + validIds[i], IStatus.OK, validate(validIds[i], IDENTIFIER)); } } /** * @see JavaConventions */ public void testValidImportDeclaration() { assertEquals("import not reconized as valid", IStatus.OK, validate("java.math.*", IMPORT_DECLARATION)); } /** * @see JavaConventions */ public void testValidMethodName() { assertEquals("unicode method name not handled", IStatus.OK, validate("getSiz\\u0065", METHOD_NAME)); } /** * @see JavaConventions */ public void testValidPackageName() { String pkgName= "org.eclipse.jdt.core.t\\u0065sts.MyPackage"; assertEquals("unicode package name not handled", IStatus.OK, validate(pkgName, PACKAGE_NAME)); assertEquals("package name not recognized as invalid1", IStatus.ERROR, validate("", PACKAGE_NAME)); assertEquals("package name not recognized as valid1", IStatus.OK, validate("java . lang", PACKAGE_NAME)); assertEquals("package name not recognized as invalid2", IStatus.ERROR, validate(" java . lang", PACKAGE_NAME)); assertEquals("package name not recognized as invalid3", IStatus.ERROR, validate("java . lang ", PACKAGE_NAME)); assertEquals("package name not recognized as invalid4", IStatus.ERROR, validate(null, PACKAGE_NAME)); assertEquals("package name not recognized as unconventional1", IStatus.WARNING, validate("Java.lang", PACKAGE_NAME)); assertEquals("package name not recognized as valid2", IStatus.OK, validate("java.Lang", PACKAGE_NAME)); assertEquals("package name not recognized as invalid5", IStatus.ERROR, validate("Test.sample&plugin", PACKAGE_NAME)); assertEquals("package name not recognized as unconventional2", IStatus.WARNING, validate("Test.sample", PACKAGE_NAME)); assertEquals("package name not recognized as valid2", IStatus.OK, validate("com. sap", PACKAGE_NAME)); assertEquals("package name not recognized as invalid6", IStatus.ERROR, validate("co m.sap", PACKAGE_NAME)); assertEquals("package name not recognized as valid2", IStatus.OK, validate("elnu", PACKAGE_NAME)); } /** * @see JavaConventions */ public void testValidTypeName() { // regression tests for 1G5HVPB: ITPJCORE:WINNT - validateJavaTypeName accepts type names ending with \ assertEquals("type name should not contain slashes (1)", IStatus.ERROR, validate("Object\\", JAVA_TYPE_NAME)); assertEquals("type name should not contain slashes (2)", IStatus.ERROR, validate("Object/", JAVA_TYPE_NAME)); assertEquals("type name should not contain slashes (3)", IStatus.ERROR, validate("\\Object", JAVA_TYPE_NAME)); assertEquals("type name should not contain slashes (4)", IStatus.ERROR, validate("java\\lang\\Object", JAVA_TYPE_NAME)); // regression test for 1G52ZIF: ITPJUI:WINNT - Wizards should strongly discourage the use of non-standard names assertEquals("discouraged type names not handled", IStatus.WARNING, validate("alowercasetypename", JAVA_TYPE_NAME)); // other tests assertEquals("unicode type name not handled", IStatus.OK, validate("P\\u0065a", JAVA_TYPE_NAME)); assertEquals("qualified type names not handled", IStatus.OK, validate("java . lang\t.Object", JAVA_TYPE_NAME)); assertEquals("simple qualified type names not handled", IStatus.OK, validate("java.lang.Object", JAVA_TYPE_NAME)); assertEquals("simple type names not handled", IStatus.OK, validate("Object", JAVA_TYPE_NAME)); assertEquals("discouraged type names not handled", IStatus.WARNING, validate("Object$SubType", JAVA_TYPE_NAME)); assertEquals("invalid type name not recognized", IStatus.ERROR, validate("==?==", JAVA_TYPE_NAME)); } /** * @see JavaConventions */ public void testValidTypeVariableName() { assertEquals("E sould be a valid variable name", IStatus.OK, validate("E", TYPE_VARIABLE_NAME)); } /** * @see JavaConventions */ public void testValidUnicodeImportDeclaration() { String pkgName= "com.\\u0069bm.jdt.core.tests.MyPackag\\u0065"; assertEquals("import not reconized as valid", IStatus.OK, validate(pkgName, IMPORT_DECLARATION)); } /** * @see JavaConventions */ public void testValidUnicodePackageName() { String pkgName= "com.\\u0069bm.jdt.core.tests.MyPackag\\u0065"; assertEquals("unicode package name not handled", IStatus.OK, validate(pkgName, PACKAGE_NAME)); assertEquals("Parameter modified", "com.\\u0069bm.jdt.core.tests.MyPackag\\u0065", pkgName); } /** * Test fix for bug 79392: [prefs] JavaConventions should offer compiler options validation API * @see 79392 * TODO (frederic) activate all following tests when bug 79392 will be finalized */ /* public void testInvalidCompilerOptions01() throws CoreException, BackingStoreException { // Set options Map options = JavaCore.getOptions(); options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_5); options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_5); options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_4); // Validate options String[] expectedMessages = { "Target level '1.4' is incompatible with source level '1.5'. A target level '1.5' or better is required" }; verifyStatus(JavaConventions.validateCompilerOptions(options), expectedMessages); } public void testInvalidCompilerOptions02() throws CoreException, BackingStoreException { Map options = JavaCore.getOptions(); options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_5); // Validate options String[] expectedMessages = { "Target level '1.2' is incompatible with source level '1.5'. A target level '1.5' or better is required", "Compliance level '1.4' is incompatible with source level '1.5'. A compliance level '1.5' or better is required" }; verifyStatus(JavaConventions.validateCompilerOptions(options), expectedMessages); } public void testInvalidCompilerOptions04() throws CoreException, BackingStoreException { // Set options Map options = JavaCore.getOptions(); options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_3); options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_4); options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_5); // Validate options String[] expectedMessages = { "Compliance level '1.3' is incompatible with target level '1.4'. A compliance level '1.4' or better is required", "Compliance level '1.3' is incompatible with source level '1.4'. A compliance level '1.4' or better is required" }; verifyStatus(JavaConventions.validateCompilerOptions(options), expectedMessages); } public void testValidCompilerOptions01() throws CoreException, BackingStoreException { // Set options Map options = JavaCore.getOptions(); options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_5); options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_4); options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_4); // Validate options String[] expectedMessages = {}; verifyStatus(JavaConventions.validateCompilerOptions(options), expectedMessages); } public void testValidCompilerOptions02() throws CoreException, BackingStoreException { // Set options Map options = JavaCore.getOptions(); options.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_4); options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_3); options.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_4); // Validate options String[] expectedMessages = {}; verifyStatus(JavaConventions.validateCompilerOptions(options), expectedMessages); } */ /** * @bug 161621: enum is a Keyword for Java5 and cannot be used as a Enum name * @test Ensure that 'assert' identifier is rejected when source level greater than 1.3 * and that 'enum' identifier is rejected when source level greater than 1.4 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=161621" */ public void testAssertIdentifier() { int length = VERSIONS.length; for (int i=0; i= 8 && j >= 8) { // source and compliance level > VERSION_9 validateModuleName(null, VERSIONS[i], VERSIONS[j], IStatus.ERROR, "A module name must not be null"); validateModuleName("mod.one", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); validateModuleName("mod_one", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); validateModuleName("one.java", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); validateModuleName("m0d.one", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); validateModuleName("1mod1. one", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "'1mod1' is not a valid Java identifier"); validateModuleName("mod1.2one", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "'2one' is not a valid Java identifier"); validateModuleName("mod..one", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "A module name must not contain consecutive dots"); validateModuleName(".mod.one", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "A module name cannot start or end with a dot"); validateModuleName("mod.one.", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "A module name cannot start or end with a dot"); validateModuleName(".mod.one.", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "A module name cannot start or end with a dot"); validateModuleName("mod.one ", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "A module name must not start or end with a blank"); validateModuleName(" mod.one", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "A module name must not start or end with a blank"); validateModuleName("java one", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "'java one' is not a valid Java identifier"); validateModuleName("mod,one", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "'mod,one' is not a valid Java identifier"); validateModuleName("mod1.one", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); validateModuleName("mod.one1.two", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); validateModuleName("java.one", VERSIONS[i], VERSIONS[j], IStatus.WARNING, "java is reserved for system modules"); validateModuleName("mod. one", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); // Now try using keywords validateModuleName("module.requires", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); validateModuleName("exports.to", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); validateModuleName("provides.with", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); validateModuleName("opens.uses", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); validateModuleName("transitive.open", VERSIONS[i], VERSIONS[j], IStatus.OK, "OK"); validateModuleName("static.requires", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "'static' is not a valid Java identifier"); validateModuleName("class.interface.method", VERSIONS[i], VERSIONS[j], IStatus.ERROR, "'class' is not a valid Java identifier"); } } } } }