diff --git a/plugins/coverage-common/src/com/intellij/coverage/BaseCoverageSuite.java b/plugins/coverage-common/src/com/intellij/coverage/BaseCoverageSuite.java index ef8794d1a4ef..70ee07e66400 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/BaseCoverageSuite.java +++ b/plugins/coverage-common/src/com/intellij/coverage/BaseCoverageSuite.java @@ -20,94 +20,71 @@ import java.io.File; import java.lang.ref.SoftReference; import java.util.concurrent.TimeUnit; -public abstract class BaseCoverageSuite implements CoverageSuite, JDOMExternalizable { +public abstract class BaseCoverageSuite implements CoverageSuite, JDOMExternalizable { private static final Logger LOG = Logger.getInstance(BaseCoverageSuite.class.getName()); - @NonNls - private static final String FILE_PATH = "FILE_PATH"; - - @NonNls - private static final String SOURCE_PROVIDER = "SOURCE_PROVIDER"; - - @NonNls - private static final String MODIFIED_STAMP = "MODIFIED"; - - @NonNls - private static final String NAME_ATTRIBUTE = "NAME"; - - @NonNls - private static final String COVERAGE_RUNNER = "RUNNER"; - - @NonNls - private static final String COVERAGE_BY_TEST_ENABLED_ATTRIBUTE_NAME = "COVERAGE_BY_TEST_ENABLED"; - - @NonNls - private static final String BRANCH_COVERAGE_ATTRIBUTE_NAME = "COVERAGE_TRACING_ENABLED"; + private static final @NonNls String FILE_PATH = "FILE_PATH"; + private static final @NonNls String SOURCE_PROVIDER = "SOURCE_PROVIDER"; + private static final @NonNls String MODIFIED_STAMP = "MODIFIED"; + private static final @NonNls String NAME_ATTRIBUTE = "NAME"; + private static final @NonNls String COVERAGE_RUNNER = "RUNNER"; + private static final @NonNls String COVERAGE_BY_TEST_ENABLED_ATTRIBUTE_NAME = "COVERAGE_BY_TEST_ENABLED"; + private static final @NonNls String BRANCH_COVERAGE_ATTRIBUTE_NAME = "COVERAGE_TRACING_ENABLED"; private SoftReference myCoverageData = new SoftReference<>(null); private String myName; - private long myLastCoverageTimeStamp; - private boolean myCoverageByTestEnabled; - private CoverageRunner myRunner; - private CoverageFileProvider myCoverageDataFileProvider; - private boolean myTrackTestFolders; - private boolean myBranchCoverage; private Project myProject; + protected CoverageRunner myRunner; + private CoverageFileProvider myCoverageDataFileProvider; + private long myTimestamp; - private RunConfigurationBase myConfiguration; + private RunConfigurationBase myConfiguration; - protected BaseCoverageSuite() { - } + protected boolean myTrackTestFolders = false; + protected boolean myBranchCoverage = false; + protected boolean myCoverageByTestEnabled = false; - public BaseCoverageSuite(final String name, - @Nullable final CoverageFileProvider fileProvider, - final long lastCoverageTimeStamp, - final boolean coverageByTestEnabled, - final boolean branchCoverage, - final boolean trackTestFolders, - final CoverageRunner coverageRunner) { - this(name, fileProvider, lastCoverageTimeStamp, coverageByTestEnabled, branchCoverage, trackTestFolders, coverageRunner, null); - } - public BaseCoverageSuite(final String name, - @Nullable final CoverageFileProvider fileProvider, - final long lastCoverageTimeStamp, - final boolean coverageByTestEnabled, - final boolean branchCoverage, - final boolean trackTestFolders, - final CoverageRunner coverageRunner, - Project project) { - myCoverageDataFileProvider = fileProvider; + protected BaseCoverageSuite() { } + + public BaseCoverageSuite(@NotNull String name, + @Nullable Project project, + @Nullable CoverageRunner runner, + @Nullable CoverageFileProvider fileProvider, + long timestamp) { myName = name; - myLastCoverageTimeStamp = lastCoverageTimeStamp; - myCoverageByTestEnabled = coverageByTestEnabled; + myProject = project; + myRunner = runner; + myCoverageDataFileProvider = fileProvider; + myTimestamp = timestamp; + } + + /** + * @deprecated Use {@link BaseCoverageSuite#BaseCoverageSuite(String, Project, CoverageRunner, CoverageFileProvider, long)} + */ + @Deprecated + public BaseCoverageSuite(String name, + @Nullable CoverageFileProvider fileProvider, + long timestamp, + boolean coverageByTestEnabled, + boolean branchCoverage, + boolean trackTestFolders, + CoverageRunner coverageRunner, + @Nullable Project project) { + this(name, project, coverageRunner, fileProvider, timestamp); myTrackTestFolders = trackTestFolders; myBranchCoverage = branchCoverage; - myRunner = coverageRunner; - myProject = project; + myCoverageByTestEnabled = coverageByTestEnabled; } - @Nullable - public static CoverageRunner readRunnerAttribute(Element element) { - final String runner = element.getAttributeValue(COVERAGE_RUNNER); - if (runner != null) { - for (CoverageRunner coverageRunner : CoverageRunner.EP_NAME.getExtensionList()) { - if (Comparing.strEqual(coverageRunner.getId(), runner)) { - return coverageRunner; - } - } - } - return null; - } - - public static CoverageFileProvider readDataFileProviderAttribute(Element element) { - final String sourceProvider = element.getAttributeValue(SOURCE_PROVIDER); - final String relativePath = FileUtil.toSystemDependentName(element.getAttributeValue(FILE_PATH)); - final File file = new File(relativePath); - return new DefaultCoverageFileProvider(file.exists() ? file - : new File(PathManager.getSystemPath(), relativePath), - sourceProvider != null ? sourceProvider : DefaultCoverageFileProvider.DEFAULT_LOCAL_PROVIDER_KEY); + /** + * @deprecated Use {@link BaseCoverageSuite#BaseCoverageSuite(String, Project, CoverageRunner, CoverageFileProvider, long)} + */ + @Deprecated + public BaseCoverageSuite(String name, @Nullable CoverageFileProvider fileProvider, long timestamp, + boolean coverageByTestEnabled, boolean branchCoverage, boolean trackTestFolders, CoverageRunner coverageRunner) { + this(name, fileProvider, timestamp, coverageByTestEnabled, branchCoverage, trackTestFolders, coverageRunner, null); } @Override @@ -115,27 +92,33 @@ public abstract class BaseCoverageSuite implements CoverageSuite, JDOMExternali return myCoverageDataFileProvider.isValid(); } - @Override - @NotNull - public String getCoverageDataFileName() { - return myCoverageDataFileProvider.getCoverageDataFilePath(); - } - - @Override - public - @NotNull - CoverageFileProvider getCoverageDataFileProvider() { - return myCoverageDataFileProvider; - } - @Override public String getPresentableName() { return myName; } + @Override + public Project getProject() { + return myProject; + } + + public void setProject(Project project) { + myProject = project; + } + + @Override + public CoverageRunner getRunner() { + return myRunner; + } + + @Override + public @NotNull CoverageFileProvider getCoverageDataFileProvider() { + return myCoverageDataFileProvider; + } + @Override public long getLastCoverageTimeStamp() { - return myLastCoverageTimeStamp; + return myTimestamp; } @Override @@ -148,76 +131,20 @@ public abstract class BaseCoverageSuite implements CoverageSuite, JDOMExternali return myBranchCoverage; } - @Override - public void readExternal(Element element) throws InvalidDataException { - myCoverageDataFileProvider = readDataFileProviderAttribute(element); - - // name - myName = element.getAttributeValue(NAME_ATTRIBUTE); - if (myName == null) myName = generateName(); - - // tc - myLastCoverageTimeStamp = Long.parseLong(element.getAttributeValue(MODIFIED_STAMP)); - - // runner - myRunner = readRunnerAttribute(element); - - // coverage per test - final String collectedLineInfo = element.getAttributeValue(COVERAGE_BY_TEST_ENABLED_ATTRIBUTE_NAME); - myCoverageByTestEnabled = collectedLineInfo != null && Boolean.valueOf(collectedLineInfo).booleanValue(); - - - // line/branch coverage - final String branchCoverage = element.getAttributeValue(BRANCH_COVERAGE_ATTRIBUTE_NAME); - myBranchCoverage = branchCoverage != null && Boolean.valueOf(branchCoverage).booleanValue(); - } - - @Override - public void writeExternal(final Element element) throws WriteExternalException { - final String fileName = - FileUtil.getRelativePath(new File(PathManager.getSystemPath()), new File(myCoverageDataFileProvider.getCoverageDataFilePath())); - element.setAttribute(FILE_PATH, fileName != null ? FileUtil.toSystemIndependentName(fileName) : myCoverageDataFileProvider.getCoverageDataFilePath()); - element.setAttribute(NAME_ATTRIBUTE, myName); - element.setAttribute(MODIFIED_STAMP, String.valueOf(myLastCoverageTimeStamp)); - element.setAttribute(SOURCE_PROVIDER, myCoverageDataFileProvider instanceof DefaultCoverageFileProvider defaultProvider - ? defaultProvider.getSourceProvider() - : myCoverageDataFileProvider.getClass().getName()); - // runner - if (getRunner() != null) { - element.setAttribute(COVERAGE_RUNNER, myRunner.getId()); - } - - // cover by test - element.setAttribute(COVERAGE_BY_TEST_ENABLED_ATTRIBUTE_NAME, String.valueOf(myCoverageByTestEnabled)); - - // line/branch coverage - element.setAttribute(BRANCH_COVERAGE_ATTRIBUTE_NAME, String.valueOf(myBranchCoverage)); - } - - @Override - public void setCoverageData(final ProjectData projectData) { - myCoverageData = new SoftReference<>(projectData); - } - - public ProjectData getCoverageData() { - return myCoverageData.get(); - } - - @Override - public void restoreCoverageData() { - setCoverageData(loadProjectInfo()); - } - - @Override - public boolean isCoverageByTestApplicable() { - return getRunner().isCoverageByTestApplicable(); - } - @Override public boolean isCoverageByTestEnabled() { return myCoverageByTestEnabled; } + @Nullable + public RunConfigurationBase getConfiguration() { + return myConfiguration; + } + + public void setConfiguration(RunConfigurationBase configuration) { + myConfiguration = configuration; + } + @Override @Nullable public ProjectData getCoverageData(final CoverageDataManager coverageDataManager) { @@ -229,17 +156,21 @@ public abstract class BaseCoverageSuite implements CoverageSuite, JDOMExternali return data; } - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - final String thisName = myCoverageDataFileProvider.getCoverageDataFilePath(); - final String thatName = ((BaseCoverageSuite)o).myCoverageDataFileProvider.getCoverageDataFilePath(); - return thisName.equals(thatName); + /** + * @return Cached coverage data without loading + */ + public ProjectData getCoverageData() { + return myCoverageData.get(); } - public int hashCode() { - return myCoverageDataFileProvider.getCoverageDataFilePath().hashCode(); + @Override + public void setCoverageData(final ProjectData projectData) { + myCoverageData = new SoftReference<>(projectData); + } + + @Override + public void restoreCoverageData() { + setCoverageData(loadProjectInfo()); } @Nullable @@ -262,16 +193,70 @@ public abstract class BaseCoverageSuite implements CoverageSuite, JDOMExternali } @Override - public CoverageRunner getRunner() { - return myRunner; + public void readExternal(Element element) throws InvalidDataException { + myCoverageDataFileProvider = readDataFileProviderAttribute(element); + + // name + myName = element.getAttributeValue(NAME_ATTRIBUTE); + if (myName == null) { + myName = generateName(myCoverageDataFileProvider.getCoverageDataFilePath()); + } + + // tc + myTimestamp = Long.parseLong(element.getAttributeValue(MODIFIED_STAMP)); + + // runner + myRunner = readRunnerAttribute(element); + + // coverage per test + final String collectedLineInfo = element.getAttributeValue(COVERAGE_BY_TEST_ENABLED_ATTRIBUTE_NAME); + myCoverageByTestEnabled = collectedLineInfo != null && Boolean.valueOf(collectedLineInfo).booleanValue(); + + + // line/branch coverage + final String branchCoverage = element.getAttributeValue(BRANCH_COVERAGE_ATTRIBUTE_NAME); + myBranchCoverage = branchCoverage != null && Boolean.valueOf(branchCoverage).booleanValue(); } - protected void setRunner(CoverageRunner runner) { - myRunner = runner; + @Override + public void writeExternal(final Element element) throws WriteExternalException { + String absolutePath = getCoverageDataFileName(); + String pathInSystemDir = FileUtil.getRelativePath(new File(PathManager.getSystemPath()), new File(absolutePath)); + element.setAttribute(FILE_PATH, pathInSystemDir != null ? FileUtil.toSystemIndependentName(pathInSystemDir) : absolutePath); + element.setAttribute(NAME_ATTRIBUTE, myName); + element.setAttribute(MODIFIED_STAMP, String.valueOf(myTimestamp)); + element.setAttribute(SOURCE_PROVIDER, myCoverageDataFileProvider instanceof DefaultCoverageFileProvider defaultProvider + ? defaultProvider.getSourceProvider() + : myCoverageDataFileProvider.getClass().getName()); + // runner + if (myRunner != null) { + element.setAttribute(COVERAGE_RUNNER, myRunner.getId()); + } + + // cover by test + element.setAttribute(COVERAGE_BY_TEST_ENABLED_ATTRIBUTE_NAME, String.valueOf(myCoverageByTestEnabled)); + + // line/branch coverage + element.setAttribute(BRANCH_COVERAGE_ATTRIBUTE_NAME, String.valueOf(myBranchCoverage)); } - private String generateName() { - String text = myCoverageDataFileProvider.getCoverageDataFilePath(); + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final String thisName = myCoverageDataFileProvider.getCoverageDataFilePath(); + final String thatName = ((BaseCoverageSuite)o).myCoverageDataFileProvider.getCoverageDataFilePath(); + return thisName.equals(thatName); + } + + @Override + public int hashCode() { + return myCoverageDataFileProvider.getCoverageDataFilePath().hashCode(); + } + + private static String generateName(String path) { + String text = path; int i = text.lastIndexOf(File.separatorChar); if (i >= 0) text = text.substring(i + 1); i = text.lastIndexOf('.'); @@ -279,21 +264,38 @@ public abstract class BaseCoverageSuite implements CoverageSuite, JDOMExternali return text; } - @Override - public Project getProject() { - return myProject; - } - - public void setProject(Project project) { - myProject = project; - } - - public void setConfiguration(RunConfigurationBase configuration) { - myConfiguration = configuration; - } - @Nullable - public RunConfigurationBase getConfiguration() { - return myConfiguration; + public static CoverageRunner readRunnerAttribute(Element element) { + final String runner = element.getAttributeValue(COVERAGE_RUNNER); + if (runner != null) { + for (CoverageRunner coverageRunner : CoverageRunner.EP_NAME.getExtensionList()) { + if (Comparing.strEqual(coverageRunner.getId(), runner)) { + return coverageRunner; + } + } + } + return null; + } + + public static @NotNull CoverageFileProvider readDataFileProviderAttribute(Element element) { + String sourceProvider = element.getAttributeValue(SOURCE_PROVIDER); + if (sourceProvider == null) { + sourceProvider = DefaultCoverageFileProvider.DEFAULT_LOCAL_PROVIDER_KEY; + } + + String relativeOrAbsolutePath = FileUtil.toSystemDependentName(element.getAttributeValue(FILE_PATH)); + File file = new File(relativeOrAbsolutePath); + if (!file.exists()) { + file = new File(PathManager.getSystemPath(), relativeOrAbsolutePath); + } + return new DefaultCoverageFileProvider(file, sourceProvider); + } + + /** + * @deprecated Is not used + */ + @Deprecated + protected void setRunner(CoverageRunner runner) { + myRunner = runner; } } diff --git a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManager.java b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManager.java index 5dc6fda9090b..cd50953eb9e9 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManager.java +++ b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManager.java @@ -12,6 +12,7 @@ import com.intellij.openapi.util.Computable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.util.Collection; import java.util.List; @@ -39,11 +40,19 @@ public abstract class CoverageDataManager { @NotNull CoverageRunner coverageRunner, boolean coverageByTestEnabled, boolean branchCoverage); + /** + * @deprecated Use {@link CoverageDataManager#addExternalCoverageSuite(File, CoverageRunner)} + */ + @Deprecated public abstract CoverageSuite addExternalCoverageSuite(@NotNull String selectedFileName, long timeStamp, @NotNull CoverageRunner coverageRunner, @NotNull CoverageFileProvider fileProvider); + public final CoverageSuite addExternalCoverageSuite(@NotNull File file, @NotNull CoverageRunner coverageRunner) { + return addExternalCoverageSuite(file.getName(), file.lastModified(), coverageRunner, new DefaultCoverageFileProvider(file.getAbsolutePath())); + } + public abstract CoverageSuite addCoverageSuite(CoverageEnabledConfiguration config); diff --git a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java index ce385c8cb952..127f4b5eb3a0 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java +++ b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java @@ -34,7 +34,10 @@ import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -142,9 +145,12 @@ public class CoverageDataManagerImpl extends CoverageDataManager implements Disp @NotNull CoverageRunner coverageRunner, boolean coverageByTestEnabled, boolean branchCoverage) { - return CoverageDataSuitesManager.getInstance(myProject) - .addSuite(coverageRunner, name, fileProvider, filters, lastCoverageTimeStamp, suiteToMergeWith, coverageByTestEnabled, - branchCoverage); + CoverageDataSuitesManager manager = CoverageDataSuitesManager.getInstance(myProject); + CoverageSuite suite = manager.createCoverageSuite(name, coverageRunner, fileProvider, lastCoverageTimeStamp); + if (suite != null) { + manager.addSuite(suite, suiteToMergeWith); + } + return suite; } /** @@ -161,7 +167,7 @@ public class CoverageDataManagerImpl extends CoverageDataManager implements Disp @NotNull CoverageRunner coverageRunner, @NotNull CoverageFileProvider fileProvider) { return CoverageDataSuitesManager.getInstance(myProject) - .addExternalCoverageSuite(coverageRunner, selectedFileName, fileProvider, timeStamp); + .addExternalCoverageSuite(selectedFileName, coverageRunner, fileProvider, timeStamp); } @Override diff --git a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataSuitesManager.kt b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataSuitesManager.kt index 619a8389aef9..32fd40310f06 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataSuitesManager.kt +++ b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataSuitesManager.kt @@ -9,10 +9,8 @@ import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.extensions.ExtensionPointListener import com.intellij.openapi.extensions.PluginDescriptor import com.intellij.openapi.project.Project -import com.intellij.util.ArrayUtilRt import org.jdom.Element import org.jetbrains.annotations.NonNls -import java.io.File private val LOG = logger() private const val SUITE: @NonNls String = "SUITE" @@ -36,19 +34,6 @@ class CoverageDataSuitesManager(private val project: Project) : PersistentStateC fun getInstance(project: Project): CoverageDataSuitesManager = project.service() } - fun addSuite(coverageRunner: CoverageRunner, - name: String, - fileProvider: CoverageFileProvider, - filters: Array?, - lastCoverageTimeStamp: Long, - suiteToMergeWith: String?, - coverageByTestEnabled: Boolean, - branchCoverage: Boolean): CoverageSuite? { - return createCoverageSuite(coverageRunner, name, fileProvider, filters, lastCoverageTimeStamp, suiteToMergeWith, - coverageByTestEnabled, branchCoverage) - ?.also { addSuite(it, suiteToMergeWith) } - } - fun addSuite(suite: CoverageSuite, suiteToMergeWith: String?) { if (suiteToMergeWith == null || suite.getPresentableName() != suiteToMergeWith) { deleteSuite(suite) @@ -57,29 +42,21 @@ class CoverageDataSuitesManager(private val project: Project) : PersistentStateC suites.add(suite) // add new instance } - fun addExternalCoverageSuite(coverageRunner: CoverageRunner, - fileName: String, + fun addExternalCoverageSuite(fileName: String, + runner: CoverageRunner, fileProvider: CoverageFileProvider, - timeStamp: Long): CoverageSuite? { - return createCoverageSuite(coverageRunner, fileName, fileProvider, ArrayUtilRt.EMPTY_STRING_ARRAY, - timeStamp, null, false, false) + timestamp: Long): CoverageSuite? { + return createCoverageSuite(fileName, runner, fileProvider, timestamp) ?.also { suites.add(it) } } fun addSuite(config: CoverageEnabledConfiguration): CoverageSuite? { - val name = CoverageBundle.message("coverage.results.suite.name", config.name) - val path = config.getCoverageFilePath() - LOG.assertTrue(path != null, "Configuration coverage report file is not configured ${config.name}") - val runner = config.coverageRunner - LOG.assertTrue(runner != null, "Cannot find coverage runner for ${path}") - if (runner == null || path == null) return null - - val fileProvider = DefaultCoverageFileProvider(File(path)) - return createCoverageSuite(config, runner, name, fileProvider) - ?.also { - deleteSuite(it) - suites.add(it) - } + val suite = createCoverageSuite(config) + if (suite != null) { + deleteSuite(suite) + suites.add(suite) + } + return suite } fun deleteSuite(suite: CoverageSuite) { @@ -93,31 +70,36 @@ class CoverageDataSuitesManager(private val project: Project) : PersistentStateC fun getSuites(): Array = suites.toTypedArray() - override fun loadState(element: Element) { - for (suiteElement in element.getChildren(SUITE)) { - val coverageRunner = BaseCoverageSuite.readRunnerAttribute(suiteElement) - // skip unknown runners - if (coverageRunner == null) continue - - var suite: CoverageSuite? = null - for (engine in CoverageEngine.EP_NAME.extensions) { - if (coverageRunner.acceptsCoverageEngine(engine)) { - suite = engine.createEmptyCoverageSuite(coverageRunner) - if (suite != null) { - if (suite is BaseCoverageSuite) { - suite.project = project - } - break - } + fun createCoverageSuite(name: String, + runner: CoverageRunner, + fileProvider: CoverageFileProvider, + timestamp: Long): CoverageSuite? { + return CoverageEngine.EP_NAME.extensionList + .filter(runner::acceptsCoverageEngine) + .firstNotNullOfOrNull { it.createCoverageSuite(name, project, runner, fileProvider, timestamp) } + .also { + if (it == null) { + LOG.error("Cannot create coverage suite for runner: " + runner.getPresentableName()) } } - if (suite != null) { - try { - suite.readExternal(suiteElement) - suites.add(suite) - } - catch (e: NumberFormatException) { // try next suite - } + } + + override fun loadState(element: Element) { + for (suiteElement in element.getChildren(SUITE)) { + val coverageRunner = BaseCoverageSuite.readRunnerAttribute(suiteElement) ?: continue // skip unknown runners + + val suite = CoverageEngine.EP_NAME.extensionList.asSequence() + .filter { coverageRunner.acceptsCoverageEngine(it) } + .firstNotNullOfOrNull { it.createEmptyCoverageSuite(coverageRunner) } ?: continue + if (suite is BaseCoverageSuite) { + suite.project = project + } + + try { + suite.readExternal(suiteElement) + suites.add(suite) + } + catch (e: NumberFormatException) { // try next suite } } } @@ -132,49 +114,18 @@ class CoverageDataSuitesManager(private val project: Project) : PersistentStateC return element } - private fun createCoverageSuite(config: CoverageEnabledConfiguration, - runner: CoverageRunner, - name: String, - fileProvider: DefaultCoverageFileProvider): CoverageSuite? { - for (engine in CoverageEngine.EP_NAME.extensions) { - if (runner.acceptsCoverageEngine(engine) && engine.isApplicableTo(config.configuration)) { - val suite = engine.createCoverageSuite(runner, name, fileProvider, config) - if (suite != null) return suite + private fun createCoverageSuite(config: CoverageEnabledConfiguration): CoverageSuite? { + return CoverageEngine.EP_NAME.extensionList + .filter { it.isApplicableTo(config.configuration) } + .firstNotNullOfOrNull { it.createCoverageSuite(config) }.also { + LOG.assertTrue(it != null, "Cannot create coverage suite for run config: ${config.javaClass.name}") } - } - LOG.error("Cannot create coverage suite for runner: " + runner.getPresentableName()) - return null - } - - private fun createCoverageSuite(runner: CoverageRunner, - name: String, - fileProvider: CoverageFileProvider, - filters: Array?, - lastCoverageTimeStamp: Long, - suiteToMergeWith: String?, - coverageByTestEnabled: Boolean, - branchCoverage: Boolean): CoverageSuite? { - for (engine in CoverageEngine.EP_NAME.extensions) { - if (!runner.acceptsCoverageEngine(engine)) continue - val suite = engine.createCoverageSuite(runner, name, fileProvider, filters, lastCoverageTimeStamp, suiteToMergeWith, - coverageByTestEnabled, branchCoverage, false, project) - if (suite != null) return suite - } - - LOG.error("Cannot create coverage suite for runner: " + runner.getPresentableName()) - return null } private fun setUpRunnerEPRemovedCallback() { CoverageRunner.EP_NAME.addExtensionPointListener(object : ExtensionPointListener { override fun extensionRemoved(extension: CoverageRunner, pluginDescriptor: PluginDescriptor) { - for (suite in suites) { - if (suite is BaseCoverageSuite) { - if (suite.getRunner() === extension) { - suite.runner = null - } - } - } + suites.removeIf { suite -> suite.runner === extension } } }, this) } diff --git a/plugins/coverage-common/src/com/intellij/coverage/CoverageEngine.java b/plugins/coverage-common/src/com/intellij/coverage/CoverageEngine.java index 5df05666d4a9..bf1db3061487 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/CoverageEngine.java +++ b/plugins/coverage-common/src/com/intellij/coverage/CoverageEngine.java @@ -58,7 +58,7 @@ public abstract class CoverageEngine { /** * Creates coverage enabled configuration for given RunConfiguration. It is supposed that one run configuration may be associated - * with no more than one coverage engine. + * with no more than one coverage engine. * * @param conf Run Configuration * @return Coverage enabled configuration with engine-specific settings @@ -66,75 +66,72 @@ public abstract class CoverageEngine { @NotNull public abstract CoverageEnabledConfiguration createCoverageEnabledConfiguration(@NotNull final RunConfigurationBase conf); + /** - * Coverage suite is coverage settings & coverage data gather by coverage runner (for suites provided by TeamCity server) - * - * @param covRunner Coverage Runner - * @param name Suite name - * @param coverageDataFileProvider Coverage raw data file provider - * @param filters Coverage data filters - * @param lastCoverageTimeStamp timestamp - * @param suiteToMerge Suite to merge this coverage data with - * @param coverageByTestEnabled Collect coverage per test - * @param branchCoverage Whether the suite includes branch coverage, or only line coverage otherwise - * @param trackTestFolders Track test folders option - * @return Suite + * Create a suite from an external report. */ - @Nullable - public CoverageSuite createCoverageSuite(@NotNull final CoverageRunner covRunner, - @NotNull final String name, - @NotNull final CoverageFileProvider coverageDataFileProvider, - final String @Nullable [] filters, - final long lastCoverageTimeStamp, - @Nullable final String suiteToMerge, - final boolean coverageByTestEnabled, - final boolean branchCoverage, - final boolean trackTestFolders) { - return createCoverageSuite(covRunner, name, coverageDataFileProvider, filters, lastCoverageTimeStamp, suiteToMerge, - coverageByTestEnabled, branchCoverage, trackTestFolders, null); + public final @Nullable CoverageSuite createCoverageSuite(@NotNull String name, + @NotNull Project project, + @NotNull CoverageRunner runner, + @NotNull CoverageFileProvider fileProvider, + long timestamp) { + return createCoverageSuite(runner, name, fileProvider, null, timestamp, null, false, false, false, project); + } + + + /** + * Create a suite from a run configuration. + */ + public final @Nullable CoverageSuite createCoverageSuite(@NotNull CoverageEnabledConfiguration config) { + CoverageRunner runner = config.getCoverageRunner(); + if (runner == null) return null; + return createCoverageSuite(runner, config.createSuiteName(), config.createFileProvider(), config); } /** - * Coverage suite is coverage settings & coverage data gather by coverage runner (for suites provided by TeamCity server) + * Coverage suite is coverage settings & coverage data gather by coverage runner. This method is used for external suites. * - * @param covRunner Coverage Runner - * @param name Suite name - * @param coverageDataFileProvider Coverage raw data file provider - * @param filters Coverage data filters - * @param lastCoverageTimeStamp timestamp - * @param suiteToMerge Suite to merge this coverage data with - * @param coverageByTestEnabled Collect coverage per test - * @param branchCoverage Whether the suite includes branch coverage, or only line coverage otherwise - * @param trackTestFolders Track test folders option + * @param runner Coverage Runner + * @param name Suite name + * @param fileProvider Coverage raw data file provider + * @param filters Coverage data filters + * @param lastCoverageTimeStamp timestamp + * @param suiteToMerge Suite to merge this coverage data with + * @param coverageByTestEnabled Collect coverage per test + * @param branchCoverage Whether the suite includes branch coverage, or only line coverage otherwise + * @param trackTestFolders Track test folders option * @return Suite + * @deprecated Use {@link CoverageEngine#createCoverageSuite(String, Project, CoverageRunner, CoverageFileProvider, long)} */ + @Deprecated @Nullable - public abstract CoverageSuite createCoverageSuite(@NotNull final CoverageRunner covRunner, - @NotNull final String name, - @NotNull final CoverageFileProvider coverageDataFileProvider, - final String @Nullable [] filters, - final long lastCoverageTimeStamp, - @Nullable final String suiteToMerge, - final boolean coverageByTestEnabled, - final boolean branchCoverage, - final boolean trackTestFolders, Project project); + public abstract CoverageSuite createCoverageSuite(@NotNull CoverageRunner runner, + @NotNull String name, + @NotNull CoverageFileProvider fileProvider, + String @Nullable [] filters, + long lastCoverageTimeStamp, + @Nullable String suiteToMerge, + boolean coverageByTestEnabled, + boolean branchCoverage, + boolean trackTestFolders, Project project); /** - * Coverage suite is coverage settings & coverage data gather by coverage runner - * - * @param covRunner Coverage Runner - * @param name Suite name - * @param config Coverage engine configuration - * @return Suite + * @deprecated Use {@link CoverageEngine#createCoverageSuite(CoverageEnabledConfiguration)} + */ + @Deprecated + @Nullable + public abstract CoverageSuite createCoverageSuite(@NotNull CoverageRunner covRunner, + @NotNull String name, + @NotNull CoverageFileProvider coverageDataFileProvider, + @NotNull CoverageEnabledConfiguration config); + + /** + * Create a new suite with no parameters set. + *

+ * This method is used to read a suite from persistent storage. */ @Nullable - public abstract CoverageSuite createCoverageSuite(@NotNull final CoverageRunner covRunner, - @NotNull final String name, - @NotNull final CoverageFileProvider coverageDataFileProvider, - @NotNull final CoverageEnabledConfiguration config); - - @Nullable - public abstract CoverageSuite createEmptyCoverageSuite(@NotNull final CoverageRunner coverageRunner); + public abstract CoverageSuite createEmptyCoverageSuite(@NotNull CoverageRunner coverageRunner); /** * Coverage annotator which annotates smth(e.g. Project view nodes / editor) with coverage information @@ -397,4 +394,22 @@ public abstract class CoverageEngine { public boolean wasTestDataCollected(Project ignoredProject) { return false; } + + /** + * @deprecated Is not used + */ + @Deprecated + @Nullable + public CoverageSuite createCoverageSuite(@NotNull CoverageRunner covRunner, + @NotNull String name, + @NotNull CoverageFileProvider coverageDataFileProvider, + String @Nullable [] filters, + long lastCoverageTimeStamp, + @Nullable String suiteToMerge, + boolean coverageByTestEnabled, + boolean branchCoverage, + boolean trackTestFolders) { + return createCoverageSuite(covRunner, name, coverageDataFileProvider, filters, lastCoverageTimeStamp, suiteToMerge, + coverageByTestEnabled, branchCoverage, trackTestFolders, null); + } } diff --git a/plugins/coverage-common/src/com/intellij/coverage/CoverageSuite.java b/plugins/coverage-common/src/com/intellij/coverage/CoverageSuite.java index 440e8111d8cc..8ddb46122588 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/CoverageSuite.java +++ b/plugins/coverage-common/src/com/intellij/coverage/CoverageSuite.java @@ -16,7 +16,7 @@ import java.io.File; /** * Represents coverage data collected by {@link CoverageRunner}. - * + * * @see BaseCoverageSuite */ public interface CoverageSuite extends JDOMExternalizable { @@ -25,33 +25,32 @@ public interface CoverageSuite extends JDOMExternalizable { */ boolean isValid(); + @NlsSafe + String getPresentableName(); + + Project getProject(); + @NotNull - String getCoverageDataFileName(); + CoverageEngine getCoverageEngine(); - @NlsSafe String getPresentableName(); - - long getLastCoverageTimeStamp(); + CoverageRunner getRunner(); @NotNull CoverageFileProvider getCoverageDataFileProvider(); - boolean isCoverageByTestApplicable(); - - boolean isCoverageByTestEnabled(); - - @Nullable - ProjectData getCoverageData(CoverageDataManager coverageDataManager); + long getLastCoverageTimeStamp(); boolean isTrackTestFolders(); boolean isBranchCoverage(); - CoverageRunner getRunner(); + boolean isCoverageByTestEnabled(); - @NotNull - CoverageEngine getCoverageEngine(); - - Project getProject(); + /** + * Get coverage data, of load it if it has not been loaded + */ + @Nullable + ProjectData getCoverageData(CoverageDataManager coverageDataManager); /** * Caches loaded coverage data on soft reference. @@ -63,6 +62,12 @@ public interface CoverageSuite extends JDOMExternalizable { */ void restoreCoverageData(); + + @NotNull + default String getCoverageDataFileName() { + return getCoverageDataFileProvider().getCoverageDataFilePath(); + } + /** * @return true if engine can provide means to remove coverage data. */ @@ -73,7 +78,7 @@ public interface CoverageSuite extends JDOMExternalizable { } /** - * Called to cleanup gathered coverage on explicit user's action in settings dialog or e.g. during rerun of the same configuration. + * Cleans gathered coverage on explicit user's action in the settings dialog or e.g., during rerun of the same configuration. */ default void deleteCachedCoverageData() { final String fileName = getCoverageDataFileName(); @@ -89,4 +94,10 @@ public interface CoverageSuite extends JDOMExternalizable { } getCoverageEngine().deleteAssociatedTraces(this); } + + default boolean isCoverageByTestApplicable() { + CoverageRunner runner = getRunner(); + if (runner == null) return false; + return runner.isCoverageByTestApplicable(); + } } diff --git a/plugins/coverage-common/src/com/intellij/coverage/actions/CoverageSuiteChooserDialog.java b/plugins/coverage-common/src/com/intellij/coverage/actions/CoverageSuiteChooserDialog.java index fddef6ea48c8..dbddba658921 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/actions/CoverageSuiteChooserDialog.java +++ b/plugins/coverage-common/src/com/intellij/coverage/actions/CoverageSuiteChooserDialog.java @@ -32,8 +32,8 @@ import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.ActionEvent; -import java.util.*; import java.util.List; +import java.util.*; import java.util.stream.Collectors; public class CoverageSuiteChooserDialog extends DialogWrapper { @@ -298,8 +298,7 @@ public class CoverageSuiteChooserDialog extends DialogWrapper { continue; } - CoverageSuite coverageSuite = myCoverageManager.addExternalCoverageSuite(file.getName(), file.getTimeStamp(), coverageRunner, - new DefaultCoverageFileProvider(file.getPath())); + CoverageSuite coverageSuite = myCoverageManager.addExternalCoverageSuite(VfsUtilCore.virtualToIoFile(file), coverageRunner); List currentlySelected = collectSelectedSuites(); currentlySelected.add(coverageSuite); diff --git a/plugins/coverage-common/src/com/intellij/execution/configurations/coverage/CoverageEnabledConfiguration.java b/plugins/coverage-common/src/com/intellij/execution/configurations/coverage/CoverageEnabledConfiguration.java index 6b7216506555..216f98425d17 100644 --- a/plugins/coverage-common/src/com/intellij/execution/configurations/coverage/CoverageEnabledConfiguration.java +++ b/plugins/coverage-common/src/com/intellij/execution/configurations/coverage/CoverageEnabledConfiguration.java @@ -1,9 +1,7 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.execution.configurations.coverage; -import com.intellij.coverage.CoverageEngine; -import com.intellij.coverage.CoverageRunner; -import com.intellij.coverage.CoverageSuite; +import com.intellij.coverage.*; import com.intellij.execution.configurations.RunConfigurationBase; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; @@ -15,6 +13,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.nio.file.Path; +import java.util.Date; /** * Base class for run configurations with enabled code coverage @@ -113,6 +112,18 @@ public abstract class CoverageEnabledConfiguration implements JDOMExternalizable myTrackPerTestCoverage = testTracking; } + public String createSuiteName() { + return CoverageBundle.message("coverage.results.suite.name", getName()); + } + + public CoverageFileProvider createFileProvider() { + return new DefaultCoverageFileProvider(getCoverageFilePath()); + } + + public long createTimestamp() { + return new Date().getTime(); + } + public void coverageRunnerExtensionRemoved(@NotNull CoverageRunner runner) { if (runner.getId().equals(myCoverageRunner.getId())) { diff --git a/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java b/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java index 2f00131e344e..9d597807ca0d 100644 --- a/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java +++ b/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java @@ -273,7 +273,7 @@ public class JavaCoverageEngine extends CoverageEngine { return createSuite(covRunner, name, coverageDataFileProvider, javaConfig.getPatterns(), javaConfig.getExcludePatterns(), - new Date().getTime(), + javaConfig.createTimestamp(), javaConfig.isTrackPerTestCoverage() && javaConfig.isBranchCoverageEnabled(), javaConfig.isBranchCoverageEnabled(), javaConfig.isTrackTestFolders(), config.getConfiguration().getProject()); @@ -698,7 +698,7 @@ public class JavaCoverageEngine extends CoverageEngine { return hasDefault; } - protected JavaCoverageSuite createSuite(CoverageRunner acceptedCovRunner, + public JavaCoverageSuite createSuite(CoverageRunner acceptedCovRunner, String name, CoverageFileProvider coverageDataFileProvider, String[] filters, String[] excludePatterns, diff --git a/plugins/coverage/src/com/intellij/coverage/JavaCoverageSuite.java b/plugins/coverage/src/com/intellij/coverage/JavaCoverageSuite.java index 75d38a6a3b71..7a916dcf6404 100644 --- a/plugins/coverage/src/com/intellij/coverage/JavaCoverageSuite.java +++ b/plugins/coverage/src/com/intellij/coverage/JavaCoverageSuite.java @@ -51,11 +51,11 @@ public class JavaCoverageSuite extends BaseCoverageSuite { final CoverageRunner coverageRunner, @NotNull final CoverageEngine coverageEngine, final Project project) { - super(name, coverageDataFileProvider, lastCoverageTimeStamp, coverageByTestEnabled, - branchCoverage, trackTestFolders, - coverageRunner != null ? coverageRunner : CoverageRunner.getInstance(IDEACoverageRunner.class), project); - + super(name, project, coverageRunner, coverageDataFileProvider, lastCoverageTimeStamp); myCoverageEngine = coverageEngine; + myBranchCoverage = branchCoverage; + myTrackTestFolders = trackTestFolders; + myCoverageByTestEnabled = coverageByTestEnabled; myIncludeFilters = includeFilters; myExcludePatterns = excludePatterns; @@ -64,6 +64,11 @@ public class JavaCoverageSuite extends BaseCoverageSuite { } } + @Override + public final @NotNull CoverageEngine getCoverageEngine() { + return myCoverageEngine; + } + public final String @NotNull [] getFilteredPackageNames() { return getPackageNames(myIncludeFilters); } @@ -133,8 +138,8 @@ public class JavaCoverageSuite extends BaseCoverageSuite { myIncludeFilters = readFilters(element, FILTER); myExcludePatterns = readFilters(element, EXCLUDED_FILTER); - if (getRunner() == null) { - setRunner(CoverageRunner.getInstance(IDEACoverageRunner.class)); //default + if (myRunner == null) { + myRunner = CoverageRunner.getInstance(IDEACoverageRunner.class); //default } } @@ -168,12 +173,6 @@ public class JavaCoverageSuite extends BaseCoverageSuite { } } - @Override - @NotNull - public final CoverageEngine getCoverageEngine() { - return myCoverageEngine; - } - public final boolean isClassFiltered(final String classFQName) { return isClassFiltered(classFQName, getFilteredClassNames()); } diff --git a/plugins/coverage/testSrc/com/intellij/coverage/CoverageSuitesTest.kt b/plugins/coverage/testSrc/com/intellij/coverage/CoverageSuitesTest.kt index 7abbd0fd4836..05d144a6fd73 100644 --- a/plugins/coverage/testSrc/com/intellij/coverage/CoverageSuitesTest.kt +++ b/plugins/coverage/testSrc/com/intellij/coverage/CoverageSuitesTest.kt @@ -14,7 +14,7 @@ class CoverageSuitesTest : CoverageIntegrationBaseTest() { assertNoSuites() val path = SIMPLE_IJ_REPORT_PATH val runner = CoverageRunner.getInstance(IDEACoverageRunner::class.java) - val suite = manager.addExternalCoverageSuite(path, -1, runner, createCoverageFileProvider(path)) + val suite = manager.addExternalCoverageSuite(File(path), runner) manager.suites.run { Assert.assertEquals(1, size)