dart-sdk/tests/standalone/full_coverage_test.dart
fschneider@google.com 76f5627abd Compile implicit closures as dispatchers instead of duplicating the original method's code.
This saves space in unoptimized code for implicit closures. In optimized code the
original method's code will often be inlined into the implicit closure dispatcher so that
there won't be a performance impact.

The static case just calls the original method. For implicit instance closures, the
this-parameter is loaded from the context and passed to the original method.


The coverage test is affected since the dispatcher has the original method's token position
associated with it. This means that the line with the method declaration is considered to
have executable code. Setting the token position to 0 (Scanner::kNoSourcePos) does not work
because it coincides with the first line (and first token) in the script.

R=hausner@google.com

Review URL: https://codereview.chromium.org//1024563004

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@44655 260f80e4-7a28-3924-810f-c04153c831b5
2015-03-24 09:33:36 +00:00

233 lines
6 KiB
Dart

// Copyright (c) 2014, 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.
// These tests fork a second VM process that runs the script
// ``tools/full-coverage.dart'' and verifies that the tool
// produces the expeced output.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:unittest/unittest.dart';
final String coverageScript =
Platform.script.resolve('../../tools/full-coverage.dart').toFilePath();
final String packageRoot = Platform.packageRoot;
final List dartBaseArgs = ['--package-root=${packageRoot}', '--checked',];
// With line numbers starting at 0, the list of hits can be understood as
// follows:
// * -1: No coverage data on this line.
// * 0: No hits on this line.
// * 1: ``Some'' hits on this line.
final coverageTests = [
{
'name': 'faculty',
'program': '''
dummy () {
for (int i = 0; i < 100; i++) {
print(i);
}
}
int fac(int n) {
int f = 1;
for (int i = 1; i <= n; i++) {
f *= i;
}
return f;
}
main() {
if (false) {
dummy(11);
} else {
fac(10);
}
}
''',
'expectedHits': [-1, 0, 0, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1,
0, -1, 1, -1, -1]
},{
'name': 'closures',
'program': '''
main() {
foo(bar) {
bar();
}
foo(() {
print("in closure");
});
}
''',
'expectedHits': [1, -1, 1, -1, -1, 1, 1, -1, -1]
}
];
String prepareEnv() {
Directory testDir = Directory.systemTemp.createTempSync("coverage-");
for (var coverageProg in coverageTests) {
var coverageProgDir = new Directory(
path.join(testDir.path, coverageProg["name"]))
..createSync();
var f = new File(path.join(coverageProgDir.path,
"${coverageProg['name']}.dart"));
f.writeAsStringSync(coverageProg["program"], mode: FileMode.WRITE);
}
return testDir.path;
}
destroyEnv(base) => new Directory(base).deleteSync(recursive: true);
generateCoverage(String workingDirectory) {
for (var coverageProg in coverageTests) {
var progPath = path.join(workingDirectory, coverageProg['name']);
var script = path.join(progPath, "${coverageProg['name']}.dart");
var dartArgs = new List.from(dartBaseArgs)
..addAll(['--coverage-dir=${progPath}', '${script}']);
var result = Process.runSync(Platform.executable, dartArgs);
expect(result.exitCode, 0);
}
}
Future<Process> convertCoverage(String programDir, String format) {
var dartArgs = new List.from(dartBaseArgs)
..addAll([
coverageScript,
'--package-root=${packageRoot}',
'--in=${programDir}',
format
]);
return Process.start(Platform.executable, dartArgs);
}
class PrettyPrintDescriptor {
var _programPath;
var _validFormat = new RegExp(r"^\s*\d*\|.*$", multiLine: true);
var _pattern = new RegExp(r"^\s*(\d+)\|", multiLine: true);
PrettyPrintDescriptor(this._programPath);
get sectionStart => _programPath;
get sectionEnd => '/';
get coverageParameter => '--pretty-print';
hitData(line) {
expect(_validFormat.hasMatch(line), isTrue);
var match = _pattern.firstMatch(line);
var result = -1;
if (match != null) {
result = (int.parse(match.group(1)) != 0) ? 1 : 0;
}
return [result];
}
}
class LcovDescriptor {
var _pattern = new RegExp(r"^DA:(\d+),(\d+)$", multiLine: true);
var _programPath;
var _line_nr = 0;
LcovDescriptor(this._programPath);
get sectionStart => 'SF:${_programPath}';
get sectionEnd => 'end_of_record';
get coverageParameter => '--lcov';
hitData(line) {
expect(_pattern.hasMatch(line), isTrue);
var match = _pattern.firstMatch(line);
// Lcov data starts at line 1, we start at 0.
var out_line = int.parse(match[1]) - 1;
var hitCount = int.parse(match[2]);
var result = [];
for ( ; _line_nr < out_line; _line_nr++) {
result.add(-1);
}
result.add((hitCount != 0) ? 1 : 0);
_line_nr++;
return result;
}
}
Stream filterHitData(input, descriptor) {
bool in_program_section = false;
return input.where((line) {
if (in_program_section) {
if (line.startsWith(descriptor.sectionEnd)) {
in_program_section = false;
return false;
}
return true;
}
if (line.startsWith(descriptor.sectionStart)) {
in_program_section = true;
}
return false;
}).map((line) {
return descriptor.hitData(line);
});
}
testCoverage(String programDir, String programPath, descriptor,
List expectedHitMap) {
var p = convertCoverage(programDir, descriptor.coverageParameter);
expect(p.then((process) {
var hitStream = filterHitData(
process.stdout.transform(UTF8.decoder)
.transform(const LineSplitter()),
descriptor);
var hitMap = [];
var subscription = hitStream.listen((data) {
// Flatten results.
data.forEach((e) => hitMap.add(e));
});
expect(subscription.asFuture().then((_) {
hitMap.forEach((e) {
expect(e, expectedHitMap.removeAt(0));
});
// Make sure that there are only lines left that do not contain coverage
// data.
expectedHitMap.forEach((e) => expect(e, -1));
}), completes);
}), completes);
}
main() {
String testingDirectory;
setUp(() {
testingDirectory = prepareEnv();
});
tearDown(() => destroyEnv(testingDirectory));
test('CoverageTests', () {
generateCoverage(testingDirectory);
coverageTests.forEach((cTest) {
String programDir = path.join(testingDirectory, cTest['name']);
String programPath = path.join(programDir, "${cTest['name']}.dart");
testCoverage(programDir, programPath,
new LcovDescriptor(programPath),
new List.from(cTest['expectedHits']));
testCoverage(programDir, programPath,
new PrettyPrintDescriptor(programPath),
new List.from(cTest['expectedHits']));
});
});
}