Skip to content

Commit 09367ad

Browse files
authored
Make coverage collection aware of workspaces (flutter#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 flutter#159390
1 parent 7982d39 commit 09367ad

File tree

6 files changed

+188
-2
lines changed

6 files changed

+188
-2
lines changed

packages/flutter_tools/lib/src/commands/test.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -727,8 +727,15 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
727727
FlutterProject flutterProject,
728728
PackageConfig packageConfig,
729729
) {
730-
final String projectName = flutterProject.manifest.appName;
731-
final Set<String> packagesToInclude = <String>{if (packagesRegExps.isEmpty) projectName};
730+
final Set<String> packagesToInclude = <String>{};
731+
if (packagesRegExps.isEmpty) {
732+
void addProject(FlutterProject project) {
733+
packagesToInclude.add(project.manifest.appName);
734+
project.workspaceProjects.forEach(addProject);
735+
}
736+
737+
addProject(flutterProject);
738+
}
732739
try {
733740
for (final String regExpStr in packagesRegExps) {
734741
final RegExp regExp = RegExp(regExpStr);

packages/flutter_tools/lib/src/flutter_manifest.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ class FlutterManifest {
140140
return dependencies != null ? <String>{...dependencies.keys.cast<String>()} : <String>{};
141141
}
142142

143+
/// List of all the entries in the workspace field of the `pubspec.yaml` file.
144+
List<String> get workspace =>
145+
(_descriptor['workspace'] as YamlList?)?.cast<String>() ?? <String>[];
146+
143147
// Flag to avoid printing multiple invalid version messages.
144148
bool _hasShowInvalidVersionMsg = false;
145149

packages/flutter_tools/lib/src/project.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,16 @@ class FlutterProject {
131131
/// The manifest of the example sub-project of this project.
132132
final FlutterManifest _exampleManifest;
133133

134+
/// List of [FlutterProject]s corresponding to the workspace entries.
135+
List<FlutterProject> get workspaceProjects =>
136+
manifest.workspace
137+
.map(
138+
(String entry) => FlutterProject.fromDirectory(
139+
directory.childDirectory(directory.fileSystem.path.normalize(entry)),
140+
),
141+
)
142+
.toList();
143+
134144
/// The set of organization names found in this project as
135145
/// part of iOS product bundle identifier, Android application ID, or
136146
/// Gradle group ID.

packages/flutter_tools/test/commands.shard/hermetic/test_test.dart

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,98 @@ dev_dependencies:
358358
},
359359
);
360360

361+
testUsingContext(
362+
'Coverage provides current library name and workspace names to Coverage Collector by default',
363+
() async {
364+
final Directory package = fs.currentDirectory;
365+
package.childFile('pubspec.yaml').writeAsStringSync('''
366+
name: my_app
367+
dev_dependencies:
368+
flutter_test:
369+
sdk: flutter
370+
integration_test:
371+
sdk: flutter
372+
workspace:
373+
- child1
374+
- child2
375+
''');
376+
package.childDirectory('child1').childFile('pubspec.yaml')
377+
..createSync(recursive: true)
378+
..writeAsStringSync('''
379+
name: child1
380+
resolution: workspace
381+
''');
382+
package.childDirectory('child2').childFile('pubspec.yaml')
383+
..createSync(recursive: true)
384+
..writeAsStringSync('''
385+
name: child2
386+
resolution: workspace
387+
workspace:
388+
- example
389+
''');
390+
package.childDirectory('child2').childDirectory('example').childFile('pubspec.yaml')
391+
..createSync(recursive: true)
392+
..writeAsStringSync('''
393+
name: child2_example
394+
resolution: workspace
395+
''');
396+
397+
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
398+
requests: <VmServiceExpectation>[
399+
FakeVmServiceRequest(
400+
method: 'getVM',
401+
jsonResponse:
402+
(VM.parse(<String, Object>{})!
403+
..isolates = <IsolateRef>[
404+
IsolateRef.parse(<String, Object>{'id': '1'})!,
405+
])
406+
.toJson(),
407+
),
408+
FakeVmServiceRequest(
409+
method: 'getSourceReport',
410+
args: <String, Object>{
411+
'isolateId': '1',
412+
'reports': <Object>['Coverage'],
413+
'forceCompile': true,
414+
'reportLines': true,
415+
'libraryFilters': <String>[
416+
'package:my_app/',
417+
'package:child1/',
418+
'package:child2/',
419+
'package:child2_example/',
420+
],
421+
'librariesAlreadyCompiled': <Object>[],
422+
},
423+
jsonResponse: SourceReport(ranges: <SourceReportRange>[]).toJson(),
424+
),
425+
],
426+
);
427+
final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0, null, fakeVmServiceHost);
428+
429+
final TestCommand testCommand = TestCommand(testRunner: testRunner);
430+
final CommandRunner<void> commandRunner = createTestCommandRunner(testCommand);
431+
await commandRunner.run(const <String>[
432+
'test',
433+
'--no-pub',
434+
'--coverage',
435+
'--',
436+
'test/some_test.dart',
437+
]);
438+
expect(fakeVmServiceHost.hasRemainingExpectations, false);
439+
expect((testRunner.lastTestWatcher! as CoverageCollector).libraryNames, <String>{
440+
'my_app',
441+
'child1',
442+
'child2',
443+
'child2_example',
444+
});
445+
},
446+
overrides: <Type, Generator>{
447+
FileSystem: () => fs,
448+
ProcessManager: () => FakeProcessManager.any(),
449+
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
450+
},
451+
);
452+
361453
testUsingContext(
362454
'Coverage provides library names matching regexps to Coverage Collector',
363455
() async {

packages/flutter_tools/test/general.shard/flutter_manifest_test.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,35 @@ flutter:
15471547
args:
15481548
- deferredComponentArg''');
15491549
});
1550+
1551+
testWithoutContext('FlutterManifest can parse workspace', () async {
1552+
const String manifest = '''
1553+
name: test
1554+
workspace:
1555+
- pkgs/bar
1556+
- pkgs/foo
1557+
''';
1558+
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
1559+
manifest,
1560+
logger: BufferLogger.test(),
1561+
);
1562+
1563+
expect(flutterManifest, isNotNull);
1564+
expect(flutterManifest!.workspace, <String>['pkgs/bar', 'pkgs/foo']);
1565+
});
1566+
1567+
testWithoutContext('FlutterManifest can parse empty workspace', () async {
1568+
const String manifest = '''
1569+
name: test
1570+
''';
1571+
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
1572+
manifest,
1573+
logger: BufferLogger.test(),
1574+
);
1575+
1576+
expect(flutterManifest, isNotNull);
1577+
expect(flutterManifest!.workspace, isEmpty);
1578+
});
15501579
}
15511580

15521581
Matcher matchesManifest({String? appVersion, String? buildName, String? buildNumber}) {

packages/flutter_tools/test/general.shard/project_test.dart

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,6 +1522,50 @@ plugins {
15221522
expect(updatedPubspecContents, validPubspecWithDependenciesAndNullValues);
15231523
});
15241524
});
1525+
1526+
group('workspaces', () {
1527+
_testInMemory('fails on invalid pubspec.yaml', () async {
1528+
final Directory directory = globals.fs.directory('myproject');
1529+
directory.childFile('pubspec.yaml')
1530+
..createSync(recursive: true)
1531+
..writeAsStringSync('''
1532+
name: parent
1533+
flutter:
1534+
workspace:
1535+
- child1
1536+
- child2
1537+
- child2/example
1538+
''');
1539+
directory.childDirectory('child1').childFile('pubspec.yaml')
1540+
..createSync(recursive: true)
1541+
..writeAsStringSync('''
1542+
name: child1
1543+
flutter:
1544+
resolution: workspace
1545+
''');
1546+
directory.childDirectory('child2').childFile('pubspec.yaml')
1547+
..createSync(recursive: true)
1548+
..writeAsStringSync('''
1549+
name: child2
1550+
flutter:
1551+
resolution: workspace
1552+
''');
1553+
directory.childDirectory('child2').childDirectory('example').childFile('pubspec.yaml')
1554+
..createSync(recursive: true)
1555+
..writeAsStringSync('''
1556+
name: child2_example
1557+
flutter:
1558+
resolution: workspace
1559+
''');
1560+
1561+
expect(
1562+
FlutterProject.fromDirectory(directory).workspaceProjects
1563+
.map((FlutterProject subproject) => subproject.manifest.appName)
1564+
.toList(),
1565+
<String>['child1', 'child2', 'child2_example'],
1566+
);
1567+
});
1568+
});
15251569
});
15261570

15271571
group('watch companion', () {

0 commit comments

Comments
 (0)