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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library test.runner.reporter.json;
6
7 import 'dart:async';
8 import 'dart:convert';
9
10 import '../../backend/live_test.dart';
11 import '../../utils.dart';
12 import '../engine.dart';
13 import '../load_exception.dart';
14 import '../reporter.dart';
15 import '../version.dart';
16
17 /// A reporter that prints machine-readable JSON-formatted test results.
18 class JsonReporter implements Reporter {
19 /// Whether to use verbose stack traces.
20 final bool _verboseTrace;
21
22 /// The engine used to run the tests.
23 final Engine _engine;
24
25 /// A stopwatch that tracks the duration of the full run.
26 final _stopwatch = new Stopwatch();
27
28 /// Whether we've started [_stopwatch].
29 ///
30 /// We can't just use `_stopwatch.isRunning` because the stopwatch is stopped
31 /// when the reporter is paused.
32 var _stopwatchStarted = false;
33
34 /// Whether the reporter is paused.
35 var _paused = false;
36
37 /// The set of all subscriptions to various streams.
38 final _subscriptions = new Set<StreamSubscription>();
39
40 /// An expando that associates unique IDs with [LiveTest]s.
41 final _ids = new Map<LiveTest, int>();
42
43 /// The next ID to associate with a [LiveTest].
44 var _nextID = 0;
45
46 /// Watches the tests run by [engine] and prints their results as JSON.
47 ///
48 /// If [verboseTrace] is `true`, this will print core library frames.
49 static JsonReporter watch(Engine engine, {bool verboseTrace: false}) {
50 return new JsonReporter._(engine, verboseTrace: verboseTrace);
51 }
52
53 JsonReporter._(this._engine, {bool verboseTrace: false})
54 : _verboseTrace = verboseTrace {
55 _subscriptions.add(_engine.onTestStarted.listen(_onTestStarted));
56
57 /// Convert the future to a stream so that the subscription can be paused or
58 /// canceled.
59 _subscriptions.add(_engine.success.asStream().listen(_onDone));
60
61 _emit("start", {
62 "protocolVersion": "0.1.0",
63 "runnerVersion": testVersion
64 });
65 }
66
67 void pause() {
68 if (_paused) return;
69 _paused = true;
70
71 _stopwatch.stop();
72
73 for (var subscription in _subscriptions) {
74 subscription.pause();
75 }
76 }
77
78 void resume() {
79 if (!_paused) return;
80 _paused = false;
81
82 if (_stopwatchStarted) _stopwatch.start();
83
84 for (var subscription in _subscriptions) {
85 subscription.resume();
86 }
87 }
88
89 void cancel() {
90 for (var subscription in _subscriptions) {
91 subscription.cancel();
92 }
93 _subscriptions.clear();
94 }
95
96 /// A callback called when the engine begins running [liveTest].
97 void _onTestStarted(LiveTest liveTest) {
98 if (!_stopwatchStarted) {
99 _stopwatchStarted = true;
100 _stopwatch.start();
101 }
102
103 var id = _nextID++;
104 _ids[liveTest] = id;
105 _emit("testStart", {
106 "test": {
107 "id": id,
108 "name": liveTest.test.name,
109 "metadata": {
110 "skip": liveTest.test.metadata.skip,
111 "skipReason": liveTest.test.metadata.skipReason
112 }
113 }
114 });
115
116 /// Convert the future to a stream so that the subscription can be paused or
117 /// canceled.
118 _subscriptions.add(liveTest.onComplete.asStream().listen((_) =>
119 _onComplete(liveTest)));
120
121 _subscriptions.add(liveTest.onError.listen((error) =>
122 _onError(liveTest, error.error, error.stackTrace)));
123
124 _subscriptions.add(liveTest.onPrint.listen((line) {
125 _emit("print", {
126 "testID": id,
127 "message": line
128 });
129 }));
130 }
131
132 /// A callback called when [liveTest] finishes running.
133 void _onComplete(LiveTest liveTest) {
134 _emit("testDone", {
135 "testID": _ids[liveTest],
136 "result": liveTest.state.result.toString(),
137 "hidden": !_engine.liveTests.contains(liveTest)
138 });
139 }
140
141 /// A callback called when [liveTest] throws [error].
142 void _onError(LiveTest liveTest, error, StackTrace stackTrace) {
143 _emit("error", {
144 "testID": _ids[liveTest],
145 "error": error.toString(),
146 "stackTrace": terseChain(stackTrace, verbose: _verboseTrace).toString(),
147 "isFailure": error is LoadException
148 });
149 }
150
151 /// A callback called when the engine is finished running tests.
152 ///
153 /// [success] will be `true` if all tests passed, `false` if some tests
154 /// failed, and `null` if the engine was closed prematurely.
155 void _onDone(bool success) {
156 cancel();
157 _stopwatch.stop();
158
159 _emit("done", {"success": success});
160 }
161
162 /// Emits an event with the given type and attributes.
163 void _emit(String type, Map attributes) {
164 attributes["type"] = type;
165 attributes["time"] = _stopwatch.elapsed.inMilliseconds;
166 print(JSON.encode(attributes));
167 }
168 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698