/**
* Copyright (C) 2010-2017 Gordon Fraser, Andrea Arcuri and EvoSuite
* contributors
*
* This file is part of EvoSuite.
*
* EvoSuite is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3.0 of the License, or
* (at your option) any later version.
*
* EvoSuite 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
* Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with EvoSuite. If not, see <http://www.gnu.org/licenses/>.
*/
package org.evosuite.eclipse.popup.actions;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.ToolFactory;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.evosuite.Properties;
import org.evosuite.eclipse.Activator;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.charset.Charset;
public class TestExtensionJob extends TestGenerationJob {
private File tempDir;
private ArrayList<String> newTests;
private List<MethodDeclaration> newMethods = null;
private List<ImportDeclaration> newImports = null;
public TestExtensionJob(Shell shell, final IResource target, String targetClass,
String testClass) {
super(shell, target, targetClass, testClass);
newTests = new ArrayList<String>();
writeAllMarkers = false;
try {
tempDir = setupTempDir();
} catch (IOException e) {
e.printStackTrace();
tempDir = new File("/tmp");
}
}
protected static String readFile(String path, Charset encoding) throws IOException
{
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
protected CompilationUnit parseJavaFile(String unitName, String fileName)
throws IOException {
String fileContents = readFile(fileName, Charset.defaultCharset());
ASTParser parser = ASTParser.newParser(AST.JLS8);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setStatementsRecovery(true);
Map<String, String> COMPILER_OPTIONS = new HashMap<String, String>(JavaCore.getOptions());
COMPILER_OPTIONS.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7);
COMPILER_OPTIONS.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7);
COMPILER_OPTIONS.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7);
//parser.setResolveBindings(true);
//parser.setBindingsRecovery(true);
parser.setUnitName(unitName);
String[] encodings = { ENCODING };
String[] classpaths = { classPath };
String[] sources = { new File(suiteClass).getParent() };
parser.setEnvironment(classpaths, sources, encodings, true);
parser.setSource(fileContents.toCharArray());
CompilationUnit compilationUnit = (CompilationUnit) parser.createAST(null);
Set<String> problems = new HashSet<String>();
for (IProblem problem : compilationUnit.getProblems()) {
problems.add(problem.getSourceLineNumber() +": "+problem.toString());
}
if (!problems.isEmpty()) {
System.out.println("Got " + problems.size()
+ " problems compiling the source file: ");
for (String problem : problems) {
System.out.println(problem);
}
}
return compilationUnit;
}
protected String getTestClassName() {
String path = tempDir.getAbsolutePath();
path += File.separator;
path += targetClass.replace('.', '/');
// int pos = path.lastIndexOf(File.separator);
// path = path.substring(0, pos+1) + "Test" + path.substring(pos+1);
path += Properties.JUNIT_SUFFIX;
path += ".java";
return path;
}
protected void loadTestSuiteContent(String fileName) throws IOException {
System.out.println("Trying to parse file: "+fileName);
CompilationUnit compilationUnit = parseJavaFile(suiteClass, fileName);
MethodExtractingVisitor methodVisitor = new MethodExtractingVisitor();
ImportDeclarationVisitor importVisitor = new ImportDeclarationVisitor();
compilationUnit.accept(methodVisitor);
compilationUnit.accept(importVisitor);
newMethods = methodVisitor.getMethods();
newImports = importVisitor.getImports();
}
protected File setupTempDir() throws IOException {
File temp = File.createTempFile("temp", Long.toString(System.nanoTime()));
if (!(temp.delete())) {
throw new IOException("Could not delete temp file: " + temp.getAbsolutePath());
}
if (!(temp.mkdir())) {
throw new IOException("Could not create temp directory: "
+ temp.getAbsolutePath());
}
return temp;
}
/* (non-Javadoc)
* @see org.evosuite.eclipse.popup.actions.TestGenerationJob#getAdditionalParameters()
*/
@Override
public List<String> getAdditionalParameters() {
List<String> parameters = new ArrayList<String>();
parameters.add("-Dtest_dir=" + tempDir.getAbsolutePath());
parameters.add("-Djunit_extend="+suiteClass);
parameters.add("-Dselected_junit="+suiteClass);
parameters.add("-Dtest_factory=JUnit");
System.out.println("Providing output dir: "+tempDir.getAbsolutePath());
return parameters;
}
private boolean hasMethod(IType classType, String methodName) throws JavaModelException {
for(IMethod method : classType.getMethods()) {
if(method.getElementName().equals(methodName))
return true;
}
return false;
}
private boolean hasImport(ICompilationUnit compilationUnit, ImportDeclaration importDecl) throws JavaModelException {
IImportDeclaration[] imports = compilationUnit.getImports();
String importName = importDecl.getName().toString();
for(IImportDeclaration imp : imports) {
if(imp.getElementName().equals(importName))
return true;
}
return false;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
IStatus status = super.run(monitor);
newTests.clear();
IJavaElement element = JavaCore.create(target);
if (element.getElementType() == IJavaElement.COMPILATION_UNIT) {
ICompilationUnit compilationUnit = (ICompilationUnit) element;
CodeFormatter formatter = ToolFactory.createCodeFormatter(null);
try {
if (compilationUnit.getTypes().length == 0) {
System.out.println("The compilation unit is empty :|");
return status;
}
IType classType = compilationUnit.getTypes()[0];
// new tests
loadTestSuiteContent(getTestClassName());
for(ImportDeclaration newImport : newImports) {
if(! hasImport(compilationUnit, newImport)) {
int flag = newImport.isStatic() ? Flags.AccStatic : Flags.AccDefault;
String strImport = newImport.getName().toString();
// Names of onDemand import declarations do not contain the '*'
if (newImport.isOnDemand()) strImport += ".*";
compilationUnit.createImport(strImport, null, flag, null);
}
}
for(MethodDeclaration newMethod : newMethods) {
if(hasMethod(classType, newMethod.getName().toString())) {
System.out.println("Test suite already contains method called: " + newMethod.getName());
int num = 1;
newMethod.setName(newMethod.getAST().newSimpleName(newMethod.getName().toString()+"_"+num));
while(hasMethod(classType, newMethod.getName().toString())) {
num += 1;
String name = newMethod.getName().toString();
newMethod.setName(newMethod.getAST().newSimpleName(name.substring(0, name.length() - 2)+"_"+num));
}
}
String testContent = newMethod.toString();
IMethod methodToAdd = classType.createMethod(testContent, null, false,
new NullProgressMonitor());
ISourceRange range = methodToAdd.getSourceRange();
TextEdit indent_edit = formatter.format(CodeFormatter.K_COMPILATION_UNIT,
classType.getCompilationUnit().getSource(), range.getOffset(), range.getLength(), 0, null);
classType.getCompilationUnit().applyTextEdit(indent_edit, null);
newTests.add(newMethod.getName().toString());
}
classType.getCompilationUnit().commitWorkingCopy(false, null);
// write markers
writeMarkersExtendedTestSuite();
} catch (JavaModelException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return status;
}
private void writeMarkersExtendedTestSuite() {
System.out.println("********** Writing markers in test suite" + suiteClass);
String testClassFileName = getSuiteFileName(suiteClass);
final IFile fileTestClass = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(testClassFileName));
String fileContents = readFileToString(testClassFileName);
ASTParser parser = ASTParser.newParser(AST.JLS8);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setStatementsRecovery(true);
Map<String, String> COMPILER_OPTIONS = new HashMap<String, String>(JavaCore.getOptions());
COMPILER_OPTIONS.put(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_7);
COMPILER_OPTIONS.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_7);
COMPILER_OPTIONS.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_7);
parser.setUnitName(suiteClass);
String[] encodings = { ENCODING };
String[] classpaths = { classPath };
String[] sources = { new File(testClassFileName).getParent() };
parser.setEnvironment(classpaths, sources, encodings, true);
parser.setSource(fileContents.toCharArray());
CompilationUnit compilationUnit = (CompilationUnit) parser.createAST(null);
MethodExtractingVisitor visitor = new MethodExtractingVisitor();
compilationUnit.accept(visitor);
List<MethodDeclaration> methods = visitor.getMethods();
Display.getDefault().syncExec(new Runnable() {
@Override
public void run() {
IWorkbenchWindow iw = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
IWorkbenchPage page = iw.getActivePage();
try {
IDE.openEditor(page, fileTestClass, true);
} catch (PartInitException e1) {
System.out.println("Could not open test suite");
e1.printStackTrace();
}
}
});
if (Activator.markersEnabled()) {
for (MethodDeclaration m : methods) {
if (newTests.contains(m.getName().toString())) {
int lineNumber = compilationUnit.getLineNumber(m.getStartPosition());
try {
IMarker mark = fileTestClass.createMarker("EvoSuiteQuickFixes.newtestmarker");
mark.setAttribute(IMarker.MESSAGE, "This test case needs to be verified.");
mark.setAttribute(IMarker.LINE_NUMBER, lineNumber);
mark.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
mark.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
mark.setAttribute(IMarker.LOCATION, fileTestClass.getName());
mark.setAttribute(IMarker.CHAR_START, m.getStartPosition());
mark.setAttribute(IMarker.CHAR_END, m.getStartPosition() + 1);
} catch (CoreException e) {
e.printStackTrace();
}
}
}
}
}
}