advance method
Moves time forward by duration, completing every delay that comes due.
Delays complete in due order, and the returned future settles only after
the microtask queue has drained — so await clock.advance(...) leaves the
system in the state it would be in after that much real time.
A delay scheduled by a completing delay is also honoured: the loop keeps going until nothing else is due, which is what makes a multi-step retry sequence testable with a single call.
Implementation
Future<void> advance(Duration duration) async {
if (duration.isNegative) {
throw ArgumentError.value(
duration,
'duration',
'Time cannot move backwards on a FakeClock; that would make already '
'completed delays un-complete.',
);
}
final target = _now.add(duration);
while (true) {
_pending.sort((a, b) => a.dueAt.compareTo(b.dueAt));
final index = _pending.indexWhere(
(pending) => !pending.dueAt.isAfter(target),
);
if (index < 0) break;
final due = _pending.removeAt(index);
_now = due.dueAt;
if (!due.completer.isCompleted) due.completer.complete();
// Let whatever was waiting run before considering the next timer, so that
// work scheduled by this delay is visible to the rest of the advance.
await _drainMicrotasks();
}
_now = target;
await _drainMicrotasks();
}