From ff16ee0b0a33126c476ab1292847b257396bd6f3 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 28 Nov 2022 16:30:02 -0500 Subject: [PATCH] [pigeon] Initial integration test setup (#2851) * [pigeon] Initial integration test setup This sets up initial proof-of-concept integration tests using the new shared native test harness: - Integration tests on the Dart side for void->void and Everything->Everything calls. - macOS implementations in the test plugin on the native side. - A new test target in the test script to drive them via `flutter test`. - A minimal change to the example app so that `flutter run`-ing it will test that the void->void call is wired up. Since this simple initial test hit https://github.com/flutter/flutter/issues/111083, which caused the test to fail, this includes a fix for that. Short-term future work (by me): - Add integration test native setup and script targets for the other generators. This includes one just to keep the initial review scope smaller. - Update https://github.com/flutter/packages/pull/2816 to include the integration test since it's still blocked until I can address the CI issues. Medium-term future work (not all by me): - Remove the legacy iOS e2e test scaffold that is currently disabled. - Add significantly more integration test coverage (likely including https://github.com/flutter/flutter/issues/115168 to reduce redundant API setup), including Flutter API integration tests rather than just host API tests. Part of https://github.com/flutter/flutter/issues/111505 Fixes https://github.com/flutter/flutter/issues/111083 * Version bump for bugfix * Check in generated files needed for analysis * Add the actual integration test file, which was left out * Address review comments * Fix incorrect Swift unit test for void call fix * Analysis ignore * Autoformat --- packages/pigeon/CHANGELOG.md | 4 + packages/pigeon/lib/generator_tools.dart | 2 +- packages/pigeon/lib/swift_generator.dart | 4 +- .../example/integration_test/test.dart | 79 ++++++ .../ios/RunnerTests/AsyncHandlersTest.swift | 2 +- .../test_plugin/example/lib/main.dart | 23 +- .../test_plugin/example/pubspec.yaml | 2 + .../platform_tests/test_plugin/lib/.gitignore | 9 +- .../test_plugin/lib/all_datatypes.gen.dart | 245 ++++++++++++++++++ .../test_plugin/lib/all_void.gen.dart | 70 +++++ .../macos/Classes/TestPlugin.swift | 26 +- packages/pigeon/pubspec.yaml | 2 +- packages/pigeon/run_tests.sh | 13 +- packages/pigeon/tool/run_tests.dart | 32 ++- 14 files changed, 478 insertions(+), 35 deletions(-) create mode 100644 packages/pigeon/platform_tests/test_plugin/example/integration_test/test.dart create mode 100644 packages/pigeon/platform_tests/test_plugin/lib/all_datatypes.gen.dart create mode 100644 packages/pigeon/platform_tests/test_plugin/lib/all_void.gen.dart diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index 5cb782703f..37b6da9df7 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.2.7 + +* [swift] Fixes a bug when calling methods that return `void`. + ## 4.2.6 * Fixes bug with parsing documentation comments that start with '/'. diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index 23641d39d8..7916bda072 100644 --- a/packages/pigeon/lib/generator_tools.dart +++ b/packages/pigeon/lib/generator_tools.dart @@ -9,7 +9,7 @@ import 'dart:mirrors'; import 'ast.dart'; /// The current version of pigeon. This must match the version in pubspec.yaml. -const String pigeonVersion = '4.2.6'; +const String pigeonVersion = '4.2.7'; /// Read all the content from [stdin] to a String. String readStdin() { diff --git a/packages/pigeon/lib/swift_generator.dart b/packages/pigeon/lib/swift_generator.dart index 758199d77b..92e310515c 100644 --- a/packages/pigeon/lib/swift_generator.dart +++ b/packages/pigeon/lib/swift_generator.dart @@ -232,7 +232,7 @@ void _writeHostApi(Indent indent, Api api, Root root) { indent.write('$call '); if (method.returnType.isVoid) { indent.scoped('{', '}', () { - indent.writeln('reply(nil)'); + indent.writeln('reply(wrapResult(nil))'); }); } else { indent.scoped('{ result in', '}', () { @@ -242,7 +242,7 @@ void _writeHostApi(Indent indent, Api api, Root root) { } else { if (method.returnType.isVoid) { indent.writeln(call); - indent.writeln('reply(nil)'); + indent.writeln('reply(wrapResult(nil))'); } else { indent.writeln('let result = $call'); indent.writeln('reply(wrapResult(result))'); diff --git a/packages/pigeon/platform_tests/test_plugin/example/integration_test/test.dart b/packages/pigeon/platform_tests/test_plugin/example/integration_test/test.dart new file mode 100644 index 0000000000..28a371600d --- /dev/null +++ b/packages/pigeon/platform_tests/test_plugin/example/integration_test/test.dart @@ -0,0 +1,79 @@ +// 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. + +// TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#104231) +// ignore: unnecessary_import +import 'dart:typed_data'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:test_plugin/all_datatypes.gen.dart'; +import 'package:test_plugin/all_void.gen.dart'; + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('Host API tests', () { + testWidgets('voidCallVoidReturn', (WidgetTester _) async { + final AllVoidHostApi api = AllVoidHostApi(); + + expect(api.doit(), completes); + }); + + testWidgets('allDataTypesEcho', (WidgetTester _) async { + final HostEverything api = HostEverything(); + + final Everything sentObject = Everything( + aBool: true, + anInt: 42, + aDouble: 3.14159, + aString: 'Hello host!', + aByteArray: Uint8List.fromList([1, 2, 3]), + a4ByteArray: Int32List.fromList([4, 5, 6]), + a8ByteArray: Int64List.fromList([7, 8, 9]), + aFloatArray: Float64List.fromList([2.71828, 3.14159]), + aList: ['Thing 1', 2], + aMap: {'a': 1, 'b': 2.0}, + nestedList: >[ + [true, false], + [false, true] + ], + ); + + final Everything echoObject = await api.echo(sentObject); + expect(echoObject.aBool, sentObject.aBool); + expect(echoObject.anInt, sentObject.anInt); + expect(echoObject.aDouble, sentObject.aDouble); + expect(echoObject.aString, sentObject.aString); + // TODO(stuartmorgan): Enable these once they work for all generators; + // currently at least Swift is broken. + // See https://github.com/flutter/flutter/issues/115906 + //expect(echoObject.aByteArray, sentObject.aByteArray); + //expect(echoObject.a4ByteArray, sentObject.a4ByteArray); + //expect(echoObject.a8ByteArray, sentObject.a8ByteArray); + //expect(echoObject.aFloatArray, sentObject.aFloatArray); + expect(listEquals(echoObject.aList, sentObject.aList), true); + expect(mapEquals(echoObject.aMap, sentObject.aMap), true); + expect(echoObject.nestedList?.length, sentObject.nestedList?.length); + // TODO(stuartmorgan): Enable this once the Dart types are fixed; see + // https://github.com/flutter/flutter/issues/116117 + //for (int i = 0; i < echoObject.nestedList!.length; i++) { + // expect(listEquals(echoObject.nestedList![i], sentObject.nestedList![i]), + // true); + //} + expect( + mapEquals( + echoObject.mapWithAnnotations, sentObject.mapWithAnnotations), + true); + expect( + mapEquals(echoObject.mapWithObject, sentObject.mapWithObject), true); + }); + }); + + group('Flutter API tests', () { + // TODO(stuartmorgan): Add Flutter API tests, driven by wrapper host APIs + // that forward the arguments and return values in the opposite direction. + }); +} diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift index 434b84c701..817e04eb95 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift @@ -44,7 +44,7 @@ class AsyncHandlersTest: XCTestCase { let expectation = XCTestExpectation(description: "voidvoid callback") binaryMessenger.handlers[channelName]?(nil) { data in let outputMap = binaryMessenger.codec.decode(data) as? [String: Any] - XCTAssertNil(outputMap?["result"]) + XCTAssertEqual(outputMap?["result"] as! NSNull, NSNull()) XCTAssertNil(outputMap?["error"]) expectation.fulfill() } diff --git a/packages/pigeon/platform_tests/test_plugin/example/lib/main.dart b/packages/pigeon/platform_tests/test_plugin/example/lib/main.dart index 4355287e7b..e063cc96b5 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/lib/main.dart +++ b/packages/pigeon/platform_tests/test_plugin/example/lib/main.dart @@ -5,6 +5,7 @@ // ignore_for_file: public_member_api_docs import 'package:flutter/material.dart'; +import 'package:test_plugin/all_void.gen.dart'; import 'package:test_plugin/test_plugin.dart'; void main() { @@ -21,6 +22,8 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { // ignore: unused_field final TestPlugin _testPlugin = TestPlugin(); + late final AllVoidHostApi api; + String status = 'Calling...'; @override void initState() { @@ -29,9 +32,18 @@ class _MyAppState extends State { } Future initPlatformState() async { - // TODO(tarrinneal): Call TestPlugin methods here for manual integration - // testing, once they exist. See - // https://github.com/flutter/flutter/issues/111505 + api = AllVoidHostApi(); + try { + await api.doit(); + } catch (e) { + setState(() { + status = 'Failed: $e'; + }); + return; + } + setState(() { + status = 'Success!'; + }); } @override @@ -41,9 +53,8 @@ class _MyAppState extends State { appBar: AppBar( title: const Text('Pigeon integration tests'), ), - body: const Center( - child: Text( - 'TODO, see https://github.com/flutter/flutter/issues/111505'), + body: Center( + child: Text(status), ), ), ); diff --git a/packages/pigeon/platform_tests/test_plugin/example/pubspec.yaml b/packages/pigeon/platform_tests/test_plugin/example/pubspec.yaml index 632cdf9a9c..1311268db6 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/pubspec.yaml +++ b/packages/pigeon/platform_tests/test_plugin/example/pubspec.yaml @@ -14,6 +14,8 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + integration_test: + sdk: flutter flutter: uses-material-design: true diff --git a/packages/pigeon/platform_tests/test_plugin/lib/.gitignore b/packages/pigeon/platform_tests/test_plugin/lib/.gitignore index b81308f4f4..2f74fbcce6 100644 --- a/packages/pigeon/platform_tests/test_plugin/lib/.gitignore +++ b/packages/pigeon/platform_tests/test_plugin/lib/.gitignore @@ -2,8 +2,7 @@ # changes on generated files. This will need a way to avoid unnecessary churn, # such as a flag to suppress version stamp generation. *.gen.dart -# TODO(stuartmorgan): Add exceptions for specific files that are used in -# integration tests, as they will need to be checked in to avoid analysis -# failures. The exclusion of other files is to prevent having multiple -# copies of all of the Dart output until more tests are restructured to -# minimize duplication. +# The following are files that are used in integration tests, which need to be +# checked in to avoid analysis failures. +!all_datatypes.gen.dart +!all_void.gen.dart diff --git a/packages/pigeon/platform_tests/test_plugin/lib/all_datatypes.gen.dart b/packages/pigeon/platform_tests/test_plugin/lib/all_datatypes.gen.dart new file mode 100644 index 0000000000..dada870e77 --- /dev/null +++ b/packages/pigeon/platform_tests/test_plugin/lib/all_datatypes.gen.dart @@ -0,0 +1,245 @@ +// 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 (v4.2.7), 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 +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'; + +class Everything { + Everything({ + this.aBool, + this.anInt, + this.aDouble, + this.aString, + this.aByteArray, + this.a4ByteArray, + this.a8ByteArray, + this.aFloatArray, + this.aList, + this.aMap, + this.nestedList, + this.mapWithAnnotations, + this.mapWithObject, + }); + + bool? aBool; + int? anInt; + double? aDouble; + String? aString; + Uint8List? aByteArray; + Int32List? a4ByteArray; + Int64List? a8ByteArray; + Float64List? aFloatArray; + List? aList; + Map? aMap; + List?>? nestedList; + Map? mapWithAnnotations; + Map? mapWithObject; + + Object encode() { + final Map pigeonMap = {}; + pigeonMap['aBool'] = aBool; + pigeonMap['anInt'] = anInt; + pigeonMap['aDouble'] = aDouble; + pigeonMap['aString'] = aString; + pigeonMap['aByteArray'] = aByteArray; + pigeonMap['a4ByteArray'] = a4ByteArray; + pigeonMap['a8ByteArray'] = a8ByteArray; + pigeonMap['aFloatArray'] = aFloatArray; + pigeonMap['aList'] = aList; + pigeonMap['aMap'] = aMap; + pigeonMap['nestedList'] = nestedList; + pigeonMap['mapWithAnnotations'] = mapWithAnnotations; + pigeonMap['mapWithObject'] = mapWithObject; + return pigeonMap; + } + + static Everything decode(Object message) { + final Map pigeonMap = message as Map; + return Everything( + aBool: pigeonMap['aBool'] as bool?, + anInt: pigeonMap['anInt'] as int?, + aDouble: pigeonMap['aDouble'] as double?, + aString: pigeonMap['aString'] as String?, + aByteArray: pigeonMap['aByteArray'] as Uint8List?, + a4ByteArray: pigeonMap['a4ByteArray'] as Int32List?, + a8ByteArray: pigeonMap['a8ByteArray'] as Int64List?, + aFloatArray: pigeonMap['aFloatArray'] as Float64List?, + aList: pigeonMap['aList'] as List?, + aMap: pigeonMap['aMap'] as Map?, + nestedList: + (pigeonMap['nestedList'] as List?)?.cast?>(), + mapWithAnnotations: + (pigeonMap['mapWithAnnotations'] as Map?) + ?.cast(), + mapWithObject: (pigeonMap['mapWithObject'] as Map?) + ?.cast(), + ); + } +} + +class _HostEverythingCodec extends StandardMessageCodec { + const _HostEverythingCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is Everything) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return Everything.decode(readValue(buffer)!); + + default: + return super.readValueOfType(type, buffer); + } + } +} + +class HostEverything { + /// Constructor for [HostEverything]. 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. + HostEverything({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = _HostEverythingCodec(); + + Future giveMeEverything() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.HostEverything.giveMeEverything', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send(null) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else if (replyMap['result'] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyMap['result'] as Everything?)!; + } + } + + Future echo(Everything arg_everything) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.HostEverything.echo', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send([arg_everything]) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else if (replyMap['result'] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyMap['result'] as Everything?)!; + } + } +} + +class _FlutterEverythingCodec extends StandardMessageCodec { + const _FlutterEverythingCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is Everything) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return Everything.decode(readValue(buffer)!); + + default: + return super.readValueOfType(type, buffer); + } + } +} + +abstract class FlutterEverything { + static const MessageCodec codec = _FlutterEverythingCodec(); + + Everything giveMeEverything(); + Everything echo(Everything everything); + static void setup(FlutterEverything? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FlutterEverything.giveMeEverything', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + final Everything output = api.giveMeEverything(); + return output; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FlutterEverything.echo', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FlutterEverything.echo was null.'); + final List args = (message as List?)!; + final Everything? arg_everything = (args[0] as Everything?); + assert(arg_everything != null, + 'Argument for dev.flutter.pigeon.FlutterEverything.echo was null, expected non-null Everything.'); + final Everything output = api.echo(arg_everything!); + return output; + }); + } + } + } +} diff --git a/packages/pigeon/platform_tests/test_plugin/lib/all_void.gen.dart b/packages/pigeon/platform_tests/test_plugin/lib/all_void.gen.dart new file mode 100644 index 0000000000..aec71fdd95 --- /dev/null +++ b/packages/pigeon/platform_tests/test_plugin/lib/all_void.gen.dart @@ -0,0 +1,70 @@ +// 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 (v4.2.7), 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 +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'; + +abstract class AllVoidFlutterApi { + static const MessageCodec codec = StandardMessageCodec(); + + void doit(); + static void setup(AllVoidFlutterApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.AllVoidFlutterApi.doit', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + api.doit(); + return; + }); + } + } + } +} + +class AllVoidHostApi { + /// Constructor for [AllVoidHostApi]. 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. + AllVoidHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = StandardMessageCodec(); + + Future doit() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.AllVoidHostApi.doit', codec, + binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send(null) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyMap['error'] != null) { + final Map error = + (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return; + } + } +} 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 699a7de6be..d713b4ce16 100644 --- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift @@ -6,14 +6,30 @@ import Cocoa import FlutterMacOS /** - * This plugin is currently a no-op since only unit tests have been set up. - * In the future, this will register Pigeon APIs used in integration tests. + * This plugin handles the native side of the integration tests in + * example/integration_test/. */ -public class TestPlugin: NSObject, FlutterPlugin { +public class TestPlugin: NSObject, FlutterPlugin, AllVoidHostApi, HostEverything { public static func register(with registrar: FlutterPluginRegistrar) { + let plugin = TestPlugin() + AllVoidHostApiSetup.setUp(binaryMessenger: registrar.messenger, api: plugin) + HostEverythingSetup.setUp(binaryMessenger: registrar.messenger, api: plugin) } - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - result(FlutterMethodNotImplemented) + // MARK: AllVoidHostApi implementation + + func doit() { + // No-op + } + + // MARK: HostEverything implementation + + func giveMeEverything() -> Everything { + // Currently unused in integration tests, so just return an empty object. + return Everything() + } + + func echo(everything: Everything) -> Everything { + return everything } } diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index 639d3e153f..baa21d22da 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%3Apigeon -version: 4.2.6 # This must match the version in lib/generator_tools.dart +version: 4.2.7 # This must match the version in lib/generator_tools.dart environment: sdk: ">=2.12.0 <3.0.0" diff --git a/packages/pigeon/run_tests.sh b/packages/pigeon/run_tests.sh index 3089a45455..b294e30e99 100755 --- a/packages/pigeon/run_tests.sh +++ b/packages/pigeon/run_tests.sh @@ -166,7 +166,11 @@ run_ios_swift_unittests() { } run_macos_swift_unittests() { - dart run tool/run_tests.dart -t mac_swift_unittests --skip-generation + dart run tool/run_tests.dart -t macos_swift_unittests --skip-generation +} + +run_macos_swift_e2e_tests() { + dart run tool/run_tests.dart -t macos_swift_integration_tests --skip-generation } run_android_kotlin_unittests() { @@ -255,6 +259,7 @@ should_run_ios_unittests=true should_run_ios_swift_unittests=true should_run_mock_handler_tests=true should_run_macos_swift_unittests=true +should_run_macos_swift_e2e_tests=true should_run_android_kotlin_unittests=true while getopts "t:l?h" opt; do case $opt in @@ -268,6 +273,7 @@ while getopts "t:l?h" opt; do should_run_ios_swift_unittests=false should_run_mock_handler_tests=false should_run_macos_swift_unittests=false + should_run_macos_swift_e2e_tests=false should_run_android_kotlin_unittests=false case $OPTARG in # TODO(stuartmorgan): Rename to include "java". @@ -281,6 +287,7 @@ while getopts "t:l?h" opt; do ios_swift_unittests) should_run_ios_swift_unittests=true ;; mock_handler_tests) should_run_mock_handler_tests=true ;; macos_swift_unittests) should_run_macos_swift_unittests=true ;; + macos_swift_e2e_tests) should_run_macos_swift_e2e_tests=true ;; android_kotlin_unittests) should_run_android_kotlin_unittests=true ;; *) echo "unrecognized test: $OPTARG" @@ -300,6 +307,7 @@ while getopts "t:l?h" opt; do ios_swift_unittests - Unit tests on generated Swift code. mock_handler_tests - Unit tests on generated Dart mock handler code. macos_swift_unittests - Unit tests on generated Swift code on macOS. + macos_swift_e2e_tests - Integration tests on generated Swift code on macOS. " exit 1 ;; @@ -356,6 +364,9 @@ fi if [ "$should_run_macos_swift_unittests" = true ]; then run_macos_swift_unittests fi +if [ "$should_run_macos_swift_e2e_tests" = true ]; then + run_macos_swift_e2e_tests +fi if [ "$should_run_android_kotlin_unittests" = true ]; then run_android_kotlin_unittests fi diff --git a/packages/pigeon/tool/run_tests.dart b/packages/pigeon/tool/run_tests.dart index b354ac1099..afa0b98f4f 100644 --- a/packages/pigeon/tool/run_tests.dart +++ b/packages/pigeon/tool/run_tests.dart @@ -24,7 +24,8 @@ const String _testFlag = 'test'; const String _listFlag = 'list'; const String _skipGenerationFlag = 'skip-generation'; -const String testPluginRelativePath = 'platform_tests/test_plugin'; +const String _testPluginRelativePath = 'platform_tests/test_plugin'; +const String _integrationTestFileRelativePath = 'integration_test/test.dart'; @immutable class _TestInfo { @@ -52,18 +53,18 @@ const Map _tests = { 'flutter_unittests': _TestInfo( function: _runFlutterUnitTests, description: 'Unit tests on generated Dart code.'), - 'ios_e2e_tests': _TestInfo( - function: _runIosE2eTests, - description: 'End-to-end Objective-C tests run on iOS Simulator'), 'ios_unittests': _TestInfo( function: _runIosUnitTests, description: 'Unit tests on generated Objective-C code.'), 'ios_swift_unittests': _TestInfo( function: _runIosSwiftUnitTests, description: 'Unit tests on generated Swift code.'), - 'mac_swift_unittests': _TestInfo( + 'macos_swift_unittests': _TestInfo( function: _runMacOSSwiftUnitTests, description: 'Unit tests on generated Swift code on macOS.'), + 'macos_swift_integration_tests': _TestInfo( + function: _runMacOSSwiftIntegrationTests, + description: 'Integration tests on generated Swift code on macOS.'), 'mock_handler_tests': _TestInfo( function: _runMockHandlerTests, description: 'Unit tests on generated Dart mock handler code.'), @@ -74,7 +75,7 @@ Future _runAndroidUnitTests() async { } Future _runAndroidKotlinUnitTests() async { - const String examplePath = './$testPluginRelativePath/example'; + const String examplePath = './$_testPluginRelativePath/example'; const String androidProjectPath = '$examplePath/android'; final File gradleFile = File(p.join(androidProjectPath, 'gradlew')); if (!gradleFile.existsSync()) { @@ -179,16 +180,12 @@ Future _runFlutterUnitTests() async { return 0; } -Future _runIosE2eTests() async { - throw UnimplementedError('See run_tests.sh.'); -} - Future _runIosUnitTests() async { throw UnimplementedError('See run_tests.sh.'); } Future _runMacOSSwiftUnitTests() async { - const String examplePath = './$testPluginRelativePath/example'; + const String examplePath = './$_testPluginRelativePath/example'; final int compileCode = await runFlutterBuild(examplePath, 'macos'); if (compileCode != 0) { return compileCode; @@ -200,8 +197,17 @@ Future _runMacOSSwiftUnitTests() async { ); } +Future _runMacOSSwiftIntegrationTests() async { + const String examplePath = './$_testPluginRelativePath/example'; + return runFlutterCommand( + examplePath, + 'test', + [_integrationTestFileRelativePath, '-d', 'macos'], + ); +} + Future _runIosSwiftUnitTests() async { - const String examplePath = './$testPluginRelativePath/example'; + const String examplePath = './$_testPluginRelativePath/example'; final int compileCode = await runFlutterBuild( examplePath, 'ios', @@ -238,7 +244,7 @@ Future _runMockHandlerTests() async { } Future _runWindowsUnitTests() async { - const String examplePath = './$testPluginRelativePath/example'; + const String examplePath = './$_testPluginRelativePath/example'; final int compileCode = await runFlutterBuild(examplePath, 'windows'); if (compileCode != 0) { return compileCode;