/**
* Copyright (C) 2012 - 2013 Eric Van Dewoestine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.eclim.plugin.jdt.command.junit;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.eclim.plugin.jdt.util.TypeUtils;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.Signature;
/**
* Utility methods for junit commands.
*
* @author Eric Van Dewoestine
*/
public class JUnitUtils
{
private static final Pattern TESTING_CLASS_NAME =
Pattern.compile("(?:^Test([^a-z].*)|(.*)Test$)");
/**
* Find the test ICompilationUnit for the supplied non-test type.
*
* @param javaProject The java project to search in.
* @param type The non-test type to find the corresponding test for.
* @return The test ICompilationUnit or null if one could not be found.
*/
public static ICompilationUnit findTest(IJavaProject javaProject, IType type)
throws Exception
{
// possible names to try.
String[] names = new String[]{
type.getFullyQualifiedName() + "Test",
type.getPackageFragment().getElementName() + ".Test" + type.getElementName(),
};
for (String name : names){
IType[] results = TypeUtils.findTypes(javaProject, name);
for (IType result : results){
if (result.getCompilationUnit() != null){
return result.getCompilationUnit();
}
}
}
return null;
}
/**
* Find the ICompilationUnit for the supplied test type.
*
* @param javaProject The java project to search in.
* @param type The test type to find the corresponding class for.
* @return The ICompilationUnit or null if one could not be found.
*/
public static ICompilationUnit findClass(IJavaProject javaProject, IType type)
throws Exception
{
String name = type.getElementName();
Matcher matcher = TESTING_CLASS_NAME.matcher(name);
IType found = null;
// test class uses a Test prefix or suffix, so remove that and search for
// the fully qualified result matching the same package name.
if (matcher.matches()){
name = matcher.group(2);
if (name == null){
name = matcher.group(1);
}
String fqn = type.getPackageFragment().getElementName() + '.' + name;
found = javaProject.findType(fqn);
}
// no type found by removing Test prefix / suffix with the same package, so
// search for the unqualified name (sans the Test prefix / suffix).
if (found == null){
IType[] types = findTypes(javaProject, type, name);
if (types.length == 1){
found = types[0];
}
}
return found != null ? found.getCompilationUnit() : null;
}
private static IType[] findTypes(
IJavaProject javaProject, IType ignore, String name)
throws Exception
{
ArrayList<IType> types = new ArrayList<IType>();
for (IType type : TypeUtils.findTypes(javaProject, name)){
if (!type.equals(ignore) && type.getCompilationUnit() != null){
types.add(type);
}
}
return types.toArray(new IType[types.size()]);
}
/**
* Attempt to find a corresponding test method in the specified test src for
* the given non-test method.
*
* @param testSrc The test ICompilationUnit to look for a test method in.
* @param method The regular non-test method to find a corresponding test for.
* @return The test IMethod or null if one could not be found.
*/
public static IMethod findTestMethod(ICompilationUnit testSrc, IMethod method)
throws Exception
{
String testName = "test" + StringUtils.capitalize(method.getElementName());
StringBuffer testNameWithParams = new StringBuffer(testName);
appendParameterNamesToMethodName(testNameWithParams, method.getParameterTypes());
replaceIllegalCharacters(testNameWithParams);
StringBuffer nameWithParams = new StringBuffer(method.getElementName());
appendParameterNamesToMethodName(nameWithParams, method.getParameterTypes());
replaceIllegalCharacters(nameWithParams);
String[] methodNames = new String[]{
testNameWithParams.toString(),
nameWithParams.toString(),
testName,
method.getElementName(),
};
for (String name : methodNames){
IMethod test = testSrc.getTypes()[0].getMethod(name, null);
if (test != null && test.exists()){
return test;
}
}
return null;
}
/**
* Attempt to find a corresponding class method in the specified src for
* the given test method.
*
* @param src The ICompilationUnit to look for the method in.
* @param testMethod The test method to find the corresponding class method for.
* @return The IMethod or null if one could not be found.
*/
public static IMethod findClassMethod(ICompilationUnit src, IMethod testMethod)
throws Exception
{
ICompilationUnit testSrc = testMethod.getCompilationUnit();
if (testSrc == null){
return null;
}
IType testType = testSrc.getTypes()[0];
// brute force since we can't assume a naming convention.
IMethod[] methods = src.getTypes()[0].getMethods();
for (IMethod method : methods){
String testName = "test" + StringUtils.capitalize(method.getElementName());
StringBuffer testNameWithParams = new StringBuffer(testName);
appendParameterNamesToMethodName(
testNameWithParams, method.getParameterTypes());
replaceIllegalCharacters(testNameWithParams);
StringBuffer nameWithParams = new StringBuffer(method.getElementName());
appendParameterNamesToMethodName(nameWithParams, method.getParameterTypes());
replaceIllegalCharacters(nameWithParams);
String[] methodNames = new String[]{
testNameWithParams.toString(),
nameWithParams.toString(),
};
for (String name : methodNames){
if (testMethod.equals(testType.getMethod(name, null))){
return method;
}
}
}
for (IMethod method : methods){
String testName = "test" + StringUtils.capitalize(method.getElementName());
String[] methodNames = new String[]{
testName,
method.getElementName(),
};
for (String name : methodNames){
if (testMethod.equals(testType.getMethod(name, null))){
return method;
}
}
}
return null;
}
/* from org.eclipse.jdt.junit.wizards.NewTestCaseWizardPageOne */
// CHECKSTYLE:OFF
private static final String QUESTION_MARK_TAG = "Q";
private static final String OF_TAG = "Of";
private static void appendParameterNamesToMethodName(
StringBuffer buffer, String[] parameters)
{
for (String parameter : parameters) {
final StringBuffer buf = new StringBuffer(
Signature.getSimpleName(
Signature.toString(
Signature.getElementType(parameter))));
final char character = buf.charAt(0);
if (buf.length() > 0 && !Character.isUpperCase(character)){
buf.setCharAt(0, Character.toUpperCase(character));
}
buffer.append(buf.toString());
for (int j = 0, arrayCount = Signature.getArrayCount(parameter);
j < arrayCount; j++)
{
buffer.append("Array");
}
}
}
private static void replaceIllegalCharacters(StringBuffer buffer)
{
char character = 0;
for (int index = buffer.length() - 1; index >= 0; index--) {
character = buffer.charAt(index);
if (Character.isWhitespace(character)){
buffer.deleteCharAt(index);
}else if (character == '<'){
buffer.replace(index, index + 1, OF_TAG);
}else if (character == '?'){
buffer.replace(index, index + 1, QUESTION_MARK_TAG);
// Skipping this for now so we don't rely on sun packages.
/*}else if (!Character.isJavaIdentifierPart(character)) {
// Check for surrogates
if (!UTF16.isSurrogate(character)) {
buffer.deleteCharAt(index);
}*/
}
}
}
// CHECKSTYLE:ON
}