Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/src/cli/cli.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:math';
import 'package:collection/collection.dart';
import 'package:coverage/coverage.dart' as coverage;
import 'package:glob/glob.dart';
import 'package:lcov_parser/lcov_parser.dart';
import 'package:mason/mason.dart';
Expand Down
50 changes: 49 additions & 1 deletion lib/src/cli/test_cli_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class TestCLIRunner {
cwd: cwd,
collectCoverage: collectCoverage,
testRunner: testRunner,
testType: testType,
arguments: [
...?arguments,
if (randomSeed != null) ...[
Expand All @@ -158,6 +159,38 @@ class TestCLIRunner {
await _cleanupOptimizerFile(cwd);
}

// Dart don't directly generate lcov files, so we need
// to read the json that is generates and convert it to lcov.
if (testType == TestRunType.dart && collectCoverage) {
final files = _dartCoverageFilesToProcess(
p.join(cwd, 'coverage'),
);

final packagesPath = p.join(
'.dart_tool',
'package_config.json',
);
final hitmap = await coverage.HitMap.parseFiles(
files,
packagePath: packagesPath,
);

final resolver = await coverage.Resolver.create(
packagesPath: packagesPath,
packagePath: packagesPath,
);

final output = hitmap.formatLcov(
resolver,
reportOn: ['lib'],
basePath: cwd,
);

// Write the lcov output to the file.
await lcovFile.create(recursive: true);
await lcovFile.writeAsString(output);
}

if (collectCoverage) {
assert(
lcovFile.existsSync(),
Expand Down Expand Up @@ -214,12 +247,21 @@ class TestCLIRunner {
'''Expected coverage >= ${minCoverage.toStringAsFixed(decimalPlaces)}% but actual is ${e.coverage.toStringAsFixed(decimalPlaces)}%.''',
);
}

static List<File> _dartCoverageFilesToProcess(String absPath) {
return Directory(absPath)
.listSync(recursive: true)
.whereType<File>()
.where((e) => e.path.endsWith('.json'))
.toList();
}
}

Future<int> _testCommand({
required void Function(String) stdout,
required void Function(String) stderr,
required VeryGoodTestRunner testRunner,
required TestRunType testType,
String cwd = '.',
bool collectCoverage = false,
List<String>? arguments,
Expand Down Expand Up @@ -273,7 +315,13 @@ Future<int> _testCommand({
subscription =
testRunner(
workingDirectory: cwd,
arguments: [if (collectCoverage) '--coverage', ...?arguments],
arguments: [
if (collectCoverage)
testType == TestRunType.flutter
? '--coverage'
: '--coverage=coverage',
...?arguments,
],
runInShell: true,
).listen(
(event) {
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies:
args: ^2.6.0
cli_completion: ^0.5.1
collection: ^1.19.0
coverage: ^1.15.0
equatable: ^2.0.5
glob: ^2.1.2
lcov_parser: ^0.1.2
Expand Down
46 changes: 45 additions & 1 deletion test/src/cli/test_runner_cli_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ void main() {
);
});

test('runs tests w/coverage', () async {
test('runs flutter tests w/coverage', () async {
final tempDirectory = Directory.systemTemp.createTempSync();
addTearDown(() => tempDirectory.deleteSync(recursive: true));

Expand Down Expand Up @@ -728,6 +728,50 @@ void main() {
expect(testRunnerArgs, equals(['--coverage']));
});

test('runs flutter tests w/coverage', () async {
final tempDirectory = Directory.systemTemp.createTempSync();
addTearDown(() => tempDirectory.deleteSync(recursive: true));

final lcovFile = File(
p.join(tempDirectory.path, 'coverage', 'lcov.info'),
);
File(p.join(tempDirectory.path, 'pubspec.yaml')).createSync();
Directory(p.join(tempDirectory.path, 'test')).createSync();
lcovFile.createSync(recursive: true);

await expectLater(
TestCLIRunner.test(
testType: TestRunType.dart,
cwd: tempDirectory.path,
collectCoverage: true,
stdout: stdoutLogs.add,
stderr: stderrLogs.add,
overrideTestRunner: testRunner(
Stream.fromIterable(
[
const DoneTestEvent(success: true, time: 0),
const ExitTestEvent(exitCode: 0, time: 0),
],
),
onStart: () {
expect(lcovFile.existsSync(), isFalse);
lcovFile.createSync(recursive: true);
},
),
logger: logger,
),
completion(equals([ExitCode.success.code])),
);
expect(
stdoutLogs,
equals([
'Running "dart test" in . ...\n',
contains('All tests passed!'),
]),
);
expect(testRunnerArgs, equals(['--coverage=coverage']));
});

test('runs tests w/coverage + min-coverage 100 (pass)', () async {
final tempDirectory = Directory.systemTemp.createTempSync();
addTearDown(() => tempDirectory.deleteSync(recursive: true));
Expand Down