[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
diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md
index 5cb7827..37b6da9 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 23641d3..7916bda 100644
--- a/packages/pigeon/lib/generator_tools.dart
+++ b/packages/pigeon/lib/generator_tools.dart
@@ -9,7 +9,7 @@
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 758199d..92e3105 100644
--- a/packages/pigeon/lib/swift_generator.dart
+++ b/packages/pigeon/lib/swift_generator.dart
@@ -232,7 +232,7 @@
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 @@
} 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 0000000..28a3716
--- /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(<int>[1, 2, 3]),
+ a4ByteArray: Int32List.fromList(<int>[4, 5, 6]),
+ a8ByteArray: Int64List.fromList(<int>[7, 8, 9]),
+ aFloatArray: Float64List.fromList(<double>[2.71828, 3.14159]),
+ aList: <Object?>['Thing 1', 2],
+ aMap: <Object?, Object?>{'a': 1, 'b': 2.0},
+ nestedList: <List<bool>>[
+ <bool>[true, false],
+ <bool>[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 434b84c..817e04e 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 @@
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 4355287..e063cc9 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 _MyAppState extends State<MyApp> {
// ignore: unused_field
final TestPlugin _testPlugin = TestPlugin();
+ late final AllVoidHostApi api;
+ String status = 'Calling...';
@override
void initState() {
@@ -29,9 +32,18 @@
}
Future<void> 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 @@
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 632cdf9..1311268 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 @@
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 b81308f..2f74fbc 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 0000000..dada870
--- /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<Object?>? aList;
+ Map<Object?, Object?>? aMap;
+ List<List<bool?>?>? nestedList;
+ Map<String?, String?>? mapWithAnnotations;
+ Map<String?, Object?>? mapWithObject;
+
+ Object encode() {
+ final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
+ 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<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
+ 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<Object?>?,
+ aMap: pigeonMap['aMap'] as Map<Object?, Object?>?,
+ nestedList:
+ (pigeonMap['nestedList'] as List<Object?>?)?.cast<List<bool?>?>(),
+ mapWithAnnotations:
+ (pigeonMap['mapWithAnnotations'] as Map<Object?, Object?>?)
+ ?.cast<String?, String?>(),
+ mapWithObject: (pigeonMap['mapWithObject'] as Map<Object?, Object?>?)
+ ?.cast<String?, Object?>(),
+ );
+ }
+}
+
+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<Object?> codec = _HostEverythingCodec();
+
+ Future<Everything> giveMeEverything() async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.HostEverything.giveMeEverything', codec,
+ binaryMessenger: _binaryMessenger);
+ final Map<Object?, Object?>? replyMap =
+ await channel.send(null) as Map<Object?, Object?>?;
+ if (replyMap == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyMap['error'] != null) {
+ final Map<Object?, Object?> error =
+ (replyMap['error'] as Map<Object?, Object?>?)!;
+ 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<Everything> echo(Everything arg_everything) async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.HostEverything.echo', codec,
+ binaryMessenger: _binaryMessenger);
+ final Map<Object?, Object?>? replyMap =
+ await channel.send(<Object?>[arg_everything]) as Map<Object?, Object?>?;
+ if (replyMap == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyMap['error'] != null) {
+ final Map<Object?, Object?> error =
+ (replyMap['error'] as Map<Object?, Object?>?)!;
+ 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<Object?> codec = _FlutterEverythingCodec();
+
+ Everything giveMeEverything();
+ Everything echo(Everything everything);
+ static void setup(FlutterEverything? api,
+ {BinaryMessenger? binaryMessenger}) {
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ '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<Object?> channel = BasicMessageChannel<Object?>(
+ '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<Object?> args = (message as List<Object?>?)!;
+ 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 0000000..aec71fd
--- /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<Object?> codec = StandardMessageCodec();
+
+ void doit();
+ static void setup(AllVoidFlutterApi? api,
+ {BinaryMessenger? binaryMessenger}) {
+ {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ '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<Object?> codec = StandardMessageCodec();
+
+ Future<void> doit() async {
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.AllVoidHostApi.doit', codec,
+ binaryMessenger: _binaryMessenger);
+ final Map<Object?, Object?>? replyMap =
+ await channel.send(null) as Map<Object?, Object?>?;
+ if (replyMap == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ );
+ } else if (replyMap['error'] != null) {
+ final Map<Object?, Object?> error =
+ (replyMap['error'] as Map<Object?, Object?>?)!;
+ 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 699a7de..d713b4c 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 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 639d3e1..baa21d2 100644
--- a/packages/pigeon/pubspec.yaml
+++ b/packages/pigeon/pubspec.yaml
@@ -2,7 +2,7 @@
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 3089a45..b294e30 100755
--- a/packages/pigeon/run_tests.sh
+++ b/packages/pigeon/run_tests.sh
@@ -166,7 +166,11 @@
}
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_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 @@
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 @@
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 @@
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 @@
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 b354ac1..afa0b98 100644
--- a/packages/pigeon/tool/run_tests.dart
+++ b/packages/pigeon/tool/run_tests.dart
@@ -24,7 +24,8 @@
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 @@
'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<int> _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 @@
return 0;
}
-Future<int> _runIosE2eTests() async {
- throw UnimplementedError('See run_tests.sh.');
-}
-
Future<int> _runIosUnitTests() async {
throw UnimplementedError('See run_tests.sh.');
}
Future<int> _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<int> _runMacOSSwiftIntegrationTests() async {
+ const String examplePath = './$_testPluginRelativePath/example';
+ return runFlutterCommand(
+ examplePath,
+ 'test',
+ <String>[_integrationTestFileRelativePath, '-d', 'macos'],
+ );
+}
+
Future<int> _runIosSwiftUnitTests() async {
- const String examplePath = './$testPluginRelativePath/example';
+ const String examplePath = './$_testPluginRelativePath/example';
final int compileCode = await runFlutterBuild(
examplePath,
'ios',
@@ -238,7 +244,7 @@
}
Future<int> _runWindowsUnitTests() async {
- const String examplePath = './$testPluginRelativePath/example';
+ const String examplePath = './$_testPluginRelativePath/example';
final int compileCode = await runFlutterBuild(examplePath, 'windows');
if (compileCode != 0) {
return compileCode;