| Index: pkg/testing/lib/src/analyze.dart
|
| diff --git a/pkg/testing/lib/src/analyze.dart b/pkg/testing/lib/src/analyze.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6106b9ea104db950de9f96f2d2293466312c224d
|
| --- /dev/null
|
| +++ b/pkg/testing/lib/src/analyze.dart
|
| @@ -0,0 +1,150 @@
|
| +// Copyright (c) 2016, 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.md file.
|
| +
|
| +library testing.analyze;
|
| +
|
| +import 'dart:async' show
|
| + Stream,
|
| + Future;
|
| +
|
| +import 'dart:convert' show
|
| + LineSplitter,
|
| + UTF8;
|
| +
|
| +import 'dart:io' show
|
| + File,
|
| + Process;
|
| +
|
| +import '../testing.dart' show
|
| + dartSdk;
|
| +
|
| +import 'log.dart' show
|
| + isVerbose;
|
| +
|
| +import 'suite.dart' show
|
| + Suite;
|
| +
|
| +class Analyze extends Suite {
|
| + final List<Uri> uris;
|
| +
|
| + final List<RegExp> exclude;
|
| +
|
| + Analyze(this.uris, this.exclude)
|
| + : super("analyze", "analyze", null);
|
| +
|
| + Future<Null> run(Uri packages, List<Uri> extraUris) {
|
| + List<Uri> allUris = new List<Uri>.from(uris);
|
| + if (extraUris != null) {
|
| + allUris.addAll(extraUris);
|
| + }
|
| + return analyzeUris(packages, allUris, exclude);
|
| + }
|
| +
|
| + static Future<Analyze> fromJsonMap(
|
| + Uri base, Map json, List<Suite> suites) async {
|
| + List<Uri> uris = new List<Uri>.from(
|
| + json["uris"].map((String relative) => base.resolve(relative)));
|
| +
|
| + List<RegExp> exclude =
|
| + new List<RegExp>.from(json["exclude"].map((String p) => new RegExp(p)));
|
| +
|
| + return new Analyze(uris, exclude);
|
| + }
|
| +
|
| + String toString() => "Analyze($uris, $exclude)";
|
| +}
|
| +
|
| +class AnalyzerDiagnostic {
|
| + final String kind;
|
| +
|
| + final String detailedKind;
|
| +
|
| + final String code;
|
| +
|
| + final Uri uri;
|
| +
|
| + final int line;
|
| +
|
| + final int startColumn;
|
| +
|
| + final int endColumn;
|
| +
|
| + final String message;
|
| +
|
| + AnalyzerDiagnostic(this.kind, this.detailedKind, this.code, this.uri,
|
| + this.line, this.startColumn, this.endColumn, this.message);
|
| +
|
| + factory AnalyzerDiagnostic.fromLine(String line) {
|
| + List<String> parts = line.split("|");
|
| + if (parts.length != 8) {
|
| + throw "Malformed output: $line";
|
| + }
|
| + return new AnalyzerDiagnostic(parts[0], parts[1], parts[2],
|
| + Uri.base.resolve(parts[3]),
|
| + int.parse(parts[4]), int.parse(parts[5]), int.parse(parts[6]),
|
| + parts[7]);
|
| + }
|
| +
|
| + String toString() {
|
| + return "$uri:$line:$startColumn: "
|
| + "${kind == 'INFO' ? 'warning: hint' : kind.toLowerCase()}:\n$message";
|
| + }
|
| +}
|
| +
|
| +Stream<AnalyzerDiagnostic> parseAnalyzerOutput(
|
| + Stream<List<int>> stream) async* {
|
| + Stream<String> lines =
|
| + stream.transform(UTF8.decoder).transform(new LineSplitter());
|
| + await for (String line in lines) {
|
| + yield new AnalyzerDiagnostic.fromLine(line);
|
| + }
|
| +}
|
| +
|
| +/// Run dartanalyzer on all tests in [uris].
|
| +Future<Null> analyzeUris(
|
| + Uri packages, List<Uri> uris, List<RegExp> exclude) async {
|
| + if (uris.isEmpty) return;
|
| + const String analyzerPath = "bin/dartanalyzer";
|
| + Uri analyzer = dartSdk.resolve(analyzerPath);
|
| + if (!await new File.fromUri(analyzer).exists()) {
|
| + throw "Couldn't find '$analyzerPath' in '${dartSdk.toFilePath()}'";
|
| + }
|
| + List<String> arguments = <String>[
|
| + "--packages=${packages.toFilePath()}",
|
| + "--package-warnings",
|
| + "--format=machine",
|
| + ];
|
| + arguments.addAll(uris.map((Uri uri) => uri.toFilePath()));
|
| + if (isVerbose) {
|
| + print("Running:\n ${analyzer.toFilePath()} ${arguments.join(' ')}");
|
| + } else {
|
| + print("Running dartanalyzer.");
|
| + }
|
| + Stopwatch sw = new Stopwatch()..start();
|
| + Process process = await Process.start(analyzer.toFilePath(), arguments);
|
| + process.stdin.close();
|
| + Future stdoutFuture = parseAnalyzerOutput(process.stdout).toList();
|
| + Future stderrFuture = parseAnalyzerOutput(process.stderr).toList();
|
| + await process.exitCode;
|
| + List<AnalyzerDiagnostic> diagnostics = <AnalyzerDiagnostic>[];
|
| + diagnostics.addAll(await stdoutFuture);
|
| + diagnostics.addAll(await stderrFuture);
|
| + bool hasOutput = false;
|
| + Set<String> seen = new Set<String>();
|
| + for (AnalyzerDiagnostic diagnostic in diagnostics) {
|
| + String path = diagnostic.uri.path;
|
| + if (exclude.any((RegExp r) => path.contains(r))) continue;
|
| + String message = "$diagnostic";
|
| + if (seen.add(message)) {
|
| + hasOutput = true;
|
| + print(message);
|
| + }
|
| + }
|
| + if (hasOutput) {
|
| + throw "Non-empty output from analyzer.";
|
| + }
|
| + sw.stop();
|
| + print("Running analyzer took: ${sw.elapsed}.");
|
| +}
|
| +
|
|
|