Files
sdk/pkg/front_end/tool/coverage_runner.dart
T
Jens Johansen 8a6b48f596 [CFE] First pass at coverage tool
* Added tests for compiling the platform with coverage information
* Patched all CFE suites to be able to capture coverage information
  (e.g. via
  `out/ReleaseX64/dart pkg/front_end/test/fasta/strong_suite.dart \
  --coverage=coverage/` and then merging and showing via
  `out/ReleaseX64/dart pkg/front_end/tool/coverage_merger.dart \
  --coverage=coverage/`)
* Added "meta test" that runs all of the cfe et al tests and captures
  coverage information at the end.
* Patched the bulk compiler to be able to capture coverage information
  (likely only works in non-Windows as it has to hook into signaling to
  be able to capture data as the process is being killed by the test.py
  script).
* Tool for combining the dumped coverage information.
* Meta test that executes everything and combines the result
  (run via e.g. `out/ReleaseX64/dart-sdk/bin/dart \
  pkg/front_end/test/run_all_coverage.dart`)

Initially I wanted to (for language tests) have per-test coverage,
changed the test.py scripts to run the tests through a special tool that
then captured coverage information for the kernel_service isolate which
worked well for tests that compiles without error, but doesn't work when
there are compile time errors (because dart terminates before coverage
can be captured). So the solution - at least for now - was to hook into
the batch compilation.

The "visualization" of the result currently isn't very good -- mostly
just a list of not covered positions -- but the hope is that everything
that should be covered (eventually) will be covered, so maybe it's not a
big deal.

Also still to do is being able to - probably via comments in the covered
code - say "this isn't expected to be covered", so we can work towards
expecting all (or certain) files to be 100% covered (modulo those
comments), e.g. when running the thing on the weekly bot.

Change-Id: I6f885f4a9c04fb52a65797a9de790e1e5eacecf1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/353103
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
2024-02-21 12:40:01 +00:00

87 lines
2.4 KiB
Dart

// Copyright (c) 2024, 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:io';
import '../test/coverage_helper.dart';
import '../test/vm_service_helper.dart';
Uri? coverageUri;
Future<void> main(final List<String> args) async {
String? coverage = Platform.environment["CFE_COVERAGE"];
if (coverage != null) {
coverageUri = Uri.base.resolveUri(Uri.file(coverage));
} else {
throw "Set coverage path via 'CFE_COVERAGE' environment!";
}
MyLaunchingVMServiceHelper launchingHelper =
new MyLaunchingVMServiceHelper(args);
await launchingHelper.start(
[
"--pause_isolates_on_exit",
"--disable-dart-dev",
...args,
],
pauseIsolateOnStart: false,
);
await launchingHelper.exitCompleter.future;
}
class MyLaunchingVMServiceHelper extends LaunchingVMServiceHelper {
final List<String> args;
final Completer<int> exitCompleter = new Completer<int>();
MyLaunchingVMServiceHelper(this.args);
@override
void processExited(int code) {
exitCode = code;
exitCompleter.complete(code);
}
@override
Future<void> run() async {
// TODO(jensj): Get coverage for the isolate paused at exit, then resume
// that one, continue until there's no more isolates left.
// E.g. for pkg/front_end/tool/coverage_runner.dart.
await waitUntilSomeIsolatePausedAtExit();
Coverage? coverage = await collectCoverageWithHelper(
helper: this,
getKernelServiceCoverageToo: true,
displayName: args.join(" "),
);
if (coverage != null) {
File f = new File.fromUri(coverageUri!.resolve("coverage_run_"
"${DateTime.now().microsecondsSinceEpoch}_"
"${process.pid}.coverage"));
coverage.writeToFile(f);
}
await resumeAllIsolates();
try {
while (true) {
VM vm = await serviceClient.getVM();
List<IsolateRef> isolates = vm.isolates!;
if (isolates.isEmpty) break;
for (IsolateRef isolate in isolates) {
try {
if (await isPaused(isolate.id!) == true) {
await serviceClient.resume(isolate.id!);
}
} catch (e) {
// It might exit at some point so we can't expect to get
// a good result.
}
}
}
} catch (e) {
// Assume this is a good thing.
}
}
}