| OLD | NEW |
| 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.compact; | 5 library test.runner.reporter.compact; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 import 'dart:isolate'; | 9 import 'dart:isolate'; |
| 10 | 10 |
| 11 import '../../backend/live_test.dart'; | 11 import '../../backend/live_test.dart'; |
| 12 import '../../backend/state.dart'; | 12 import '../../backend/state.dart'; |
| 13 import '../../utils.dart'; | 13 import '../../utils.dart'; |
| 14 import '../../utils.dart' as utils; |
| 14 import '../engine.dart'; | 15 import '../engine.dart'; |
| 15 import '../load_exception.dart'; | 16 import '../load_exception.dart'; |
| 16 import '../load_suite.dart'; | 17 import '../load_suite.dart'; |
| 17 | 18 |
| 18 /// The maximum console line length. | 19 /// The maximum console line length. |
| 19 /// | 20 /// |
| 20 /// Lines longer than this will be cropped. | 21 /// Lines longer than this will be cropped. |
| 21 const _lineLength = 100; | 22 const _lineLength = 100; |
| 22 | 23 |
| 23 /// A reporter that prints test results to the console in a single | 24 /// A reporter that prints test results to the console in a single |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 /// printed. | 80 /// printed. |
| 80 int _lastProgressFailed; | 81 int _lastProgressFailed; |
| 81 | 82 |
| 82 /// The duration of the test run in seconds last time a progress notification | 83 /// The duration of the test run in seconds last time a progress notification |
| 83 /// was printed. | 84 /// was printed. |
| 84 int _lastProgressElapsed; | 85 int _lastProgressElapsed; |
| 85 | 86 |
| 86 /// The message printed for the last progress notification. | 87 /// The message printed for the last progress notification. |
| 87 String _lastProgressMessage; | 88 String _lastProgressMessage; |
| 88 | 89 |
| 90 /// Whether the message printed for the last progress notification was |
| 91 /// truncated. |
| 92 bool _lastProgressTruncated; |
| 93 |
| 89 // Whether a newline has been printed since the last progress line. | 94 // Whether a newline has been printed since the last progress line. |
| 90 var _printedNewline = true; | 95 var _printedNewline = true; |
| 91 | 96 |
| 92 /// Watches the tests run by [engine] and prints their results to the | 97 /// Watches the tests run by [engine] and prints their results to the |
| 93 /// terminal. | 98 /// terminal. |
| 94 /// | 99 /// |
| 95 /// If [color] is `true`, this will use terminal colors; if it's `false`, it | 100 /// If [color] is `true`, this will use terminal colors; if it's `false`, it |
| 96 /// won't. If [verboseTrace] is `true`, this will print core library frames. | 101 /// won't. If [verboseTrace] is `true`, this will print core library frames. |
| 97 /// If [printPath] is `true`, this will print the path name as part of the | 102 /// If [printPath] is `true`, this will print the path name as part of the |
| 98 /// test description. Likewise, if [printPlatform] is `true`, this will print | 103 /// test description. Likewise, if [printPlatform] is `true`, this will print |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 _timer = new Timer.periodic(new Duration(seconds: 1), | 136 _timer = new Timer.periodic(new Duration(seconds: 1), |
| 132 (_) => _progressLine(_lastProgressMessage)); | 137 (_) => _progressLine(_lastProgressMessage)); |
| 133 } | 138 } |
| 134 | 139 |
| 135 // If this is the first test to start, print a progress line so the user | 140 // If this is the first test to start, print a progress line so the user |
| 136 // knows what's running. It's possible that the active test may not be | 141 // knows what's running. It's possible that the active test may not be |
| 137 // [liveTest] because the engine doesn't always surface load tests. | 142 // [liveTest] because the engine doesn't always surface load tests. |
| 138 if (_engine.active.length == 1 && _engine.active.first == liveTest) { | 143 if (_engine.active.length == 1 && _engine.active.first == liveTest) { |
| 139 _progressLine(_description(liveTest)); | 144 _progressLine(_description(liveTest)); |
| 140 } | 145 } |
| 141 _printedNewline = false; | |
| 142 | 146 |
| 143 liveTest.onStateChange.listen((state) => _onStateChange(liveTest, state)); | 147 liveTest.onStateChange.listen((state) => _onStateChange(liveTest, state)); |
| 144 | 148 |
| 145 liveTest.onError.listen((error) => | 149 liveTest.onError.listen((error) => |
| 146 _onError(liveTest, error.error, error.stackTrace)); | 150 _onError(liveTest, error.error, error.stackTrace)); |
| 147 | 151 |
| 148 liveTest.onPrint.listen((line) { | 152 liveTest.onPrint.listen((line) { |
| 149 _progressLine(_description(liveTest)); | 153 _progressLine(_description(liveTest), truncate: false); |
| 150 if (!_printedNewline) print(''); | 154 if (!_printedNewline) print(''); |
| 151 _printedNewline = true; | 155 _printedNewline = true; |
| 152 | 156 |
| 153 print(line); | 157 print(line); |
| 154 }); | 158 }); |
| 155 } | 159 } |
| 156 | 160 |
| 157 /// A callback called when [liveTest]'s state becomes [state]. | 161 /// A callback called when [liveTest]'s state becomes [state]. |
| 158 void _onStateChange(LiveTest liveTest, State state) { | 162 void _onStateChange(LiveTest liveTest, State state) { |
| 159 if (state.status != Status.complete) return; | 163 if (state.status != Status.complete) return; |
| 160 | 164 |
| 161 if (liveTest.test.metadata.skip && | 165 if (liveTest.test.metadata.skip && |
| 162 liveTest.test.metadata.skipReason != null) { | 166 liveTest.test.metadata.skipReason != null) { |
| 163 _progressLine(_description(liveTest)); | 167 _progressLine(_description(liveTest)); |
| 164 print(''); | 168 print(''); |
| 165 print(indent('${_yellow}Skip: ${liveTest.test.metadata.skipReason}' | 169 print(indent('${_yellow}Skip: ${liveTest.test.metadata.skipReason}' |
| 166 '$_noColor')); | 170 '$_noColor')); |
| 167 } else { | 171 } else { |
| 168 // Always display the name of the oldest active test, unless testing | 172 // Always display the name of the oldest active test, unless testing |
| 169 // is finished in which case display the last test to complete. | 173 // is finished in which case display the last test to complete. |
| 170 if (_engine.active.isEmpty) { | 174 if (_engine.active.isEmpty) { |
| 171 _progressLine(_description(liveTest)); | 175 _progressLine(_description(liveTest)); |
| 172 } else { | 176 } else { |
| 173 _progressLine(_description(_engine.active.first)); | 177 _progressLine(_description(_engine.active.first)); |
| 174 } | 178 } |
| 175 | |
| 176 _printedNewline = false; | |
| 177 } | 179 } |
| 178 } | 180 } |
| 179 | 181 |
| 180 /// A callback called when [liveTest] throws [error]. | 182 /// A callback called when [liveTest] throws [error]. |
| 181 void _onError(LiveTest liveTest, error, StackTrace stackTrace) { | 183 void _onError(LiveTest liveTest, error, StackTrace stackTrace) { |
| 182 if (liveTest.state.status != Status.complete) return; | 184 if (liveTest.state.status != Status.complete) return; |
| 183 | 185 |
| 184 _progressLine(_description(liveTest)); | 186 _progressLine(_description(liveTest), truncate: false); |
| 185 if (!_printedNewline) print(''); | 187 if (!_printedNewline) print(''); |
| 186 _printedNewline = true; | 188 _printedNewline = true; |
| 187 | 189 |
| 188 if (error is! LoadException) { | 190 if (error is! LoadException) { |
| 189 print(indent(error.toString())); | 191 print(indent(error.toString())); |
| 190 var chain = terseChain(stackTrace, verbose: _verboseTrace); | 192 var chain = terseChain(stackTrace, verbose: _verboseTrace); |
| 191 print(indent(chain.toString())); | 193 print(indent(chain.toString())); |
| 192 return; | 194 return; |
| 193 } | 195 } |
| 194 | 196 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 _progressLine("All tests passed!"); | 242 _progressLine("All tests passed!"); |
| 241 print(''); | 243 print(''); |
| 242 } | 244 } |
| 243 } | 245 } |
| 244 | 246 |
| 245 /// Prints a line representing the current state of the tests. | 247 /// Prints a line representing the current state of the tests. |
| 246 /// | 248 /// |
| 247 /// [message] goes after the progress report, and may be truncated to fit the | 249 /// [message] goes after the progress report, and may be truncated to fit the |
| 248 /// entire line within [_lineLength]. If [color] is passed, it's used as the | 250 /// entire line within [_lineLength]. If [color] is passed, it's used as the |
| 249 /// color for [message]. | 251 /// color for [message]. |
| 250 bool _progressLine(String message, {String color}) { | 252 bool _progressLine(String message, {String color, bool truncate: true}) { |
| 251 var elapsed = _stopwatch.elapsed.inSeconds; | 253 var elapsed = _stopwatch.elapsed.inSeconds; |
| 252 | 254 |
| 253 // Print nothing if nothing has changed since the last progress line. | 255 // Print nothing if nothing has changed since the last progress line. |
| 254 if (_engine.passed.length == _lastProgressPassed && | 256 if (_engine.passed.length == _lastProgressPassed && |
| 255 _engine.skipped.length == _lastProgressSkipped && | 257 _engine.skipped.length == _lastProgressSkipped && |
| 256 _engine.failed.length == _lastProgressFailed && | 258 _engine.failed.length == _lastProgressFailed && |
| 257 elapsed == _lastProgressElapsed && | 259 elapsed == _lastProgressElapsed && |
| 258 message == _lastProgressMessage) { | 260 message == _lastProgressMessage && |
| 261 truncate == _lastProgressTruncated) { |
| 259 return false; | 262 return false; |
| 260 } | 263 } |
| 261 | 264 |
| 262 _lastProgressPassed = _engine.passed.length; | 265 _lastProgressPassed = _engine.passed.length; |
| 263 _lastProgressSkipped = _engine.skipped.length; | 266 _lastProgressSkipped = _engine.skipped.length; |
| 264 _lastProgressFailed = _engine.failed.length; | 267 _lastProgressFailed = _engine.failed.length; |
| 265 _lastProgressElapsed = elapsed; | 268 _lastProgressElapsed = elapsed; |
| 266 _lastProgressMessage = message; | 269 _lastProgressMessage = message; |
| 270 _lastProgressTruncated = truncate; |
| 267 | 271 |
| 268 if (color == null) color = ''; | 272 if (color == null) color = ''; |
| 269 var duration = _stopwatch.elapsed; | 273 var duration = _stopwatch.elapsed; |
| 270 var buffer = new StringBuffer(); | 274 var buffer = new StringBuffer(); |
| 271 | 275 |
| 272 // \r moves back to the beginning of the current line. | 276 // \r moves back to the beginning of the current line. |
| 273 buffer.write('\r${_timeString(duration)} '); | 277 buffer.write('\r${_timeString(duration)} '); |
| 274 buffer.write(_green); | 278 buffer.write(_green); |
| 275 buffer.write('+'); | 279 buffer.write('+'); |
| 276 buffer.write(_engine.passed.length); | 280 buffer.write(_engine.passed.length); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 290 buffer.write(_noColor); | 294 buffer.write(_noColor); |
| 291 } | 295 } |
| 292 | 296 |
| 293 buffer.write(': '); | 297 buffer.write(': '); |
| 294 buffer.write(color); | 298 buffer.write(color); |
| 295 | 299 |
| 296 // Ensure the line fits within [_lineLength]. [buffer] includes the color | 300 // Ensure the line fits within [_lineLength]. [buffer] includes the color |
| 297 // escape sequences too. Because these sequences are not visible characters, | 301 // escape sequences too. Because these sequences are not visible characters, |
| 298 // we make sure they are not counted towards the limit. | 302 // we make sure they are not counted towards the limit. |
| 299 var length = withoutColors(buffer.toString()).length; | 303 var length = withoutColors(buffer.toString()).length; |
| 300 buffer.write(truncate(message, _lineLength - length)); | 304 if (truncate) message = utils.truncate(message, _lineLength - length); |
| 305 buffer.write(message); |
| 301 buffer.write(_noColor); | 306 buffer.write(_noColor); |
| 302 | 307 |
| 303 // Pad the rest of the line so that it looks erased. | 308 // Pad the rest of the line so that it looks erased. |
| 304 buffer.write(' ' * (_lineLength - withoutColors(buffer.toString()).length)); | 309 buffer.write(' ' * (_lineLength - withoutColors(buffer.toString()).length)); |
| 305 stdout.write(buffer.toString()); | 310 stdout.write(buffer.toString()); |
| 311 |
| 312 _printedNewline = false; |
| 306 return true; | 313 return true; |
| 307 } | 314 } |
| 308 | 315 |
| 309 /// Returns a representation of [duration] as `MM:SS`. | 316 /// Returns a representation of [duration] as `MM:SS`. |
| 310 String _timeString(Duration duration) { | 317 String _timeString(Duration duration) { |
| 311 return "${duration.inMinutes.toString().padLeft(2, '0')}:" | 318 return "${duration.inMinutes.toString().padLeft(2, '0')}:" |
| 312 "${(duration.inSeconds % 60).toString().padLeft(2, '0')}"; | 319 "${(duration.inSeconds % 60).toString().padLeft(2, '0')}"; |
| 313 } | 320 } |
| 314 | 321 |
| 315 /// Returns a description of [liveTest]. | 322 /// Returns a description of [liveTest]. |
| 316 /// | 323 /// |
| 317 /// This differs from the test's own description in that it may also include | 324 /// This differs from the test's own description in that it may also include |
| 318 /// the suite's name. | 325 /// the suite's name. |
| 319 String _description(LiveTest liveTest) { | 326 String _description(LiveTest liveTest) { |
| 320 var name = liveTest.test.name; | 327 var name = liveTest.test.name; |
| 321 | 328 |
| 322 if (_printPath && liveTest.suite.path != null) { | 329 if (_printPath && liveTest.suite.path != null) { |
| 323 name = "${liveTest.suite.path}: $name"; | 330 name = "${liveTest.suite.path}: $name"; |
| 324 } | 331 } |
| 325 | 332 |
| 326 if (_printPlatform && liveTest.suite.platform != null) { | 333 if (_printPlatform && liveTest.suite.platform != null) { |
| 327 name = "[${liveTest.suite.platform}] $name"; | 334 name = "[${liveTest.suite.platform}] $name"; |
| 328 } | 335 } |
| 329 | 336 |
| 330 if (liveTest.suite is LoadSuite) name = "$_bold$_gray$name$_noColor"; | 337 if (liveTest.suite is LoadSuite) name = "$_bold$_gray$name$_noColor"; |
| 331 | 338 |
| 332 return name; | 339 return name; |
| 333 } | 340 } |
| 334 } | 341 } |
| OLD | NEW |