Actually call argument-less methods. (#265)

I accidentally broke this in an earlier patch.
This commit is contained in:
Ian Hickson
2021-02-03 10:44:19 -08:00
committed by GitHub
parent 5cbdac1903
commit 93ae0899bb
11 changed files with 124 additions and 36 deletions

View File

@ -38,7 +38,7 @@ linter:
- always_specify_types
- annotate_overrides
# - avoid_annotating_with_dynamic # conflicts with always_specify_types
# - avoid_as # conflicts with NNBD
# - avoid_as # no longer relevant with null safety
- avoid_bool_literals_in_conditional_expressions
# - avoid_catches_without_on_clauses # we do this commonly
# - avoid_catching_errors # we do this commonly

View File

@ -1,3 +1,8 @@
## 0.1.19
* Fixed a bug introduced in 0.1.17 where methods without arguments were
no longer being called.
## 0.1.18
* Null safe requires Dart 2.12.

View File

@ -88,6 +88,7 @@ void _writeFlutterApi(
}) {
assert(api.location == ApiLocation.flutter);
final String nullTag = opt.isNullSafe ? '?' : '';
final String unwrapOperator = opt.isNullSafe ? '!' : '';
indent.write('abstract class ${api.name} ');
indent.scoped('{', '}', () {
for (Method func in api.methods) {
@ -106,10 +107,10 @@ void _writeFlutterApi(
indent.writeln(
'const BasicMessageChannel<Object$nullTag> channel =',
);
final String channelName = channelNameFunc == null
? makeChannelName(api, func)
: channelNameFunc(func);
indent.nest(2, () {
final String channelName = channelNameFunc == null
? makeChannelName(api, func)
: channelNameFunc(func);
indent.writeln(
'BasicMessageChannel<Object$nullTag>(\'$channelName\', StandardMessageCodec());',
);
@ -134,16 +135,16 @@ void _writeFlutterApi(
: func.returnType == 'void'
? 'return;'
: 'return null;';
indent.write('if (message == null) ');
indent.scoped('{', '}', () {
indent.writeln(emptyReturnStatement);
});
String call;
if (argType == 'void') {
indent.writeln('// ignore message');
call = 'api.${func.name}()';
} else {
indent.writeln(
'final $argType input = $argType.decode(message);',
'assert(message != null, \'Argument for $channelName was null. Expected $argType.\');',
);
indent.writeln(
'final $argType input = $argType.decode(message$unwrapOperator);',
);
call = 'api.${func.name}(input)';
}
@ -213,7 +214,6 @@ void generateDart(DartOptions opt, Root root, StringSink sink) {
if (klass.fields.isNotEmpty) {
indent.writeln('');
}
indent.writeln('// ignore: unused_element');
indent.write('Object encode() ');
indent.scoped('{', '}', () {
indent.writeln(
@ -232,7 +232,6 @@ void generateDart(DartOptions opt, Root root, StringSink sink) {
indent.writeln('return pigeonMap;');
});
indent.writeln('');
indent.writeln('// ignore: unused_element');
indent.write(
'static ${klass.name} decode(Object message) ',
);

View File

@ -7,8 +7,8 @@ import 'dart:io';
import 'dart:mirrors';
import 'ast.dart';
/// The current version of pigeon.
const String pigeonVersion = '0.1.18';
/// The current version of pigeon. This must match the version in pubspec.yaml.
const String pigeonVersion = '0.1.19';
/// Read all the content from [stdin] to a String.
String readStdin() {

View File

@ -1,16 +1,16 @@
// Autogenerated from Pigeon (v0.1.15), do not edit directly.
// Autogenerated from Pigeon (v0.1.19), 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
// @dart = 2.8
import 'dart:async';
import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;
import 'package:flutter/services.dart';
class SearchReply {
String result;
String error;
// ignore: unused_element
Object encode() {
final Map<Object, Object> pigeonMap = <Object, Object>{};
pigeonMap['result'] = result;
@ -18,7 +18,6 @@ class SearchReply {
return pigeonMap;
}
// ignore: unused_element
static SearchReply decode(Object message) {
final Map<Object, Object> pigeonMap = message as Map<Object, Object>;
return SearchReply()
@ -32,7 +31,6 @@ class SearchRequest {
int anInt;
bool aBool;
// ignore: unused_element
Object encode() {
final Map<Object, Object> pigeonMap = <Object, Object>{};
pigeonMap['query'] = query;
@ -41,7 +39,6 @@ class SearchRequest {
return pigeonMap;
}
// ignore: unused_element
static SearchRequest decode(Object message) {
final Map<Object, Object> pigeonMap = message as Map<Object, Object>;
return SearchRequest()
@ -54,14 +51,12 @@ class SearchRequest {
class Nested {
SearchRequest request;
// ignore: unused_element
Object encode() {
final Map<Object, Object> pigeonMap = <Object, Object>{};
pigeonMap['request'] = request == null ? null : request.encode();
return pigeonMap;
}
// ignore: unused_element
static Nested decode(Object message) {
final Map<Object, Object> pigeonMap = message as Map<Object, Object>;
return Nested()
@ -81,9 +76,8 @@ abstract class FlutterSearchApi {
channel.setMessageHandler(null);
} else {
channel.setMessageHandler((Object message) async {
if (message == null) {
return null;
}
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();
@ -121,6 +115,30 @@ class NestedApi {
}
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
}
}
Future<SearchReply> search(SearchRequest arg) async {
final Object encoded = arg.encode();
const BasicMessageChannel<Object> channel = BasicMessageChannel<Object>(

View File

@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v0.1.15), do not edit directly.
// Autogenerated from Pigeon (v0.1.19), 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
// @dart = 2.8
@ -19,9 +19,8 @@ abstract class TestNestedApi {
channel.setMockMessageHandler(null);
} else {
channel.setMockMessageHandler((Object message) async {
if (message == null) {
return <Object, Object>{};
}
assert(message != null,
'Argument for dev.flutter.pigeon.NestedApi.search was null. Expected Nested.');
final Nested input = Nested.decode(message);
final SearchReply output = api.search(input);
return <Object, Object>{'result': output.encode()};
@ -32,8 +31,22 @@ abstract class TestNestedApi {
}
abstract class TestHostApi {
void initialize();
SearchReply search(SearchRequest arg);
static void setup(TestHostApi api) {
{
const BasicMessageChannel<Object> channel = BasicMessageChannel<Object>(
'dev.flutter.pigeon.Api.initialize', StandardMessageCodec());
if (api == null) {
channel.setMockMessageHandler(null);
} else {
channel.setMockMessageHandler((Object message) async {
// ignore message
api.initialize();
return <Object, Object>{};
});
}
}
{
const BasicMessageChannel<Object> channel = BasicMessageChannel<Object>(
'dev.flutter.pigeon.Api.search', StandardMessageCodec());
@ -41,9 +54,8 @@ abstract class TestHostApi {
channel.setMockMessageHandler(null);
} else {
channel.setMockMessageHandler((Object message) async {
if (message == null) {
return <Object, Object>{};
}
assert(message != null,
'Argument for dev.flutter.pigeon.Api.search was null. Expected SearchRequest.');
final SearchRequest input = SearchRequest.decode(message);
final SearchReply output = api.search(input);
return <Object, Object>{'result': output.encode()};

View File

@ -2,16 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'message.dart';
import 'test.dart';
class Mock implements TestHostApi {
bool didCall = false;
List<String> log = <String>[];
@override
void initialize() {
log.add('initialize');
}
@override
SearchReply search(SearchRequest arg) {
didCall = true;
log.add('search');
return SearchReply()..result = arg.query;
}
}
@ -46,7 +55,48 @@ void main() {
final Mock mock = Mock();
TestHostApi.setup(mock);
final SearchReply reply = await api.search(SearchRequest()..query = 'foo');
expect(mock.didCall, true);
expect(mock.log, <String>['search']);
expect(reply.result, 'foo');
});
test('no-arg calls', () async {
final Api api = Api();
final Mock mock = Mock();
TestHostApi.setup(mock);
await api.initialize();
expect(mock.log, <String>['initialize']);
});
test(
'calling methods with null',
() async {
final Mock mock = Mock();
TestHostApi.setup(mock);
expect(
await const BasicMessageChannel<Object>(
'dev.flutter.pigeon.Api.initialize',
StandardMessageCodec(),
).send(null),
isEmpty,
);
try {
await const BasicMessageChannel<Object>(
'dev.flutter.pigeon.Api.search',
StandardMessageCodec(),
).send(null) as Map<Object, Object>;
expect(true, isFalse); // should not reach here
} catch (error) {
expect(error, isAssertionError);
expect(
error.toString(),
contains(
'Argument for dev.flutter.pigeon.Api.search was null. Expected SearchRequest.',
),
);
}
expect(mock.log, <String>['initialize']);
},
// TODO(ianh): skip can be removed after first stable release in 2021
skip: Platform.environment['CHANNEL'] == 'stable',
);
}

View File

@ -20,6 +20,7 @@ class SearchReply {
@HostApi(dartHostTestHandler: 'TestHostApi')
abstract class Api {
void initialize();
SearchReply search(SearchRequest request);
}

View File

@ -1,5 +1,5 @@
name: pigeon
version: 0.1.18
version: 0.1.19 # This must match the version in lib/generator_tools.dart
description: Code generator tool to make communication between Flutter and the host platform type-safe and easier.
homepage: https://github.com/flutter/packages/tree/master/packages/pigeon
dependencies:

View File

@ -144,7 +144,10 @@ void main() {
final StringBuffer sink = StringBuffer();
generateDart(DartOptions(), root, sink);
final String code = sink.toString();
expect(code, isNot(matches('=.*doSomething')));
// The next line verifies that we're not setting a variable to the value of "doSomething", but
// ignores the line where we assert the value of the argument isn't null, since on that line
// we mention "doSomething" in the assertion message.
expect(code, isNot(matches('[^!]=.*doSomething')));
expect(code, contains('doSomething('));
expect(code, isNot(contains('.encode()')));
});

View File

@ -11,7 +11,7 @@ void main() {
test('pigeon version matches pubspec', () {
final String pubspecPath = '${Directory.current.path}/pubspec.yaml';
final String pubspec = File(pubspecPath).readAsStringSync();
final RegExp regex = RegExp('version:\s*(.*)');
final RegExp regex = RegExp('version:\s*(.*?) #');
final RegExpMatch match = regex.firstMatch(pubspec);
expect(match, isNotNull);
expect(pigeonVersion, match.group(1).trim());