diff --git a/pkgs/test/CHANGELOG.md b/pkgs/test/CHANGELOG.md index c6e92726d..2893eb21f 100644 --- a/pkgs/test/CHANGELOG.md +++ b/pkgs/test/CHANGELOG.md @@ -1,7 +1,8 @@ -## 1.26.4-wip +## 1.27.0-wip * Restrict to latest version of analyzer package. * Require Dart 3.7 +* Add `--coverage-path` and `--branch-coverage` options to `dart test`. ## 1.26.3 diff --git a/pkgs/test/README.md b/pkgs/test/README.md index 36103d9c1..ccca4504a 100644 --- a/pkgs/test/README.md +++ b/pkgs/test/README.md @@ -257,36 +257,25 @@ The available options for the `--reporter` flag are: ### Collecting Code Coverage -To collect code coverage, you can run tests with the `--coverage ` -argument. The directory specified can be an absolute or relative path. -If a directory does not exist at the path specified, a directory will be -created. If a directory does exist, files may be overwritten with the latest -coverage data, if they conflict. - -This option will enable code coverage collection on a suite-by-suite basis, -and the resulting coverage files will be outputted in the directory specified. -The files can then be formatted using the `package:coverage` -`format_coverage` executable. +To collect code coverage, you can run tests with the `--coverage-path ` +argument, which outputs a LCOV report to the given file path. The file +specified can be an absolute or relative path. If a directory does not exist at +the path specified, a directory will be created. If a directory does exist, +files may be overwritten with the latest coverage data, if they conflict. Coverage gathering is currently only implemented for tests run on the Dart VM or Chrome. -Here's an example of how to run tests and format the collected coverage to LCOV: +Here's an example of how to run tests and collect coverage: ```shell -## Run Dart tests and output them at directory `./coverage`: -dart run test --coverage=./coverage - -## Activate package `coverage` (if needed): -dart pub global activate coverage - -## Format collected coverage to LCOV (only for directory "lib") -dart pub global run coverage:format_coverage --packages=.dart_tool/package_config.json --report-on=lib --lcov -o ./coverage/lcov.info -i ./coverage +## Run Dart tests and output coverage info to `./coverage/lcov.info`: +dart run test --coverage-path=./coverage/lcov.info -## Generate LCOV report: +## Generate a human readable report: genhtml -o ./coverage/report ./coverage/lcov.info -## Open the HTML coverage report: +## Open the coverage report: open ./coverage/report/index.html ``` diff --git a/pkgs/test/pubspec.yaml b/pkgs/test/pubspec.yaml index 0208cbc9d..7c167d764 100644 --- a/pkgs/test/pubspec.yaml +++ b/pkgs/test/pubspec.yaml @@ -1,5 +1,5 @@ name: test -version: 1.26.4-wip +version: 1.27.0-wip description: >- A full featured library for writing and running Dart tests across platforms. repository: https://github.com/dart-lang/test/tree/master/pkgs/test @@ -14,7 +14,7 @@ dependencies: async: ^2.5.0 boolean_selector: ^2.1.0 collection: ^1.15.0 - coverage: ^1.0.1 + coverage: ^1.15.0 http_multi_server: ^3.0.0 io: ^1.0.0 js: '>=0.6.4 <0.8.0' diff --git a/pkgs/test/test/io.dart b/pkgs/test/test/io.dart index 3e878fca1..7096896f5 100644 --- a/pkgs/test/test/io.dart +++ b/pkgs/test/test/io.dart @@ -21,14 +21,6 @@ final Future packageDir = Isolate.resolvePackageUri( return dir; }); -/// The path to the `pub` executable in the current Dart SDK. -final _pubPath = p.absolute( - p.join( - p.dirname(Platform.resolvedExecutable), - Platform.isWindows ? 'pub.bat' : 'pub', - ), -); - /// The platform-specific message emitted when a nonexistent file is loaded. final String noSuchFileMessage = Platform.isWindows @@ -174,8 +166,8 @@ Future runPub( Map? environment, }) { return TestProcess.start( - _pubPath, - args, + p.absolute(Platform.resolvedExecutable), + ['pub', ...args], workingDirectory: d.sandbox, environment: environment, description: 'pub ${args.first}', diff --git a/pkgs/test/test/runner/coverage_test.dart b/pkgs/test/test/runner/coverage_test.dart index e52255924..62dce565f 100644 --- a/pkgs/test/test/runner/coverage_test.dart +++ b/pkgs/test/test/runner/coverage_test.dart @@ -8,6 +8,7 @@ library; import 'dart:convert'; import 'dart:io'; +import 'package:coverage/coverage.dart'; import 'package:path/path.dart' as p; import 'package:test/test.dart'; import 'package:test_descriptor/test_descriptor.dart' as d; @@ -20,31 +21,66 @@ void main() { group('with the --coverage flag,', () { late Directory coverageDirectory; + late d.DirectoryDescriptor packageDirectory; - Future validateCoverage(TestProcess test, String coveragePath) async { + Future validateTest(TestProcess test) async { expect(test.stdout, emitsThrough(contains('+1: All tests passed!'))); await test.shouldExit(0); + } + + Future> validateCoverage( + TestProcess test, + String coveragePath, + ) async { + await validateTest(test); final coverageFile = File(p.join(coverageDirectory.path, coveragePath)); final coverage = await coverageFile.readAsString(); - final jsonCoverage = json.decode(coverage); - expect(jsonCoverage['coverage'], isNotEmpty); + final jsonCoverage = json.decode(coverage)['coverage'] as List; + expect(jsonCoverage, isNotEmpty); + + return HitMap.parseJson(jsonCoverage.cast>()); } setUp(() async { - await d.file('test.dart', ''' - import 'package:test/test.dart'; - - void main() { - test("test 1", () { - expect(true, isTrue); - }); - } - ''').create(); - coverageDirectory = await Directory.systemTemp.createTemp( 'test_coverage', ); + + packageDirectory = d.dir(d.sandbox, [ + d.dir('lib', [ + d.file('calculate.dart', ''' + int calculate(int x) { + if (x % 2 == 0) { + return x * 2; + } else { + return x * 3; + } + } + '''), + ]), + d.dir('test', [ + d.file('test.dart', ''' + import 'package:fake_package/calculate.dart'; + import 'package:test/test.dart'; + + void main() { + test('test 1', () { + expect(calculate(6), 12); + }); + } + '''), + ]), + d.file('pubspec.yaml', ''' +name: fake_package +version: 1.0.0 +environment: + sdk: ^3.5.0 +dev_dependencies: + test: ^1.26.2 + '''), + ]); + await packageDirectory.create(); }); tearDown(() async { @@ -52,23 +88,69 @@ void main() { }); test('gathers coverage for VM tests', () async { + await (await runPub(['get'])).shouldExit(0); var test = await runTest([ '--coverage', coverageDirectory.path, - 'test.dart', - ]); - await validateCoverage(test, 'test.dart.vm.json'); + 'test/test.dart', + ], packageConfig: p.join(d.sandbox, '.dart_tool/package_config.json')); + final coverage = await validateCoverage(test, 'test/test.dart.vm.json'); + final hitmap = coverage['package:fake_package/calculate.dart']!; + expect(hitmap.lineHits, {1: 1, 2: 2, 3: 1, 5: 0}); + expect(hitmap.funcHits, isNull); + expect(hitmap.branchHits, isNull); + }); + + test('gathers branch coverage for VM tests', () async { + await (await runPub(['get'])).shouldExit(0); + var test = await runTest( + [ + '--coverage', + coverageDirectory.path, + '--branch-coverage', + 'test/test.dart', + ], + vmArgs: ['--branch-coverage'], + packageConfig: p.join(d.sandbox, '.dart_tool/package_config.json'), + ); + final coverage = await validateCoverage(test, 'test/test.dart.vm.json'); + final hitmap = coverage['package:fake_package/calculate.dart']!; + expect(hitmap.lineHits, {1: 1, 2: 2, 3: 1, 5: 0}); + expect(hitmap.funcHits, isNull); + expect(hitmap.branchHits, {1: 1, 2: 1, 4: 0}); + }); + + test('gathers lcov coverage for VM tests', () async { + await (await runPub(['get'])).shouldExit(0); + final lcovFile = p.join(coverageDirectory.path, 'lcov.info'); + var test = await runTest([ + '--coverage-path', + lcovFile, + 'test/test.dart', + ], packageConfig: p.join(d.sandbox, '.dart_tool/package_config.json')); + await validateTest(test); + expect(File(lcovFile).readAsStringSync(), ''' +SF:${p.join(d.sandbox, 'lib', 'calculate.dart')} +DA:1,1 +DA:2,2 +DA:3,1 +DA:5,0 +LF:4 +LH:3 +end_of_record +'''); }); test('gathers coverage for Chrome tests', () async { + await (await runPub(['get'])).shouldExit(0); var test = await runTest([ '--coverage', coverageDirectory.path, - 'test.dart', + 'test/test.dart', '-p', 'chrome', - ]); - await validateCoverage(test, 'test.dart.chrome.json'); + ], packageConfig: p.join(d.sandbox, '.dart_tool/package_config.json')); + await validateCoverage(test, 'test/test.dart.chrome.json'); }); test( diff --git a/pkgs/test/test/runner/runner_test.dart b/pkgs/test/test/runner/runner_test.dart index 4a96ffdb7..fdb4c5738 100644 --- a/pkgs/test/test/runner/runner_test.dart +++ b/pkgs/test/test/runner/runner_test.dart @@ -92,6 +92,10 @@ $_runtimeCompilers --debug Run the VM and Chrome tests in debug mode. --coverage= Gather coverage and output it to the specified directory. Implies --debug. + --coverage-path= Gather coverage and output an lcov report to the specified file. + Implies --debug. + --branch-coverage Include branch coverage information in the coverage report. + Must be paired with --coverage or --coverage-path. --[no-]chain-stack-traces Use chained stack traces to provide greater exception details especially for asynchronous code. It may be useful to disable to provide improved test performance but at the cost of diff --git a/pkgs/test/test/utils.dart b/pkgs/test/test/utils.dart index f2d941b88..cfa26cff2 100644 --- a/pkgs/test/test/utils.dart +++ b/pkgs/test/test/utils.dart @@ -138,6 +138,7 @@ Engine declareEngine( void Function() body, { bool runSkipped = false, String? coverage, + String? coverageLcov, bool stopOnFirstFailure = false, }) { var declarer = Declarer()..declare(body); @@ -151,6 +152,7 @@ Engine declareEngine( ), ], coverage: coverage, + coverageLcov: coverageLcov, stopOnFirstFailure: stopOnFirstFailure, ); } @@ -222,6 +224,8 @@ Configuration configuration({ String? reporter, Map? fileReporters, String? coverage, + String? coverageLcov, + bool? branchCoverage, int? concurrency, int? shardIndex, int? totalShards, @@ -272,6 +276,8 @@ Configuration configuration({ reporter: reporter, fileReporters: fileReporters, coverage: coverage, + coverageLcov: coverageLcov, + branchCoverage: branchCoverage, concurrency: concurrency, shardIndex: shardIndex, totalShards: totalShards, diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md index 2126ef1c7..74d7fb713 100644 --- a/pkgs/test_core/CHANGELOG.md +++ b/pkgs/test_core/CHANGELOG.md @@ -2,6 +2,7 @@ * Restrict to latest version of analyzer package. * Require Dart 3.7 +* Add `--coverage-path` and `--branch-coverage` options to `dart test`. ## 0.6.12 diff --git a/pkgs/test_core/lib/src/runner.dart b/pkgs/test_core/lib/src/runner.dart index f8fb1df48..7aedabbdb 100644 --- a/pkgs/test_core/lib/src/runner.dart +++ b/pkgs/test_core/lib/src/runner.dart @@ -77,6 +77,7 @@ class Runner { var engine = Engine( concurrency: config.concurrency, coverage: config.coverage, + coverageLcov: config.coverageLcov, testRandomizeOrderingSeed: config.testRandomizeOrderingSeed, stopOnFirstFailure: config.stopOnFirstFailure, ); diff --git a/pkgs/test_core/lib/src/runner/configuration.dart b/pkgs/test_core/lib/src/runner/configuration.dart index 9434ed3d4..e9c3bebe9 100644 --- a/pkgs/test_core/lib/src/runner/configuration.dart +++ b/pkgs/test_core/lib/src/runner/configuration.dart @@ -58,12 +58,23 @@ class Configuration { final bool? _pauseAfterLoad; /// Whether to run browsers in their respective debug modes - bool get debug => pauseAfterLoad || (_debug ?? false) || coverage != null; + bool get debug => + pauseAfterLoad || + (_debug ?? false) || + coverage != null || + coverageLcov != null; final bool? _debug; - /// The output folder for coverage gathering + /// The output folder for coverage gathering. final String? coverage; + /// The lcov file to output coverage to. + final String? coverageLcov; + + /// Whether to collect branch coverage info. + bool get branchCoverage => _branchCoverage ?? false; + final bool? _branchCoverage; + /// The path to the file from which to load more configuration information. /// /// This is *not* resolved automatically. @@ -260,6 +271,8 @@ class Configuration { required String? reporter, required Map? fileReporters, required String? coverage, + required String? coverageLcov, + required bool? branchCoverage, required int? concurrency, required int? shardIndex, required int? totalShards, @@ -313,6 +326,8 @@ class Configuration { reporter: reporter, fileReporters: fileReporters, coverage: coverage, + coverageLcov: coverageLcov, + branchCoverage: branchCoverage, concurrency: concurrency, shardIndex: shardIndex, totalShards: totalShards, @@ -372,6 +387,8 @@ class Configuration { String? reporter, Map? fileReporters, String? coverage, + String? coverageLcov, + bool? branchCoverage, int? concurrency, int? shardIndex, int? totalShards, @@ -423,6 +440,8 @@ class Configuration { reporter: reporter, fileReporters: fileReporters, coverage: coverage, + coverageLcov: coverageLcov, + branchCoverage: branchCoverage, concurrency: concurrency, shardIndex: shardIndex, totalShards: totalShards, @@ -491,6 +510,8 @@ class Configuration { reporter: null, fileReporters: null, coverage: null, + coverageLcov: null, + branchCoverage: null, concurrency: null, shardIndex: null, totalShards: null, @@ -555,6 +576,8 @@ class Configuration { reporter: null, fileReporters: null, coverage: null, + coverageLcov: null, + branchCoverage: null, concurrency: null, shardIndex: null, totalShards: null, @@ -622,6 +645,8 @@ class Configuration { color: null, configurationPath: null, coverage: null, + coverageLcov: null, + branchCoverage: null, shardIndex: null, totalShards: null, testSelections: null, @@ -683,6 +708,8 @@ class Configuration { reporter: null, fileReporters: null, coverage: null, + coverageLcov: null, + branchCoverage: null, concurrency: null, shardIndex: null, totalShards: null, @@ -750,6 +777,8 @@ class Configuration { required String? reporter, required Map? fileReporters, required this.coverage, + required this.coverageLcov, + required bool? branchCoverage, required int? concurrency, required this.shardIndex, required this.totalShards, @@ -776,6 +805,7 @@ class Configuration { _configurationPath = configurationPath, _reporter = reporter, fileReporters = fileReporters ?? {}, + _branchCoverage = branchCoverage, _concurrency = concurrency, _testSelections = testSelections == null || testSelections.isEmpty @@ -841,6 +871,8 @@ class Configuration { reporter: null, fileReporters: null, coverage: null, + coverageLcov: null, + branchCoverage: null, concurrency: null, shardIndex: null, totalShards: null, @@ -941,6 +973,8 @@ class Configuration { reporter: other._reporter ?? _reporter, fileReporters: mergeMaps(fileReporters, other.fileReporters), coverage: other.coverage ?? coverage, + coverageLcov: other.coverageLcov ?? coverageLcov, + branchCoverage: other._branchCoverage ?? _branchCoverage, concurrency: other._concurrency ?? _concurrency, shardIndex: other.shardIndex ?? shardIndex, totalShards: other.totalShards ?? totalShards, @@ -996,6 +1030,8 @@ class Configuration { String? reporter, Map? fileReporters, String? coverage, + String? coverageLcov, + bool? branchCoverage, int? concurrency, int? shardIndex, int? totalShards, @@ -1044,6 +1080,8 @@ class Configuration { reporter: reporter ?? _reporter, fileReporters: fileReporters ?? this.fileReporters, coverage: coverage ?? this.coverage, + coverageLcov: coverageLcov ?? this.coverageLcov, + branchCoverage: branchCoverage ?? _branchCoverage, concurrency: concurrency ?? _concurrency, shardIndex: shardIndex ?? this.shardIndex, totalShards: totalShards ?? this.totalShards, diff --git a/pkgs/test_core/lib/src/runner/configuration/args.dart b/pkgs/test_core/lib/src/runner/configuration/args.dart index b66435be8..e248bf244 100644 --- a/pkgs/test_core/lib/src/runner/configuration/args.dart +++ b/pkgs/test_core/lib/src/runner/configuration/args.dart @@ -166,6 +166,20 @@ final ArgParser _parser = 'Implies --debug.', valueHelp: 'directory', ); + parser.addOption( + 'coverage-path', + help: + 'Gather coverage and output an lcov report to the specified file.\n' + 'Implies --debug.', + valueHelp: 'file', + ); + parser.addFlag( + 'branch-coverage', + help: + 'Include branch coverage information in the coverage report.\n' + 'Must be paired with --coverage or --coverage-path.', + negatable: false, + ); parser.addFlag( 'chain-stack-traces', help: @@ -418,6 +432,19 @@ class _Parser { ); } + final coverageDir = _ifParsed('coverage'); + final coverageLcov = _ifParsed('coverage-path'); + final branchCoverage = _ifParsed('branch-coverage') ?? false; + if (coverageDir == null && coverageLcov == null && branchCoverage) { + throw ArgumentError( + 'If you set --branch-coverage you must set either --coverage or ' + '--coverage-path', + ); + } + if (coverageLcov != null && coverageDir != null) { + throw ArgumentError('Cannot set both --coverage and --coverage-path'); + } + return Configuration( help: _ifParsed('help'), version: _ifParsed('version'), @@ -432,7 +459,9 @@ class _Parser { precompiledPath: _ifParsed('precompiled'), reporter: reporter, fileReporters: _parseFileReporterOption(), - coverage: _ifParsed('coverage'), + coverage: coverageDir, + coverageLcov: coverageLcov, + branchCoverage: branchCoverage, concurrency: _parseOption('concurrency', int.parse), shardIndex: shardIndex, totalShards: totalShards, diff --git a/pkgs/test_core/lib/src/runner/coverage.dart b/pkgs/test_core/lib/src/runner/coverage.dart index fd6086f5b..68f48c984 100644 --- a/pkgs/test_core/lib/src/runner/coverage.dart +++ b/pkgs/test_core/lib/src/runner/coverage.dart @@ -5,25 +5,49 @@ import 'dart:convert'; import 'dart:io'; +import 'package:coverage/coverage.dart'; import 'package:path/path.dart' as p; +import '../util/package_config.dart'; import 'live_suite_controller.dart'; /// Collects coverage and outputs to the [coveragePath] path. -Future writeCoverage( - String coveragePath, +Future> writeCoverage( + String? coveragePath, LiveSuiteController controller, ) async { - var suite = controller.liveSuite.suite; - var coverage = await controller.liveSuite.suite.gatherCoverage(); - final outfile = File( - p.join( - coveragePath, - '${suite.path}.${suite.platform.runtime.name.toLowerCase()}.json', - ), - )..createSync(recursive: true); + final suite = controller.liveSuite.suite; + final coverage = await controller.liveSuite.suite.gatherCoverage(); + if (coveragePath != null) { + final outfile = File( + p.join( + coveragePath, + '${suite.path}.${suite.platform.runtime.name.toLowerCase()}.json', + ), + )..createSync(recursive: true); + final out = outfile.openWrite(); + out.write(json.encode(coverage)); + await out.flush(); + await out.close(); + } + return HitMap.parseJson(coverage['coverage'] as List>); +} + +Future writeCoverageLcov( + String coverageLcov, + Map allCoverageData, +) async { + final resolver = await Resolver.create( + packagePath: (await currentPackage).root.toFilePath(), + ); + final filteredCoverageData = allCoverageData.filterIgnored( + ignoredLinesInFilesCache: {}, + resolver: resolver, + ); + final lcovData = filteredCoverageData.formatLcov(resolver); + final outfile = File(coverageLcov)..createSync(recursive: true); final out = outfile.openWrite(); - out.write(json.encode(coverage)); + out.write(lcovData); await out.flush(); await out.close(); } diff --git a/pkgs/test_core/lib/src/runner/coverage_stub.dart b/pkgs/test_core/lib/src/runner/coverage_stub.dart index a9b82cbf5..2cedce919 100644 --- a/pkgs/test_core/lib/src/runner/coverage_stub.dart +++ b/pkgs/test_core/lib/src/runner/coverage_stub.dart @@ -2,12 +2,22 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'package:coverage/coverage.dart'; + import 'live_suite_controller.dart'; -Future writeCoverage( - String coveragePath, +Future> writeCoverage( + String? coveragePath, LiveSuiteController controller, ) => throw UnsupportedError( 'Coverage is only supported through the test runner.', ); + +Future writeCoverageLcov( + String coverageLcov, + Map allCoverageData, +) => + throw UnsupportedError( + 'Coverage is only supported through the test runner.', + ); diff --git a/pkgs/test_core/lib/src/runner/engine.dart b/pkgs/test_core/lib/src/runner/engine.dart index a506ab58c..5d96369f4 100644 --- a/pkgs/test_core/lib/src/runner/engine.dart +++ b/pkgs/test_core/lib/src/runner/engine.dart @@ -7,6 +7,7 @@ import 'dart:math'; import 'package:async/async.dart' hide Result; import 'package:collection/collection.dart'; +import 'package:coverage/coverage.dart'; import 'package:pool/pool.dart'; import 'package:test_api/src/backend/group.dart'; // ignore: implementation_imports import 'package:test_api/src/backend/invoker.dart'; // ignore: implementation_imports @@ -61,7 +62,13 @@ class Engine { bool? _closedBeforeDone; /// The coverage output directory. - String? _coverage; + final String? _coverage; + + /// The coverage output lcov file. + final String? _coverageLcov; + + /// The merged coverage data from all tests. + final Map _allCoverageData = {}; /// The seed used to generate randomness for test case shuffling. /// @@ -92,8 +99,7 @@ class Engine { /// This will be `null` if [close] was called before all the tests finished /// running. Future get success async { - await Future.wait([_group.future, _runPool.done], eagerError: true); - if (_closedBeforeDone!) return null; + if (!await _done) return null; return liveTests.every( (liveTest) => liveTest.state.result.isPassing && @@ -216,11 +222,13 @@ class Engine { Engine({ int? concurrency, String? coverage, + String? coverageLcov, this.testRandomizeOrderingSeed, bool stopOnFirstFailure = false, }) : _runPool = Pool(concurrency ?? 1), _stopOnFirstFailure = stopOnFirstFailure, - _coverage = coverage { + _coverage = coverage, + _coverageLcov = coverageLcov { _group.future .then((_) { _onTestStartedGroup.close(); @@ -243,11 +251,13 @@ class Engine { List suites, { int? concurrency, String? coverage, + String? coverageLcov, bool stopOnFirstFailure = false, }) { var engine = Engine( concurrency: concurrency, coverage: coverage, + coverageLcov: coverageLcov, stopOnFirstFailure: stopOnFirstFailure, ); for (var suite in suites) { @@ -293,17 +303,25 @@ class Engine { if (_closed) return; await _runGroup(controller, controller.liveSuite.suite.group, []); controller.noMoreLiveTests(); - if (_coverage != null) await writeCoverage(_coverage!, controller); + if (_coverage != null || _coverageLcov != null) { + _allCoverageData.merge( + await writeCoverage(_coverage, controller), + ); + } } finally { resource.allowRelease(() => controller?.close()); } }()); }) - ..onDone(() { + ..onDone(() async { _subscriptions.remove(subscription); _onSuiteAddedController.close(); _group.close(); _runPool.close(); + + if (_coverageLcov != null && await _done) { + await writeCoverageLcov(_coverageLcov, _allCoverageData); + } }); _subscriptions.add(subscription); @@ -595,4 +613,9 @@ class Engine { futures.add(_runPool.close()); await Future.wait(futures, eagerError: true); } + + Future get _done async { + await Future.wait([_group.future, _runPool.done], eagerError: true); + return !_closedBeforeDone!; + } } diff --git a/pkgs/test_core/lib/src/runner/vm/platform.dart b/pkgs/test_core/lib/src/runner/vm/platform.dart index e4de034ce..f44c694c8 100644 --- a/pkgs/test_core/lib/src/runner/vm/platform.dart +++ b/pkgs/test_core/lib/src/runner/vm/platform.dart @@ -162,7 +162,7 @@ class VMPlatform extends PlatformPlugin { environment, channel.cast(), message, - gatherCoverage: () => _gatherCoverage(environment!), + gatherCoverage: () => _gatherCoverage(environment!, _config), ); if (isolateRef != null) { @@ -414,7 +414,10 @@ stderr: ${processResult.stderr}'''); } } -Future> _gatherCoverage(Environment environment) async { +Future> _gatherCoverage( + Environment environment, + Configuration config, +) async { final isolateId = Uri.parse( environment.observatoryUrl!.fragment, @@ -424,8 +427,9 @@ Future> _gatherCoverage(Environment environment) async { false, false, false, - {}, + {(await currentPackage).name}, isolateIds: {isolateId!}, + branchCoverage: config.branchCoverage, ); } diff --git a/pkgs/test_core/lib/src/util/package_config.dart b/pkgs/test_core/lib/src/util/package_config.dart index c33dda628..53ad07cc0 100644 --- a/pkgs/test_core/lib/src/util/package_config.dart +++ b/pkgs/test_core/lib/src/util/package_config.dart @@ -37,3 +37,8 @@ Future absoluteUri(String path) async { return absoluteUri; } } + +/// Returns the current package. +final Future currentPackage = () async { + return (await currentPackageConfig).packageOf(await packageConfigUri)!; +}(); diff --git a/pkgs/test_core/pubspec.yaml b/pkgs/test_core/pubspec.yaml index 63b67cfcd..c1084c21b 100644 --- a/pkgs/test_core/pubspec.yaml +++ b/pkgs/test_core/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: async: ^2.5.0 boolean_selector: ^2.1.0 collection: ^1.15.0 - coverage: ^1.0.0 + coverage: ^1.15.0 frontend_server_client: '>=3.2.0 <5.0.0' glob: ^2.0.0 io: ^1.0.0