chore: enable discarded_futures lint
BREAKING CHANGE: This changes the runInRoot method to not return a future. As a user, if you need the result of an async computation passed to runInRoot, please await it directly. Also the KeyVerification start and a few call methods now return a future.
This commit is contained in:
parent
5dc3adadfc
commit
8b8a647cf9
|
|
@ -6,6 +6,8 @@ linter:
|
|||
always_use_package_imports: true
|
||||
avoid_bool_literals_in_conditional_expressions: true
|
||||
avoid_print: true
|
||||
cancel_subscriptions: true
|
||||
discarded_futures: true
|
||||
non_constant_identifier_names: false # seems to wrongly diagnose static const variables
|
||||
prefer_final_in_for_each: true
|
||||
prefer_final_locals: true
|
||||
|
|
|
|||
|
|
@ -100,11 +100,12 @@ class Encryption {
|
|||
|
||||
void handleDeviceOneTimeKeysCount(
|
||||
Map<String, int>? countJson, List<String>? unusedFallbackKeyTypes) {
|
||||
runInRoot(() => olmManager.handleDeviceOneTimeKeysCount(
|
||||
runInRoot(() async => olmManager.handleDeviceOneTimeKeysCount(
|
||||
countJson, unusedFallbackKeyTypes));
|
||||
}
|
||||
|
||||
void onSync() {
|
||||
// ignore: discarded_futures
|
||||
keyVerificationManager.cleanup();
|
||||
}
|
||||
|
||||
|
|
@ -118,30 +119,25 @@ class Encryption {
|
|||
.contains(event.type)) {
|
||||
// "just" room key request things. We don't need these asap, so we handle
|
||||
// them in the background
|
||||
// ignore: unawaited_futures
|
||||
runInRoot(() => keyManager.handleToDeviceEvent(event));
|
||||
}
|
||||
if (event.type == EventTypes.Dummy) {
|
||||
// the previous device just had to create a new olm session, due to olm session
|
||||
// corruption. We want to try to send it the last message we just sent it, if possible
|
||||
// ignore: unawaited_futures
|
||||
runInRoot(() => olmManager.handleToDeviceEvent(event));
|
||||
}
|
||||
if (event.type.startsWith('m.key.verification.')) {
|
||||
// some key verification event. No need to handle it now, we can easily
|
||||
// do this in the background
|
||||
|
||||
// ignore: unawaited_futures
|
||||
runInRoot(() => keyVerificationManager.handleToDeviceEvent(event));
|
||||
}
|
||||
if (event.type.startsWith('m.secret.')) {
|
||||
// some ssss thing. We can do this in the background
|
||||
// ignore: unawaited_futures
|
||||
runInRoot(() => ssss.handleToDeviceEvent(event));
|
||||
}
|
||||
if (event.sender == client.userID) {
|
||||
// maybe we need to re-try SSSS secrets
|
||||
// ignore: unawaited_futures
|
||||
runInRoot(() => ssss.periodicallyRequestMissingCache());
|
||||
}
|
||||
}
|
||||
|
|
@ -157,14 +153,11 @@ class Encryption {
|
|||
update.content['content']['msgtype']
|
||||
.startsWith('m.key.verification.'))) {
|
||||
// "just" key verification, no need to do this in sync
|
||||
|
||||
// ignore: unawaited_futures
|
||||
runInRoot(() => keyVerificationManager.handleEventUpdate(update));
|
||||
}
|
||||
if (update.content['sender'] == client.userID &&
|
||||
update.content['unsigned']?['transaction_id'] == null) {
|
||||
// maybe we need to re-try SSSS secrets
|
||||
// ignore: unawaited_futures
|
||||
runInRoot(() => ssss.periodicallyRequestMissingCache());
|
||||
}
|
||||
}
|
||||
|
|
@ -239,6 +232,7 @@ class Encryption {
|
|||
// the entry should always exist. In the case it doesn't, the following
|
||||
// line *could* throw an error. As that is a future, though, and we call
|
||||
// it un-awaited here, nothing happens, which is exactly the result we want
|
||||
// ignore: discarded_futures
|
||||
client.database?.updateInboundGroupSessionIndexes(
|
||||
json.encode(inboundGroupSession.indexes), roomId, sessionId);
|
||||
}
|
||||
|
|
@ -252,7 +246,7 @@ class Encryption {
|
|||
?.session_id() ??
|
||||
'') ==
|
||||
content.sessionId) {
|
||||
runInRoot(() =>
|
||||
runInRoot(() async =>
|
||||
keyManager.clearOrUseOutboundGroupSession(roomId, wipe: true));
|
||||
}
|
||||
if (canRequestSession) {
|
||||
|
|
|
|||
|
|
@ -244,7 +244,8 @@ class KeyManager {
|
|||
!client.isUnknownSession) {
|
||||
// do e2ee recovery
|
||||
_requestedSessionIds.add(requestIdent);
|
||||
runInRoot(() => request(
|
||||
|
||||
runInRoot(() async => request(
|
||||
room,
|
||||
sessionId,
|
||||
senderKey,
|
||||
|
|
@ -775,8 +776,8 @@ class KeyManager {
|
|||
Future<void>? _uploadingFuture;
|
||||
|
||||
void startAutoUploadKeys() {
|
||||
_uploadKeysOnSync = encryption.client.onSync.stream
|
||||
.listen((_) => uploadInboundGroupSessions(skipIfInProgress: true));
|
||||
_uploadKeysOnSync = encryption.client.onSync.stream.listen(
|
||||
(_) async => uploadInboundGroupSessions(skipIfInProgress: true));
|
||||
}
|
||||
|
||||
/// This task should be performed after sync processing but should not block
|
||||
|
|
@ -1064,6 +1065,7 @@ class KeyManager {
|
|||
StreamSubscription<SyncUpdate>? _uploadKeysOnSync;
|
||||
|
||||
void dispose() {
|
||||
// ignore: discarded_futures
|
||||
_uploadKeysOnSync?.cancel();
|
||||
for (final sess in _outboundGroupSessions.values) {
|
||||
sess.dispose();
|
||||
|
|
|
|||
|
|
@ -396,20 +396,24 @@ class OlmManager {
|
|||
final device = client.userDeviceKeys[event.sender]?.deviceKeys.values
|
||||
.firstWhereOrNull((d) => d.curve25519Key == senderKey);
|
||||
final existingSessions = olmSessions[senderKey];
|
||||
Future<void> updateSessionUsage([OlmSession? session]) =>
|
||||
runInRoot(() async {
|
||||
if (session != null) {
|
||||
session.lastReceived = DateTime.now();
|
||||
await storeOlmSession(session);
|
||||
}
|
||||
if (device != null) {
|
||||
device.lastActive = DateTime.now();
|
||||
await encryption.olmDatabase?.setLastActiveUserDeviceKey(
|
||||
device.lastActive.millisecondsSinceEpoch,
|
||||
device.userId,
|
||||
device.deviceId!);
|
||||
}
|
||||
});
|
||||
Future<void> updateSessionUsage([OlmSession? session]) async {
|
||||
try {
|
||||
if (session != null) {
|
||||
session.lastReceived = DateTime.now();
|
||||
await storeOlmSession(session);
|
||||
}
|
||||
if (device != null) {
|
||||
device.lastActive = DateTime.now();
|
||||
await encryption.olmDatabase?.setLastActiveUserDeviceKey(
|
||||
device.lastActive.millisecondsSinceEpoch,
|
||||
device.userId,
|
||||
device.deviceId!);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logs().e('Error while updating olm session timestamp', e, s);
|
||||
}
|
||||
}
|
||||
|
||||
if (existingSessions != null) {
|
||||
for (final session in existingSessions) {
|
||||
if (session.session == null) {
|
||||
|
|
@ -446,14 +450,16 @@ class OlmManager {
|
|||
newSession.create_inbound_from(_olmAccount!, senderKey, body);
|
||||
_olmAccount!.remove_one_time_keys(newSession);
|
||||
await encryption.olmDatabase?.updateClientKeys(pickledOlmAccount!);
|
||||
|
||||
plaintext = newSession.decrypt(type, body);
|
||||
await runInRoot(() => storeOlmSession(OlmSession(
|
||||
key: client.userID!,
|
||||
identityKey: senderKey,
|
||||
sessionId: newSession.session_id(),
|
||||
session: newSession,
|
||||
lastReceived: DateTime.now(),
|
||||
)));
|
||||
|
||||
await storeOlmSession(OlmSession(
|
||||
key: client.userID!,
|
||||
identityKey: senderKey,
|
||||
sessionId: newSession.session_id(),
|
||||
session: newSession,
|
||||
lastReceived: DateTime.now(),
|
||||
));
|
||||
await updateSessionUsage();
|
||||
} catch (e) {
|
||||
newSession.free();
|
||||
|
|
@ -570,8 +576,6 @@ class OlmManager {
|
|||
return _decryptToDeviceEvent(event);
|
||||
} catch (_) {
|
||||
// okay, the thing errored while decrypting. It is safe to assume that the olm session is corrupt and we should generate a new one
|
||||
|
||||
// ignore: unawaited_futures
|
||||
runInRoot(() => restoreOlmSession(event.senderId, senderKey));
|
||||
|
||||
rethrow;
|
||||
|
|
@ -658,14 +662,18 @@ class OlmManager {
|
|||
final encryptResult = sess.first.session!.encrypt(json.encode(fullPayload));
|
||||
await storeOlmSession(sess.first);
|
||||
if (encryption.olmDatabase != null) {
|
||||
await runInRoot(
|
||||
() async => encryption.olmDatabase?.setLastSentMessageUserDeviceKey(
|
||||
json.encode({
|
||||
'type': type,
|
||||
'content': payload,
|
||||
}),
|
||||
device.userId,
|
||||
device.deviceId!));
|
||||
try {
|
||||
await encryption.olmDatabase?.setLastSentMessageUserDeviceKey(
|
||||
json.encode({
|
||||
'type': type,
|
||||
'content': payload,
|
||||
}),
|
||||
device.userId,
|
||||
device.deviceId!);
|
||||
} catch (e, s) {
|
||||
// we can ignore this error, since it would just make us use a different olm session possibly
|
||||
Logs().w('Error while updating olm usage timestamp', e, s);
|
||||
}
|
||||
}
|
||||
final encryptedBody = <String, dynamic>{
|
||||
'algorithm': AlgorithmTypes.olmV1Curve25519AesSha2,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import 'package:matrix/encryption/utils/ssss_cache.dart';
|
|||
import 'package:matrix/matrix.dart';
|
||||
import 'package:matrix/src/utils/cached_stream_controller.dart';
|
||||
import 'package:matrix/src/utils/crypto/crypto.dart' as uc;
|
||||
import 'package:matrix/src/utils/run_in_root.dart';
|
||||
|
||||
const cacheTypes = <String>{
|
||||
EventTypes.CrossSigningSelfSigning,
|
||||
|
|
@ -722,7 +721,11 @@ class OpenSSSS {
|
|||
throw InvalidPassphraseException('Inalid key');
|
||||
}
|
||||
if (postUnlock) {
|
||||
await runInRoot(() => _postUnlock());
|
||||
try {
|
||||
await _postUnlock();
|
||||
} catch (e, s) {
|
||||
Logs().e('Error during post unlock', e, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import 'dart:typed_data';
|
|||
|
||||
/// decodes base64
|
||||
///
|
||||
/// Dart's native [base64.decode] requires a padded base64 input String.
|
||||
/// Dart's native [base64.decode()] requires a padded base64 input String.
|
||||
/// This function allows unpadded base64 too.
|
||||
///
|
||||
/// See: https://github.com/dart-lang/sdk/issues/39510
|
||||
|
|
|
|||
|
|
@ -1636,7 +1636,7 @@ class Client extends MatrixApi {
|
|||
set backgroundSync(bool enabled) {
|
||||
_backgroundSync = enabled;
|
||||
if (_backgroundSync) {
|
||||
_sync();
|
||||
runInRoot(() async => _sync());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2232,7 +2232,7 @@ class Client extends MatrixApi {
|
|||
requestHistoryOnLimitedTimeline) {
|
||||
Logs().v(
|
||||
'Limited timeline for ${rooms[roomIndex].id} request history now');
|
||||
unawaited(runInRoot(rooms[roomIndex].requestHistory));
|
||||
runInRoot(rooms[roomIndex].requestHistory);
|
||||
}
|
||||
}
|
||||
return room;
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ class Event extends MatrixEvent {
|
|||
final json = toJson();
|
||||
json['unsigned'] ??= <String, dynamic>{};
|
||||
json['unsigned'][messageSendingStatusKey] = EventStatus.error.intValue;
|
||||
// ignore: discarded_futures
|
||||
room.client.handleSync(
|
||||
SyncUpdate(
|
||||
nextBatch: '',
|
||||
|
|
@ -154,6 +155,7 @@ class Event extends MatrixEvent {
|
|||
MessageTypes.File,
|
||||
}.contains(messageType) &&
|
||||
!room.sendingFilePlaceholders.containsKey(eventId)) {
|
||||
// ignore: discarded_futures
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1620,6 +1620,7 @@ class Room {
|
|||
return user.asUser;
|
||||
} else {
|
||||
if (mxID.isValidMatrixId) {
|
||||
// ignore: discarded_futures
|
||||
requestUser(
|
||||
mxID,
|
||||
ignoreErrors: true,
|
||||
|
|
|
|||
|
|
@ -300,8 +300,11 @@ class Timeline {
|
|||
|
||||
/// Don't forget to call this before you dismiss this object!
|
||||
void cancelSubscriptions() {
|
||||
// ignore: discarded_futures
|
||||
sub?.cancel();
|
||||
// ignore: discarded_futures
|
||||
roomSub?.cancel();
|
||||
// ignore: discarded_futures
|
||||
sessionIdReceivedSub?.cancel();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -504,7 +504,7 @@ class DeviceKeys extends SignableKey {
|
|||
lastActive = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
}
|
||||
|
||||
KeyVerification startVerification() {
|
||||
Future<KeyVerification> startVerification() async {
|
||||
if (!isValid) {
|
||||
throw Exception('setVerification called on invalid key');
|
||||
}
|
||||
|
|
@ -516,7 +516,7 @@ class DeviceKeys extends SignableKey {
|
|||
final request = KeyVerification(
|
||||
encryption: encryption, userId: userId, deviceId: deviceId!);
|
||||
|
||||
request.start();
|
||||
await request.start();
|
||||
encryption.keyVerificationManager.addRequest(request);
|
||||
return request;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,10 +50,9 @@ abstract class NativeImplementations {
|
|||
bool retryInDummy = false,
|
||||
});
|
||||
|
||||
@override
|
||||
|
||||
/// this implementation will catch any non-implemented method
|
||||
dynamic noSuchMethod(Invocation invocation) {
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) async {
|
||||
final dynamic argument = invocation.positionalArguments.single;
|
||||
final memberName = invocation.memberName.toString().split('"')[1];
|
||||
|
||||
|
|
|
|||
|
|
@ -20,13 +20,13 @@ import 'dart:async';
|
|||
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
Future<T?> runInRoot<T>(FutureOr<T> Function() fn) async {
|
||||
return await Zone.root.run(() async {
|
||||
void runInRoot<T>(FutureOr<T> Function() fn) {
|
||||
// ignore: discarded_futures
|
||||
Zone.root.run(() async {
|
||||
try {
|
||||
return await fn();
|
||||
await fn();
|
||||
} catch (e, s) {
|
||||
Logs().e('Error thrown in root zone', e, s);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ class UiaRequest<T> {
|
|||
}
|
||||
|
||||
UiaRequest({this.onUpdate, required this.request}) {
|
||||
// ignore: discarded_futures
|
||||
_run();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class NativeImplementationsWebWorker extends NativeImplementations {
|
|||
return completer.future.timeout(timeout);
|
||||
}
|
||||
|
||||
void _handleIncomingMessage(MessageEvent event) {
|
||||
Future<void> _handleIncomingMessage(MessageEvent event) async {
|
||||
final data = event.data;
|
||||
// don't forget handling errors of our second thread...
|
||||
if (data['label'] == 'stacktrace') {
|
||||
|
|
@ -46,12 +46,10 @@ class NativeImplementationsWebWorker extends NativeImplementations {
|
|||
|
||||
final error = event.data['error']!;
|
||||
|
||||
Future.value(
|
||||
onStackTrace.call(event.data['stacktrace'] as String),
|
||||
).then(
|
||||
(stackTrace) => completer?.completeError(
|
||||
WebWorkerError(error: error, stackTrace: stackTrace),
|
||||
),
|
||||
final stackTrace =
|
||||
await onStackTrace.call(event.data['stacktrace'] as String);
|
||||
completer?.completeError(
|
||||
WebWorkerError(error: error, stackTrace: stackTrace),
|
||||
);
|
||||
} else {
|
||||
final response = WebWorkerData.fromJson(event.data);
|
||||
|
|
|
|||
|
|
@ -522,17 +522,18 @@ class CallSession {
|
|||
await gotCallFeedsForAnswer(callFeeds);
|
||||
}
|
||||
|
||||
void replacedBy(CallSession newCall) {
|
||||
Future<void> replacedBy(CallSession newCall) async {
|
||||
if (state == CallState.kWaitLocalMedia) {
|
||||
Logs().v('Telling new call to wait for local media');
|
||||
newCall.waitForLocalAVStream = true;
|
||||
} else if (state == CallState.kCreateOffer ||
|
||||
state == CallState.kInviteSent) {
|
||||
Logs().v('Handing local stream to new call');
|
||||
newCall.gotCallFeedsForAnswer(getLocalStreams);
|
||||
await newCall.gotCallFeedsForAnswer(getLocalStreams);
|
||||
}
|
||||
successor = newCall;
|
||||
onCallReplaced.add(newCall);
|
||||
// ignore: unawaited_futures
|
||||
hangup(CallErrorCode.Replaced, true);
|
||||
}
|
||||
|
||||
|
|
@ -1510,8 +1511,9 @@ class CallSession {
|
|||
return pc;
|
||||
}
|
||||
|
||||
void createDataChannel(String label, RTCDataChannelInit dataChannelDict) {
|
||||
pc?.createDataChannel(label, dataChannelDict);
|
||||
Future<void> createDataChannel(
|
||||
String label, RTCDataChannelInit dataChannelDict) async {
|
||||
await pc?.createDataChannel(label, dataChannelDict);
|
||||
}
|
||||
|
||||
Future<void> tryRemoveStopedStreams() async {
|
||||
|
|
|
|||
|
|
@ -45,11 +45,15 @@ class ConnectionTester {
|
|||
|
||||
await pc1!.setRemoteDescription(answer);
|
||||
|
||||
void dispose() {
|
||||
pc1!.close();
|
||||
pc1!.dispose();
|
||||
pc2!.close();
|
||||
pc2!.dispose();
|
||||
Future<void> dispose() async {
|
||||
await Future.wait([
|
||||
pc1!.close(),
|
||||
pc2!.close(),
|
||||
]);
|
||||
await Future.wait([
|
||||
pc1!.dispose(),
|
||||
pc2!.dispose(),
|
||||
]);
|
||||
}
|
||||
|
||||
bool connected = false;
|
||||
|
|
@ -69,6 +73,7 @@ class ConnectionTester {
|
|||
.e('[VOIP] ConnectionTester Error while testing TURN server: ', e, s);
|
||||
}
|
||||
|
||||
// ignore: unawaited_futures
|
||||
dispose();
|
||||
return connected;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -232,11 +232,11 @@ class GroupCall {
|
|||
this.groupCallId = groupCallId ?? genCallID();
|
||||
}
|
||||
|
||||
GroupCall create() {
|
||||
Future<GroupCall> create() async {
|
||||
voip.groupCalls[groupCallId] = this;
|
||||
voip.groupCalls[room.id] = this;
|
||||
|
||||
client.setRoomStateWithKey(
|
||||
await client.setRoomStateWithKey(
|
||||
room.id,
|
||||
EventTypes.GroupCallPrefix,
|
||||
groupCallId,
|
||||
|
|
@ -413,6 +413,7 @@ class GroupCall {
|
|||
if (localUserMediaStream != null) {
|
||||
final oldStream = localUserMediaStream!.stream;
|
||||
localUserMediaStream!.setNewStream(stream.stream!);
|
||||
// ignore: discarded_futures
|
||||
stopMediaStream(oldStream);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ class VoIP {
|
|||
for (final room in client.rooms) {
|
||||
if (room.activeGroupCallEvents.isNotEmpty) {
|
||||
for (final groupCall in room.activeGroupCallEvents) {
|
||||
// ignore: discarded_futures
|
||||
createGroupCallFromRoomStateEvent(groupCall,
|
||||
emitHandleNewGroupCall: false);
|
||||
}
|
||||
|
|
@ -589,7 +590,7 @@ class VoIP {
|
|||
return null;
|
||||
}
|
||||
final groupId = genCallID();
|
||||
final groupCall = GroupCall(
|
||||
final groupCall = await GroupCall(
|
||||
groupCallId: groupId,
|
||||
client: client,
|
||||
voip: this,
|
||||
|
|
|
|||
|
|
@ -1137,8 +1137,8 @@ void main() {
|
|||
reason: '!5345234235:example.com not found as archived room');
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
matrix.dispose(closeDatabase: true);
|
||||
tearDown(() async {
|
||||
await matrix.dispose(closeDatabase: true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import 'package:matrix/matrix.dart';
|
|||
import 'fake_database.dart';
|
||||
|
||||
void main() {
|
||||
group('HiveCollections Database Test', () {
|
||||
group('HiveCollections Database Test', () async {
|
||||
testDatabase(
|
||||
getHiveCollectionsDatabase(null),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ void main() {
|
|||
|
||||
test('start verification', () async {
|
||||
if (!olmEnabled) return;
|
||||
var req = client
|
||||
var req = await client
|
||||
.userDeviceKeys['@alice:example.com']?.deviceKeys['JLAFKJWSCS']
|
||||
?.startVerification();
|
||||
expect(req != null, true);
|
||||
|
|
|
|||
|
|
@ -260,6 +260,7 @@ class FakeMatrixApi extends BaseClient {
|
|||
}
|
||||
}
|
||||
// and generate a fake sync
|
||||
// ignore: discarded_futures
|
||||
_client!.handleSync(sdk.SyncUpdate(nextBatch: ''));
|
||||
}
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ void main() {
|
|||
insertList.clear();
|
||||
});
|
||||
|
||||
tearDown(() => client.dispose().onError((e, s) {}));
|
||||
tearDown(() async => client.dispose().onError((e, s) {}));
|
||||
|
||||
test('archive room not loaded', () async {
|
||||
final archiveRoom =
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ void main() {
|
|||
var olmEnabled = true;
|
||||
|
||||
final countStream = StreamController<int>.broadcast();
|
||||
Future<int> waitForCount(int count) {
|
||||
Future<int> waitForCount(int count) async {
|
||||
if (updateCount == count) {
|
||||
return Future.value(updateCount);
|
||||
}
|
||||
|
|
@ -46,9 +46,9 @@ void main() {
|
|||
final completer = Completer<int>();
|
||||
|
||||
StreamSubscription<int>? sub;
|
||||
sub = countStream.stream.listen((newCount) {
|
||||
sub = countStream.stream.listen((newCount) async {
|
||||
if (newCount == count) {
|
||||
sub?.cancel();
|
||||
await sub?.cancel();
|
||||
completer.complete(count);
|
||||
}
|
||||
});
|
||||
|
|
@ -100,7 +100,8 @@ void main() {
|
|||
testTimeStamp = DateTime.now().millisecondsSinceEpoch;
|
||||
});
|
||||
|
||||
tearDown(() => client.dispose(closeDatabase: true).onError((e, s) {}));
|
||||
tearDown(
|
||||
() async => client.dispose(closeDatabase: true).onError((e, s) {}));
|
||||
|
||||
test('Request future', () async {
|
||||
timeline.events.clear();
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ void main() {
|
|||
var currentPoison = 0;
|
||||
|
||||
final countStream = StreamController<int>.broadcast();
|
||||
Future<int> waitForCount(int count) {
|
||||
Future<int> waitForCount(int count) async {
|
||||
if (updateCount == count) {
|
||||
return Future.value(updateCount);
|
||||
}
|
||||
|
|
@ -47,9 +47,9 @@ void main() {
|
|||
final completer = Completer<int>();
|
||||
|
||||
StreamSubscription<int>? sub;
|
||||
sub = countStream.stream.listen((newCount) {
|
||||
sub = countStream.stream.listen((newCount) async {
|
||||
if (newCount == count) {
|
||||
sub?.cancel();
|
||||
await sub?.cancel();
|
||||
completer.complete(count);
|
||||
}
|
||||
});
|
||||
|
|
@ -109,7 +109,8 @@ void main() {
|
|||
testTimeStamp = DateTime.now().millisecondsSinceEpoch;
|
||||
});
|
||||
|
||||
tearDown(() => client.dispose(closeDatabase: true).onError((e, s) {}));
|
||||
tearDown(
|
||||
() async => client.dispose(closeDatabase: true).onError((e, s) {}));
|
||||
|
||||
test('Create', () async {
|
||||
client.onEvent.add(EventUpdate(
|
||||
|
|
|
|||
Loading…
Reference in New Issue