diff --git a/analysis_options.yaml b/analysis_options.yaml index a9d10322a..9ea324932 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -2,19 +2,44 @@ include: package:lints/recommended.yaml linter: rules: - camel_case_types: true - avoid_print: true - constant_identifier_names: true - prefer_final_locals: true + # We enable a few additional rules not in the default and recommended sets. + # Those in general have low impact on correct code apart from possibly requiring an additional keyword (like async, + # await, final) or asking you to move a statement to a different line. However many of these linter rules make the + # code either more uniform or avoid bug prone behaviour. For example not awaiting a future usually is a mistake. + # You can always disable a linter warning with a comment like `// ignore: unawaited_futures`. Please add reasoning, + # why you disable the rule in such cases. This helps others understand, that you explicitly want a behaviour, that + # usually would be considered a mistake. + + # Performance (or potential bugs) + # Fixing these warnings makes code easier to optimize for the compiler or prevents leaks. + cancel_subscriptions: true prefer_final_in_for_each: true - sort_pub_dependencies: true - always_use_package_imports: true + prefer_final_locals: true + + # Warn about possible bugs + # Usually code with these warnings indicates a bug. + # Please document if your code explicitly wants such a behaviour. always_declare_return_types: true - prefer_single_quotes: true - sort_child_properties_last: true + discarded_futures: true + no_adjacent_strings_in_list: true + test_types_in_equals: true + throw_in_finally: true unawaited_futures: true + unnecessary_statements: true unsafe_html: true - avoid_function_literals_in_foreach_calls: false + + # Readability & Style + # These are opinionated choices, where Dart gives us 2 ways to express the same thing. + # This avoids mental overhead by not having to make a choice and making code more uniform to read. + always_use_package_imports: true + avoid_bool_literals_in_conditional_expressions: true + prefer_single_quotes: true + sort_child_properties_last: true + sort_pub_dependencies: true + + # Be nice to our users and allow them to configure what gets logged. + avoid_print: true + non_constant_identifier_names: false # seems to wrongly diagnose static const variables analyzer: @@ -22,6 +47,4 @@ analyzer: todo: ignore exclude: - example/main.dart - # needed until crypto packages upgrade - - lib/src/database/database.g.dart plugins: diff --git a/lib/encryption/encryption.dart b/lib/encryption/encryption.dart index 7403da9dd..8a5d1635c 100644 --- a/lib/encryption/encryption.dart +++ b/lib/encryption/encryption.dart @@ -100,11 +100,12 @@ class Encryption { void handleDeviceOneTimeKeysCount( Map? countJson, List? 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) { diff --git a/lib/encryption/key_manager.dart b/lib/encryption/key_manager.dart index d8cb59fb9..6c70f870d 100644 --- a/lib/encryption/key_manager.dart +++ b/lib/encryption/key_manager.dart @@ -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? _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? _uploadKeysOnSync; void dispose() { + // ignore: discarded_futures _uploadKeysOnSync?.cancel(); for (final sess in _outboundGroupSessions.values) { sess.dispose(); diff --git a/lib/encryption/olm_manager.dart b/lib/encryption/olm_manager.dart index ce60c29bd..fca70d752 100644 --- a/lib/encryption/olm_manager.dart +++ b/lib/encryption/olm_manager.dart @@ -396,20 +396,24 @@ class OlmManager { final device = client.userDeviceKeys[event.sender]?.deviceKeys.values .firstWhereOrNull((d) => d.curve25519Key == senderKey); final existingSessions = olmSessions[senderKey]; - Future 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 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 = { 'algorithm': AlgorithmTypes.olmV1Curve25519AesSha2, diff --git a/lib/encryption/ssss.dart b/lib/encryption/ssss.dart index e6dab3870..b24854e3a 100644 --- a/lib/encryption/ssss.dart +++ b/lib/encryption/ssss.dart @@ -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 = { 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); + } } } diff --git a/lib/encryption/utils/base64_unpadded.dart b/lib/encryption/utils/base64_unpadded.dart index 160a8d113..43f4c7784 100644 --- a/lib/encryption/utils/base64_unpadded.dart +++ b/lib/encryption/utils/base64_unpadded.dart @@ -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 diff --git a/lib/encryption/utils/key_verification.dart b/lib/encryption/utils/key_verification.dart index e011e1013..a088e949d 100644 --- a/lib/encryption/utils/key_verification.dart +++ b/lib/encryption/utils/key_verification.dart @@ -267,11 +267,8 @@ class KeyVerification { } /// `qrCanWork` - qr cannot work if we are verifying another master key but our own is unverified - final qrCanWork = (userId != client.userID) - ? ((client.userDeviceKeys[client.userID]?.masterKey?.verified ?? false) - ? true - : false) - : true; + final qrCanWork = (userId == client.userID) || + ((client.userDeviceKeys[client.userID]?.masterKey?.verified ?? false)); if (client.verificationMethods.contains(KeyVerificationMethod.qrShow) && qrCanWork) { diff --git a/lib/src/client.dart b/lib/src/client.dart index 4a8690798..1cfd549c5 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -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; diff --git a/lib/src/database/hive_collections_database.dart b/lib/src/database/hive_collections_database.dart index e40262bac..c30d5bc5a 100644 --- a/lib/src/database/hive_collections_database.dart +++ b/lib/src/database/hive_collections_database.dart @@ -612,7 +612,7 @@ class HiveCollectionsDatabase extends DatabaseApi { // post-load the heroes final heroes = room.summary.mHeroes; if (heroes != null) { - heroes.forEach((hero) => membersToPostload.add(hero)); + membersToPostload.addAll(heroes); } } // Load members @@ -771,9 +771,9 @@ class HiveCollectionsDatabase extends DatabaseApi { .toList(); final states = await _roomMembersBox.getAll(keys); states.removeWhere((state) => state == null); - states.forEach( - (state) => users.add(Event.fromJson(copyMap(state!), room).asUser), - ); + for (final state in states) { + users.add(Event.fromJson(copyMap(state!), room).asUser); + } return users; } diff --git a/lib/src/event.dart b/lib/src/event.dart index f352143b5..b5549d1d9 100644 --- a/lib/src/event.dart +++ b/lib/src/event.dart @@ -128,6 +128,7 @@ class Event extends MatrixEvent { final json = toJson(); json['unsigned'] ??= {}; 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(); } } diff --git a/lib/src/room.dart b/lib/src/room.dart index 3c3b24436..1ff131eac 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -1620,6 +1620,7 @@ class Room { return user.asUser; } else { if (mxID.isValidMatrixId) { + // ignore: discarded_futures requestUser( mxID, ignoreErrors: true, @@ -2280,7 +2281,7 @@ class Room { } final Map servers = {}; - users.forEach((user) { + for (final user in users) { if (user.id.domain != null) { if (servers.containsKey(user.id.domain!)) { servers[user.id.domain!] = servers[user.id.domain!]! + 1; @@ -2288,7 +2289,7 @@ class Room { servers[user.id.domain!] = 1; } } - }); + } final sortedServers = Map.fromEntries(servers.entries.toList() ..sort((e1, e2) => e1.value.compareTo(e2.value))); for (var i = 0; i <= 2; i++) { diff --git a/lib/src/timeline.dart b/lib/src/timeline.dart index c7cc26b7b..c6baf6ba1 100644 --- a/lib/src/timeline.dart +++ b/lib/src/timeline.dart @@ -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(); } diff --git a/lib/src/utils/device_keys_list.dart b/lib/src/utils/device_keys_list.dart index 7f9e1d5d8..e3daa2e54 100644 --- a/lib/src/utils/device_keys_list.dart +++ b/lib/src/utils/device_keys_list.dart @@ -433,17 +433,16 @@ class DeviceKeys extends SignableKey { bool? _validSelfSignature; bool get selfSigned => _validSelfSignature ?? - (_validSelfSignature = (deviceId != null && - signatures - ?.tryGetMap(userId) - ?.tryGet('ed25519:$deviceId') == - null - ? false + (_validSelfSignature = deviceId != null && + signatures + ?.tryGetMap(userId) + ?.tryGet('ed25519:$deviceId') != + null && // without libolm we still want to be able to add devices. In that case we ofc just can't // verify the signature - : _verifySignature( + _verifySignature( ed25519Key!, signatures![userId]!['ed25519:$deviceId']!, - isSignatureWithoutLibolmValid: true))); + isSignatureWithoutLibolmValid: true)); @override bool get blocked => super.blocked || !selfSigned; @@ -505,7 +504,7 @@ class DeviceKeys extends SignableKey { lastActive = DateTime.fromMillisecondsSinceEpoch(0); } - KeyVerification startVerification() { + Future startVerification() async { if (!isValid) { throw Exception('setVerification called on invalid key'); } @@ -517,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; } diff --git a/lib/src/utils/native_implementations.dart b/lib/src/utils/native_implementations.dart index 9faf431c8..48b840693 100644 --- a/lib/src/utils/native_implementations.dart +++ b/lib/src/utils/native_implementations.dart @@ -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]; diff --git a/lib/src/utils/run_in_root.dart b/lib/src/utils/run_in_root.dart index 614a0db0a..c19eb6695 100644 --- a/lib/src/utils/run_in_root.dart +++ b/lib/src/utils/run_in_root.dart @@ -20,13 +20,13 @@ import 'dart:async'; import 'package:matrix/matrix.dart'; -Future runInRoot(FutureOr Function() fn) async { - return await Zone.root.run(() async { +void runInRoot(FutureOr 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; }); } diff --git a/lib/src/utils/uia_request.dart b/lib/src/utils/uia_request.dart index 7f1f0dffb..9cad2e634 100644 --- a/lib/src/utils/uia_request.dart +++ b/lib/src/utils/uia_request.dart @@ -52,6 +52,7 @@ class UiaRequest { } UiaRequest({this.onUpdate, required this.request}) { + // ignore: discarded_futures _run(); } diff --git a/lib/src/utils/web_worker/native_implementations_web_worker.dart b/lib/src/utils/web_worker/native_implementations_web_worker.dart index 24a26fc2f..8672d43dc 100644 --- a/lib/src/utils/web_worker/native_implementations_web_worker.dart +++ b/lib/src/utils/web_worker/native_implementations_web_worker.dart @@ -37,7 +37,7 @@ class NativeImplementationsWebWorker extends NativeImplementations { return completer.future.timeout(timeout); } - void _handleIncomingMessage(MessageEvent event) { + Future _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); diff --git a/lib/src/voip/call.dart b/lib/src/voip/call.dart index e71cc42c5..f08e3ce20 100644 --- a/lib/src/voip/call.dart +++ b/lib/src/voip/call.dart @@ -522,17 +522,18 @@ class CallSession { await gotCallFeedsForAnswer(callFeeds); } - void replacedBy(CallSession newCall) { + Future 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); } @@ -698,7 +699,7 @@ class CallSession { Logs().i( 'Stream purpose update: \nid = "$streamId", \npurpose = "${sdpStreamMetadata.purpose}", \naudio_muted = ${sdpStreamMetadata.audio_muted}, \nvideo_muted = ${sdpStreamMetadata.video_muted}'); }); - getRemoteStreams.forEach((wpstream) { + for (final wpstream in getRemoteStreams) { final streamId = wpstream.stream!.id; final purpose = metadata.sdpStreamMetadatas[streamId]; if (purpose != null) { @@ -712,7 +713,7 @@ class CallSession { wpstream.stopped = true; fireCallEvent(CallEvent.kFeedsChanged); } - }); + } } Future onSDPStreamMetadataReceived(SDPStreamMetadata metadata) async { @@ -1510,17 +1511,18 @@ class CallSession { return pc; } - void createDataChannel(String label, RTCDataChannelInit dataChannelDict) { - pc?.createDataChannel(label, dataChannelDict); + Future createDataChannel( + String label, RTCDataChannelInit dataChannelDict) async { + await pc?.createDataChannel(label, dataChannelDict); } Future tryRemoveStopedStreams() async { final removedStreams = {}; - streams.forEach((stream) { + for (final stream in streams) { if (stream.stopped) { removedStreams[stream.stream!.id] = stream; } - }); + } streams .removeWhere((stream) => removedStreams.containsKey(stream.stream!.id)); for (final element in removedStreams.entries) { @@ -1561,9 +1563,9 @@ class CallSession { try { if (candidatesQueue.isNotEmpty) { final candidates = >[]; - candidatesQueue.forEach((element) { + for (final element in candidatesQueue) { candidates.add(element.toMap()); - }); + } localCandidates = []; final res = await sendCallCandidates( opts.room, callId, localPartyId, candidates); diff --git a/lib/src/voip/conn_tester.dart b/lib/src/voip/conn_tester.dart index 2e00eb13d..889334dc5 100644 --- a/lib/src/voip/conn_tester.dart +++ b/lib/src/voip/conn_tester.dart @@ -45,11 +45,15 @@ class ConnectionTester { await pc1!.setRemoteDescription(answer); - void dispose() { - pc1!.close(); - pc1!.dispose(); - pc2!.close(); - pc2!.dispose(); + Future 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; } diff --git a/lib/src/voip/group_call.dart b/lib/src/voip/group_call.dart index 272b16a99..b6fe62ace 100644 --- a/lib/src/voip/group_call.dart +++ b/lib/src/voip/group_call.dart @@ -150,8 +150,9 @@ class IGroupCallRoomMemberState { List calls = []; IGroupCallRoomMemberState.fromJson(MatrixEvent event) { if (event.content['m.calls'] != null) { - (event.content['m.calls'] as List).forEach( - (call) => calls.add(IGroupCallRoomMemberCallState.fromJson(call))); + for (final call in (event.content['m.calls'] as List)) { + calls.add(IGroupCallRoomMemberCallState.fromJson(call)); + } } } } @@ -231,11 +232,11 @@ class GroupCall { this.groupCallId = groupCallId ?? genCallID(); } - GroupCall create() { + Future create() async { voip.groupCalls[groupCallId] = this; voip.groupCalls[room.id] = this; - client.setRoomStateWithKey( + await client.setRoomStateWithKey( room.id, EventTypes.GroupCallPrefix, groupCallId, @@ -276,12 +277,12 @@ class GroupCall { final List events = []; final roomStates = await client.getRoomState(room.id); roomStates.sort((a, b) => a.originServerTs.compareTo(b.originServerTs)); - roomStates.forEach((value) { + for (final value in roomStates) { if (value.type == EventTypes.GroupCallMemberPrefix && !room.callMemberStateIsExpired(value, groupCallId)) { events.add(value); } - }); + } return events; } @@ -412,6 +413,7 @@ class GroupCall { if (localUserMediaStream != null) { final oldStream = localUserMediaStream!.stream; localUserMediaStream!.setNewStream(stream.stream!); + // ignore: discarded_futures stopMediaStream(oldStream); } } diff --git a/lib/src/voip/utils.dart b/lib/src/voip/utils.dart index 037da1ecb..182843e22 100644 --- a/lib/src/voip/utils.dart +++ b/lib/src/voip/utils.dart @@ -23,9 +23,9 @@ Future stopMediaStream(MediaStream? stream) async { } void setTracksEnabled(List tracks, bool enabled) { - tracks.forEach((element) { + for (final element in tracks) { element.enabled = enabled; - }); + } } Future hasAudioDevice() async { diff --git a/lib/src/voip/voip.dart b/lib/src/voip/voip.dart index 2d6d93463..22a6a1650 100644 --- a/lib/src/voip/voip.dart +++ b/lib/src/voip/voip.dart @@ -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, diff --git a/test/client_test.dart b/test/client_test.dart index a63f3fecc..295ea3917 100644 --- a/test/client_test.dart +++ b/test/client_test.dart @@ -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); }); }); } diff --git a/test/database_api_test.dart b/test/database_api_test.dart index 9d096fe8c..ff1723978 100644 --- a/test/database_api_test.dart +++ b/test/database_api_test.dart @@ -28,9 +28,450 @@ import 'fake_database.dart'; void main() { group('HiveCollections Database Test', () { - testDatabase( - getHiveCollectionsDatabase(null), - ); + late DatabaseApi database; + late int toDeviceQueueIndex; + test('Open', () async { + database = await getHiveCollectionsDatabase(null); + }); + test('transaction', () async { + var counter = 0; + await database.transaction(() async { + expect(counter++, 0); + await database.transaction(() async { + expect(counter++, 1); + await Future.delayed(Duration(milliseconds: 50)); + expect(counter++, 2); + }); + expect(counter++, 3); + }); + }); + test('insertIntoToDeviceQueue', () async { + toDeviceQueueIndex = await database.insertIntoToDeviceQueue( + 'm.test', + 'txnId', + '{"foo":"bar"}', + ); + }); + test('getToDeviceEventQueue', () async { + final toDeviceQueue = await database.getToDeviceEventQueue(); + expect(toDeviceQueue.first.type, 'm.test'); + }); + test('deleteFromToDeviceQueue', () async { + await database.deleteFromToDeviceQueue(toDeviceQueueIndex); + final toDeviceQueue = await database.getToDeviceEventQueue(); + expect(toDeviceQueue.isEmpty, true); + }); + test('storeFile', () async { + await database.storeFile( + Uri.parse('mxc://test'), Uint8List.fromList([0]), 0); + final file = await database.getFile(Uri.parse('mxc://test')); + expect(file != null, database.supportsFileStoring); + }); + test('getFile', () async { + await database.getFile(Uri.parse('mxc://test')); + }); + test('deleteOldFiles', () async { + await database.deleteOldFiles(1); + final file = await database.getFile(Uri.parse('mxc://test')); + expect(file == null, true); + }); + test('storeRoomUpdate', () async { + final roomUpdate = JoinedRoomUpdate.fromJson({ + 'highlight_count': 0, + 'notification_count': 0, + 'limited_timeline': false, + 'membership': Membership.join, + }); + final client = Client('testclient'); + await database.storeRoomUpdate('!testroom', roomUpdate, client); + final rooms = await database.getRoomList(client); + expect(rooms.single.id, '!testroom'); + }); + test('getRoomList', () async { + final room = + await database.getSingleRoom(Client('testclient'), '!testroom'); + expect(room?.id, '!testroom'); + }); + test('getRoomList', () async { + final list = await database.getRoomList(Client('testclient')); + expect(list.single.id, '!testroom'); + }); + test('setRoomPrevBatch', () async { + final client = Client('testclient'); + await database.setRoomPrevBatch('1234', '!testroom', client); + final rooms = await database.getRoomList(client); + expect(rooms.single.prev_batch, '1234'); + }); + test('forgetRoom', () async { + await database.forgetRoom('!testroom'); + final rooms = await database.getRoomList(Client('testclient')); + expect(rooms.isEmpty, true); + }); + test('getClient', () async { + await database.getClient('name'); + }); + test('insertClient', () async { + await database.insertClient( + 'name', + 'homeserverUrl', + 'token', + 'userId', + 'deviceId', + 'deviceName', + 'prevBatch', + 'olmAccount', + ); + + final client = await database.getClient('name'); + expect(client?['token'], 'token'); + }); + test('updateClient', () async { + await database.updateClient( + 'homeserverUrl', + 'token_different', + 'userId', + 'deviceId', + 'deviceName', + 'prevBatch', + 'olmAccount', + ); + final client = await database.getClient('name'); + expect(client?['token'], 'token_different'); + }); + test('updateClientKeys', () async { + await database.updateClientKeys( + 'olmAccount2', + ); + final client = await database.getClient('name'); + expect(client?['olm_account'], 'olmAccount2'); + }); + test('storeSyncFilterId', () async { + await database.storeSyncFilterId( + '1234', + ); + final client = await database.getClient('name'); + expect(client?['sync_filter_id'], '1234'); + }); + test('getAccountData', () async { + await database.getAccountData(); + }); + test('storeAccountData', () async { + await database.storeAccountData('m.test', '{"foo":"bar"}'); + final events = await database.getAccountData(); + expect(events.values.single.type, 'm.test'); + + await database.storeAccountData('m.abc+de', '{"foo":"bar"}'); + final events2 = await database.getAccountData(); + expect(events2.values.any((element) => element.type == 'm.abc+de'), true); + }); + test('storeEventUpdate', () async { + await database.storeEventUpdate( + EventUpdate( + roomID: '!testroom:example.com', + type: EventUpdateType.timeline, + content: { + 'type': EventTypes.Message, + 'content': { + 'body': '* edit 3', + 'msgtype': 'm.text', + 'm.new_content': { + 'body': 'edit 3', + 'msgtype': 'm.text', + }, + 'm.relates_to': { + 'event_id': '\$source', + 'rel_type': RelationshipTypes.edit, + }, + }, + 'event_id': '\$event:example.com', + 'sender': '@bob:example.org', + }, + ), + Client('testclient')); + }); + test('getEventById', () async { + final event = await database.getEventById('\$event:example.com', + Room(id: '!testroom:example.com', client: Client('testclient'))); + expect(event?.type, EventTypes.Message); + }); + test('getEventList', () async { + final events = await database.getEventList( + Room(id: '!testroom:example.com', client: Client('testclient')), + ); + expect(events.single.type, EventTypes.Message); + }); + test('getUser', () async { + final user = await database.getUser('@bob:example.org', + Room(id: '!testroom:example.com', client: Client('testclient'))); + expect(user, null); + }); + test('getUsers', () async { + final users = await database.getUsers( + Room(id: '!testroom:example.com', client: Client('testclient'))); + expect(users.isEmpty, true); + }); + test('removeEvent', () async { + await database.removeEvent( + '\$event:example.com', '!testroom:example.com'); + final event = await database.getEventById('\$event:example.com', + Room(id: '!testroom:example.com', client: Client('testclient'))); + expect(event, null); + }); + test('getAllInboundGroupSessions', () async { + final result = await database.getAllInboundGroupSessions(); + expect(result.isEmpty, true); + }); + test('getInboundGroupSession', () async { + await database.getInboundGroupSession( + '!testroom:example.com', 'sessionId'); + }); + test('getInboundGroupSessionsToUpload', () async { + await database.getInboundGroupSessionsToUpload(); + }); + test('storeInboundGroupSession', () async { + await database.storeInboundGroupSession( + '!testroom:example.com', + 'sessionId', + 'pickle', + '{"foo":"bar"}', + '{}', + '{}', + 'senderKey', + '{}', + ); + final session = await database.getInboundGroupSession( + '!testroom:example.com', + 'sessionId', + ); + expect(jsonDecode(session!.content)['foo'], 'bar'); + }); + test('markInboundGroupSessionAsUploaded', () async { + await database.markInboundGroupSessionAsUploaded( + '!testroom:example.com', 'sessionId'); + }); + test('markInboundGroupSessionsAsNeedingUpload', () async { + await database.markInboundGroupSessionsAsNeedingUpload(); + }); + test('updateInboundGroupSessionAllowedAtIndex', () async { + await database.updateInboundGroupSessionAllowedAtIndex( + '{}', + '!testroom:example.com', + 'sessionId', + ); + }); + test('updateInboundGroupSessionIndexes', () async { + await database.updateInboundGroupSessionIndexes( + '{}', + '!testroom:example.com', + 'sessionId', + ); + }); + test('getSSSSCache', () async { + final cache = await database.getSSSSCache('type'); + expect(cache, null); + }); + test('storeSSSSCache', () async { + await database.storeSSSSCache('type', 'keyId', 'ciphertext', '{}'); + final cache = (await database.getSSSSCache('type'))!; + expect(cache.type, 'type'); + expect(cache.keyId, 'keyId'); + expect(cache.ciphertext, 'ciphertext'); + expect(cache.content, '{}'); + }); + test('getOlmSessions', () async { + final olm = await database.getOlmSessions( + 'identityKey', + 'userId', + ); + expect(olm.isEmpty, true); + }); + test('getAllOlmSessions', () async { + var sessions = await database.getAllOlmSessions(); + expect(sessions.isEmpty, true); + await database.storeOlmSession( + 'identityKey', + 'sessionId', + 'pickle', + 0, + ); + await database.storeOlmSession( + 'identityKey', + 'sessionId2', + 'pickle', + 0, + ); + sessions = await database.getAllOlmSessions(); + expect( + sessions, + { + 'identityKey': { + 'sessionId': { + 'identity_key': 'identityKey', + 'pickle': 'pickle', + 'session_id': 'sessionId', + 'last_received': 0 + }, + 'sessionId2': { + 'identity_key': 'identityKey', + 'pickle': 'pickle', + 'session_id': 'sessionId2', + 'last_received': 0 + } + } + }, + ); + }); + test('getOlmSessionsForDevices', () async { + final olm = await database.getOlmSessionsForDevices( + ['identityKeys'], + 'userId', + ); + expect(olm.isEmpty, true); + }); + test('storeOlmSession', () async { + if (!(await olmEnabled())) return; + await database.storeOlmSession( + 'identityKey', + 'sessionId', + 'pickle', + 0, + ); + final olm = await database.getOlmSessions( + 'identityKey', + 'userId', + ); + expect(olm.isNotEmpty, true); + }); + test('getOutboundGroupSession', () async { + final session = await database.getOutboundGroupSession( + '!testroom:example.com', + '@alice:example.com', + ); + expect(session, null); + }); + test('storeOutboundGroupSession', () async { + if (!(await olmEnabled())) return; + await database.storeOutboundGroupSession( + '!testroom:example.com', + 'pickle', + '{}', + 0, + ); + final session = await database.getOutboundGroupSession( + '!testroom:example.com', + '@alice:example.com', + ); + expect(session?.devices.isEmpty, true); + }); + test('getLastSentMessageUserDeviceKey', () async { + final list = await database.getLastSentMessageUserDeviceKey( + 'userId', + 'deviceId', + ); + expect(list.isEmpty, true); + }); + test('getUnimportantRoomEventStatesForRoom', () async { + final events = await database.getUnimportantRoomEventStatesForRoom( + ['events'], + Room(id: '!mep', client: Client('testclient')), + ); + expect(events.isEmpty, true); + }); + test('getUserDeviceKeys', () async { + await database.getUserDeviceKeys(Client('testclient')); + }); + test('storeUserCrossSigningKey', () async { + await database.storeUserCrossSigningKey( + '@alice:example.com', + 'publicKey', + '{}', + false, + false, + ); + }); + test('setVerifiedUserCrossSigningKey', () async { + await database.setVerifiedUserCrossSigningKey( + true, + '@alice:example.com', + 'publicKey', + ); + }); + test('setBlockedUserCrossSigningKey', () async { + await database.setBlockedUserCrossSigningKey( + true, + '@alice:example.com', + 'publicKey', + ); + }); + test('removeUserCrossSigningKey', () async { + await database.removeUserCrossSigningKey( + '@alice:example.com', + 'publicKey', + ); + }); + test('storeUserDeviceKeysInfo', () async { + await database.storeUserDeviceKeysInfo( + '@alice:example.com', + true, + ); + }); + test('storeUserDeviceKey', () async { + await database.storeUserDeviceKey( + '@alice:example.com', + 'deviceId', + '{}', + false, + false, + 0, + ); + }); + test('setVerifiedUserDeviceKey', () async { + await database.setVerifiedUserDeviceKey( + true, + '@alice:example.com', + 'deviceId', + ); + }); + test('setBlockedUserDeviceKey', () async { + await database.setBlockedUserDeviceKey( + true, + '@alice:example.com', + 'deviceId', + ); + }); + test('getStorePresences', () async { + const userId = '@alice:example.com'; + final presence = CachedPresence( + PresenceType.online, + 100, + 'test message', + true, + '@alice:example.com', + ); + await database.storePresence( + userId, + presence, + ); + final storedPresence = await database.getPresence(userId); + expect( + presence.toJson(), + storedPresence?.toJson(), + ); + }); + + // Clearing up from here + test('clearSSSSCache', () async { + await database.clearSSSSCache(); + }); + test('clearCache', () async { + await database.clearCache(); + }); + test('clear', () async { + await database.clear(); + }); + test('Close', () async { + await database.close(); + }); }); } @@ -44,451 +485,3 @@ Future olmEnabled() async { } return olmEnabled; } - -void testDatabase( - Future futureDatabase, -) { - late DatabaseApi database; - late int toDeviceQueueIndex; - test('Open', () async { - database = await futureDatabase; - }); - test('transaction', () async { - var counter = 0; - await database.transaction(() async { - expect(counter++, 0); - await database.transaction(() async { - expect(counter++, 1); - await Future.delayed(Duration(milliseconds: 50)); - expect(counter++, 2); - }); - expect(counter++, 3); - }); - }); - test('insertIntoToDeviceQueue', () async { - toDeviceQueueIndex = await database.insertIntoToDeviceQueue( - 'm.test', - 'txnId', - '{"foo":"bar"}', - ); - }); - test('getToDeviceEventQueue', () async { - final toDeviceQueue = await database.getToDeviceEventQueue(); - expect(toDeviceQueue.first.type, 'm.test'); - }); - test('deleteFromToDeviceQueue', () async { - await database.deleteFromToDeviceQueue(toDeviceQueueIndex); - final toDeviceQueue = await database.getToDeviceEventQueue(); - expect(toDeviceQueue.isEmpty, true); - }); - test('storeFile', () async { - await database.storeFile( - Uri.parse('mxc://test'), Uint8List.fromList([0]), 0); - final file = await database.getFile(Uri.parse('mxc://test')); - expect(file != null, database.supportsFileStoring); - }); - test('getFile', () async { - await database.getFile(Uri.parse('mxc://test')); - }); - test('deleteOldFiles', () async { - await database.deleteOldFiles(1); - final file = await database.getFile(Uri.parse('mxc://test')); - expect(file == null, true); - }); - test('storeRoomUpdate', () async { - final roomUpdate = JoinedRoomUpdate.fromJson({ - 'highlight_count': 0, - 'notification_count': 0, - 'limited_timeline': false, - 'membership': Membership.join, - }); - final client = Client('testclient'); - await database.storeRoomUpdate('!testroom', roomUpdate, client); - final rooms = await database.getRoomList(client); - expect(rooms.single.id, '!testroom'); - }); - test('getRoomList', () async { - final room = - await database.getSingleRoom(Client('testclient'), '!testroom'); - expect(room?.id, '!testroom'); - }); - test('getRoomList', () async { - final list = await database.getRoomList(Client('testclient')); - expect(list.single.id, '!testroom'); - }); - test('setRoomPrevBatch', () async { - final client = Client('testclient'); - await database.setRoomPrevBatch('1234', '!testroom', client); - final rooms = await database.getRoomList(client); - expect(rooms.single.prev_batch, '1234'); - }); - test('forgetRoom', () async { - await database.forgetRoom('!testroom'); - final rooms = await database.getRoomList(Client('testclient')); - expect(rooms.isEmpty, true); - }); - test('getClient', () async { - await database.getClient('name'); - }); - test('insertClient', () async { - await database.insertClient( - 'name', - 'homeserverUrl', - 'token', - 'userId', - 'deviceId', - 'deviceName', - 'prevBatch', - 'olmAccount', - ); - - final client = await database.getClient('name'); - expect(client?['token'], 'token'); - }); - test('updateClient', () async { - await database.updateClient( - 'homeserverUrl', - 'token_different', - 'userId', - 'deviceId', - 'deviceName', - 'prevBatch', - 'olmAccount', - ); - final client = await database.getClient('name'); - expect(client?['token'], 'token_different'); - }); - test('updateClientKeys', () async { - await database.updateClientKeys( - 'olmAccount2', - ); - final client = await database.getClient('name'); - expect(client?['olm_account'], 'olmAccount2'); - }); - test('storeSyncFilterId', () async { - await database.storeSyncFilterId( - '1234', - ); - final client = await database.getClient('name'); - expect(client?['sync_filter_id'], '1234'); - }); - test('getAccountData', () async { - await database.getAccountData(); - }); - test('storeAccountData', () async { - await database.storeAccountData('m.test', '{"foo":"bar"}'); - final events = await database.getAccountData(); - expect(events.values.single.type, 'm.test'); - - await database.storeAccountData('m.abc+de', '{"foo":"bar"}'); - final events2 = await database.getAccountData(); - expect(events2.values.any((element) => element.type == 'm.abc+de'), true); - }); - test('storeEventUpdate', () async { - await database.storeEventUpdate( - EventUpdate( - roomID: '!testroom:example.com', - type: EventUpdateType.timeline, - content: { - 'type': EventTypes.Message, - 'content': { - 'body': '* edit 3', - 'msgtype': 'm.text', - 'm.new_content': { - 'body': 'edit 3', - 'msgtype': 'm.text', - }, - 'm.relates_to': { - 'event_id': '\$source', - 'rel_type': RelationshipTypes.edit, - }, - }, - 'event_id': '\$event:example.com', - 'sender': '@bob:example.org', - }, - ), - Client('testclient')); - }); - test('getEventById', () async { - final event = await database.getEventById('\$event:example.com', - Room(id: '!testroom:example.com', client: Client('testclient'))); - expect(event?.type, EventTypes.Message); - }); - test('getEventList', () async { - final events = await database.getEventList( - Room(id: '!testroom:example.com', client: Client('testclient')), - ); - expect(events.single.type, EventTypes.Message); - }); - test('getUser', () async { - final user = await database.getUser('@bob:example.org', - Room(id: '!testroom:example.com', client: Client('testclient'))); - expect(user, null); - }); - test('getUsers', () async { - final users = await database.getUsers( - Room(id: '!testroom:example.com', client: Client('testclient'))); - expect(users.isEmpty, true); - }); - test('removeEvent', () async { - await database.removeEvent('\$event:example.com', '!testroom:example.com'); - final event = await database.getEventById('\$event:example.com', - Room(id: '!testroom:example.com', client: Client('testclient'))); - expect(event, null); - }); - test('getAllInboundGroupSessions', () async { - final result = await database.getAllInboundGroupSessions(); - expect(result.isEmpty, true); - }); - test('getInboundGroupSession', () async { - await database.getInboundGroupSession('!testroom:example.com', 'sessionId'); - }); - test('getInboundGroupSessionsToUpload', () async { - await database.getInboundGroupSessionsToUpload(); - }); - test('storeInboundGroupSession', () async { - await database.storeInboundGroupSession( - '!testroom:example.com', - 'sessionId', - 'pickle', - '{"foo":"bar"}', - '{}', - '{}', - 'senderKey', - '{}', - ); - final session = await database.getInboundGroupSession( - '!testroom:example.com', - 'sessionId', - ); - expect(jsonDecode(session!.content)['foo'], 'bar'); - }); - test('markInboundGroupSessionAsUploaded', () async { - await database.markInboundGroupSessionAsUploaded( - '!testroom:example.com', 'sessionId'); - }); - test('markInboundGroupSessionsAsNeedingUpload', () async { - await database.markInboundGroupSessionsAsNeedingUpload(); - }); - test('updateInboundGroupSessionAllowedAtIndex', () async { - await database.updateInboundGroupSessionAllowedAtIndex( - '{}', - '!testroom:example.com', - 'sessionId', - ); - }); - test('updateInboundGroupSessionIndexes', () async { - await database.updateInboundGroupSessionIndexes( - '{}', - '!testroom:example.com', - 'sessionId', - ); - }); - test('getSSSSCache', () async { - final cache = await database.getSSSSCache('type'); - expect(cache, null); - }); - test('storeSSSSCache', () async { - await database.storeSSSSCache('type', 'keyId', 'ciphertext', '{}'); - final cache = (await database.getSSSSCache('type'))!; - expect(cache.type, 'type'); - expect(cache.keyId, 'keyId'); - expect(cache.ciphertext, 'ciphertext'); - expect(cache.content, '{}'); - }); - test('getOlmSessions', () async { - final olm = await database.getOlmSessions( - 'identityKey', - 'userId', - ); - expect(olm.isEmpty, true); - }); - test('getAllOlmSessions', () async { - var sessions = await database.getAllOlmSessions(); - expect(sessions.isEmpty, true); - await database.storeOlmSession( - 'identityKey', - 'sessionId', - 'pickle', - 0, - ); - await database.storeOlmSession( - 'identityKey', - 'sessionId2', - 'pickle', - 0, - ); - sessions = await database.getAllOlmSessions(); - expect( - sessions, - { - 'identityKey': { - 'sessionId': { - 'identity_key': 'identityKey', - 'pickle': 'pickle', - 'session_id': 'sessionId', - 'last_received': 0 - }, - 'sessionId2': { - 'identity_key': 'identityKey', - 'pickle': 'pickle', - 'session_id': 'sessionId2', - 'last_received': 0 - } - } - }, - ); - }); - test('getOlmSessionsForDevices', () async { - final olm = await database.getOlmSessionsForDevices( - ['identityKeys'], - 'userId', - ); - expect(olm.isEmpty, true); - }); - test('storeOlmSession', () async { - if (!(await olmEnabled())) return; - await database.storeOlmSession( - 'identityKey', - 'sessionId', - 'pickle', - 0, - ); - final olm = await database.getOlmSessions( - 'identityKey', - 'userId', - ); - expect(olm.isNotEmpty, true); - }); - test('getOutboundGroupSession', () async { - final session = await database.getOutboundGroupSession( - '!testroom:example.com', - '@alice:example.com', - ); - expect(session, null); - }); - test('storeOutboundGroupSession', () async { - if (!(await olmEnabled())) return; - await database.storeOutboundGroupSession( - '!testroom:example.com', - 'pickle', - '{}', - 0, - ); - final session = await database.getOutboundGroupSession( - '!testroom:example.com', - '@alice:example.com', - ); - expect(session?.devices.isEmpty, true); - }); - test('getLastSentMessageUserDeviceKey', () async { - final list = await database.getLastSentMessageUserDeviceKey( - 'userId', - 'deviceId', - ); - expect(list.isEmpty, true); - }); - test('getUnimportantRoomEventStatesForRoom', () async { - final events = await database.getUnimportantRoomEventStatesForRoom( - ['events'], - Room(id: '!mep', client: Client('testclient')), - ); - expect(events.isEmpty, true); - }); - test('getUserDeviceKeys', () async { - await database.getUserDeviceKeys(Client('testclient')); - }); - test('storeUserCrossSigningKey', () async { - await database.storeUserCrossSigningKey( - '@alice:example.com', - 'publicKey', - '{}', - false, - false, - ); - }); - test('setVerifiedUserCrossSigningKey', () async { - await database.setVerifiedUserCrossSigningKey( - true, - '@alice:example.com', - 'publicKey', - ); - }); - test('setBlockedUserCrossSigningKey', () async { - await database.setBlockedUserCrossSigningKey( - true, - '@alice:example.com', - 'publicKey', - ); - }); - test('removeUserCrossSigningKey', () async { - await database.removeUserCrossSigningKey( - '@alice:example.com', - 'publicKey', - ); - }); - test('storeUserDeviceKeysInfo', () async { - await database.storeUserDeviceKeysInfo( - '@alice:example.com', - true, - ); - }); - test('storeUserDeviceKey', () async { - await database.storeUserDeviceKey( - '@alice:example.com', - 'deviceId', - '{}', - false, - false, - 0, - ); - }); - test('setVerifiedUserDeviceKey', () async { - await database.setVerifiedUserDeviceKey( - true, - '@alice:example.com', - 'deviceId', - ); - }); - test('setBlockedUserDeviceKey', () async { - await database.setBlockedUserDeviceKey( - true, - '@alice:example.com', - 'deviceId', - ); - }); - test('getStorePresences', () async { - const userId = '@alice:example.com'; - final presence = CachedPresence( - PresenceType.online, - 100, - 'test message', - true, - '@alice:example.com', - ); - await database.storePresence( - userId, - presence, - ); - final storedPresence = await database.getPresence(userId); - expect( - presence.toJson(), - storedPresence?.toJson(), - ); - }); - - // Clearing up from here - test('clearSSSSCache', () async { - await database.clearSSSSCache(); - }); - test('clearCache', () async { - await database.clearCache(); - }); - test('clear', () async { - await database.clear(); - }); - test('Close', () async { - await database.close(); - }); - return; -} diff --git a/test/device_keys_list_test.dart b/test/device_keys_list_test.dart index 36b2ad8e0..69a2498e2 100644 --- a/test/device_keys_list_test.dart +++ b/test/device_keys_list_test.dart @@ -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); diff --git a/test/encryption/key_manager_test.dart b/test/encryption/key_manager_test.dart index dbdf12c13..7110bc751 100644 --- a/test/encryption/key_manager_test.dart +++ b/test/encryption/key_manager_test.dart @@ -123,9 +123,9 @@ void main() { 0); // rotate after too many messages - Iterable.generate(300).forEach((_) { + for (final _ in Iterable.generate(300)) { sess.outboundGroupSession!.encrypt('some string'); - }); + } await client.encryption!.keyManager .clearOrUseOutboundGroupSession(roomId); expect( diff --git a/test/fake_matrix_api.dart b/test/fake_matrix_api.dart index fd64189d3..c48ababe8 100644 --- a/test/fake_matrix_api.dart +++ b/test/fake_matrix_api.dart @@ -260,6 +260,7 @@ class FakeMatrixApi extends BaseClient { } } // and generate a fake sync + // ignore: discarded_futures _client!.handleSync(sdk.SyncUpdate(nextBatch: '')); } return {}; diff --git a/test/room_archived_test.dart b/test/room_archived_test.dart index c99af5abe..6cfa5bd93 100644 --- a/test/room_archived_test.dart +++ b/test/room_archived_test.dart @@ -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 = diff --git a/test/timeline_context_test.dart b/test/timeline_context_test.dart index f62b45c83..e1d07ca67 100644 --- a/test/timeline_context_test.dart +++ b/test/timeline_context_test.dart @@ -38,7 +38,7 @@ void main() { var olmEnabled = true; final countStream = StreamController.broadcast(); - Future waitForCount(int count) { + Future waitForCount(int count) async { if (updateCount == count) { return Future.value(updateCount); } @@ -46,9 +46,9 @@ void main() { final completer = Completer(); StreamSubscription? 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(); diff --git a/test/timeline_test.dart b/test/timeline_test.dart index 97f738975..e7e7c2307 100644 --- a/test/timeline_test.dart +++ b/test/timeline_test.dart @@ -39,7 +39,7 @@ void main() { var currentPoison = 0; final countStream = StreamController.broadcast(); - Future waitForCount(int count) { + Future waitForCount(int count) async { if (updateCount == count) { return Future.value(updateCount); } @@ -47,9 +47,9 @@ void main() { final completer = Completer(); StreamSubscription? 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(