Merge pull request #1597 from famedly/nico/stricter-lints

stricter lints
This commit is contained in:
Nicolas Werner 2023-11-17 14:44:00 +01:00 committed by GitHub
commit ee14fb7116
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 620 additions and 584 deletions

View File

@ -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
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
# 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
unawaited_futures: true
unsafe_html: true
avoid_function_literals_in_foreach_calls: false
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:

View File

@ -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) {

View File

@ -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();

View File

@ -396,8 +396,8 @@ 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 {
Future<void> updateSessionUsage([OlmSession? session]) async {
try {
if (session != null) {
session.lastReceived = DateTime.now();
await storeOlmSession(session);
@ -409,7 +409,11 @@ class OlmManager {
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(
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(
try {
await encryption.olmDatabase?.setLastSentMessageUserDeviceKey(
json.encode({
'type': type,
'content': payload,
}),
device.userId,
device.deviceId!));
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,

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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<String, int> 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++) {

View File

@ -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();
}

View File

@ -433,17 +433,16 @@ class DeviceKeys extends SignableKey {
bool? _validSelfSignature;
bool get selfSigned =>
_validSelfSignature ??
(_validSelfSignature = (deviceId != null &&
(_validSelfSignature = deviceId != null &&
signatures
?.tryGetMap<String, Object?>(userId)
?.tryGet<String>('ed25519:$deviceId') ==
null
? false
?.tryGet<String>('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<KeyVerification> 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;
}

View File

@ -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];

View File

@ -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;
});
}

View File

@ -52,6 +52,7 @@ class UiaRequest<T> {
}
UiaRequest({this.onUpdate, required this.request}) {
// ignore: discarded_futures
_run();
}

View File

@ -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(
final stackTrace =
await onStackTrace.call(event.data['stacktrace'] as String);
completer?.completeError(
WebWorkerError(error: error, stackTrace: stackTrace),
),
);
} else {
final response = WebWorkerData.fromJson(event.data);

View File

@ -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);
}
@ -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<void> onSDPStreamMetadataReceived(SDPStreamMetadata metadata) async {
@ -1510,17 +1511,18 @@ 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 {
final removedStreams = <String, WrappedMediaStream>{};
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 = <Map<String, dynamic>>[];
candidatesQueue.forEach((element) {
for (final element in candidatesQueue) {
candidates.add(element.toMap());
});
}
localCandidates = [];
final res = await sendCallCandidates(
opts.room, callId, localPartyId, candidates);

View File

@ -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;
}

View File

@ -150,8 +150,9 @@ class IGroupCallRoomMemberState {
List<IGroupCallRoomMemberCallState> calls = [];
IGroupCallRoomMemberState.fromJson(MatrixEvent event) {
if (event.content['m.calls'] != null) {
(event.content['m.calls'] as List<dynamic>).forEach(
(call) => calls.add(IGroupCallRoomMemberCallState.fromJson(call)));
for (final call in (event.content['m.calls'] as List<dynamic>)) {
calls.add(IGroupCallRoomMemberCallState.fromJson(call));
}
}
}
}
@ -231,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,
@ -276,12 +277,12 @@ class GroupCall {
final List<MatrixEvent> 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);
}
}

View File

@ -23,9 +23,9 @@ Future<void> stopMediaStream(MediaStream? stream) async {
}
void setTracksEnabled(List<MediaStreamTrack> tracks, bool enabled) {
tracks.forEach((element) {
for (final element in tracks) {
element.enabled = enabled;
});
}
}
Future<bool> hasAudioDevice() async {

View File

@ -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,

View File

@ -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);
});
});
}

View File

@ -28,30 +28,10 @@ import 'fake_database.dart';
void main() {
group('HiveCollections Database Test', () {
testDatabase(
getHiveCollectionsDatabase(null),
);
});
}
Future<bool> olmEnabled() async {
var olmEnabled = true;
try {
await olm.init();
olm.get_library_version();
} catch (e) {
olmEnabled = false;
}
return olmEnabled;
}
void testDatabase(
Future<DatabaseApi> futureDatabase,
) {
late DatabaseApi database;
late int toDeviceQueueIndex;
test('Open', () async {
database = await futureDatabase;
database = await getHiveCollectionsDatabase(null);
});
test('transaction', () async {
var counter = 0;
@ -231,7 +211,8 @@ void testDatabase(
expect(users.isEmpty, true);
});
test('removeEvent', () async {
await database.removeEvent('\$event:example.com', '!testroom:example.com');
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);
@ -241,7 +222,8 @@ void testDatabase(
expect(result.isEmpty, true);
});
test('getInboundGroupSession', () async {
await database.getInboundGroupSession('!testroom:example.com', 'sessionId');
await database.getInboundGroupSession(
'!testroom:example.com', 'sessionId');
});
test('getInboundGroupSessionsToUpload', () async {
await database.getInboundGroupSessionsToUpload();
@ -490,5 +472,16 @@ void testDatabase(
test('Close', () async {
await database.close();
});
return;
});
}
Future<bool> olmEnabled() async {
var olmEnabled = true;
try {
await olm.init();
olm.get_library_version();
} catch (e) {
olmEnabled = false;
}
return olmEnabled;
}

View File

@ -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);

View File

@ -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(

View File

@ -260,6 +260,7 @@ class FakeMatrixApi extends BaseClient {
}
}
// and generate a fake sync
// ignore: discarded_futures
_client!.handleSync(sdk.SyncUpdate(nextBatch: ''));
}
return {};

View File

@ -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 =

View File

@ -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();

View File

@ -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(