Small refactors in Invoker (#1052)
- Remove `removeAllOutstandingCallbacks` method. This never had any
usage outside of `scheduled_test` which has been deprecated for a long
time.
- Change some bare `Future` to `Future<void>`.
- Move and rename `OutstandingCallbackCounter` class - the
implementation has no ties to the concept of callbacks, but that is
how it is used.
- Use the modern syntax for function typed arguments.
- Add generics to `unclosable` to void throwing away potentially useful
type information.
diff --git a/pkgs/test_api/lib/src/backend/invoker.dart b/pkgs/test_api/lib/src/backend/invoker.dart
index 100cd1f..5b44624 100644
--- a/pkgs/test_api/lib/src/backend/invoker.dart
+++ b/pkgs/test_api/lib/src/backend/invoker.dart
@@ -17,7 +17,6 @@
import 'live_test_controller.dart';
import 'message.dart';
import 'metadata.dart';
-import 'outstanding_callback_counter.dart';
import 'state.dart';
import 'suite.dart';
import 'suite_platform.dart';
@@ -97,19 +96,19 @@
bool get closed => _closable && _onCloseCompleter.isCompleted;
/// A future that completes once the test has been closed.
- Future get onClose => _closable
+ Future<void> get onClose => _closable
? _onCloseCompleter.future
// If we're in an unclosable block, return a future that will never
// complete.
- : Completer().future;
- final _onCloseCompleter = Completer();
+ : Completer<void>().future;
+ final _onCloseCompleter = Completer<void>();
/// The test being run.
LocalTest get _test => liveTest.test as LocalTest;
/// The outstanding callback counter for the current zone.
- OutstandingCallbackCounter get _outstandingCallbacks {
- var counter = Zone.current[_counterKey] as OutstandingCallbackCounter;
+ _AsyncCounter get _outstandingCallbacks {
+ var counter = Zone.current[_counterKey] as _AsyncCounter;
if (counter != null) return counter;
throw StateError("Can't add or remove outstanding callbacks outside "
"of a test body.");
@@ -206,23 +205,16 @@
/// Throws a [ClosedException] if this test has been closed.
void addOutstandingCallback() {
if (closed) throw ClosedException();
- _outstandingCallbacks.addOutstandingCallback();
+ _outstandingCallbacks.increment();
}
/// Tells the invoker that a callback declared with [addOutstandingCallback]
/// is no longer running.
void removeOutstandingCallback() {
heartbeat();
- _outstandingCallbacks.removeOutstandingCallback();
+ _outstandingCallbacks.decrement();
}
- /// Removes all outstanding callbacks, for example when an error occurs.
- ///
- /// Future calls to [addOutstandingCallback] and [removeOutstandingCallback]
- /// will be ignored.
- void removeAllOutstandingCallbacks() =>
- _outstandingCallbacks.removeAllOutstandingCallbacks();
-
/// Runs [fn] and returns once all (registered) outstanding callbacks it
/// transitively invokes have completed.
///
@@ -239,19 +231,19 @@
/// If the test times out, the *most recent* call to
/// [waitForOutstandingCallbacks] will treat that error as occurring within
/// [fn]—that is, it will complete immediately.
- Future waitForOutstandingCallbacks(fn()) {
+ Future<void> waitForOutstandingCallbacks(FutureOr<void> Function() fn) {
heartbeat();
Zone zone;
- var counter = OutstandingCallbackCounter();
+ var counter = _AsyncCounter();
runZoned(() async {
zone = Zone.current;
_outstandingCallbackZones.add(zone);
await fn();
- counter.removeOutstandingCallback();
+ counter.decrement();
}, zoneValues: {_counterKey: counter});
- return counter.noOutstandingCallbacks.whenComplete(() {
+ return counter.onZero.whenComplete(() {
_outstandingCallbackZones.remove(zone);
});
}
@@ -261,7 +253,7 @@
/// This is useful for running code that should be able to register callbacks
/// and interact with the test framework normally even when the invoker is
/// closed, for example cleanup code.
- unclosable(fn()) {
+ T unclosable<T>(T Function() fn) {
heartbeat();
return runZoned(fn, zoneValues: {_closableKey: false});
@@ -345,7 +337,7 @@
}
_controller.addError(error, stackTrace);
- zone.run(removeAllOutstandingCallbacks);
+ zone.run(() => _outstandingCallbacks.complete());
if (!liveTest.test.metadata.chainStackTraces) {
_printsOnFailure.add("Consider enabling the flag chain-stack-traces to "
@@ -378,7 +370,7 @@
void _onRun() {
_controller.setState(const State(Status.running, Result.success));
- var outstandingCallbacksForBody = OutstandingCallbackCounter();
+ var outstandingCallbacksForBody = _AsyncCounter();
_runCount++;
Chain.capture(() {
@@ -402,7 +394,7 @@
removeOutstandingCallback();
}));
- await _outstandingCallbacks.noOutstandingCallbacks;
+ await _outstandingCallbacks.onZero;
if (_timeoutTimer != null) _timeoutTimer.cancel();
if (liveTest.state.result != Result.success &&
@@ -431,7 +423,7 @@
}
/// Runs [callback], in a [Invoker.guard] context if [_guarded] is `true`.
- void _guardIfGuarded(void callback()) {
+ void _guardIfGuarded(void Function() callback) {
if (_guarded) {
Invoker.guard(callback);
} else {
@@ -443,9 +435,37 @@
void _print(String text) => _controller.message(Message.print(text));
/// Run [_tearDowns] in reverse order.
- Future _runTearDowns() async {
+ Future<void> _runTearDowns() async {
while (_tearDowns.isNotEmpty) {
await errorsDontStopTest(_tearDowns.removeLast());
}
}
}
+
+/// A manually incremented/decremented counter that completes a [Future] the
+/// first time it reaches zero or is forcefully completed.
+class _AsyncCounter {
+ var _count = 1;
+
+ /// A Future that completes the first time the counter reaches 0.
+ Future<void> get onZero => _completer.future;
+ final _completer = Completer<void>();
+
+ void increment() {
+ _count++;
+ }
+
+ void decrement() {
+ _count--;
+ if (_count != 0) return;
+ if (_completer.isCompleted) return;
+ _completer.complete();
+ }
+
+ /// Force [onZero] to complete.
+ ///
+ /// No effect if [onZero] has already completed.
+ void complete() {
+ if (!_completer.isCompleted) _completer.complete();
+ }
+}
diff --git a/pkgs/test_api/lib/src/backend/outstanding_callback_counter.dart b/pkgs/test_api/lib/src/backend/outstanding_callback_counter.dart
deleted file mode 100644
index 4f8e401..0000000
--- a/pkgs/test_api/lib/src/backend/outstanding_callback_counter.dart
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2015, 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.
-
-import 'dart:async';
-
-/// A class that counts outstanding callbacks for a test and fires a future once
-/// they reach zero.
-///
-/// The outstanding callback count automatically starts at 1.
-class OutstandingCallbackCounter {
- /// The number of outstanding callbacks.
- var _count = 1;
-
- /// A future that fires when the oustanding callback count reaches 0.
- Future get noOutstandingCallbacks => _completer.future;
- final _completer = Completer();
-
- /// Adds an outstanding callback.
- void addOutstandingCallback() {
- _count++;
- }
-
- /// Removes an outstanding callback.
- void removeOutstandingCallback() {
- _count--;
- if (_count != 0) return;
- if (_completer.isCompleted) return;
- _completer.complete();
- }
-
- /// Removes all outstanding callbacks, forcing [noOutstandingCallbacks] to
- /// fire.
- ///
- /// Future calls to [addOutstandingCallback] and [removeOutstandingCallback]
- /// will be ignored.
- void removeAllOutstandingCallbacks() {
- if (!_completer.isCompleted) _completer.complete();
- }
-}