/**
* 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.intellij;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import org.evosuite.intellij.util.AsyncGUINotifier;
import org.evosuite.intellij.util.EvoSuiteExecutor;
import org.evosuite.intellij.util.Utils;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* Created by arcuri on 9/24/14.
*/
public class EvoAction extends AnAction {
public EvoAction() {
super("Run EvoSuite",
"Open GUI dialog to configure and start running EvoSuite to generate JUnit tests automatically",
loadIcon());
}
private static Icon loadIcon(){
try {
Image image = ImageIO.read( EvoAction.class.getClassLoader().getResourceAsStream( "evosuite.png" ));
image = image.getScaledInstance(16, 16, java.awt.Image.SCALE_SMOOTH);
ImageIcon icon = new ImageIcon(image);
return icon;
} catch (IOException e) {
e.printStackTrace(); //should not really happen
}
return null;
}
public void actionPerformed(AnActionEvent event) {
String title = "EvoSuite Plugin";
Project project = event.getData(PlatformDataKeys.PROJECT);
ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
ToolWindow toolWindow = toolWindowManager.getToolWindow("EvoSuite");
final AsyncGUINotifier notifier = IntelliJNotifier.getNotifier(project);
if (EvoSuiteExecutor.getInstance().isAlreadyRunning()) {
Messages.showMessageDialog(project, "An instance of EvoSuite is already running",
title, Messages.getErrorIcon());
return;
}
Map<String,Set<String>> map = getCUTsToTest(event);
if(map==null || map.isEmpty() || map.values().stream().mapToInt(Set::size).sum() == 0){
Messages.showMessageDialog(project, "No '.java' file or non-empty source folder was selected in a valid module",
title, Messages.getErrorIcon());
return;
}
EvoStartDialog dialog = new EvoStartDialog();
dialog.initFields(project, EvoParameters.getInstance());
dialog.setModal(true);
dialog.setLocationRelativeTo(null);
//dialog.setLocationByPlatform(true);
dialog.pack();
dialog.setVisible(true);
if (dialog.isWasOK()) {
toolWindow.show(() -> notifier.clearConsole());
EvoParameters.getInstance().save(project);
EvoSuiteExecutor.getInstance().run(project,EvoParameters.getInstance(),map,notifier);
}
}
/**
*
*
* @return a map where key is a maven module root path, and value a list of full class names of CUTs
*/
private Map<String, Set<String>> getCUTsToTest(AnActionEvent event){
Map<String,Set<String>> map = new LinkedHashMap<>();
Project project = event.getData(PlatformDataKeys.PROJECT);
ModulesInfo modulesInfo = new ModulesInfo(project);
if (! modulesInfo.hasRoots()){
return null;
}
Set<String> alreadyHandled = new LinkedHashSet<>();
for(VirtualFile virtualFile : event.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY)){
String selectedFilePath = new File(virtualFile.getCanonicalPath()).getAbsolutePath();
recursiveHandle(map, modulesInfo, alreadyHandled, selectedFilePath);
}
return map;
}
private void recursiveHandle(Map<String,Set<String>> map, ModulesInfo modulesInfo, Set<String> alreadyHandled, String path){
if(alreadyHandled.contains(path)){
return;
}
Set<String> skip = handleSelectedPath(map, modulesInfo, path);
alreadyHandled.add(path);
for(String s : skip){
recursiveHandle(map, modulesInfo, alreadyHandled, s);
}
}
private Set<String> handleSelectedPath(Map<String, Set<String>> map, ModulesInfo modulesInfo, String selectedFilePath) {
/*
if Module A includes sub-module B, the source roots in B should
not be marked for A
*/
Set<String> skip = new LinkedHashSet<>();
String module = modulesInfo.getModuleFolder(selectedFilePath);
File selectedFile = new File(selectedFilePath);
if(module == null){
return skip;
}
Set<String> classes = map.getOrDefault(module, new LinkedHashSet<>());
String root = modulesInfo.getSourceRootForFile(selectedFilePath);
if(root == null){
/*
the chosen file is not in a source folder.
Need to check if its parent of any of them
*/
Set<String> included = modulesInfo.getIncludedSourceRoots(selectedFilePath);
if(included==null || included.isEmpty()){
return skip;
}
for(String otherModule : modulesInfo.getModulePathsView()) {
if(otherModule.length() > module.length() && otherModule.startsWith(module)) {
//the considered module has a sub-module
included.stream().filter(inc -> inc.startsWith(otherModule)).forEach(skip::add);
}
}
for(String sourceFolder : included){
if(skip.contains(sourceFolder)){
continue;
}
scanFolder(new File(sourceFolder),classes,sourceFolder);
}
} else {
if(!selectedFile.isDirectory()){
if(!selectedFilePath.endsWith(".java")){
// likely a resource file
return skip;
}
String name = getCUTName(selectedFilePath, root);
classes.add(name);
} else {
scanFolder(selectedFile,classes,root);
}
}
if(! classes.isEmpty()) {
map.put(module, classes);
}
return skip;
}
private void scanFolder(File file, Set<String> classes, String root) {
for(File child : file.listFiles()){
if(child.isDirectory()){
scanFolder(child, classes, root);
} else {
String path = child.getAbsolutePath();
if(path.endsWith(".java")){
String name = getCUTName(path,root);
classes.add(name);
}
}
}
}
private String getCUTName(String path, String root) {
String name = path.substring(root.length()+1, path.length() - ".java".length());
name = name.replace('/','.'); //posix
name = name.replace("\\", "."); // windows
return name;
}
}