/******************************************************************************* | |
* Copyright (c) 2020, 2021 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.dom; | |
import java.io.File; | |
import java.io.IOException; | |
import java.lang.reflect.Method; | |
import java.text.NumberFormat; | |
import java.util.ArrayList; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Map; | |
import junit.framework.Test; | |
import junit.framework.TestSuite; | |
import org.eclipse.jdt.core.ICompilationUnit; | |
import org.eclipse.jdt.core.IJavaProject; | |
import org.eclipse.jdt.core.JavaCore; | |
import org.eclipse.jdt.core.JavaModelException; | |
import org.eclipse.jdt.core.compiler.IProblem; | |
import org.eclipse.jdt.core.dom.AST; | |
import org.eclipse.jdt.core.dom.ASTNode; | |
import org.eclipse.jdt.core.dom.ASTParser; | |
import org.eclipse.jdt.core.dom.ArrayType; | |
import org.eclipse.jdt.core.dom.Comment; | |
import org.eclipse.jdt.core.dom.CompilationUnit; | |
import org.eclipse.jdt.core.dom.IBinding; | |
import org.eclipse.jdt.core.dom.Javadoc; | |
import org.eclipse.jdt.core.dom.MemberRef; | |
import org.eclipse.jdt.core.dom.MethodDeclaration; | |
import org.eclipse.jdt.core.dom.MethodRef; | |
import org.eclipse.jdt.core.dom.MethodRefParameter; | |
import org.eclipse.jdt.core.dom.ModuleQualifiedName; | |
import org.eclipse.jdt.core.dom.Name; | |
import org.eclipse.jdt.core.dom.QualifiedName; | |
import org.eclipse.jdt.core.dom.SimpleName; | |
import org.eclipse.jdt.core.dom.SimpleType; | |
import org.eclipse.jdt.core.dom.TagElement; | |
import org.eclipse.jdt.core.dom.TextElement; | |
import org.eclipse.jdt.core.dom.Type; | |
import org.eclipse.jdt.core.dom.IModuleBinding; | |
import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; | |
/** | |
* Class to test DOM/AST nodes built for Javadoc comments. | |
* | |
* Most of tests are 'automatic'. It means that to add a new tests, you only need to | |
* create one or several CUs and put them in org.eclipse.jdt.core.model.tests/workspace/Converter/src/javadoc/testXXX | |
* folder and add the corresponding test in this class: | |
* <pre> | |
* public void testXXX() throws JavaModelException { | |
* verifyComments("testXXX"); | |
* } | |
* </pre> | |
* | |
* Note that when a test fails, the easiest way to debug it is to open | |
* a runtime workbench, create a project 'Converter', delete the default 'src' source folder | |
* and replace it by a linked source to the 'src' folder of org.eclipse.jdt.core.model.tests/workspace/Converter/src | |
* in your workspace. | |
* | |
* Then open the CU on which the test fails in a ASTView and verify the offset/length | |
* of the offending node located at the positions displayed in the console when the test failed... | |
* | |
* Since 3.4, the failing test also provides the comparison between the source of the comment | |
* and the string get from the built DOM/AST nodes in the comment (see {@link ASTConverterJavadocFlattener}) | |
* but this may be not enough to see precisely the origin of the problem. | |
*/ | |
@SuppressWarnings({"rawtypes", "unchecked"}) | |
public class ASTConverterJavadocTest_15 extends ConverterTestSetup { | |
// Flag to know whether Converter directory should be copied from org.eclipse.jdt.core.tests.model project | |
static protected boolean COPY_DIR = true; | |
// Test counters | |
protected static int[] TEST_COUNTERS = { 0, 0, 0, 0 }; | |
// Unicode tests | |
protected static boolean UNICODE = false; | |
// Unix tests | |
final boolean unix; | |
static final String UNIX_SUPPORT = System.getProperty("unix"); | |
// Doc Comment support | |
static final String DOC_COMMENT_SUPPORT = System.getProperty("doc.support"); | |
final String docCommentSupport; | |
// List of comments read from source of test | |
private static final int LINE_COMMENT = 100; | |
private static final int BLOCK_COMMENT =200; | |
private static final int DOC_COMMENT = 300; | |
List comments = new ArrayList(); | |
private String chars; | |
// List of tags contained in each comment read from test source. | |
List allTags = new ArrayList(); | |
// tags inhibiting inline tags | |
static final String TAG_CODE = "code"; | |
static final String TAG_LITERAL = "literal"; | |
// Current compilation unit | |
protected ICompilationUnit sourceUnit; | |
// Test package binding | |
protected boolean resolveBinding = true; | |
protected boolean packageBinding = true; | |
// AST Level | |
protected int astLevel = AST.getJLSLatest(); | |
protected int savedLevel; | |
// Debug | |
protected String prefix = ""; | |
protected boolean debug = false; | |
protected StringBuffer problems; | |
protected String compilerOption = JavaCore.IGNORE; | |
protected List failures; | |
protected boolean stopOnFailure = true; | |
Map savedOptions = null; | |
protected ICompilationUnit moduleUnit; | |
/** | |
* @param name | |
* @param support | |
*/ | |
public ASTConverterJavadocTest_15(String name, String support, String unix) { | |
super(name); | |
this.docCommentSupport = support; | |
this.unix = "true".equals(unix); | |
} | |
/** | |
* @param name | |
*/ | |
public ASTConverterJavadocTest_15(String name) { | |
this(name.substring(0, name.indexOf(" - ")), | |
name.substring(name.indexOf(" - Doc ") + 7, name.lastIndexOf("abled") + 5), | |
name.indexOf(" - Unix") != -1 ? "true" : "false"); | |
} | |
/* (non-Javadoc) | |
* @see junit.framework.TestCase#getName() | |
*/ | |
public String getName() { | |
String strUnix = this.unix ? " - Unix" : ""; | |
return super.getName()+" - Doc "+this.docCommentSupport+strUnix; | |
} | |
public static Test suite() { | |
TestSuite suite = new Suite(ASTConverterJavadocTest_15.class.getName()); | |
// String param = System.getProperty("unicode"); | |
// if ("true".equals(param)) { | |
// unicode = true; | |
// } | |
// String param = System.getProperty("unix"); | |
// if ("true".equals(param)) { | |
// unix = true; | |
// } | |
if (DOC_COMMENT_SUPPORT == null) { | |
buildSuite(suite, JavaCore.ENABLED); | |
buildSuite(suite, JavaCore.DISABLED); | |
} else { | |
String support = DOC_COMMENT_SUPPORT==null ? JavaCore.DISABLED : (DOC_COMMENT_SUPPORT.equals(JavaCore.DISABLED)?JavaCore.DISABLED:JavaCore.ENABLED); | |
buildSuite(suite, support); | |
} | |
return suite; | |
// Run test cases subset | |
// COPY_DIR = false; | |
// System.err.println("WARNING: only subset of tests will be executed!!!"); | |
// suite.addTest(new ASTConverterJavadocTest("testBug165525")); | |
// return suite; | |
} | |
public static void buildSuite(TestSuite suite, String support) { | |
Class c = ASTConverterJavadocTest_15.class; | |
Method[] methods = c.getMethods(); | |
for (int i = 0, max = methods.length; i < max; i++) { | |
if (methods[i].getName().startsWith("test")) { //$NON-NLS-1$ | |
suite.addTest(new ASTConverterJavadocTest_15(methods[i].getName(), support, UNIX_SUPPORT)); | |
} | |
} | |
// when unix support not specified, also run using unix format | |
if (UNIX_SUPPORT == null && JavaCore.ENABLED.equals(support)) { | |
for (int i = 0, max = methods.length; i < max; i++) { | |
if (methods[i].getName().startsWith("test")) { //$NON-NLS-1$ | |
suite.addTest(new ASTConverterJavadocTest_15(methods[i].getName(), support, "true")); | |
} | |
} | |
} | |
} | |
/* (non-Javadoc) | |
* @see org.eclipse.jdt.core.tests.model.AbstractJavaModelTests#copyDirectory(java.io.File, java.io.File) | |
*/ | |
@Override | |
protected void copyDirectory(File sourceDir, File targetDir) throws IOException { | |
if (COPY_DIR) { | |
super.copyDirectory(sourceDir, targetDir); | |
} else { | |
targetDir.mkdirs(); | |
File sourceFile = new File(sourceDir, ".project"); | |
File targetFile = new File(targetDir, ".project"); | |
targetFile.createNewFile(); | |
copy(sourceFile, targetFile); | |
sourceFile = new File(sourceDir, ".classpath"); | |
targetFile = new File(targetDir, ".classpath"); | |
targetFile.createNewFile(); | |
copy(sourceFile, targetFile); | |
} | |
} | |
/* (non-Javadoc) | |
* @see junit.framework.TestCase#setUp() | |
*/ | |
@Override | |
protected void setUp() throws Exception { | |
super.setUp(); | |
TEST_COUNTERS[0]++; | |
this.failures = new ArrayList(); | |
this.problems = new StringBuffer(); | |
this.workingCopies = null; | |
this.savedLevel = this.astLevel; | |
} | |
/* (non-Javadoc) | |
* @see junit.framework.TestCase#tearDown() | |
*/ | |
@Override | |
protected void tearDown() throws Exception { | |
int size = this.failures.size(); | |
String title = size+" positions/bindings were incorrect in "+getName(); | |
if (size == 0) { | |
TEST_COUNTERS[1]++; | |
} else if (this.problems.length() > 0) { | |
if (this.debug) { | |
System.out.println("Compilation warnings/errors occured:"); | |
System.out.println(this.problems.toString()); | |
} | |
TEST_COUNTERS[2]++; | |
} else { | |
TEST_COUNTERS[3]++; | |
System.out.println(title+":"); | |
for (int i=0; i<size; i++) { | |
System.out.println(" - "+this.failures.get(i)); | |
} | |
} | |
// if (!stopOnFailure) { | |
assertTrue(title, size==0 || this.problems.length() > 0); | |
// } | |
super.tearDown(); | |
// Restore saved ast level | |
this.astLevel = this.savedLevel; | |
} | |
/* (non-Javadoc) | |
* @see junit.framework.TestCase#tearDown() | |
*/ | |
@Override | |
public void tearDownSuite() throws Exception { | |
// put default options on project | |
if (this.currentProject != null && this.savedOptions != null) { | |
this.currentProject.setOptions(this.savedOptions); | |
} | |
super.tearDownSuite(); | |
if (TEST_COUNTERS[0] != TEST_COUNTERS[1]) { | |
NumberFormat intFormat = NumberFormat.getInstance(); | |
intFormat.setMinimumIntegerDigits(3); | |
intFormat.setMaximumIntegerDigits(3); | |
System.out.println("====================================="); | |
System.out.println(intFormat.format(TEST_COUNTERS[0])+" tests have been executed:"); | |
System.out.println(" - "+intFormat.format(TEST_COUNTERS[1])+" tests have been actually executed."); | |
System.out.println(" - "+intFormat.format(TEST_COUNTERS[2])+" tests were skipped due to compilation errors."); | |
System.out.println(" - "+intFormat.format(TEST_COUNTERS[3])+" tests failed."); | |
} | |
} | |
@Override | |
public ASTNode runConversion(char[] source, String unitName, IJavaProject project) { | |
ASTParser parser = ASTParser.newParser(this.astLevel); | |
parser.setSource(source); | |
parser.setUnitName(unitName); | |
parser.setProject(project); | |
parser.setResolveBindings(this.resolveBinding); | |
return parser.createAST(null); | |
} | |
@Override | |
public ASTNode runConversion(char[] source, String unitName, IJavaProject project, Map options) { | |
if (project == null) { | |
ASTParser parser = ASTParser.newParser(this.astLevel); | |
parser.setSource(source); | |
parser.setUnitName(unitName); | |
parser.setCompilerOptions(options); | |
parser.setResolveBindings(this.resolveBinding); | |
return parser.createAST(null); | |
} | |
return runConversion(source, unitName, project); | |
} | |
private char getNextChar(char[] source, int idx) { | |
// get next char | |
char ch = source[idx]; | |
int charLength = 1; | |
int pos = idx; | |
this.chars = null; | |
if (ch == '\\' && source[idx+1] == 'u') { | |
//-------------unicode traitement ------------ | |
int c1, c2, c3, c4; | |
charLength++; | |
while (source[idx+charLength] == 'u') charLength++; | |
if (((c1 = ScannerHelper.getHexadecimalValue(source[idx+charLength++])) > 15 || c1 < 0) | |
|| ((c2 = ScannerHelper.getHexadecimalValue(source[idx+charLength++])) > 15 || c2 < 0) | |
|| ((c3 = ScannerHelper.getHexadecimalValue(source[idx+charLength++])) > 15 || c3 < 0) | |
|| ((c4 = ScannerHelper.getHexadecimalValue(source[idx+charLength++])) > 15 || c4 < 0)) { | |
return ch; | |
} | |
ch = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); | |
this.chars = new String(source, pos, charLength); | |
} | |
return ch; | |
} | |
/* | |
* Convert Javadoc source to match Javadoc.toString(). | |
* Store converted comments and their corresponding tags respectively | |
* in comments and allTags fields | |
*/ | |
protected void setSourceComment(char[] source) throws ArrayIndexOutOfBoundsException { | |
this.comments = new ArrayList(); | |
this.allTags = new ArrayList(); | |
StringBuffer buffer = null; | |
int comment = 0; | |
boolean end = false, lineStarted = false; | |
String tag = null; | |
List tags = new ArrayList(); | |
int length = source.length; | |
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345 | |
// when parsing tags such as @code and @literal, | |
// any tag should be discarded and considered as plain text until | |
// properly closed with closing brace | |
boolean considerTagAsPlainText = false; | |
int openingBraces = 0; | |
char previousChar=0, currentChar=0; | |
for (int i=0; i<length;) { | |
previousChar = currentChar; | |
// get next char | |
currentChar = getNextChar(source, i); | |
i += (this.chars==null) ? 1 : this.chars.length(); | |
switch (comment) { | |
case 0: | |
switch (currentChar) { | |
case '/': | |
comment = 1; // first char for comments... | |
buffer = new StringBuffer(); | |
if (this.chars == null) buffer.append(currentChar); | |
else buffer.append(this.chars); | |
break; | |
case '\'': | |
while (i<length) { | |
// get next char | |
currentChar = getNextChar(source, i); | |
i += (this.chars==null) ? 1 : this.chars.length(); | |
if (currentChar == '\\') { | |
// get next char | |
currentChar = getNextChar(source, i); | |
i += (this.chars==null) ? 1 : this.chars.length(); | |
} else { | |
if (currentChar == '\'') { | |
break; | |
} | |
} | |
} | |
break; | |
case '"': | |
while (i<length) { | |
// get next char | |
currentChar = getNextChar(source, i); | |
i += (this.chars==null) ? 1 : this.chars.length(); | |
if (currentChar == '\\') { | |
// get next char | |
currentChar = getNextChar(source, i); | |
i += (this.chars==null) ? 1 : this.chars.length(); | |
} else { | |
if (currentChar == '"') { | |
// get next char | |
currentChar = getNextChar(source, i); | |
if (currentChar == '"') { | |
i += (this.chars==null) ? 1 : this.chars.length(); | |
} else { | |
break; | |
} | |
} | |
} | |
} | |
break; | |
} | |
break; | |
case 1: // first '/' has been found... | |
switch (currentChar) { | |
case '/': | |
if (this.chars == null) buffer.append(currentChar); | |
else buffer.append(this.chars); | |
comment = LINE_COMMENT; | |
break; | |
case '*': | |
if (this.chars == null) buffer.append(currentChar); | |
else buffer.append(this.chars); | |
comment = 2; // next step | |
break; | |
default: | |
comment = 0; | |
break; | |
} | |
break; | |
case 2: // '/*' has been found... | |
if (currentChar == '*') { | |
comment = 3; // next step... | |
} else { | |
comment = BLOCK_COMMENT; | |
} | |
if (this.chars == null) buffer.append(currentChar); | |
else buffer.append(this.chars); | |
break; | |
case 3: // '/**' has bee found, verify that's not an empty block comment | |
if (currentChar == '/') { // empty block comment | |
if (this.chars == null) buffer.append(currentChar); | |
else buffer.append(this.chars); | |
this.comments.add(buffer.toString()); | |
this.allTags.add(new ArrayList()); | |
comment = 0; | |
break; | |
} | |
comment = DOC_COMMENT; | |
// $FALL-THROUGH$ - do not break, directly go to next case... | |
case DOC_COMMENT: | |
if (tag != null) { // a tag name is currently scanned | |
if (currentChar >= 'a' && currentChar <= 'z') { | |
tag += currentChar; | |
} else { | |
if (tag.equalsIgnoreCase(TAG_LITERAL) || tag.equalsIgnoreCase(TAG_CODE)) considerTagAsPlainText = true; | |
tags.add(tag); | |
tag = null; | |
} | |
} | |
// Some characters are special in javadoc comments | |
switch (currentChar) { | |
case '@': | |
if (!lineStarted) { | |
tag = ""; | |
lineStarted = true; | |
} else if (previousChar == '{') { | |
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345 | |
if (considerTagAsPlainText) { | |
openingBraces++; | |
} else { | |
tag = ""; | |
lineStarted = true; | |
} | |
} | |
break; | |
case '\r': | |
case '\n': | |
lineStarted = false; | |
break; | |
case '*': | |
break; | |
case '}': | |
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345 | |
if (considerTagAsPlainText) { | |
if (openingBraces > 0) { | |
openingBraces--; | |
} else { | |
considerTagAsPlainText = false; | |
} | |
} | |
break; | |
default: | |
if (!Character.isWhitespace(currentChar)) { | |
lineStarted = true; | |
} | |
} | |
// $FALL-THROUGH$ - common treatment for block and javadoc comments | |
case BLOCK_COMMENT: | |
if (this.chars == null) buffer.append(currentChar); | |
else buffer.append(this.chars); | |
if (end && currentChar == '/') { | |
comment = 0; | |
lineStarted = false; | |
this.comments.add(buffer.toString()); | |
this.allTags.add(tags); | |
tags = new ArrayList(); | |
} | |
end = currentChar == '*'; | |
break; | |
case LINE_COMMENT: | |
if (currentChar == '\r' || currentChar == '\n') { | |
/* | |
if (currentChar == '\r' && source[i+1] == '\n') { | |
buffer.append(source[++i]); | |
} | |
*/ | |
comment = 0; | |
this.comments.add(buffer.toString()); | |
this.allTags.add(tags); | |
} else { | |
if (this.chars == null) buffer.append(currentChar); | |
else buffer.append(this.chars); | |
} | |
break; | |
default: | |
// do nothing | |
break; | |
} | |
} | |
} | |
/* | |
* Convert Javadoc source to match Javadoc.toString(). | |
* Store converted comments and their corresponding tags respectively | |
* in comments and allTags fields | |
*/ | |
char[] getUnicodeSource(char[] source) { | |
int length = source.length; | |
int unicodeLength = length*6; | |
char[] unicodeSource = new char[unicodeLength]; | |
int u=0; | |
for (int i=0; i<length; i++) { | |
// get next char | |
if (source[i] == '\\' && source[i+1] == 'u') { | |
//-------------unicode traitement ------------ | |
int c1, c2, c3, c4; | |
unicodeSource[u++] = source[i]; | |
unicodeSource[u++] = source[++i]; | |
if (((c1 = ScannerHelper.getHexadecimalValue(source[i+1])) > 15 || c1 < 0) | |
|| ((c2 = ScannerHelper.getHexadecimalValue(source[i+2])) > 15 || c2 < 0) | |
|| ((c3 = ScannerHelper.getHexadecimalValue(source[i+3])) > 15 || c3 < 0) | |
|| ((c4 = ScannerHelper.getHexadecimalValue(source[i+4])) > 15 || c4 < 0)) { | |
throw new RuntimeException("Invalid unicode in source at "+i); | |
} | |
for (int j=0; j<4; j++) unicodeSource[u++] = source[++i]; | |
} else { | |
unicodeSource[u++] = '\\'; | |
unicodeSource[u++] = 'u'; | |
unicodeSource[u++] = '0'; | |
unicodeSource[u++] = '0'; | |
int val = source[i]/16; | |
unicodeSource[u++] = (char) (val<10 ? val+ 0x30 : val-10+0x61); | |
val = source[i]%16; | |
unicodeSource[u++] = (char) (val<10 ? val+ 0x30 : val-10+0x61); | |
} | |
} | |
// Return one well sized array | |
if (u != unicodeLength) { | |
char[] result = new char[u]; | |
System.arraycopy(unicodeSource, 0, result, 0, u); | |
return result; | |
} | |
return unicodeSource; | |
} | |
/* | |
* Convert Javadoc source to match Javadoc.toString(). | |
* Store converted comments and their corresponding tags respectively | |
* in comments and allTags fields | |
*/ | |
char[] getUnixSource(char[] source) { | |
int length = source.length; | |
int unixLength = length; | |
char[] unixSource = new char[unixLength]; | |
int u=0; | |
for (int i=0; i<length; i++) { | |
// get next char | |
if (source[i] == '\r' && source[i+1] == '\n') { | |
i++; | |
} | |
unixSource[u++] = source[i]; | |
} | |
// Return one well sized array | |
if (u != unixLength) { | |
char[] result = new char[u]; | |
System.arraycopy(unixSource, 0, result, 0, u); | |
return result; | |
} | |
return unixSource; | |
} | |
/* | |
* Return all tags number for a given Javadoc | |
*/ | |
int allTags(Javadoc docComment) { | |
int all = 0; | |
// Count main tags | |
Iterator tags = docComment.tags().listIterator(); | |
while (tags.hasNext()) { | |
TagElement tagElement = (TagElement) tags.next(); | |
if (tagElement.getTagName() != null) { | |
all++; | |
} | |
Iterator fragments = tagElement.fragments().listIterator(); | |
while (fragments.hasNext()) { | |
ASTNode node = (ASTNode) fragments.next(); | |
if (node.getNodeType() == ASTNode.TAG_ELEMENT) { | |
all++; | |
} | |
} | |
} | |
return all; | |
} | |
/* | |
* Add a failure to the list. Use only one method as it easier to put breakpoint to | |
* debug failure when it occurs... | |
*/ | |
private void addFailure(String msg) { | |
this.failures.add(msg); | |
} | |
/* | |
* Put the failure message in list instead of throwing exception immediately. | |
* This allow to store several failures per test... | |
* @see tearDown method which finally throws the execption to signal that test fails. | |
*/ | |
protected void assumeTrue(String msg, boolean cond) { | |
if (!cond) { | |
addFailure(msg); | |
if (this.stopOnFailure) assertTrue(msg, cond); | |
} | |
} | |
/* | |
* Put the failure message in list instead of throwing exception immediately. | |
* This allow to store several failures per test... | |
* @see tearDown method which finally throws the execption to signal that test fails. | |
*/ | |
protected void assumeNull(String msg, Object obj) { | |
if (obj != null) { | |
addFailure(msg); | |
if (this.stopOnFailure) assertNull(msg, obj); | |
} | |
} | |
/* | |
* Put the failure message in list instead of throwing exception immediately. | |
* This allow to store several failures per test... | |
* @see tearDown method which finally throws the execption to signal that test fails. | |
*/ | |
protected void assumeNotNull(String msg, Object obj) { | |
if (obj == null) { | |
addFailure(msg); | |
if (this.stopOnFailure) assertNotNull(msg, obj); | |
} | |
} | |
/* | |
* Put the failure message in list instead of throwing exception immediately. | |
* This allow to store several failures per test... | |
* @see tearDown method which finally throws the execption to signal that test fails. | |
*/ | |
protected void assumeEquals(String msg, int expected, int actual) { | |
if (expected != actual) { | |
addFailure(msg+", expected="+expected+" actual="+actual); | |
if (this.stopOnFailure) assertEquals(msg, expected, actual); | |
} | |
} | |
/* | |
* Put the failure message in list instead of throwing exception immediately. | |
* This allow to store several failures per test... | |
* @see tearDown method which finally throws the execption to signal that test fails. | |
*/ | |
protected void assumeEquals(String msg, Object expected, Object actual) { | |
if (expected == null && actual == null) | |
return; | |
if (expected != null && expected.equals(actual)) | |
return; | |
addFailure(msg+", expected:<"+expected+"> actual:<"+actual+'>'); | |
if (this.stopOnFailure) assertEquals(msg, expected, actual); | |
} | |
/* | |
* Verify positions of tags in source | |
*/ | |
private void verifyPositions(Javadoc docComment, char[] source) { | |
boolean stop = this.stopOnFailure; | |
this.stopOnFailure = false; | |
// Verify javadoc start and end position | |
int start = docComment.getStartPosition(); | |
int end = start+docComment.getLength()-1; | |
assumeTrue(this.prefix+"Misplaced javadoc start at <"+start+">: "+docComment, source[start++] == '/' && source[start++] == '*' && source[start++] == '*'); | |
// Get first meaningful character | |
int tagStart = start; | |
// Verify tags | |
Iterator tags = docComment.tags().listIterator(); | |
while (tags.hasNext()) { | |
while (source[tagStart] == '*' || Character.isWhitespace(source[tagStart])) { | |
tagStart++; // purge non-stored characters | |
} | |
TagElement tagElement = (TagElement) tags.next(); | |
int teStart = tagElement.getStartPosition(); | |
assumeEquals(this.prefix+"Wrong start position <"+teStart+"> for tag element: "+tagElement, tagStart, teStart); | |
verifyPositions(tagElement, source); | |
tagStart += tagElement.getLength(); | |
} | |
while (source[tagStart] == '*' || Character.isWhitespace(source[tagStart])) { | |
tagStart++; // purge non-stored characters | |
} | |
assumeTrue(this.prefix+"Misplaced javadoc end at <"+tagStart+'>', source[tagStart-1] == '*' && source[tagStart] == '/'); | |
assumeEquals(this.prefix+"Wrong javadoc length at <"+end+">: ", tagStart, end); | |
this.stopOnFailure = stop; | |
if (stop && this.failures.size() > 0) { | |
String expected = new String(source, docComment.getStartPosition(), docComment.getLength()); | |
ASTConverterJavadocFlattener flattener = new ASTConverterJavadocFlattener(expected); | |
docComment.accept(flattener); | |
assertEquals("Unexpected errors while verifying javadoc comment positions!", expected, flattener.getResult()); | |
} | |
} | |
/** | |
* Verify positions of fragments in source | |
* @deprecated using deprecated code | |
*/ | |
private void verifyPositions(TagElement tagElement, char[] source) { | |
String text = null; | |
// Verify tag name | |
String tagName = tagElement.getTagName(); | |
int tagStart = tagElement.getStartPosition(); | |
if (tagElement.isNested()) { | |
assumeEquals(this.prefix+"Wrong start position <"+tagStart+"> for "+tagElement, '{', source[tagStart++]); | |
} | |
if (tagName != null) { | |
text= new String(source, tagStart, tagName.length()); | |
assumeEquals(this.prefix+"Misplaced tag name at <"+tagStart+">: ", tagName, text); | |
tagStart += tagName.length(); | |
} | |
// Verify each fragment | |
ASTNode previousFragment = null; | |
Iterator elements = tagElement.fragments().listIterator(); | |
while (elements.hasNext()) { | |
ASTNode fragment = (ASTNode) elements.next(); | |
if (fragment.getNodeType() == ASTNode.TEXT_ELEMENT) { | |
if (previousFragment == null && TagElement.TAG_PARAM.equals(tagName) && ((TextElement)fragment).getText().equals("<")) { // special case here for @param <E> syntax | |
int start = tagStart; | |
// verify '<' | |
while (source[start] == ' ' || Character.isWhitespace(source[start])) { | |
start++; // purge white characters | |
} | |
text = new String(source, start, fragment.getLength()); | |
assumeEquals(this.prefix+"Misplaced text element at <"+fragment.getStartPosition()+">: ", text, ((TextElement) fragment).getText()); | |
start += fragment.getLength(); | |
// verify simple name | |
assumeTrue(this.prefix+"Unexpected fragment end for "+tagElement, elements.hasNext()); | |
fragment = (ASTNode) elements.next(); | |
while (source[start] == ' ' || Character.isWhitespace(source[start])) { | |
start++; // purge white characters | |
} | |
assumeEquals(this.prefix+"Unexpected node type for tag element "+tagElement, ASTNode.SIMPLE_NAME, fragment.getNodeType()); | |
Name name = (Name) fragment; | |
verifyNamePositions(start, name, source); | |
start += fragment.getLength(); | |
// verify simple name | |
assumeTrue(this.prefix+"Unexpected fragment end for "+tagElement, elements.hasNext()); | |
fragment = (ASTNode) elements.next(); | |
while (source[start] == ' ' || Character.isWhitespace(source[start])) { | |
start++; // purge white characters | |
} | |
text = new String(source, start, fragment.getLength()); | |
assumeEquals(this.prefix+"Misplaced text element at <"+fragment.getStartPosition()+">: ", text, ((TextElement) fragment).getText()); | |
start += fragment.getLength(); | |
// reset fragment as simple name to avoid issue with next text element | |
fragment = name; | |
tagStart += (start- tagStart) - name.getLength(); | |
} else { | |
if (previousFragment == null) { | |
if (tagName != null && (source[tagStart] == '\r' || source[tagStart] == '\n')) { | |
while (source[tagStart] == '*' || Character.isWhitespace(source[tagStart])) { | |
tagStart++; // purge non-stored characters | |
} | |
} | |
} else { | |
if (previousFragment.getNodeType() == ASTNode.TEXT_ELEMENT) { | |
assumeTrue(this.prefix+"Wrong length at <"+previousFragment.getStartPosition()+"> for text element "+previousFragment, (source[tagStart] == '\r' /* && source[tagStart+1] == '\n' */ || source[tagStart] == '\n')); | |
while (source[tagStart] == '*' || Character.isWhitespace(source[tagStart])) { | |
tagStart++; // purge non-stored characters | |
} | |
} else if (TagElement.TAG_PARAM.equals(tagName) && previousFragment.getNodeType() == ASTNode.SIMPLE_NAME && ((TextElement)fragment).getText().equals(">")) { | |
while (source[tagStart] == ' ' || Character.isWhitespace(source[tagStart])) { | |
tagStart++; // purge white characters | |
} | |
} else { | |
int start = tagStart; | |
boolean newLine = false; | |
while (source[start] == '*' || Character.isWhitespace(source[start])) { | |
start++; // purge non-stored characters | |
if (source[tagStart] == '\r' || source[tagStart] == '\n') { | |
newLine = true; | |
} | |
} | |
if (newLine) tagStart = start; | |
} | |
} | |
text = new String(source, tagStart, fragment.getLength()); | |
assumeEquals(this.prefix+"Misplaced text element at <"+fragment.getStartPosition()+">: ", text, ((TextElement) fragment).getText()); | |
} | |
} else { | |
while (source[tagStart] == '*' || Character.isWhitespace(source[tagStart])) { | |
tagStart++; // purge non-stored characters | |
} | |
if (fragment.getNodeType() == ASTNode.SIMPLE_NAME || fragment.getNodeType() == ASTNode.QUALIFIED_NAME) { | |
verifyNamePositions(tagStart, (Name) fragment, source); | |
} else if (fragment.getNodeType() == ASTNode.TAG_ELEMENT) { | |
TagElement inlineTag = (TagElement) fragment; | |
assumeEquals(this.prefix+"Tag element <"+inlineTag+"> has wrong start position", tagStart, inlineTag.getStartPosition()); | |
verifyPositions(inlineTag, source); | |
} else if (fragment.getNodeType() == ASTNode.MEMBER_REF) { | |
MemberRef memberRef = (MemberRef) fragment; | |
// Store start position | |
int start = tagStart; | |
// Verify qualifier position | |
Name qualifier = memberRef.getQualifier(); | |
if (qualifier != null) { | |
verifyNamePositions(start, qualifier, source); | |
start += qualifier.getLength(); | |
while (source[start] == '*' || Character.isWhitespace(source[start])) { | |
start++; // purge non-stored characters | |
} | |
} | |
// Verify member separator position | |
assumeEquals(this.prefix+"Misplaced # separator at <"+start+"> for member ref "+memberRef, '#', source[start]); | |
start++; | |
while (source[start] == '*' || Character.isWhitespace(source[start])) { | |
start++; // purge non-stored characters | |
} | |
// Verify member name position | |
Name name = memberRef.getName(); | |
text = new String(source, start, name.getLength()); | |
assumeEquals(this.prefix+"Misplaced member ref at <"+start+">: ", text, name.toString()); | |
verifyNamePositions(start, name, source); | |
} else if (fragment.getNodeType() == ASTNode.METHOD_REF) { | |
MethodRef methodRef = (MethodRef) fragment; | |
// Store start position | |
int start = tagStart; | |
// Verify qualifier position | |
Name qualifier = methodRef.getQualifier(); | |
if (qualifier != null) { | |
verifyNamePositions(start, qualifier, source); | |
start += qualifier.getLength(); | |
while (source[start] == '*' || Character.isWhitespace(source[start])) { | |
start++; // purge non-stored characters | |
} | |
} | |
// Verify member separator position | |
assumeEquals(this.prefix+"Misplaced # separator at <"+start+"> for method ref: "+methodRef, '#', source[start]); | |
start++; | |
while (source[start] == '*' || Character.isWhitespace(source[start])) { | |
start++; // purge non-stored characters | |
} | |
// Verify member name position | |
Name name = methodRef.getName(); | |
int nameLength = name.getLength(); | |
text = new String(source, start, nameLength); | |
if (!text.equals(name.toString())) { // may have qualified constructor reference for inner classes | |
if (methodRef.getQualifier().isQualifiedName()) { | |
text = new String(source, start, methodRef.getQualifier().getLength()); | |
assumeEquals(this.prefix+"Misplaced method ref name at <"+start+">: ", text, methodRef.getQualifier().toString()); | |
while (source[start] != '.' || Character.isWhitespace(source[start])) { | |
start++; // purge non-stored characters | |
} | |
start++; | |
} else { | |
while (source[start] != '.' || Character.isWhitespace(source[start])) { | |
start++; // purge non-stored characters | |
} | |
start++; | |
text = new String(source, start, nameLength); | |
assumeEquals(this.prefix+"Misplaced method ref name at <"+start+">: ", text, name.toString()); | |
} | |
} | |
verifyNamePositions(start, name, source); | |
start += nameLength; | |
// Verify arguments starting open parenthesis | |
while (source[start] == '*' || Character.isWhitespace(source[start])) { | |
start++; // purge non-stored characters | |
} | |
// assumeEquals(prefix+"Misplaced ( at <"+start+"> for method ref: "+methodRef, '(', source[start]); | |
if (source[start] == '(') { // now method reference may have no parenthesis... | |
start++; | |
// Verify parameters | |
Iterator parameters = methodRef.parameters().listIterator(); | |
while (parameters.hasNext()) { | |
MethodRefParameter param = (MethodRefParameter) parameters.next(); | |
boolean lastParam = !parameters.hasNext(); | |
// Verify parameter type positions | |
while (source[start] == '*' || Character.isWhitespace(source[start])) { | |
start++; // purge non-stored characters | |
} | |
Type type = param.getType(); | |
if (type.isSimpleType()) { | |
verifyNamePositions(start, ((SimpleType)type).getName(), source); | |
} else if (type.isPrimitiveType()) { | |
text = new String(source, start, type.getLength()); | |
assumeEquals(this.prefix+"Misplaced method ref parameter type at <"+start+"> for method ref: "+methodRef, text, type.toString()); | |
} else if (type.isArrayType()) { | |
Type elementType = ((ArrayType) param.getType()).getElementType(); | |
if (elementType.isSimpleType()) { | |
verifyNamePositions(start, ((SimpleType)elementType).getName(), source); | |
} else if (elementType.isPrimitiveType()) { | |
text = new String(source, start, elementType.getLength()); | |
assumeEquals(this.prefix+"Misplaced method ref parameter type at <"+start+"> for method ref: "+methodRef, text, elementType.toString()); | |
} | |
} | |
start += type.getLength(); | |
// if last param then perhaps a varargs | |
while (Character.isWhitespace(source[start])) { // do NOT accept '*' in parameter declaration | |
start++; // purge non-stored characters | |
} | |
if (lastParam && this.astLevel != AST.JLS2 && param.isVarargs()) { | |
for (int p=0;p<3;p++) { | |
assumeTrue(this.prefix+"Missing ellipsis for vararg method ref parameter at <"+start+"> for method ref: "+methodRef, source[start++]=='.'); | |
} | |
} | |
// Verify parameter name positions | |
while (Character.isWhitespace(source[start])) { // do NOT accept '*' in parameter declaration | |
start++; // purge non-stored characters | |
} | |
name = param.getName(); | |
if (name != null) { | |
text = new String(source, start, name.getLength()); | |
assumeEquals(this.prefix+"Misplaced method ref parameter name at <"+start+"> for method ref: "+methodRef, text, name.toString()); | |
start += name.getLength(); | |
} | |
// Verify end parameter declaration | |
while (source[start] == '*' || Character.isWhitespace(source[start])) { | |
start++; | |
} | |
assumeTrue(this.prefix+"Misplaced parameter end at <"+start+"> for method ref: "+methodRef, source[start] == ',' || source[start] == ')'); | |
start++; | |
if (source[start] == ')') { | |
break; | |
} | |
} | |
} | |
} | |
} | |
tagStart += fragment.getLength(); | |
previousFragment = fragment; | |
} | |
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345 | |
if (!(TAG_CODE.equalsIgnoreCase(tagName) || !TAG_LITERAL.equalsIgnoreCase(tagName)) && tagElement.isNested()) { | |
assumeEquals(this.prefix+"Wrong end character at <"+tagStart+"> for "+tagElement, '}', source[tagStart++]); | |
} | |
} | |
/* | |
* Verify each name component positions. | |
*/ | |
private void verifyNamePositions(int nameStart, Name name, char[] source) { | |
if (name.isQualifiedName()) { | |
QualifiedName qualified = (QualifiedName) name; | |
int start = qualified.getName().getStartPosition(); | |
String str = new String(source, start, qualified.getName().getLength()); | |
assumeEquals(this.prefix+"Misplaced or wrong name for qualified name: "+name, str, qualified.getName().toString()); | |
verifyNamePositions(nameStart, ((QualifiedName) name).getQualifier(), source); | |
} | |
String str = new String(source, nameStart, name.getLength()); | |
if (str.indexOf('\n') < 0) { // cannot compare if text contains new line | |
assumeEquals(this.prefix+"Misplaced name for qualified name: ", str, name.toString()); | |
} else if (this.debug) { | |
System.out.println(this.prefix+"Name contains new line for qualified name: "+name); | |
} | |
} | |
/* | |
* Verify that bindings of Javadoc comment structure are resolved or not. | |
* For expected unresolved binding, verify that following text starts with 'Unknown' | |
*/ | |
private void verifyBindings(Javadoc docComment) { | |
boolean stop = this.stopOnFailure; | |
// stopOnFailure = false; | |
// Verify tags | |
Iterator tags = docComment.tags().listIterator(); | |
while (tags.hasNext()) { | |
verifyBindings((TagElement) tags.next()); | |
} | |
this.stopOnFailure = stop; | |
assertTrue(!stop || this.failures.size()==0); | |
} | |
/* | |
* Verify that bindings of Javadoc tag structure are resolved or not. | |
* For expected unresolved binding, verify that following text starts with 'Unknown' | |
*/ | |
private void verifyBindings(TagElement tagElement) { | |
// Verify each fragment | |
Iterator elements = tagElement.fragments().listIterator(); | |
IBinding previousBinding = null; | |
ASTNode previousFragment = null; | |
boolean resolvedBinding = false; | |
while (elements.hasNext()) { | |
ASTNode fragment = (ASTNode) elements.next(); | |
if (fragment.getNodeType() == ASTNode.TEXT_ELEMENT) { | |
TextElement text = (TextElement) fragment; | |
if (resolvedBinding) { | |
if (previousBinding == null) { | |
assumeTrue(this.prefix+"Reference '"+previousFragment+"' should be bound!", text.getText().trim().indexOf("Unknown")>=0); | |
} else { | |
assumeTrue(this.prefix+"Unknown reference '"+previousFragment+"' should NOT be bound!", text.getText().trim().indexOf("Unknown")<0); | |
} | |
} | |
previousBinding = null; | |
resolvedBinding = false; | |
} else if (fragment.getNodeType() == ASTNode.TAG_ELEMENT) { | |
verifyBindings((TagElement) fragment); | |
previousBinding = null; | |
resolvedBinding = false; | |
} else { | |
resolvedBinding = true; | |
if (fragment.getNodeType() == ASTNode.SIMPLE_NAME) { | |
previousBinding = ((Name)fragment).resolveBinding(); | |
} else if (fragment.getNodeType() == ASTNode.QUALIFIED_NAME) { | |
QualifiedName name = (QualifiedName) fragment; | |
previousBinding = name.resolveBinding(); | |
verifyNameBindings(name); | |
} else if (fragment.getNodeType() == ASTNode.MODULE_QUALIFIED_NAME) { | |
ModuleQualifiedName name = (ModuleQualifiedName) fragment; | |
Name typeName = name.getName(); | |
if (typeName != null) { | |
if (typeName.getNodeType() == ASTNode.SIMPLE_NAME) { | |
previousBinding = ((Name)fragment).resolveBinding(); | |
} else if (typeName.getNodeType() == ASTNode.QUALIFIED_NAME) { | |
QualifiedName qname = (QualifiedName) typeName; | |
previousBinding = qname.resolveBinding(); | |
verifyNameBindings(qname); | |
} | |
} | |
Name mName = name.getModuleQualifier(); | |
if (mName.getNodeType() == ASTNode.SIMPLE_NAME) { | |
previousBinding = ((Name)fragment).resolveBinding(); | |
} else if (mName.getNodeType() == ASTNode.QUALIFIED_NAME) { | |
QualifiedName qname = (QualifiedName) mName; | |
previousBinding = qname.resolveBinding(); | |
} | |
assumeNotNull(this.prefix+""+name+" binding was not foundfound in "+fragment, previousBinding); | |
assumeTrue(this.prefix+""+name+" binding is not module binding "+fragment, previousBinding instanceof IModuleBinding); | |
} else if (fragment.getNodeType() == ASTNode.MEMBER_REF) { | |
MemberRef memberRef = (MemberRef) fragment; | |
previousBinding = memberRef.resolveBinding(); | |
if (previousBinding != null) { | |
SimpleName name = memberRef.getName(); | |
assumeNotNull(this.prefix+""+name+" binding was not foundfound in "+fragment, name.resolveBinding()); | |
verifyNameBindings(memberRef.getQualifier()); | |
} | |
} else if (fragment.getNodeType() == ASTNode.METHOD_REF) { | |
MethodRef methodRef = (MethodRef) fragment; | |
previousBinding = methodRef.resolveBinding(); | |
if (previousBinding != null) { | |
SimpleName methodName = methodRef.getName(); | |
IBinding methNameBinding = methodName.resolveBinding(); | |
Name methodQualifier = methodRef.getQualifier(); | |
// TODO (frederic) Replace the two following lines by commented block when bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=62650 will be fixed | |
assumeNotNull(this.prefix+""+methodName+" binding was not found in "+fragment, methNameBinding); | |
verifyNameBindings(methodQualifier); | |
/* | |
if (methodQualifier == null) { | |
if (methNameBinding == null) { | |
char firstChar = methodName.getIdentifier().charAt(0); | |
if (Character.isUpperCase(firstChar)) { | |
// assume that selector starting with uppercase is for constructor => signal that binding is null | |
System.out.println(prefix+"Binding for selector of '"+methodRef+"' is null."); | |
} | |
} else { | |
if (methNameBinding.getName().equals(methodName.getIdentifier())) { // binding is not null only for constructor | |
assumeNotNull(prefix+""+methodName+" binding was not found!",methNameBinding); | |
} else { | |
assumeNull(prefix+""+methodName+" binding should be null!", methNameBinding); | |
} | |
} | |
} else { | |
SimpleName methodSimpleType = null; | |
if (methodQualifier.isQualifiedName()) { | |
methodSimpleType = ((QualifiedName)methodQualifier).getName(); | |
} else { | |
methodSimpleType = (SimpleName) methodQualifier; | |
} | |
if (methodSimpleType.getIdentifier().equals(methodName.getIdentifier())) { // binding is not null only for constructor | |
assumeNotNull(prefix+""+methodName+" binding was not found!",methNameBinding); | |
} else { | |
assumeNull(prefix+""+methodName+" binding should be null!", methNameBinding); | |
} | |
verifyNameBindings(methodRef.getQualifier()); | |
} | |
*/ | |
Iterator parameters = methodRef.parameters().listIterator(); | |
while (parameters.hasNext()) { | |
MethodRefParameter param = (MethodRefParameter) parameters.next(); | |
Type type = param.getType(); | |
assumeNotNull(this.prefix+""+type+" binding was not found in "+fragment, type.resolveBinding()); | |
if (type.isSimpleType()) { | |
verifyNameBindings(((SimpleType)type).getName()); | |
} else if (type.isArrayType()) { | |
Type elementType = ((ArrayType) param.getType()).getElementType(); | |
assumeNotNull(this.prefix+""+elementType+" binding was not found in "+fragment, elementType.resolveBinding()); | |
if (elementType.isSimpleType()) { | |
verifyNameBindings(((SimpleType)elementType).getName()); | |
} | |
} | |
// Do not verify parameter name as no binding is expected for them | |
} | |
} | |
} | |
} | |
previousFragment = fragment; | |
} | |
assumeTrue(this.prefix+"Reference '"+(previousFragment==null?tagElement:previousFragment)+"' should be bound!", (!resolvedBinding || previousBinding != null)); | |
} | |
/* | |
* Verify each name component binding. | |
*/ | |
private void verifyNameBindings(Name name) { | |
if (name != null) { | |
IBinding binding = name.resolveBinding(); | |
if (name.toString().indexOf("Unknown") > 0) { | |
assumeNull(this.prefix+name+" binding should be null!", binding); | |
} else { | |
assumeNotNull(this.prefix+name+" binding was not found!", binding); | |
} | |
SimpleName simpleName = null; | |
int index = 0; | |
while (name.isQualifiedName()) { | |
simpleName = ((QualifiedName) name).getName(); | |
binding = simpleName.resolveBinding(); | |
if (simpleName.getIdentifier().equalsIgnoreCase("Unknown")) { | |
assumeNull(this.prefix+simpleName+" binding should be null!", binding); | |
} else { | |
assumeNotNull(this.prefix+simpleName+" binding was not found!", binding); | |
} | |
if (index > 0 && this.packageBinding) { | |
assumeEquals(this.prefix+"Wrong binding type!", IBinding.PACKAGE, binding.getKind()); | |
} | |
index++; | |
name = ((QualifiedName) name).getQualifier(); | |
binding = name.resolveBinding(); | |
if (name.toString().indexOf("Unknown") > 0) { | |
assumeNull(this.prefix+name+" binding should be null!", binding); | |
} else { | |
assumeNotNull(this.prefix+name+" binding was not found!", binding); | |
} | |
if (this.packageBinding) { | |
assumeEquals(this.prefix+"Wrong binding type!", IBinding.PACKAGE, binding.getKind()); | |
} | |
} | |
} | |
} | |
/* (non-Javadoc) | |
* @see junit.framework.TestCase#setUp() | |
*/ | |
protected void verifyComments(String test) throws JavaModelException { | |
ICompilationUnit[] units = getCompilationUnits("Converter" , "src", "javadoc."+test); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
for (int i=0; i<units.length; i++) { | |
verifyComments(units[i]); | |
} | |
} | |
/* | |
* Verify the comments of a compilation unit. | |
*/ | |
protected void verifyWorkingCopiesComments() throws JavaModelException { | |
assumeNotNull("No working copies to verify!", this.workingCopies); | |
int length = this.workingCopies.length; | |
assumeTrue("We need to have at least one working copy to verify!", length>0); | |
for (int i=0; i<length; i++) { | |
verifyComments(this.workingCopies[i]); | |
} | |
} | |
/* | |
* Verify the comments of a compilation unit. | |
*/ | |
protected CompilationUnit verifyComments(ICompilationUnit unit) throws JavaModelException { | |
// Get test file | |
this.sourceUnit = unit; | |
this.prefix = unit.getElementName()+": "; | |
// Get current project | |
String sourceStr = this.sourceUnit.getSource(); | |
if (this.savedOptions != null && !this.sourceUnit.getJavaProject().getElementName().equals(this.currentProject.getElementName())) { | |
this.currentProject.setOptions(this.savedOptions); | |
this.savedOptions = null; | |
} | |
this.currentProject = this.sourceUnit.getJavaProject(); | |
if (this.savedOptions == null) this.savedOptions = this.currentProject.getOptions(false); | |
// set up java project options | |
this.currentProject.setOption(JavaCore.COMPILER_PB_INVALID_JAVADOC, this.compilerOption); | |
this.currentProject.setOption(JavaCore.COMPILER_PB_MISSING_JAVADOC_TAGS, this.compilerOption); | |
this.currentProject.setOption(JavaCore.COMPILER_PB_MISSING_JAVADOC_COMMENTS, this.compilerOption); | |
this.currentProject.setOption(JavaCore.COMPILER_PB_METHOD_WITH_CONSTRUCTOR_NAME, JavaCore.IGNORE); | |
this.currentProject.setOption(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, this.docCommentSupport); | |
// Verify source regardings converted comments | |
char[] source = sourceStr.toCharArray(); | |
String fileName = unit.getPath().toString(); | |
try { | |
return verifyComments(fileName, source); | |
} | |
catch (RuntimeException ex) { | |
TEST_COUNTERS[3]++; | |
throw ex; | |
} | |
} | |
protected CompilationUnit verifyComments(String fileName, char[] source) { | |
return verifyComments(fileName, source, null); | |
} | |
protected CompilationUnit verifyComments(String fileName, char[] source, Map options) { | |
// Verify comments either in unicode or not | |
char[] testedSource = source; | |
if (UNICODE) { | |
testedSource = getUnicodeSource(source); | |
} | |
// Verify comments either in unicode or not | |
else if (this.unix) { | |
testedSource = getUnixSource(source); | |
} | |
// Get comments infos from test file | |
setSourceComment(testedSource); | |
// Create DOM AST nodes hierarchy | |
List unitComments = null; | |
String sourceLevel = null; | |
String complianceLevel = null; | |
if (this.currentProject != null) { | |
complianceLevel = this.currentProject.getOption(JavaCore.COMPILER_COMPLIANCE, true); | |
sourceLevel = this.currentProject.getOption(JavaCore.COMPILER_SOURCE, true); | |
this.currentProject.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_15); | |
this.currentProject.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_15); | |
} | |
CompilationUnit compilUnit = (CompilationUnit) runConversion(testedSource, fileName, this.currentProject, options); | |
if (this.compilerOption.equals(JavaCore.ERROR)) { | |
assumeEquals(this.prefix+"Unexpected problems", 0, compilUnit.getProblems().length); //$NON-NLS-1$ | |
} else if (this.compilerOption.equals(JavaCore.WARNING)) { | |
IProblem[] problemsList = compilUnit.getProblems(); | |
int length = problemsList.length; | |
if (length > 0) { | |
this.problems.append(" - "+this.prefix+length+" problems:"); //$NON-NLS-1$ | |
for (int i = 0; i < problemsList.length; i++) { | |
this.problems.append(" + "); | |
this.problems.append(problemsList[i]); | |
this.problems.append("\n"); | |
} | |
} | |
} | |
unitComments = compilUnit.getCommentList(); | |
assumeNotNull(this.prefix+"Unexpected problems", unitComments); | |
// Basic comments verification | |
int size = unitComments.size(); | |
assumeEquals(this.prefix+"Wrong number of comments!", this.comments.size(), size); | |
// Verify comments positions and bindings | |
for (int i=0; i<size; i++) { | |
Comment comment = (Comment) unitComments.get(i); | |
List tags = (List) this.allTags.get(i); | |
// Verify flattened content | |
String stringComment = (String) this.comments.get(i); | |
// ASTConverterJavadocFlattener printer = new ASTConverterJavadocFlattener(stringComment); | |
// comment.accept(printer); | |
String text = new String(testedSource, comment.getStartPosition(), comment.getLength()); | |
assumeEquals(this.prefix+"Flattened comment does NOT match source!", stringComment, text); | |
// Verify javdoc tags positions and bindings | |
if (comment.isDocComment()) { | |
Javadoc docComment = (Javadoc)comment; | |
if (this.docCommentSupport.equals(JavaCore.ENABLED)) { | |
assumeEquals(this.prefix+"Invalid tags number in javadoc:\n"+docComment+"\n", tags.size(), allTags(docComment)); | |
verifyPositions(docComment, testedSource); | |
if (this.resolveBinding) { | |
verifyBindings(docComment); | |
} | |
} else { | |
assumeEquals("Javadoc should be flat!", 0, docComment.tags().size()); | |
} | |
} | |
} | |
/* Verify each javadoc: not implemented yet | |
Iterator types = compilUnit.types().listIterator(); | |
while (types.hasNext()) { | |
TypeDeclaration typeDeclaration = (TypeDeclaration) types.next(); | |
verifyJavadoc(typeDeclaration.getJavadoc()); | |
} | |
*/ | |
if (sourceLevel != null) { | |
this.currentProject.setOption(JavaCore.COMPILER_COMPLIANCE, complianceLevel); | |
this.currentProject.setOption(JavaCore.COMPILER_SOURCE, sourceLevel); | |
} | |
// Return compilation unit for possible further verifications | |
return compilUnit; | |
} | |
public void testJavadoc1() throws JavaModelException { | |
this.moduleUnit = getWorkingCopy("/Converter_15_1/src/module-info.java", | |
"module test1.one.two {\r\n" + | |
"}"); | |
this.workingCopies = new ICompilationUnit[1]; | |
this.workingCopies[0] = getWorkingCopy("/Converter_15_1/src/javadoc/X.java", | |
"package javadoc;\n" + | |
"public class X {\n" + | |
" /** \n" + | |
" * @see test1.one.two/ \n" + | |
" * {@link test1.one.two/} \n" + | |
" * {@linkplain test1.one.two/} \n" + | |
" */ \n" + | |
" public static void foo(Object object) {\n" + | |
" }\n" + | |
"}\n" | |
); | |
CompilationUnit compilUnit = verifyComments(this.workingCopies[0]); | |
if (this.docCommentSupport.equals(JavaCore.ENABLED)) { | |
// Get comments | |
List unitComments = compilUnit.getCommentList(); | |
int size = unitComments.size(); | |
assertEquals("Wrong number of comments", 1, size); | |
Javadoc[] javadocs = new Javadoc[size]; | |
Iterator iterator = unitComments.iterator(); | |
for (int i=0; i<size; i++) { | |
Comment comment = (Comment) iterator.next(); | |
assertEquals("Expect javadoc for comment: "+comment, ASTNode.JAVADOC, comment.getNodeType()); | |
javadocs[i] = (Javadoc) comment; | |
} | |
// Verify member type declaration start | |
ASTNode node = getASTNode(compilUnit, 0, 0); | |
assertEquals("Expected method declaration for node: "+node, ASTNode.METHOD_DECLARATION, node.getNodeType()); | |
MethodDeclaration methodDeclaration = (MethodDeclaration) node; | |
int javadocStart = javadocs[0].getStartPosition(); | |
assertEquals("Invalid start position for MethodDeclaration: "+methodDeclaration, methodDeclaration.getStartPosition(), javadocStart); | |
} | |
} | |
public void testJavadoc3() throws JavaModelException { | |
this.moduleUnit = getWorkingCopy("/Converter_15_1/src/module-info.java", | |
"module test1.one.two {\r\n" + | |
"}"); | |
this.workingCopies = new ICompilationUnit[1]; | |
this.workingCopies[0] = getWorkingCopy("/Converter_15_1/src/javadoc/X.java", | |
"package javadoc;\n" + | |
"public class X {\n" + | |
" /** \n" + | |
" * @see test1.one.two/javadoc.X#foo \n" + | |
" */ \n" + | |
" public static void foo(Object object) {\n" + | |
" }\n" + | |
"}\n" | |
); | |
CompilationUnit compilUnit = verifyComments(this.workingCopies[0]); | |
if (this.docCommentSupport.equals(JavaCore.ENABLED)) { | |
// Get comments | |
List unitComments = compilUnit.getCommentList(); | |
int size = unitComments.size(); | |
assertEquals("Wrong number of comments", 1, size); | |
Javadoc[] javadocs = new Javadoc[size]; | |
Iterator iterator = unitComments.iterator(); | |
for (int i=0; i<size; i++) { | |
Comment comment = (Comment) iterator.next(); | |
assertEquals("Expect javadoc for comment: "+comment, ASTNode.JAVADOC, comment.getNodeType()); | |
javadocs[i] = (Javadoc) comment; | |
} | |
// Verify member type declaration start | |
ASTNode node = getASTNode(compilUnit, 0, 0); | |
assertEquals("Expected method declaration for node: "+node, ASTNode.METHOD_DECLARATION, node.getNodeType()); | |
MethodDeclaration methodDeclaration = (MethodDeclaration) node; | |
int javadocStart = javadocs[0].getStartPosition(); | |
assertEquals("Invalid start position for MethodDeclaration: "+methodDeclaration, methodDeclaration.getStartPosition(), javadocStart); | |
} | |
} | |
public void testJavadoc2() throws JavaModelException { | |
this.moduleUnit = getWorkingCopy("/Converter_15_1/src/module-info.java", | |
"module test1.one.two {\r\n" + | |
"}"); | |
this.workingCopies = new ICompilationUnit[1]; | |
this.workingCopies[0] = getWorkingCopy("/Converter_15_1/src/javadoc/X.java", | |
"package javadoc;\n" + | |
"public class X {\n" + | |
" /** \n" + | |
" * @see test1.one.two/javadoc.X \n" + | |
" */ \n" + | |
" public static void foo(Object object) {\n" + | |
" }\n" + | |
"}\n" | |
); | |
CompilationUnit compilUnit = verifyComments(this.workingCopies[0]); | |
if (this.docCommentSupport.equals(JavaCore.ENABLED)) { | |
// Get comments | |
List unitComments = compilUnit.getCommentList(); | |
int size = unitComments.size(); | |
assertEquals("Wrong number of comments", 1, size); | |
Javadoc[] javadocs = new Javadoc[size]; | |
Iterator iterator = unitComments.iterator(); | |
for (int i=0; i<size; i++) { | |
Comment comment = (Comment) iterator.next(); | |
assertEquals("Expect javadoc for comment: "+comment, ASTNode.JAVADOC, comment.getNodeType()); | |
javadocs[i] = (Javadoc) comment; | |
} | |
// Verify member type declaration start | |
ASTNode node = getASTNode(compilUnit, 0, 0); | |
assertEquals("Expected method declaration for node: "+node, ASTNode.METHOD_DECLARATION, node.getNodeType()); | |
MethodDeclaration methodDeclaration = (MethodDeclaration) node; | |
int javadocStart = javadocs[0].getStartPosition(); | |
assertEquals("Invalid start position for MethodDeclaration: "+methodDeclaration, methodDeclaration.getStartPosition(), javadocStart); | |
} | |
} | |
} |