Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(425)

Unified Diff: lib/src/runner/reporter/json.dart

Issue 1461293005: Add a JSON reporter. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: lib/src/runner/reporter/json.dart
diff --git a/lib/src/runner/reporter/json.dart b/lib/src/runner/reporter/json.dart
new file mode 100644
index 0000000000000000000000000000000000000000..b0c45bbcf53125927146504e61bae27ffe1f4eeb
--- /dev/null
+++ b/lib/src/runner/reporter/json.dart
@@ -0,0 +1,168 @@
+// 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.
+
+library test.runner.reporter.json;
+
+import 'dart:async';
+import 'dart:convert';
+
+import '../../backend/live_test.dart';
+import '../../utils.dart';
+import '../engine.dart';
+import '../load_exception.dart';
+import '../reporter.dart';
+import '../version.dart';
+
+/// A reporter that prints machine-readable JSON-formatted test results.
+class JsonReporter implements Reporter {
+ /// Whether to use verbose stack traces.
+ final bool _verboseTrace;
+
+ /// The engine used to run the tests.
+ final Engine _engine;
+
+ /// A stopwatch that tracks the duration of the full run.
+ final _stopwatch = new Stopwatch();
+
+ /// Whether we've started [_stopwatch].
+ ///
+ /// We can't just use `_stopwatch.isRunning` because the stopwatch is stopped
+ /// when the reporter is paused.
+ var _stopwatchStarted = false;
+
+ /// Whether the reporter is paused.
+ var _paused = false;
+
+ /// The set of all subscriptions to various streams.
+ final _subscriptions = new Set<StreamSubscription>();
+
+ /// An expando that associates unique IDs with [LiveTest]s.
+ final _ids = new Map<LiveTest, int>();
+
+ /// The next ID to associate with a [LiveTest].
+ var _nextID = 0;
+
+ /// Watches the tests run by [engine] and prints their results as JSON.
+ ///
+ /// If [verboseTrace] is `true`, this will print core library frames.
+ static JsonReporter watch(Engine engine, {bool verboseTrace: false}) {
+ return new JsonReporter._(engine, verboseTrace: verboseTrace);
+ }
+
+ JsonReporter._(this._engine, {bool verboseTrace: false})
+ : _verboseTrace = verboseTrace {
+ _subscriptions.add(_engine.onTestStarted.listen(_onTestStarted));
+
+ /// Convert the future to a stream so that the subscription can be paused or
+ /// canceled.
+ _subscriptions.add(_engine.success.asStream().listen(_onDone));
+
+ _emit("start", {
+ "protocolVersion": "0.1.0",
+ "runnerVersion": testVersion
+ });
+ }
+
+ void pause() {
+ if (_paused) return;
+ _paused = true;
+
+ _stopwatch.stop();
+
+ for (var subscription in _subscriptions) {
+ subscription.pause();
+ }
+ }
+
+ void resume() {
+ if (!_paused) return;
+ _paused = false;
+
+ if (_stopwatchStarted) _stopwatch.start();
+
+ for (var subscription in _subscriptions) {
+ subscription.resume();
+ }
+ }
+
+ void cancel() {
+ for (var subscription in _subscriptions) {
+ subscription.cancel();
+ }
+ _subscriptions.clear();
+ }
+
+ /// A callback called when the engine begins running [liveTest].
+ void _onTestStarted(LiveTest liveTest) {
+ if (!_stopwatchStarted) {
+ _stopwatchStarted = true;
+ _stopwatch.start();
+ }
+
+ var id = _nextID++;
+ _ids[liveTest] = id;
+ _emit("testStart", {
+ "test": {
+ "id": id,
+ "name": liveTest.test.name,
+ "metadata": {
+ "skip": liveTest.test.metadata.skip,
+ "skipReason": liveTest.test.metadata.skipReason
+ }
+ }
+ });
+
+ /// Convert the future to a stream so that the subscription can be paused or
+ /// canceled.
+ _subscriptions.add(liveTest.onComplete.asStream().listen((_) =>
+ _onComplete(liveTest)));
+
+ _subscriptions.add(liveTest.onError.listen((error) =>
+ _onError(liveTest, error.error, error.stackTrace)));
+
+ _subscriptions.add(liveTest.onPrint.listen((line) {
+ _emit("print", {
+ "testID": id,
+ "message": line
+ });
+ }));
+ }
+
+ /// A callback called when [liveTest] finishes running.
+ void _onComplete(LiveTest liveTest) {
+ _emit("testDone", {
+ "testID": _ids[liveTest],
+ "result": liveTest.state.result.toString(),
+ "hidden": !_engine.liveTests.contains(liveTest)
+ });
+ }
+
+ /// A callback called when [liveTest] throws [error].
+ void _onError(LiveTest liveTest, error, StackTrace stackTrace) {
+ _emit("error", {
+ "testID": _ids[liveTest],
+ "error": error.toString(),
+ "stackTrace": terseChain(stackTrace, verbose: _verboseTrace).toString(),
+ "isFailure": error is LoadException
+ });
+ }
+
+ /// A callback called when the engine is finished running tests.
+ ///
+ /// [success] will be `true` if all tests passed, `false` if some tests
+ /// failed, and `null` if the engine was closed prematurely.
+ void _onDone(bool success) {
+ cancel();
+ _stopwatch.stop();
+
+ _emit("done", {"success": success});
+ }
+
+ /// Emits an event with the given type and attributes.
+ void _emit(String type, Map attributes) {
+ attributes["type"] = type;
+ attributes["time"] = _stopwatch.elapsed.inMilliseconds;
+ print(JSON.encode(attributes));
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698