Skip to content
This repository has been archived by the owner on Oct 17, 2024. It is now read-only.

Revert change of visible behavior in CancelableOperation. #208

Merged
merged 3 commits into from
Mar 18, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 43 additions & 9 deletions lib/src/cancelable_operation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -153,16 +153,50 @@ class CancelableOperation<T> {
final completer =
CancelableCompleter<R>(onCancel: propagateCancel ? cancel : null);

_completer._inner?.future
.then(onValue, onError: onError)
.then(completer.complete, onError: completer.completeError);
_completer._cancelCompleter?.future.then((_) {
if (onCancel != null) {
completer.complete(Future.sync(onCancel));
} else {
completer._cancel();
// if `_completer._inner` completes before `completer` is cancelled
// call `onValue` or `onError` with the result, and complete `completer`
// with the result of that call (unless cancelled in the meantime).
//
// If `_completer._cancelCompleter` completes (always with a value)
// before `completer` is cancelled, then call `onCancel` (if supplied)
// with that that value and complete `completer` with the result of that
// call (unless cancelled in the meantime).
//
// If any of the callbacks throw synchronously, the `completer` is
// completed with that error.
//
// If no `onCancel` is provided, and `_completer._cancelCompleter`
// completes before `completer` is cancelled,
// then cancel `cancelCompleter`. (Cancelling twice is safe.)

_completer._inner?.future.then<void>((value) {
if (completer.isCanceled) return;
try {
completer.complete(onValue(value));
} catch (error, stack) {
completer.completeError(error, stack);
}
});
},
onError: onError == null
? completer.completeError // Is ignored if already cancelled.
: (Object error, StackTrace stack) {
if (completer.isCanceled) return;
try {
completer.complete(onError(error, stack));
} catch (error2, stack2) {
completer.completeError(error2, stack2);
}
});
_completer._cancelCompleter?.future.whenComplete(onCancel == null
? completer._cancel
: () {
if (completer.isCanceled) return;
try {
completer.complete(onCancel());
} catch (error, stack) {
completer.completeError(error, stack);
}
});

return completer.operation;
}
Expand Down
42 changes: 42 additions & 0 deletions test/cancelable_operation_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,48 @@ void main() {

expect(originalCompleter.isCanceled, false);
});

test('onValue callback not called after cancel', () async {
var called = false;
onValue = expectAsync1((_) {
called = true;
fail("onValue unreachable");
return "";
}, count: 0);

await runThen().cancel();
originalCompleter.complete(0);
await flushMicrotasks();
expect(called, false);
});

test('onError callback not called after cancel', () async {
var called = false;
onError = expectAsync2((_, __) {
called = true;
fail("onError unreachable");
return "";
}, count: 0);

await runThen().cancel();
originalCompleter.completeError("Error", StackTrace.empty);
await flushMicrotasks();
expect(called, false);
});

test('onCancel callback not called after cancel', () async {
var called = false;
onCancel = expectAsync0(() {
called = true;
fail("onCancel unreachable");
return "";
}, count: 0);

await runThen().cancel();
await originalCompleter.operation.cancel();
await flushMicrotasks();
expect(called, false);
});
});
});

Expand Down