Skip to content

Commit

Permalink
Merge ab0757d into 3b73292
Browse files Browse the repository at this point in the history
  • Loading branch information
kevmoo committed Jun 29, 2022
2 parents 3b73292 + ab0757d commit 4673352
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 80 deletions.
41 changes: 19 additions & 22 deletions lib/src/hitmap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -348,28 +348,25 @@ List<T> _flattenMap<T>(Map map) {
}

/// Returns a JSON hit map backward-compatible with pre-1.16.0 SDKs.
Map<String, dynamic> hitmapToJson(HitMap hitmap, Uri scriptUri) {
final json = <String, dynamic>{};
json['source'] = '$scriptUri';
json['script'] = {
'type': '@Script',
'fixedId': true,
'id': 'libraries/1/scripts/${Uri.encodeComponent(scriptUri.toString())}',
'uri': '$scriptUri',
'_kind': 'library',
};
json['hits'] = _flattenMap<int>(hitmap.lineHits);
if (hitmap.funcHits != null) {
json['funcHits'] = _flattenMap<int>(hitmap.funcHits!);
}
if (hitmap.funcNames != null) {
json['funcNames'] = _flattenMap<dynamic>(hitmap.funcNames!);
}
if (hitmap.branchHits != null) {
json['branchHits'] = _flattenMap<int>(hitmap.branchHits!);
}
return json;
}
Map<String, dynamic> hitmapToJson(HitMap hitmap, Uri scriptUri) =>
<String, dynamic>{
'source': '$scriptUri',
'script': {
'type': '@Script',
'fixedId': true,
'id':
'libraries/1/scripts/${Uri.encodeComponent(scriptUri.toString())}',
'uri': '$scriptUri',
'_kind': 'library',
},
'hits': _flattenMap<int>(hitmap.lineHits),
if (hitmap.funcHits != null)
'funcHits': _flattenMap<int>(hitmap.funcHits!),
if (hitmap.funcNames != null)
'funcNames': _flattenMap<dynamic>(hitmap.funcNames!),
if (hitmap.branchHits != null)
'branchHits': _flattenMap<int>(hitmap.branchHits!),
};

