| // 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:isolate'; | |
| import 'package:flutter/services.dart'; | |
| import 'pair.dart'; | |
| import 'test_step.dart'; | |
| class ExtendedStandardMessageCodec extends StandardMessageCodec { | |
| const ExtendedStandardMessageCodec(); | |
| static const int _dateTime = 128; | |
| static const int _pair = 129; | |
| @override | |
| void writeValue(WriteBuffer buffer, dynamic value) { | |
| if (value is DateTime) { | |
| buffer.putUint8(_dateTime); | |
| buffer.putInt64(value.millisecondsSinceEpoch); | |
| } else if (value is Pair) { | |
| buffer.putUint8(_pair); | |
| writeValue(buffer, value.left); | |
| writeValue(buffer, value.right); | |
| } else { | |
| super.writeValue(buffer, value); | |
| } | |
| } | |
| @override | |
| dynamic readValueOfType(int type, ReadBuffer buffer) { | |
| switch (type) { | |
| case _dateTime: | |
| return DateTime.fromMillisecondsSinceEpoch(buffer.getInt64()); | |
| case _pair: | |
| return Pair(readValue(buffer), readValue(buffer)); | |
| default: return super.readValueOfType(type, buffer); | |
| } | |
| } | |
| } | |
| Future<TestStepResult> basicBinaryHandshake(ByteData? message) async { | |
| const BasicMessageChannel<ByteData?> channel = | |
| BasicMessageChannel<ByteData?>( | |
| 'binary-msg', | |
| BinaryCodec(), | |
| ); | |
| return _basicMessageHandshake<ByteData?>( | |
| 'Binary >${toString(message)}<', channel, message); | |
| } | |
| Future<TestStepResult> basicStringHandshake(String? message) async { | |
| const BasicMessageChannel<String?> channel = BasicMessageChannel<String?>( | |
| 'string-msg', | |
| StringCodec(), | |
| ); | |
| return _basicMessageHandshake<String?>('String >$message<', channel, message); | |
| } | |
| Future<TestStepResult> basicJsonHandshake(dynamic message) async { | |
| const BasicMessageChannel<dynamic> channel = | |
| BasicMessageChannel<dynamic>( | |
| 'json-msg', | |
| JSONMessageCodec(), | |
| ); | |
| return _basicMessageHandshake<dynamic>('JSON >$message<', channel, message); | |
| } | |
| Future<TestStepResult> basicStandardHandshake(dynamic message) async { | |
| const BasicMessageChannel<dynamic> channel = | |
| BasicMessageChannel<dynamic>( | |
| 'std-msg', | |
| ExtendedStandardMessageCodec(), | |
| ); | |
| return _basicMessageHandshake<dynamic>( | |
| 'Standard >${toString(message)}<', channel, message); | |
| } | |
| Future<void> _basicBackgroundStandardEchoMain(List<Object> args) async { | |
| final SendPort sendPort = args[2] as SendPort; | |
| final Object message = args[1]; | |
| final String name = 'Background Echo >${toString(message)}<'; | |
| const String description = | |
| 'Uses a platform channel from a background isolate.'; | |
| try { | |
| BackgroundIsolateBinaryMessenger.ensureInitialized( | |
| args[0] as RootIsolateToken); | |
| const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>( | |
| 'std-echo', | |
| ExtendedStandardMessageCodec(), | |
| ); | |
| final Object response = await channel.send(message) as Object; | |
| final TestStatus testStatus = TestStepResult.deepEquals(message, response) | |
| ? TestStatus.ok | |
| : TestStatus.failed; | |
| sendPort.send(TestStepResult(name, description, testStatus)); | |
| } catch (ex) { | |
| sendPort.send(TestStepResult(name, description, TestStatus.failed, | |
| error: ex.toString())); | |
| } | |
| } | |
| Future<TestStepResult> basicBackgroundStandardEcho(Object message) async { | |
| final ReceivePort receivePort = ReceivePort(); | |
| Isolate.spawn(_basicBackgroundStandardEchoMain, <Object>[ | |
| ServicesBinding.rootIsolateToken!, | |
| message, | |
| receivePort.sendPort, | |
| ]); | |
| return await receivePort.first as TestStepResult; | |
| } | |
| Future<TestStepResult> basicBinaryMessageToUnknownChannel() async { | |
| const BasicMessageChannel<ByteData?> channel = | |
| BasicMessageChannel<ByteData?>( | |
| 'binary-unknown', | |
| BinaryCodec(), | |
| ); | |
| return _basicMessageToUnknownChannel<ByteData>('Binary', channel); | |
| } | |
| Future<TestStepResult> basicStringMessageToUnknownChannel() async { | |
| const BasicMessageChannel<String?> channel = BasicMessageChannel<String?>( | |
| 'string-unknown', | |
| StringCodec(), | |
| ); | |
| return _basicMessageToUnknownChannel<String>('String', channel); | |
| } | |
| Future<TestStepResult> basicJsonMessageToUnknownChannel() async { | |
| const BasicMessageChannel<dynamic> channel = | |
| BasicMessageChannel<dynamic>( | |
| 'json-unknown', | |
| JSONMessageCodec(), | |
| ); | |
| return _basicMessageToUnknownChannel<dynamic>('JSON', channel); | |
| } | |
| Future<TestStepResult> basicStandardMessageToUnknownChannel() async { | |
| const BasicMessageChannel<dynamic> channel = | |
| BasicMessageChannel<dynamic>( | |
| 'std-unknown', | |
| ExtendedStandardMessageCodec(), | |
| ); | |
| return _basicMessageToUnknownChannel<dynamic>('Standard', channel); | |
| } | |
| /// Sends the specified message to the platform, doing a | |
| /// receive message/send reply/receive reply echo handshake initiated by the | |
| /// platform, then expecting a reply echo to the original message. | |
| /// | |
| /// Fails, if an error occurs, or if any message seen is not deeply equal to | |
| /// the original message. | |
| Future<TestStepResult> _basicMessageHandshake<T>( | |
| String description, | |
| BasicMessageChannel<T?> channel, | |
| T message, | |
| ) async { | |
| final List<dynamic> received = <dynamic>[]; | |
| channel.setMessageHandler((T? message) async { | |
| received.add(message); | |
| return message; | |
| }); | |
| dynamic messageEcho = nothing; | |
| dynamic error = nothing; | |
| try { | |
| messageEcho = await channel.send(message); | |
| } catch (e) { | |
| error = e; | |
| } | |
| return resultOfHandshake( | |
| 'Basic message handshake', | |
| description, | |
| message, | |
| received, | |
| messageEcho, | |
| error, | |
| ); | |
| } | |
| /// Sends a message on a channel that no one listens on. | |
| Future<TestStepResult> _basicMessageToUnknownChannel<T>( | |
| String description, | |
| BasicMessageChannel<T?> channel, | |
| ) async { | |
| dynamic messageEcho = nothing; | |
| dynamic error = nothing; | |
| try { | |
| messageEcho = await channel.send(null); | |
| } catch (e) { | |
| error = e; | |
| } | |
| return resultOfHandshake( | |
| 'Message on unknown channel', | |
| description, | |
| null, | |
| <dynamic>[null, null], | |
| messageEcho, | |
| error, | |
| ); | |
| } | |
| String toString(dynamic message) { | |
| if (message is ByteData) { | |
| return message.buffer | |
| .asUint8List(message.offsetInBytes, message.lengthInBytes) | |
| .toString(); | |
| } else { | |
| return '$message'; | |
| } | |
| } |