flutter/packages/flutter_tools/lib/src/test/coverage_collector.dart
2017-02-15 18:50:19 -08:00

81 lines
3.2 KiB
Dart

// Copyright 2016 The Chromium Authors. 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 'package:coverage/coverage.dart' as coverage;
import '../base/file_system.dart';
import '../base/io.dart';
import '../dart/package_map.dart';
import '../globals.dart';
/// A class that's used to collect coverage data during tests.
class CoverageCollector {
Map<String, dynamic> _globalHitmap;
void _addHitmap(Map<String, dynamic> hitmap) {
if (_globalHitmap == null)
_globalHitmap = hitmap;
else
coverage.mergeHitmaps(hitmap, _globalHitmap);
}
/// Collects coverage for the given [Process] using the given `port`.
///
/// This should be called when the code whose coverage data is being collected
/// has been run to completion so that all coverage data has been recorded.
///
/// The returned [Future] completes when the coverage is collected.
Future<Null> collectCoverage(Process process, InternetAddress host, int port) async {
assert(process != null);
assert(port != null);
int pid = process.pid;
int exitCode;
process.exitCode.then<Null>((int code) {
exitCode = code;
});
if (exitCode != null)
throw new Exception('Failed to collect coverage, process terminated before coverage could be collected.');
printTrace('pid $pid (port $port): collecting coverage data...');
final Map<String, dynamic> data = await coverage.collect(host.address, port, false, false).timeout(
const Duration(seconds: 30),
onTimeout: () { throw new Exception('Failed to collect coverage, it took more than thirty seconds.'); },
);
printTrace('pid $pid (port $port): ${ exitCode != null ? "process terminated prematurely with exit code $exitCode; aborting" : "collected coverage data; merging..." }');
if (exitCode != null)
throw new Exception('Failed to collect coverage, process terminated while coverage was being collected.');
_addHitmap(coverage.createHitmap(data['coverage']));
printTrace('pid $pid (port $port): done merging coverage data into global coverage map.');
}
/// Returns a future that will complete with the formatted coverage data
/// (using [formatter]) once all coverage data has been collected.
///
/// This will not start any collection tasks. It us up to the caller of to
/// call [collectCoverage] for each process first.
///
/// If [timeout] is specified, the future will timeout (with a
/// [TimeoutException]) after the specified duration.
Future<String> finalizeCoverage({
coverage.Formatter formatter,
Duration timeout,
}) async {
printTrace('formating coverage data');
if (_globalHitmap == null)
return null;
if (formatter == null) {
coverage.Resolver resolver = new coverage.Resolver(packagesPath: PackageMap.globalPackagesPath);
String packagePath = fs.currentDirectory.path;
List<String> reportOn = <String>[fs.path.join(packagePath, 'lib')];
formatter = new coverage.LcovFormatter(resolver, reportOn: reportOn, basePath: packagePath);
}
String result = await formatter.format(_globalHitmap);
_globalHitmap = null;
return result;
}
}