blob: a32f3fdcc42f47a955fac70922064e2f4ec4d335 [file] [log] [blame]
// Copyright (c) 2015, 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 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:coverage/coverage.dart';
import 'package:coverage/src/util.dart';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
import 'test_util.dart';
final _sampleAppPath = p.join('test', 'test_files', 'test_app.dart');
final _isolateLibPath = p.join('test', 'test_files', 'test_app_isolate.dart');
final _sampleAppFileUri = p.toUri(p.absolute(_sampleAppPath)).toString();
final _isolateLibFileUri = p.toUri(p.absolute(_isolateLibPath)).toString();
void main() {
test('validate hitMap', () async {
final hitmap = await _getHitMap();
expect(hitmap, contains(_sampleAppFileUri));
expect(hitmap, contains(_isolateLibFileUri));
expect(hitmap, contains('package:coverage/src/util.dart'));
final sampleAppHitMap = hitmap[_sampleAppFileUri];
final sampleAppHitLines = sampleAppHitMap?.lineHits;
final sampleAppHitFuncs = sampleAppHitMap?.funcHits;
final sampleAppFuncNames = sampleAppHitMap?.funcNames;
final sampleAppBranchHits = sampleAppHitMap?.branchHits;
expect(sampleAppHitLines, containsPair(46, greaterThanOrEqualTo(1)),
reason: 'be careful if you modify the test file');
expect(sampleAppHitLines, containsPair(50, 0),
reason: 'be careful if you modify the test file');
expect(sampleAppHitLines, isNot(contains(32)),
reason: 'be careful if you modify the test file');
expect(sampleAppHitFuncs, containsPair(45, 1),
reason: 'be careful if you modify the test file');
expect(sampleAppHitFuncs, containsPair(49, 0),
reason: 'be careful if you modify the test file');
expect(sampleAppFuncNames, containsPair(45, 'usedMethod'),
reason: 'be careful if you modify the test file');
expect(sampleAppBranchHits, containsPair(41, 1),
reason: 'be careful if you modify the test file');
}, skip: !platformVersionCheck(2, 17));
test('validate hitMap, old VM without branch coverage', () async {
final hitmap = await _getHitMap();
expect(hitmap, contains(_sampleAppFileUri));
expect(hitmap, contains(_isolateLibFileUri));
expect(hitmap, contains('package:coverage/src/util.dart'));
final sampleAppHitMap = hitmap[_sampleAppFileUri];
final sampleAppHitLines = sampleAppHitMap?.lineHits;
final sampleAppHitFuncs = sampleAppHitMap?.funcHits;
final sampleAppFuncNames = sampleAppHitMap?.funcNames;
expect(sampleAppHitLines, containsPair(46, greaterThanOrEqualTo(1)),
reason: 'be careful if you modify the test file');
expect(sampleAppHitLines, containsPair(50, 0),
reason: 'be careful if you modify the test file');
expect(sampleAppHitLines, isNot(contains(32)),
reason: 'be careful if you modify the test file');
expect(sampleAppHitFuncs, containsPair(45, 1),
reason: 'be careful if you modify the test file');
expect(sampleAppHitFuncs, containsPair(49, 0),
reason: 'be careful if you modify the test file');
expect(sampleAppFuncNames, containsPair(45, 'usedMethod'),
reason: 'be careful if you modify the test file');
}, skip: platformVersionCheck(2, 17));
group('LcovFormatter', () {
test('format()', () async {
final hitmap = await _getHitMap();
final resolver = await Resolver.create(packagePath: '.');
// ignore: deprecated_member_use_from_same_package
final formatter = LcovFormatter(resolver);
final res = await formatter
.format(hitmap.map((key, value) => MapEntry(key, value.lineHits)));
expect(res, contains(p.absolute(_sampleAppPath)));
expect(res, contains(p.absolute(_isolateLibPath)));
expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
});
test('formatLcov()', () async {
final hitmap = await _getHitMap();
final resolver = await Resolver.create(packagePath: '.');
final res = hitmap.formatLcov(resolver);
expect(res, contains(p.absolute(_sampleAppPath)));
expect(res, contains(p.absolute(_isolateLibPath)));
expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
});
test('formatLcov() includes files in reportOn list', () async {
final hitmap = await _getHitMap();
final resolver = await Resolver.create(packagePath: '.');
final res = hitmap.formatLcov(resolver, reportOn: ['lib/', 'test/']);
expect(res, contains(p.absolute(_sampleAppPath)));
expect(res, contains(p.absolute(_isolateLibPath)));
expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
});
test('formatLcov() excludes files not in reportOn list', () async {
final hitmap = await _getHitMap();
final resolver = await Resolver.create(packagePath: '.');
final res = hitmap.formatLcov(resolver, reportOn: ['lib/']);
expect(res, isNot(contains(p.absolute(_sampleAppPath))));
expect(res, isNot(contains(p.absolute(_isolateLibPath))));
expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
});
test('formatLcov() uses paths relative to basePath', () async {
final hitmap = await _getHitMap();
final resolver = await Resolver.create(packagePath: '.');
final res = hitmap.formatLcov(resolver, basePath: p.absolute('lib'));
expect(
res, isNot(contains(p.absolute(p.join('lib', 'src', 'util.dart')))));
expect(res, contains(p.join('src', 'util.dart')));
});
});
group('PrettyPrintFormatter', () {
test('format()', () async {
final hitmap = await _getHitMap();
final resolver = await Resolver.create(packagePath: '.');
// ignore: deprecated_member_use_from_same_package
final formatter = PrettyPrintFormatter(resolver, Loader());
final res = await formatter
.format(hitmap.map((key, value) => MapEntry(key, value.lineHits)));
expect(res, contains(p.absolute(_sampleAppPath)));
expect(res, contains(p.absolute(_isolateLibPath)));
expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
// be very careful if you change the test file
expect(res, contains(' 0| return a - b;'));
expect(res, contains('| return _withTimeout(() async {'),
reason: 'be careful if you change lib/src/util.dart');
final hitLineRegexp = RegExp(r'\s+(\d+)\| return a \+ b;');
final match = hitLineRegexp.allMatches(res).single;
final hitCount = int.parse(match[1]!);
expect(hitCount, greaterThanOrEqualTo(1));
});
test('prettyPrint()', () async {
final hitmap = await _getHitMap();
final resolver = await Resolver.create(packagePath: '.');
final res = await hitmap.prettyPrint(resolver, Loader());
expect(res, contains(p.absolute(_sampleAppPath)));
expect(res, contains(p.absolute(_isolateLibPath)));
expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
// be very careful if you change the test file
expect(res, contains(' 0| return a - b;'));
expect(res, contains('| return _withTimeout(() async {'),
reason: 'be careful if you change lib/src/util.dart');
final hitLineRegexp = RegExp(r'\s+(\d+)\| return a \+ b;');
final match = hitLineRegexp.allMatches(res).single;
final hitCount = int.parse(match[1]!);
expect(hitCount, greaterThanOrEqualTo(1));
});
test('prettyPrint() includes files in reportOn list', () async {
final hitmap = await _getHitMap();
final resolver = await Resolver.create(packagePath: '.');
final res = await hitmap
.prettyPrint(resolver, Loader(), reportOn: ['lib/', 'test/']);
expect(res, contains(p.absolute(_sampleAppPath)));
expect(res, contains(p.absolute(_isolateLibPath)));
expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
});
test('prettyPrint() excludes files not in reportOn list', () async {
final hitmap = await _getHitMap();
final resolver = await Resolver.create(packagePath: '.');
final res =
await hitmap.prettyPrint(resolver, Loader(), reportOn: ['lib/']);
expect(res, isNot(contains(p.absolute(_sampleAppPath))));
expect(res, isNot(contains(p.absolute(_isolateLibPath))));
expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
});
test('prettyPrint() functions', () async {
final hitmap = await _getHitMap();
final resolver = await Resolver.create(packagePath: '.');
final res =
await hitmap.prettyPrint(resolver, Loader(), reportFuncs: true);
expect(res, contains(p.absolute(_sampleAppPath)));
expect(res, contains(p.absolute(_isolateLibPath)));
expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
// be very careful if you change the test file
expect(res, contains(' 1|Future<void> main() async {'));
expect(res, contains(' 1|int usedMethod(int a, int b) {'));
expect(res, contains(' 0|int unusedMethod(int a, int b) {'));
expect(res, contains(' | return a + b;'));
});
test('prettyPrint() branches', () async {
final hitmap = await _getHitMap();
final resolver = await Resolver.create(packagePath: '.');
final res =
await hitmap.prettyPrint(resolver, Loader(), reportBranches: true);
expect(res, contains(p.absolute(_sampleAppPath)));
expect(res, contains(p.absolute(_isolateLibPath)));
expect(res, contains(p.absolute(p.join('lib', 'src', 'util.dart'))));
// be very careful if you change the test file
expect(res, contains(' 1| if (x == answer) {'));
expect(res, contains(' 0| while (i < lines.length) {'));
expect(res, contains(' | bar.baz();'));
}, skip: !platformVersionCheck(2, 17));
});
}
Future<Map<String, HitMap>> _getHitMap() async {
expect(FileSystemEntity.isFileSync(_sampleAppPath), isTrue);
// select service port.
final port = await getOpenPort();
// start sample app.
final sampleAppArgs = [
'--pause-isolates-on-exit',
'--enable-vm-service=$port',
// Dart VM versions before 2.17 don't support branch coverage.
if (platformVersionCheck(2, 17)) '--branch-coverage',
_sampleAppPath
];
final sampleProcess =
await Process.start(Platform.resolvedExecutable, sampleAppArgs);
// Capture the VM service URI.
final serviceUriCompleter = Completer<Uri>();
sampleProcess.stdout
.transform(utf8.decoder)
.transform(LineSplitter())
.listen((line) {
if (!serviceUriCompleter.isCompleted) {
final serviceUri = extractVMServiceUri(line);
if (serviceUri != null) {
serviceUriCompleter.complete(serviceUri);
}
}
});
final serviceUri = await serviceUriCompleter.future;
// collect hit map.
final coverageJson = (await collect(serviceUri, true, true, false, <String>{},
functionCoverage: true,
branchCoverage: true))['coverage'] as List<Map<String, dynamic>>;
final hitMap = HitMap.parseJson(coverageJson);
// wait for sample app to terminate.
final exitCode = await sampleProcess.exitCode;
if (exitCode != 0) {
throw ProcessException(Platform.resolvedExecutable, sampleAppArgs,
'Fatal error. Exit code: $exitCode', exitCode);
}
await sampleProcess.stderr.drain();
return hitMap;
}