package com.intellij.coverage;
import com.intellij.execution.configurations.ModuleBasedConfiguration;
import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootModificationTracker;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.GlobalSearchScopesCore;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.reference.SoftReference;
import com.intellij.rt.coverage.data.LineData;
import com.intellij.rt.coverage.data.ProjectData;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeMap;
public class CoverageSuitesBundle {
private final CoverageSuite[] mySuites;
private CoverageEngine myEngine;
private Set<Module> myProcessedModules;
private CachedValue<GlobalSearchScope> myCachedValue;
private SoftReference<ProjectData> myData = new SoftReference<>(null);
private static final Logger LOG = Logger.getInstance(CoverageSuitesBundle.class);
public CoverageSuitesBundle(CoverageSuite suite) {
this(new CoverageSuite[]{suite});
}
public CoverageSuitesBundle(CoverageSuite[] suites) {
mySuites = suites;
LOG.assertTrue(mySuites.length > 0);
myEngine = mySuites[0].getCoverageEngine();
for (CoverageSuite suite : suites) {
final CoverageEngine engine = suite.getCoverageEngine();
LOG.assertTrue(Comparing.equal(engine, myEngine));
}
}
public boolean isValid() {
for (CoverageSuite suite : mySuites) {
if (!suite.isValid()) return false;
}
return true;
}
public long getLastCoverageTimeStamp() {
long max = 0;
for (CoverageSuite suite : mySuites) {
max = Math.max(max, suite.getLastCoverageTimeStamp());
}
return max;
}
public boolean isCoverageByTestApplicable() {
for (CoverageSuite suite : mySuites) {
if (suite.isCoverageByTestApplicable()) return true;
}
return false;
}
public boolean isCoverageByTestEnabled() {
for (CoverageSuite suite : mySuites) {
if (suite.isCoverageByTestEnabled()) return true;
}
return false;
}
@Nullable
public ProjectData getCoverageData() {
final ProjectData projectData = myData.get();
if (projectData != null) return projectData;
ProjectData data = new ProjectData();
for (CoverageSuite suite : mySuites) {
final ProjectData coverageData = suite.getCoverageData(null);
if (coverageData != null) {
data.merge(coverageData);
}
}
myData = new SoftReference<>(data);
return data;
}
public boolean isTrackTestFolders() {
for (CoverageSuite suite : mySuites) {
if (suite.isTrackTestFolders()) return true;
}
return false;
}
public boolean isTracingEnabled() {
for (CoverageSuite suite : mySuites) {
if (suite.isTracingEnabled()) return true;
}
return false;
}
@NotNull
public CoverageEngine getCoverageEngine() {
return myEngine;
}
public LineMarkerRendererWithErrorStripe getLineMarkerRenderer(int lineNumber,
@Nullable final String className,
final TreeMap<Integer, LineData> lines,
final boolean coverageByTestApplicable,
@NotNull final CoverageSuitesBundle coverageSuite,
final Function<Integer, Integer> newToOldConverter,
final Function<Integer, Integer> oldToNewConverter, boolean subCoverageActive) {
return myEngine.getLineMarkerRenderer(lineNumber, className, lines, coverageByTestApplicable, coverageSuite, newToOldConverter, oldToNewConverter, subCoverageActive);
}
public CoverageAnnotator getAnnotator(Project project) {
return myEngine.getCoverageAnnotator(project);
}
@NotNull
public CoverageSuite[] getSuites() {
return mySuites;
}
public boolean contains(CoverageSuite suite) {
return ArrayUtilRt.find(mySuites, suite) > -1;
}
public void setCoverageData(ProjectData projectData) {
myData = new SoftReference<>(projectData);
}
public void restoreCoverageData() {
myData = new SoftReference<>(null);
}
public String getPresentableName() {
return StringUtil.join(mySuites, coverageSuite -> coverageSuite.getPresentableName(), ", ");
}
public boolean isModuleChecked(final Module module) {
return myProcessedModules != null && myProcessedModules.contains(module);
}
public void checkModule(final Module module) {
if (myProcessedModules == null) {
myProcessedModules = new HashSet<>();
}
myProcessedModules.add(module);
}
@Nullable
public RunConfigurationBase getRunConfiguration() {
for (CoverageSuite suite : mySuites) {
if (suite instanceof BaseCoverageSuite) {
final RunConfigurationBase configuration = ((BaseCoverageSuite)suite).getConfiguration();
if (configuration != null) {
return configuration;
}
}
}
return null;
}
public GlobalSearchScope getSearchScope(final Project project) {
if (myCachedValue == null) {
myCachedValue = CachedValuesManager.getManager(project).createCachedValue(
() -> new CachedValueProvider.Result<>(getSearchScopeInner(project), ProjectRootModificationTracker.getInstance(project)), false);
}
return myCachedValue.getValue();
}
private GlobalSearchScope getSearchScopeInner(Project project) {
Module[] modules = Arrays.stream(mySuites).filter(suite -> suite instanceof BaseCoverageSuite)
.map(suite -> ((BaseCoverageSuite)suite).getConfiguration())
.filter(configuration -> configuration instanceof ModuleBasedConfiguration)
.map(configuration -> ((ModuleBasedConfiguration)configuration).getConfigurationModule().getModule())
.toArray(Module[]::new);
if (modules.length == 0 || ArrayUtil.find(modules, null) > -1) {
return isTrackTestFolders() ? GlobalSearchScope.projectScope(project) : GlobalSearchScopesCore.projectProductionScope(project);
}
return GlobalSearchScope.union(Arrays.stream(modules).map(module -> GlobalSearchScope.moduleRuntimeScope(module, isTrackTestFolders())).toArray(GlobalSearchScope[]::new));
}
}