Add branch coverage to flutter test (#113802)
This commit is contained in:
parent
5259e1bc6d
commit
0c14308404
@ -121,6 +121,11 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
||||
help: 'Whether to merge coverage data with "coverage/lcov.base.info".\n'
|
||||
'Implies collecting coverage data. (Requires lcov.)',
|
||||
)
|
||||
..addFlag('branch-coverage',
|
||||
negatable: false,
|
||||
help: 'Whether to collect branch coverage information. '
|
||||
'Implies collecting coverage data.',
|
||||
)
|
||||
..addFlag('ipv6',
|
||||
negatable: false,
|
||||
hide: !verboseHelp,
|
||||
@ -378,7 +383,8 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
||||
|
||||
final bool machine = boolArgDeprecated('machine');
|
||||
CoverageCollector? collector;
|
||||
if (boolArgDeprecated('coverage') || boolArgDeprecated('merge-coverage')) {
|
||||
if (boolArgDeprecated('coverage') || boolArgDeprecated('merge-coverage') ||
|
||||
boolArgDeprecated('branch-coverage')) {
|
||||
final String projectName = flutterProject.manifest.appName;
|
||||
collector = CoverageCollector(
|
||||
verbose: !machine,
|
||||
@ -386,6 +392,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
||||
packagesPath: buildInfo.packagesPath,
|
||||
resolver: await CoverageCollector.getResolver(buildInfo.packagesPath),
|
||||
testTimeRecorder: testTimeRecorder,
|
||||
branchCoverage: boolArgDeprecated('branch-coverage'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,9 @@ import 'watcher.dart';
|
||||
|
||||
/// A class that collects code coverage data during test runs.
|
||||
class CoverageCollector extends TestWatcher {
|
||||
CoverageCollector({this.libraryNames, this.verbose = true, required this.packagesPath, this.resolver, this.testTimeRecorder});
|
||||
CoverageCollector({
|
||||
this.libraryNames, this.verbose = true, required this.packagesPath,
|
||||
this.resolver, this.testTimeRecorder, this.branchCoverage = false});
|
||||
|
||||
/// True when log messages should be emitted.
|
||||
final bool verbose;
|
||||
@ -38,6 +40,9 @@ class CoverageCollector extends TestWatcher {
|
||||
|
||||
final TestTimeRecorder? testTimeRecorder;
|
||||
|
||||
/// Whether to collect branch coverage information.
|
||||
bool branchCoverage;
|
||||
|
||||
static Future<coverage.Resolver> getResolver(String? packagesPath) async {
|
||||
try {
|
||||
return await coverage.Resolver.create(packagesPath: packagesPath);
|
||||
@ -97,7 +102,8 @@ class CoverageCollector extends TestWatcher {
|
||||
/// The returned [Future] completes when the coverage is collected.
|
||||
Future<void> collectCoverageIsolate(Uri observatoryUri) async {
|
||||
_logMessage('collecting coverage data from $observatoryUri...');
|
||||
final Map<String, dynamic> data = await collect(observatoryUri, libraryNames);
|
||||
final Map<String, dynamic> data = await collect(
|
||||
observatoryUri, libraryNames, branchCoverage: branchCoverage);
|
||||
if (data == null) {
|
||||
throw Exception('Failed to collect coverage.');
|
||||
}
|
||||
@ -136,7 +142,9 @@ class CoverageCollector extends TestWatcher {
|
||||
final Future<void> collectionComplete = testDevice.observatoryUri
|
||||
.then((Uri? observatoryUri) {
|
||||
_logMessage('collecting coverage data from $testDevice at $observatoryUri...');
|
||||
return collect(observatoryUri!, libraryNames, serviceOverride: serviceOverride)
|
||||
return collect(
|
||||
observatoryUri!, libraryNames, serviceOverride: serviceOverride,
|
||||
branchCoverage: branchCoverage)
|
||||
.then<void>((Map<String, dynamic> result) {
|
||||
if (result == null) {
|
||||
throw Exception('Failed to collect coverage.');
|
||||
@ -254,6 +262,10 @@ Future<Map<String, dynamic>> collect(Uri serviceUri, Set<String>? libraryNames,
|
||||
String? debugName,
|
||||
@visibleForTesting bool forceSequential = false,
|
||||
@visibleForTesting FlutterVmService? serviceOverride,
|
||||
bool branchCoverage = false,
|
||||
}) {
|
||||
return coverage.collect(serviceUri, false, false, false, libraryNames, serviceOverrideForTesting: serviceOverride?.service);
|
||||
return coverage.collect(
|
||||
serviceUri, false, false, false, libraryNames,
|
||||
serviceOverrideForTesting: serviceOverride?.service,
|
||||
branchCoverage: branchCoverage);
|
||||
}
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@Timeout.factor(10)
|
||||
|
||||
import 'dart:convert' show jsonEncode;
|
||||
import 'dart:io' show Directory, File;
|
||||
|
||||
@ -331,6 +329,97 @@ void main() {
|
||||
expect(fakeVmServiceHost.hasRemainingExpectations, false);
|
||||
});
|
||||
|
||||
testWithoutContext('Coverage collector with branch coverage', () async {
|
||||
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: 'getVersion',
|
||||
jsonResponse: Version(major: 3, minor: 56).toJson(),
|
||||
),
|
||||
FakeVmServiceRequest(
|
||||
method: 'getScripts',
|
||||
args: <String, Object>{
|
||||
'isolateId': '1',
|
||||
},
|
||||
jsonResponse: ScriptList(scripts: <ScriptRef>[
|
||||
ScriptRef(uri: 'package:foo/foo.dart', id: '1'),
|
||||
ScriptRef(uri: 'package:bar/bar.dart', id: '2'),
|
||||
]).toJson(),
|
||||
),
|
||||
FakeVmServiceRequest(
|
||||
method: 'getSourceReport',
|
||||
args: <String, Object>{
|
||||
'isolateId': '1',
|
||||
'reports': <Object>['Coverage', 'BranchCoverage'],
|
||||
'scriptId': '1',
|
||||
'forceCompile': true,
|
||||
'reportLines': true,
|
||||
},
|
||||
jsonResponse: SourceReport(
|
||||
ranges: <SourceReportRange>[
|
||||
SourceReportRange(
|
||||
scriptIndex: 0,
|
||||
startPos: 0,
|
||||
endPos: 0,
|
||||
compiled: true,
|
||||
coverage: SourceReportCoverage(
|
||||
hits: <int>[1, 3],
|
||||
misses: <int>[2],
|
||||
),
|
||||
branchCoverage: SourceReportCoverage(
|
||||
hits: <int>[4, 6],
|
||||
misses: <int>[5],
|
||||
),
|
||||
),
|
||||
],
|
||||
scripts: <ScriptRef>[
|
||||
ScriptRef(
|
||||
uri: 'package:foo/foo.dart',
|
||||
id: '1',
|
||||
),
|
||||
],
|
||||
).toJson(),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
final Map<String, Object?> result = await collect(
|
||||
Uri(),
|
||||
<String>{'foo'},
|
||||
serviceOverride: fakeVmServiceHost.vmService,
|
||||
branchCoverage: true,
|
||||
);
|
||||
|
||||
expect(result, <String, Object>{
|
||||
'type': 'CodeCoverage',
|
||||
'coverage': <Object>[
|
||||
<String, Object>{
|
||||
'source': 'package:foo/foo.dart',
|
||||
'script': <String, Object>{
|
||||
'type': '@Script',
|
||||
'fixedId': true,
|
||||
'id': 'libraries/1/scripts/package%3Afoo%2Ffoo.dart',
|
||||
'uri': 'package:foo/foo.dart',
|
||||
'_kind': 'library',
|
||||
},
|
||||
'hits': <Object>[1, 1, 3, 1, 2, 0],
|
||||
'branchHits': <Object>[4, 1, 6, 1, 5, 0],
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(fakeVmServiceHost.hasRemainingExpectations, false);
|
||||
});
|
||||
|
||||
testWithoutContext('Coverage collector caches read files', () async {
|
||||
Directory? tempDir;
|
||||
try {
|
||||
|
Loading…
x
Reference in New Issue
Block a user