[pigeon] Added more dart unit tests, added commented out test for the encoder fix. (#329)
diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md
index e611fa4..0125754 100644
--- a/packages/pigeon/CHANGELOG.md
+++ b/packages/pigeon/CHANGELOG.md
@@ -1,6 +1,7 @@
## 0.2.1
* Java: Fixed issue where multiple async HostApis can generate multiple Result interfaces.
+* Dart: Made it so you can specify the BinaryMessenger of the generated APIs.
## 0.2.0
diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart
index 41c1dcb..56fdc22 100644
--- a/packages/pigeon/lib/dart_generator.dart
+++ b/packages/pigeon/lib/dart_generator.dart
@@ -28,6 +28,15 @@
bool first = true;
indent.write('class ${api.name} ');
indent.scoped('{', '}', () {
+ indent.format('''
+/// Constructor for [${api.name}]. 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.
+${api.name}({BinaryMessenger$nullTag binaryMessenger}) : _binaryMessenger = binaryMessenger;
+
+final BinaryMessenger$nullTag _binaryMessenger;
+''');
+
for (final Method func in api.methods) {
if (!first) {
indent.writeln('');
@@ -51,10 +60,10 @@
}
final String channelName = makeChannelName(api, func);
indent.writeln(
- 'const BasicMessageChannel<Object$nullTag> channel = BasicMessageChannel<Object$nullTag>(');
+ 'final BasicMessageChannel<Object$nullTag> channel = BasicMessageChannel<Object$nullTag>(');
indent.nest(2, () {
indent.writeln(
- '\'$channelName\', StandardMessageCodec());',
+ '\'$channelName\', const StandardMessageCodec(), binaryMessenger: _binaryMessenger);',
);
});
final String returnStatement = func.returnType == 'void'
diff --git a/packages/pigeon/pigeons/flutter_unittests.dart b/packages/pigeon/pigeons/flutter_unittests.dart
new file mode 100644
index 0000000..acc28b8
--- /dev/null
+++ b/packages/pigeon/pigeons/flutter_unittests.dart
@@ -0,0 +1,30 @@
+// Copyright 2020 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.
+
+import 'package:pigeon/pigeon.dart';
+
+class SearchRequest {
+ String? query;
+}
+
+class SearchReply {
+ String? result;
+ String? error;
+}
+
+class SearchRequests {
+ // ignore: always_specify_types
+ List? requests;
+}
+
+class SearchReplies {
+ // ignore: always_specify_types
+ List? replies;
+}
+
+@HostApi()
+abstract class Api {
+ SearchReply search(SearchRequest request);
+ SearchReplies doSearches(SearchRequests request);
+}
diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart
index ef41241..5154847 100644
--- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart
+++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart
@@ -1,6 +1,6 @@
-// Autogenerated from Pigeon (v0.1.21), do not edit directly.
+// Autogenerated from Pigeon (v0.2.0), 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
+// 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
// @dart = 2.12
import 'dart:async';
import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;
@@ -28,121 +28,62 @@
class SearchRequest {
String? query;
- int? anInt;
- bool? aBool;
Object encode() {
final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
pigeonMap['query'] = query;
- pigeonMap['anInt'] = anInt;
- pigeonMap['aBool'] = aBool;
return pigeonMap;
}
static SearchRequest decode(Object message) {
final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
- return SearchRequest()
- ..query = pigeonMap['query'] as String?
- ..anInt = pigeonMap['anInt'] as int?
- ..aBool = pigeonMap['aBool'] as bool?;
+ return SearchRequest()..query = pigeonMap['query'] as String?;
}
}
-class Nested {
- SearchRequest? request;
+class SearchReplies {
+ List<Object?>? replies;
Object encode() {
final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
- pigeonMap['request'] = request == null ? null : request!.encode();
+ pigeonMap['replies'] = replies;
return pigeonMap;
}
- static Nested decode(Object message) {
+ static SearchReplies decode(Object message) {
final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
- return Nested()
- ..request = pigeonMap['request'] != null
- ? SearchRequest.decode(pigeonMap['request']!)
- : null;
+ return SearchReplies()..replies = pigeonMap['replies'] as List<Object?>?;
}
}
-abstract class FlutterSearchApi {
- SearchReply search(SearchRequest arg);
- static void setup(FlutterSearchApi? api) {
- {
- const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.FlutterSearchApi.search', StandardMessageCodec());
- if (api == null) {
- channel.setMessageHandler(null);
- } else {
- channel.setMessageHandler((Object? message) async {
- assert(message != null,
- 'Argument for dev.flutter.pigeon.FlutterSearchApi.search was null. Expected SearchRequest.');
- final SearchRequest input = SearchRequest.decode(message!);
- final SearchReply output = api.search(input);
- return output.encode();
- });
- }
- }
- }
-}
+class SearchRequests {
+ List<Object?>? requests;
-class NestedApi {
- Future<SearchReply> search(Nested arg) async {
- final Object encoded = arg.encode();
- const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.NestedApi.search', StandardMessageCodec());
- final Map<Object?, Object?>? replyMap =
- await channel.send(encoded) as Map<Object?, Object?>?;
- if (replyMap == null) {
- throw PlatformException(
- code: 'channel-error',
- message: 'Unable to establish connection on channel.',
- details: null,
- );
- } 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 SearchReply.decode(replyMap['result']!);
- }
+ Object encode() {
+ final Map<Object?, Object?> pigeonMap = <Object?, Object?>{};
+ pigeonMap['requests'] = requests;
+ return pigeonMap;
+ }
+
+ static SearchRequests decode(Object message) {
+ final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?>;
+ return SearchRequests()..requests = pigeonMap['requests'] as List<Object?>?;
}
}
class Api {
- Future<void> initialize() async {
- const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.Api.initialize', StandardMessageCodec());
- 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.',
- details: null,
- );
- } 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 {
- // noop
- }
- }
+ /// Constructor for [Api]. 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.
+ Api({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger;
+
+ final BinaryMessenger? _binaryMessenger;
Future<SearchReply> search(SearchRequest arg) async {
final Object encoded = arg.encode();
- const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
- 'dev.flutter.pigeon.Api.search', StandardMessageCodec());
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.Api.search', const StandardMessageCodec(),
+ binaryMessenger: _binaryMessenger);
final Map<Object?, Object?>? replyMap =
await channel.send(encoded) as Map<Object?, Object?>?;
if (replyMap == null) {
@@ -153,9 +94,9 @@
);
} else if (replyMap['error'] != null) {
final Map<Object?, Object?> error =
- replyMap['error']! as Map<Object?, Object?>;
+ (replyMap['error'] as Map<Object?, Object?>?)!;
throw PlatformException(
- code: error['code']! as String,
+ code: (error['code'] as String?)!,
message: error['message'] as String?,
details: error['details'],
);
@@ -163,4 +104,30 @@
return SearchReply.decode(replyMap['result']!);
}
}
+
+ Future<SearchReplies> doSearches(SearchRequests arg) async {
+ final Object encoded = arg.encode();
+ final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+ 'dev.flutter.pigeon.Api.doSearches', const StandardMessageCodec(),
+ binaryMessenger: _binaryMessenger);
+ final Map<Object?, Object?>? replyMap =
+ await channel.send(encoded) as Map<Object?, Object?>?;
+ if (replyMap == null) {
+ throw PlatformException(
+ code: 'channel-error',
+ message: 'Unable to establish connection on channel.',
+ details: null,
+ );
+ } 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 SearchReplies.decode(replyMap['result']!);
+ }
+ }
}
diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/pubspec.yaml b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/pubspec.yaml
index 32058de..9b21234 100644
--- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/pubspec.yaml
+++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/pubspec.yaml
@@ -10,8 +10,10 @@
sdk: flutter
dev_dependencies:
+ build_runner: ^1.11.0
flutter_test:
sdk: flutter
+ mockito: ^5.0.4
flutter:
uses-material-design: true
diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/null_safe_test.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/null_safe_test.dart
index 523127a..c407fd9 100644
--- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/null_safe_test.dart
+++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/null_safe_test.dart
@@ -2,9 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:async';
+
+import 'package:flutter/services.dart';
import 'package:flutter_unit_tests/null_safe_pigeon.dart';
import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+import 'null_safe_test.mocks.dart';
+@GenerateMocks(<Type>[BinaryMessenger])
void main() {
test('with values filled', () {
final SearchReply reply = SearchReply()
@@ -25,4 +32,43 @@
expect(reply.result, decoded.result);
expect(reply.error, decoded.error);
});
+
+ test('send/receive', () async {
+ final SearchRequest request = SearchRequest()..query = 'hey';
+ final SearchReply reply = SearchReply()..result = 'ho';
+ final BinaryMessenger mockMessenger = MockBinaryMessenger();
+ const MessageCodec<Object?> codec = StandardMessageCodec();
+ final Completer<ByteData?> completer = Completer<ByteData?>();
+ completer.complete(
+ codec.encodeMessage(<String, Object>{'result': reply.encode()}));
+ final Future<ByteData?> sendResult = completer.future;
+ when(mockMessenger.send('dev.flutter.pigeon.Api.search', any))
+ .thenAnswer((Invocation realInvocation) => sendResult);
+ final Api api = Api(binaryMessenger: mockMessenger);
+ final SearchReply readReply = await api.search(request);
+ expect(readReply, isNotNull);
+ expect(reply.result, readReply.result);
+ });
+
+ // TODO(gaaclarke): This test is a companion for the fix to https://github.com/flutter/flutter/issues/80538
+ // test('send/receive list classes', () async {
+ // final SearchRequest request = SearchRequest()
+ // ..query = 'hey';
+ // final SearchReply reply = SearchReply()
+ // ..result = 'ho';
+ // final SearchRequests requests = SearchRequests()
+ // ..requests = <SearchRequest>[request];
+ // final SearchReplies replies = SearchReplies()
+ // ..replies = <SearchReply>[reply];
+ // final BinaryMessenger mockMessenger = MockBinaryMessenger();
+ // const MessageCodec<Object?> codec = StandardMessageCodec();
+ // final Completer<ByteData?> completer = Completer<ByteData?>();
+ // completer.complete(codec.encodeMessage(<String, Object>{'result' : replies.encode()}));
+ // final Future<ByteData?> sendResult = completer.future;
+ // when(mockMessenger.send('dev.flutter.pigeon.Api.search', any)).thenAnswer((Invocation realInvocation) => sendResult);
+ // final Api api = Api(binaryMessenger: mockMessenger);
+ // final SearchReplies readReplies = await api.doSearches(requests);
+ // expect(readReplies, isNotNull);
+ // expect(reply.result, (readReplies.replies![0] as SearchReply?)!.result);
+ // });
}
diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/null_safe_test.mocks.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/null_safe_test.mocks.dart
new file mode 100644
index 0000000..5a326b5
--- /dev/null
+++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/test/null_safe_test.mocks.dart
@@ -0,0 +1,55 @@
+// Mocks generated by Mockito 5.0.4 from annotations
+// in flutter_unit_tests/test/null_safe_test.dart.
+// Do not manually edit this file.
+
+import 'dart:async' as _i3;
+import 'dart:typed_data' as _i4;
+import 'dart:ui' as _i5;
+
+import 'package:flutter/src/services/binary_messenger.dart' as _i2;
+import 'package:mockito/mockito.dart' as _i1;
+
+// ignore_for_file: comment_references
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: always_specify_types
+
+/// A class which mocks [BinaryMessenger].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockBinaryMessenger extends _i1.Mock implements _i2.BinaryMessenger {
+ MockBinaryMessenger() {
+ _i1.throwOnMissingStub(this);
+ }
+
+ @override
+ _i3.Future<void> handlePlatformMessage(String? channel, _i4.ByteData? data,
+ _i5.PlatformMessageResponseCallback? callback) =>
+ (super.noSuchMethod(
+ Invocation.method(#handlePlatformMessage, [channel, data, callback]),
+ returnValue: Future<void>.value(null),
+ returnValueForMissingStub:
+ Future<dynamic>.value()) as _i3.Future<void>);
+ @override
+ _i3.Future<_i4.ByteData?>? send(String? channel, _i4.ByteData? message) =>
+ (super.noSuchMethod(Invocation.method(#send, [channel, message]))
+ as _i3.Future<_i4.ByteData?>?);
+ @override
+ void setMessageHandler(String? channel, _i2.MessageHandler? handler) => super
+ .noSuchMethod(Invocation.method(#setMessageHandler, [channel, handler]),
+ returnValueForMissingStub: null);
+ @override
+ bool checkMessageHandler(String? channel, _i2.MessageHandler? handler) =>
+ (super.noSuchMethod(
+ Invocation.method(#checkMessageHandler, [channel, handler]),
+ returnValue: false) as bool);
+ @override
+ void setMockMessageHandler(String? channel, _i2.MessageHandler? handler) =>
+ super.noSuchMethod(
+ Invocation.method(#setMockMessageHandler, [channel, handler]),
+ returnValueForMissingStub: null);
+ @override
+ bool checkMockMessageHandler(String? channel, _i2.MessageHandler? handler) =>
+ (super.noSuchMethod(
+ Invocation.method(#checkMockMessageHandler, [channel, handler]),
+ returnValue: false) as bool);
+}
diff --git a/packages/pigeon/run_tests.sh b/packages/pigeon/run_tests.sh
index d76d5f8..82f09bb 100755
--- a/packages/pigeon/run_tests.sh
+++ b/packages/pigeon/run_tests.sh
@@ -192,7 +192,7 @@
run_flutter_unittests() {
pushd $PWD
pub run pigeon \
- --input pigeons/message.dart \
+ --input pigeons/flutter_unittests.dart \
--dart_out platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart
cd platform_tests/flutter_null_safe_unit_tests
flutter pub get