Skip to content

Commit

Permalink
Merge 16cca2f into 62428b0
Browse files Browse the repository at this point in the history
  • Loading branch information
kevmoo committed Jun 30, 2022
2 parents 62428b0 + 16cca2f commit 6003bab
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 92 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 1.5.0-dev

* Support passing extra arguments to `test_with_coverage` which are then passed
to `package:test`.

Example: `dart run coverage:test_with_coverage -- --preset CI`


## 1.4.0 - 2022-6-16

* Added `HitMap.parseJsonSync` which takes a cache of ignored lines which can
Expand Down
121 changes: 70 additions & 51 deletions bin/test_with_coverage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ import 'package:path/path.dart' as path;
import 'collect_coverage.dart' as collect_coverage;
import 'format_coverage.dart' as format_coverage;

final allProcesses = <Process>[];
final _allProcesses = <Process>[];

Future<void> dartRun(List<String> args,
Future<void> _dartRun(List<String> args,
{void Function(String)? onStdout, String? workingDir}) async {
final process = await Process.start(
Platform.executable,
args,
workingDirectory: workingDir,
);
allProcesses.add(process);
_allProcesses.add(process);
final broadStdout = process.stdout.asBroadcastStream();
broadStdout.listen(stdout.add);
if (onStdout != null) {
Expand All @@ -36,55 +36,63 @@ Future<void> dartRun(List<String> args,
}
}

Future<String?> packageNameFromConfig(String packageDir) async {
Future<String?> _packageNameFromConfig(String packageDir) async {
final config = await findPackageConfig(Directory(packageDir));
return config?.packageOf(Uri.directory(packageDir))?.name;
}

void watchExitSignal(ProcessSignal signal) {
void _watchExitSignal(ProcessSignal signal) {
signal.watch().listen((sig) {
for (final process in allProcesses) {
for (final process in _allProcesses) {
process.kill(sig);
}
exit(1);
});
}

ArgParser createArgParser() {
final parser = ArgParser();
parser.addOption(
ArgParser _createArgParser() => ArgParser()
..addOption(
'package',
help: 'Root directory of the package to test.',
defaultsTo: '.',
);
parser.addOption(
)
..addOption(
'package-name',
help: 'Name of the package to test. '
'Deduced from --package if not provided.',
);
parser.addOption('port', help: 'VM service port.', defaultsTo: '8181');
parser.addOption('out',
abbr: 'o', help: 'Output directory. Defaults to <package-dir>/coverage.');
parser.addOption('test', help: 'Test script to run.', defaultsTo: 'test');
parser.addFlag(
)
..addOption('port', help: 'VM service port.', defaultsTo: '8181')
..addOption(
'out',
abbr: 'o',
help: 'Output directory. Defaults to <package-dir>/coverage.',
)
..addOption('test', help: 'Test script to run.', defaultsTo: 'test')
..addFlag(
'function-coverage',
abbr: 'f',
defaultsTo: false,
help: 'Collect function coverage info.',
);
parser.addFlag(
)
..addFlag(
'branch-coverage',
abbr: 'b',
defaultsTo: false,
help: 'Collect branch coverage info.',
);
parser.addFlag('help', abbr: 'h', negatable: false, help: 'Show this help.');
return parser;
}
)
..addFlag('help', abbr: 'h', negatable: false, help: 'Show this help.');

class Flags {
Flags(this.packageDir, this.packageName, this.outDir, this.port,
this.testScript, this.functionCoverage, this.branchCoverage);
Flags(
this.packageDir,
this.packageName,
this.outDir,
this.port,
this.testScript,
this.functionCoverage,
this.branchCoverage, {
required this.rest,
});

final String packageDir;
final String packageName;
Expand All @@ -93,18 +101,24 @@ class Flags {
final String testScript;
final bool functionCoverage;
final bool branchCoverage;
final List<String> rest;
}

Future<Flags> parseArgs(List<String> arguments) async {
final parser = createArgParser();
Future<Flags> _parseArgs(List<String> arguments) async {
final parser = _createArgParser();
final args = parser.parse(arguments);

void printUsage() {
print('Runs tests and collects coverage for a package. By default this '
"script assumes it's being run from the root directory of a package, and "
'outputs a coverage.json and lcov.info to ./coverage/');
print('Usage: dart test_with_coverage.dart [OPTIONS...]\n');
print(parser.usage);
print('''
Runs tests and collects coverage for a package.
By default this script assumes it's being run from the root directory of a
package, and outputs a coverage.json and lcov.info to ./coverage/
Usage: test_with_coverage [OPTIONS...] [-- <test script OPTIONS>]
${parser.usage}
''');
}

Never fail(String msg) {
Expand All @@ -124,7 +138,7 @@ Future<Flags> parseArgs(List<String> arguments) async {
}

final packageName = (args['package-name'] as String?) ??
await packageNameFromConfig(packageDir);
await _packageNameFromConfig(packageDir);
if (packageName == null) {
fail(
"Couldn't figure out package name from --package. Make sure this is a "
Expand All @@ -140,40 +154,45 @@ Future<Flags> parseArgs(List<String> arguments) async {
args['test'] as String,
args['function-coverage'] as bool,
args['branch-coverage'] as bool,
rest: args.rest,
);
}

Future<void> main(List<String> arguments) async {
final flags = await parseArgs(arguments);
final flags = await _parseArgs(arguments);
final outJson = path.join(flags.outDir, 'coverage.json');
final outLcov = path.join(flags.outDir, 'lcov.info');

if (!FileSystemEntity.isDirectorySync(flags.outDir)) {
await Directory(flags.outDir).create(recursive: true);
}

watchExitSignal(ProcessSignal.sighup);
watchExitSignal(ProcessSignal.sigint);
_watchExitSignal(ProcessSignal.sighup);
_watchExitSignal(ProcessSignal.sigint);
if (!Platform.isWindows) {
watchExitSignal(ProcessSignal.sigterm);
_watchExitSignal(ProcessSignal.sigterm);
}

final serviceUriCompleter = Completer<Uri>();
final testProcess = dartRun([
if (flags.branchCoverage) '--branch-coverage',
'run',
'--pause-isolates-on-exit',
'--disable-service-auth-codes',
'--enable-vm-service=${flags.port}',
flags.testScript,
], onStdout: (line) {
if (!serviceUriCompleter.isCompleted) {
final uri = extractVMServiceUri(line);
if (uri != null) {
serviceUriCompleter.complete(uri);
final testProcess = _dartRun(
[
if (flags.branchCoverage) '--branch-coverage',
'run',
'--pause-isolates-on-exit',
'--disable-service-auth-codes',
'--enable-vm-service=${flags.port}',
flags.testScript,
...flags.rest,
],
onStdout: (line) {
if (!serviceUriCompleter.isCompleted) {
final uri = extractVMServiceUri(line);
if (uri != null) {
serviceUriCompleter.complete(uri);
}
}
}
});
},
);
final serviceUri = await serviceUriCompleter.future;

await collect_coverage.main([
Expand Down
12 changes: 6 additions & 6 deletions lib/src/collect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import 'dart:io';

import 'package:vm_service/vm_service.dart';

import 'util.dart';
import 'hitmap.dart';
import 'util.dart';

const _retryInterval = Duration(milliseconds: 200);
const _debugTokenPositions = bool.fromEnvironment('DEBUG_COVERAGE');
Expand Down Expand Up @@ -374,9 +374,9 @@ Future<List<Map<String, dynamic>>> _getCoverageJson(
}

forEachLine(coverage.hits!, (line) {
_incrementCountForKey(hits.lineHits, line);
hits.lineHits.increment(line);
if (hits.funcNames != null && hits.funcNames!.containsKey(line)) {
_incrementCountForKey(hits.funcHits!, line);
hits.funcHits!.increment(line);
}
});
forEachLine(coverage.misses!, (line) {
Expand All @@ -390,7 +390,7 @@ Future<List<Map<String, dynamic>>> _getCoverageJson(
if (branchCoverage != null) {
hits.branchHits ??= <int, int>{};
forEachLine(branchCoverage.hits!, (line) {
_incrementCountForKey(hits.branchHits!, line);
hits.branchHits!.increment(line);
});
forEachLine(branchCoverage.misses!, (line) {
hits.branchHits!.putIfAbsent(line, () => 0);
Expand All @@ -406,8 +406,8 @@ Future<List<Map<String, dynamic>>> _getCoverageJson(
return coverage;
}

void _incrementCountForKey(Map<int, int> counter, int key) {
counter[key] = counter.containsKey(key) ? counter[key]! + 1 : 1;
extension _MapExtension<T> on Map<T, int> {
void increment(T key) => this[key] = (this[key] ?? 0) + 1;
}

Future<String> _getFuncName(
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: coverage
version: 1.4.0
version: 1.5.0-dev
description: Coverage data manipulation and formatting
repository: https://github.com/dart-lang/coverage

Expand Down
15 changes: 15 additions & 0 deletions test/test_with_coverage_package/lib/validate_lib.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
int sum(Iterable<int> values) {
var val = 0;
for (var value in values) {
val += value;
}
return val;
}

int product(Iterable<int> values) {
var val = 1;
for (var value in values) {
val *= value;
}
return val;
}
5 changes: 4 additions & 1 deletion test/test_with_coverage_package/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ publish_to: none
environment:
sdk: '>=2.15.0 <3.0.0'

dependencies:
dev_dependencies:
test: ^1.16.0

dependency_overrides:
coverage:
path: ../../
14 changes: 14 additions & 0 deletions test/test_with_coverage_package/test/product_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// 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:test/test.dart';

// ignore: avoid_relative_lib_imports
import '../lib/validate_lib.dart';

void main() {
test('product', () {
expect(product([2, 3]), 6);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,13 @@
// 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.

void main() {}
import 'package:test/test.dart';

// ignore: avoid_relative_lib_imports
import '../lib/validate_lib.dart';

void main() {
test('sum', () {
expect(sum([1, 2]), 3);
});
}
Loading

0 comments on commit 6003bab

Please sign in to comment.