| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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_progress; | 5 library test_progress; |
| 6 | 6 |
| 7 import "dart:async"; | 7 import "dart:async"; |
| 8 import "dart:io"; | 8 import "dart:io"; |
| 9 import "dart:io" as io; | 9 import "dart:io" as io; |
| 10 import "dart:convert" show JSON; | 10 import "dart:convert" show JSON; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 static String ESCAPE = decodeUtf8([27]); | 54 static String ESCAPE = decodeUtf8([27]); |
| 55 | 55 |
| 56 String passed(String msg) => _color(msg, GREEN); | 56 String passed(String msg) => _color(msg, GREEN); |
| 57 String failed(String msg) => _color(msg, RED); | 57 String failed(String msg) => _color(msg, RED); |
| 58 | 58 |
| 59 static String _color(String msg, int color) { | 59 static String _color(String msg, int color) { |
| 60 return "$ESCAPE[${color}m$msg$ESCAPE[0m"; | 60 return "$ESCAPE[${color}m$msg$ESCAPE[0m"; |
| 61 } | 61 } |
| 62 } | 62 } |
| 63 | 63 |
| 64 | |
| 65 List<String> _buildFailureOutput(TestCase test, | 64 List<String> _buildFailureOutput(TestCase test, |
| 66 [Formatter formatter = const Formatter()]) { | 65 [Formatter formatter = const Formatter()]) { |
| 67 | |
| 68 List<String> getLinesWithoutCarriageReturn(List<int> output) { | 66 List<String> getLinesWithoutCarriageReturn(List<int> output) { |
| 69 return decodeUtf8(output).replaceAll('\r\n', '\n') | 67 return decodeUtf8(output) |
| 70 .replaceAll('\r', '\n').split('\n'); | 68 .replaceAll('\r\n', '\n') |
| 69 .replaceAll('\r', '\n') |
| 70 .split('\n'); |
| 71 } | 71 } |
| 72 | 72 |
| 73 List<String> output = new List<String>(); | 73 List<String> output = new List<String>(); |
| 74 output.add(''); | 74 output.add(''); |
| 75 output.add(formatter.failed('FAILED: ${test.configurationString}' | 75 output.add(formatter.failed('FAILED: ${test.configurationString}' |
| 76 ' ${test.displayName}')); | 76 ' ${test.displayName}')); |
| 77 StringBuffer expected = new StringBuffer(); | 77 StringBuffer expected = new StringBuffer(); |
| 78 expected.write('Expected: '); | 78 expected.write('Expected: '); |
| 79 for (var expectation in test.expectedOutcomes) { | 79 for (var expectation in test.expectedOutcomes) { |
| 80 expected.write('$expectation '); | 80 expected.write('$expectation '); |
| 81 } | 81 } |
| 82 output.add(expected.toString()); | 82 output.add(expected.toString()); |
| 83 output.add('Actual: ${test.result}'); | 83 output.add('Actual: ${test.result}'); |
| 84 if (!test.lastCommandOutput.hasTimedOut) { | 84 if (!test.lastCommandOutput.hasTimedOut) { |
| 85 if (test.commandOutputs.length != test.commands.length | 85 if (test.commandOutputs.length != test.commands.length && |
| 86 && !test.expectCompileError) { | 86 !test.expectCompileError) { |
| 87 output.add('Unexpected compile-time error.'); | 87 output.add('Unexpected compile-time error.'); |
| 88 } else { | 88 } else { |
| 89 if (test.expectCompileError) { | 89 if (test.expectCompileError) { |
| 90 output.add('Compile-time error expected.'); | 90 output.add('Compile-time error expected.'); |
| 91 } | 91 } |
| 92 if (test.hasRuntimeError) { | 92 if (test.hasRuntimeError) { |
| 93 output.add('Runtime error expected.'); | 93 output.add('Runtime error expected.'); |
| 94 } | 94 } |
| 95 if (test.configuration['checked'] && test.isNegativeIfChecked) { | 95 if (test.configuration['checked'] && test.isNegativeIfChecked) { |
| 96 output.add('Dynamic type error expected.'); | 96 output.add('Dynamic type error expected.'); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 116 } | 116 } |
| 117 if (!commandOutput.stderr.isEmpty) { | 117 if (!commandOutput.stderr.isEmpty) { |
| 118 output.add(''); | 118 output.add(''); |
| 119 output.add('stderr:'); | 119 output.add('stderr:'); |
| 120 output.addAll(getLinesWithoutCarriageReturn(commandOutput.stderr)); | 120 output.addAll(getLinesWithoutCarriageReturn(commandOutput.stderr)); |
| 121 } | 121 } |
| 122 } | 122 } |
| 123 } | 123 } |
| 124 if (test is BrowserTestCase) { | 124 if (test is BrowserTestCase) { |
| 125 // Additional command for rerunning the steps locally after the fact. | 125 // Additional command for rerunning the steps locally after the fact. |
| 126 var command = | 126 var command = test.configuration["_servers_"].httpServerCommandline(); |
| 127 test.configuration["_servers_"].httpServerCommandline(); | |
| 128 output.add(''); | 127 output.add(''); |
| 129 output.add('To retest, run: $command'); | 128 output.add('To retest, run: $command'); |
| 130 } | 129 } |
| 131 for (var i = 0; i < test.commands.length; i++) { | 130 for (var i = 0; i < test.commands.length; i++) { |
| 132 var command = test.commands[i]; | 131 var command = test.commands[i]; |
| 133 var commandOutput = test.commandOutputs[command]; | 132 var commandOutput = test.commandOutputs[command]; |
| 134 output.add(''); | 133 output.add(''); |
| 135 output.add('Command[${command.displayName}]: $command'); | 134 output.add('Command[${command.displayName}]: $command'); |
| 136 if (commandOutput != null) { | 135 if (commandOutput != null) { |
| 137 output.add('Took ${commandOutput.time}'); | 136 output.add('Took ${commandOutput.time}'); |
| 138 } else { | 137 } else { |
| 139 output.add('Did not run'); | 138 output.add('Did not run'); |
| 140 } | 139 } |
| 141 } | 140 } |
| 142 | 141 |
| 143 var arguments = ['python', 'tools/test.py']; | 142 var arguments = ['python', 'tools/test.py']; |
| 144 arguments.addAll(test.configuration['_reproducing_arguments_']); | 143 arguments.addAll(test.configuration['_reproducing_arguments_']); |
| 145 arguments.add(test.displayName); | 144 arguments.add(test.displayName); |
| 146 var testPyCommandline = arguments.map(escapeCommandLineArgument).join(' '); | 145 var testPyCommandline = arguments.map(escapeCommandLineArgument).join(' '); |
| 147 | 146 |
| 148 output.add(''); | 147 output.add(''); |
| 149 output.add('Short reproduction command (experimental):'); | 148 output.add('Short reproduction command (experimental):'); |
| 150 output.add(" $testPyCommandline"); | 149 output.add(" $testPyCommandline"); |
| 151 return output; | 150 return output; |
| 152 } | 151 } |
| 153 | 152 |
| 154 String _buildSummaryEnd(int failedTests) { | 153 String _buildSummaryEnd(int failedTests) { |
| 155 if (failedTests == 0) { | 154 if (failedTests == 0) { |
| 156 return '\n===\n=== All tests succeeded\n===\n'; | 155 return '\n===\n=== All tests succeeded\n===\n'; |
| 157 } else { | 156 } else { |
| 158 var pluralSuffix = failedTests != 1 ? 's' : ''; | 157 var pluralSuffix = failedTests != 1 ? 's' : ''; |
| 159 return '\n===\n=== ${failedTests} test$pluralSuffix failed\n===\n'; | 158 return '\n===\n=== ${failedTests} test$pluralSuffix failed\n===\n'; |
| 160 } | 159 } |
| 161 } | 160 } |
| 162 | 161 |
| 163 | |
| 164 class EventListener { | 162 class EventListener { |
| 165 void testAdded() { } | 163 void testAdded() {} |
| 166 void done(TestCase test) { } | 164 void done(TestCase test) {} |
| 167 void allTestsKnown() { } | 165 void allTestsKnown() {} |
| 168 void allDone() { } | 166 void allDone() {} |
| 169 } | 167 } |
| 170 | 168 |
| 171 class ExitCodeSetter extends EventListener { | 169 class ExitCodeSetter extends EventListener { |
| 172 void done(TestCase test) { | 170 void done(TestCase test) { |
| 173 if (test.unexpectedOutput) { | 171 if (test.unexpectedOutput) { |
| 174 io.exitCode = 1; | 172 io.exitCode = 1; |
| 175 } | 173 } |
| 176 } | 174 } |
| 177 } | 175 } |
| 178 | 176 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 * }, | 217 * }, |
| 220 * { | 218 * { |
| 221 * name: 'ff', | 219 * name: 'ff', |
| 222 * duration: 200.2, | 220 * duration: 200.2, |
| 223 * }, | 221 * }, |
| 224 * ], | 222 * ], |
| 225 * } | 223 * } |
| 226 * }, | 224 * }, |
| 227 */ | 225 */ |
| 228 | 226 |
| 229 static final INTERESTED_CONFIGURATION_PARAMETERS = | 227 static final INTERESTED_CONFIGURATION_PARAMETERS = [ |
| 230 ['mode', 'arch', 'compiler', 'runtime', 'checked', 'host_checked', | 228 'mode', |
| 231 'minified', 'csp', 'system', 'vm_options', 'use_sdk', | 229 'arch', |
| 232 'use_repository_packages', 'use_public_packages', 'builder_tag']; | 230 'compiler', |
| 231 'runtime', |
| 232 'checked', |
| 233 'host_checked', |
| 234 'minified', |
| 235 'csp', |
| 236 'system', |
| 237 'vm_options', |
| 238 'use_sdk', |
| 239 'use_repository_packages', |
| 240 'use_public_packages', |
| 241 'builder_tag' |
| 242 ]; |
| 233 | 243 |
| 234 IOSink _sink; | 244 IOSink _sink; |
| 235 | 245 |
| 236 void done(TestCase test) { | 246 void done(TestCase test) { |
| 237 var name = test.displayName; | 247 var name = test.displayName; |
| 238 var configuration = {}; | 248 var configuration = {}; |
| 239 for (var key in INTERESTED_CONFIGURATION_PARAMETERS) { | 249 for (var key in INTERESTED_CONFIGURATION_PARAMETERS) { |
| 240 configuration[key] = test.configuration[key]; | 250 configuration[key] = test.configuration[key]; |
| 241 } | 251 } |
| 242 var outcome = '${test.lastCommandOutput.result(test)}'; | 252 var outcome = '${test.lastCommandOutput.result(test)}'; |
| 243 var expectations = | 253 var expectations = |
| 244 test.expectedOutcomes.map((expectation) => "$expectation").toList(); | 254 test.expectedOutcomes.map((expectation) => "$expectation").toList(); |
| 245 | 255 |
| 246 var commandResults = []; | 256 var commandResults = []; |
| 247 double totalDuration = 0.0; | 257 double totalDuration = 0.0; |
| 248 for (var command in test.commands) { | 258 for (var command in test.commands) { |
| 249 var output = test.commandOutputs[command]; | 259 var output = test.commandOutputs[command]; |
| 250 if (output != null) { | 260 if (output != null) { |
| 251 double duration = output.time.inMicroseconds/1000.0; | 261 double duration = output.time.inMicroseconds / 1000.0; |
| 252 totalDuration += duration; | 262 totalDuration += duration; |
| 253 commandResults.add({ | 263 commandResults |
| 254 'name': command.displayName, | 264 .add({'name': command.displayName, 'duration': duration,}); |
| 255 'duration': duration, | |
| 256 }); | |
| 257 } | 265 } |
| 258 } | 266 } |
| 259 _writeTestOutcomeRecord({ | 267 _writeTestOutcomeRecord({ |
| 260 'name' : name, | 268 'name': name, |
| 261 'configuration' : configuration, | 269 'configuration': configuration, |
| 262 'test_result' : { | 270 'test_result': { |
| 263 'outcome' : outcome, | 271 'outcome': outcome, |
| 264 'expected_outcomes' : expectations, | 272 'expected_outcomes': expectations, |
| 265 'duration' : totalDuration, | 273 'duration': totalDuration, |
| 266 'command_results' : commandResults, | 274 'command_results': commandResults, |
| 267 }, | 275 }, |
| 268 }); | 276 }); |
| 269 } | 277 } |
| 270 | 278 |
| 271 void allDone() { | 279 void allDone() { |
| 272 if (_sink != null) _sink.close(); | 280 if (_sink != null) _sink.close(); |
| 273 } | 281 } |
| 274 | 282 |
| 275 void _writeTestOutcomeRecord(Map record) { | 283 void _writeTestOutcomeRecord(Map record) { |
| 276 if (_sink == null) { | 284 if (_sink == null) { |
| 277 _sink = new File(TestUtils.testOutcomeFileName()) | 285 _sink = new File(TestUtils.testOutcomeFileName()) |
| 278 .openWrite(mode: FileMode.APPEND); | 286 .openWrite(mode: FileMode.APPEND); |
| 279 } | 287 } |
| 280 _sink.write("${JSON.encode(record)}\n"); | 288 _sink.write("${JSON.encode(record)}\n"); |
| 281 } | 289 } |
| 282 } | 290 } |
| 283 | 291 |
| 284 | |
| 285 class UnexpectedCrashDumpArchiver extends EventListener { | 292 class UnexpectedCrashDumpArchiver extends EventListener { |
| 286 void done(TestCase test) { | 293 void done(TestCase test) { |
| 287 if (test.unexpectedOutput && test.result == Expectation.CRASH) { | 294 if (test.unexpectedOutput && test.result == Expectation.CRASH) { |
| 288 var name = "core.dart.${test.lastCommandOutput.pid}"; | 295 var name = "core.dart.${test.lastCommandOutput.pid}"; |
| 289 var file = new File(name); | 296 var file = new File(name); |
| 290 if (file.existsSync()) { | 297 if (file.existsSync()) { |
| 291 // Find the binary - we assume this is the first part of the command | 298 // Find the binary - we assume this is the first part of the command |
| 292 var binName = test.lastCommandExecuted.toString().split(' ').first; | 299 var binName = test.lastCommandExecuted.toString().split(' ').first; |
| 293 var binFile = new File(binName); | 300 var binFile = new File(binName); |
| 294 var binBaseName = new Path(binName).filename; | 301 var binBaseName = new Path(binName).filename; |
| 295 if (binFile.existsSync()) { | 302 if (binFile.existsSync()) { |
| 296 var tmpPath = new Path(Directory.systemTemp.path); | 303 var tmpPath = new Path(Directory.systemTemp.path); |
| 297 var dir = new Path(TestUtils.mkdirRecursive(tmpPath, | 304 var dir = new Path(TestUtils |
| 298 new Path('coredump_${test.lastCommandOutput.pid}')).path); | 305 .mkdirRecursive( |
| 306 tmpPath, new Path('coredump_${test.lastCommandOutput.pid}')) |
| 307 .path); |
| 299 TestUtils.copyFile(new Path(name), dir.append(name)); | 308 TestUtils.copyFile(new Path(name), dir.append(name)); |
| 300 TestUtils.copyFile(new Path(binName), dir.append(binBaseName)); | 309 TestUtils.copyFile(new Path(binName), dir.append(binBaseName)); |
| 301 print("\nCopied core dump and binary for unexpected crash to: " | 310 print("\nCopied core dump and binary for unexpected crash to: " |
| 302 "$dir"); | 311 "$dir"); |
| 303 } | 312 } |
| 304 } | 313 } |
| 305 } | 314 } |
| 306 } | 315 } |
| 307 } | 316 } |
| 308 | 317 |
| 309 | |
| 310 class SummaryPrinter extends EventListener { | 318 class SummaryPrinter extends EventListener { |
| 311 final bool jsonOnly; | 319 final bool jsonOnly; |
| 312 | 320 |
| 313 SummaryPrinter({bool jsonOnly}) | 321 SummaryPrinter({bool jsonOnly}) |
| 314 : jsonOnly = (jsonOnly == null) ? false : jsonOnly; | 322 : jsonOnly = (jsonOnly == null) ? false : jsonOnly; |
| 315 | 323 |
| 316 void allTestsKnown() { | 324 void allTestsKnown() { |
| 317 if (jsonOnly) { | 325 if (jsonOnly) { |
| 318 print("JSON:"); | 326 print("JSON:"); |
| 319 print(JSON.encode(summaryReport.values)); | 327 print(JSON.encode(summaryReport.values)); |
| 320 } else { | 328 } else { |
| 321 summaryReport.printReport(); | 329 summaryReport.printReport(); |
| 322 } | 330 } |
| 323 } | 331 } |
| 324 } | 332 } |
| 325 | 333 |
| 326 | |
| 327 class TimingPrinter extends EventListener { | 334 class TimingPrinter extends EventListener { |
| 328 final _command2testCases = new Map<Command, List<TestCase>>(); | 335 final _command2testCases = new Map<Command, List<TestCase>>(); |
| 329 final _commandOutputs = new Set<CommandOutput>(); | 336 final _commandOutputs = new Set<CommandOutput>(); |
| 330 DateTime _startTime; | 337 DateTime _startTime; |
| 331 | 338 |
| 332 TimingPrinter(this._startTime); | 339 TimingPrinter(this._startTime); |
| 333 | 340 |
| 334 void done(TestCase testCase) { | 341 void done(TestCase testCase) { |
| 335 for (var commandOutput in testCase.commandOutputs.values) { | 342 for (var commandOutput in testCase.commandOutputs.values) { |
| 336 var command = commandOutput.command; | 343 var command = commandOutput.command; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 350 for (int i = 0; i < 20 && i < outputs.length; i++) { | 357 for (int i = 0; i < 20 && i < outputs.length; i++) { |
| 351 var commandOutput = outputs[i]; | 358 var commandOutput = outputs[i]; |
| 352 var command = commandOutput.command; | 359 var command = commandOutput.command; |
| 353 var testCases = _command2testCases[command]; | 360 var testCases = _command2testCases[command]; |
| 354 | 361 |
| 355 var testCasesDescription = testCases.map((testCase) { | 362 var testCasesDescription = testCases.map((testCase) { |
| 356 return "${testCase.configurationString}/${testCase.displayName}"; | 363 return "${testCase.configurationString}/${testCase.displayName}"; |
| 357 }).join(', '); | 364 }).join(', '); |
| 358 | 365 |
| 359 print('${commandOutput.time} - ' | 366 print('${commandOutput.time} - ' |
| 360 '${command.displayName} - ' | 367 '${command.displayName} - ' |
| 361 '$testCasesDescription'); | 368 '$testCasesDescription'); |
| 362 } | 369 } |
| 363 } | 370 } |
| 364 } | 371 } |
| 365 | 372 |
| 366 class StatusFileUpdatePrinter extends EventListener { | 373 class StatusFileUpdatePrinter extends EventListener { |
| 367 var statusToConfigs = new Map<String, List<String>>(); | 374 var statusToConfigs = new Map<String, List<String>>(); |
| 368 var _failureSummary = <String>[]; | 375 var _failureSummary = <String>[]; |
| 369 | 376 |
| 370 void done(TestCase test) { | 377 void done(TestCase test) { |
| 371 if (test.unexpectedOutput) { | 378 if (test.unexpectedOutput) { |
| 372 _printFailureOutput(test); | 379 _printFailureOutput(test); |
| 373 } | 380 } |
| 374 } | 381 } |
| 375 | 382 |
| 376 void allDone() { | 383 void allDone() { |
| 377 _printFailureSummary(); | 384 _printFailureSummary(); |
| 378 } | 385 } |
| 379 | 386 |
| 380 | |
| 381 void _printFailureOutput(TestCase test) { | 387 void _printFailureOutput(TestCase test) { |
| 382 String status = '${test.displayName}: ${test.result}'; | 388 String status = '${test.displayName}: ${test.result}'; |
| 383 List<String> configs = | 389 List<String> configs = |
| 384 statusToConfigs.putIfAbsent(status, () => <String>[]); | 390 statusToConfigs.putIfAbsent(status, () => <String>[]); |
| 385 configs.add(test.configurationString); | 391 configs.add(test.configurationString); |
| 386 if (test.lastCommandOutput.hasTimedOut) { | 392 if (test.lastCommandOutput.hasTimedOut) { |
| 387 print('\n${test.displayName} timed out on ${test.configurationString}'); | 393 print('\n${test.displayName} timed out on ${test.configurationString}'); |
| 388 } | 394 } |
| 389 } | 395 } |
| 390 | 396 |
| 391 String _extractRuntime(String configuration) { | 397 String _extractRuntime(String configuration) { |
| 392 // Extract runtime from a configuration, for example, | 398 // Extract runtime from a configuration, for example, |
| 393 // 'none-vm-checked release_ia32'. | 399 // 'none-vm-checked release_ia32'. |
| 394 List<String> runtime = configuration.split(' ')[0].split('-'); | 400 List<String> runtime = configuration.split(' ')[0].split('-'); |
| 395 return '${runtime[0]}-${runtime[1]}'; | 401 return '${runtime[0]}-${runtime[1]}'; |
| 396 } | 402 } |
| 397 | 403 |
| 398 void _printFailureSummary() { | 404 void _printFailureSummary() { |
| 399 var groupedStatuses = new Map<String, List<String>>(); | 405 var groupedStatuses = new Map<String, List<String>>(); |
| 400 statusToConfigs.forEach((String status, List<String> configs) { | 406 statusToConfigs.forEach((String status, List<String> configs) { |
| 401 var runtimeToConfiguration = new Map<String, List<String>>(); | 407 var runtimeToConfiguration = new Map<String, List<String>>(); |
| 402 for (String config in configs) { | 408 for (String config in configs) { |
| 403 String runtime = _extractRuntime(config); | 409 String runtime = _extractRuntime(config); |
| 404 var runtimeConfigs = | 410 var runtimeConfigs = |
| 405 runtimeToConfiguration.putIfAbsent(runtime, () => <String>[]); | 411 runtimeToConfiguration.putIfAbsent(runtime, () => <String>[]); |
| 406 runtimeConfigs.add(config); | 412 runtimeConfigs.add(config); |
| 407 } | 413 } |
| 408 runtimeToConfiguration.forEach((String runtime, | 414 runtimeToConfiguration |
| 409 List<String> runtimeConfigs) { | 415 .forEach((String runtime, List<String> runtimeConfigs) { |
| 410 runtimeConfigs.sort((a, b) => a.compareTo(b)); | 416 runtimeConfigs.sort((a, b) => a.compareTo(b)); |
| 411 List<String> statuses = | 417 List<String> statuses = groupedStatuses.putIfAbsent( |
| 412 groupedStatuses.putIfAbsent('$runtime: $runtimeConfigs', | 418 '$runtime: $runtimeConfigs', () => <String>[]); |
| 413 () => <String>[]); | |
| 414 statuses.add(status); | 419 statuses.add(status); |
| 415 }); | 420 }); |
| 416 }); | 421 }); |
| 417 | 422 |
| 418 print('\n\nNecessary status file updates:'); | 423 print('\n\nNecessary status file updates:'); |
| 419 groupedStatuses.forEach((String config, List<String> statuses) { | 424 groupedStatuses.forEach((String config, List<String> statuses) { |
| 420 print(''); | 425 print(''); |
| 421 print('$config:'); | 426 print('$config:'); |
| 422 statuses.sort((a, b) => a.compareTo(b)); | 427 statuses.sort((a, b) => a.compareTo(b)); |
| 423 for (String status in statuses) { | 428 for (String status in statuses) { |
| 424 print(' $status'); | 429 print(' $status'); |
| 425 } | 430 } |
| 426 }); | 431 }); |
| 427 } | 432 } |
| 428 } | 433 } |
| 429 | 434 |
| 430 class SkippedCompilationsPrinter extends EventListener { | 435 class SkippedCompilationsPrinter extends EventListener { |
| 431 int _skippedCompilations = 0; | 436 int _skippedCompilations = 0; |
| 432 | 437 |
| 433 void done(TestCase test) { | 438 void done(TestCase test) { |
| 434 for (var commandOutput in test.commandOutputs.values) { | 439 for (var commandOutput in test.commandOutputs.values) { |
| 435 if (commandOutput.compilationSkipped) | 440 if (commandOutput.compilationSkipped) _skippedCompilations++; |
| 436 _skippedCompilations++; | |
| 437 } | 441 } |
| 438 } | 442 } |
| 439 | 443 |
| 440 void allDone() { | 444 void allDone() { |
| 441 if (_skippedCompilations > 0) { | 445 if (_skippedCompilations > 0) { |
| 442 print('\n$_skippedCompilations compilations were skipped because ' | 446 print('\n$_skippedCompilations compilations were skipped because ' |
| 443 'the previous output was already up to date\n'); | 447 'the previous output was already up to date\n'); |
| 444 } | 448 } |
| 445 } | 449 } |
| 446 } | 450 } |
| 447 | 451 |
| 448 class LeftOverTempDirPrinter extends EventListener { | 452 class LeftOverTempDirPrinter extends EventListener { |
| 449 final MIN_NUMBER_OF_TEMP_DIRS = 50; | 453 final MIN_NUMBER_OF_TEMP_DIRS = 50; |
| 450 | 454 |
| 451 static RegExp _getTemporaryDirectoryRegexp() { | 455 static RegExp _getTemporaryDirectoryRegexp() { |
| 452 // These are the patterns of temporary directory names created by | 456 // These are the patterns of temporary directory names created by |
| 453 // 'Directory.systemTemp.createTemp()' on linux/macos and windows. | 457 // 'Directory.systemTemp.createTemp()' on linux/macos and windows. |
| 454 if (['macos', 'linux'].contains(Platform.operatingSystem)) { | 458 if (['macos', 'linux'].contains(Platform.operatingSystem)) { |
| 455 return new RegExp(r'^temp_dir1_......$'); | 459 return new RegExp(r'^temp_dir1_......$'); |
| 456 } else { | 460 } else { |
| 457 return new RegExp(r'tempdir-........-....-....-....-............$'); | 461 return new RegExp(r'tempdir-........-....-....-....-............$'); |
| 458 } | 462 } |
| 459 } | 463 } |
| 460 | 464 |
| 461 static Stream<Directory> getLeftOverTemporaryDirectories() { | 465 static Stream<Directory> getLeftOverTemporaryDirectories() { |
| 462 var regExp = _getTemporaryDirectoryRegexp(); | 466 var regExp = _getTemporaryDirectoryRegexp(); |
| 463 return Directory.systemTemp.list().where( | 467 return Directory.systemTemp.list().where((FileSystemEntity fse) { |
| 464 (FileSystemEntity fse) { | 468 if (fse is Directory) { |
| 465 if (fse is Directory) { | 469 if (regExp.hasMatch(new Path(fse.path).filename)) { |
| 466 if (regExp.hasMatch(new Path(fse.path).filename)) { | 470 return true; |
| 467 return true; | 471 } |
| 468 } | 472 } |
| 469 } | 473 return false; |
| 470 return false; | 474 }); |
| 471 }); | |
| 472 } | 475 } |
| 473 | 476 |
| 474 void allDone() { | 477 void allDone() { |
| 475 getLeftOverTemporaryDirectories().length.then((int count) { | 478 getLeftOverTemporaryDirectories().length.then((int count) { |
| 476 if (count > MIN_NUMBER_OF_TEMP_DIRS) { | 479 if (count > MIN_NUMBER_OF_TEMP_DIRS) { |
| 477 DebugLogger.warning("There are ${count} directories " | 480 DebugLogger.warning("There are ${count} directories " |
| 478 "in the system tempdir " | 481 "in the system tempdir " |
| 479 "('${Directory.systemTemp.path}')! " | 482 "('${Directory.systemTemp.path}')! " |
| 480 "Maybe left over directories?\n"); | 483 "Maybe left over directories?\n"); |
| 481 } | 484 } |
| 482 }).catchError((error) { | 485 }).catchError((error) { |
| 483 DebugLogger.warning("Could not list temp directories, got: $error"); | 486 DebugLogger.warning("Could not list temp directories, got: $error"); |
| 484 }); | 487 }); |
| 485 } | 488 } |
| 486 } | 489 } |
| 487 | 490 |
| 488 class LineProgressIndicator extends EventListener { | 491 class LineProgressIndicator extends EventListener { |
| 489 void done(TestCase test) { | 492 void done(TestCase test) { |
| 490 var status = 'pass'; | 493 var status = 'pass'; |
| 491 if (test.unexpectedOutput) { | 494 if (test.unexpectedOutput) { |
| 492 status = 'fail'; | 495 status = 'fail'; |
| 493 } | 496 } |
| 494 print('Done ${test.configurationString} ${test.displayName}: $status'); | 497 print('Done ${test.configurationString} ${test.displayName}: $status'); |
| 495 } | 498 } |
| 496 } | 499 } |
| 497 | 500 |
| 498 | |
| 499 class TestFailurePrinter extends EventListener { | 501 class TestFailurePrinter extends EventListener { |
| 500 bool _printSummary; | 502 bool _printSummary; |
| 501 var _formatter; | 503 var _formatter; |
| 502 var _failureSummary = <String>[]; | 504 var _failureSummary = <String>[]; |
| 503 var _failedTests= 0; | 505 var _failedTests = 0; |
| 504 | 506 |
| 505 TestFailurePrinter(this._printSummary, | 507 TestFailurePrinter(this._printSummary, [this._formatter = const Formatter()]); |
| 506 [this._formatter = const Formatter()]); | |
| 507 | 508 |
| 508 void done(TestCase test) { | 509 void done(TestCase test) { |
| 509 if (test.unexpectedOutput) { | 510 if (test.unexpectedOutput) { |
| 510 _failedTests++; | 511 _failedTests++; |
| 511 var lines = _buildFailureOutput(test, _formatter); | 512 var lines = _buildFailureOutput(test, _formatter); |
| 512 for (var line in lines) { | 513 for (var line in lines) { |
| 513 print(line); | 514 print(line); |
| 514 } | 515 } |
| 515 print(''); | 516 print(''); |
| 516 if (_printSummary) { | 517 if (_printSummary) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 531 | 532 |
| 532 print(_buildSummaryEnd(_failedTests)); | 533 print(_buildSummaryEnd(_failedTests)); |
| 533 } | 534 } |
| 534 } | 535 } |
| 535 } | 536 } |
| 536 } | 537 } |
| 537 | 538 |
| 538 class ProgressIndicator extends EventListener { | 539 class ProgressIndicator extends EventListener { |
| 539 ProgressIndicator(this._startTime); | 540 ProgressIndicator(this._startTime); |
| 540 | 541 |
| 541 | 542 void testAdded() { |
| 542 void testAdded() { _foundTests++; } | 543 _foundTests++; |
| 544 } |
| 543 | 545 |
| 544 void done(TestCase test) { | 546 void done(TestCase test) { |
| 545 if (test.unexpectedOutput) { | 547 if (test.unexpectedOutput) { |
| 546 _failedTests++; | 548 _failedTests++; |
| 547 } else { | 549 } else { |
| 548 _passedTests++; | 550 _passedTests++; |
| 549 } | 551 } |
| 550 _printDoneProgress(test); | 552 _printDoneProgress(test); |
| 551 } | 553 } |
| 552 | 554 |
| 553 void allTestsKnown() { | 555 void allTestsKnown() { |
| 554 _allTestsKnown = true; | 556 _allTestsKnown = true; |
| 555 } | 557 } |
| 556 | 558 |
| 557 void _printDoneProgress(TestCase test) {} | 559 void _printDoneProgress(TestCase test) {} |
| 558 | 560 |
| 559 int _completedTests() => _passedTests + _failedTests; | 561 int _completedTests() => _passedTests + _failedTests; |
| 560 | 562 |
| 561 int _foundTests = 0; | 563 int _foundTests = 0; |
| 562 int _passedTests = 0; | 564 int _passedTests = 0; |
| 563 int _failedTests = 0; | 565 int _failedTests = 0; |
| 564 bool _allTestsKnown = false; | 566 bool _allTestsKnown = false; |
| 565 DateTime _startTime; | 567 DateTime _startTime; |
| 566 } | 568 } |
| 567 | 569 |
| 568 abstract class CompactIndicator extends ProgressIndicator { | 570 abstract class CompactIndicator extends ProgressIndicator { |
| 569 CompactIndicator(DateTime startTime) | 571 CompactIndicator(DateTime startTime) : super(startTime); |
| 570 : super(startTime); | |
| 571 | 572 |
| 572 void allDone() { | 573 void allDone() { |
| 573 if (_failedTests > 0) { | 574 if (_failedTests > 0) { |
| 574 // We may have printed many failure logs, so reprint the summary data. | 575 // We may have printed many failure logs, so reprint the summary data. |
| 575 _printProgress(); | 576 _printProgress(); |
| 576 } | 577 } |
| 577 print(''); | 578 print(''); |
| 578 } | 579 } |
| 579 | 580 |
| 580 void _printDoneProgress(TestCase test) => _printProgress(); | 581 void _printDoneProgress(TestCase test) => _printProgress(); |
| 581 | 582 |
| 582 void _printProgress(); | 583 void _printProgress(); |
| 583 } | 584 } |
| 584 | 585 |
| 585 | |
| 586 class CompactProgressIndicator extends CompactIndicator { | 586 class CompactProgressIndicator extends CompactIndicator { |
| 587 Formatter _formatter; | 587 Formatter _formatter; |
| 588 | 588 |
| 589 CompactProgressIndicator(DateTime startTime, this._formatter) | 589 CompactProgressIndicator(DateTime startTime, this._formatter) |
| 590 : super(startTime); | 590 : super(startTime); |
| 591 | 591 |
| 592 void _printProgress() { | 592 void _printProgress() { |
| 593 var percent = ((_completedTests() / _foundTests) * 100).toInt().toString(); | 593 var percent = ((_completedTests() / _foundTests) * 100).toInt().toString(); |
| 594 var progressPadded = _pad(_allTestsKnown ? percent : '--', 3); | 594 var progressPadded = _pad(_allTestsKnown ? percent : '--', 3); |
| 595 var passedPadded = _pad(_passedTests.toString(), 5); | 595 var passedPadded = _pad(_passedTests.toString(), 5); |
| 596 var failedPadded = _pad(_failedTests.toString(), 5); | 596 var failedPadded = _pad(_failedTests.toString(), 5); |
| 597 Duration d = (new DateTime.now()).difference(_startTime); | 597 Duration d = (new DateTime.now()).difference(_startTime); |
| 598 var progressLine = | 598 var progressLine = '\r[${_timeString(d)} | $progressPadded% | ' |
| 599 '\r[${_timeString(d)} | $progressPadded% | ' | |
| 600 '+${_formatter.passed(passedPadded)} | ' | 599 '+${_formatter.passed(passedPadded)} | ' |
| 601 '-${_formatter.failed(failedPadded)}]'; | 600 '-${_formatter.failed(failedPadded)}]'; |
| 602 stdout.write(progressLine); | 601 stdout.write(progressLine); |
| 603 } | 602 } |
| 604 } | 603 } |
| 605 | 604 |
| 606 | |
| 607 class VerboseProgressIndicator extends ProgressIndicator { | 605 class VerboseProgressIndicator extends ProgressIndicator { |
| 608 VerboseProgressIndicator(DateTime startTime) | 606 VerboseProgressIndicator(DateTime startTime) : super(startTime); |
| 609 : super(startTime); | |
| 610 | 607 |
| 611 void _printDoneProgress(TestCase test) { | 608 void _printDoneProgress(TestCase test) { |
| 612 var status = 'pass'; | 609 var status = 'pass'; |
| 613 if (test.unexpectedOutput) { | 610 if (test.unexpectedOutput) { |
| 614 status = 'fail'; | 611 status = 'fail'; |
| 615 } | 612 } |
| 616 print('Done ${test.configurationString} ${test.displayName}: $status'); | 613 print('Done ${test.configurationString} ${test.displayName}: $status'); |
| 617 } | 614 } |
| 618 } | 615 } |
| 619 | 616 |
| 620 | |
| 621 class BuildbotProgressIndicator extends ProgressIndicator { | 617 class BuildbotProgressIndicator extends ProgressIndicator { |
| 622 static String stepName; | 618 static String stepName; |
| 623 var _failureSummary = <String>[]; | 619 var _failureSummary = <String>[]; |
| 624 | 620 |
| 625 BuildbotProgressIndicator(DateTime startTime) : super(startTime); | 621 BuildbotProgressIndicator(DateTime startTime) : super(startTime); |
| 626 | 622 |
| 627 void done(TestCase test) { | 623 void done(TestCase test) { |
| 628 super.done(test); | 624 super.done(test); |
| 629 if (test.unexpectedOutput) { | 625 if (test.unexpectedOutput) { |
| 630 _failureSummary.addAll(_buildFailureOutput(test)); | 626 _failureSummary.addAll(_buildFailureOutput(test)); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 650 } | 646 } |
| 651 for (String line in _failureSummary) { | 647 for (String line in _failureSummary) { |
| 652 print(line); | 648 print(line); |
| 653 } | 649 } |
| 654 print(''); | 650 print(''); |
| 655 } | 651 } |
| 656 print(_buildSummaryEnd(_failedTests)); | 652 print(_buildSummaryEnd(_failedTests)); |
| 657 } | 653 } |
| 658 } | 654 } |
| 659 | 655 |
| 660 | 656 EventListener progressIndicatorFromName( |
| 661 EventListener progressIndicatorFromName(String name, | 657 String name, DateTime startTime, Formatter formatter) { |
| 662 DateTime startTime, | |
| 663 Formatter formatter) { | |
| 664 switch (name) { | 658 switch (name) { |
| 665 case 'compact': | 659 case 'compact': |
| 666 return new CompactProgressIndicator(startTime, formatter); | 660 return new CompactProgressIndicator(startTime, formatter); |
| 667 case 'line': | 661 case 'line': |
| 668 return new LineProgressIndicator(); | 662 return new LineProgressIndicator(); |
| 669 case 'verbose': | 663 case 'verbose': |
| 670 return new VerboseProgressIndicator(startTime); | 664 return new VerboseProgressIndicator(startTime); |
| 671 case 'status': | 665 case 'status': |
| 672 return new ProgressIndicator(startTime); | 666 return new ProgressIndicator(startTime); |
| 673 case 'buildbot': | 667 case 'buildbot': |
| 674 return new BuildbotProgressIndicator(startTime); | 668 return new BuildbotProgressIndicator(startTime); |
| 675 default: | 669 default: |
| 676 assert(false); | 670 assert(false); |
| 677 break; | 671 break; |
| 678 } | 672 } |
| 679 } | 673 } |
| OLD | NEW |