Chromium Code Reviews| Index: utils/tests/pub/command_line_config.dart |
| diff --git a/utils/tests/pub/command_line_config.dart b/utils/tests/pub/command_line_config.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..48aecfa1961ed58f7d46c11ea5c6f7888bb73c29 |
| --- /dev/null |
| +++ b/utils/tests/pub/command_line_config.dart |
| @@ -0,0 +1,130 @@ |
| +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +library command_line_config; |
| + |
| +import 'dart:io'; |
| + |
| +import '../../../pkg/unittest/lib/unittest.dart'; |
| + |
| +const _GREEN = '\u001b[32m'; |
| +const _RED = '\u001b[31m'; |
| +const _MAGENTA = '\u001b[35m'; |
| +const _NONE = '\u001b[0m'; |
| + |
| +/// A custom unittest configuration for running the pub tests from the |
| +/// command-line and generating human-friendly output. |
| +class CommandLineConfiguration extends Configuration { |
| + void onInit() { |
| + // Do nothing. Overridden to prevent the base class from printing. |
| + } |
| + |
| + String _padLeft(String string, int length) { |
|
nweiz
2013/01/18 03:35:06
Style nit: this probably belongs down near _indent
Bob Nystrom
2013/01/18 21:11:32
Done.
|
| + if (string.length >= length) return string; |
| + |
| + var result = new StringBuffer(); |
| + result.add(string); |
| + for (var i = 0; i < length - string.length; i++) { |
| + result.add(' '); |
| + } |
| + |
| + return result.toString(); |
| + } |
| + |
| + void onTestResult(TestCase testCase) { |
| + var result; |
| + switch (testCase.result) { |
| + case PASS: result = '${_GREEN}\u2713${_NONE}'; break; |
|
nweiz
2013/01/18 03:35:06
It would be nice to have constants for the pass an
Bob Nystrom
2013/01/18 21:11:32
Done.
|
| + case FAIL: result = '${_RED}\u2717${_NONE}'; break; |
| + case ERROR: result = '${_MAGENTA}?${_NONE}'; break; |
| + } |
| + print('$result ${testCase.description}'); |
| + |
| + if (testCase.message != '') { |
| + print(_indent(testCase.message)); |
| + } |
| + |
| + if (testCase.stackTrace != null && testCase.stackTrace != '') { |
|
nweiz
2013/01/18 03:35:06
It would be nice to short-circuit here rather than
Bob Nystrom
2013/01/18 21:11:32
Done.
|
| + // Clean up the stack trace. |
| + var regex = new RegExp(r'\#\d+\s+(.*) \(file:///([^)]+)\)'); |
|
nweiz
2013/01/18 03:35:06
I don't think "#" needs to be escaped.
Also, "reg
Bob Nystrom
2013/01/18 21:11:32
Done.
|
| + var stack = []; |
| + for (var line in testCase.stackTrace.split('\n')) { |
| + if (line.trim() == '') continue; |
| + |
| + var match = regex.firstMatch(line); |
| + if (match == null) throw "Couldn't clean up stack trace line '$line'."; |
|
nweiz
2013/01/18 03:35:06
Throwing here seems like it would be really annoyi
Bob Nystrom
2013/01/18 21:11:32
It's mostly just to get our attention to tweak the
|
| + stack.add([match[2], match[1]]); |
|
nweiz
2013/01/18 03:35:06
We do have a Pair class...
Bob Nystrom
2013/01/18 21:11:32
Done.
|
| + } |
| + |
| + // Find the common prefixes of the paths. |
| + if (stack.length > 0) { |
|
nweiz
2013/01/18 03:35:06
Another place it might be nice to short-circuit.
Bob Nystrom
2013/01/18 21:11:32
Done.
|
| + var common = 0; |
| + while (true) { |
| + var matching = true; |
| + // TODO(bob): Handle empty stack. |
| + var c = stack[0][0][common]; |
|
nweiz
2013/01/18 03:35:06
I like ".first" better than "[0]". Also below.
Bob Nystrom
2013/01/18 21:11:32
Done.
|
| + for (var pair in stack) { |
| + if (pair[0].length <= common || pair[0][common] != c) { |
| + matching = false; |
| + break; |
| + } |
| + } |
| + |
| + if (!matching) break; |
| + common++; |
| + } |
|
nweiz
2013/01/18 03:35:06
I'd probably factor this out into a "commonPrefix"
Bob Nystrom
2013/01/18 21:11:32
Pulled all of the stack clean up into a separate m
|
| + |
| + // Remove them. |
| + if (common > 0) { |
| + for (var pair in stack) { |
| + pair[0] = pair[0].substring(common); |
| + } |
| + } |
| + |
| + // Figure out the longest path so we know how much to pad. |
| + int longest = 0; |
| + for (var pair in stack) { |
| + if (pair[0].length > longest) longest = pair[0].length; |
| + } |
|
nweiz
2013/01/18 03:35:06
"stack.map((pair) => pair.first.length).max()" wou
Bob Nystrom
2013/01/18 21:11:32
Done.
|
| + |
| + // Print out the stack trace nicely formatted. |
| + for (var pair in stack) { |
| + print(' ${_padLeft(pair[0], longest)} ${pair[1]}'); |
| + } |
| + } |
| + print(''); |
| + } |
| + |
| + currentTestCase = null; |
| + } |
| + |
| + void onSummary(int passed, int failed, int errors, List<TestCase> results, |
| + String uncaughtError) { |
| + var success = false; |
| + if (uncaughtError != null) { |
| + print('Top-level uncaught error: $uncaughtError'); |
| + } else if (errors != 0) { |
| + print('${_GREEN}$passed${_NONE} passed, ${_RED}$failed${_NONE} failed, ' |
| + '${_MAGENTA}$errors${_NONE} errors.'); |
| + } else if (failed != 0) { |
| + print('${_GREEN}$passed${_NONE} passed, ${_RED}$failed${_NONE} ' |
| + 'failed.'); |
| + } else if (passed == 0) { |
| + print('No tests found.'); |
| + } else { |
| + print('All ${_GREEN}$passed${_NONE} tests passed!'); |
| + success = true; |
| + } |
| + } |
| + |
| + void onDone(bool success) { |
| + if (!success) exit(1); |
| + } |
| + |
| + String _indent(String str) { |
| + // TODO(nweiz): Use this simpler code once issue 2980 is fixed. |
|
nweiz
2013/01/18 03:35:06
That bug has been open for a long time.
Bob Nystrom
2013/01/18 21:11:32
<shrug>
|
| + // return str.replaceAll(new RegExp("^", multiLine: true), " "); |
| + return Strings.join(str.split("\n").mappedBy((line) => " $line"), "\n"); |
| + } |
| +} |