Skip to content

Commit 3735ba4

Browse files
authored
fix: coverage on dart test (#1338)
* fix: coverage on dart test * adding missing test * simplyfying method
1 parent d97a006 commit 3735ba4

File tree

4 files changed

+96
-2
lines changed

4 files changed

+96
-2
lines changed

lib/src/cli/cli.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:async';
22
import 'dart:math';
33
import 'package:collection/collection.dart';
4+
import 'package:coverage/coverage.dart' as coverage;
45
import 'package:glob/glob.dart';
56
import 'package:lcov_parser/lcov_parser.dart';
67
import 'package:mason/mason.dart';

lib/src/cli/test_cli_runner.dart

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class TestCLIRunner {
142142
cwd: cwd,
143143
collectCoverage: collectCoverage,
144144
testRunner: testRunner,
145+
testType: testType,
145146
arguments: [
146147
...?arguments,
147148
if (randomSeed != null) ...[
@@ -158,6 +159,38 @@ class TestCLIRunner {
158159
await _cleanupOptimizerFile(cwd);
159160
}
160161

162+
// Dart don't directly generate lcov files, so we need
163+
// to read the json that is generates and convert it to lcov.
164+
if (testType == TestRunType.dart && collectCoverage) {
165+
final files = _dartCoverageFilesToProcess(
166+
p.join(cwd, 'coverage'),
167+
);
168+
169+
final packagesPath = p.join(
170+
'.dart_tool',
171+
'package_config.json',
172+
);
173+
final hitmap = await coverage.HitMap.parseFiles(
174+
files,
175+
packagePath: packagesPath,
176+
);
177+
178+
final resolver = await coverage.Resolver.create(
179+
packagesPath: packagesPath,
180+
packagePath: packagesPath,
181+
);
182+
183+
final output = hitmap.formatLcov(
184+
resolver,
185+
reportOn: ['lib'],
186+
basePath: cwd,
187+
);
188+
189+
// Write the lcov output to the file.
190+
await lcovFile.create(recursive: true);
191+
await lcovFile.writeAsString(output);
192+
}
193+
161194
if (collectCoverage) {
162195
assert(
163196
lcovFile.existsSync(),
@@ -214,12 +247,21 @@ class TestCLIRunner {
214247
'''Expected coverage >= ${minCoverage.toStringAsFixed(decimalPlaces)}% but actual is ${e.coverage.toStringAsFixed(decimalPlaces)}%.''',
215248
);
216249
}
250+
251+
static List<File> _dartCoverageFilesToProcess(String absPath) {
252+
return Directory(absPath)
253+
.listSync(recursive: true)
254+
.whereType<File>()
255+
.where((e) => e.path.endsWith('.json'))
256+
.toList();
257+
}
217258
}
218259

219260
Future<int> _testCommand({
220261
required void Function(String) stdout,
221262
required void Function(String) stderr,
222263
required VeryGoodTestRunner testRunner,
264+
required TestRunType testType,
223265
String cwd = '.',
224266
bool collectCoverage = false,
225267
List<String>? arguments,
@@ -273,7 +315,13 @@ Future<int> _testCommand({
273315
subscription =
274316
testRunner(
275317
workingDirectory: cwd,
276-
arguments: [if (collectCoverage) '--coverage', ...?arguments],
318+
arguments: [
319+
if (collectCoverage)
320+
testType == TestRunType.flutter
321+
? '--coverage'
322+
: '--coverage=coverage',
323+
...?arguments,
324+
],
277325
runInShell: true,
278326
).listen(
279327
(event) {

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ dependencies:
1414
args: ^2.6.0
1515
cli_completion: ^0.5.1
1616
collection: ^1.19.0
17+
coverage: ^1.15.0
1718
equatable: ^2.0.5
1819
glob: ^2.1.2
1920
lcov_parser: ^0.1.2

test/src/cli/test_runner_cli_test.dart

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ void main() {
684684
);
685685
});
686686

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

@@ -728,6 +728,50 @@ void main() {
728728
expect(testRunnerArgs, equals(['--coverage']));
729729
});
730730

731+
test('runs flutter tests w/coverage', () async {
732+
final tempDirectory = Directory.systemTemp.createTempSync();
733+
addTearDown(() => tempDirectory.deleteSync(recursive: true));
734+
735+
final lcovFile = File(
736+
p.join(tempDirectory.path, 'coverage', 'lcov.info'),
737+
);
738+
File(p.join(tempDirectory.path, 'pubspec.yaml')).createSync();
739+
Directory(p.join(tempDirectory.path, 'test')).createSync();
740+
lcovFile.createSync(recursive: true);
741+
742+
await expectLater(
743+
TestCLIRunner.test(
744+
testType: TestRunType.dart,
745+
cwd: tempDirectory.path,
746+
collectCoverage: true,
747+
stdout: stdoutLogs.add,
748+
stderr: stderrLogs.add,
749+
overrideTestRunner: testRunner(
750+
Stream.fromIterable(
751+
[
752+
const DoneTestEvent(success: true, time: 0),
753+
const ExitTestEvent(exitCode: 0, time: 0),
754+
],
755+
),
756+
onStart: () {
757+
expect(lcovFile.existsSync(), isFalse);
758+
lcovFile.createSync(recursive: true);
759+
},
760+
),
761+
logger: logger,
762+
),
763+
completion(equals([ExitCode.success.code])),
764+
);
765+
expect(
766+
stdoutLogs,
767+
equals([
768+
'Running "dart test" in . ...\n',
769+
contains('All tests passed!'),
770+
]),
771+
);
772+
expect(testRunnerArgs, equals(['--coverage=coverage']));
773+
});
774+
731775
test('runs tests w/coverage + min-coverage 100 (pass)', () async {
732776
final tempDirectory = Directory.systemTemp.createTempSync();
733777
addTearDown(() => tempDirectory.deleteSync(recursive: true));

0 commit comments

Comments
 (0)