| 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 import 'dart:math' as math; | |
| 9 | |
| 10 import 'package:pathos/path.dart' as path; | |
| 11 import 'package:unittest/unittest.dart'; | |
| 12 import '../../pub/utils.dart'; | |
| 13 | |
| 14 /// Gets a "special" string (ANSI escape or Unicode). On Windows, returns | |
| 15 /// something else since those aren't supported. | |
| 16 String _getSpecial(String color, [String onWindows = '']) { | |
| 17 // No ANSI escapes on windows. | |
| 18 if (Platform.operatingSystem == 'windows') return onWindows; | |
| 19 return color; | |
| 20 } | |
| 21 | |
| 22 /// Pretty Unicode characters! | |
| 23 final _checkbox = _getSpecial('\u2713', 'PASS'); | |
| 24 final _ballotX = _getSpecial('\u2717', 'FAIL'); | |
| 25 final _lambda = _getSpecial('\u03bb', '<fn>'); | |
| 26 | |
| 27 final _green = _getSpecial('\u001b[32m'); | |
| 28 final _red = _getSpecial('\u001b[31m'); | |
| 29 final _magenta = _getSpecial('\u001b[35m'); | |
| 30 final _none = _getSpecial('\u001b[0m'); | |
| 31 | |
| 32 /// A custom unittest configuration for running the pub tests from the | |
| 33 /// command-line and generating human-friendly output. | |
| 34 class CommandLineConfiguration extends Configuration { | |
| 35 void onInit() { | |
| 36 // Do nothing. Overridden to prevent the base class from printing. | |
| 37 } | |
| 38 | |
| 39 void onTestResult(TestCase testCase) { | |
| 40 var result; | |
| 41 switch (testCase.result) { | |
| 42 case PASS: result = '$_green$_checkbox$_none'; break; | |
| 43 case FAIL: result = '$_red$_ballotX$_none'; break; | |
| 44 case ERROR: result = '$_magenta?$_none'; break; | |
| 45 } | |
| 46 print('$result ${testCase.description}'); | |
| 47 | |
| 48 if (testCase.message != '') { | |
| 49 print(_indent(testCase.message)); | |
| 50 } | |
| 51 | |
| 52 _printStackTrace(testCase.stackTrace); | |
| 53 | |
| 54 super.onTestResult(testCase); | |
| 55 } | |
| 56 | |
| 57 void onSummary(int passed, int failed, int errors, List<TestCase> results, | |
| 58 String uncaughtError) { | |
| 59 var success = false; | |
| 60 if (uncaughtError != null) { | |
| 61 print('Top-level uncaught error: $uncaughtError'); | |
| 62 } else if (errors != 0) { | |
| 63 print('${_green}$passed${_none} passed, ${_red}$failed${_none} failed, ' | |
| 64 '${_magenta}$errors${_none} errors.'); | |
| 65 } else if (failed != 0) { | |
| 66 print('${_green}$passed${_none} passed, ${_red}$failed${_none} ' | |
| 67 'failed.'); | |
| 68 } else if (passed == 0) { | |
| 69 print('No tests found.'); | |
| 70 } else { | |
| 71 print('All ${_green}$passed${_none} tests passed!'); | |
| 72 success = true; | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 void onDone(bool success) { | |
| 77 if (!success) exit(1); | |
| 78 } | |
| 79 | |
| 80 void _printStackTrace(String stackTrace) { | |
| 81 if (stackTrace == null || stackTrace == '') return; | |
| 82 | |
| 83 print(''); | |
| 84 | |
| 85 // Parse out each stack entry. | |
| 86 var stack = []; | |
| 87 for (var line in stackTrace.split('\n')) { | |
| 88 if (line.trim() == '') continue; | |
| 89 stack.add(new _StackFrame(line)); | |
| 90 } | |
| 91 | |
| 92 if (stack.length == 0) return; | |
| 93 | |
| 94 // Figure out the longest path so we know how much to pad. | |
| 95 int longest = stack.map((frame) => frame.location.length).reduce(math.max); | |
| 96 | |
| 97 // Print out the stack trace nicely formatted. | |
| 98 for (var frame in stack) { | |
| 99 print(' ${_padLeft(frame.location, longest)} ${frame.member}'); | |
| 100 } | |
| 101 | |
| 102 print(''); | |
| 103 } | |
| 104 | |
| 105 String _padLeft(String string, int length) { | |
| 106 if (string.length >= length) return string; | |
| 107 | |
| 108 var result = new StringBuffer(); | |
| 109 result.write(string); | |
| 110 for (var i = 0; i < length - string.length; i++) { | |
| 111 result.write(' '); | |
| 112 } | |
| 113 | |
| 114 return result.toString(); | |
| 115 } | |
| 116 | |
| 117 String _indent(String str) { | |
| 118 // TODO(nweiz): Use this simpler code once issue 2980 is fixed. | |
| 119 // return str.replaceAll(new RegExp("^", multiLine: true), " "); | |
| 120 return str.split("\n").map((line) => " $line").join("\n"); | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 class _StackFrame { | |
| 125 static final fileRegExp = new RegExp( | |
| 126 r'#\d+\s+(.*) \(file://(/.+):(\d+):(\d+)\)'); | |
| 127 static final coreRegExp = new RegExp(r'#\d+\s+(.*) \((.+):(\d+):(\d+)\)'); | |
| 128 | |
| 129 /// If `true`, then this stack frame is for a library built into Dart and | |
| 130 /// not a regular file path. | |
| 131 final bool isCore; | |
| 132 | |
| 133 /// The path to the library or the library name if a core library. | |
| 134 String library; | |
| 135 | |
| 136 /// The line number. | |
| 137 final String line; | |
| 138 | |
| 139 /// The column number. | |
| 140 final String column; | |
| 141 | |
| 142 /// The member where the error occurred. | |
| 143 final String member; | |
| 144 | |
| 145 /// A formatted description of the code location. | |
| 146 String get location => '$library $line:$column'; | |
| 147 | |
| 148 _StackFrame._(this.isCore, this.library, this.line, this.column, this.member); | |
| 149 | |
| 150 factory _StackFrame(String text) { | |
| 151 var match = fileRegExp.firstMatch(text); | |
| 152 var isCore = false; | |
| 153 | |
| 154 if (match == null) { | |
| 155 match = coreRegExp.firstMatch(text); | |
| 156 if (match == null) { | |
| 157 throw new FormatException("Couldn't parse stack trace line '$text'."); | |
| 158 } | |
| 159 isCore = true; | |
| 160 } | |
| 161 | |
| 162 var library = match[2]; | |
| 163 if (!isCore) { | |
| 164 // Make the library path relative to the entrypoint. | |
| 165 library = path.relative(library); | |
| 166 } | |
| 167 | |
| 168 var member = match[1].replaceAll("<anonymous closure>", _lambda); | |
| 169 return new _StackFrame._(isCore, library, match[3], match[4], member); | |
| 170 } | |
| 171 } | |
| OLD | NEW |