Make coverage collection aware of workspaces (#166389)
By default, `CoverageCollector.libraryNames` was being set to the name of the current `FlutterProject`. This means that only tests in the current project are included in the coverage report. So if the project is a workspace, tests in its subprojects were being excluded. I've changed it so that it also allows tests that are part of any of the subprojects. Fixes #159390
This commit is contained in:
@@ -727,8 +727,15 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
|||||||
FlutterProject flutterProject,
|
FlutterProject flutterProject,
|
||||||
PackageConfig packageConfig,
|
PackageConfig packageConfig,
|
||||||
) {
|
) {
|
||||||
final String projectName = flutterProject.manifest.appName;
|
final Set<String> packagesToInclude = <String>{};
|
||||||
final Set<String> packagesToInclude = <String>{if (packagesRegExps.isEmpty) projectName};
|
if (packagesRegExps.isEmpty) {
|
||||||
|
void addProject(FlutterProject project) {
|
||||||
|
packagesToInclude.add(project.manifest.appName);
|
||||||
|
project.workspaceProjects.forEach(addProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
addProject(flutterProject);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
for (final String regExpStr in packagesRegExps) {
|
for (final String regExpStr in packagesRegExps) {
|
||||||
final RegExp regExp = RegExp(regExpStr);
|
final RegExp regExp = RegExp(regExpStr);
|
||||||
|
|||||||
@@ -140,6 +140,10 @@ class FlutterManifest {
|
|||||||
return dependencies != null ? <String>{...dependencies.keys.cast<String>()} : <String>{};
|
return dependencies != null ? <String>{...dependencies.keys.cast<String>()} : <String>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List of all the entries in the workspace field of the `pubspec.yaml` file.
|
||||||
|
List<String> get workspace =>
|
||||||
|
(_descriptor['workspace'] as YamlList?)?.cast<String>() ?? <String>[];
|
||||||
|
|
||||||
// Flag to avoid printing multiple invalid version messages.
|
// Flag to avoid printing multiple invalid version messages.
|
||||||
bool _hasShowInvalidVersionMsg = false;
|
bool _hasShowInvalidVersionMsg = false;
|
||||||
|
|
||||||
|
|||||||
@@ -131,6 +131,16 @@ class FlutterProject {
|
|||||||
/// The manifest of the example sub-project of this project.
|
/// The manifest of the example sub-project of this project.
|
||||||
final FlutterManifest _exampleManifest;
|
final FlutterManifest _exampleManifest;
|
||||||
|
|
||||||
|
/// List of [FlutterProject]s corresponding to the workspace entries.
|
||||||
|
List<FlutterProject> get workspaceProjects =>
|
||||||
|
manifest.workspace
|
||||||
|
.map(
|
||||||
|
(String entry) => FlutterProject.fromDirectory(
|
||||||
|
directory.childDirectory(directory.fileSystem.path.normalize(entry)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
/// The set of organization names found in this project as
|
/// The set of organization names found in this project as
|
||||||
/// part of iOS product bundle identifier, Android application ID, or
|
/// part of iOS product bundle identifier, Android application ID, or
|
||||||
/// Gradle group ID.
|
/// Gradle group ID.
|
||||||
|
|||||||
@@ -358,6 +358,98 @@ dev_dependencies:
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
testUsingContext(
|
||||||
|
'Coverage provides current library name and workspace names to Coverage Collector by default',
|
||||||
|
() async {
|
||||||
|
final Directory package = fs.currentDirectory;
|
||||||
|
package.childFile('pubspec.yaml').writeAsStringSync('''
|
||||||
|
name: my_app
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
integration_test:
|
||||||
|
sdk: flutter
|
||||||
|
workspace:
|
||||||
|
- child1
|
||||||
|
- child2
|
||||||
|
''');
|
||||||
|
package.childDirectory('child1').childFile('pubspec.yaml')
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync('''
|
||||||
|
name: child1
|
||||||
|
resolution: workspace
|
||||||
|
''');
|
||||||
|
package.childDirectory('child2').childFile('pubspec.yaml')
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync('''
|
||||||
|
name: child2
|
||||||
|
resolution: workspace
|
||||||
|
workspace:
|
||||||
|
- example
|
||||||
|
''');
|
||||||
|
package.childDirectory('child2').childDirectory('example').childFile('pubspec.yaml')
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync('''
|
||||||
|
name: child2_example
|
||||||
|
resolution: workspace
|
||||||
|
''');
|
||||||
|
|
||||||
|
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
||||||
|
requests: <VmServiceExpectation>[
|
||||||
|
FakeVmServiceRequest(
|
||||||
|
method: 'getVM',
|
||||||
|
jsonResponse:
|
||||||
|
(VM.parse(<String, Object>{})!
|
||||||
|
..isolates = <IsolateRef>[
|
||||||
|
IsolateRef.parse(<String, Object>{'id': '1'})!,
|
||||||
|
])
|
||||||
|
.toJson(),
|
||||||
|
),
|
||||||
|
FakeVmServiceRequest(
|
||||||
|
method: 'getSourceReport',
|
||||||
|
args: <String, Object>{
|
||||||
|
'isolateId': '1',
|
||||||
|
'reports': <Object>['Coverage'],
|
||||||
|
'forceCompile': true,
|
||||||
|
'reportLines': true,
|
||||||
|
'libraryFilters': <String>[
|
||||||
|
'package:my_app/',
|
||||||
|
'package:child1/',
|
||||||
|
'package:child2/',
|
||||||
|
'package:child2_example/',
|
||||||
|
],
|
||||||
|
'librariesAlreadyCompiled': <Object>[],
|
||||||
|
},
|
||||||
|
jsonResponse: SourceReport(ranges: <SourceReportRange>[]).toJson(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0, null, fakeVmServiceHost);
|
||||||
|
|
||||||
|
final TestCommand testCommand = TestCommand(testRunner: testRunner);
|
||||||
|
final CommandRunner<void> commandRunner = createTestCommandRunner(testCommand);
|
||||||
|
await commandRunner.run(const <String>[
|
||||||
|
'test',
|
||||||
|
'--no-pub',
|
||||||
|
'--coverage',
|
||||||
|
'--',
|
||||||
|
'test/some_test.dart',
|
||||||
|
]);
|
||||||
|
expect(fakeVmServiceHost.hasRemainingExpectations, false);
|
||||||
|
expect((testRunner.lastTestWatcher! as CoverageCollector).libraryNames, <String>{
|
||||||
|
'my_app',
|
||||||
|
'child1',
|
||||||
|
'child2',
|
||||||
|
'child2_example',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
testUsingContext(
|
testUsingContext(
|
||||||
'Coverage provides library names matching regexps to Coverage Collector',
|
'Coverage provides library names matching regexps to Coverage Collector',
|
||||||
() async {
|
() async {
|
||||||
|
|||||||
@@ -1547,6 +1547,35 @@ flutter:
|
|||||||
args:
|
args:
|
||||||
- deferredComponentArg''');
|
- deferredComponentArg''');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext('FlutterManifest can parse workspace', () async {
|
||||||
|
const String manifest = '''
|
||||||
|
name: test
|
||||||
|
workspace:
|
||||||
|
- pkgs/bar
|
||||||
|
- pkgs/foo
|
||||||
|
''';
|
||||||
|
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
|
||||||
|
manifest,
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(flutterManifest, isNotNull);
|
||||||
|
expect(flutterManifest!.workspace, <String>['pkgs/bar', 'pkgs/foo']);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('FlutterManifest can parse empty workspace', () async {
|
||||||
|
const String manifest = '''
|
||||||
|
name: test
|
||||||
|
''';
|
||||||
|
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
|
||||||
|
manifest,
|
||||||
|
logger: BufferLogger.test(),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(flutterManifest, isNotNull);
|
||||||
|
expect(flutterManifest!.workspace, isEmpty);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Matcher matchesManifest({String? appVersion, String? buildName, String? buildNumber}) {
|
Matcher matchesManifest({String? appVersion, String? buildName, String? buildNumber}) {
|
||||||
|
|||||||
@@ -1522,6 +1522,50 @@ plugins {
|
|||||||
expect(updatedPubspecContents, validPubspecWithDependenciesAndNullValues);
|
expect(updatedPubspecContents, validPubspecWithDependenciesAndNullValues);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('workspaces', () {
|
||||||
|
_testInMemory('fails on invalid pubspec.yaml', () async {
|
||||||
|
final Directory directory = globals.fs.directory('myproject');
|
||||||
|
directory.childFile('pubspec.yaml')
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync('''
|
||||||
|
name: parent
|
||||||
|
flutter:
|
||||||
|
workspace:
|
||||||
|
- child1
|
||||||
|
- child2
|
||||||
|
- child2/example
|
||||||
|
''');
|
||||||
|
directory.childDirectory('child1').childFile('pubspec.yaml')
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync('''
|
||||||
|
name: child1
|
||||||
|
flutter:
|
||||||
|
resolution: workspace
|
||||||
|
''');
|
||||||
|
directory.childDirectory('child2').childFile('pubspec.yaml')
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync('''
|
||||||
|
name: child2
|
||||||
|
flutter:
|
||||||
|
resolution: workspace
|
||||||
|
''');
|
||||||
|
directory.childDirectory('child2').childDirectory('example').childFile('pubspec.yaml')
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync('''
|
||||||
|
name: child2_example
|
||||||
|
flutter:
|
||||||
|
resolution: workspace
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
FlutterProject.fromDirectory(directory).workspaceProjects
|
||||||
|
.map((FlutterProject subproject) => subproject.manifest.appName)
|
||||||
|
.toList(),
|
||||||
|
<String>['child1', 'child2', 'child2_example'],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group('watch companion', () {
|
group('watch companion', () {
|
||||||
|
|||||||
Reference in New Issue
Block a user