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

Side by Side Diff: lib/src/runner/reporter/expanded.dart

Issue 1187103004: Allow Suites to be added to an Engine over time. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Created 5 years, 6 months 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
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library test.runner.reporter.no_io_compact; 5 library test.runner.reporter.no_io_compact;
6 6
7 import 'dart:async'; 7 import 'dart:isolate';
8 8
9 import '../../backend/live_test.dart'; 9 import '../../backend/live_test.dart';
10 import '../../backend/state.dart'; 10 import '../../backend/state.dart';
11 import '../../backend/suite.dart';
12 import '../../utils.dart'; 11 import '../../utils.dart';
13 import '../engine.dart'; 12 import '../engine.dart';
13 import '../load_exception.dart';
14 14
15 /// The maximum console line length. 15 /// The maximum console line length.
16 /// 16 ///
17 /// Lines longer than this will be cropped. 17 /// Lines longer than this will be cropped.
18 const _lineLength = 100; 18 const _lineLength = 100;
19 19
20 /// A reporter that prints each test on its own line. 20 /// A reporter that prints each test on its own line.
21 /// 21 ///
22 /// This is currently used in place of [CompactReporter] by `lib/test.dart`, 22 /// This is currently used in place of [CompactReporter] by `lib/test.dart`,
23 /// which can't transitively import `dart:io` but still needs access to a runner 23 /// which can't transitively import `dart:io` but still needs access to a runner
24 /// so that test files can be run directly. This means that until issue 6943 is 24 /// so that test files can be run directly. This means that until issue 6943 is
25 /// fixed, this must not import `dart:io`. 25 /// fixed, this must not import `dart:io`.
26 class ExpandedReporter { 26 class ExpandedReporter {
27 /// Whether the reporter should emit terminal color escapes.
28 final bool _color;
29
27 /// The terminal escape for green text, or the empty string if this is Windows 30 /// The terminal escape for green text, or the empty string if this is Windows
28 /// or not outputting to a terminal. 31 /// or not outputting to a terminal.
29 final String _green; 32 final String _green;
30 33
31 /// The terminal escape for red text, or the empty string if this is Windows 34 /// The terminal escape for red text, or the empty string if this is Windows
32 /// or not outputting to a terminal. 35 /// or not outputting to a terminal.
33 final String _red; 36 final String _red;
34 37
35 /// The terminal escape for yellow text, or the empty string if this is 38 /// The terminal escape for yellow text, or the empty string if this is
36 /// Windows or not outputting to a terminal. 39 /// Windows or not outputting to a terminal.
37 final String _yellow; 40 final String _yellow;
38 41
39 /// The terminal escape for removing test coloring, or the empty string if 42 /// The terminal escape for removing test coloring, or the empty string if
40 /// this is Windows or not outputting to a terminal. 43 /// this is Windows or not outputting to a terminal.
41 final String _noColor; 44 final String _noColor;
42 45
43 /// Whether to use verbose stack traces. 46 /// Whether to use verbose stack traces.
44 final bool _verboseTrace; 47 final bool _verboseTrace;
45 48
46 /// The engine used to run the tests. 49 /// The engine used to run the tests.
47 final Engine _engine; 50 final Engine _engine;
48 51
49 /// Whether multiple test files are being run. 52 /// Whether the path to each test's suite should be printed.
50 final bool _multiplePaths; 53 final bool _printPath;
51 54
52 /// Whether tests are being run on multiple platforms. 55 /// Whether the platform each test is running on should be printed.
53 final bool _multiplePlatforms; 56 final bool _printPlatform;
54 57
55 /// A stopwatch that tracks the duration of the full run. 58 /// A stopwatch that tracks the duration of the full run.
56 final _stopwatch = new Stopwatch(); 59 final _stopwatch = new Stopwatch();
57 60
58 /// Whether [close] has been called.
59 bool _closed = false;
60
61 /// The size of `_engine.passed` last time a progress notification was 61 /// The size of `_engine.passed` last time a progress notification was
62 /// printed. 62 /// printed.
63 int _lastProgressPassed; 63 int _lastProgressPassed;
64 64
65 /// The size of `_engine.skipped` last time a progress notification was 65 /// The size of `_engine.skipped` last time a progress notification was
66 /// printed. 66 /// printed.
67 int _lastProgressSkipped; 67 int _lastProgressSkipped;
68 68
69 /// The size of `_engine.failed` last time a progress notification was 69 /// The size of `_engine.failed` last time a progress notification was
70 /// printed. 70 /// printed.
71 int _lastProgressFailed; 71 int _lastProgressFailed;
72 72
73 /// The message printed for the last progress notification. 73 /// The message printed for the last progress notification.
74 String _lastProgressMessage; 74 String _lastProgressMessage;
75 75
76 /// Creates a [NoIoCompactReporter] that will run all tests in [suites]. 76 /// Watches the tests run by [engine] and prints their results to the
77 /// terminal.
77 /// 78 ///
78 /// [concurrency] controls how many suites are run at once. If [color] is 79 /// If [color] is `true`, this will use terminal colors; if it's `false`, it
79 /// `true`, this will use terminal colors; if it's `false`, it won't. If 80 /// won't. If [verboseTrace] is `true`, this will print core library frames.
80 /// [verboseTrace] is `true`, this will print core library frames. 81 /// If [printPath] is `true`, this will print the path name as part of the
81 ExpandedReporter(Iterable<Suite> suites, {int concurrency, bool color: true, 82 /// test description. Likewise, if [printPlatform] is `true`, this will print
82 bool verboseTrace: false}) 83 /// the platform as part of the test description.
83 : _multiplePaths = suites.map((suite) => suite.path).toSet().length > 1, 84 static void watch(Engine engine, {bool color: true, bool verboseTrace: false,
84 _multiplePlatforms = 85 bool printPath: true, bool printPlatform: true}) {
85 suites.map((suite) => suite.platform).toSet().length > 1, 86 new ExpandedReporter._(
86 _engine = new Engine(suites, concurrency: concurrency), 87 engine,
87 _verboseTrace = verboseTrace, 88 color: color,
89 verboseTrace: verboseTrace,
90 printPath: printPath,
91 printPlatform: printPlatform);
92 }
93
94 ExpandedReporter._(this._engine, {bool color: true, bool verboseTrace: false,
95 bool printPath: true, bool printPlatform: true})
96 : _verboseTrace = verboseTrace,
97 _printPath = printPath,
98 _printPlatform = printPlatform,
99 _color = color,
88 _green = color ? '\u001b[32m' : '', 100 _green = color ? '\u001b[32m' : '',
89 _red = color ? '\u001b[31m' : '', 101 _red = color ? '\u001b[31m' : '',
90 _yellow = color ? '\u001b[33m' : '', 102 _yellow = color ? '\u001b[33m' : '',
91 _noColor = color ? '\u001b[0m' : '' { 103 _noColor = color ? '\u001b[0m' : '' {
92 _engine.onTestStarted.listen((liveTest) { 104 _engine.onTestStarted.listen(_onTestStarted);
93 // If this is the first test to start, print a progress line so the user 105 _engine.success.then(_onDone);
94 // knows what's running. 106 }
95 if (_engine.active.length == 1) _progressLine(_description(liveTest));
96 107
97 liveTest.onStateChange.listen((state) { 108 /// A callback called when the engine begins running [liveTest].
98 if (state.status != Status.complete) return; 109 void _onTestStarted(LiveTest liveTest) {
110 if (!_stopwatch.isRunning) _stopwatch.start();
99 111
100 if (liveTest.test.metadata.skip && 112 // If this is the first test to start, print a progress line so
101 liveTest.test.metadata.skipReason != null) { 113 // the user knows what's running.
102 _progressLine(_description(liveTest)); 114 if (_engine.active.length == 1) _progressLine(_description(liveTest));
103 print(indent('${_yellow}Skip: ${liveTest.test.metadata.skipReason}'
104 '$_noColor'));
105 } else if (_engine.active.isNotEmpty) {
106 // If any tests are running, display the name of the oldest active
107 // test.
108 _progressLine(_description(_engine.active.first));
109 }
110 });
111 115
112 liveTest.onError.listen((error) { 116 liveTest.onStateChange.listen((state) => _onStateChange(liveTest, state));
113 if (liveTest.state.status != Status.complete) return;
114 117
115 _progressLine(_description(liveTest)); 118 liveTest.onError.listen((error) =>
116 print(indent(error.error.toString())); 119 _onError(liveTest, error.error, error.stackTrace));
117 var chain = terseChain(error.stackTrace, verbose: _verboseTrace);
118 print(indent(chain.toString()));
119 });
120 120
121 liveTest.onPrint.listen((line) { 121 liveTest.onPrint.listen((line) {
122 _progressLine(_description(liveTest)); 122 _progressLine(_description(liveTest));
123 print(line); 123 print(line);
124 });
125 }); 124 });
126 } 125 }
127 126
128 /// Runs all tests in all provided suites. 127 /// A callback called when [liveTest]'s state becomes [state].
128 void _onStateChange(LiveTest liveTest, State state) {
129 if (state.status != Status.complete) return;
130
131 if (liveTest.test.metadata.skip &&
132 liveTest.test.metadata.skipReason != null) {
133 _progressLine(_description(liveTest));
134 print(indent('${_yellow}Skip: ${liveTest.test.metadata.skipReason}'
135 '$_noColor'));
136 } else if (_engine.active.isNotEmpty) {
137 // If any tests are running, display the name of the oldest active
138 // test.
139 _progressLine(_description(_engine.active.first));
140 }
141 }
142
143 /// A callback called when [liveTest] throws [error].
144 void _onError(LiveTest liveTest, error, StackTrace stackTrace) {
145 if (liveTest.state.status != Status.complete) return;
146
147 _progressLine(_description(liveTest));
148
149 if (error is! LoadException) {
150 print(indent(error.toString()));
151 var chain = terseChain(stackTrace, verbose: _verboseTrace);
152 print(indent(chain.toString()));
153 return;
154 }
155
156 print(indent(error.toString(color: _color)));
157
158 // Only print stack traces for load errors that come from the user's code.
159 if (error.innerError is! IsolateSpawnException &&
160 error.innerError is! FormatException &&
161 error.innerError is! String) {
162 print(indent(terseChain(stackTrace).toString()));
163 }
164 }
165
166 /// A callback called when the engine is finished running tests.
129 /// 167 ///
130 /// This returns `true` if all tests succeed, and `false` otherwise. It will 168 /// [success] will be `true` if all tests passed, `false` if some tests
131 /// only return once all tests have finished running. 169 /// failed, and `null` if the engine was closed prematurely.
132 Future<bool> run() async { 170 void _onDone(bool success) {
133 if (_stopwatch.isRunning) { 171 // A null success value indicates that the engine was closed before the
134 throw new StateError("ExpandedReporter.run() may not be called more than " 172 // tests finished running, probably because of a signal from the user, in
135 "once."); 173 // which case we shouldn't print summary information.
136 } 174 if (success == null) return;
137 175
138 if (_engine.liveTests.isEmpty) { 176 if (_engine.liveTests.isEmpty) {
139 print("No tests ran."); 177 print("No tests ran.");
140 return true; 178 } else if (!success) {
141 }
142
143 _stopwatch.start();
144 var success = await _engine.run();
145 if (_closed) return false;
146
147 if (!success) {
148 _progressLine('Some tests failed.', color: _red); 179 _progressLine('Some tests failed.', color: _red);
149 } else if (_engine.passed.isEmpty) { 180 } else if (_engine.passed.isEmpty) {
150 _progressLine("All tests skipped."); 181 _progressLine("All tests skipped.");
151 } else { 182 } else {
152 _progressLine("All tests passed!"); 183 _progressLine("All tests passed!");
153 } 184 }
154
155 return success;
156 } 185 }
157 186
158 /// Signals that the caller is done with any test output and the reporter
159 /// should release any resources it has allocated.
160 Future close() => _engine.close();
161
162 /// Prints a line representing the current state of the tests. 187 /// Prints a line representing the current state of the tests.
163 /// 188 ///
164 /// [message] goes after the progress report, and may be truncated to fit the 189 /// [message] goes after the progress report, and may be truncated to fit the
165 /// entire line within [_lineLength]. If [color] is passed, it's used as the 190 /// entire line within [_lineLength]. If [color] is passed, it's used as the
166 /// color for [message]. 191 /// color for [message].
167 void _progressLine(String message, {String color}) { 192 void _progressLine(String message, {String color}) {
168 // Print nothing if nothing has changed since the last progress line. 193 // Print nothing if nothing has changed since the last progress line.
169 if (_engine.passed.length == _lastProgressPassed && 194 if (_engine.passed.length == _lastProgressPassed &&
170 _engine.skipped.length == _lastProgressSkipped && 195 _engine.skipped.length == _lastProgressSkipped &&
171 _engine.failed.length == _lastProgressFailed && 196 _engine.failed.length == _lastProgressFailed &&
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 "${(duration.inSeconds % 60).toString().padLeft(2, '0')}"; 249 "${(duration.inSeconds % 60).toString().padLeft(2, '0')}";
225 } 250 }
226 251
227 /// Returns a description of [liveTest]. 252 /// Returns a description of [liveTest].
228 /// 253 ///
229 /// This differs from the test's own description in that it may also include 254 /// This differs from the test's own description in that it may also include
230 /// the suite's name. 255 /// the suite's name.
231 String _description(LiveTest liveTest) { 256 String _description(LiveTest liveTest) {
232 var name = liveTest.test.name; 257 var name = liveTest.test.name;
233 258
234 if (_multiplePaths && liveTest.suite.path != null) { 259 if (_printPath && liveTest.suite.path != null) {
235 name = "${liveTest.suite.path}: $name"; 260 name = "${liveTest.suite.path}: $name";
236 } 261 }
237 262
238 if (_multiplePlatforms && liveTest.suite.platform != null) { 263 if (_printPlatform && liveTest.suite.platform != null) {
239 name = "[${liveTest.suite.platform}] $name"; 264 name = "[${liveTest.suite.platform}] $name";
240 } 265 }
241 266
242 return name; 267 return name;
243 } 268 }
244 } 269 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698