Migrate to ChannelBuffers.push (#82564)

This commit is contained in:
Ian Hickson 2021-05-21 15:09:03 -07:00 committed by GitHub
parent fa5883b78e
commit 5e0cc4cba4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
77 changed files with 1119 additions and 738 deletions

View file

@ -11,6 +11,6 @@ void main() {
Ticker((Duration duration) { }).start();
final ByteData? message = const StringCodec().encodeMessage('AppLifecycleState.paused');
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {});
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {});
});
}

View file

@ -29,9 +29,6 @@ void main() {
app.main();
await tester.pumpAndSettle();
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
SystemChannels.textInput.setMockMethodCallHandler(null);
// Focus on a TextFormField.
final Finder finder = find.byKey(const Key('input'));
expect(finder, findsOneWidget);
@ -56,9 +53,6 @@ void main() {
app.main();
await tester.pumpAndSettle();
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
SystemChannels.textInput.setMockMethodCallHandler(null);
// Focus on a TextFormField.
final Finder finder = find.byKey(const Key('empty-input'));
expect(finder, findsOneWidget);
@ -83,9 +77,6 @@ void main() {
app.main();
await tester.pumpAndSettle();
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
SystemChannels.textInput.setMockMethodCallHandler(null);
// This text will show no-enter initially. It will have 'enter-pressed'
// after `onFieldSubmitted` of TextField is triggered.
final Finder textFinder = find.byKey(const Key('text'));
@ -118,9 +109,6 @@ void main() {
app.main();
await tester.pumpAndSettle();
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
SystemChannels.textInput.setMockMethodCallHandler(null);
// Focus on a TextFormField.
final Finder finder = find.byKey(const Key('input'));
expect(finder, findsOneWidget);
@ -152,9 +140,6 @@ void main() {
app.main();
await tester.pumpAndSettle();
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
SystemChannels.textInput.setMockMethodCallHandler(null);
// Focus on a TextFormField.
final Finder finder = find.byKey(const Key('input'));
expect(finder, findsOneWidget);
@ -203,9 +188,6 @@ void main() {
app.main();
await tester.pumpAndSettle();
// TODO(nurhan): https://github.com/flutter/flutter/issues/51885
SystemChannels.textInput.setMockMethodCallHandler(null);
// Select something from the selectable text.
final Finder finder = find.byKey(const Key('selectable'));
expect(finder, findsOneWidget);

View file

@ -5,7 +5,7 @@
import 'dart:async';
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
import 'package:test/test.dart';
import 'package:webdriver/async_io.dart';
// TODO(web): Migrate this test to a normal integration_test with a WidgetTester.
@ -35,6 +35,7 @@ void main() {
test('enable accessibility', () async {
await driver.setSemantics(true);
// TODO(ianh): this delay violates our style guide. We should instead wait for a triggering event.
await Future<void>.delayed(const Duration(seconds: 2));
// A flutter web app may be rendered directly on the body of the page, or

View file

@ -104,8 +104,8 @@ abstract class BindingBase {
/// A number of additional bindings are defined as extensions of
/// [BindingBase], e.g., [ServicesBinding], [RendererBinding], and
/// [WidgetsBinding]. Each of these bindings define behaviors that interact
/// with a [ui.PlatformDispatcher], e.g., [ServicesBinding] registers a
/// [ui.PlatformDispatcher.onPlatformMessage] handler, and [RendererBinding]
/// with a [ui.PlatformDispatcher], e.g., [ServicesBinding] registers
/// listeners with the [ChannelBuffers], and [RendererBinding]
/// registers [ui.PlatformDispatcher.onMetricsChanged],
/// [ui.PlatformDispatcher.onTextScaleFactorChanged],
/// [ui.PlatformDispatcher.onSemanticsEnabledChanged], and

View file

@ -2,12 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'binding.dart';
/// A function which takes a platform message and asynchronously returns an encoded response.
typedef MessageHandler = Future<ByteData?>? Function(ByteData? message);
@ -19,12 +16,39 @@ abstract class BinaryMessenger {
/// const constructors so that they can be used in const expressions.
const BinaryMessenger();
/// Calls the handler registered for the given channel.
/// Queues a message.
///
/// Typically called by [ServicesBinding] to handle platform messages received
/// from [dart:ui.PlatformDispatcher.onPlatformMessage].
/// The returned future completes immediately.
///
/// This method adds the provided message to the given channel (named by the
/// `channel` argument) of the [ChannelBuffers] object. This simulates what
/// happens when a plugin on the platform thread (e.g. Kotlin or Swift code)
/// sends a message to the plugin package on the Dart thread.
///
/// The `data` argument contains the message as encoded bytes. (The format
/// used for the message depends on the channel.)
///
/// The `callback` argument, if non-null, is eventually invoked with the
/// response that would have been sent to the platform thread.
///
/// In production code, it is more efficient to call
/// `ServicesBinding.instance.channelBuffers.push` directly.
///
/// In tests, consider using
/// `tester.binding.defaultBinaryMessenger.handlePlatformMessage` (see
/// [WidgetTester], [TestWidgetsFlutterBinding], [TestDefaultBinaryMessenger],
/// and [TestDefaultBinaryMessenger.handlePlatformMessage] respectively).
///
/// To register a handler for a given message channel, see [setMessageHandler].
///
/// To send a message _to_ a plugin on the platform thread, see [send].
// TODO(ianh): deprecate this method once cocoon and other customer_tests are migrated:
// @NotYetDeprecated(
// 'Instead of calling this method, use ServicesBinding.instance.channelBuffers.push. '
// 'In tests, consider using tester.binding.defaultBinaryMessenger.handlePlatformMessage '
// 'or TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.handlePlatformMessage. '
// 'This feature was deprecated after v2.1.0-10.0.pre.'
// )
Future<void> handlePlatformMessage(String channel, ByteData? data, ui.PlatformMessageResponseCallback? callback);
/// Send a binary message to the platform plugins on the given channel.
@ -43,37 +67,6 @@ abstract class BinaryMessenger {
/// The handler's return value, if non-null, is sent as a response, unencoded.
void setMessageHandler(String channel, MessageHandler? handler);
/// Returns true if the `handler` argument matches the `handler` previously
/// passed to [setMessageHandler].
///
/// This method is useful for tests or test harnesses that want to assert the
/// handler for the specified channel has not been altered by a previous test.
///
/// Passing null for the `handler` returns true if the handler for the
/// `channel` is not set.
bool checkMessageHandler(String channel, MessageHandler? handler);
/// Set a mock callback for intercepting messages from the [send] method on
/// this class, on the given channel, without decoding them.
///
/// The given callback will replace the currently registered mock callback for
/// that channel, if any. To remove the mock handler, pass null as the
/// `handler` argument.
///
/// The handler's return value, if non-null, is used as a response, unencoded.
///
/// This is intended for testing. Messages intercepted in this manner are not
/// sent to platform plugins.
void setMockMessageHandler(String channel, MessageHandler? handler);
/// Returns true if the `handler` argument matches the `handler` previously
/// passed to [setMockMessageHandler].
///
/// This method is useful for tests or test harnesses that want to assert the
/// mock handler for the specified channel has not been altered by a previous
/// test.
///
/// Passing null for the `handler` returns true if the handler for the
/// `channel` is not set.
bool checkMockMessageHandler(String channel, MessageHandler? handler);
// Looking for setMockMessageHandler or checkMockMessageHandler?
// See this shim package: packages/flutter_test/lib/src/deprecated.dart
}

View file

@ -30,7 +30,6 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
_instance = this;
_defaultBinaryMessenger = createBinaryMessenger();
_restorationManager = createRestorationManager();
window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
initLicenses();
SystemChannels.system.setMessageHandler((dynamic message) => handleSystemMessage(message as Object));
SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
@ -49,6 +48,28 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
BinaryMessenger get defaultBinaryMessenger => _defaultBinaryMessenger;
late BinaryMessenger _defaultBinaryMessenger;
/// The low level buffering and dispatch mechanism for messages sent by
/// plugins on the engine side to their corresponding plugin code on
/// the framework side.
///
/// This exposes the [dart:ui.channelBuffers] object. Bindings can override
/// this getter to intercept calls to the [ChannelBuffers] mechanism (for
/// example, for tests).
///
/// In production, direct access to this object should not be necessary.
/// Messages are received and dispatched by the [defaultBinaryMessenger]. This
/// object is primarily used to send mock messages in tests, via the
/// [ChannelBuffers.push] method (simulating a plugin sending a message to the
/// framework).
///
/// See also:
///
/// * [PlatformDispatcher.sendPlatformMessage], which is used for sending
/// messages to plugins from the framework (the opposite of
/// [channelBuffers]).
/// * [platformDispatcher], the [PlatformDispatcher] singleton.
ui.ChannelBuffers get channelBuffers => ui.channelBuffers;
/// Creates a default [BinaryMessenger] instance that can be used for sending
/// platform messages.
@protected
@ -56,7 +77,6 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
return const _DefaultBinaryMessenger._();
}
/// Called when the operating system notifies the application of a memory
/// pressure situation.
///
@ -253,17 +273,20 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
class _DefaultBinaryMessenger extends BinaryMessenger {
const _DefaultBinaryMessenger._();
// Handlers for incoming messages from platform plugins.
// This is static so that this class can have a const constructor.
static final Map<String, MessageHandler> _handlers =
<String, MessageHandler>{};
@override
Future<void> handlePlatformMessage(
String channel,
ByteData? message,
ui.PlatformMessageResponseCallback? callback,
) async {
ui.channelBuffers.push(channel, message, (ByteData? data) {
if (callback != null)
callback(data);
});
}
// Mock handlers that intercept and respond to outgoing messages.
// This is static so that this class can have a const constructor.
static final Map<String, MessageHandler> _mockHandlers =
<String, MessageHandler>{};
Future<ByteData?> _sendPlatformMessage(String channel, ByteData? message) {
@override
Future<ByteData?> send(String channel, ByteData? message) {
final Completer<ByteData?> completer = Completer<ByteData?>();
// ui.PlatformDispatcher.instance is accessed directly instead of using
// ServicesBinding.instance.platformDispatcher because this method might be
@ -272,6 +295,8 @@ class _DefaultBinaryMessenger extends BinaryMessenger {
// ui.PlatformDispatcher.instance because the PlatformDispatcher may be
// dependency injected elsewhere with a different instance. However, static
// access at this location seems to be the least bad option.
// TODO(ianh): Use ServicesBinding.instance once we have better diagnostics
// on that getter.
ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {
try {
completer.complete(reply);
@ -287,67 +312,27 @@ class _DefaultBinaryMessenger extends BinaryMessenger {
return completer.future;
}
@override
@pragma('vm:notify-debugger-on-exception')
Future<void> handlePlatformMessage(
String channel,
ByteData? data,
ui.PlatformMessageResponseCallback? callback,
) async {
ByteData? response;
try {
final MessageHandler? handler = _handlers[channel];
if (handler != null) {
response = await handler(data);
} else {
ui.channelBuffers.push(channel, data, callback!);
callback = null;
}
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: ErrorDescription('during a platform message callback'),
));
} finally {
if (callback != null) {
callback(response);
}
}
}
@override
Future<ByteData?>? send(String channel, ByteData? message) {
final MessageHandler? handler = _mockHandlers[channel];
if (handler != null)
return handler(message);
return _sendPlatformMessage(channel, message);
}
@override
void setMessageHandler(String channel, MessageHandler? handler) {
if (handler == null) {
_handlers.remove(channel);
ui.channelBuffers.clearListener(channel);
} else {
_handlers[channel] = handler;
ui.channelBuffers.drain(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
await handlePlatformMessage(channel, data, callback);
ui.channelBuffers.setListener(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
ByteData? response;
try {
response = await handler(data);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: ErrorDescription('during a platform message callback'),
));
} finally {
callback(response);
}
});
}
}
@override
bool checkMessageHandler(String channel, MessageHandler? handler) => _handlers[channel] == handler;
@override
void setMockMessageHandler(String channel, MessageHandler? handler) {
if (handler == null)
_mockHandlers.remove(channel);
else
_mockHandlers[channel] = handler;
}
@override
bool checkMockMessageHandler(String channel, MessageHandler? handler) => _mockHandlers[channel] == handler;
}

View file

@ -95,7 +95,6 @@ abstract class MethodCodec {
ByteData encodeErrorEnvelope({ required String code, String? message, Object? details});
}
/// Thrown to indicate that a platform interaction failed in the platform
/// plugin.
///

View file

@ -75,31 +75,10 @@ class BasicMessageChannel<T> {
}
}
/// Sets a mock callback for intercepting messages sent on this channel.
/// Messages may be null.
///
/// The given callback will replace the currently registered mock callback for
/// this channel, if any. To remove the mock handler, pass null as the
/// `handler` argument.
///
/// The handler's return value is used as a message reply. It may be null.
///
/// This is intended for testing. Messages intercepted in this manner are not
/// sent to platform plugins.
void setMockMessageHandler(Future<T> Function(T? message)? handler) {
if (handler == null) {
binaryMessenger.setMockMessageHandler(name, null);
} else {
binaryMessenger.setMockMessageHandler(name, (ByteData? message) async {
return codec.encodeMessage(await handler(codec.decodeMessage(message)));
});
}
}
// Looking for setMockMessageHandler?
// See this shim package: packages/flutter_test/lib/src/deprecated.dart
}
Expando<Object> _methodChannelHandlers = Expando<Object>();
Expando<Object> _methodChannelMockHandlers = Expando<Object>();
/// A named channel for communicating with platform plugins using asynchronous
/// method calls.
///
@ -393,7 +372,6 @@ class MethodChannel {
/// similarly to what happens if no method call handler has been set.
/// Any other exception results in an error envelope being sent.
void setMethodCallHandler(Future<dynamic> Function(MethodCall call)? handler) {
_methodChannelHandlers[this] = handler;
binaryMessenger.setMessageHandler(
name,
handler == null
@ -402,53 +380,7 @@ class MethodChannel {
);
}
/// Returns true if the `handler` argument matches the `handler` previously
/// passed to [setMethodCallHandler].
///
/// This method is useful for tests or test harnesses that want to assert the
/// handler for the specified channel has not been altered by a previous test.
///
/// Passing null for the `handler` returns true if the handler for the channel
/// is not set.
bool checkMethodCallHandler(Future<dynamic> Function(MethodCall call)? handler) => _methodChannelHandlers[this] == handler;
/// Sets a mock callback for intercepting method invocations on this channel.
///
/// The given callback will replace the currently registered mock callback for
/// this channel, if any. To remove the mock handler, pass null as the
/// `handler` argument.
///
/// Later calls to [invokeMethod] will result in a successful result,
/// a [PlatformException] or a [MissingPluginException], determined by how
/// the future returned by the mock callback completes. The [codec] of this
/// channel is used to encode and decode values and errors.
///
/// This is intended for testing. Method calls intercepted in this manner are
/// not sent to platform plugins.
///
/// The provided `handler` must return a `Future` that completes with the
/// return value of the call. The value will be encoded using
/// [MethodCodec.encodeSuccessEnvelope], to act as if platform plugin had
/// returned that value.
void setMockMethodCallHandler(Future<dynamic>? Function(MethodCall call)? handler) {
_methodChannelMockHandlers[this] = handler;
binaryMessenger.setMockMessageHandler(
name,
handler == null ? null : (ByteData? message) => _handleAsMethodCall(message, handler),
);
}
/// Returns true if the `handler` argument matches the `handler` previously
/// passed to [setMockMethodCallHandler].
///
/// This method is useful for tests or test harnesses that want to assert the
/// handler for the specified channel has not been altered by a previous test.
///
/// Passing null for the `handler` returns true if the handler for the channel
/// is not set.
bool checkMockMethodCallHandler(Future<dynamic> Function(MethodCall call)? handler) => _methodChannelMockHandlers[this] == handler;
Future<ByteData?> _handleAsMethodCall(ByteData? message, Future<dynamic>? Function(MethodCall call) handler) async {
Future<ByteData?> _handleAsMethodCall(ByteData? message, Future<dynamic> Function(MethodCall call) handler) async {
final MethodCall call = codec.decodeMethodCall(message);
try {
return codec.encodeSuccessEnvelope(await handler(call));
@ -464,6 +396,9 @@ class MethodChannel {
return codec.encodeErrorEnvelope(code: 'error', message: e.toString(), details: null);
}
}
// Looking for setMockMethodCallHandler or checkMethodCallHandler?
// See this shim package: packages/flutter_test/lib/src/deprecated.dart
}
/// A [MethodChannel] that ignores missing platform plugins.

View file

@ -166,7 +166,6 @@ class RestorationManager extends ChangeNotifier {
/// that communications channel, or to set it up differently, as necessary.
@protected
void initChannels() {
assert(!SystemChannels.restoration.checkMethodCallHandler(_methodHandler));
SystemChannels.restoration.setMethodCallHandler(_methodHandler);
}

View file

@ -129,6 +129,11 @@ class SystemChannels {
/// they apply, so that stale messages referencing past transactions can be
/// ignored.
///
/// In debug builds, messages sent with a client ID of -1 are always accepted.
/// This allows tests to smuggle messages without having to mock the engine's
/// text handling (for example, allowing the engine to still handle the text
/// input messages in an integration test).
///
/// The methods described below are wrapped in a more convenient form by the
/// [TextInput] and [TextInputConnection] class.
///
@ -161,9 +166,15 @@ class SystemChannels {
/// is a transaction identifier. Calls for stale transactions should be ignored.
///
/// * `TextInputClient.updateEditingState`: The user has changed the contents
/// of the text control. The second argument is a [String] containing a
/// JSON-encoded object with seven keys, in the form expected by
/// [TextEditingValue.fromJSON].
/// of the text control. The second argument is an object with seven keys,
/// in the form expected by [TextEditingValue.fromJSON].
///
/// * `TextInputClient.updateEditingStateWithTag`: One or more text controls
/// were autofilled by the platform's autofill service. The first argument
/// (the client ID) is ignored, the second argument is a map of tags to
/// objects in the form expected by [TextEditingValue.fromJSON]. See
/// [AutofillScope.getAutofillClient] for details on the interpretation of
/// the tag.
///
/// * `TextInputClient.performAction`: The user has triggered an action. The
/// second argument is a [String] consisting of the stringification of one
@ -174,7 +185,8 @@ class SystemChannels {
/// one. The framework should call `TextInput.setClient` and
/// `TextInput.setEditingState` again with its most recent information. If
/// there is no existing state on the framework side, the call should
/// fizzle.
/// fizzle. (This call is made without a client ID; indeed, without any
/// arguments at all.)
///
/// * `TextInputClient.onConnectionClosed`: The text input connection closed
/// on the platform side. For example the application is moved to

View file

@ -1327,9 +1327,11 @@ class TextInput {
final List<dynamic> args = methodCall.arguments as List<dynamic>;
// The updateEditingStateWithTag request (autofill) can come up even to a
// text field that doesn't have a connection.
if (method == 'TextInputClient.updateEditingStateWithTag') {
assert(_currentConnection!._client != null);
final TextInputClient client = _currentConnection!._client;
assert(client != null);
final AutofillScope? scope = client.currentAutofillScope;
final Map<String, dynamic> editingValue = args[1] as Map<String, dynamic>;
for (final String tag in editingValue.keys) {
@ -1343,9 +1345,22 @@ class TextInput {
}
final int client = args[0] as int;
// The incoming message was for a different client.
if (client != _currentConnection!._id)
return;
if (client != _currentConnection!._id) {
// If the client IDs don't match, the incoming message was for a different
// client.
bool debugAllowAnyway = false;
assert(() {
// In debug builds we allow "-1" as a magical client ID that ignores
// this verification step so that tests can always get through, even
// when they are not mocking the engine side of text input.
if (client == -1)
debugAllowAnyway = true;
return true;
}());
if (!debugAllowAnyway)
return;
}
switch (method) {
case 'TextInputClient.updateEditingState':
_currentConnection!._client.updateEditingValue(TextEditingValue.fromJSON(args[1] as Map<String, dynamic>));
@ -1502,7 +1517,7 @@ class TextInput {
assert(shouldSave != null);
TextInput._instance._channel.invokeMethod<void>(
'TextInput.finishAutofillContext',
shouldSave ,
shouldSave,
);
}
}

View file

@ -2112,7 +2112,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
if (_hasFocus) {
_openInputConnection();
} else {
widget.focusNode.requestFocus();
widget.focusNode.requestFocus(); // This eventually calls _openInputConnection also, see _handleFocusChanged.
}
}
@ -2360,11 +2360,13 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
void _cursorWaitForStart(Timer timer) {
assert(_kCursorBlinkHalfPeriod > _fadeDuration);
assert(!EditableText.debugDeterministicCursor);
_cursorTimer?.cancel();
_cursorTimer = Timer.periodic(_kCursorBlinkHalfPeriod, _cursorTick);
}
void _startCursorTimer() {
assert(_cursorTimer == null);
_targetCursorVisibility = true;
_cursorBlinkOpacityController.value = 1.0;
if (EditableText.debugDeterministicCursor)

View file

@ -201,7 +201,7 @@ void main() {
final List<int> selectedItems = <int>[];
final List<MethodCall> systemCalls = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
systemCalls.add(methodCall);
});
@ -254,7 +254,7 @@ void main() {
final List<int> selectedItems = <int>[];
final List<MethodCall> systemCalls = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
systemCalls.add(methodCall);
});

View file

@ -175,7 +175,7 @@ void main() {
testWidgets('drag past threshold triggers refresh task', (WidgetTester tester) async {
final List<MethodCall> platformCallLog = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
platformCallLog.add(methodCall);
});

View file

@ -132,9 +132,9 @@ void main() {
await tester.pump();
int hapticFeedbackCalls = 0;
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'HapticFeedback.vibrate') {
hapticFeedbackCalls++;
hapticFeedbackCalls += 1;
}
});
@ -692,9 +692,9 @@ void main() {
await tester.pump();
int hapticFeedbackCalls = 0;
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'HapticFeedback.vibrate') {
hapticFeedbackCalls++;
hapticFeedbackCalls += 1;
}
});

View file

@ -47,7 +47,7 @@ void main() {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -87,7 +87,7 @@ void main() {
bool value2 = false;
final List<MethodCall> log = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -154,7 +154,7 @@ void main() {
bool value = false;
final List<MethodCall> log = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -192,7 +192,7 @@ void main() {
bool value = false;
final List<MethodCall> log = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});

View file

@ -162,7 +162,7 @@ class PathPointsMatcher extends Matcher {
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockClipboard mockClipboard = MockClipboard();
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
// Returns the first RenderEditable.
RenderEditable findRenderEditable(WidgetTester tester) {
@ -3228,7 +3228,7 @@ void main() {
testWidgets('text field respects keyboardAppearance from theme', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -3251,7 +3251,7 @@ void main() {
testWidgets('text field can override keyboardAppearance from theme', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});

View file

@ -66,7 +66,7 @@ const _LongCupertinoLocalizations _longLocalizations = _LongCupertinoLocalizatio
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockClipboard mockClipboard = MockClipboard();
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
// Returns true iff the button is visually enabled.
bool appearsEnabled(WidgetTester tester, String text) {

View file

@ -21,7 +21,8 @@ class TestServiceExtensionsBinding extends BindingBase
PaintingBinding,
SemanticsBinding,
RendererBinding,
WidgetsBinding {
WidgetsBinding,
TestDefaultBinaryMessengerBinding {
final Map<String, ServiceExtensionCallback> extensions = <String, ServiceExtensionCallback>{};
@ -467,7 +468,7 @@ void main() {
bool completed;
completed = false;
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
expect(utf8.decode(message!.buffer.asUint8List()), 'test');
completed = true;
return ByteData(5); // 0x0000000000
@ -494,7 +495,7 @@ void main() {
});
expect(data, isFalse);
expect(completed, isTrue);
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', null);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', null);
});
test('Service extensions - exit', () async {

View file

@ -2,12 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Logically this file should be part of `gesture_binding_test.dart` but is here
// due to conflict of `flutter_test` and `package:test`.
// See https://github.com/dart-lang/matcher/issues/98
// TODO(CareF): Consider combine this file back to `gesture_binding_test.dart`
// after #98 is fixed.
import 'dart:ui' as ui;
import 'package:clock/clock.dart';

View file

@ -267,7 +267,7 @@ void main() {
testWidgets('has semantic events', (WidgetTester tester) async {
dynamic semanticEvent;
bool? checkboxValue = false;
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
semanticEvent = message;
});
final SemanticsTester semanticsTester = SemanticsTester(tester);
@ -300,7 +300,7 @@ void main() {
});
expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
SystemChannels.accessibility.setMockMessageHandler(null);
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
semanticsTester.dispose();
});

View file

@ -27,14 +27,14 @@ void main () {
setUp(() {
semanticEvents = <Map<String, Object>>[];
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
final Map<dynamic, dynamic> typedMessage = message as Map<dynamic, dynamic>;
semanticEvents.add(typedMessage.cast<String, Object>());
});
});
tearDown(() {
SystemChannels.accessibility.setMockMessageHandler(null);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
});
testWidgets('forTap', (WidgetTester tester) async {

View file

@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
/// Tracks how often feedback has been requested since its instantiation.
///
@ -10,13 +11,7 @@ import 'package:flutter/services.dart';
/// cannot be used in combination with other classes that do the same.
class FeedbackTester {
FeedbackTester() {
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
if (methodCall.method == 'HapticFeedback.vibrate')
_hapticCount++;
if (methodCall.method == 'SystemSound.play' &&
methodCall.arguments == SystemSoundType.click.toString())
_clickSoundCount++;
});
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, _handler);
}
/// Number of times haptic feedback was requested (vibration).
@ -27,8 +22,17 @@ class FeedbackTester {
int get clickSoundCount => _clickSoundCount;
int _clickSoundCount = 0;
Future<void> _handler(MethodCall methodCall) async {
if (methodCall.method == 'HapticFeedback.vibrate')
_hapticCount++;
if (methodCall.method == 'SystemSound.play' &&
methodCall.arguments == SystemSoundType.click.toString())
_clickSoundCount++;
}
/// Stops tracking.
void dispose() {
SystemChannels.platform.setMockMethodCallHandler(null);
assert(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(SystemChannels.platform.name, _handler));
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
}
}

View file

@ -241,9 +241,9 @@ void main() {
// Fill the clipboard so that the Paste option is available in the text
// selection menu.
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
addTearDown(() => SystemChannels.platform.setMockMethodCallHandler(null));
addTearDown(() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null));
await tester.pumpWidget(_inputDatePickerField(autofocus: true));
await tester.pumpAndSettle();

View file

@ -537,7 +537,7 @@ void main() {
final Key key = UniqueKey();
dynamic semanticEvent;
int? radioValue = 2;
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
semanticEvent = message;
});
@ -568,7 +568,7 @@ void main() {
expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
semantics.dispose();
SystemChannels.accessibility.setMockMessageHandler(null);
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
});
testWidgets('RadioListTile can autofocus unless disabled.', (WidgetTester tester) async {

View file

@ -292,7 +292,7 @@ void main() {
final Key key = UniqueKey();
dynamic semanticEvent;
int? radioValue = 2;
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
semanticEvent = message;
});
@ -319,7 +319,7 @@ void main() {
expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
semantics.dispose();
SystemChannels.accessibility.setMockMessageHandler(null);
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
});
testWidgets('Radio ink ripple is displayed correctly', (WidgetTester tester) async {

View file

@ -32,12 +32,12 @@ void main() {
setUp(() async {
// Fill the clipboard so that the Paste option is available in the text
// selection menu.
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
});
tearDown(() {
SystemChannels.platform.setMockMethodCallHandler(null);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
});
testWidgets('Can open and close search', (WidgetTester tester) async {

View file

@ -577,7 +577,7 @@ void main() {
testWidgets('switch has semantic events', (WidgetTester tester) async {
dynamic semanticEvent;
bool value = false;
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
semanticEvent = message;
});
final SemanticsTester semanticsTester = SemanticsTester(tester);
@ -615,13 +615,13 @@ void main() {
expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
semanticsTester.dispose();
SystemChannels.accessibility.setMockMessageHandler(null);
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
});
testWidgets('switch sends semantic events from parent if fully merged', (WidgetTester tester) async {
dynamic semanticEvent;
bool value = false;
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
semanticEvent = message;
});
final SemanticsTester semanticsTester = SemanticsTester(tester);
@ -665,7 +665,7 @@ void main() {
expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
semanticsTester.dispose();
SystemChannels.accessibility.setMockMessageHandler(null);
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
});
testWidgets('Switch.adaptive', (WidgetTester tester) async {

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:math' as math;
import 'dart:ui' as ui show window, BoxHeightStyle, BoxWidthStyle;
@ -164,14 +165,20 @@ void main() {
setUp(() async {
debugResetSemanticsIdCounter();
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(
SystemChannels.platform,
mockClipboard.handleMethodCall,
);
// Fill the clipboard so that the Paste option is available in the text
// selection menu.
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
});
tearDown(() {
SystemChannels.platform.setMockMethodCallHandler(null);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(
SystemChannels.platform,
null,
);
});
final Key textFieldKey = UniqueKey();
@ -339,7 +346,7 @@ void main() {
testWidgets('TextField has consistent size', (WidgetTester tester) async {
final Key textFieldKey = UniqueKey();
late String textFieldValue;
String? textFieldValue;
await tester.pumpWidget(
overlay(
@ -362,15 +369,16 @@ void main() {
Future<void> checkText(String testValue) async {
return TestAsyncUtils.guard(() async {
expect(textFieldValue, isNull);
await tester.enterText(find.byType(TextField), testValue);
// Check that the onChanged event handler fired.
expect(textFieldValue, equals(testValue));
textFieldValue = null;
await skipPastScrollingAnimation(tester);
});
}
await checkText(' ');
expect(findTextFieldBox(), equals(inputBox));
expect(inputBox.size, equals(emptyInputSize));
@ -416,6 +424,8 @@ void main() {
text: 'X',
selection: TextSelection.collapsed(offset: 1),
));
await tester.idle();
expect(tester.state(find.byType(EditableText)), editableText);
await checkCursorToggle();
});
@ -4694,8 +4704,8 @@ void main() {
);
String clipboardContent = '';
SystemChannels.platform
.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.setData')
clipboardContent = methodCall.arguments['text'] as String;
else if (methodCall.method == 'Clipboard.getData')
@ -4767,8 +4777,8 @@ void main() {
);
String clipboardContent = '';
SystemChannels.platform
.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.setData')
clipboardContent = methodCall.arguments['text'] as String;
else if (methodCall.method == 'Clipboard.getData')
@ -4840,8 +4850,8 @@ void main() {
);
const String clipboardContent = 'I love Flutter!';
SystemChannels.platform
.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.getData')
return <String, dynamic>{'text': clipboardContent};
return null;
@ -4890,8 +4900,8 @@ void main() {
maxLines: 3,
);
String clipboardContent = '';
SystemChannels.platform
.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.setData')
clipboardContent = methodCall.arguments['text'] as String;
else if (methodCall.method == 'Clipboard.getData')
@ -4964,8 +4974,8 @@ void main() {
obscureText: true,
);
String clipboardContent = '';
SystemChannels.platform
.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.setData')
clipboardContent = methodCall.arguments['text'] as String;
else if (methodCall.method == 'Clipboard.getData')
@ -9371,8 +9381,8 @@ void main() {
);
bool triedToReadClipboard = false;
SystemChannels.platform
.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger
.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.getData') {
triedToReadClipboard = true;
}

View file

@ -32,7 +32,7 @@ class MockClipboard {
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockClipboard mockClipboard = MockClipboard();
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
setUp(() async {
// Fill the clipboard so that the Paste option is available in the text

View file

@ -28,7 +28,7 @@ class MockClipboard {
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockClipboard mockClipboard = MockClipboard();
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
setUp(() async {
await Clipboard.setData(const ClipboardData(text: 'clipboard data'));

View file

@ -1193,7 +1193,7 @@ void main() {
testWidgets('has semantic events', (WidgetTester tester) async {
final List<dynamic> semanticEvents = <dynamic>[];
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
semanticEvents.add(message);
});
final SemanticsTester semantics = SemanticsTester(tester);
@ -1230,7 +1230,7 @@ void main() {
},
]));
semantics.dispose();
SystemChannels.accessibility.setMockMessageHandler(null);
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
});
testWidgets('default Tooltip debugFillProperties', (WidgetTester tester) async {
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();

View file

@ -1153,7 +1153,7 @@ void main() {
testWidgets('has semantic events by default - ThemeData.tooltipTheme', (WidgetTester tester) async {
final List<dynamic> semanticEvents = <dynamic>[];
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
semanticEvents.add(message);
});
final SemanticsTester semantics = SemanticsTester(tester);
@ -1191,12 +1191,12 @@ void main() {
},
]));
semantics.dispose();
SystemChannels.accessibility.setMockMessageHandler(null);
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
});
testWidgets('has semantic events by default - TooltipTheme', (WidgetTester tester) async {
final List<dynamic> semanticEvents = <dynamic>[];
SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
semanticEvents.add(message);
});
final SemanticsTester semantics = SemanticsTester(tester);
@ -1236,7 +1236,7 @@ void main() {
},
]));
semantics.dispose();
SystemChannels.accessibility.setMockMessageHandler(null);
tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
});
testWidgets('default Tooltip debugFillProperties', (WidgetTester tester) async {

View file

@ -12,11 +12,11 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
final TestRenderBinding binding = TestRenderBinding();
test('Flutter dispatches first frame event on the web only', () async {
final Completer<void> completer = Completer<void>();
final TestRenderBinding binding = TestRenderBinding();
const MethodChannel firstFrameChannel = MethodChannel('flutter/service_worker');
firstFrameChannel.setMockMethodCallHandler((MethodCall methodCall) async {
binding.defaultBinaryMessenger.setMockMethodCallHandler(firstFrameChannel, (MethodCall methodCall) async {
completer.complete();
});
@ -27,4 +27,10 @@ void main() {
}, skip: !kIsWeb);
}
class TestRenderBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding {}
class TestRenderBinding extends BindingBase
with SchedulerBinding,
ServicesBinding,
GestureBinding,
SemanticsBinding,
RendererBinding,
TestDefaultBinaryMessengerBinding { }

View file

@ -56,14 +56,14 @@ void main() {
setUp(() {
_binding.postFrameCallbacks.clear();
SystemChannels.mouseCursor.setMockMethodCallHandler((MethodCall call) async {
_binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, (MethodCall call) async {
if (_methodCallHandler != null)
return _methodCallHandler!(call);
});
});
tearDown(() {
SystemChannels.mouseCursor.setMockMethodCallHandler(null);
_binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, null);
});
test('Should work on platforms that does not support mouse cursor', () async {

View file

@ -9,6 +9,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart' show TestDefaultBinaryMessengerBinding;
class _TestHitTester extends RenderBox {
_TestHitTester(this.hitTestOverride);
@ -24,7 +25,7 @@ class _TestHitTester extends RenderBox {
// A binding used to test MouseTracker, allowing the test to override hit test
// searching.
class TestMouseTrackerFlutterBinding extends BindingBase
with SchedulerBinding, ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding {
with SchedulerBinding, ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding, TestDefaultBinaryMessengerBinding {
@override
void initInstances() {
super.initInstances();

View file

@ -9,12 +9,12 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart' show EnginePhase, fail;
import 'package:flutter_test/flutter_test.dart' show TestDefaultBinaryMessengerBinding, EnginePhase, fail;
export 'package:flutter/foundation.dart' show FlutterError, FlutterErrorDetails;
export 'package:flutter_test/flutter_test.dart' show EnginePhase;
export 'package:flutter_test/flutter_test.dart' show TestDefaultBinaryMessengerBinding, EnginePhase;
class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding {
class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, TestDefaultBinaryMessengerBinding {
/// Creates a binding for testing rendering library functionality.
///
/// If [onErrors] is not null, it is called if [FlutterError] caught any errors

View file

@ -13,12 +13,13 @@ void main() {
test('Semantic announcement', () async {
final List<Map<dynamic, dynamic>> log = <Map<dynamic, dynamic>>[];
Future<dynamic> handleMessage(dynamic mockMessage) async {
final Map<dynamic, dynamic> message = mockMessage as Map<dynamic, dynamic>;
log.add(message);
}
SystemChannels.accessibility.setMockMessageHandler(handleMessage);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, handleMessage);
await SemanticsService.announce('announcement 1', TextDirection.ltr);
await SemanticsService.announce('announcement 2', TextDirection.rtl);

View file

@ -191,15 +191,6 @@ class FakeTextChannel implements MethodChannel {
incoming = handler;
}
@override
bool checkMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
@override
void setMockMethodCallHandler(Future<void>? Function(MethodCall call)? handler) => throw UnimplementedError();
@override
bool checkMockMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
void validateOutgoingMethodCalls(List<MethodCall> calls) {
expect(outgoingCalls.length, calls.length);
bool hasError = false;

View file

@ -34,7 +34,7 @@ L2Paragraph2
L2Paragraph3''';
const String licenses = '''
const String combinedLicenses = '''
$license1
--------------------------------------------------------------------------------
$license2
@ -42,29 +42,25 @@ $license2
class TestBinding extends BindingBase with SchedulerBinding, ServicesBinding {
@override
BinaryMessenger createBinaryMessenger() {
return super.createBinaryMessenger()
..setMockMessageHandler('flutter/assets', (ByteData? message) async {
if (const StringCodec().decodeMessage(message) == 'NOTICES') {
return const StringCodec().encodeMessage(licenses);
}
return null;
})
..setMockMessageHandler('flutter/assets', (ByteData? message) async {
if (const StringCodec().decodeMessage(message) == 'NOTICES.Z' && !kIsWeb) {
return Uint8List.fromList(gzip.encode(utf8.encode(licenses))).buffer.asByteData();
}
if (const StringCodec().decodeMessage(message) == 'NOTICES' && kIsWeb) {
return const StringCodec().encodeMessage(licenses);
}
return null;
});
TestDefaultBinaryMessenger get defaultBinaryMessenger => super.defaultBinaryMessenger as TestDefaultBinaryMessenger;
@override
TestDefaultBinaryMessenger createBinaryMessenger() {
return TestDefaultBinaryMessenger(super.createBinaryMessenger());
}
}
void main() {
test('Adds rootBundle LICENSES to LicenseRegistry', () async {
TestBinding(); // The test binding registers a mock handler that returns licenses for the LICENSE key
TestBinding().defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
if (const StringCodec().decodeMessage(message) == 'NOTICES.Z' && !kIsWeb) {
return Uint8List.fromList(gzip.encode(utf8.encode(combinedLicenses))).buffer.asByteData();
}
if (const StringCodec().decodeMessage(message) == 'NOTICES' && kIsWeb) {
return const StringCodec().encodeMessage(combinedLicenses);
}
return null;
});
final List<LicenseEntry> licenses = await LicenseRegistry.licenses.toList();

View file

@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
@ -19,36 +20,39 @@ void main() {
}
test('default binary messenger calls callback once', () async {
int count = 0;
int countInbound = 0;
int countOutbound = 0;
const String channel = 'foo';
ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
final ByteData bar = _makeByteData('bar');
final Completer<void> done = Completer<void>();
ServicesBinding.instance!.channelBuffers.push(
channel,
_makeByteData('bar'),
bar,
(ByteData? message) async {
count += 1;
expect(message, isNull);
countOutbound += 1;
done.complete();
},
);
expect(count, equals(0));
await ui.channelBuffers.drain(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
callback(null);
});
expect(count, equals(1));
});
test('can check the handler', () {
Future<ByteData> handler(ByteData? call) => Future<ByteData>.value(null);
final BinaryMessenger messenger = ServicesBinding.instance!.defaultBinaryMessenger;
expect(messenger.checkMessageHandler('test_channel', null), true);
expect(messenger.checkMessageHandler('test_channel', handler), false);
messenger.setMessageHandler('test_channel', handler);
expect(messenger.checkMessageHandler('test_channel', handler), true);
messenger.setMessageHandler('test_channel', null);
expect(countInbound, equals(0));
expect(countOutbound, equals(0));
ServicesBinding.instance!.defaultBinaryMessenger.setMessageHandler(
channel,
(ByteData? message) async {
expect(message, bar);
countInbound += 1;
},
);
expect(countInbound, equals(0));
expect(countOutbound, equals(0));
await done.future;
expect(countInbound, equals(1));
expect(countOutbound, equals(1));
});
test('can check the mock handler', () {
Future<ByteData> handler(ByteData? call) => Future<ByteData>.value(null);
final BinaryMessenger messenger = ServicesBinding.instance!.defaultBinaryMessenger;
final TestDefaultBinaryMessenger messenger = TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger;
expect(messenger.checkMockMessageHandler('test_channel', null), true);
expect(messenger.checkMockMessageHandler('test_channel', handler), false);

View file

@ -11,7 +11,7 @@ void main() {
test('installDeferredComponent test', () async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.deferredComponent.setMockMethodCallHandler((MethodCall methodCall) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.deferredComponent, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -27,7 +27,7 @@ void main() {
test('uninstallDeferredComponent test', () async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.deferredComponent.setMockMethodCallHandler((MethodCall methodCall) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.deferredComponent, (MethodCall methodCall) async {
log.add(methodCall);
});

View file

@ -8,6 +8,7 @@ import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
/// Used in internal testing.
class FakePlatformViewController extends PlatformViewController {
@ -122,7 +123,7 @@ class FakeAndroidViewController implements AndroidViewController {
class FakeAndroidPlatformViewsController {
FakeAndroidPlatformViewsController() {
SystemChannels.platform_views.setMockMethodCallHandler(_onMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall);
}
Iterable<FakeAndroidPlatformView> get views => _views.values;
@ -301,7 +302,7 @@ class FakeAndroidPlatformViewsController {
class FakeIosPlatformViewsController {
FakeIosPlatformViewsController() {
SystemChannels.platform_views.setMockMethodCallHandler(_onMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall);
}
Iterable<FakeUiKitView> get views => _views.values;
@ -396,7 +397,7 @@ class FakeIosPlatformViewsController {
class FakeHtmlPlatformViewsController {
FakeHtmlPlatformViewsController() {
SystemChannels.platform_views.setMockMethodCallHandler(_onMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall);
}
Iterable<FakeHtmlPlatformView> get views => _views.values;

View file

@ -11,7 +11,7 @@ void main() {
test('Haptic feedback control test', () async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -25,7 +25,7 @@ void main() {
Future<void> callAndVerifyHapticFunction(Function hapticFunction, String platformMethodArgument) async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});

View file

@ -12,7 +12,7 @@ void main() {
const MessageCodec<String?> string = StringCodec();
const BasicMessageChannel<String?> channel = BasicMessageChannel<String?>('ch', string);
test('can send string message and get reply', () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
'ch',
(ByteData? message) async => string.encodeMessage(string.decodeMessage(message)! + ' world'),
);
@ -23,7 +23,7 @@ void main() {
test('can receive string message and send reply', () async {
channel.setMessageHandler((String? message) async => message! + ' world');
String? reply;
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
'ch',
const StringCodec().encodeMessage('hello'),
(ByteData? replyBinary) {
@ -40,7 +40,7 @@ void main() {
const MethodChannel channel = MethodChannel('ch7', jsonMethod);
const OptionalMethodChannel optionalMethodChannel = OptionalMethodChannel('ch8', jsonMethod);
test('can invoke method and get result', () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
'ch7',
(ByteData? message) async {
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@ -56,7 +56,7 @@ void main() {
});
test('can invoke list method and get result', () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
'ch7',
(ByteData? message) async {
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@ -72,7 +72,7 @@ void main() {
});
test('can invoke list method and get null result', () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
'ch7',
(ByteData? message) async {
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@ -87,7 +87,7 @@ void main() {
});
test('can invoke map method and get result', () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
'ch7',
(ByteData? message) async {
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@ -103,7 +103,7 @@ void main() {
});
test('can invoke map method and get null result', () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
'ch7',
(ByteData? message) async {
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@ -118,7 +118,7 @@ void main() {
});
test('can invoke method and get error', () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
'ch7',
(ByteData? message) async {
return jsonMessage.encodeMessage(<dynamic>[
@ -141,7 +141,7 @@ void main() {
});
test('can invoke unimplemented method', () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
'ch7',
(ByteData? message) async => null,
);
@ -157,7 +157,7 @@ void main() {
});
test('can invoke unimplemented method (optional)', () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
'ch8',
(ByteData? message) async => null,
);
@ -169,7 +169,7 @@ void main() {
channel.setMethodCallHandler(null);
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
ByteData? envelope;
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
envelope = result;
});
await null; // just in case there's something async happening
@ -179,7 +179,7 @@ void main() {
test('can handle method call with no registered plugin (setting after)', () async {
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
ByteData? envelope;
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
envelope = result;
});
channel.setMethodCallHandler(null);
@ -193,7 +193,7 @@ void main() {
});
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
ByteData? envelope;
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
envelope = result;
});
expect(envelope, isNull);
@ -203,7 +203,7 @@ void main() {
channel.setMethodCallHandler((MethodCall call) async => '${call.arguments}, world');
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
ByteData? envelope;
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
envelope = result;
});
expect(jsonMethod.decodeEnvelope(envelope!), equals('hello, world'));
@ -215,7 +215,7 @@ void main() {
});
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
ByteData? envelope;
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
envelope = result;
});
try {
@ -235,7 +235,7 @@ void main() {
});
final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
ByteData? envelope;
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
envelope = result;
});
try {
@ -249,24 +249,14 @@ void main() {
}
});
test('can check the handler', () {
test('can check the mock handler', () async {
Future<dynamic> handler(MethodCall call) => Future<dynamic>.value(null);
const MethodChannel channel = MethodChannel('test_handler');
expect(channel.checkMethodCallHandler(null), true);
expect(channel.checkMethodCallHandler(handler), false);
channel.setMethodCallHandler(handler);
expect(channel.checkMethodCallHandler(handler), true);
});
test('can check the mock handler', () {
Future<dynamic> handler(MethodCall call) => Future<dynamic>.value(null);
const MethodChannel channel = MethodChannel('test_handler');
expect(channel.checkMockMethodCallHandler(null), true);
expect(channel.checkMockMethodCallHandler(handler), false);
channel.setMockMethodCallHandler(handler);
expect(channel.checkMockMethodCallHandler(handler), true);
expect(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel.name, null), true);
expect(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel.name, handler), false);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(channel, handler);
expect(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel.name, handler), true);
});
});
@ -275,7 +265,7 @@ void main() {
const MethodCodec jsonMethod = JSONMethodCodec();
const EventChannel channel = EventChannel('ch', jsonMethod);
void emitEvent(ByteData? event) {
ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
'ch',
event,
(ByteData? reply) {},
@ -283,7 +273,7 @@ void main() {
}
test('can receive event stream', () async {
bool canceled = false;
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
'ch',
(ByteData? message) async {
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@ -308,7 +298,7 @@ void main() {
});
test('can receive error event', () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
'ch',
(ByteData? message) async {
final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;

View file

@ -7,24 +7,23 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('Mock binary message handler control test', () async {
// Initialize all bindings because defaultBinaryMessenger.send() needs a window.
TestWidgetsFlutterBinding.ensureInitialized();
TestWidgetsFlutterBinding.ensureInitialized();
test('Mock binary message handler control test', () async {
final List<ByteData?> log = <ByteData>[];
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', (ByteData? message) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', (ByteData? message) async {
log.add(message);
return null;
});
final ByteData message = ByteData(2)..setUint16(0, 0xABCD);
await ServicesBinding.instance!.defaultBinaryMessenger.send('test1', message);
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.send('test1', message);
expect(log, equals(<ByteData>[message]));
log.clear();
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', null);
await ServicesBinding.instance!.defaultBinaryMessenger.send('test1', message);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', null);
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.send('test1', message);
expect(log, isEmpty);
});
}

View file

@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
@ -30,6 +29,7 @@ void main() {
RawKeyboard.instance.removeListener(handleKey);
}
});
testWidgets('No character is produced for non-printables', (WidgetTester tester) async {
for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows', 'web']) {
void handleKey(RawKeyEvent event) {
@ -40,6 +40,7 @@ void main() {
RawKeyboard.instance.removeListener(handleKey);
}
});
testWidgets('keysPressed is maintained', (WidgetTester tester) async {
for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows', 'ios']) {
RawKeyboard.instance.clearKeysPressed();
@ -209,7 +210,7 @@ void main() {
// when this event is received, but it's not in keysPressed yet.
data['modifiers'] |= RawKeyEventDataMacOs.modifierLeftShift | RawKeyEventDataMacOs.modifierShift;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -234,7 +235,7 @@ void main() {
// when this event is received, but it's not in keysPressed yet.
data['modifiers'] |= RawKeyEventDataMacOs.modifierLeftShift | RawKeyEventDataMacOs.modifierShift;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -259,7 +260,7 @@ void main() {
// when this event is received, but it's not in keysPressed yet.
data['modifiers'] |= RawKeyEventDataWindows.modifierLeftShift | RawKeyEventDataWindows.modifierShift;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -284,7 +285,7 @@ void main() {
// when this event is received, but it's not in keysPressed yet.
data['metaState'] |= RawKeyEventDataAndroid.modifierLeftShift | RawKeyEventDataAndroid.modifierShift;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -309,7 +310,7 @@ void main() {
// when this event is received, but it's not in keysPressed yet.
data['modifiers'] |= RawKeyEventDataFuchsia.modifierLeftShift;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -334,7 +335,7 @@ void main() {
// when this event is received, but it's not in keysPressed yet.
data['modifiers'] |= GLFWKeyHelper.modifierShift;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -364,7 +365,7 @@ void main() {
isDown: true,
)..['metaState'] |= RawKeyEventDataWeb.modifierShift;
// Dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -456,7 +457,7 @@ void main() {
RawKeyEventDataAndroid.modifierControl |
RawKeyEventDataAndroid.modifierMeta;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -494,7 +495,7 @@ void main() {
RawKeyEventDataMacOs.modifierCommand |
RawKeyEventDataMacOs.modifierControl;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -570,7 +571,7 @@ void main() {
RawKeyEventDataWindows.modifierAlt |
RawKeyEventDataWindows.modifierControl;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -607,7 +608,7 @@ void main() {
GLFWKeyHelper.modifierControl |
GLFWKeyHelper.modifierMeta;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -645,7 +646,7 @@ void main() {
RawKeyEventDataWeb.modifierControl |
RawKeyEventDataWeb.modifierMeta;
// dispatch the modified data.
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {},
@ -665,12 +666,6 @@ void main() {
});
testWidgets('RawKeyboard asserts if no keys are in keysPressed after receiving a key down event', (WidgetTester tester) async {
FlutterErrorDetails? errorDetails;
final FlutterExceptionHandler? oldHandler = FlutterError.onError;
FlutterError.onError = (FlutterErrorDetails details) {
errorDetails = details;
};
final Map<String, dynamic> keyEventMessage;
if (kIsWeb) {
keyEventMessage = const <String, dynamic>{
@ -692,19 +687,15 @@ void main() {
}
try {
await ServicesBinding.instance!.defaultBinaryMessenger
.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(keyEventMessage),
(ByteData? data) {},
(ByteData? data) { },
);
} finally {
FlutterError.onError = oldHandler;
fail('Expected an exception, but did not get one.');
} on AssertionError catch (error) {
expect(error.toString(), contains('Attempted to send a key down event when no keys are in keysPressed'));
}
expect(errorDetails, isNotNull);
expect(errorDetails!.stack, isNotNull);
final String fullErrorMessage = errorDetails.toString().replaceAll('\n', ' ');
expect(fullErrorMessage, contains('Attempted to send a key down event when no keys are in keysPressed'));
});
});
@ -757,6 +748,7 @@ void main() {
}
}
});
test('modifier keys are recognized when combined', () {
for (final int modifier in modifierTests.keys) {
if (modifier == RawKeyEventDataAndroid.modifierFunction) {
@ -799,6 +791,7 @@ void main() {
}
}
});
test('Printable keyboard keys are correctly translated', () {
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(<String, dynamic>{
'type': 'keydown',
@ -817,6 +810,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
expect(data.keyLabel, equals('a'));
});
test('Control keyboard keys are correctly translated', () {
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -833,6 +827,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
expect(data.keyLabel, isEmpty);
});
test('Modifier keyboard keys are correctly translated', () {
final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -850,6 +845,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
expect(data.keyLabel, isEmpty);
});
test('DPAD keys from a joystick give physical key mappings', () {
final RawKeyEvent joystickDpadDown = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -867,6 +863,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.arrowDown));
expect(data.keyLabel, isEmpty);
});
test('Arrow keys from a keyboard give correct physical key mappings', () {
final RawKeyEvent joystickDpadDown = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -883,6 +880,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.arrowDown));
expect(data.keyLabel, isEmpty);
});
test('DPAD center from a game pad gives physical key mappings', () {
final RawKeyEvent joystickDpadCenter = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -900,6 +898,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.select));
expect(data.keyLabel, isEmpty);
});
test('Device id is read from message', () {
final RawKeyEvent joystickDpadCenter = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -915,6 +914,7 @@ void main() {
final RawKeyEventDataAndroid data = joystickDpadCenter.data as RawKeyEventDataAndroid;
expect(data.deviceId, equals(10));
});
test('Repeat count is passed correctly', () {
final RawKeyEvent repeatCountEvent = RawKeyEvent.fromMessage(<String, dynamic>{
'type': 'keydown',
@ -931,6 +931,7 @@ void main() {
final RawKeyEventDataAndroid data = repeatCountEvent.data as RawKeyEventDataAndroid;
expect(data.repeatCount, equals(42));
});
testWidgets('Key events are responded to correctly.', (WidgetTester tester) async {
expect(RawKeyboard.instance.keysPressed, isEmpty);
// Generate the data for a regular key down event.
@ -940,7 +941,7 @@ void main() {
isDown: true,
);
Map<String, dynamic>? message;
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {
@ -963,7 +964,7 @@ void main() {
focusNode.requestFocus();
await tester.pump();
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {
@ -971,7 +972,7 @@ void main() {
},
);
expect(message, equals(<String, dynamic>{ 'handled': true }));
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(SystemChannels.keyEvent.name, null);
tester.binding.defaultBinaryMessenger.setMockMessageHandler(SystemChannels.keyEvent.name, null);
});
}, skip: isBrowser); // This is an Android-specific group.
@ -1019,6 +1020,7 @@ void main() {
}
}
});
test('modifier keys are recognized when combined', () {
for (final int modifier in modifierTests.keys) {
if (modifier == RawKeyEventDataFuchsia.modifierCapsLock) {
@ -1052,6 +1054,7 @@ void main() {
}
}
});
test('Printable keyboard keys are correctly translated', () {
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(<String, dynamic>{
'type': 'keydown',
@ -1065,6 +1068,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
expect(data.keyLabel, equals('a'));
});
test('Control keyboard keys are correctly translated', () {
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1136,6 +1140,7 @@ void main() {
}
}
});
test('modifier keys are recognized when combined', () {
for (final int modifier in modifierTests.keys) {
if (modifier == RawKeyEventDataMacOs.modifierCapsLock) {
@ -1175,6 +1180,7 @@ void main() {
}
}
});
test('Printable keyboard keys are correctly translated', () {
const String unmodifiedCharacter = 'a';
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
@ -1190,6 +1196,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
expect(data.keyLabel, equals('a'));
});
test('Control keyboard keys are correctly translated', () {
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1281,6 +1288,7 @@ void main() {
}
}
});
test('modifier keys are recognized when combined', () {
for (final int modifier in modifierTests.keys) {
if (modifier == RawKeyEventDataIos.modifierCapsLock) {
@ -1320,6 +1328,7 @@ void main() {
}
}
});
test('Printable keyboard keys are correctly translated', () {
const String unmodifiedCharacter = 'a';
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
@ -1335,6 +1344,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
expect(data.keyLabel, equals('a'));
});
test('Control keyboard keys are correctly translated', () {
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1427,6 +1437,7 @@ void main() {
}
}
});
test('modifier keys are recognized when combined', () {
for (final int modifier in modifierTests.keys) {
if (modifier == RawKeyEventDataWindows.modifierCaps) {
@ -1466,6 +1477,7 @@ void main() {
}
}
});
test('Printable keyboard keys are correctly translated', () {
const int unmodifiedCharacter = 97; // ASCII value for 'a'.
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
@ -1481,6 +1493,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
expect(data.keyLabel, equals('a'));
});
test('Control keyboard keys are correctly translated', () {
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1495,6 +1508,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
expect(data.keyLabel, isEmpty);
});
test('Modifier keyboard keys are correctly translated', () {
final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1509,6 +1523,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
expect(data.keyLabel, isEmpty);
});
test('Unprintable keyboard keys are correctly translated', () {
final RawKeyEvent leftArrowKey = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1522,6 +1537,7 @@ void main() {
expect(data.physicalKey, equals(PhysicalKeyboardKey.arrowLeft));
expect(data.logicalKey, equals(LogicalKeyboardKey.arrowLeft));
});
testWidgets('Win32 VK_PROCESSKEY events are skipped', (WidgetTester tester) async {
const String platform = 'windows';
bool lastHandled = true;
@ -1620,6 +1636,7 @@ void main() {
}
}
});
test('modifier keys are recognized when combined', () {
for (final int modifier in modifierTests.keys) {
if (modifier == GLFWKeyHelper.modifierControl) {
@ -1660,6 +1677,7 @@ void main() {
}
}
});
test('Printable keyboard keys are correctly translated', () {
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1675,6 +1693,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.keyQ));
expect(data.keyLabel, equals('q'));
});
test('Code points with two Unicode scalar values are allowed', () {
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1723,6 +1742,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
expect(data.keyLabel, isEmpty);
});
test('Modifier keyboard keys are correctly translated', () {
final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1804,6 +1824,7 @@ void main() {
}
}
});
test('modifier keys are recognized when combined', () {
for (final int modifier in modifierTests.keys) {
if (modifier == GtkKeyHelper.modifierControl) {
@ -1844,6 +1865,7 @@ void main() {
}
}
});
test('Printable keyboard keys are correctly translated', () {
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1859,6 +1881,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.keyQ));
expect(data.keyLabel, equals('q'));
});
test('Code points with two Unicode scalar values are allowed', () {
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1907,6 +1930,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
expect(data.keyLabel, isEmpty);
});
test('Modifier keyboard keys are correctly translated', () {
final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -1960,6 +1984,7 @@ void main() {
}
}
});
test('modifier keys are recognized when combined', () {
for (final int modifier in modifierTests.keys) {
if (modifier == RawKeyEventDataWeb.modifierMeta) {
@ -1992,6 +2017,7 @@ void main() {
}
}
});
test('Printable keyboard keys are correctly translated', () {
final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -2005,6 +2031,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
expect(data.keyLabel, equals('a'));
});
test('Control keyboard keys are correctly translated', () {
final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -2017,6 +2044,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
expect(data.keyLabel, isEmpty);
});
test('Modifier keyboard keys are correctly translated', () {
final RawKeyEvent shiftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',
@ -2029,6 +2057,7 @@ void main() {
expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
expect(data.keyLabel, isEmpty);
});
test('Arrow keys from a keyboard give correct physical key mappings', () {
final RawKeyEvent arrowKeyDown = RawKeyEvent.fromMessage(const <String, dynamic>{
'type': 'keydown',

View file

@ -18,7 +18,7 @@ void main() {
testWidgets('root bucket retrieval', (WidgetTester tester) async {
final List<MethodCall> callsToEngine = <MethodCall>[];
final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
callsToEngine.add(call);
return result.future;
});
@ -64,7 +64,7 @@ void main() {
testWidgets('root bucket received from engine before retrieval', (WidgetTester tester) async {
SystemChannels.restoration.setMethodCallHandler(null);
final List<MethodCall> callsToEngine = <MethodCall>[];
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) async {
callsToEngine.add(call);
});
final RestorationManager manager = RestorationManager();
@ -83,7 +83,7 @@ void main() {
SystemChannels.restoration.setMethodCallHandler(null);
final List<MethodCall> callsToEngine = <MethodCall>[];
final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
callsToEngine.add(call);
return result.future;
});
@ -110,7 +110,7 @@ void main() {
});
testWidgets('root bucket is properly replaced when new data is available', (WidgetTester tester) async {
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) async {
return _createEncodedRestorationData1();
});
final RestorationManager manager = RestorationManager();
@ -152,7 +152,7 @@ void main() {
testWidgets('returns null as root bucket when restoration is disabled', (WidgetTester tester) async {
final List<MethodCall> callsToEngine = <MethodCall>[];
final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
callsToEngine.add(call);
return result.future;
});
@ -195,7 +195,7 @@ void main() {
testWidgets('flushData', (WidgetTester tester) async {
final List<MethodCall> callsToEngine = <MethodCall>[];
final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
callsToEngine.add(call);
return result.future;
});
@ -230,7 +230,7 @@ void main() {
testWidgets('isReplacing', (WidgetTester tester) async {
final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
return result.future;
});

View file

@ -7,6 +7,8 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
testWidgets('SystemChrome overlay style test', (WidgetTester tester) async {
// The first call is a cache miss and will queue a microtask
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
@ -24,7 +26,7 @@ void main() {
test('setPreferredOrientations control test', () async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -42,7 +44,7 @@ void main() {
test('setApplicationSwitcherDescription control test', () async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -60,7 +62,7 @@ void main() {
test('setApplicationSwitcherDescription missing plugin', () async {
final List<ByteData?> log = <ByteData>[];
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/platform', (ByteData? message) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/platform', (ByteData? message) async {
log.add(message);
});
@ -74,7 +76,7 @@ void main() {
test('setEnabledSystemUIOverlays control test', () async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});

View file

@ -18,7 +18,7 @@ void main() {
}
test('System navigator control test - platform messages', () async {
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -26,11 +26,11 @@ void main() {
isMethodCall('SystemNavigator.pop', arguments: null),
]);
SystemChannels.platform.setMockMethodCallHandler(null);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
});
test('System navigator control test - navigation messages', () async {
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -54,6 +54,6 @@ void main() {
isMethodCall('routeUpdated', arguments: <String, dynamic>{ 'routeName': 'a', 'previousRouteName': 'b' }),
]);
SystemChannels.navigation.setMockMethodCallHandler(null);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, null);
});
}

View file

@ -12,7 +12,7 @@ void main() {
test('System sound control test', () async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});

View file

@ -466,16 +466,6 @@ class FakeTextChannel implements MethodChannel {
@override
void setMethodCallHandler(Future<void> Function(MethodCall call)? handler) => incoming = handler;
@override
bool checkMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
@override
void setMockMethodCallHandler(Future<void>? Function(MethodCall call)? handler) => throw UnimplementedError();
@override
bool checkMockMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
void validateOutgoingMethodCalls(List<MethodCall> calls) {
expect(outgoingCalls.length, calls.length);
bool hasError = false;

View file

@ -3107,7 +3107,7 @@ Future<void> _testLongPressDraggableHapticFeedback({ required WidgetTester teste
bool onDragStartedCalled = false;
int hapticFeedbackCalls = 0;
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'HapticFeedback.vibrate') {
hapticFeedbackCalls++;
}

View file

@ -79,7 +79,7 @@ void main() {
// Populate a fake clipboard.
const String clipboardContent = ' ';
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.getData')
return const <String, dynamic>{'text': clipboardContent};
return null;
@ -131,7 +131,7 @@ void main() {
// Populate a fake clipboard.
const String clipboardContent = ' ';
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.getData')
return const <String, dynamic>{'text': clipboardContent};
return null;
@ -853,7 +853,7 @@ void main() {
// Populate a fake clipboard.
const String clipboardContent = 'Hello world!';
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.getData')
return const <String, dynamic>{'text': clipboardContent};
return null;
@ -911,7 +911,7 @@ void main() {
// Populate a fake clipboard.
const String clipboardContent = 'Hello world!';
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.getData')
return const <String, dynamic>{'text': clipboardContent};
return null;

View file

@ -65,9 +65,9 @@ class MockClipboard {
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockClipboard mockClipboard = MockClipboard();
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
(TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding)
.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
setUp(() async {
debugResetSemanticsIdCounter();
@ -1982,7 +1982,7 @@ void main() {
await tester.pump(); // An extra pump to allow focus request to go through.
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -3234,7 +3234,7 @@ void main() {
// Regression test for https://github.com/flutter/flutter/issues/22212.
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -3265,7 +3265,7 @@ void main() {
testWidgets('location of widget is sent on show keyboard', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -3302,7 +3302,7 @@ void main() {
testWidgets('transform and size is reset when text connection opens', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -3390,7 +3390,7 @@ void main() {
testWidgets('size and transform are sent when they change', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -3432,7 +3432,7 @@ void main() {
testWidgets('text styling info is sent on show keyboard', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -3519,7 +3519,7 @@ void main() {
await tester.showKeyboard(find.byType(EditableText));
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
setState(() {
@ -3748,7 +3748,7 @@ void main() {
// Regression test for https://github.com/flutter/flutter/issues/22212.
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -5720,7 +5720,7 @@ void main() {
testWidgets('Synchronous test of local and remote editing values', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/65059
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) {
@ -5848,7 +5848,7 @@ void main() {
testWidgets('Send text input state to engine when the input formatter rejects user input', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/67828
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) {
@ -5927,7 +5927,7 @@ void main() {
testWidgets('Repeatedly receiving [TextEditingValue] will not trigger a keyboard request', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/66036
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
final TextEditingController controller = TextEditingController();
@ -6048,7 +6048,7 @@ void main() {
testWidgets('TextEditingController.clear() behavior test', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/66316
final List<MethodCall> log = <MethodCall>[];
SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
log.add(methodCall);
});
final TextEditingController controller = TextEditingController();

View file

@ -159,7 +159,7 @@ void main() {
testWidgets('ModalBarrier plays system alert sound when user tries to dismiss it', (WidgetTester tester) async {
final List<String> playedSystemSounds = <String>[];
try {
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'SystemSound.play')
playedSystemSounds.add(methodCall.arguments as String);
});
@ -176,7 +176,7 @@ void main() {
await tester.tap(find.text('target'), warnIfMissed: false);
await tester.pumpWidget(subject);
} finally {
SystemChannels.platform.setMockMethodCallHandler(null);
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
}
expect(playedSystemSounds, hasLength(1));
expect(playedSystemSounds[0], SystemSoundType.alert.toString());

View file

@ -1591,7 +1591,7 @@ void main() {
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer(location: const Offset(100, 100));
addTearDown(gesture.removePointer);
SystemChannels.mouseCursor.setMockMethodCallHandler((_) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, (_) async {
logCursors.add('cursor');
});

View file

@ -1075,7 +1075,7 @@ void main() {
await tester.pump();
late int lastPlatformViewTextClient;
SystemChannels.textInput.setMockMethodCallHandler((MethodCall call) {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall call) {
if (call.method == 'TextInput.setPlatformViewClient') {
lastPlatformViewTextClient = call.arguments as int;
}

View file

@ -55,7 +55,7 @@ void main() {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -110,7 +110,7 @@ void main() {
testWidgets('Navigator does not report route name by default', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -160,7 +160,7 @@ void main() {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -215,7 +215,7 @@ void main() {
testWidgets('Nameless routes should send platform messages', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
log.add(methodCall);
});
@ -257,7 +257,7 @@ void main() {
testWidgets('PlatformRouteInformationProvider reports URL', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
log.add(methodCall);
});

View file

@ -124,7 +124,7 @@ double getOpacity(WidgetTester tester, Finder finder) {
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final MockClipboard mockClipboard = MockClipboard();
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
const String kThreeLines =
'First line of text is\n'
@ -1665,7 +1665,7 @@ void main() {
final FocusNode focusNode = FocusNode();
String clipboardContent = '';
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
if (methodCall.method == 'Clipboard.setData')
clipboardContent = methodCall.arguments['text'] as String;
else if (methodCall.method == 'Clipboard.getData')

View file

@ -19,15 +19,15 @@ class MockClipboard {
'text': null,
};
Future<dynamic> handleMethodCall(MethodCall methodCall) async {
Future<Object?> handleMethodCall(MethodCall methodCall) async {
switch (methodCall.method) {
case 'Clipboard.getData':
if (getDataThrows) {
if (getDataThrows)
throw Exception();
}
return _clipboardData;
case 'Clipboard.setData':
_clipboardData = methodCall.arguments;
break;
}
}
}
@ -758,11 +758,11 @@ void main() {
group('when Clipboard fails', () {
setUp(() {
final MockClipboard mockClipboard = MockClipboard(getDataThrows: true);
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
});
tearDown(() {
SystemChannels.platform.setMockMethodCallHandler(null);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
});
test('Clipboard API failure is gracefully recovered from', () async {
@ -778,11 +778,11 @@ void main() {
final MockClipboard mockClipboard = MockClipboard();
setUp(() {
SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
});
tearDown(() {
SystemChannels.platform.setMockMethodCallHandler(null);
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
});
test('update sets value based on clipboard contents', () async {

View file

@ -36,7 +36,7 @@ void main() {
testWidgets('should not pass "null" to setApplicationSwitcherDescription', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
log.add(methodCall);
});

View file

@ -30,7 +30,7 @@ const String _extensionMethodName = 'driver';
/// eventually completes to a string response.
typedef DataHandler = Future<String> Function(String? message);
class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding, TestDefaultBinaryMessengerBinding {
_DriverBinding(this._handler, this._silenceErrors, this._enableTextEntryEmulation, this.finders, this.commands);
final DataHandler? _handler;
@ -51,11 +51,6 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
registerWebServiceExtension(extension.call);
}
}
@override
BinaryMessenger createBinaryMessenger() {
return TestDefaultBinaryMessenger(super.createBinaryMessenger());
}
}
/// Enables Flutter Driver VM service extension.
@ -330,11 +325,11 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory,
registerTextInput();
}
for(final FinderExtension finder in finders) {
for (final FinderExtension finder in finders) {
_finderExtensions[finder.finderType] = finder;
}
for(final CommandExtension command in commands) {
for (final CommandExtension command in commands) {
_commandExtensions[command.commandKind] = command;
}
}
@ -418,7 +413,7 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory,
@override
Command deserializeCommand(Map<String, String> params, DeserializeFinderFactory finderFactory) {
final String? kind = params['command'];
if(_commandExtensions.containsKey(kind)) {
if (_commandExtensions.containsKey(kind)) {
return _commandExtensions[kind]!.deserialize(params, finderFactory, this);
}
@ -434,7 +429,7 @@ class FlutterDriverExtension with DeserializeFinderFactory, CreateFinderFactory,
@override
Future<Result> handleCommand(Command command, WidgetController prober, CreateFinderFactory finderFactory) {
final String kind = command.kind;
if(_commandExtensions.containsKey(kind)) {
if (_commandExtensions.containsKey(kind)) {
return _commandExtensions[kind]!.call(command, prober, finderFactory, this);
}

View file

@ -279,7 +279,7 @@ void main() {
'waiting for NoPendingPlatformMessages returns until a single method channel call returns', (WidgetTester tester) async {
const MethodChannel channel = MethodChannel('helloChannel', JSONMethodCodec());
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
'helloChannel', (ByteData? message) {
return Future<ByteData>.delayed(
const Duration(milliseconds: 10),
@ -313,7 +313,7 @@ void main() {
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
// Configures channel 1
const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
'helloChannel1', (ByteData? message) {
return Future<ByteData>.delayed(
const Duration(milliseconds: 10),
@ -322,7 +322,7 @@ void main() {
// Configures channel 2
const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
'helloChannel2', (ByteData? message) {
return Future<ByteData>.delayed(
const Duration(milliseconds: 20),
@ -362,7 +362,7 @@ void main() {
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
// Configures channel 1
const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
'helloChannel1', (ByteData? message) {
return Future<ByteData>.delayed(
const Duration(milliseconds: 10),
@ -371,7 +371,7 @@ void main() {
// Configures channel 2
const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
'helloChannel2', (ByteData? message) {
return Future<ByteData>.delayed(
const Duration(milliseconds: 20),
@ -413,7 +413,7 @@ void main() {
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
// Configures channel 1
const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
'helloChannel1', (ByteData? message) {
return Future<ByteData>.delayed(
const Duration(milliseconds: 20),
@ -422,7 +422,7 @@ void main() {
// Configures channel 2
const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
tester.binding.defaultBinaryMessenger.setMockMessageHandler(
'helloChannel2', (ByteData? message) {
return Future<ByteData>.delayed(
const Duration(milliseconds: 10),

View file

@ -61,6 +61,7 @@ export 'src/all_elements.dart';
export 'src/animation_sheet.dart';
export 'src/binding.dart';
export 'src/controller.dart';
export 'src/deprecated.dart';
export 'src/event_simulation.dart';
export 'src/finders.dart';
export 'src/frame_timing_summarizer.dart';
@ -73,6 +74,7 @@ export 'src/restoration.dart';
export 'src/stack_manipulation.dart';
export 'src/test_async_utils.dart';
export 'src/test_compat.dart';
export 'src/test_default_binary_messenger.dart';
export 'src/test_exception_reporter.dart';
export 'src/test_pointer.dart';
export 'src/test_text_input.dart';

View file

@ -13,8 +13,8 @@ import 'package:path/path.dart' as path;
// ignore: deprecated_member_use
import 'package:test_api/test_api.dart' as test_package;
import 'binding.dart';
import 'deprecated.dart';
/// Ensure the [WidgetsBinding] is initialized.
WidgetsBinding ensureInitialized([@visibleForTesting Map<String, String>? environment]) {

View file

@ -15,8 +15,7 @@ import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart' show TestWindow;
import 'package:stack_trace/stack_trace.dart' as stack_trace;
// ignore: deprecated_member_use
import 'package:test_api/test_api.dart' as test_package;
import 'package:test_api/test_api.dart' as test_package; // ignore: deprecated_member_use
import 'package:vector_math/vector_math_64.dart';
import '_binding_io.dart' if (dart.library.html) '_binding_web.dart' as binding;
@ -25,6 +24,7 @@ import 'platform.dart';
import 'restoration.dart';
import 'stack_manipulation.dart';
import 'test_async_utils.dart';
import 'test_default_binary_messenger.dart';
import 'test_exception_reporter.dart';
import 'test_text_input.dart';
@ -79,74 +79,29 @@ enum TestBindingEventSource {
const Size _kDefaultTestViewportSize = Size(800.0, 600.0);
/// A [BinaryMessenger] subclass that is used as the default binary messenger
/// under testing environment.
/// Overrides the [ServicesBinding]'s binary messenger logic to use
/// [TestDefaultBinaryMessenger].
///
/// It tracks status of data sent across the Flutter platform barrier, which is
/// useful for testing frameworks to monitor and synchronize against the
/// platform messages.
class TestDefaultBinaryMessenger extends BinaryMessenger {
/// Creates a [TestDefaultBinaryMessenger] instance.
///
/// The [delegate] instance must not be null.
TestDefaultBinaryMessenger(this.delegate): assert(delegate != null);
/// The delegate [BinaryMessenger].
final BinaryMessenger delegate;
final List<Future<ByteData?>> _pendingMessages = <Future<ByteData?>>[];
/// The number of incomplete/pending calls sent to the platform channels.
int get pendingMessageCount => _pendingMessages.length;
/// Test bindings that are used by tests that mock message handlers for plugins
/// should mix in this binding to enable the use of the
/// [TestDefaultBinaryMessenger] APIs.
mixin TestDefaultBinaryMessengerBinding on BindingBase, ServicesBinding {
@override
Future<ByteData?>? send(String channel, ByteData? message) {
final Future<ByteData?>? resultFuture = delegate.send(channel, message);
if (resultFuture != null) {
_pendingMessages.add(resultFuture);
resultFuture
.catchError((Object error) { /* errors are the responsibility of the caller */ })
.whenComplete(() => _pendingMessages.remove(resultFuture));
}
return resultFuture;
void initInstances() {
super.initInstances();
_instance = this;
}
/// Returns a Future that completes after all the platform calls are finished.
///
/// If a new platform message is sent after this method is called, this new
/// message is not tracked. Use with [pendingMessageCount] to guarantee no
/// pending message calls.
Future<void> get platformMessagesFinished {
return Future.wait<void>(_pendingMessages);
}
/// The current [TestDefaultBinaryMessengerBinding], if one has been created.
static TestDefaultBinaryMessengerBinding? get instance => _instance;
static TestDefaultBinaryMessengerBinding? _instance;
@override
Future<void> handlePlatformMessage(
String channel,
ByteData? data,
ui.PlatformMessageResponseCallback? callback,
) {
return delegate.handlePlatformMessage(channel, data, callback);
}
TestDefaultBinaryMessenger get defaultBinaryMessenger => super.defaultBinaryMessenger as TestDefaultBinaryMessenger;
@override
void setMessageHandler(String channel, MessageHandler? handler) {
delegate.setMessageHandler(channel, handler);
}
@override
bool checkMessageHandler(String channel, MessageHandler? handler) {
return delegate.checkMessageHandler(channel, handler);
}
@override
void setMockMessageHandler(String channel, MessageHandler? handler) {
delegate.setMockMessageHandler(channel, handler);
}
@override
bool checkMockMessageHandler(String channel, MessageHandler? handler) {
return delegate.checkMockMessageHandler(channel, handler);
TestDefaultBinaryMessenger createBinaryMessenger() {
return TestDefaultBinaryMessenger(super.createBinaryMessenger());
}
}
@ -171,7 +126,8 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
SemanticsBinding,
RendererBinding,
PaintingBinding,
WidgetsBinding {
WidgetsBinding,
TestDefaultBinaryMessengerBinding {
/// Constructor for [TestWidgetsFlutterBinding].
///
@ -195,9 +151,15 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
/// Called by the test framework at the beginning of a widget test to
/// prepare the binding for the next test.
///
/// If [registerTestTextInput] returns true when this method is called,
/// the [testTextInput] is configured to simulate the keyboard.
void reset() {
_restorationManager = null;
resetGestureBinding();
testTextInput.reset();
if (registerTestTextInput)
_testTextInput.register();
}
@override
@ -237,7 +199,8 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
@protected
bool get overrideHttpClient => true;
/// Determines whether the binding automatically registers [testTextInput].
/// Determines whether the binding automatically registers [testTextInput] as
/// a fake keyboard implementation.
///
/// Unit tests make use of this to mock out text input communication for
/// widgets. An integration test would set this to false, to test real IME
@ -245,6 +208,19 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
///
/// [TestTextInput.isRegistered] reports whether the text input mock is
/// registered or not.
///
/// Some of the properties and methods on [testTextInput] are only valid if
/// [registerTestTextInput] returns true when a test starts. If those
/// members are accessed when using a binding that sets this flag to false,
/// they will throw.
///
/// If this property returns true when a test ends, the [testTextInput] is
/// unregistered.
///
/// This property should not change the value it returns during the lifetime
/// of the binding. Changing the value of this property risks very confusing
/// behavior as the [TestTextInput] may be inconsistently registered or
/// unregistered.
@protected
bool get registerTestTextInput => true;
@ -319,14 +295,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
binding.setupHttpOverrides();
}
_testTextInput = TestTextInput(onCleared: _resetFocusedEditable);
if (registerTestTextInput) {
_testTextInput.register();
}
}
@override
BinaryMessenger createBinaryMessenger() {
return TestDefaultBinaryMessenger(super.createBinaryMessenger());
}
@override
@ -515,12 +483,20 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
TestTextInput get testTextInput => _testTextInput;
late TestTextInput _testTextInput;
/// The current client of the onscreen keyboard. Callers must pump
/// an additional frame after setting this property to complete the
/// focus change.
/// The [State] of the current [EditableText] client of the onscreen keyboard.
///
/// Setting this property to a new value causes the given [EditableTextState]
/// to focus itself and request the keyboard to establish a
/// [TextInputConnection].
///
/// Callers must pump an additional frame after setting this property to
/// complete the focus change.
///
/// Instead of setting this directly, consider using
/// [WidgetTester.showKeyboard].
//
// TODO(ianh): We should just remove this property and move the call to
// requestKeyboard to the WidgetTester.showKeyboard method.
EditableTextState? get focusedEditable => _focusedEditable;
EditableTextState? _focusedEditable;
set focusedEditable(EditableTextState? value) {
@ -799,6 +775,8 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
// alone so that we don't cause more spurious errors.
runApp(Container(key: UniqueKey(), child: _postTestMessage)); // Unmount any remaining widgets.
await pump();
if (registerTestTextInput)
_testTextInput.unregister();
invariantTester();
_verifyAutoUpdateGoldensUnset(autoUpdateGoldensBeforeTest && !isBrowser);
_verifyReportTestExceptionUnset(reportTestExceptionBeforeTest);

View file

@ -0,0 +1,109 @@
// Copyright 2014 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:flutter/services.dart';
import 'binding.dart';
// TODO(ianh): Once https://github.com/dart-lang/dartdoc/issues/2033 is fixed, update the hyperlinks marked HYPERLINK below.
// TODO(ianh): Once cocoon and other customer_tests are migrated, deprecate these transitional APIs
/// Shim to support the obsolete [setMockMessageHandler] and
/// [checkMockMessageHandler] methods on [BinaryMessenger] in tests.
///
/// The implementations defer to [TestDefaultBinaryMessengerBinding.defaultBinaryMessenger].
///
/// Rather than calling [setMockMessageHandler] on the
/// `ServicesBinding.defaultBinaryMessenger`, use
/// `tester.binding.defaultBinaryMessenger.setMockMessageHandler` directly. This
/// more accurately represents the actual method invocation.
extension TestBinaryMessengerExtension on BinaryMessenger {
/// Shim for `TestDefaultBinaryMessenger.setMockMessageHandler`.
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// TODO(ianh): deprecate this method: @NotYetDeprecated(
// 'Use tester.binding.defaultBinaryMessenger.setMockMessageHandler or '
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.setMockMessageHandler instead. '
// 'This feature was deprecated after v2.1.0-10.0.pre.'
// )
void setMockMessageHandler(String channel, MessageHandler? handler) {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(channel, handler);
}
/// Shim for `TestDefaultBinaryMessenger.checkMockMessageHandler`.
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// TODO(ianh): deprecate this method: @NotYetDeprecated(
// 'Use tester.binding.defaultBinaryMessenger.checkMockMessageHandler or '
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.checkMockMessageHandler instead.'
// 'This feature was deprecated after v2.1.0-10.0.pre.'
// )
bool checkMockMessageHandler(String channel, Object? handler) {
return TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel, handler);
}
}
/// Shim to support the obsolete [setMockMessageHandler] and
/// [checkMockMessageHandler] methods on [BasicMessageChannel] in tests.
///
/// The implementations defer to [TestDefaultBinaryMessengerBinding.defaultBinaryMessenger].
///
/// Rather than calling [setMockMessageHandler] on the message channel, use
/// `tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler`
/// directly. This more accurately represents the actual method invocation.
extension TestBasicMessageChannelExtension<T> on BasicMessageChannel<T> {
/// Shim for `TestDefaultBinaryMessenger.setMockDecodedMessageHandler`.
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// TODO(ianh): deprecate this method: @NotYetDeprecated(
// 'Use tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler or '
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.setMockDecodedMessageHandler instead. '
// 'This feature was deprecated after v2.1.0-10.0.pre.'
// )
void setMockMessageHandler(Future<T> Function(T? message)? handler) {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<T>(this, handler);
}
/// Shim for `TestDefaultBinaryMessenger.checkMockMessageHandler`.
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// TODO(ianh): deprecate this method: @NotYetDeprecated(
// 'Use tester.binding.defaultBinaryMessenger.checkMockMessageHandler or '
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.checkMockMessageHandler instead. '
// 'For the first argument, pass channel.name. '
// 'This feature was deprecated after v2.1.0-10.0.pre.'
// )
bool checkMockMessageHandler(Object? handler) {
return TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(name, handler);
}
}
/// Shim to support the obsolete [setMockMethodCallHandler] and
/// [checkMockMethodCallHandler] methods on [MethodChannel] in tests.
///
/// The implementations defer to [TestDefaultBinaryMessengerBinding.defaultBinaryMessenger].
///
/// Rather than calling [setMockMethodCallHandler] on the method channel, use
/// `tester.binding.defaultBinaryMessenger.setMockMethodCallHandler` directly.
/// This more accurately represents the actual method invocation.
extension TestMethodChannelExtension on MethodChannel {
/// Shim for `TestDefaultBinaryMessenger.setMockMethodCallHandler`.
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// TODO(ianh): deprecate this method: @NotYetDeprecated(
// 'Use tester.binding.defaultBinaryMessenger.setMockMethodCallHandler or '
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.setMockMethodCallHandler instead. '
// 'This feature was deprecated after v2.1.0-10.0.pre.'
// )
void setMockMethodCallHandler(Future<dynamic>? Function(MethodCall call)? handler) {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(this, handler);
}
/// Shim for `TestDefaultBinaryMessenger.checkMockMessageHandler`.
// HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// TODO(ianh): deprecate this method: @NotYetDeprecated(
// 'Use tester.binding.defaultBinaryMessenger.checkMockMessageHandler or '
// 'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.checkMockMessageHandler instead. '
// 'For the first argument, pass channel.name. '
// 'This feature was deprecated after v2.1.0-10.0.pre.'
// )
bool checkMockMethodCallHandler(Object? handler) {
return TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(name, handler);
}
}

View file

@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/services.dart';
import 'binding.dart';
import 'test_async_utils.dart';
// TODO(gspencergoog): Replace this with more robust key simulation code once
@ -640,22 +643,22 @@ class KeyEventSimulator {
platform ??= Platform.operatingSystem;
assert(_osIsSupported(platform!), 'Platform $platform not supported for key simulation');
final Map<String, dynamic> data = getKeyData(key, platform: platform!, isDown: true, physicalKey: physicalKey, character: character);
bool result = false;
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
final Completer<bool> result = Completer<bool>();
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {
if (data == null) {
result.complete(false);
return;
}
final Map<String, dynamic> decoded = SystemChannels.keyEvent.codec.decodeMessage(data) as Map<String, dynamic>;
if (decoded['handled'] as bool) {
result = true;
}
result.complete(decoded['handled'] as bool);
}
);
return result;
return result.future;
});
}
@ -681,7 +684,7 @@ class KeyEventSimulator {
final Map<String, dynamic> data = getKeyData(key, platform: platform!, isDown: false, physicalKey: physicalKey);
bool result = false;
await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.keyEvent.name,
SystemChannels.keyEvent.codec.encodeMessage(data),
(ByteData? data) {

View file

@ -0,0 +1,306 @@
// Copyright 2014 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 'dart:async';
import 'dart:ui' as ui;
import 'package:fake_async/fake_async.dart';
import 'package:flutter/services.dart';
/// A [BinaryMessenger] subclass that is used as the default binary messenger
/// under testing environment.
///
/// It tracks status of data sent across the Flutter platform barrier, which is
/// useful for testing frameworks to monitor and synchronize against the
/// platform messages.
///
/// ## Messages from the framework to the platform
///
/// Messages are sent from the framework to the platform via the
/// [send] method.
///
/// To intercept a message sent from the framework to the platform,
/// consider using [setMockMessageHandler],
/// [setMockDecodedMessageHandler], and [setMockMethodCallHandler]
/// (see also [checkMockMessageHandler]).
///
/// To wait for all pending framework-to-platform messages, the
/// [platformMessagesFinished] getter provides an appropriate
/// [Future]. The [pendingMessageCount] getter returns the current
/// number of outstanding messages.
///
/// ## Messages from the platform to the framework
///
/// The platform sends messages via the [ChannelBuffers] API. Mock
/// messages can be sent to the framework using
/// [handlePlatformMessage].
///
/// Listeners for these messages are configured using [setMessageHandler].
class TestDefaultBinaryMessenger extends BinaryMessenger {
/// Creates a [TestDefaultBinaryMessenger] instance.
///
/// The [delegate] instance must not be null.
TestDefaultBinaryMessenger(this.delegate): assert(delegate != null);
/// The delegate [BinaryMessenger].
final BinaryMessenger delegate;
// The handlers for messages from the engine (including fake
// messages sent by handlePlatformMessage).
final Map<String, MessageHandler> _inboundHandlers = <String, MessageHandler>{};
/// Send a mock message to the framework as if it came from the platform.
///
/// If a listener has been set using [setMessageHandler], that listener is
/// invoked to handle the message, and this method returns a future that
/// completes with that handler's result.
///
/// {@template flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
/// It is strongly recommended that all handlers used with this API be
/// synchronous (not requiring any microtasks to complete), because
/// [testWidgets] tests run in a [FakeAsync] zone in which microtasks do not
/// progress except when time is explicitly advanced (e.g. with
/// [WidgetTester.pump]), which means that `await`ing a [Future] will result
/// in the test hanging.
/// {@endtemplate}
///
/// If no listener is configured, this method returns right away with null.
///
/// The `callback` argument, if non-null, will be called just before this
/// method's future completes, either with the result of the listener
/// registered with [setMessageHandler], or with null if no listener has
/// been registered.
///
/// Messages can also be sent via [ChannelBuffers.push] (see
/// [ServicesBinding.channelBuffers]); the effect is the same, though that API
/// will not wait for a response.
// TODO(ianh): When the superclass `handlePlatformMessage` is removed,
// remove this @override (but leave the method).
@override
Future<ByteData?> handlePlatformMessage(
String channel,
ByteData? data,
ui.PlatformMessageResponseCallback? callback,
) {
Future<ByteData?>? result;
if (_inboundHandlers.containsKey(channel))
result = _inboundHandlers[channel]!(data);
result ??= Future<ByteData?>.value(null);
if (callback != null)
result = result.then((ByteData? result) { callback(result); return result; });
return result;
}
@override
void setMessageHandler(String channel, MessageHandler? handler) {
if (handler == null) {
_inboundHandlers.remove(channel);
delegate.setMessageHandler(channel, null);
} else {
_inboundHandlers[channel] = handler; // used to handle fake messages sent via handlePlatformMessage
delegate.setMessageHandler(channel, handler); // used to handle real messages from the engine
}
}
final List<Future<ByteData?>> _pendingMessages = <Future<ByteData?>>[];
/// The number of incomplete/pending calls sent to the platform channels.
int get pendingMessageCount => _pendingMessages.length;
// Handlers that intercept and respond to outgoing messages,
// pretending to be the platform.
final Map<String, MessageHandler> _outboundHandlers = <String, MessageHandler>{};
// The outbound callbacks that were actually registered, so that we
// can implement the [checkMockMessageHandler] method.
final Map<String, Object> _outboundHandlerIdentities = <String, Object>{};
@override
Future<ByteData?>? send(String channel, ByteData? message) {
final Future<ByteData?>? resultFuture;
final MessageHandler? handler = _outboundHandlers[channel];
if (handler != null) {
resultFuture = handler(message);
} else {
resultFuture = delegate.send(channel, message);
}
if (resultFuture != null) {
_pendingMessages.add(resultFuture);
resultFuture
.catchError((Object error) { /* errors are the responsibility of the caller */ })
.whenComplete(() => _pendingMessages.remove(resultFuture));
}
return resultFuture;
}
/// Returns a Future that completes after all the platform calls are finished.
///
/// If a new platform message is sent after this method is called, this new
/// message is not tracked. Use with [pendingMessageCount] to guarantee no
/// pending message calls.
Future<void> get platformMessagesFinished {
return Future.wait<void>(_pendingMessages);
}
/// Set a callback for intercepting messages sent to the platform on
/// the given channel, without decoding them.
///
/// Intercepted messages are not forwarded to the platform.
///
/// The given callback will replace the currently registered
/// callback for that channel, if any. To stop intercepting messages
/// at all, pass null as the handler.
///
/// The handler's return value, if non-null, is used as a response,
/// unencoded.
///
/// {@macro flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
///
/// The `identity` argument, if non-null, is used to identify the
/// callback when checked by [checkMockMessageHandler]. If null, the
/// `handler` is used instead. (This allows closures to be passed as
/// the `handler` with an alias used as the `identity` so that a
/// reference to the closure need not be used. In practice, this is
/// used by [setMockDecodedMessageHandler] and
/// [setMockMethodCallHandler] to allow [checkMockMessageHandler] to
/// recognize the closures that were passed to those methods even
/// though those methods wrap those closures when passing them to
/// this method.)
///
/// Registered callbacks are cleared after each test.
///
/// See also:
///
/// * [checkMockMessageHandler], which can verify if a handler is still
/// registered, which is useful in tests to ensure that no unexpected
/// handlers are being registered.
///
/// * [setMockDecodedMessageHandler], which wraps this method but
/// decodes the messages using a [MessageCodec].
///
/// * [setMockMethodCallHandler], which wraps this method but decodes
/// the messages using a [MethodCodec].
void setMockMessageHandler(String channel, MessageHandler? handler, [ Object? identity ]) {
if (handler == null) {
_outboundHandlers.remove(channel);
_outboundHandlerIdentities.remove(channel);
} else {
identity ??= handler;
_outboundHandlers[channel] = handler;
_outboundHandlerIdentities[channel] = identity;
}
}
/// Set a callback for intercepting messages sent to the platform on
/// the given channel.
///
/// Intercepted messages are not forwarded to the platform.
///
/// The given callback will replace the currently registered
/// callback for that channel, if any. To stop intercepting messages
/// at all, pass null as the handler.
///
/// Messages are decoded using the codec of the channel.
///
/// The handler's return value, if non-null, is used as a response,
/// after encoding it using the channel's codec.
///
/// {@macro flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
///
/// Registered callbacks are cleared after each test.
///
/// See also:
///
/// * [checkMockMessageHandler], which can verify if a handler is still
/// registered, which is useful in tests to ensure that no unexpected
/// handlers are being registered.
///
/// * [setMockMessageHandler], which is similar but provides raw
/// access to the underlying bytes.
///
/// * [setMockMethodCallHandler], which is similar but decodes
/// the messages using a [MethodCodec].
void setMockDecodedMessageHandler<T>(BasicMessageChannel<T> channel, Future<T> Function(T? message)? handler) {
if (handler == null) {
setMockMessageHandler(channel.name, null);
return;
}
setMockMessageHandler(channel.name, (ByteData? message) async {
return channel.codec.encodeMessage(await handler(channel.codec.decodeMessage(message)));
}, handler);
}
/// Set a callback for intercepting method calls sent to the
/// platform on the given channel.
///
/// Intercepted method calls are not forwarded to the platform.
///
/// The given callback will replace the currently registered
/// callback for that channel, if any. To stop intercepting messages
/// at all, pass null as the handler.
///
/// Methods are decoded using the codec of the channel.
///
/// The handler's return value, if non-null, is used as a response,
/// after re-encoding it using the channel's codec.
///
/// To send an error, throw a [PlatformException] in the handler.
/// Other exceptions are not caught.
///
/// {@macro flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
///
/// Registered callbacks are cleared after each test.
///
/// See also:
///
/// * [checkMockMessageHandler], which can verify if a handler is still
/// registered, which is useful in tests to ensure that no unexpected
/// handlers are being registered.
///
/// * [setMockMessageHandler], which is similar but provides raw
/// access to the underlying bytes.
///
/// * [setMockDecodedMessageHandler], which is similar but decodes
/// the messages using a [MessageCodec].
void setMockMethodCallHandler(MethodChannel channel, Future<Object?>? Function(MethodCall message)? handler) {
if (handler == null) {
setMockMessageHandler(channel.name, null);
return;
}
setMockMessageHandler(channel.name, (ByteData? message) async {
final MethodCall call = channel.codec.decodeMethodCall(message);
try {
return channel.codec.encodeSuccessEnvelope(await handler(call));
} on PlatformException catch (error) {
return channel.codec.encodeErrorEnvelope(
code: error.code,
message: error.message,
details: error.details,
);
} on MissingPluginException {
return null;
} catch (error) {
return channel.codec.encodeErrorEnvelope(code: 'error', message: '$error', details: null);
}
}, handler);
}
/// Returns true if the `handler` argument matches the `handler`
/// previously passed to [setMockMessageHandler],
/// [setMockDecodedMessageHandler], or [setMockMethodCallHandler].
///
/// Specifically, it compares the argument provided to the `identity`
/// argument provided to [setMockMessageHandler], defaulting to the
/// `handler` argument passed to that method is `identity` was null.
///
/// This method is useful for tests or test harnesses that want to assert the
/// mock handler for the specified channel has not been altered by a previous
/// test.
///
/// Passing null for the `handler` returns true if the handler for the
/// `channel` is not set.
///
/// Registered callbacks are cleared after each test.
bool checkMockMessageHandler(String channel, Object? handler) => _outboundHandlerIdentities[channel] == handler;
}

View file

@ -8,12 +8,28 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'binding.dart' show TestDefaultBinaryMessengerBinding;
import 'deprecated.dart';
import 'test_async_utils.dart';
export 'package:flutter/services.dart' show TextEditingValue, TextInputAction;
/// A testing stub for the system's onscreen keyboard.
///
/// Typical app tests will not need to use this class directly.
///
/// The [TestWidgetsFlutterBinding] class registers a [TestTextInput] instance
/// ([TestWidgetsFlutterBinding.testTextInput]) as a stub keyboard
/// implementation if its [TestWidgetsFlutterBinding.registerTestTextInput]
/// property returns true when a test starts, and unregisters it when the test
/// ends (unless it ends with a failure).
///
/// See [register], [unregister], and [isRegistered] for details.
///
/// The [enterText], [updateEditingValue], [receiveAction], and
/// [closeConnection] methods can be used even when the [TestTextInput] is not
/// registered. All other methods will assert if [isRegistered] is false.
///
/// See also:
///
/// * [WidgetTester.enterText], which uses this class to simulate keyboard input.
@ -33,61 +49,76 @@ class TestTextInput {
/// first be requested, e.g. using [WidgetTester.showKeyboard].
final VoidCallback? onCleared;
/// The messenger which sends the bytes for this channel, not null.
BinaryMessenger get _binaryMessenger => ServicesBinding.instance!.defaultBinaryMessenger;
/// Resets any internal state of this object and calls [register].
///
/// This method is invoked by the testing framework between tests. It should
/// not ordinarily be called by tests directly.
void resetAndRegister() {
log.clear();
editingState = null;
setClientArgs = null;
_client = 0;
_isVisible = false;
register();
}
/// Installs this object as a mock handler for [SystemChannels.textInput].
void register() => SystemChannels.textInput.setMockMethodCallHandler(_handleTextInputCall);
/// Removes this object as a mock handler for [SystemChannels.textInput].
///
/// After calling this method, the channel will exchange messages with the
/// Flutter engine. Use this with [FlutterDriver] tests that need to display
/// on-screen keyboard provided by the operating system.
void unregister() => SystemChannels.textInput.setMockMethodCallHandler(null);
/// Log for method calls.
///
/// For all registered channels, handled calls are added to the list. Can
/// be cleaned using `log.clear()`.
final List<MethodCall> log = <MethodCall>[];
/// Installs this object as a mock handler for [SystemChannels.textInput].
///
/// Called by the binding at the top of a test when
/// [TestWidgetsFlutterBinding.registerTestTextInput] is true.
void register() => SystemChannels.textInput.setMockMethodCallHandler(_handleTextInputCall);
/// Removes this object as a mock handler for [SystemChannels.textInput].
///
/// After calling this method, the channel will exchange messages with the
/// Flutter engine instead of the stub.
///
/// Called by the binding at the end of a (successful) test when
/// [TestWidgetsFlutterBinding.registerTestTextInput] is true.
void unregister() => SystemChannels.textInput.setMockMethodCallHandler(null);
/// Whether this [TestTextInput] is registered with [SystemChannels.textInput].
///
/// Use [register] and [unregister] methods to control this value.
/// The binding uses the [register] and [unregister] methods to control this
/// value when [TestWidgetsFlutterBinding.registerTestTextInput] is true.
bool get isRegistered => SystemChannels.textInput.checkMockMethodCallHandler(_handleTextInputCall);
int? _client;
/// Whether there are any active clients listening to text input.
bool get hasAnyClients {
assert(isRegistered);
return _client > 0;
return _client != null && _client! > 0;
}
int _client = 0;
/// Arguments supplied to the TextInput.setClient method call.
/// The last set of arguments supplied to the `TextInput.setClient` and
/// `TextInput.updateConfig` methods of this stub implementation.
Map<String, dynamic>? setClientArgs;
/// The last set of arguments that [TextInputConnection.setEditingState] sent
/// to the embedder.
/// to this stub implementation (i.e. the arguments set to
/// `TextInput.setEditingState`).
///
/// This is a map representation of a [TextEditingValue] object. For example,
/// it will have a `text` entry whose value matches the most recent
/// [TextEditingValue.text] that was sent to the embedder.
Map<String, dynamic>? editingState;
/// Whether the onscreen keyboard is visible to the user.
///
/// Specifically, this reflects the last call to `TextInput.show` or
/// `TextInput.hide` received by the stub implementation.
bool get isVisible {
assert(isRegistered);
return _isVisible;
}
bool _isVisible = false;
/// Resets any internal state of this object.
///
/// This method is invoked by the testing framework between tests. It should
/// not ordinarily be called by tests directly.
void reset() {
log.clear();
_client = null;
setClientArgs = null;
editingState = null;
_isVisible = false;
}
Future<dynamic> _handleTextInputCall(MethodCall methodCall) async {
log.add(methodCall);
switch (methodCall.method) {
@ -99,7 +130,7 @@ class TestTextInput {
setClientArgs = methodCall.arguments as Map<String, dynamic>;
break;
case 'TextInput.clearClient':
_client = 0;
_client = null;
_isVisible = false;
onCleared?.call();
break;
@ -115,87 +146,86 @@ class TestTextInput {
}
}
/// Whether the onscreen keyboard is visible to the user.
bool get isVisible {
assert(isRegistered);
return _isVisible;
}
bool _isVisible = false;
/// Simulates the user changing the [TextEditingValue] to the given value.
void updateEditingValue(TextEditingValue value) {
assert(isRegistered);
// Not using the `expect` function because in the case of a FlutterDriver
// test this code does not run in a package:test test zone.
if (_client == 0)
throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
_binaryMessenger.handlePlatformMessage(
SystemChannels.textInput.name,
SystemChannels.textInput.codec.encodeMethodCall(
MethodCall(
'TextInputClient.updateEditingState',
<dynamic>[_client, value.toJSON()],
),
),
(ByteData? data) { /* response from framework is discarded */ },
);
}
/// Simulates the user closing the text input connection.
/// Simulates the user hiding the onscreen keyboard.
///
/// For example:
/// - User pressed the home button and sent the application to background.
/// - User closed the virtual keyboard.
void closeConnection() {
/// This does nothing but set the internal flag.
void hide() {
assert(isRegistered);
// Not using the `expect` function because in the case of a FlutterDriver
// test this code does not run in a package:test test zone.
if (_client == 0)
throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
_binaryMessenger.handlePlatformMessage(
SystemChannels.textInput.name,
SystemChannels.textInput.codec.encodeMethodCall(
MethodCall(
'TextInputClient.onConnectionClosed',
<dynamic>[_client,]
),
),
(ByteData? data) { /* response from framework is discarded */ },
);
_isVisible = false;
}
/// Simulates the user typing the given text.
/// Simulates the user changing the text of the focused text field, and resets
/// the selection.
///
/// Calling this method replaces the content of the connected input field with
/// `text`, and places the caret at the end of the text.
///
/// To update the UI under test after this method is invoked, use
/// [WidgetTester.pump].
///
/// This can be called even if the [TestTextInput] has not been [register]ed.
///
/// If this is used to inject text when there is a real IME connection, for
/// example when using the [integration_test] library, there is a risk that
/// the real IME will become confused as to the current state of input.
///
/// See also:
///
/// * [updateEditingValue], which takes a [TextEditingValue] so that one can
/// also change the selection.
void enterText(String text) {
assert(isRegistered);
updateEditingValue(TextEditingValue(
text: text,
selection: TextSelection.collapsed(offset: text.length),
));
}
/// Simulates the user changing the [TextEditingValue] to the given value.
///
/// To update the UI under test after this method is invoked, use
/// [WidgetTester.pump].
///
/// This can be called even if the [TestTextInput] has not been [register]ed.
///
/// If this is used to inject text when there is a real IME connection, for
/// example when using the [integration_test] library, there is a risk that
/// the real IME will become confused as to the current state of input.
///
/// See also:
///
/// * [enterText], which is similar but takes only a String and resets the
/// selection.
void updateEditingValue(TextEditingValue value) {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.textInput.name,
SystemChannels.textInput.codec.encodeMethodCall(
MethodCall(
'TextInputClient.updateEditingState',
<dynamic>[_client ?? -1, value.toJSON()],
),
),
(ByteData? data) { /* ignored */ },
);
}
/// Simulates the user pressing one of the [TextInputAction] buttons.
/// Does not check that the [TextInputAction] performed is an acceptable one
/// based on the `inputAction` [setClientArgs].
///
/// This can be called even if the [TestTextInput] has not been [register]ed.
///
/// If this is used to inject an action when there is a real IME connection,
/// for example when using the [integration_test] library, there is a risk
/// that the real IME will become confused as to the current state of input.
Future<void> receiveAction(TextInputAction action) async {
assert(isRegistered);
return TestAsyncUtils.guard(() {
// Not using the `expect` function because in the case of a FlutterDriver
// test this code does not run in a package:test test zone.
if (_client == 0) {
throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
}
final Completer<void> completer = Completer<void>();
_binaryMessenger.handlePlatformMessage(
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.textInput.name,
SystemChannels.textInput.codec.encodeMethodCall(
MethodCall(
'TextInputClient.performAction',
<dynamic>[_client, action.toString()],
<dynamic>[_client ?? -1, action.toString()],
),
),
(ByteData? data) {
@ -204,8 +234,7 @@ class TestTextInput {
// Decoding throws a PlatformException if the data represents an
// error, and that's all we care about here.
SystemChannels.textInput.codec.decodeEnvelope(data!);
// No error was found. Complete without issue.
// If we reach here then no error was found. Complete without issue.
completer.complete();
} catch (error) {
// An exception occurred as a result of receiveAction()'ing. Report
@ -214,14 +243,32 @@ class TestTextInput {
}
},
);
return completer.future;
});
}
/// Simulates the user hiding the onscreen keyboard.
void hide() {
assert(isRegistered);
_isVisible = false;
/// Simulates the user closing the text input connection.
///
/// For example:
///
/// * User pressed the home button and sent the application to background.
/// * User closed the virtual keyboard.
///
/// This can be called even if the [TestTextInput] has not been [register]ed.
///
/// If this is used to inject text when there is a real IME connection, for
/// example when using the [integration_test] library, there is a risk that
/// the real IME will become confused as to the current state of input.
void closeConnection() {
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
SystemChannels.textInput.name,
SystemChannels.textInput.codec.encodeMethodCall(
MethodCall(
'TextInputClient.onConnectionClosed',
<dynamic>[_client ?? -1],
),
),
(ByteData? data) { /* response from framework is discarded */ },
);
}
}

View file

@ -129,7 +129,7 @@ void testWidgets(
dynamic tags,
}) {
assert(variant != null);
assert(variant.values.isNotEmpty, 'There must be at least on value to test in the testing variant');
assert(variant.values.isNotEmpty, 'There must be at least one value to test in the testing variant.');
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
final WidgetTester tester = WidgetTester._(binding);
for (final dynamic value in variant.values) {
@ -147,9 +147,8 @@ void testWidgets(
test_package.addTearDown(binding.postTest);
return binding.runTest(
() async {
binding.reset();
binding.reset(); // TODO(ianh): the binding should just do this itself in _runTest
debugResetSemanticsIdCounter();
tester.resetTestTextInput();
Object? memento;
try {
memento = await variant.setUp(value);
@ -918,10 +917,12 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
/// Acts as if the application went idle.
///
/// Runs all remaining microtasks, including those scheduled as a result of
/// running them, until there are no more microtasks scheduled.
/// running them, until there are no more microtasks scheduled. Then, runs any
/// previously scheduled timers with zero time, and completes the returned future.
///
/// Does not run timers. May result in an infinite loop or run out of memory
/// if microtasks continue to recursively schedule new microtasks.
/// May result in an infinite loop or run out of memory if microtasks continue
/// to recursively schedule new microtasks. Will not run any timers scheduled
/// after this method was invoked, even if they are zero-time timers.
Future<void> idle() {
return TestAsyncUtils.guard<void>(() => binding.idle());
}
@ -1002,18 +1003,13 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
///
/// Typical app tests will not need to use this value. To add text to widgets
/// like [TextField] or [TextFormField], call [enterText].
TestTextInput get testTextInput => binding.testTextInput;
/// Ensures that [testTextInput] is registered and [TestTextInput.log] is
/// reset.
///
/// This is called by the testing framework before test runs, so that if a
/// previous test has set its own handler on [SystemChannels.textInput], the
/// [testTextInput] regains control and the log is fresh for the new test.
/// It should not typically need to be called by tests.
void resetTestTextInput() {
testTextInput.resetAndRegister();
}
/// Some of the properties and methods on this value are only valid if the
/// binding's [TestWidgetsFlutterBinding.registerTestTextInput] flag is set to
/// true as a test is starting (meaning that the keyboard is to be simulated
/// by the test framework). If those members are accessed when using a binding
/// that sets this flag to false, they will throw.
TestTextInput get testTextInput => binding.testTextInput;
/// Give the text input widget specified by [finder] the focus, as if the
/// onscreen keyboard had appeared.
@ -1035,6 +1031,9 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
matchRoot: true,
),
);
// Setting focusedEditable causes the binding to call requestKeyboard()
// on the EditableTextState, which itself eventually calls TextInput.attach
// to establish the connection.
binding.focusedEditable = editable;
await pump();
});
@ -1052,6 +1051,12 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
///
/// To just give [finder] the focus without entering any text,
/// see [showKeyboard].
///
/// To enter text into other widgets (e.g. a custom widget that maintains a
/// TextInputConnection the way that a [EditableText] does), first ensure that
/// that widget has an open connection (e.g. by using [tap] to to focus it),
/// then call `testTextInput.enterText` directly (see
/// [TestTextInput.enterText]).
Future<void> enterText(Finder finder, String text) async {
return TestAsyncUtils.guard<void>(() async {
await showKeyboard(finder);

View file

@ -379,8 +379,16 @@ class TestWindow implements ui.SingletonFlutterWindow {
platformDispatcher.sendPlatformMessage(name, data, callback);
}
@Deprecated(
'Instead of calling this callback, use ServicesBinding.instance.channelBuffers.push. '
'This feature was deprecated after v2.1.0-10.0.pre.'
)
@override
ui.PlatformMessageCallback? get onPlatformMessage => platformDispatcher.onPlatformMessage;
@Deprecated(
'Instead of setting this callback, use ServicesBinding.instance.defaultBinaryMessenger.setMessageHandler. '
'This feature was deprecated after v2.1.0-10.0.pre.'
)
@override
set onPlatformMessage(ui.PlatformMessageCallback? callback) {
platformDispatcher.onPlatformMessage = callback;

View file

@ -11,6 +11,8 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:test_api/test_api.dart' as test_package;
void main() {
final AutomatedTestWidgetsFlutterBinding binding = AutomatedTestWidgetsFlutterBinding();
group(TestViewConfiguration, () {
test('is initialized with top-level window if one is not provided', () {
// The code below will throw without the default.
@ -20,15 +22,32 @@ void main() {
group(AutomatedTestWidgetsFlutterBinding, () {
test('allows setting defaultTestTimeout to 5 minutes', () {
final AutomatedTestWidgetsFlutterBinding binding = AutomatedTestWidgetsFlutterBinding();
binding.defaultTestTimeout = const test_package.Timeout(Duration(minutes: 5));
expect(binding.defaultTestTimeout.duration, const Duration(minutes: 5));
});
});
// The next three tests must run in order -- first using `test`, then `testWidgets`, then `test` again.
int order = 0;
test('Initializes httpOverrides and testTextInput', () async {
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
expect(binding.testTextInput.isRegistered, true);
assert(order == 0);
expect(binding.testTextInput, isNotNull);
expect(binding.testTextInput.isRegistered, isFalse);
expect(HttpOverrides.current, isNotNull);
order += 1;
});
testWidgets('Registers testTextInput', (WidgetTester tester) async {
assert(order == 1);
expect(tester.testTextInput.isRegistered, isTrue);
order += 1;
});
test('Unregisters testTextInput', () async {
assert(order == 2);
expect(binding.testTextInput.isRegistered, isFalse);
order += 1;
});
}

View file

@ -20,12 +20,6 @@ class TestDelegate extends BinaryMessenger {
Future<void> handlePlatformMessage(String channel, ByteData? data, ui.PlatformMessageResponseCallback? callback) => throw UnimplementedError();
@override
void setMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
@override
bool checkMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
@override
void setMockMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
@override
bool checkMockMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
}
void main() {

View file

@ -61,7 +61,7 @@ class Registrar extends BinaryMessenger {
/// the [dart:ui] library. That function is only available when
/// compiling for the web.
void registerMessageHandler() {
// The function below is only defined in the Web dart:ui.
// The `ui.webOnlySetPluginHandler` function below is only defined in the Web dart:ui.
// ignore: undefined_function
ui.webOnlySetPluginHandler(handleFrameworkMessage);
}
@ -141,7 +141,7 @@ class Registrar extends BinaryMessenger {
@override
Future<ByteData?> send(String channel, ByteData? message) {
final Completer<ByteData?> completer = Completer<ByteData?>();
ui.window.onPlatformMessage!(channel, message, (ByteData? reply) {
ui.channelBuffers.push(channel, message, (ByteData? reply) {
try {
completer.complete(reply);
} catch (exception, stack) {
@ -163,26 +163,6 @@ class Registrar extends BinaryMessenger {
else
_handlers[channel] = handler;
}
@override
bool checkMessageHandler(String channel, MessageHandler? handler) => _handlers[channel] == handler;
@override
void setMockMessageHandler(
String channel,
MessageHandler? handler,
) {
throw FlutterError(
'Setting mock handlers is not supported on the platform side.',
);
}
@override
bool checkMockMessageHandler(String channel, MessageHandler? handler) {
throw FlutterError(
'Setting mock handlers is not supported on the platform side.',
);
}
}
/// This class was previously separate from [Registrar] but was merged into it

View file

@ -71,12 +71,5 @@ void main() {
ServicesBinding.instance!.defaultBinaryMessenger
.setMessageHandler('test_send', null);
});
test('throws when trying to set a mock handler', () {
expect(
() => pluginBinaryMessenger.setMockMessageHandler(
'test', (ByteData? data) async => ByteData(0)),
throwsFlutterError);
});
});
}