| 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.no_io_compact; | 5 library test.runner.reporter.no_io_compact; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import '../../backend/live_test.dart'; | 9 import '../../backend/live_test.dart'; |
| 10 import '../../backend/state.dart'; | 10 import '../../backend/state.dart'; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 | 48 |
| 49 /// Whether multiple test files are being run. | 49 /// Whether multiple test files are being run. |
| 50 final bool _multiplePaths; | 50 final bool _multiplePaths; |
| 51 | 51 |
| 52 /// Whether tests are being run on multiple platforms. | 52 /// Whether tests are being run on multiple platforms. |
| 53 final bool _multiplePlatforms; | 53 final bool _multiplePlatforms; |
| 54 | 54 |
| 55 /// A stopwatch that tracks the duration of the full run. | 55 /// A stopwatch that tracks the duration of the full run. |
| 56 final _stopwatch = new Stopwatch(); | 56 final _stopwatch = new Stopwatch(); |
| 57 | 57 |
| 58 /// The set of tests that have completed and been marked as passing. | |
| 59 final _passed = new Set<LiveTest>(); | |
| 60 | |
| 61 /// The set of tests that have completed and been marked as skipped. | |
| 62 final _skipped = new Set<LiveTest>(); | |
| 63 | |
| 64 /// The set of tests that have completed and been marked as failing or error. | |
| 65 final _failed = new Set<LiveTest>(); | |
| 66 | |
| 67 /// The set of tests that are still running. | |
| 68 final _active = new List<LiveTest>(); | |
| 69 | |
| 70 /// Whether [close] has been called. | 58 /// Whether [close] has been called. |
| 71 bool _closed = false; | 59 bool _closed = false; |
| 72 | 60 |
| 73 /// The size of [_passed] last time a progress notification was printed. | 61 /// The size of `_engine.passed` last time a progress notification was |
| 62 /// printed. |
| 74 int _lastProgressPassed; | 63 int _lastProgressPassed; |
| 75 | 64 |
| 76 /// The size of [_skipped] last time a progress notification was printed. | 65 /// The size of `_engine.skipped` last time a progress notification was |
| 66 /// printed. |
| 77 int _lastProgressSkipped; | 67 int _lastProgressSkipped; |
| 78 | 68 |
| 79 /// The size of [_failed] last time a progress notification was printed. | 69 /// The size of `_engine.failed` last time a progress notification was |
| 70 /// printed. |
| 80 int _lastProgressFailed; | 71 int _lastProgressFailed; |
| 81 | 72 |
| 82 /// The message printed for the last progress notification. | 73 /// The message printed for the last progress notification. |
| 83 String _lastProgressMessage; | 74 String _lastProgressMessage; |
| 84 | 75 |
| 85 /// Creates a [NoIoCompactReporter] that will run all tests in [suites]. | 76 /// Creates a [NoIoCompactReporter] that will run all tests in [suites]. |
| 86 /// | 77 /// |
| 87 /// [concurrency] controls how many suites are run at once. If [color] is | 78 /// [concurrency] controls how many suites are run at once. If [color] is |
| 88 /// `true`, this will use terminal colors; if it's `false`, it won't. If | 79 /// `true`, this will use terminal colors; if it's `false`, it won't. If |
| 89 /// [verboseTrace] is `true`, this will print core library frames. | 80 /// [verboseTrace] is `true`, this will print core library frames. |
| 90 ExpandedReporter(Iterable<Suite> suites, {int concurrency, bool color: true, | 81 ExpandedReporter(Iterable<Suite> suites, {int concurrency, bool color: true, |
| 91 bool verboseTrace: false}) | 82 bool verboseTrace: false}) |
| 92 : _multiplePaths = suites.map((suite) => suite.path).toSet().length > 1, | 83 : _multiplePaths = suites.map((suite) => suite.path).toSet().length > 1, |
| 93 _multiplePlatforms = | 84 _multiplePlatforms = |
| 94 suites.map((suite) => suite.platform).toSet().length > 1, | 85 suites.map((suite) => suite.platform).toSet().length > 1, |
| 95 _engine = new Engine(suites, concurrency: concurrency), | 86 _engine = new Engine(suites, concurrency: concurrency), |
| 96 _verboseTrace = verboseTrace, | 87 _verboseTrace = verboseTrace, |
| 97 _green = color ? '\u001b[32m' : '', | 88 _green = color ? '\u001b[32m' : '', |
| 98 _red = color ? '\u001b[31m' : '', | 89 _red = color ? '\u001b[31m' : '', |
| 99 _yellow = color ? '\u001b[33m' : '', | 90 _yellow = color ? '\u001b[33m' : '', |
| 100 _noColor = color ? '\u001b[0m' : '' { | 91 _noColor = color ? '\u001b[0m' : '' { |
| 101 _engine.onTestStarted.listen((liveTest) { | 92 _engine.onTestStarted.listen((liveTest) { |
| 102 if (_active.isEmpty) _progressLine(_description(liveTest)); | 93 // If this is the first test to start, print a progress line so the user |
| 103 _active.add(liveTest); | 94 // knows what's running. |
| 95 if (_engine.active.length == 1) _progressLine(_description(liveTest)); |
| 104 | 96 |
| 105 liveTest.onStateChange.listen((state) { | 97 liveTest.onStateChange.listen((state) { |
| 106 if (state.status != Status.complete) return; | 98 if (state.status != Status.complete) return; |
| 107 _active.remove(liveTest); | |
| 108 | |
| 109 if (state.result != Result.success) { | |
| 110 _passed.remove(liveTest); | |
| 111 _failed.add(liveTest); | |
| 112 } else if (liveTest.test.metadata.skip) { | |
| 113 _skipped.add(liveTest); | |
| 114 } else { | |
| 115 _passed.add(liveTest); | |
| 116 } | |
| 117 | 99 |
| 118 if (liveTest.test.metadata.skip && | 100 if (liveTest.test.metadata.skip && |
| 119 liveTest.test.metadata.skipReason != null) { | 101 liveTest.test.metadata.skipReason != null) { |
| 120 _progressLine(_description(liveTest)); | 102 _progressLine(_description(liveTest)); |
| 121 print(indent('${_yellow}Skip: ${liveTest.test.metadata.skipReason}' | 103 print(indent('${_yellow}Skip: ${liveTest.test.metadata.skipReason}' |
| 122 '$_noColor')); | 104 '$_noColor')); |
| 123 } else if (_active.isNotEmpty) { | 105 } else if (_engine.active.isNotEmpty) { |
| 124 // If any tests are running, display the name of the oldest active | 106 // If any tests are running, display the name of the oldest active |
| 125 // test. | 107 // test. |
| 126 _progressLine(_description(_active.first)); | 108 _progressLine(_description(_engine.active.first)); |
| 127 } | 109 } |
| 128 }); | 110 }); |
| 129 | 111 |
| 130 liveTest.onError.listen((error) { | 112 liveTest.onError.listen((error) { |
| 131 if (liveTest.state.status != Status.complete) return; | 113 if (liveTest.state.status != Status.complete) return; |
| 132 | 114 |
| 133 _progressLine(_description(liveTest)); | 115 _progressLine(_description(liveTest)); |
| 134 print(indent(error.error.toString())); | 116 print(indent(error.error.toString())); |
| 135 var chain = terseChain(error.stackTrace, verbose: _verboseTrace); | 117 var chain = terseChain(error.stackTrace, verbose: _verboseTrace); |
| 136 print(indent(chain.toString())); | 118 print(indent(chain.toString())); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 157 print("No tests ran."); | 139 print("No tests ran."); |
| 158 return true; | 140 return true; |
| 159 } | 141 } |
| 160 | 142 |
| 161 _stopwatch.start(); | 143 _stopwatch.start(); |
| 162 var success = await _engine.run(); | 144 var success = await _engine.run(); |
| 163 if (_closed) return false; | 145 if (_closed) return false; |
| 164 | 146 |
| 165 if (!success) { | 147 if (!success) { |
| 166 _progressLine('Some tests failed.', color: _red); | 148 _progressLine('Some tests failed.', color: _red); |
| 167 } else if (_passed.isEmpty) { | 149 } else if (_engine.passed.isEmpty) { |
| 168 _progressLine("All tests skipped."); | 150 _progressLine("All tests skipped."); |
| 169 } else { | 151 } else { |
| 170 _progressLine("All tests passed!"); | 152 _progressLine("All tests passed!"); |
| 171 } | 153 } |
| 172 | 154 |
| 173 return success; | 155 return success; |
| 174 } | 156 } |
| 175 | 157 |
| 176 /// Signals that the caller is done with any test output and the reporter | 158 /// Signals that the caller is done with any test output and the reporter |
| 177 /// should release any resources it has allocated. | 159 /// should release any resources it has allocated. |
| 178 Future close() => _engine.close(); | 160 Future close() => _engine.close(); |
| 179 | 161 |
| 180 /// Prints a line representing the current state of the tests. | 162 /// Prints a line representing the current state of the tests. |
| 181 /// | 163 /// |
| 182 /// [message] goes after the progress report, and may be truncated to fit the | 164 /// [message] goes after the progress report, and may be truncated to fit the |
| 183 /// entire line within [_lineLength]. If [color] is passed, it's used as the | 165 /// entire line within [_lineLength]. If [color] is passed, it's used as the |
| 184 /// color for [message]. | 166 /// color for [message]. |
| 185 void _progressLine(String message, {String color}) { | 167 void _progressLine(String message, {String color}) { |
| 186 // Print nothing if nothing has changed since the last progress line. | 168 // Print nothing if nothing has changed since the last progress line. |
| 187 if (_passed.length == _lastProgressPassed && | 169 if (_engine.passed.length == _lastProgressPassed && |
| 188 _skipped.length == _lastProgressSkipped && | 170 _engine.skipped.length == _lastProgressSkipped && |
| 189 _failed.length == _lastProgressFailed && | 171 _engine.failed.length == _lastProgressFailed && |
| 190 message == _lastProgressMessage) { | 172 message == _lastProgressMessage) { |
| 191 return; | 173 return; |
| 192 } | 174 } |
| 193 | 175 |
| 194 _lastProgressPassed = _passed.length; | 176 _lastProgressPassed = _engine.passed.length; |
| 195 _lastProgressSkipped = _skipped.length; | 177 _lastProgressSkipped = _engine.skipped.length; |
| 196 _lastProgressFailed = _failed.length; | 178 _lastProgressFailed = _engine.failed.length; |
| 197 _lastProgressMessage = message; | 179 _lastProgressMessage = message; |
| 198 | 180 |
| 199 if (color == null) color = ''; | 181 if (color == null) color = ''; |
| 200 var duration = _stopwatch.elapsed; | 182 var duration = _stopwatch.elapsed; |
| 201 var buffer = new StringBuffer(); | 183 var buffer = new StringBuffer(); |
| 202 | 184 |
| 203 // \r moves back to the beginning of the current line. | 185 // \r moves back to the beginning of the current line. |
| 204 buffer.write('${_timeString(duration)} '); | 186 buffer.write('${_timeString(duration)} '); |
| 205 buffer.write(_green); | 187 buffer.write(_green); |
| 206 buffer.write('+'); | 188 buffer.write('+'); |
| 207 buffer.write(_passed.length); | 189 buffer.write(_engine.passed.length); |
| 208 buffer.write(_noColor); | 190 buffer.write(_noColor); |
| 209 | 191 |
| 210 if (_skipped.isNotEmpty) { | 192 if (_engine.skipped.isNotEmpty) { |
| 211 buffer.write(_yellow); | 193 buffer.write(_yellow); |
| 212 buffer.write(' ~'); | 194 buffer.write(' ~'); |
| 213 buffer.write(_skipped.length); | 195 buffer.write(_engine.skipped.length); |
| 214 buffer.write(_noColor); | 196 buffer.write(_noColor); |
| 215 } | 197 } |
| 216 | 198 |
| 217 if (_failed.isNotEmpty) { | 199 if (_engine.failed.isNotEmpty) { |
| 218 buffer.write(_red); | 200 buffer.write(_red); |
| 219 buffer.write(' -'); | 201 buffer.write(' -'); |
| 220 buffer.write(_failed.length); | 202 buffer.write(_engine.failed.length); |
| 221 buffer.write(_noColor); | 203 buffer.write(_noColor); |
| 222 } | 204 } |
| 223 | 205 |
| 224 buffer.write(': '); | 206 buffer.write(': '); |
| 225 buffer.write(color); | 207 buffer.write(color); |
| 226 | 208 |
| 227 // Ensure the line fits within [_lineLength]. [buffer] includes the color | 209 // Ensure the line fits within [_lineLength]. [buffer] includes the color |
| 228 // escape sequences too. Because these sequences are not visible characters, | 210 // escape sequences too. Because these sequences are not visible characters, |
| 229 // we make sure they are not counted towards the limit. | 211 // we make sure they are not counted towards the limit. |
| 230 var nonVisible = 1 + _green.length + _noColor.length + color.length + | 212 var nonVisible = 1 + _green.length + _noColor.length + color.length + |
| 231 (_failed.isEmpty ? 0 : _red.length + _noColor.length); | 213 (_engine.failed.isEmpty ? 0 : _red.length + _noColor.length); |
| 232 var length = buffer.length - nonVisible; | 214 var length = buffer.length - nonVisible; |
| 233 buffer.write(truncate(message, _lineLength - length)); | 215 buffer.write(truncate(message, _lineLength - length)); |
| 234 buffer.write(_noColor); | 216 buffer.write(_noColor); |
| 235 | 217 |
| 236 print(buffer.toString()); | 218 print(buffer.toString()); |
| 237 } | 219 } |
| 238 | 220 |
| 239 /// Returns a representation of [duration] as `MM:SS`. | 221 /// Returns a representation of [duration] as `MM:SS`. |
| 240 String _timeString(Duration duration) { | 222 String _timeString(Duration duration) { |
| 241 return "${duration.inMinutes.toString().padLeft(2, '0')}:" | 223 return "${duration.inMinutes.toString().padLeft(2, '0')}:" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 253 name = "${liveTest.suite.path}: $name"; | 235 name = "${liveTest.suite.path}: $name"; |
| 254 } | 236 } |
| 255 | 237 |
| 256 if (_multiplePlatforms && liveTest.suite.platform != null) { | 238 if (_multiplePlatforms && liveTest.suite.platform != null) { |
| 257 name = "[${liveTest.suite.platform}] $name"; | 239 name = "[${liveTest.suite.platform}] $name"; |
| 258 } | 240 } |
| 259 | 241 |
| 260 return name; | 242 return name; |
| 261 } | 243 } |
| 262 } | 244 } |
| OLD | NEW |