From 6a447aa89f8a65ac4ff375c0b875fabf81dc5a41 Mon Sep 17 00:00:00 2001 From: tarrinneal Date: Wed, 22 Jan 2025 16:52:58 -0800 Subject: [PATCH 1/8] fixes dart instance name usage and adds test --- .../app/lib/src/event_channel_messages.g.dart | 4 +- packages/pigeon/lib/dart_generator.dart | 4 +- .../lib/integration_tests.dart | 78 ++++ .../lib/message.gen.dart | 355 ++++++++++++++++++ .../generated/event_channel_tests.gen.dart | 8 +- .../test/message_test.dart | 195 ++++++++++ 6 files changed, 636 insertions(+), 8 deletions(-) create mode 100644 packages/pigeon/platform_tests/shared_test_plugin_code/lib/message.gen.dart create mode 100644 packages/pigeon/platform_tests/shared_test_plugin_code/test/message_test.dart diff --git a/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart b/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart index c180a9d742a..0759a36398e 100644 --- a/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart +++ b/packages/pigeon/example/app/lib/src/event_channel_messages.g.dart @@ -93,8 +93,8 @@ Stream streamEvents({String instanceName = ''}) { if (instanceName.isNotEmpty) { instanceName = '.$instanceName'; } - const EventChannel streamEventsChannel = EventChannel( - 'dev.flutter.pigeon.pigeon_example_package.EventChannelMethods.streamEvents', + final EventChannel streamEventsChannel = EventChannel( + 'dev.flutter.pigeon.pigeon_example_package.EventChannelMethods.streamEvents$instanceName', pigeonMethodCodec); return streamEventsChannel.receiveBroadcastStream().map((dynamic event) { return event as PlatformEvent; diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index 4f54839f874..58553b93489 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -556,8 +556,8 @@ final BinaryMessenger? ${varNamePrefix}binaryMessenger; if (instanceName.isNotEmpty) { instanceName = '.\$instanceName'; } - const EventChannel ${func.name}Channel = - EventChannel('${makeChannelName(api, func, dartPackageName)}', $_pigeonMethodChannelCodec); + final EventChannel ${func.name}Channel = + EventChannel('${makeChannelName(api, func, dartPackageName)}\$instanceName', $_pigeonMethodChannelCodec); return ${func.name}Channel.receiveBroadcastStream().map((dynamic event) { return event as ${func.returnType.baseName}; }); diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart index 01115629506..3842fd5c449 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart @@ -2865,6 +2865,7 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { TargetGenerator.kotlin, TargetGenerator.swift ]; + testWidgets('event channel sends continuous ints', (_) async { final Stream events = streamInts(); final List listEvents = await events.toList(); @@ -2912,6 +2913,83 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { }); await completer.future; }, skip: !eventChannelSupported.contains(targetGenerator)); + + testWidgets('event channels handle multiple instances', (_) async { + final Completer completer1 = Completer(); + final Completer completer2 = Completer(); + int count1 = 0; + int count2 = 0; + final Stream events1 = streamEvents(instanceName: '1'); + final Stream events2 = streamEvents(instanceName: '2'); + events1.listen((PlatformEvent event) { + switch (event) { + case IntEvent(): + expect(event.value, 1); + expect(count1, 0); + count1++; + case StringEvent(): + expect(event.value, 'string'); + expect(count1, 1); + count1++; + case BoolEvent(): + expect(event.value, false); + expect(count1, 2); + count1++; + case DoubleEvent(): + expect(event.value, 3.14); + expect(count1, 3); + count1++; + case ObjectsEvent(): + expect(event.value, true); + expect(count1, 4); + count1++; + case EnumEvent(): + expect(event.value, EventEnum.fortyTwo); + expect(count1, 5); + count1++; + case ClassEvent(): + expect(event.value.aNullableInt, 0); + expect(count1, 6); + count1++; + completer1.complete(); + } + }); + events2.listen((PlatformEvent event) { + switch (event) { + case IntEvent(): + expect(event.value, 1); + expect(count2, 0); + count2++; + case StringEvent(): + expect(event.value, 'string'); + expect(count2, 1); + count2++; + case BoolEvent(): + expect(event.value, false); + expect(count2, 2); + count2++; + case DoubleEvent(): + expect(event.value, 3.14); + expect(count2, 3); + count2++; + case ObjectsEvent(): + expect(event.value, true); + expect(count2, 4); + count2++; + case EnumEvent(): + expect(event.value, EventEnum.fortyTwo); + expect(count2, 5); + count2++; + case ClassEvent(): + expect(event.value.aNullableInt, 0); + expect(count2, 6); + count2++; + completer2.complete(); + } + }); + await completer1.future; + await completer2.future; + }); } class _FlutterApiTestImplementation implements FlutterIntegrationCoreApi { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/message.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/message.gen.dart new file mode 100644 index 00000000000..2fc9d88444b --- /dev/null +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/message.gen.dart @@ -0,0 +1,355 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Autogenerated from Pigeon (v22.7.3), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + +List wrapResponse( + {Object? result, PlatformException? error, bool empty = false}) { + if (empty) { + return []; + } + if (error == null) { + return [result]; + } + return [error.code, error.message, error.details]; +} + +/// This comment is to test enum documentation comments. +/// +/// This comment also tests multiple line comments. +/// +/// //////////////////////// +/// This comment also tests comments that start with '/' +/// //////////////////////// +enum MessageRequestState { + pending, + success, + failure, +} + +/// This comment is to test class documentation comments. +/// +/// This comment also tests multiple line comments. +class MessageSearchRequest { + MessageSearchRequest({ + this.query, + this.anInt, + this.aBool, + }); + + /// This comment is to test field documentation comments. + String? query; + + /// This comment is to test field documentation comments. + int? anInt; + + /// This comment is to test field documentation comments. + bool? aBool; + + Object encode() { + return [ + query, + anInt, + aBool, + ]; + } + + static MessageSearchRequest decode(Object result) { + result as List; + return MessageSearchRequest( + query: result[0] as String?, + anInt: result[1] as int?, + aBool: result[2] as bool?, + ); + } +} + +/// This comment is to test class documentation comments. +class MessageSearchReply { + MessageSearchReply({ + this.result, + this.error, + this.state, + }); + + /// This comment is to test field documentation comments. + /// + /// This comment also tests multiple line comments. + String? result; + + /// This comment is to test field documentation comments. + String? error; + + /// This comment is to test field documentation comments. + MessageRequestState? state; + + Object encode() { + return [ + result, + error, + state, + ]; + } + + static MessageSearchReply decode(Object result) { + result as List; + return MessageSearchReply( + result: result[0] as String?, + error: result[1] as String?, + state: result[2] as MessageRequestState?, + ); + } +} + +/// This comment is to test class documentation comments. +class MessageNested { + MessageNested({ + this.request, + }); + + /// This comment is to test field documentation comments. + MessageSearchRequest? request; + + Object encode() { + return [ + request, + ]; + } + + static MessageNested decode(Object result) { + result as List; + return MessageNested( + request: result[0] as MessageSearchRequest?, + ); + } +} + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is MessageRequestState) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is MessageSearchRequest) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is MessageSearchReply) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is MessageNested) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final int? value = readValue(buffer) as int?; + return value == null ? null : MessageRequestState.values[value]; + case 130: + return MessageSearchRequest.decode(readValue(buffer)!); + case 131: + return MessageSearchReply.decode(readValue(buffer)!); + case 132: + return MessageNested.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +/// This comment is to test api documentation comments. +/// +/// This comment also tests multiple line comments. +class MessageApi { + /// Constructor for [MessageApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MessageApi( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + /// This comment is to test documentation comments. + /// + /// This comment also tests multiple line comments. + Future initialize() async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_test_plugin_code.MessageApi.initialize$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// This comment is to test method documentation comments. + Future search(MessageSearchRequest request) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_test_plugin_code.MessageApi.search$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([request]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as MessageSearchReply?)!; + } + } +} + +/// This comment is to test api documentation comments. +class MessageNestedApi { + /// Constructor for [MessageNestedApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MessageNestedApi( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + /// This comment is to test method documentation comments. + /// + /// This comment also tests multiple line comments. + Future search(MessageNested nested) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.shared_test_plugin_code.MessageNestedApi.search$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([nested]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as MessageSearchReply?)!; + } + } +} + +/// This comment is to test api documentation comments. +abstract class MessageFlutterSearchApi { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + /// This comment is to test method documentation comments. + MessageSearchReply search(MessageSearchRequest request); + + static void setUp( + MessageFlutterSearchApi? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.shared_test_plugin_code.MessageFlutterSearchApi.search$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageFlutterSearchApi.search was null.'); + final List args = (message as List?)!; + final MessageSearchRequest? arg_request = + (args[0] as MessageSearchRequest?); + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageFlutterSearchApi.search was null, expected non-null MessageSearchRequest.'); + try { + final MessageSearchReply output = api.search(arg_request!); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart index fe57f06e99f..65118adc53d 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart @@ -432,8 +432,8 @@ Stream streamInts({String instanceName = ''}) { if (instanceName.isNotEmpty) { instanceName = '.$instanceName'; } - const EventChannel streamIntsChannel = EventChannel( - 'dev.flutter.pigeon.pigeon_integration_tests.EventChannelMethods.streamInts', + final EventChannel streamIntsChannel = EventChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.EventChannelMethods.streamInts$instanceName', pigeonMethodCodec); return streamIntsChannel.receiveBroadcastStream().map((dynamic event) { return event as int; @@ -444,8 +444,8 @@ Stream streamEvents({String instanceName = ''}) { if (instanceName.isNotEmpty) { instanceName = '.$instanceName'; } - const EventChannel streamEventsChannel = EventChannel( - 'dev.flutter.pigeon.pigeon_integration_tests.EventChannelMethods.streamEvents', + final EventChannel streamEventsChannel = EventChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.EventChannelMethods.streamEvents$instanceName', pigeonMethodCodec); return streamEventsChannel.receiveBroadcastStream().map((dynamic event) { return event as PlatformEvent; diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/test/message_test.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/test/message_test.dart new file mode 100644 index 00000000000..f7681ab6501 --- /dev/null +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/test/message_test.dart @@ -0,0 +1,195 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Autogenerated from Pigeon (v22.7.3), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import, no_leading_underscores_for_local_identifiers +// ignore_for_file: avoid_relative_lib_imports +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:shared_test_plugin_code/message.gen.dart'; + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is MessageRequestState) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is MessageSearchRequest) { + buffer.putUint8(130); + writeValue(buffer, value.encode()); + } else if (value is MessageSearchReply) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); + } else if (value is MessageNested) { + buffer.putUint8(132); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final int? value = readValue(buffer) as int?; + return value == null ? null : MessageRequestState.values[value]; + case 130: + return MessageSearchRequest.decode(readValue(buffer)!); + case 131: + return MessageSearchReply.decode(readValue(buffer)!); + case 132: + return MessageNested.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +/// This comment is to test api documentation comments. +/// +/// This comment also tests multiple line comments. +abstract class TestHostApi { + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => + TestDefaultBinaryMessengerBinding.instance; + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + /// This comment is to test documentation comments. + /// + /// This comment also tests multiple line comments. + void initialize(); + + /// This comment is to test method documentation comments. + MessageSearchReply search(MessageSearchRequest request); + + static void setUp( + TestHostApi? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.shared_test_plugin_code.MessageApi.initialize$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { + try { + api.initialize(); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.shared_test_plugin_code.MessageApi.search$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageApi.search was null.'); + final List args = (message as List?)!; + final MessageSearchRequest? arg_request = + (args[0] as MessageSearchRequest?); + assert(arg_request != null, + 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageApi.search was null, expected non-null MessageSearchRequest.'); + try { + final MessageSearchReply output = api.search(arg_request!); + return [output]; + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} + +/// This comment is to test api documentation comments. +abstract class TestNestedApi { + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => + TestDefaultBinaryMessengerBinding.instance; + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + /// This comment is to test method documentation comments. + /// + /// This comment also tests multiple line comments. + MessageSearchReply search(MessageNested nested); + + static void setUp( + TestNestedApi? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.shared_test_plugin_code.MessageNestedApi.search$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(pigeonVar_channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageNestedApi.search was null.'); + final List args = (message as List?)!; + final MessageNested? arg_nested = (args[0] as MessageNested?); + assert(arg_nested != null, + 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageNestedApi.search was null, expected non-null MessageNested.'); + try { + final MessageSearchReply output = api.search(arg_nested!); + return [output]; + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} From b17abcd5025ae9d7e85df4ae9da3f6315a6250ef Mon Sep 17 00:00:00 2001 From: tarrinneal Date: Wed, 22 Jan 2025 17:28:20 -0800 Subject: [PATCH 2/8] add tests --- .../pigeon/pigeons/event_channel_tests.dart | 1 + .../lib/integration_tests.dart | 79 +++---------------- .../generated/event_channel_tests.gen.dart | 14 ++++ .../test_plugin/EventChannelTests.gen.kt | 19 +++++ .../com/example/test_plugin/TestPlugin.kt | 27 +++++++ .../ios/Classes/EventChannelTests.gen.swift | 18 +++++ .../test_plugin/ios/Classes/TestPlugin.swift | 27 +++++++ .../macos/Classes/EventChannelTests.gen.swift | 18 +++++ 8 files changed, 135 insertions(+), 68 deletions(-) diff --git a/packages/pigeon/pigeons/event_channel_tests.dart b/packages/pigeon/pigeons/event_channel_tests.dart index d925a320dfe..e089a60db7e 100644 --- a/packages/pigeon/pigeons/event_channel_tests.dart +++ b/packages/pigeon/pigeons/event_channel_tests.dart @@ -141,4 +141,5 @@ class ClassEvent extends PlatformEvent { abstract class EventChannelMethods { int streamInts(); PlatformEvent streamEvents(); + int streamConsistentNumbers(); } diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart index 3842fd5c449..1be0440940e 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart @@ -2917,76 +2917,19 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { testWidgets('event channels handle multiple instances', (_) async { final Completer completer1 = Completer(); final Completer completer2 = Completer(); - int count1 = 0; - int count2 = 0; - final Stream events1 = streamEvents(instanceName: '1'); - final Stream events2 = streamEvents(instanceName: '2'); - events1.listen((PlatformEvent event) { - switch (event) { - case IntEvent(): - expect(event.value, 1); - expect(count1, 0); - count1++; - case StringEvent(): - expect(event.value, 'string'); - expect(count1, 1); - count1++; - case BoolEvent(): - expect(event.value, false); - expect(count1, 2); - count1++; - case DoubleEvent(): - expect(event.value, 3.14); - expect(count1, 3); - count1++; - case ObjectsEvent(): - expect(event.value, true); - expect(count1, 4); - count1++; - case EnumEvent(): - expect(event.value, EventEnum.fortyTwo); - expect(count1, 5); - count1++; - case ClassEvent(): - expect(event.value.aNullableInt, 0); - expect(count1, 6); - count1++; - completer1.complete(); - } + final Stream events1 = streamConsistentNumbers(instanceName: '1'); + final Stream events2 = streamConsistentNumbers(instanceName: '2'); + + events1.listen((int event) { + expect(event, 1); }); - events2.listen((PlatformEvent event) { - switch (event) { - case IntEvent(): - expect(event.value, 1); - expect(count2, 0); - count2++; - case StringEvent(): - expect(event.value, 'string'); - expect(count2, 1); - count2++; - case BoolEvent(): - expect(event.value, false); - expect(count2, 2); - count2++; - case DoubleEvent(): - expect(event.value, 3.14); - expect(count2, 3); - count2++; - case ObjectsEvent(): - expect(event.value, true); - expect(count2, 4); - count2++; - case EnumEvent(): - expect(event.value, EventEnum.fortyTwo); - expect(count2, 5); - count2++; - case ClassEvent(): - expect(event.value.aNullableInt, 0); - expect(count2, 6); - count2++; - completer2.complete(); - } + await events1.last.then((_) => completer1.complete()); + + events2.listen((int event) { + expect(event, 2); }); + await events2.last.then((_) => completer2.complete()); + await completer1.future; await completer2.future; }); diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart index 65118adc53d..a681092d35a 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/event_channel_tests.gen.dart @@ -451,3 +451,17 @@ Stream streamEvents({String instanceName = ''}) { return event as PlatformEvent; }); } + +Stream streamConsistentNumbers({String instanceName = ''}) { + if (instanceName.isNotEmpty) { + instanceName = '.$instanceName'; + } + final EventChannel streamConsistentNumbersChannel = EventChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.EventChannelMethods.streamConsistentNumbers$instanceName', + pigeonMethodCodec); + return streamConsistentNumbersChannel + .receiveBroadcastStream() + .map((dynamic event) { + return event as int; + }); +} diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt index 08eb85b55ef..7b36b0a4350 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/EventChannelTests.gen.kt @@ -470,3 +470,22 @@ abstract class StreamEventsStreamHandler : PigeonEventChannelWrapper { + companion object { + fun register( + messenger: BinaryMessenger, + streamHandler: StreamConsistentNumbersStreamHandler, + instanceName: String = "" + ) { + var channelName: String = + "dev.flutter.pigeon.pigeon_integration_tests.EventChannelMethods.streamConsistentNumbers" + if (instanceName.isNotEmpty()) { + channelName += ".$instanceName" + } + val internalStreamHandler = PigeonStreamHandler(streamHandler) + EventChannel(messenger, channelName, EventChannelTestsPigeonMethodCodec) + .setStreamHandler(internalStreamHandler) + } + } +} diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt index f175076abcd..1fe102181f2 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt @@ -31,6 +31,7 @@ class TestPlugin : FlutterPlugin, HostIntegrationCoreApi { StreamEventsStreamHandler.register(binding.binaryMessenger, SendClass) StreamIntsStreamHandler.register(binding.binaryMessenger, SendInts) + StreamConsistentNumbersStreamHandler.register(binding.binaryMessenger, SendConsistentNumbers) } override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { @@ -927,3 +928,29 @@ object SendClass : StreamEventsStreamHandler() { handler.postDelayed(r, 10) } } + +var numberToSend = 1L + +object SendConsistentNumbers : StreamConsistentNumbersStreamHandler() { + val handler = Handler(Looper.getMainLooper()) + + override fun onListen(p0: Any?, sink: PigeonEventSink) { + val numberThatWillBeSent = numberToSend++ + var count: Int = 0 + val r: Runnable = + object : Runnable { + override fun run() { + if (count >= 10) { + sink.endOfStream() + } else { + handler.post { + sink.success(numberThatWillBeSent) + count++ + } + handler.postDelayed(this, 10) + } + } + } + handler.postDelayed(r, 10) + } +} diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/EventChannelTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/EventChannelTests.gen.swift index 09f682ece4b..d2970947a2d 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/EventChannelTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/EventChannelTests.gen.swift @@ -574,3 +574,21 @@ class StreamEventsStreamHandler: PigeonEventChannelWrapper { channel.setStreamHandler(internalStreamHandler) } } + +class StreamConsistentNumbersStreamHandler: PigeonEventChannelWrapper { + static func register( + with messenger: FlutterBinaryMessenger, + instanceName: String = "", + streamHandler: StreamConsistentNumbersStreamHandler + ) { + var channelName = + "dev.flutter.pigeon.pigeon_integration_tests.EventChannelMethods.streamConsistentNumbers" + if !instanceName.isEmpty { + channelName += ".\(instanceName)" + } + let internalStreamHandler = PigeonStreamHandler(wrapper: streamHandler) + let channel = FlutterEventChannel( + name: channelName, binaryMessenger: messenger, codec: eventChannelTestsPigeonMethodCodec) + channel.setStreamHandler(internalStreamHandler) + } +} diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift index 6b39a002a14..de7e2bb613c 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift @@ -31,6 +31,8 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { StreamIntsStreamHandler.register(with: binaryMessenger, streamHandler: SendInts()) StreamEventsStreamHandler.register(with: binaryMessenger, streamHandler: SendEvents()) + StreamConsistentNumbersStreamHandler.register( + with: binaryMessenger, streamHandler: SendConsistentNumbers()) proxyApiRegistrar = ProxyApiTestsPigeonProxyApiRegistrar( binaryMessenger: binaryMessenger, apiDelegate: ProxyApiDelegate()) proxyApiRegistrar!.setUp() @@ -1272,6 +1274,31 @@ class SendEvents: StreamEventsStreamHandler { } } +var numberToSend = 1 + +class SendConsistentNumbers: StreamConsistentNumbersStreamHandler { + var timerActive = false + var timer: Timer? + + override func onListen(withArguments arguments: Any?, sink: PigeonEventSink) { + var numberThatWillBeSent = numberToSend + var count: Int64 = 0 + if !timerActive { + timerActive = true + timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { _ in + DispatchQueue.main.async { + sink.success(numberThatWillBeSent) + count += 1 + if count >= 10 { + sink.endOfStream() + self.timer?.invalidate() + } + } + } + } + } +} + class ProxyApiDelegate: ProxyApiTestsPigeonProxyApiDelegate { func pigeonApiProxyApiTestClass(_ registrar: ProxyApiTestsPigeonProxyApiRegistrar) -> PigeonApiProxyApiTestClass diff --git a/packages/pigeon/platform_tests/test_plugin/macos/Classes/EventChannelTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/macos/Classes/EventChannelTests.gen.swift index 09f682ece4b..d2970947a2d 100644 --- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/EventChannelTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/EventChannelTests.gen.swift @@ -574,3 +574,21 @@ class StreamEventsStreamHandler: PigeonEventChannelWrapper { channel.setStreamHandler(internalStreamHandler) } } + +class StreamConsistentNumbersStreamHandler: PigeonEventChannelWrapper { + static func register( + with messenger: FlutterBinaryMessenger, + instanceName: String = "", + streamHandler: StreamConsistentNumbersStreamHandler + ) { + var channelName = + "dev.flutter.pigeon.pigeon_integration_tests.EventChannelMethods.streamConsistentNumbers" + if !instanceName.isEmpty { + channelName += ".\(instanceName)" + } + let internalStreamHandler = PigeonStreamHandler(wrapper: streamHandler) + let channel = FlutterEventChannel( + name: channelName, binaryMessenger: messenger, codec: eventChannelTestsPigeonMethodCodec) + channel.setStreamHandler(internalStreamHandler) + } +} From fe29b29e25664b26bb490632323eca9a431205a8 Mon Sep 17 00:00:00 2001 From: tarrinneal Date: Wed, 22 Jan 2025 17:46:27 -0800 Subject: [PATCH 3/8] skip --- .../shared_test_plugin_code/lib/integration_tests.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart index 1be0440940e..a05c45fbff7 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart @@ -2932,7 +2932,7 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { await completer1.future; await completer2.future; - }); + }, skip: !eventChannelSupported.contains(targetGenerator)); } class _FlutterApiTestImplementation implements FlutterIntegrationCoreApi { From 507c1c5bba6c468c7add4b14d70957ab0211405b Mon Sep 17 00:00:00 2001 From: tarrinneal Date: Wed, 22 Jan 2025 18:30:21 -0800 Subject: [PATCH 4/8] fix swift ints --- .../lib/message.gen.dart | 355 ------------------ .../test/message_test.dart | 195 ---------- .../test_plugin/ios/Classes/TestPlugin.swift | 4 +- 3 files changed, 2 insertions(+), 552 deletions(-) delete mode 100644 packages/pigeon/platform_tests/shared_test_plugin_code/lib/message.gen.dart delete mode 100644 packages/pigeon/platform_tests/shared_test_plugin_code/test/message_test.dart diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/message.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/message.gen.dart deleted file mode 100644 index 2fc9d88444b..00000000000 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/message.gen.dart +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Autogenerated from Pigeon (v22.7.3), do not edit directly. -// See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers - -import 'dart:async'; -import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; - -import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; -import 'package:flutter/services.dart'; - -PlatformException _createConnectionError(String channelName) { - return PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel: "$channelName".', - ); -} - -List wrapResponse( - {Object? result, PlatformException? error, bool empty = false}) { - if (empty) { - return []; - } - if (error == null) { - return [result]; - } - return [error.code, error.message, error.details]; -} - -/// This comment is to test enum documentation comments. -/// -/// This comment also tests multiple line comments. -/// -/// //////////////////////// -/// This comment also tests comments that start with '/' -/// //////////////////////// -enum MessageRequestState { - pending, - success, - failure, -} - -/// This comment is to test class documentation comments. -/// -/// This comment also tests multiple line comments. -class MessageSearchRequest { - MessageSearchRequest({ - this.query, - this.anInt, - this.aBool, - }); - - /// This comment is to test field documentation comments. - String? query; - - /// This comment is to test field documentation comments. - int? anInt; - - /// This comment is to test field documentation comments. - bool? aBool; - - Object encode() { - return [ - query, - anInt, - aBool, - ]; - } - - static MessageSearchRequest decode(Object result) { - result as List; - return MessageSearchRequest( - query: result[0] as String?, - anInt: result[1] as int?, - aBool: result[2] as bool?, - ); - } -} - -/// This comment is to test class documentation comments. -class MessageSearchReply { - MessageSearchReply({ - this.result, - this.error, - this.state, - }); - - /// This comment is to test field documentation comments. - /// - /// This comment also tests multiple line comments. - String? result; - - /// This comment is to test field documentation comments. - String? error; - - /// This comment is to test field documentation comments. - MessageRequestState? state; - - Object encode() { - return [ - result, - error, - state, - ]; - } - - static MessageSearchReply decode(Object result) { - result as List; - return MessageSearchReply( - result: result[0] as String?, - error: result[1] as String?, - state: result[2] as MessageRequestState?, - ); - } -} - -/// This comment is to test class documentation comments. -class MessageNested { - MessageNested({ - this.request, - }); - - /// This comment is to test field documentation comments. - MessageSearchRequest? request; - - Object encode() { - return [ - request, - ]; - } - - static MessageNested decode(Object result) { - result as List; - return MessageNested( - request: result[0] as MessageSearchRequest?, - ); - } -} - -class _PigeonCodec extends StandardMessageCodec { - const _PigeonCodec(); - @override - void writeValue(WriteBuffer buffer, Object? value) { - if (value is int) { - buffer.putUint8(4); - buffer.putInt64(value); - } else if (value is MessageRequestState) { - buffer.putUint8(129); - writeValue(buffer, value.index); - } else if (value is MessageSearchRequest) { - buffer.putUint8(130); - writeValue(buffer, value.encode()); - } else if (value is MessageSearchReply) { - buffer.putUint8(131); - writeValue(buffer, value.encode()); - } else if (value is MessageNested) { - buffer.putUint8(132); - writeValue(buffer, value.encode()); - } else { - super.writeValue(buffer, value); - } - } - - @override - Object? readValueOfType(int type, ReadBuffer buffer) { - switch (type) { - case 129: - final int? value = readValue(buffer) as int?; - return value == null ? null : MessageRequestState.values[value]; - case 130: - return MessageSearchRequest.decode(readValue(buffer)!); - case 131: - return MessageSearchReply.decode(readValue(buffer)!); - case 132: - return MessageNested.decode(readValue(buffer)!); - default: - return super.readValueOfType(type, buffer); - } - } -} - -/// This comment is to test api documentation comments. -/// -/// This comment also tests multiple line comments. -class MessageApi { - /// Constructor for [MessageApi]. The [binaryMessenger] named argument is - /// available for dependency injection. If it is left null, the default - /// BinaryMessenger will be used which routes to the host platform. - MessageApi( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) - : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; - final BinaryMessenger? pigeonVar_binaryMessenger; - - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - final String pigeonVar_messageChannelSuffix; - - /// This comment is to test documentation comments. - /// - /// This comment also tests multiple line comments. - Future initialize() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.shared_test_plugin_code.MessageApi.initialize$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send(null) as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - } - - /// This comment is to test method documentation comments. - Future search(MessageSearchRequest request) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.shared_test_plugin_code.MessageApi.search$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([request]) as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as MessageSearchReply?)!; - } - } -} - -/// This comment is to test api documentation comments. -class MessageNestedApi { - /// Constructor for [MessageNestedApi]. The [binaryMessenger] named argument is - /// available for dependency injection. If it is left null, the default - /// BinaryMessenger will be used which routes to the host platform. - MessageNestedApi( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) - : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; - final BinaryMessenger? pigeonVar_binaryMessenger; - - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - final String pigeonVar_messageChannelSuffix; - - /// This comment is to test method documentation comments. - /// - /// This comment also tests multiple line comments. - Future search(MessageNested nested) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.shared_test_plugin_code.MessageNestedApi.search$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([nested]) as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as MessageSearchReply?)!; - } - } -} - -/// This comment is to test api documentation comments. -abstract class MessageFlutterSearchApi { - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - /// This comment is to test method documentation comments. - MessageSearchReply search(MessageSearchRequest request); - - static void setUp( - MessageFlutterSearchApi? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; - { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.shared_test_plugin_code.MessageFlutterSearchApi.search$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - pigeonVar_channel.setMessageHandler(null); - } else { - pigeonVar_channel.setMessageHandler((Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageFlutterSearchApi.search was null.'); - final List args = (message as List?)!; - final MessageSearchRequest? arg_request = - (args[0] as MessageSearchRequest?); - assert(arg_request != null, - 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageFlutterSearchApi.search was null, expected non-null MessageSearchRequest.'); - try { - final MessageSearchReply output = api.search(arg_request!); - return wrapResponse(result: output); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - } -} diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/test/message_test.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/test/message_test.dart deleted file mode 100644 index f7681ab6501..00000000000 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/test/message_test.dart +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Autogenerated from Pigeon (v22.7.3), do not edit directly. -// See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import, no_leading_underscores_for_local_identifiers -// ignore_for_file: avoid_relative_lib_imports -import 'dart:async'; -import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; -import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:shared_test_plugin_code/message.gen.dart'; - -class _PigeonCodec extends StandardMessageCodec { - const _PigeonCodec(); - @override - void writeValue(WriteBuffer buffer, Object? value) { - if (value is int) { - buffer.putUint8(4); - buffer.putInt64(value); - } else if (value is MessageRequestState) { - buffer.putUint8(129); - writeValue(buffer, value.index); - } else if (value is MessageSearchRequest) { - buffer.putUint8(130); - writeValue(buffer, value.encode()); - } else if (value is MessageSearchReply) { - buffer.putUint8(131); - writeValue(buffer, value.encode()); - } else if (value is MessageNested) { - buffer.putUint8(132); - writeValue(buffer, value.encode()); - } else { - super.writeValue(buffer, value); - } - } - - @override - Object? readValueOfType(int type, ReadBuffer buffer) { - switch (type) { - case 129: - final int? value = readValue(buffer) as int?; - return value == null ? null : MessageRequestState.values[value]; - case 130: - return MessageSearchRequest.decode(readValue(buffer)!); - case 131: - return MessageSearchReply.decode(readValue(buffer)!); - case 132: - return MessageNested.decode(readValue(buffer)!); - default: - return super.readValueOfType(type, buffer); - } - } -} - -/// This comment is to test api documentation comments. -/// -/// This comment also tests multiple line comments. -abstract class TestHostApi { - static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => - TestDefaultBinaryMessengerBinding.instance; - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - /// This comment is to test documentation comments. - /// - /// This comment also tests multiple line comments. - void initialize(); - - /// This comment is to test method documentation comments. - MessageSearchReply search(MessageSearchRequest request); - - static void setUp( - TestHostApi? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; - { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.shared_test_plugin_code.MessageApi.initialize$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, - (Object? message) async { - try { - api.initialize(); - return wrapResponse(empty: true); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.shared_test_plugin_code.MessageApi.search$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, - (Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageApi.search was null.'); - final List args = (message as List?)!; - final MessageSearchRequest? arg_request = - (args[0] as MessageSearchRequest?); - assert(arg_request != null, - 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageApi.search was null, expected non-null MessageSearchRequest.'); - try { - final MessageSearchReply output = api.search(arg_request!); - return [output]; - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - } -} - -/// This comment is to test api documentation comments. -abstract class TestNestedApi { - static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => - TestDefaultBinaryMessengerBinding.instance; - static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - - /// This comment is to test method documentation comments. - /// - /// This comment also tests multiple line comments. - MessageSearchReply search(MessageNested nested); - - static void setUp( - TestNestedApi? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; - { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.shared_test_plugin_code.MessageNestedApi.search$messageChannelSuffix', - pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, null); - } else { - _testBinaryMessengerBinding!.defaultBinaryMessenger - .setMockDecodedMessageHandler(pigeonVar_channel, - (Object? message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageNestedApi.search was null.'); - final List args = (message as List?)!; - final MessageNested? arg_nested = (args[0] as MessageNested?); - assert(arg_nested != null, - 'Argument for dev.flutter.pigeon.shared_test_plugin_code.MessageNestedApi.search was null, expected non-null MessageNested.'); - try { - final MessageSearchReply output = api.search(arg_nested!); - return [output]; - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - } -} diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift index de7e2bb613c..2022ecca9a3 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift @@ -1274,14 +1274,14 @@ class SendEvents: StreamEventsStreamHandler { } } -var numberToSend = 1 +var numberToSend: Int64 = 1 class SendConsistentNumbers: StreamConsistentNumbersStreamHandler { var timerActive = false var timer: Timer? override func onListen(withArguments arguments: Any?, sink: PigeonEventSink) { - var numberThatWillBeSent = numberToSend + var numberThatWillBeSent: Int64 = numberToSend var count: Int64 = 0 if !timerActive { timerActive = true From f2540d097033795f3430a4263d7098ba96e5ceb8 Mon Sep 17 00:00:00 2001 From: tarrinneal Date: Wed, 22 Jan 2025 18:55:40 -0800 Subject: [PATCH 5/8] version --- packages/pigeon/CHANGELOG.md | 4 ++++ packages/pigeon/lib/generator_tools.dart | 2 +- .../platform_tests/test_plugin/ios/Classes/TestPlugin.swift | 2 +- packages/pigeon/pubspec.yaml | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index 4f8c47d2b84..a631243c843 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,7 @@ +## 22.7.4 + +* [dart] Fixes bug with multi instance event channel support. + ## 22.7.3 * Adds compatibility with `analyzer` 7.x.*. diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index a64742711cb..7e301b4b16b 100644 --- a/packages/pigeon/lib/generator_tools.dart +++ b/packages/pigeon/lib/generator_tools.dart @@ -14,7 +14,7 @@ import 'ast.dart'; /// The current version of pigeon. /// /// This must match the version in pubspec.yaml. -const String pigeonVersion = '22.7.3'; +const String pigeonVersion = '22.7.4'; /// Read all the content from [stdin] to a String. String readStdin() { diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift index 2022ecca9a3..c0ecd986a90 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift @@ -1281,7 +1281,7 @@ class SendConsistentNumbers: StreamConsistentNumbersStreamHandler { var timer: Timer? override func onListen(withArguments arguments: Any?, sink: PigeonEventSink) { - var numberThatWillBeSent: Int64 = numberToSend + let numberThatWillBeSent: Int64 = numberToSend var count: Int64 = 0 if !timerActive { timerActive = true diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index 442e7194e9b..021284ad7f9 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -2,7 +2,7 @@ name: pigeon description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. repository: https://github.com/flutter/packages/tree/main/packages/pigeon issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+pigeon%22 -version: 22.7.3 # This must match the version in lib/generator_tools.dart +version: 22.7.4 # This must match the version in lib/generator_tools.dart environment: sdk: ^3.4.0 From edd276ae9f34e26d3abc627a59e4bae1077e0d8c Mon Sep 17 00:00:00 2001 From: tarrinneal Date: Thu, 23 Jan 2025 11:38:07 -0800 Subject: [PATCH 6/8] fix integration tests --- .../lib/integration_tests.dart | 6 ++---- .../kotlin/com/example/test_plugin/TestPlugin.kt | 15 ++++++++------- .../test_plugin/ios/Classes/TestPlugin.swift | 12 +++++++++--- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart index a05c45fbff7..bf3b05f4052 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart @@ -2922,13 +2922,11 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { events1.listen((int event) { expect(event, 1); - }); - await events1.last.then((_) => completer1.complete()); + }).onDone(() => completer1.complete()); events2.listen((int event) { expect(event, 2); - }); - await events2.last.then((_) => completer2.complete()); + }).onDone(() => completer2.complete()); await completer1.future; await completer2.future; diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt index 1fe102181f2..3177d6cdc8d 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt @@ -31,7 +31,10 @@ class TestPlugin : FlutterPlugin, HostIntegrationCoreApi { StreamEventsStreamHandler.register(binding.binaryMessenger, SendClass) StreamIntsStreamHandler.register(binding.binaryMessenger, SendInts) - StreamConsistentNumbersStreamHandler.register(binding.binaryMessenger, SendConsistentNumbers) + StreamConsistentNumbersStreamHandler.register( + binding.binaryMessenger, SendConsistentNumbers(1), "1") + StreamConsistentNumbersStreamHandler.register( + binding.binaryMessenger, SendConsistentNumbers(2), "2") } override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { @@ -929,13 +932,11 @@ object SendClass : StreamEventsStreamHandler() { } } -var numberToSend = 1L - -object SendConsistentNumbers : StreamConsistentNumbersStreamHandler() { - val handler = Handler(Looper.getMainLooper()) +class SendConsistentNumbers(private val numberToSend: Long) : + StreamConsistentNumbersStreamHandler() { + private val handler = Handler(Looper.getMainLooper()) override fun onListen(p0: Any?, sink: PigeonEventSink) { - val numberThatWillBeSent = numberToSend++ var count: Int = 0 val r: Runnable = object : Runnable { @@ -944,7 +945,7 @@ object SendConsistentNumbers : StreamConsistentNumbersStreamHandler() { sink.endOfStream() } else { handler.post { - sink.success(numberThatWillBeSent) + sink.success(numberToSend) count++ } handler.postDelayed(this, 10) diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift index c0ecd986a90..1ecd036cd1e 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift @@ -32,7 +32,11 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { StreamIntsStreamHandler.register(with: binaryMessenger, streamHandler: SendInts()) StreamEventsStreamHandler.register(with: binaryMessenger, streamHandler: SendEvents()) StreamConsistentNumbersStreamHandler.register( - with: binaryMessenger, streamHandler: SendConsistentNumbers()) + with: binaryMessenger, instanceName: "1", + streamHandler: SendConsistentNumbers(numberToSend: 1)) + StreamConsistentNumbersStreamHandler.register( + with: binaryMessenger, instanceName: "2", + streamHandler: SendConsistentNumbers(numberToSend: 2)) proxyApiRegistrar = ProxyApiTestsPigeonProxyApiRegistrar( binaryMessenger: binaryMessenger, apiDelegate: ProxyApiDelegate()) proxyApiRegistrar!.setUp() @@ -1274,9 +1278,11 @@ class SendEvents: StreamEventsStreamHandler { } } -var numberToSend: Int64 = 1 - class SendConsistentNumbers: StreamConsistentNumbersStreamHandler { + let numberToSend: Int64 + init(numberToSend: Int64) { + self.numberToSend = numberToSend + } var timerActive = false var timer: Timer? From 95bce9eb9462e636a2b4cf73d1d1f3b755225ae1 Mon Sep 17 00:00:00 2001 From: tarrinneal Date: Thu, 23 Jan 2025 13:22:35 -0800 Subject: [PATCH 7/8] - --- packages/pigeon/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index a631243c843..7724e95d9ae 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,6 +1,6 @@ ## 22.7.4 -* [dart] Fixes bug with multi instance event channel support. +* [dart] Fixes bug with multi-instance event channel support. ## 22.7.3 From de2e8f560d30ede0121365db26659b98a8f88e5a Mon Sep 17 00:00:00 2001 From: tarrinneal Date: Thu, 23 Jan 2025 13:27:52 -0800 Subject: [PATCH 8/8] add macos code --- .../macos/Classes/TestPlugin.swift | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift index bcee6f7eb38..c23056111ed 100644 --- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift @@ -27,6 +27,12 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { binaryMessenger: binaryMessenger, messageChannelSuffix: "suffixOne") flutterSmallApiTwo = FlutterSmallApi( binaryMessenger: binaryMessenger, messageChannelSuffix: "suffixTwo") + StreamConsistentNumbersStreamHandler.register( + with: binaryMessenger, instanceName: "1", + streamHandler: SendConsistentNumbers(numberToSend: 1)) + StreamConsistentNumbersStreamHandler.register( + with: binaryMessenger, instanceName: "2", + streamHandler: SendConsistentNumbers(numberToSend: 2)) proxyApiRegistrar = ProxyApiTestsPigeonProxyApiRegistrar( binaryMessenger: binaryMessenger, apiDelegate: ProxyApiDelegate()) proxyApiRegistrar!.setUp() @@ -1270,6 +1276,33 @@ class SendEvents: StreamEventsStreamHandler { } } +class SendConsistentNumbers: StreamConsistentNumbersStreamHandler { + let numberToSend: Int64 + init(numberToSend: Int64) { + self.numberToSend = numberToSend + } + var timerActive = false + var timer: Timer? + + override func onListen(withArguments arguments: Any?, sink: PigeonEventSink) { + let numberThatWillBeSent: Int64 = numberToSend + var count: Int64 = 0 + if !timerActive { + timerActive = true + timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { _ in + DispatchQueue.main.async { + sink.success(numberThatWillBeSent) + count += 1 + if count >= 10 { + sink.endOfStream() + self.timer?.invalidate() + } + } + } + } + } +} + class ProxyApiDelegate: ProxyApiTestsPigeonProxyApiDelegate { func pigeonApiProxyApiTestClass(_ registrar: ProxyApiTestsPigeonProxyApiRegistrar) -> PigeonApiProxyApiTestClass