blob: 82ed52031cb1acf3df1885d6f068b85c0c0df2ad [file] [log] [blame]
/*
* User: anna
* Date: 29-May-2008
*/
package com.intellij.coverage.actions;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.hint.ImplementationViewComponent;
import com.intellij.coverage.CoverageDataManager;
import com.intellij.coverage.CoverageSuite;
import com.intellij.coverage.CoverageSuitesBundle;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.PanelWithText;
import com.intellij.openapi.ui.popup.ComponentPopupBuilder;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.rt.coverage.data.LineCoverage;
import com.intellij.rt.coverage.data.LineData;
import com.intellij.ui.popup.NotLookupOrSearchCondition;
import com.intellij.util.ArrayUtil;
import com.intellij.util.PlatformIcons;
import com.intellij.util.Processor;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
public class ShowCoveringTestsAction extends AnAction {
private static final Logger LOG = Logger.getInstance("#" + ShowCoveringTestsAction.class.getName());
private final String myClassFQName;
private final LineData myLineData;
public ShowCoveringTestsAction(final String classFQName, LineData lineData) {
super("Show tests covering line", "Show tests covering line", PlatformIcons.TEST_SOURCE_FOLDER);
myClassFQName = classFQName;
myLineData = lineData;
}
public void actionPerformed(final AnActionEvent e) {
final DataContext context = e.getDataContext();
final Project project = CommonDataKeys.PROJECT.getData(context);
LOG.assertTrue(project != null);
final Editor editor = CommonDataKeys.EDITOR.getData(context);
LOG.assertTrue(editor != null);
final CoverageSuitesBundle currentSuite = CoverageDataManager.getInstance(project).getCurrentSuitesBundle();
LOG.assertTrue(currentSuite != null);
final File[] traceFiles = getTraceFiles(project);
final Set<String> tests = new HashSet<String>();
Runnable runnable = new Runnable() {
public void run() {
for (File traceFile : traceFiles) {
DataInputStream in = null;
try {
in = new DataInputStream(new FileInputStream(traceFile));
extractTests(traceFile, in, tests);
}
catch (Exception ex) {
LOG.error(traceFile.getName(), ex);
}
finally {
try {
in.close();
}
catch (IOException ex) {
LOG.error(ex);
}
}
}
}
};
if (ProgressManager.getInstance().runProcessWithProgressSynchronously(runnable, "Extract information about tests", false, project)) { //todo cache them? show nothing found message
final String[] testNames = ArrayUtil.toStringArray(tests);
Arrays.sort(testNames);
if (testNames.length == 0) {
HintManager.getInstance().showErrorHint(editor, "Failed to load covered tests");
return;
}
final List<PsiElement> elements = currentSuite.getCoverageEngine().findTestsByNames(testNames, project);
final ImplementationViewComponent component;
final String title = "Tests covering line " + myClassFQName + ":" + myLineData.getLineNumber();
final ComponentPopupBuilder popupBuilder;
if (!elements.isEmpty()) {
component = new ImplementationViewComponent(PsiUtilCore.toPsiElementArray(elements), 0);
popupBuilder = JBPopupFactory.getInstance().createComponentPopupBuilder(component, component.getPreferredFocusableComponent())
.setDimensionServiceKey(project, "ShowTestsPopup", false)
.setCouldPin(new Processor<JBPopup>() {
@Override
public boolean process(JBPopup popup) {
component.showInUsageView();
popup.cancel();
return false;
}
});
} else {
component = null;
final JPanel panel = new PanelWithText("Following test" + (testNames.length > 1 ? "s" : "") + " could not be found: " + StringUtil.join(testNames, ",").replace("_", "."));
popupBuilder = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, null);
}
final JBPopup popup = popupBuilder.setRequestFocusCondition(project, NotLookupOrSearchCondition.INSTANCE)
.setProject(project)
.setResizable(true)
.setMovable(true)
.setTitle(title)
.createPopup();
popup.showInBestPositionFor(editor);
if (component != null) {
component.setHint(popup, title);
}
}
}
private void extractTests(final File traceFile, final DataInputStream in, final Set<String> tests) throws IOException {
long traceSize = in.readInt();
for (int i = 0; i < traceSize; i++) {
final String className = in.readUTF();
final int linesSize = in.readInt();
for(int l = 0; l < linesSize; l++) {
final int line = in.readInt();
if (Comparing.strEqual(className, myClassFQName)) {
if (myLineData.getLineNumber() == line) {
tests.add(FileUtil.getNameWithoutExtension(traceFile));
return;
}
}
}
}
}
@Override
public void update(final AnActionEvent e) {
final Presentation presentation = e.getPresentation();
presentation.setEnabled(false);
if (myLineData != null && myLineData.getStatus() != LineCoverage.NONE) {
final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
if (project != null) {
final File[] files = getTraceFiles(project);
if (files != null && files.length > 0) {
presentation.setEnabled(CoverageDataManager.getInstance(project).getCurrentSuitesBundle().isCoverageByTestEnabled());
}
}
}
}
@Nullable
private static File[] getTraceFiles(Project project) {
final CoverageSuitesBundle currentSuite = CoverageDataManager.getInstance(project).getCurrentSuitesBundle();
if (currentSuite == null) return null;
final List<File> files = new ArrayList<File>();
for (CoverageSuite coverageSuite : currentSuite.getSuites()) {
final String filePath = coverageSuite.getCoverageDataFileName();
final String dirName = FileUtil.getNameWithoutExtension(new File(filePath).getName());
final File parentDir = new File(filePath).getParentFile();
final File tracesDir = new File(parentDir, dirName);
final File[] suiteFiles = tracesDir.listFiles();
if (suiteFiles != null) {
Collections.addAll(files, suiteFiles);
}
}
return files.isEmpty() ? null : files.toArray(new File[files.size()]);
}
}