| 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 command_line_config; | 5 library command_line_config; |
| 6 | 6 |
| 7 import 'dart:io'; | 7 import 'dart:io'; |
| 8 | 8 |
| 9 import '../../../pkg/unittest/lib/unittest.dart'; | 9 import '../../../pkg/unittest/lib/unittest.dart'; |
| 10 import '../../pub/utils.dart'; | 10 import '../../pub/utils.dart'; |
| 11 | 11 |
| 12 const _GREEN = '\u001b[32m'; | 12 const _GREEN = '\u001b[32m'; |
| 13 const _RED = '\u001b[31m'; | 13 const _RED = '\u001b[31m'; |
| 14 const _MAGENTA = '\u001b[35m'; | 14 const _MAGENTA = '\u001b[35m'; |
| 15 const _NONE = '\u001b[0m'; | 15 const _NONE = '\u001b[0m'; |
| 16 | 16 |
| 17 /// Pretty Unicode characters! | 17 /// Pretty Unicode characters! |
| 18 const _CHECKBOX = '\u2713'; | 18 const _CHECKBOX = '\u2713'; |
| 19 const _BALLOT_X = '\u2717'; | 19 const _BALLOT_X = '\u2717'; |
| 20 const _LAMBDA = '\u03bb'; |
| 20 | 21 |
| 21 /// A custom unittest configuration for running the pub tests from the | 22 /// A custom unittest configuration for running the pub tests from the |
| 22 /// command-line and generating human-friendly output. | 23 /// command-line and generating human-friendly output. |
| 23 class CommandLineConfiguration extends Configuration { | 24 class CommandLineConfiguration extends Configuration { |
| 24 void onInit() { | 25 void onInit() { |
| 25 // Do nothing. Overridden to prevent the base class from printing. | 26 // Do nothing. Overridden to prevent the base class from printing. |
| 26 } | 27 } |
| 27 | 28 |
| 28 void onTestResult(TestCase testCase) { | 29 void onTestResult(TestCase testCase) { |
| 29 var result; | 30 var result; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 } | 64 } |
| 64 | 65 |
| 65 void onDone(bool success) { | 66 void onDone(bool success) { |
| 66 if (!success) exit(1); | 67 if (!success) exit(1); |
| 67 } | 68 } |
| 68 | 69 |
| 69 void _printStackTrace(String stackTrace) { | 70 void _printStackTrace(String stackTrace) { |
| 70 if (stackTrace == null || stackTrace == '') return; | 71 if (stackTrace == null || stackTrace == '') return; |
| 71 | 72 |
| 72 // Parse out each stack entry. | 73 // Parse out each stack entry. |
| 73 var regexp = new RegExp(r'#\d+\s+(.*) \(file:///([^)]+)\)'); | |
| 74 var stack = []; | 74 var stack = []; |
| 75 for (var line in stackTrace.split('\n')) { | 75 for (var line in stackTrace.split('\n')) { |
| 76 if (line.trim() == '') continue; | 76 if (line.trim() == '') continue; |
| 77 | 77 stack.add(new _StackFrame(line)); |
| 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 } | 78 } |
| 82 | 79 |
| 83 if (stack.length == 0) return; | 80 if (stack.length == 0) return; |
| 84 | 81 |
| 85 // Find the common prefixes of the paths. | 82 // Find the common prefixes of the paths. |
| 86 var common = 0; | 83 var common = 0; |
| 87 while (true) { | 84 while (true) { |
| 88 var matching = true; | 85 var matching = true; |
| 89 // TODO(bob): Handle empty stack. | 86 var c; |
| 90 var c = stack[0].first[common]; | 87 for (var frame in stack) { |
| 91 for (var pair in stack) { | 88 if (frame.isCore) continue; |
| 92 if (pair.first.length <= common || pair.first[common] != c) { | 89 if (c == null) c = frame.library[common]; |
| 90 |
| 91 if (frame.library.length <= common || frame.library[common] != c) { |
| 93 matching = false; | 92 matching = false; |
| 94 break; | 93 break; |
| 95 } | 94 } |
| 96 } | 95 } |
| 97 | 96 |
| 98 if (!matching) break; | 97 if (!matching) break; |
| 99 common++; | 98 common++; |
| 100 } | 99 } |
| 101 | 100 |
| 102 // Remove them. | 101 // Remove them. |
| 103 if (common > 0) { | 102 if (common > 0) { |
| 104 for (var pair in stack) { | 103 for (var frame in stack) { |
| 105 pair.first = pair.first.substring(common); | 104 if (frame.isCore) continue; |
| 105 frame.library = frame.library.substring(common); |
| 106 } | 106 } |
| 107 } | 107 } |
| 108 | 108 |
| 109 // Figure out the longest path so we know how much to pad. | 109 // Figure out the longest path so we know how much to pad. |
| 110 int longest = stack.mappedBy((pair) => pair.first.length).max(); | 110 int longest = stack.mappedBy((frame) => frame.location.length).max(); |
| 111 | 111 |
| 112 // Print out the stack trace nicely formatted. | 112 // Print out the stack trace nicely formatted. |
| 113 for (var pair in stack) { | 113 for (var frame in stack) { |
| 114 var path = pair.first; | 114 print(' ${_padLeft(frame.location, longest)} ${frame.member}'); |
| 115 path = path.replaceFirst(':', ' '); | |
| 116 print(' ${_padLeft(path, longest)} ${pair.last}'); | |
| 117 } | 115 } |
| 118 | 116 |
| 119 print(''); | 117 print(''); |
| 120 } | 118 } |
| 121 | 119 |
| 122 String _padLeft(String string, int length) { | 120 String _padLeft(String string, int length) { |
| 123 if (string.length >= length) return string; | 121 if (string.length >= length) return string; |
| 124 | 122 |
| 125 var result = new StringBuffer(); | 123 var result = new StringBuffer(); |
| 126 result.add(string); | 124 result.add(string); |
| 127 for (var i = 0; i < length - string.length; i++) { | 125 for (var i = 0; i < length - string.length; i++) { |
| 128 result.add(' '); | 126 result.add(' '); |
| 129 } | 127 } |
| 130 | 128 |
| 131 return result.toString(); | 129 return result.toString(); |
| 132 } | 130 } |
| 133 | 131 |
| 134 String _indent(String str) { | 132 String _indent(String str) { |
| 135 // TODO(nweiz): Use this simpler code once issue 2980 is fixed. | 133 // TODO(nweiz): Use this simpler code once issue 2980 is fixed. |
| 136 // return str.replaceAll(new RegExp("^", multiLine: true), " "); | 134 // return str.replaceAll(new RegExp("^", multiLine: true), " "); |
| 137 return Strings.join(str.split("\n").mappedBy((line) => " $line"), "\n"); | 135 return Strings.join(str.split("\n").mappedBy((line) => " $line"), "\n"); |
| 138 } | 136 } |
| 139 } | 137 } |
| 138 |
| 139 class _StackFrame { |
| 140 static final fileRegExp = new RegExp( |
| 141 r'#\d+\s+(.*) \((file:///.+):(\d+):(\d+)\)'); |
| 142 static final coreRegExp = new RegExp(r'#\d+\s+(.*) \((.+):(\d+):(\d+)\)'); |
| 143 |
| 144 /// If `true`, then this stack frame is for a library built into Dart and |
| 145 /// not a regular file path. |
| 146 final bool isCore; |
| 147 |
| 148 /// The path to the library or the library name if a core library. |
| 149 String library; |
| 150 |
| 151 /// The line number. |
| 152 final String line; |
| 153 |
| 154 /// The column number. |
| 155 final String column; |
| 156 |
| 157 /// The member where the error occurred. |
| 158 final String member; |
| 159 |
| 160 /// A formatted description of the code location. |
| 161 String get location => '$library $line:$column'; |
| 162 |
| 163 _StackFrame._(this.isCore, this.library, this.line, this.column, this.member); |
| 164 |
| 165 factory _StackFrame(String text) { |
| 166 var match = fileRegExp.firstMatch(text); |
| 167 var isCore = false; |
| 168 |
| 169 if (match == null) { |
| 170 match = coreRegExp.firstMatch(text); |
| 171 if (match == null) throw "Couldn't parse stack trace line '$text'."; |
| 172 isCore = true; |
| 173 } |
| 174 |
| 175 var member = match[1].replaceAll("<anonymous closure>", _LAMBDA); |
| 176 return new _StackFrame._(isCore, match[2], match[3], match[4], member); |
| 177 } |
| 178 } |
| OLD | NEW |