OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library command_line_config; |
| 6 |
| 7 import 'dart:io'; |
| 8 |
| 9 import '../../../pkg/unittest/lib/unittest.dart'; |
| 10 import '../../pub/utils.dart'; |
| 11 |
| 12 const _GREEN = '\u001b[32m'; |
| 13 const _RED = '\u001b[31m'; |
| 14 const _MAGENTA = '\u001b[35m'; |
| 15 const _NONE = '\u001b[0m'; |
| 16 |
| 17 /// Pretty Unicode characters! |
| 18 const _CHECKBOX = '\u2713'; |
| 19 const _BALLOT_X = '\u2717'; |
| 20 |
| 21 /// A custom unittest configuration for running the pub tests from the |
| 22 /// command-line and generating human-friendly output. |
| 23 class CommandLineConfiguration extends Configuration { |
| 24 void onInit() { |
| 25 // Do nothing. Overridden to prevent the base class from printing. |
| 26 } |
| 27 |
| 28 void onTestResult(TestCase testCase) { |
| 29 var result; |
| 30 switch (testCase.result) { |
| 31 case PASS: result = '$_GREEN$_CHECKBOX$_NONE'; break; |
| 32 case FAIL: result = '$_RED$_BALLOT_X$_NONE'; break; |
| 33 case ERROR: result = '$_MAGENTA?$_NONE'; break; |
| 34 } |
| 35 print('$result ${testCase.description}'); |
| 36 |
| 37 if (testCase.message != '') { |
| 38 print(_indent(testCase.message)); |
| 39 } |
| 40 |
| 41 _printStackTrace(testCase.stackTrace); |
| 42 |
| 43 currentTestCase = null; |
| 44 } |
| 45 |
| 46 void onSummary(int passed, int failed, int errors, List<TestCase> results, |
| 47 String uncaughtError) { |
| 48 var success = false; |
| 49 if (uncaughtError != null) { |
| 50 print('Top-level uncaught error: $uncaughtError'); |
| 51 } else if (errors != 0) { |
| 52 print('${_GREEN}$passed${_NONE} passed, ${_RED}$failed${_NONE} failed, ' |
| 53 '${_MAGENTA}$errors${_NONE} errors.'); |
| 54 } else if (failed != 0) { |
| 55 print('${_GREEN}$passed${_NONE} passed, ${_RED}$failed${_NONE} ' |
| 56 'failed.'); |
| 57 } else if (passed == 0) { |
| 58 print('No tests found.'); |
| 59 } else { |
| 60 print('All ${_GREEN}$passed${_NONE} tests passed!'); |
| 61 success = true; |
| 62 } |
| 63 } |
| 64 |
| 65 void onDone(bool success) { |
| 66 if (!success) exit(1); |
| 67 } |
| 68 |
| 69 void _printStackTrace(String stackTrace) { |
| 70 if (stackTrace == null || stackTrace == '') return; |
| 71 |
| 72 // Parse out each stack entry. |
| 73 var regexp = new RegExp(r'#\d+\s+(.*) \(file:///([^)]+)\)'); |
| 74 var stack = []; |
| 75 for (var line in stackTrace.split('\n')) { |
| 76 if (line.trim() == '') continue; |
| 77 |
| 78 var match = regexp.firstMatch(line); |
| 79 if (match == null) throw "Couldn't clean up stack trace line '$line'."; |
| 80 stack.add(new Pair(match[2], match[1])); |
| 81 } |
| 82 |
| 83 if (stack.length == 0) return; |
| 84 |
| 85 // Find the common prefixes of the paths. |
| 86 var common = 0; |
| 87 while (true) { |
| 88 var matching = true; |
| 89 // TODO(bob): Handle empty stack. |
| 90 var c = stack[0].first[common]; |
| 91 for (var pair in stack) { |
| 92 if (pair.first.length <= common || pair.first[common] != c) { |
| 93 matching = false; |
| 94 break; |
| 95 } |
| 96 } |
| 97 |
| 98 if (!matching) break; |
| 99 common++; |
| 100 } |
| 101 |
| 102 // Remove them. |
| 103 if (common > 0) { |
| 104 for (var pair in stack) { |
| 105 pair.first = pair.first.substring(common); |
| 106 } |
| 107 } |
| 108 |
| 109 // Figure out the longest path so we know how much to pad. |
| 110 int longest = stack.mappedBy((pair) => pair.first.length).max(); |
| 111 |
| 112 // Print out the stack trace nicely formatted. |
| 113 for (var pair in stack) { |
| 114 var path = pair.first; |
| 115 path = path.replaceFirst(':', ' '); |
| 116 print(' ${_padLeft(path, longest)} ${pair.last}'); |
| 117 } |
| 118 |
| 119 print(''); |
| 120 } |
| 121 |
| 122 String _padLeft(String string, int length) { |
| 123 if (string.length >= length) return string; |
| 124 |
| 125 var result = new StringBuffer(); |
| 126 result.add(string); |
| 127 for (var i = 0; i < length - string.length; i++) { |
| 128 result.add(' '); |
| 129 } |
| 130 |
| 131 return result.toString(); |
| 132 } |
| 133 |
| 134 String _indent(String str) { |
| 135 // TODO(nweiz): Use this simpler code once issue 2980 is fixed. |
| 136 // return str.replaceAll(new RegExp("^", multiLine: true), " "); |
| 137 return Strings.join(str.split("\n").mappedBy((line) => " $line"), "\n"); |
| 138 } |
| 139 } |
OLD | NEW |