Added a tool to find uncovered files (#529)
- Thanks for your contribution! Please replace this text with a description of what this PR is changing or adding and why, list any relevant issues, and review the contribution guidelines below.
- [x] I’ve reviewed the contributor guide and applied the relevant portions to this PR.
Contribution guidelines:
- See our contributor guide for general expectations for PRs.
- Larger or significant changes should be discussed in an issue before creating a PR.
- Contributions to our repos should follow the Dart style guide and use
dart format. - Most changes should add an entry to the changelog and may need to rev the pubspec package version.
- Changes to packages require corresponding tests.
Note that many Dart repos have a weekly cadence for reviewing PRs - please allow for some latency before initial review feedback.
Overview
This PR adds support for a new --include-uncovered flag in format_coverage.dart, allowing uncovered Dart files (i.e., those with no test coverage) to be included in the LCOV output. Solving the issue (#529)
This is what I did:
- CLI: Modified
format_coverage.dartto parse--include-uncoveredflag. - Core: Modified
formatter.dartto pass the logic and format the LCOV to include files that are not covered by coverage.
Key changes in formatter.dart:
- Added two new imports:
import 'dart:io';import 'package:yaml/yaml.dart';required to scan all files in the directory and compare it with the covered files. - Added new parameter to
formatLcovandprettyprint:bool Function(String path)? includeUncovered, - Created three new functions:
_findAllDartFiles: to scan all files in the directory.getPackageName: to get package.toPackageUri: to convert the file paths into package uri for checking if the file is included or not. - Added the logic to scan the files , check whether they are covered if no then format the lcov, and wraped this logic within an if statement:
if (includeUncovered != null) {
// Step 1: Identify all Dart files
final allFiles = _findAllDartFiles(reportOn: reportOn);
print('detected files: $allFiles');
// Step 2: Identify covered files
final coveredFiles = Map.fromEntries(entries
.where((entry) => entry.value.lineHits.values.any((hit) => hit > 0)));
// check if the file is covered or no.
final packageName = getPackageName();
final uncoveredFiles = <String>[];
for (final file in allFiles) {
final pkgUri = toPackageUri(file, packageName);
if (!coveredFiles.containsKey(pkgUri)) {
uncoveredFiles.add(file);
}
}
print('Uncovered Dart files:');
for (final file in uncoveredFiles) {
print(file);
}
//formatlcov for including uncovered.
final uncoveredBuf = StringBuffer();
for (final file in uncoveredFiles) {
if (!pathFilter(file)) continue;
final lines = File(file).readAsLinesSync();
var displayPath = file;
if (basePath != null) {
displayPath = p.relative(file, from: basePath);
}
displayPath = displayPath.replaceAll('\\', '/'); // For Windows compatibility
uncoveredBuf.writeln('SF:$displayPath');
var lineNumber = 1;
var realLines = 0;
for (final line in lines) {
final trimmed = line.trim();
if (trimmed.isNotEmpty && !trimmed.startsWith('//')) {
uncoveredBuf.writeln('DA:$lineNumber,0');
realLines++;
}
lineNumber++;
}
uncoveredBuf.writeln('LF:$realLines');
uncoveredBuf.writeln('LH:0');
uncoveredBuf.writeln('end_of_record');
}
buf.write(uncoveredBuf.toString());
}
Testing:
CLI cmd: dart run coverage:format_coverage --lcov --in=coverage --out=[lcov.info](http://lcov.info/) --report-on=lib --include-uncovered
example:
project-root/
├── lib/
│ ├── main.dart
│ └── utils.dart
└── test/
└── main_test.dart
Before implementation:
SF:C:\flutter_dev\projects\geminitest\lib\main.dart
DA:6,1
DA:8,2
DA:10,3
DA:12,1
DA:13,1
DA:14,0
DA:16,2
DA:17,4
DA:20,1
DA:21,1
DA:22,0
DA:24,2
DA:25,0
DA:27,2
DA:28,4
DA:31,1
DA:32,1
DA:33,0
DA:35,2
DA:38,1
DA:39,1
DA:40,5
DA:44,1
DA:45,3
DA:46,4
DA:47,1
DA:48,2
DA:49,2
LF:28
LH:24
end_of_record
as utils.dart didn't had any coresponding tests, it was not included in the LCOV.
After implementation:
SF:C:\flutter_dev\projects\geminitest\lib\main.dart
DA:6,1
DA:8,2
DA:10,3
DA:12,1
DA:13,1
DA:14,0
DA:16,2
DA:17,4
DA:20,1
DA:21,1
DA:22,0
DA:24,2
DA:25,0
DA:27,2
DA:28,4
DA:31,1
DA:32,1
DA:33,0
DA:35,2
DA:38,1
DA:39,1
DA:40,5
DA:44,1
DA:45,3
DA:46,4
DA:47,1
DA:48,2
DA:49,2
LF:28
LH:24
end_of_record
SF:lib/utils.dart
DA:5,0
DA:8,0
DA:10,0
DA:13,0
DA:16,0
DA:18,0
DA:21,0
DA:24,0
DA:26,0
DA:27,0
DA:28,0
DA:30,0
DA:31,0
DA:32,0
DA:35,0
DA:36,0
DA:37,0
DA:38,0
DA:39,0
DA:40,0
DA:41,0
DA:43,0
DA:44,0
DA:45,0
DA:46,0
DA:48,0
DA:50,0
DA:51,0
DA:53,0
DA:54,0
DA:55,0
DA:56,0
DA:57,0
DA:59,0
DA:60,0
DA:61,0
DA:62,0
DA:64,0
DA:68,0
DA:69,0
DA:74,0
DA:75,0
DA:76,0
DA:77,0
DA:81,0
DA:82,0
DA:83,0
DA:84,0
DA:85,0
LF:49
LH:0
end_of_record
utils.dart was included in the LCOV with 0 lines hit.
Conclusion:
--include-uncovered is successfully working as expected.
Feedback:
Please let me know if any changes or refinements are needed. Thank you!
This needs a test. Also, there's a merge conflict in format_coverage.dart that will need to be resolved before the github CI can be run
Ohh yes.. I will resolve it..
Closing for now due to inactivity - feel free to reopen and revive! :)