Skip to content

Commit

Permalink
fix: fix ConcurrentModificationError when and are called ynchronously…
Browse files Browse the repository at this point in the history
… but without keyword
  • Loading branch information
littleGnAl committed Feb 16, 2023
1 parent 2f393b9 commit 4f5058d
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 10 deletions.
6 changes: 0 additions & 6 deletions lib/src/iris_method_channel.dart
Expand Up @@ -548,12 +548,6 @@ class IrisMethodChannel {
),
));

subScopedObjects?.remove(eventKey);

if (subScopedObjects?.keys.isEmpty == true) {
scopedEventHandlers.remove(scopedEvent.scopedKey);
}

return result;
}
}
Expand Down
162 changes: 158 additions & 4 deletions test/iris_method_channel_test.dart
Expand Up @@ -313,9 +313,13 @@ void main() {
handler: eventHandler),
jsonEncode({}));

final DisposableScopedObjects? subScopedObjects =
irisMethodChannel.scopedEventHandlers.get(key);
expect(subScopedObjects, isNull);
final DisposableScopedObjects subScopedObjects =
irisMethodChannel.scopedEventHandlers.get(key)!;
expect(subScopedObjects.keys.length, 1);

final EventHandlerHolder holder =
subScopedObjects.values.elementAt(0) as EventHandlerHolder;
expect(holder.getEventHandlers().length, 0);

final registerEventHandlerCallRecord = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'unregisterEventHandler');
Expand Down Expand Up @@ -532,7 +536,7 @@ void main() {

final DisposableScopedObjects subScopedObjects =
irisMethodChannel.scopedEventHandlers.get(key)!;
expect(subScopedObjects.keys.length, 1);
expect(subScopedObjects.keys.length, 2);

final holder = subScopedObjects.values.elementAt(0) as EventHandlerHolder;

Expand All @@ -541,10 +545,160 @@ void main() {
expect(holder.getEventHandlers().length, 1);
expect(holder.getEventHandlers().elementAt(0), eventHandler1);

final holder2 = subScopedObjects.values.elementAt(1) as EventHandlerHolder;

expect(holder2.getEventHandlers().length, 0);

final unregisterEventHandlerCallRecord = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'unregisterEventHandler1');
expect(unregisterEventHandlerCallRecord.length, 1);

await irisMethodChannel.dispose();
});

test(
'registerEventHandler 2 times with different registerName, then unregisterEventHandler, then unregisterEventHandlers',
() async {
final irisMethodChannel = IrisMethodChannel();
await irisMethodChannel.initilize(nativeBindingsProvider);

const key = TypedScopedKey(_TestEventLoopEventHandler);
final eventHandler1 = _TestEventLoopEventHandler();
final eventHandler2 = _TestEventLoopEventHandler();
await irisMethodChannel.registerEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler',
unregisterName: 'unregisterEventHandler',
handler: eventHandler1),
jsonEncode({}));
await irisMethodChannel.registerEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler1',
unregisterName: 'unregisterEventHandler1',
handler: eventHandler2),
jsonEncode({}));

await irisMethodChannel.unregisterEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler1',
unregisterName: 'unregisterEventHandler1',
handler: eventHandler2),
jsonEncode({}));

await irisMethodChannel.unregisterEventHandlers(key);

final DisposableScopedObjects? subScopedObjects =
irisMethodChannel.scopedEventHandlers.get(key);
expect(subScopedObjects, isNull);

final unregisterEventHandlerCallRecord = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'unregisterEventHandler');
expect(unregisterEventHandlerCallRecord.length, 1);

final unregisterEventHandlerCallRecord1 = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'unregisterEventHandler1');
expect(unregisterEventHandlerCallRecord1.length, 1);

await irisMethodChannel.dispose();
});

test(
'registerEventHandler 2 times with different registerName, then unregisterEventHandler without await, then unregisterEventHandlers',
() async {
final irisMethodChannel = IrisMethodChannel();
await irisMethodChannel.initilize(nativeBindingsProvider);

const key = TypedScopedKey(_TestEventLoopEventHandler);
final eventHandler1 = _TestEventLoopEventHandler();
final eventHandler2 = _TestEventLoopEventHandler();
await irisMethodChannel.registerEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler',
unregisterName: 'unregisterEventHandler',
handler: eventHandler1),
jsonEncode({}));
await irisMethodChannel.registerEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler1',
unregisterName: 'unregisterEventHandler1',
handler: eventHandler2),
jsonEncode({}));

irisMethodChannel.unregisterEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler1',
unregisterName: 'unregisterEventHandler1',
handler: eventHandler2),
jsonEncode({}));

await irisMethodChannel.unregisterEventHandlers(key);

final DisposableScopedObjects? subScopedObjects =
irisMethodChannel.scopedEventHandlers.get(key);
expect(subScopedObjects, isNull);

final unregisterEventHandlerCallRecord = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'unregisterEventHandler');
expect(unregisterEventHandlerCallRecord.length, 1);

final unregisterEventHandlerCallRecord1 = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'unregisterEventHandler1');
expect(unregisterEventHandlerCallRecord1.length, 1);

await irisMethodChannel.dispose();
});

test(
'registerEventHandler 2 times with different registerName, then unregisterEventHandler without await, then unregisterEventHandlers without await',
() async {
final irisMethodChannel = IrisMethodChannel();
await irisMethodChannel.initilize(nativeBindingsProvider);

const key = TypedScopedKey(_TestEventLoopEventHandler);
final eventHandler1 = _TestEventLoopEventHandler();
final eventHandler2 = _TestEventLoopEventHandler();
await irisMethodChannel.registerEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler',
unregisterName: 'unregisterEventHandler',
handler: eventHandler1),
jsonEncode({}));
await irisMethodChannel.registerEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler1',
unregisterName: 'unregisterEventHandler1',
handler: eventHandler2),
jsonEncode({}));

irisMethodChannel.unregisterEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler1',
unregisterName: 'unregisterEventHandler1',
handler: eventHandler2),
jsonEncode({}));

irisMethodChannel.unregisterEventHandlers(key);

// Wait for `unregisterEventHandler/unregisterEventHandlers` completed.
await Future.delayed(const Duration(milliseconds: 500));

final unregisterEventHandlerCallRecord = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'unregisterEventHandler');
expect(unregisterEventHandlerCallRecord.length, 1);

final unregisterEventHandlerCallRecord1 = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'unregisterEventHandler1');
expect(unregisterEventHandlerCallRecord1.length, 1);

await irisMethodChannel.dispose();
});

Expand Down

0 comments on commit 4f5058d

Please sign in to comment.