/// Sorts the hits array based on the line numbers.
List _sortHits(List hits) {
Expand Down
30 changes: 17 additions & 13 deletions lib/src/run_and_collect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,35 @@ Future<Map<String, dynamic>> runAndCollect(String scriptPath,
final dartArgs = [
'--enable-vm-service',
'--pause_isolates_on_exit',
if (checked) '--checked',
scriptPath,
...?scriptArgs,
];

if (checked) {
dartArgs.add('--checked');
}

dartArgs.add(scriptPath);

if (scriptArgs != null) {
dartArgs.addAll(scriptArgs);
}

final process = await Process.start(Platform.executable, dartArgs);

final serviceUri = await serviceUriFromProcess(process.stdout.lines());
Map<String, dynamic> coverage;
try {
coverage = await collect(serviceUri, true, true, includeDart, <String>{},
timeout: timeout);
coverage = await collect(
serviceUri,
true,
true,
includeDart,
<String>{},
timeout: timeout,
);
} finally {
await process.stderr.drain();
}
final exitStatus = await process.exitCode;
if (exitStatus != 0) {
throw 'Process exited with exit code $exitStatus';
throw ProcessException(
Platform.executable,
dartArgs,
'Process failed.',
exitStatus,
);
}
return coverage;
}
66 changes: 31 additions & 35 deletions test/collect_coverage_api_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@ final _isolateLibFileUri = p.toUri(p.absolute(_isolateLibPath)).toString();

void main() {
test('collect_coverage_api', () async {
final json = await _collectCoverage();
expect(json.keys, unorderedEquals(<String>['type', 'coverage']));
expect(json, containsPair('type', 'CodeCoverage'));

final coverage = json['coverage'] as List;
final coverage = coverageDataFromJson(await _collectCoverage());
expect(coverage, isNotEmpty);

final sources = coverage.sources();
Expand All @@ -37,12 +33,9 @@ void main() {
});

test('collect_coverage_api with scoped output', () async {
final json =
await _collectCoverage(scopedOutput: <String>{}..add('coverage'));
expect(json.keys, unorderedEquals(<String>['type', 'coverage']));
expect(json, containsPair('type', 'CodeCoverage'));

final coverage = json['coverage'] as List;
final coverage = coverageDataFromJson(
await _collectCoverage(scopedOutput: <String>{}..add('coverage')),
);
expect(coverage, isNotEmpty);

final sources = coverage.sources();
Expand All @@ -54,41 +47,44 @@ void main() {
});

test('collect_coverage_api with isolateIds', () async {
final json = await _collectCoverage(isolateIds: true);
expect(json.keys, unorderedEquals(<String>['type', 'coverage']));
expect(json, containsPair('type', 'CodeCoverage'));

final coverage = json['coverage'] as List<Map<String, dynamic>>;
final coverage =
coverageDataFromJson(await _collectCoverage(isolateIds: true));
expect(coverage, isEmpty);
});

test('collect_coverage_api with function coverage', () async {
final json = await _collectCoverage(functionCoverage: true);
expect(json.keys, unorderedEquals(<String>['type', 'coverage']));
expect(json, containsPair('type', 'CodeCoverage'));

final coverage = json['coverage'] as List;
final coverage =
coverageDataFromJson(await _collectCoverage(functionCoverage: true));
expect(coverage, isNotEmpty);

final sources = coverage.sources();

for (var sampleCoverageData in sources[_sampleAppFileUri]!) {
expect(sampleCoverageData['funcNames'], isNotEmpty);
expect(sampleCoverageData['funcHits'], isNotEmpty);
}

for (var sampleCoverageData in sources[_isolateLibFileUri]!) {
expect(sampleCoverageData['funcNames'], isNotEmpty);
expect(sampleCoverageData['funcHits'], isNotEmpty);
}
final functionInfo = functionInfoFromSources(sources);

expect(
functionInfo[_sampleAppFileUri]!,
{
'main': 1,
'usedMethod': 1,
'unusedMethod': 0,
},
);

expect(
functionInfo[_isolateLibFileUri]!,
{
'BarClass.BarClass': 1,
'fooAsync': 1,
'fooSync': 1,
'isolateTask': 1,
'BarClass.baz': 1
},
);
});

test('collect_coverage_api with branch coverage', () async {
final json = await _collectCoverage(branchCoverage: true);
expect(json.keys, unorderedEquals(<String>['type', 'coverage']));
expect(json, containsPair('type', 'CodeCoverage'));

final coverage = json['coverage'] as List;
final coverage =
coverageDataFromJson(await _collectCoverage(branchCoverage: true));
expect(coverage, isNotEmpty);

final sources = coverage.sources();
Expand Down
7 changes: 2 additions & 5 deletions test/collect_coverage_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,9 @@ void main() {
final resultString = await _getCoverageResult();

// analyze the output json
final jsonResult = json.decode(resultString) as Map<String, dynamic>;

expect(jsonResult.keys, unorderedEquals(<String>['type', 'coverage']));
expect(jsonResult, containsPair('type', 'CodeCoverage'));
final coverage =
coverageDataFromJson(json.decode(resultString) as Map<String, dynamic>);

final coverage = jsonResult['coverage'] as List;
expect(coverage, isNotEmpty);

final sources = coverage.sources();
Expand Down
6 changes: 1 addition & 5 deletions test/run_and_collect_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ final _isolateLibFileUri = p.toUri(p.absolute(_isolateLibPath)).toString();
void main() {
test('runAndCollect', () async {
// use runAndCollect and verify that the results match w/ running manually
final json = await runAndCollect(testAppPath);
expect(json.keys, unorderedEquals(<String>['type', 'coverage']));
expect(json, containsPair('type', 'CodeCoverage'));

final coverage = json['coverage'] as List<Map<String, dynamic>>;
final coverage = coverageDataFromJson(await runAndCollect(testAppPath));
expect(coverage, isNotEmpty);

final sources = coverage.sources();
Expand Down
46 changes: 46 additions & 0 deletions test/test_util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'dart:async';
import 'dart:io';

import 'package:path/path.dart' as p;
import 'package:test/test.dart';
import 'package:test_process/test_process.dart';

final String testAppPath = p.join('test', 'test_files', 'test_app.dart');
Expand All @@ -23,6 +24,13 @@ Future<TestProcess> runTestApp(int openPort) => TestProcess.start(
],
);

List<Map<String, dynamic>> coverageDataFromJson(Map<String, dynamic> json) {
expect(json.keys, unorderedEquals(<String>['type', 'coverage']));
expect(json, containsPair('type', 'CodeCoverage'));

return (json['coverage'] as List).cast<Map<String, dynamic>>();
}

final _versionPattern = RegExp('([0-9]+)\\.([0-9]+)\\.([0-9]+)');
bool platformVersionCheck(int minMajor, int minMinor) {
final match = _versionPattern.matchAsPrefix(Platform.version);
Expand All @@ -33,6 +41,44 @@ bool platformVersionCheck(int minMajor, int minMinor) {
return major > minMajor || (major == minMajor && minor >= minMinor);
}

/// Returns a mapping of <URL: <function_name: hit_count>> from [sources].
Map<String, Map<String, int>> functionInfoFromSources(
Map<String, List<Map<dynamic, dynamic>>> sources,
) {
Map<int, String> getFuncNames(List list) {
return {
for (var i = 0; i < list.length; i += 2)
list[i] as int: list[i + 1] as String,
};
}

Map<int, int> getFuncHits(List list) {
return {
for (var i = 0; i < list.length; i += 2)
list[i] as int: list[i + 1] as int,
};
}

return {
for (var entry in sources.entries)
entry.key: entry.value.fold(
{},
(previousValue, element) {
expect(element['source'], entry.key);
final names = getFuncNames(element['funcNames'] as List);
final hits = getFuncHits(element['funcHits'] as List);

for (var pair in hits.entries) {
previousValue[names[pair.key]!] =
(previousValue[names[pair.key]!] ?? 0) + pair.value;
}

return previousValue;
},
),
};
}

extension ListTestExtension on List {
Map<String, List<Map<dynamic, dynamic>>> sources() => cast<Map>().fold(
<String, List<Map>>{},
Expand Down

0 comments on commit 4673352

Please sign in to comment.