blob: 910e4f5fcbaa03d76b9e83caa7779b90e4841aa5 [file] [log] [blame]
// 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();
}
}