exclude coverage patterns (IDEA-82234)

This commit is contained in:
Anna.Kozlova
2017-07-04 19:41:41 +02:00
parent e122c56621
commit 027062a52a
8 changed files with 164 additions and 50 deletions
@@ -38,6 +38,10 @@ public class ClassFilter implements JDOMExternalizable, Cloneable{
public String PATTERN = "";
@Attribute("enabled")
public boolean ENABLED = true;
@Attribute("include")
public boolean INCLUDE = true;
private Matcher myMatcher; // to speedup matching
public ClassFilter() {
@@ -58,6 +62,11 @@ public class ClassFilter implements JDOMExternalizable, Cloneable{
return ENABLED;
}
@Transient
public boolean isInclude() {
return INCLUDE;
}
public void setPattern(String pattern) {
if (pattern != null && !pattern.equals(PATTERN)) {
PATTERN = pattern;
@@ -68,6 +77,10 @@ public class ClassFilter implements JDOMExternalizable, Cloneable{
ENABLED = value;
}
public void setInclude(boolean value) {
INCLUDE = value;
}
public String toString() {
return getPattern();
}
@@ -79,7 +92,11 @@ public class ClassFilter implements JDOMExternalizable, Cloneable{
@Override
public void writeExternal(Element element) throws WriteExternalException {
DefaultJDOMExternalizer.writeExternal(this, element);
element.addContent(new Element("option").setAttribute("name", "PATTERN").setAttribute("value", PATTERN));
element.addContent(new Element("option").setAttribute("name", "ENABLED").setAttribute("value", String.valueOf(ENABLED)));
if (!INCLUDE) {
element.addContent(new Element("option").setAttribute("name", "INCLUDE").setAttribute("value", "false"));
}
}
public boolean equals(Object o) {
@@ -48,12 +48,14 @@ import java.util.LinkedList;
import java.util.List;
public class ClassFilterEditor extends JPanel implements ComponentWithEmptyText {
private static final String IS_ACTIVE = "Is Active";
protected JBTable myTable = null;
protected FilterTableModel myTableModel = null;
protected final Project myProject;
private final ClassFilter myChooserFilter;
@Nullable
private final String myPatternsHelpId;
private final boolean myExcludeAllowed;
private String classDelimiter = "$";
public ClassFilterEditor(Project project) {
@@ -65,8 +67,13 @@ public class ClassFilterEditor extends JPanel implements ComponentWithEmptyText
}
public ClassFilterEditor(Project project, ClassFilter classFilter, @Nullable String patternsHelpId) {
this(project, classFilter, patternsHelpId, false);
}
public ClassFilterEditor(Project project, ClassFilter classFilter, @Nullable String patternsHelpId, boolean excludeAllowed) {
super(new BorderLayout());
myPatternsHelpId = patternsHelpId;
myExcludeAllowed = excludeAllowed;
myTable = new JBTable();
final ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myTable)
@@ -111,14 +118,27 @@ public class ClassFilterEditor extends JPanel implements ComponentWithEmptyText
myTable.setModel(myTableModel);
myTable.setShowGrid(false);
myTable.setIntercellSpacing(new Dimension(0, 0));
myTable.setTableHeader(null);
myTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
myTable.setColumnSelectionAllowed(false);
myTable.setPreferredScrollableViewportSize(new Dimension(200, myTable.getRowHeight() * JBTable.PREFERRED_SCROLLABLE_VIEWPORT_HEIGHT_IN_ROWS));
TableColumnModel columnModel = myTable.getColumnModel();
TableColumn column = columnModel.getColumn(FilterTableModel.CHECK_MARK);
TableUtil.setupCheckboxColumn(column);
int preferredWidth;
if (!excludeAllowed) {
myTable.setTableHeader(null);
preferredWidth = 0;
}
else {
JTableHeader tableHeader = myTable.getTableHeader();
final FontMetrics fontMetrics = tableHeader.getFontMetrics(tableHeader.getFont());
preferredWidth = fontMetrics.stringWidth(IS_ACTIVE) + 20;
TableColumn includeColumn = columnModel.getColumn(FilterTableModel.INCLUDE_MARK);
includeColumn.setCellRenderer(new EnabledCellRenderer(myTable.getDefaultRenderer(Boolean.class)));
TableUtil.setupCheckboxColumn(includeColumn, preferredWidth);
}
TableUtil.setupCheckboxColumn(column, preferredWidth);
column.setCellRenderer(new EnabledCellRenderer(myTable.getDefaultRenderer(Boolean.class)));
columnModel.getColumn(FilterTableModel.FILTER).setCellRenderer(new FilterCellRenderer());
@@ -177,6 +197,7 @@ public class ClassFilterEditor extends JPanel implements ComponentWithEmptyText
private final List<com.intellij.ui.classFilter.ClassFilter> myFilters = new LinkedList<>();
public static final int CHECK_MARK = 0;
public static final int FILTER = 1;
public static final int INCLUDE_MARK = 2;
public final void setFilters(com.intellij.ui.classFilter.ClassFilter[] filters) {
myFilters.clear();
@@ -216,9 +237,23 @@ public class ClassFilterEditor extends JPanel implements ComponentWithEmptyText
}
public int getColumnCount() {
if (myExcludeAllowed) {
return 3;
}
return 2;
}
@Override
public String getColumnName(int column) {
if (column == FILTER) {
return "Pattern";
}
if (column == INCLUDE_MARK) {
return "Include";
}
return IS_ACTIVE;
}
public Object getValueAt(int rowIndex, int columnIndex) {
com.intellij.ui.classFilter.ClassFilter filter = myFilters.get(rowIndex);
if (columnIndex == FILTER) {
@@ -227,6 +262,9 @@ public class ClassFilterEditor extends JPanel implements ComponentWithEmptyText
if (columnIndex == CHECK_MARK) {
return filter.isEnabled();
}
if (columnIndex == INCLUDE_MARK) {
return filter.isInclude();
}
return null;
}
@@ -238,12 +276,15 @@ public class ClassFilterEditor extends JPanel implements ComponentWithEmptyText
else if (columnIndex == CHECK_MARK) {
filter.setEnabled(aValue == null || ((Boolean)aValue).booleanValue());
}
else if (columnIndex == INCLUDE_MARK) {
filter.setInclude(aValue == null || ((Boolean)aValue).booleanValue());
}
// fireTableCellUpdated(rowIndex, columnIndex);
fireTableRowsUpdated(rowIndex, rowIndex);
}
public Class getColumnClass(int columnIndex) {
if (columnIndex == CHECK_MARK) {
if (columnIndex == CHECK_MARK || columnIndex == INCLUDE_MARK) {
return Boolean.class;
}
return super.getColumnClass(columnIndex);
@@ -28,7 +28,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@@ -69,11 +68,16 @@ public class IDEACoverageRunner extends JavaCoverageRunner {
SimpleJavaParameters parameters,
boolean collectLineInfo,
boolean isSampling) {
appendCoverageArgument(sessionDataFilePath, patterns, parameters, collectLineInfo, isSampling, null);
appendCoverageArgument(sessionDataFilePath, patterns, null, parameters, collectLineInfo, isSampling, null);
}
public void appendCoverageArgument(final String sessionDataFilePath, final String[] patterns, final SimpleJavaParameters javaParameters,
final boolean collectLineInfo, final boolean isSampling, @Nullable String sourceMapPath) {
public void appendCoverageArgument(final String sessionDataFilePath,
final String[] patterns,
final String[] excludePatterns,
final SimpleJavaParameters javaParameters,
final boolean collectLineInfo,
final boolean isSampling,
@Nullable String sourceMapPath) {
StringBuilder argument = new StringBuilder("-javaagent:");
final String agentPath = PathUtil.getJarPathForClass(ProjectData.class);
final String parentPath = handleSpacesInPath(agentPath, file -> {
@@ -97,13 +101,11 @@ public class IDEACoverageRunner extends JavaCoverageRunner {
write2file(tempFile, sourceMapPath);
}
if (patterns != null) {
for (String coveragePattern : patterns) {
coveragePattern = coveragePattern.replace("$", "\\$").replace(".", "\\.").replaceAll("\\*", ".*");
if (!coveragePattern.endsWith(".*")) { //include inner classes
coveragePattern += "(\\$.*)*";
}
write2file(tempFile, coveragePattern);
}
writePatterns(tempFile, patterns);
}
if (excludePatterns != null) {
write2file(tempFile, "-exclude");
writePatterns(tempFile, excludePatterns);
}
argument.append(tempFile.getCanonicalPath());
}
@@ -115,6 +117,16 @@ public class IDEACoverageRunner extends JavaCoverageRunner {
javaParameters.getVMParametersList().add(argument.toString());
}
private static void writePatterns(File tempFile, String[] patterns) throws IOException {
for (String coveragePattern : patterns) {
coveragePattern = coveragePattern.replace("$", "\\$").replace(".", "\\.").replaceAll("\\*", ".*");
if (!coveragePattern.endsWith(".*")) { //include inner classes
coveragePattern += "(\\$.*)*";
}
write2file(tempFile, coveragePattern);
}
}
public String getPresentableName() {
return "IntelliJ IDEA";
@@ -128,7 +128,7 @@ public class JavaCoverageEngine extends CoverageEngine {
boolean tracingEnabled,
boolean trackTestFolders, Project project) {
return createSuite(covRunner, name, coverageDataFileProvider, filters, lastCoverageTimeStamp, coverageByTestEnabled,
return createSuite(covRunner, name, coverageDataFileProvider, filters, null, lastCoverageTimeStamp, coverageByTestEnabled,
tracingEnabled, trackTestFolders, project);
}
@@ -141,6 +141,7 @@ public class JavaCoverageEngine extends CoverageEngine {
final JavaCoverageEnabledConfiguration javaConfig = (JavaCoverageEnabledConfiguration)config;
return createSuite(covRunner, name, coverageDataFileProvider,
javaConfig.getPatterns(),
javaConfig.getExcludePatterns(),
new Date().getTime(),
javaConfig.isTrackPerTestCoverage() && !javaConfig.isSampling(),
!javaConfig.isSampling(),
@@ -186,8 +187,7 @@ public class JavaCoverageEngine extends CoverageEngine {
for (CoverageSuite coverageSuite : suite.getSuites()) {
final JavaCoverageSuite javaSuite = (JavaCoverageSuite)coverageSuite;
final List<PsiPackage> packages = javaSuite.getCurrentSuitePackages(project);
if (isUnderFilteredPackages((PsiClassOwner)psiFile, packages)) {
if (javaSuite.isPackageFiltered(ReadAction.compute(() ->((PsiClassOwner)psiFile).getPackageName()))) {
return true;
} else {
final List<PsiClass> classes = javaSuite.getCurrentSuiteClasses(project);
@@ -242,16 +242,6 @@ public class JavaCoverageEngine extends CoverageEngine {
return ModuleRootManager.getInstance(module).getSourceRoots(rootType).stream().anyMatch(vFile -> !compilerManager.isExcludedFromCompilation(vFile));
}
public static boolean isUnderFilteredPackages(final PsiClassOwner javaFile, final List<PsiPackage> packages) {
final PsiPackage hisPackage =
ReadAction.compute(() -> JavaPsiFacade.getInstance(javaFile.getProject()).findPackage(javaFile.getPackageName()));
if (hisPackage == null) return false;
for (PsiPackage aPackage : packages) {
if (PsiTreeUtil.isAncestor(aPackage, hisPackage, false)) return true;
}
return false;
}
@Nullable
public List<Integer> collectSrcLinesForUntouchedFile(@NotNull final File classFile, @NotNull final CoverageSuitesBundle suite) {
final List<Integer> uncoveredLines = new ArrayList<>();
@@ -554,11 +544,12 @@ public class JavaCoverageEngine extends CoverageEngine {
protected JavaCoverageSuite createSuite(CoverageRunner acceptedCovRunner,
String name, CoverageFileProvider coverageDataFileProvider,
String[] filters,
String[] excludePatterns,
long lastCoverageTimeStamp,
boolean coverageByTestEnabled,
boolean tracingEnabled,
boolean trackTestFolders, Project project) {
return new JavaCoverageSuite(name, coverageDataFileProvider, filters, lastCoverageTimeStamp, coverageByTestEnabled, tracingEnabled,
return new JavaCoverageSuite(name, coverageDataFileProvider, filters, excludePatterns, lastCoverageTimeStamp, coverageByTestEnabled, tracingEnabled,
trackTestFolders, acceptedCovRunner, this, project);
}
@@ -47,8 +47,13 @@ public abstract class JavaCoverageRunner extends CoverageRunner {
public abstract void appendCoverageArgument(final String sessionDataFilePath, @Nullable final String[] patterns, final SimpleJavaParameters parameters,
final boolean collectLineInfo, final boolean isSampling);
public void appendCoverageArgument(final String sessionDataFilePath, @Nullable final String[] patterns, final SimpleJavaParameters parameters,
final boolean collectLineInfo, final boolean isSampling, String sourceMapPath) {
public void appendCoverageArgument(final String sessionDataFilePath,
@Nullable final String[] patterns,
String[] excludePatterns,
final SimpleJavaParameters parameters,
final boolean collectLineInfo,
final boolean isSampling,
String sourceMapPath) {
appendCoverageArgument(sessionDataFilePath, patterns, parameters, collectLineInfo, isSampling);
}
@@ -49,10 +49,12 @@ public class JavaCoverageSuite extends BaseCoverageSuite {
@NonNls
private static final String FILTER = "FILTER";
private static final String EXCLUDED_FILTER = "EXCLUDED_FILTER";
@NonNls
private static final String MERGE_SUITE = "MERGE_SUITE";
@NonNls
private static final String COVERAGE_RUNNER = "RUNNER";
private String[] myExcludePatterns;
private final CoverageEngine myCoverageEngine;
//read external only
@@ -64,6 +66,7 @@ public class JavaCoverageSuite extends BaseCoverageSuite {
public JavaCoverageSuite(final String name,
final CoverageFileProvider coverageDataFileProvider,
final String[] filters,
final String[] excludePatterns,
final long lastCoverageTimeStamp,
final boolean coverageByTestEnabled,
final boolean tracingEnabled,
@@ -76,14 +79,24 @@ public class JavaCoverageSuite extends BaseCoverageSuite {
coverageRunner != null ? coverageRunner : CoverageRunner.getInstance(IDEACoverageRunner.class), project);
myFilters = filters;
myExcludePatterns = excludePatterns;
myCoverageEngine = coverageSupportProvider;
}
@NotNull
public String[] getFilteredPackageNames() {
if (myFilters == null || myFilters.length == 0) return ArrayUtil.EMPTY_STRING_ARRAY;
return getPackageNames(myFilters);
}
@NotNull
public String[] getExcludedPackageNames() {
return getPackageNames(myExcludePatterns);
}
private static String[] getPackageNames(String[] filters) {
if (filters == null || filters.length == 0) return ArrayUtil.EMPTY_STRING_ARRAY;
List<String> result = new ArrayList<>();
for (String filter : myFilters) {
for (String filter : filters) {
if (filter.equals("*")) {
result.add(""); //default package
}
@@ -94,9 +107,19 @@ public class JavaCoverageSuite extends BaseCoverageSuite {
@NotNull
public String[] getFilteredClassNames() {
if (myFilters == null) return ArrayUtil.EMPTY_STRING_ARRAY;
return getClassNames(myFilters);
}
@NotNull
public String[] getExcludedClassNames() {
return getClassNames(myFilters);
}
@NotNull
private static String[] getClassNames(final String[] filters) {
if (filters == null) return ArrayUtil.EMPTY_STRING_ARRAY;
List<String> result = new ArrayList<>();
for (String filter : myFilters) {
for (String filter : filters) {
if (!filter.equals("*") && !filter.endsWith(".*")) result.add(filter);
}
return ArrayUtil.toStringArray(result);
@@ -106,13 +129,8 @@ public class JavaCoverageSuite extends BaseCoverageSuite {
super.readExternal(element);
// filters
final List children = element.getChildren(FILTER);
List<String> filters = new ArrayList<>();
//noinspection unchecked
for (Element child : ((Iterable<Element>)children)) {
filters.add(child.getValue());
}
myFilters = filters.isEmpty() ? null : ArrayUtil.toStringArray(filters);
myFilters = readFilters(element, FILTER);
myExcludePatterns = readFilters(element, EXCLUDED_FILTER);
// suite to merge
mySuiteToMerge = element.getAttributeValue(MERGE_SUITE);
@@ -122,20 +140,34 @@ public class JavaCoverageSuite extends BaseCoverageSuite {
}
}
private static String[] readFilters(Element element, final String tagName) {
final List<Element> children = element.getChildren(tagName);
List<String> filters = new ArrayList<>();
for (Element child : children) {
filters.add(child.getValue());
}
return filters.isEmpty() ? null : ArrayUtil.toStringArray(filters);
}
public void writeExternal(final Element element) throws WriteExternalException {
super.writeExternal(element);
if (mySuiteToMerge != null) {
element.setAttribute(MERGE_SUITE, mySuiteToMerge);
}
if (myFilters != null) {
for (String filter : myFilters) {
final Element filterElement = new Element(FILTER);
writeFilters(element, myFilters, FILTER);
writeFilters(element, myExcludePatterns, EXCLUDED_FILTER);
final CoverageRunner coverageRunner = getRunner();
element.setAttribute(COVERAGE_RUNNER, coverageRunner != null ? coverageRunner.getId() : "emma");
}
private static void writeFilters(Element element, final String[] filters, final String tagName) {
if (filters != null) {
for (String filter : filters) {
final Element filterElement = new Element(tagName);
filterElement.setText(filter);
element.addContent(filterElement);
}
}
final CoverageRunner coverageRunner = getRunner();
element.setAttribute(COVERAGE_RUNNER, coverageRunner != null ? coverageRunner.getId() : "emma");
}
@Nullable
@@ -187,6 +219,9 @@ public class JavaCoverageSuite extends BaseCoverageSuite {
}
public boolean isPackageFiltered(final String packageFQName) {
for (String name : getExcludedPackageNames()) {
if (packageFQName.equals(name) || packageFQName.startsWith(name + ".")) return false;
}
final String[] filteredPackageNames = getFilteredPackageNames();
for (final String packName : filteredPackageNames) {
if (packName.equals(packageFQName) || packageFQName.startsWith(packName) && packageFQName.charAt(packName.length()) == '.') {
@@ -86,7 +86,7 @@ public class CoverageConfigurable extends SettingsEditor<RunConfigurationBase> {
if (aClass.getContainingClass() != null) return false;
return true;
}
});
}, null, true);
}
protected void addPatternFilter() {
@@ -87,6 +87,7 @@ public class JavaCoverageEnabledConfiguration extends CoverageEnabledConfigurati
((JavaCoverageRunner)runner).appendCoverageArgument(new File(path).getCanonicalPath(),
getPatterns(),
getExcludePatterns(),
javaParameters,
isTrackPerTestCoverage() && !isSampling(),
isSampling(),
@@ -116,7 +117,19 @@ public class JavaCoverageEnabledConfiguration extends CoverageEnabledConfigurati
if (myCoveragePatterns != null) {
List<String> patterns = new ArrayList<>();
for (ClassFilter coveragePattern : myCoveragePatterns) {
if (coveragePattern.isEnabled()) patterns.add(coveragePattern.getPattern());
if (coveragePattern.isEnabled() && coveragePattern.isInclude()) patterns.add(coveragePattern.getPattern());
}
return ArrayUtil.toStringArray(patterns);
}
return null;
}
@Nullable
public String [] getExcludePatterns() {
if (myCoveragePatterns != null) {
List<String> patterns = new ArrayList<>();
for (ClassFilter coveragePattern : myCoveragePatterns) {
if (coveragePattern.isEnabled() && !coveragePattern.isInclude()) patterns.add(coveragePattern.getPattern());
}
return ArrayUtil.toStringArray(patterns);
}
@@ -205,7 +218,7 @@ public class JavaCoverageEnabledConfiguration extends CoverageEnabledConfigurati
if (myCoveragePatterns != null) {
for (ClassFilter pattern : myCoveragePatterns) {
@NonNls final Element patternElement = new Element(COVERAGE_PATTERN_ELEMENT_NAME);
DefaultJDOMExternalizer.writeExternal(pattern, patternElement);
pattern.writeExternal(patternElement);
element.addContent(patternElement);
}
}