-
Notifications
You must be signed in to change notification settings - Fork 324
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Repair the support for Test with Coverage #8007
Merged
jwren
merged 1 commit into
flutter:master
from
jwren:7810_test_coverage_regression_fix_3
Apr 7, 2025
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
flutter-idea/src/io/flutter/run/coverage/FlutterCoverageAnnotator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright 2021 The Chromium Authors. All rights reserved. | ||
* Use of this source code is governed by a BSD-style license that can be | ||
* found in the LICENSE file. | ||
*/ | ||
package io.flutter.run.coverage; | ||
|
||
import com.intellij.coverage.CoverageDataManager; | ||
import com.intellij.coverage.CoverageSuitesBundle; | ||
import com.intellij.coverage.SimpleCoverageAnnotator; | ||
import com.intellij.openapi.module.Module; | ||
import com.intellij.openapi.project.Project; | ||
import com.intellij.openapi.roots.ModuleRootManager; | ||
import com.intellij.openapi.vfs.VirtualFile; | ||
import io.flutter.utils.FlutterModuleUtils; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.io.File; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
public class FlutterCoverageAnnotator extends SimpleCoverageAnnotator { | ||
|
||
@Nullable | ||
public static FlutterCoverageAnnotator getInstance(Project project) { | ||
return project.getService(FlutterCoverageAnnotator.class); | ||
} | ||
|
||
public FlutterCoverageAnnotator(Project project) { | ||
super(project); | ||
} | ||
|
||
@Override | ||
protected FileCoverageInfo fillInfoForUncoveredFile(@NotNull File file) { | ||
return new FileCoverageInfo(); | ||
} | ||
|
||
@Override | ||
protected boolean shouldCollectCoverageInsideLibraryDirs() { | ||
return false; | ||
} | ||
|
||
@Override | ||
protected VirtualFile[] getRoots(Project project, | ||
@NotNull CoverageDataManager dataManager, | ||
CoverageSuitesBundle suite) { | ||
return dataManager.doInReadActionIfProjectOpen(() -> { | ||
final List<VirtualFile> roots = new ArrayList<>(); | ||
for (Module module : FlutterModuleUtils.findModulesWithFlutterContents(project)) { | ||
final ModuleRootManager rootManager = ModuleRootManager.getInstance(module); | ||
roots.addAll(Arrays.asList(rootManager.getContentRoots())); | ||
} | ||
return roots.toArray(VirtualFile.EMPTY_ARRAY); | ||
}); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add a trailing newline here and below? |
60 changes: 60 additions & 0 deletions
60
flutter-idea/src/io/flutter/run/coverage/FlutterCoverageEnabledConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
* Copyright 2021 The Chromium Authors. All rights reserved. | ||
* Use of this source code is governed by a BSD-style license that can be | ||
* found in the LICENSE file. | ||
*/ | ||
package io.flutter.run.coverage; | ||
|
||
import com.intellij.coverage.CoverageDataManager; | ||
import com.intellij.coverage.CoverageRunner; | ||
import com.intellij.execution.configurations.RunConfigurationBase; | ||
import com.intellij.execution.configurations.coverage.CoverageEnabledConfiguration; | ||
import com.intellij.openapi.application.ModalityState; | ||
import com.intellij.openapi.diagnostic.Logger; | ||
import com.intellij.openapi.vfs.VirtualFile; | ||
import com.intellij.util.ModalityUiUtil; | ||
import io.flutter.pub.PubRoot; | ||
import io.flutter.run.test.TestConfig; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
public class FlutterCoverageEnabledConfiguration extends CoverageEnabledConfiguration { | ||
private static final Logger LOG = Logger.getInstance(FlutterCoverageEnabledConfiguration.class.getName()); | ||
|
||
public FlutterCoverageEnabledConfiguration(@NotNull RunConfigurationBase<?> configuration) { | ||
super(configuration); | ||
super.setCoverageRunner(CoverageRunner.getInstance(FlutterCoverageRunner.class)); | ||
createCoverageFile(); | ||
ModalityUiUtil.invokeLaterIfNeeded( | ||
ModalityState.any(), | ||
() -> setCurrentCoverageSuite(CoverageDataManager.getInstance(configuration.getProject()).addCoverageSuite(this))); | ||
} | ||
|
||
@Override | ||
protected String createCoverageFile() { | ||
if (myCoverageFilePath == null) { | ||
if (!(getConfiguration() instanceof TestConfig)) { | ||
return ""; | ||
} | ||
VirtualFile file = ((TestConfig)getConfiguration()).getFields().getFileOrDir(); | ||
final VirtualFile root = PubRoot.forFile(file).getRoot(); | ||
myCoverageFilePath = root.getPath() + "/coverage/lcov.info"; | ||
} | ||
return myCoverageFilePath; | ||
} | ||
|
||
@Override | ||
public void setCoverageRunner(@Nullable final CoverageRunner coverageRunner) { | ||
// Save and restore myCoverageFilePath because the super method clears it. | ||
final String path = myCoverageFilePath; | ||
super.setCoverageRunner(coverageRunner); | ||
myCoverageFilePath = path; | ||
} | ||
|
||
@Override | ||
public void coverageRunnerExtensionRemoved(@NotNull CoverageRunner runner) { | ||
final String path = myCoverageFilePath; | ||
super.coverageRunnerExtensionRemoved(runner); | ||
myCoverageFilePath = path; | ||
} | ||
} |
163 changes: 163 additions & 0 deletions
163
flutter-idea/src/io/flutter/run/coverage/FlutterCoverageEngine.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
/* | ||
* Copyright 2021 The Chromium Authors. All rights reserved. | ||
* Use of this source code is governed by a BSD-style license that can be | ||
* found in the LICENSE file. | ||
*/ | ||
package io.flutter.run.coverage; | ||
|
||
import com.intellij.coverage.CoverageAnnotator; | ||
import com.intellij.coverage.CoverageEngine; | ||
import com.intellij.coverage.CoverageFileProvider; | ||
import com.intellij.coverage.CoverageRunner; | ||
import com.intellij.coverage.CoverageSuite; | ||
import com.intellij.coverage.CoverageSuitesBundle; | ||
import com.intellij.execution.configurations.RunConfigurationBase; | ||
import com.intellij.execution.configurations.RunProfile; | ||
import com.intellij.execution.configurations.WrappingRunConfiguration; | ||
import com.intellij.execution.configurations.coverage.CoverageEnabledConfiguration; | ||
import com.intellij.execution.testframework.AbstractTestProxy; | ||
import com.intellij.openapi.module.Module; | ||
import com.intellij.openapi.project.Project; | ||
import com.intellij.openapi.vfs.VirtualFile; | ||
import com.intellij.psi.PsiElement; | ||
import com.intellij.psi.PsiFile; | ||
import com.jetbrains.lang.dart.DartFileType; | ||
import com.jetbrains.lang.dart.psi.DartFile; | ||
import io.flutter.FlutterBundle; | ||
import io.flutter.FlutterUtils; | ||
import io.flutter.pub.PubRoot; | ||
import io.flutter.run.test.TestConfig; | ||
|
||
import java.io.File; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
public class FlutterCoverageEngine extends CoverageEngine { | ||
|
||
public static FlutterCoverageEngine getInstance() { | ||
return CoverageEngine.EP_NAME.findExtensionOrFail(FlutterCoverageEngine.class); | ||
} | ||
|
||
@Override | ||
public boolean isApplicableTo(@NotNull RunConfigurationBase conf) { | ||
return unwrapRunProfile(conf) instanceof TestConfig; | ||
} | ||
|
||
@Override | ||
public boolean canHavePerTestCoverage(@NotNull RunConfigurationBase conf) { | ||
return true; | ||
} | ||
|
||
@Override | ||
public @NotNull CoverageEnabledConfiguration createCoverageEnabledConfiguration(@NotNull RunConfigurationBase conf) { | ||
return new FlutterCoverageEnabledConfiguration(conf); | ||
} | ||
|
||
@Override | ||
public @Nullable CoverageSuite createCoverageSuite(@NotNull CoverageRunner covRunner, | ||
@NotNull String name, | ||
@NotNull CoverageFileProvider coverageDataFileProvider, | ||
@Nullable String[] filters, | ||
long lastCoverageTimeStamp, | ||
@Nullable String suiteToMerge, | ||
boolean coverageByTestEnabled, | ||
boolean tracingEnabled, | ||
boolean trackTestFolders, | ||
Project project) { | ||
return null; | ||
} | ||
|
||
@Override | ||
public @Nullable CoverageSuite createCoverageSuite(@NotNull CoverageRunner covRunner, | ||
@NotNull String name, | ||
@NotNull CoverageFileProvider coverageDataFileProvider, | ||
@NotNull CoverageEnabledConfiguration config) { | ||
if (config instanceof FlutterCoverageEnabledConfiguration) { | ||
return new FlutterCoverageSuite(covRunner, name, coverageDataFileProvider, | ||
config.getConfiguration().getProject(), this); | ||
} | ||
return null; | ||
} | ||
|
||
@Override | ||
public @Nullable CoverageSuite createEmptyCoverageSuite(@NotNull CoverageRunner coverageRunner) { | ||
return new FlutterCoverageSuite(this); | ||
} | ||
|
||
@Override | ||
public @NotNull CoverageAnnotator getCoverageAnnotator(Project project) { | ||
return FlutterCoverageAnnotator.getInstance(project); | ||
} | ||
|
||
@Override | ||
public boolean coverageEditorHighlightingApplicableTo(@NotNull PsiFile psiFile) { | ||
final PubRoot root = PubRoot.forPsiFile(psiFile); | ||
if (root == null) return false; | ||
final VirtualFile file = psiFile.getVirtualFile(); | ||
if (file == null) return false; | ||
final String path = root.getRelativePath(file); | ||
if (path == null) return false; | ||
return path.startsWith("lib") && FlutterUtils.isDartFile(file); | ||
} | ||
|
||
@Override | ||
public boolean coverageProjectViewStatisticsApplicableTo(VirtualFile fileOrDir) { | ||
return !fileOrDir.isDirectory() && fileOrDir.getFileType() instanceof DartFileType; | ||
} | ||
|
||
@Override | ||
public boolean acceptedByFilters(@NotNull PsiFile psiFile, @NotNull CoverageSuitesBundle suite) { | ||
return psiFile instanceof DartFile; | ||
} | ||
|
||
@Override | ||
public boolean recompileProjectAndRerunAction(@NotNull Module module, | ||
@NotNull CoverageSuitesBundle suite, | ||
@NotNull Runnable chooseSuiteAction) { | ||
return false; | ||
} | ||
|
||
@Override | ||
public String getQualifiedName(@NotNull final File outputFile, | ||
@NotNull final PsiFile sourceFile) { | ||
return getQName(sourceFile); | ||
} | ||
|
||
@Override | ||
public @NotNull Set<String> getQualifiedNames(@NotNull PsiFile sourceFile) { | ||
final Set<String> qualifiedNames = new HashSet<>(); | ||
qualifiedNames.add(getQName(sourceFile)); | ||
return qualifiedNames; | ||
} | ||
|
||
@Override | ||
public List<PsiElement> findTestsByNames(@NotNull String[] testNames, @NotNull Project project) { | ||
return null; | ||
} | ||
|
||
@Override | ||
public @Nullable String getTestMethodName(@NotNull PsiElement element, @NotNull AbstractTestProxy testProxy) { | ||
return null; | ||
} | ||
|
||
@Override | ||
public String getPresentableText() { | ||
return FlutterBundle.message("flutter.coverage.presentable.text"); | ||
} | ||
|
||
@NotNull | ||
private static String getQName(@NotNull PsiFile sourceFile) { | ||
return sourceFile.getVirtualFile().getPath(); | ||
} | ||
|
||
static @NotNull RunProfile unwrapRunProfile(@NotNull RunProfile runProfile) { | ||
if (runProfile instanceof WrappingRunConfiguration) { | ||
return ((WrappingRunConfiguration<?>)runProfile).getPeer(); | ||
} | ||
return runProfile; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be 2025? (Similarly for the other new files?)