| Index: pkg/unittest/lib/unittest.dart
|
| diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
|
| index 7b134e96235dd72086c2d378d5d00fb6972da951..ec788778ecf751a8caf8cb0c07b00822ed88c801 100644
|
| --- a/pkg/unittest/lib/unittest.dart
|
| +++ b/pkg/unittest/lib/unittest.dart
|
| @@ -173,9 +173,6 @@ import 'dart:math' show max;
|
| import 'matcher.dart';
|
| export 'matcher.dart';
|
|
|
| -import 'package:stack_trace/stack_trace.dart';
|
| -
|
| -import 'src/utils.dart';
|
| part 'src/config.dart';
|
| part 'src/test_case.dart';
|
|
|
| @@ -456,7 +453,7 @@ class _SpreadArgsHelper {
|
| testCase.error(
|
| 'Callback ${id}called ($actualCalls) after test case '
|
| '${testCase.description} has already been marked as '
|
| - '${testCase.result}.');
|
| + '${testCase.result}.', '');
|
| }
|
| return false;
|
| } else if (maxExpectedCalls >= 0 && actualCalls > maxExpectedCalls) {
|
| @@ -677,7 +674,7 @@ void _nextTestCase() {
|
| * Utility function that can be used to notify the test framework that an
|
| * error was caught outside of this library.
|
| */
|
| -void _reportTestError(String msg, trace) {
|
| +void _reportTestError(String msg, String trace) {
|
| if (_currentTestCaseIndex < testCases.length) {
|
| final testCase = testCases[_currentTestCaseIndex];
|
| testCase.error(msg, trace);
|
| @@ -754,6 +751,7 @@ void registerException(e, [trace]) {
|
| * Registers that an exception was caught for the current test.
|
| */
|
| void _registerException(TestCase testCase, e, [trace]) {
|
| + trace = trace == null ? '' : trace.toString();
|
| String message = (e is TestFailure) ? e.message : 'Caught $e';
|
| if (testCase.result == null) {
|
| testCase.fail(message, trace);
|
| @@ -866,31 +864,85 @@ void disableTest(int testId) => _setTestEnabledState(testId, false);
|
| typedef dynamic TestFunction();
|
|
|
| /**
|
| - * A flag that controls whether we hide unittest and core library details in
|
| - * exception stacks.
|
| - *
|
| + * A flag that controls whether we hide unittest details in exception stacks.
|
| * Useful to disable when debugging unittest or matcher customizations.
|
| */
|
| bool formatStacks = true;
|
|
|
| -/** Returns a Trace object from a StackTrace object or a String. */
|
| -Trace _getTrace(stack) {
|
| - Trace trace;
|
| - if (stack == null) return null;
|
| - if (stack is String) {
|
| - trace = new Trace.parse(stack);
|
| - } else if (stack is StackTrace) {
|
| - trace = new Trace.from(stack);
|
| +// Stack formatting utility. Strips extraneous content from a stack trace.
|
| +// Stack frame lines are parsed with a regexp, which has been tested
|
| +// in Chrome, Firefox and the VM. If a line fails to be parsed it is
|
| +// included in the output to be conservative.
|
| +//
|
| +// The output stack consists of everything after the call to TestCase._run.
|
| +// If we see an 'expect' in the frame we will prune everything above that
|
| +// as well.
|
| +final _frameRegExp = new RegExp(
|
| + r'^\s*' // Skip leading spaces.
|
| + r'(?:' // Group of choices for the prefix.
|
| + r'(?:#\d+\s*)|' // Skip VM's #<frameNumber>.
|
| + r'(?:at )|' // Skip Firefox's 'at '.
|
| + r'(?:))' // Other environments have nothing here.
|
| + r'(.+)' // Extract the function/method.
|
| + r'\s*[@\(]' // Skip space and @ or (.
|
| + r'(' // This group of choices is for the source file.
|
| + r'(?:.+:\/\/.+\/[^:]*)|' // Handle file:// or http:// URLs.
|
| + r'(?:dart:[^:]*)|' // Handle dart:<lib>.
|
| + r'(?:package:[^:]*)' // Handle package:<path>
|
| + r'):([:\d]+)[\)]?$'); // Get the line number and optional column number.
|
| +
|
| +String _formatStack(stack) {
|
| + if (!formatStacks) return "$stack";
|
| + var lines;
|
| + if (stack is StackTrace) {
|
| + lines = stack.toString().split('\n');
|
| + } else if (stack is String) {
|
| + lines = stack.split('\n');
|
| } else {
|
| - throw new Exception('Invalid stack type ${stack.runtimeType} for $stack.');
|
| + return stack.toString();
|
| }
|
|
|
| - if (!formatStacks) return trace;
|
| + // Calculate the max width of first column so we can
|
| + // pad to align the second columns.
|
| + int padding = lines.fold(0, (n, line) {
|
| + var match = _frameRegExp.firstMatch(line);
|
| + if (match == null) return n;
|
| + return max(n, match[1].length + 1);
|
| + });
|
|
|
| - // Format the stack trace by removing everything above TestCase._runTest,
|
| - // which is usually going to be irrelevant. Also fold together unittest and
|
| - // core library calls so only the function the user called is visible.
|
| - return new Trace(trace.frames.takeWhile((frame) {
|
| - return frame.package != 'unittest' || frame.member != 'TestCase._runTest';
|
| - })).terse.foldFrames((frame) => frame.package == 'unittest' || frame.isCore);
|
| + // We remove all entries that have a location in unittest.
|
| + // We strip out anything before _nextBatch too.
|
| + var sb = new StringBuffer();
|
| + for (var i = 0; i < lines.length; i++) {
|
| + var line = lines[i];
|
| + if (line == '') continue;
|
| + var match = _frameRegExp.firstMatch(line);
|
| + if (match == null) {
|
| + sb.write(line);
|
| + sb.write('\n');
|
| + } else {
|
| + var member = match[1];
|
| + var location = match[2];
|
| + var position = match[3];
|
| + if (member.indexOf('TestCase._runTest') >= 0) {
|
| + // Don't include anything after this.
|
| + break;
|
| + } else if (member.indexOf('expect') >= 0) {
|
| + // It looks like this was an expect() failure;
|
| + // drop all the frames up to here.
|
| + sb.clear();
|
| + } else {
|
| + sb.write(member);
|
| + // Pad second column to a fixed position.
|
| + for (var j = 0; j <= padding - member.length; j++) {
|
| + sb.write(' ');
|
| + }
|
| + sb.write(location);
|
| + sb.write(' ');
|
| + sb.write(position);
|
| + sb.write('\n');
|
| + }
|
| + }
|
| + }
|
| + return sb.toString();
|
| }
|
|
|