| // 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 schedule_error; |
| |
| import 'dart:async'; |
| |
| import 'package:stack_trace/stack_trace.dart'; |
| |
| import 'schedule.dart'; |
| import 'task.dart'; |
| import 'utils.dart'; |
| |
| /// A wrapper for errors that occur during a scheduled test. |
| class ScheduleError { |
| /// The wrapped error. |
| final error; |
| |
| /// The stack trace that was attached to the error. Can be `null`. |
| final stackTrace; |
| |
| /// The schedule during which this error occurred. |
| final Schedule schedule; |
| |
| /// The task that was running when this error occurred. This may be `null` if |
| /// there was no such task. |
| final Task task; |
| |
| /// The task queue that was running when this error occured. This may be |
| /// `null` if there was no such queue. |
| final TaskQueue queue; |
| |
| /// The descriptions of out-of-band callbacks that were pending when this |
| /// error occurred. |
| final Iterable<PendingCallback> pendingCallbacks; |
| |
| /// The state of the schedule at the time the error was detected. |
| final ScheduleState _stateWhenDetected; |
| |
| int get hashCode => schedule.hashCode ^ task.hashCode ^ queue.hashCode ^ |
| _stateWhenDetected.hashCode ^ error.hashCode ^ stackTrace.hashCode; |
| |
| /// Creates a new [ScheduleError] wrapping [error]. The metadata in |
| /// [ScheduleError]s will be preserved. |
| factory ScheduleError.from(Schedule schedule, error, |
| {StackTrace stackTrace}) { |
| if (error is ScheduleError) return error; |
| |
| var attachedTrace = getAttachedStackTrace(error); |
| if (attachedTrace != null) { |
| // Overwrite the explicit stack trace, because it probably came from a |
| // rethrow in the first place. |
| stackTrace = attachedTrace; |
| } |
| |
| if (stackTrace == null) stackTrace = new Trace.current(); |
| return new ScheduleError(schedule, error, stackTrace); |
| } |
| |
| // TODO(floitsch): restore StackTrace type when it has been integrated into |
| // the core libraries. |
| ScheduleError(Schedule schedule, error, var stackTrace) |
| : error = error, |
| stackTrace = stackTrace, |
| schedule = schedule, |
| task = schedule.currentTask, |
| queue = schedule.currentQueue, |
| pendingCallbacks = schedule.currentQueue == null ? <PendingCallback>[] |
| : schedule.currentQueue.pendingCallbacks.toList(), |
| _stateWhenDetected = schedule.state; |
| |
| bool operator ==(other) => other is ScheduleError && task == other.task && |
| queue == other.queue && _stateWhenDetected == other._stateWhenDetected && |
| error == other.error && stackTrace == other.stackTrace; |
| |
| String toString() { |
| var result = new StringBuffer(); |
| |
| var errorString = error.toString(); |
| if (errorString.contains("\n")) { |
| result.write('ScheduleError:\n'); |
| result.write(prefixLines(errorString.trim())); |
| result.write("\n\n"); |
| } else { |
| result.write('ScheduleError: "$errorString"\n'); |
| } |
| |
| if (stackTrace != null) { |
| result.write('Stack trace:\n'); |
| result.write(prefixLines(terseTraceString(stackTrace))); |
| result.write("\n\n"); |
| } |
| |
| if (task != null) { |
| result.write('Error detected during task in queue "$queue":\n'); |
| result.write(task.generateTree()); |
| } else if (_stateWhenDetected == ScheduleState.DONE) { |
| result.write('Error detected after all tasks in the schedule had ' |
| 'finished.'); |
| } else if (_stateWhenDetected == ScheduleState.RUNNING) { |
| result.write('Error detected when waiting for out-of-band callbacks in ' |
| 'queue "$queue".'); |
| } else { // _stateWhenDetected == ScheduleState.SET_UP |
| result.write('Error detected before the schedule started running.'); |
| } |
| |
| if (!pendingCallbacks.isEmpty) { |
| result.write("\n\n"); |
| result.writeln("Pending out-of-band callbacks:"); |
| for (var callback in pendingCallbacks) { |
| result.writeln(prefixLines(callback.toString(), firstPrefix: "* ")); |
| } |
| } |
| |
| return result.toString().trim(); |
| } |
| } |