basic_messaging.dart 6.13 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
6
import 'dart:isolate';
7 8 9

import 'package:flutter/services.dart';

10
import 'pair.dart';
11 12
import 'test_step.dart';

13 14 15
class ExtendedStandardMessageCodec extends StandardMessageCodec {
  const ExtendedStandardMessageCodec();

16 17
  static const int _dateTime = 128;
  static const int _pair = 129;
18 19 20 21

  @override
  void writeValue(WriteBuffer buffer, dynamic value) {
    if (value is DateTime) {
22
      buffer.putUint8(_dateTime);
23 24
      buffer.putInt64(value.millisecondsSinceEpoch);
    } else if (value is Pair) {
25
      buffer.putUint8(_pair);
26 27 28 29 30 31 32 33 34 35
      writeValue(buffer, value.left);
      writeValue(buffer, value.right);
    } else {
      super.writeValue(buffer, value);
    }
  }

  @override
  dynamic readValueOfType(int type, ReadBuffer buffer) {
    switch (type) {
36
    case _dateTime:
37
      return DateTime.fromMillisecondsSinceEpoch(buffer.getInt64());
38
    case _pair:
39
      return Pair(readValue(buffer), readValue(buffer));
40 41 42 43 44
    default: return super.readValueOfType(type, buffer);
    }
  }
}

45 46 47
Future<TestStepResult> basicBinaryHandshake(ByteData? message) async {
  const BasicMessageChannel<ByteData?> channel =
      BasicMessageChannel<ByteData?>(
48
    'binary-msg',
49
    BinaryCodec(),
50
  );
51
  return _basicMessageHandshake<ByteData?>(
52 53 54
      'Binary >${toString(message)}<', channel, message);
}

55 56
Future<TestStepResult> basicStringHandshake(String? message) async {
  const BasicMessageChannel<String?> channel = BasicMessageChannel<String?>(
57
    'string-msg',
58
    StringCodec(),
59
  );
60
  return _basicMessageHandshake<String?>('String >$message<', channel, message);
61 62
}

63
Future<TestStepResult> basicJsonHandshake(dynamic message) async {
64
  const BasicMessageChannel<dynamic> channel =
65
      BasicMessageChannel<dynamic>(
66
    'json-msg',
67
    JSONMessageCodec(),
68 69 70 71 72 73
  );
  return _basicMessageHandshake<dynamic>('JSON >$message<', channel, message);
}

Future<TestStepResult> basicStandardHandshake(dynamic message) async {
  const BasicMessageChannel<dynamic> channel =
74
      BasicMessageChannel<dynamic>(
75
    'std-msg',
76
    ExtendedStandardMessageCodec(),
77 78 79 80 81
  );
  return _basicMessageHandshake<dynamic>(
      'Standard >${toString(message)}<', channel, message);
}

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
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;
}

117
Future<TestStepResult> basicBinaryMessageToUnknownChannel() async {
118 119
  const BasicMessageChannel<ByteData?> channel =
      BasicMessageChannel<ByteData?>(
120
    'binary-unknown',
121
    BinaryCodec(),
122 123 124 125 126
  );
  return _basicMessageToUnknownChannel<ByteData>('Binary', channel);
}

Future<TestStepResult> basicStringMessageToUnknownChannel() async {
127
  const BasicMessageChannel<String?> channel = BasicMessageChannel<String?>(
128
    'string-unknown',
129
    StringCodec(),
130 131 132 133 134 135
  );
  return _basicMessageToUnknownChannel<String>('String', channel);
}

Future<TestStepResult> basicJsonMessageToUnknownChannel() async {
  const BasicMessageChannel<dynamic> channel =
136
      BasicMessageChannel<dynamic>(
137
    'json-unknown',
138
    JSONMessageCodec(),
139 140 141 142 143 144
  );
  return _basicMessageToUnknownChannel<dynamic>('JSON', channel);
}

Future<TestStepResult> basicStandardMessageToUnknownChannel() async {
  const BasicMessageChannel<dynamic> channel =
145
      BasicMessageChannel<dynamic>(
146
    'std-unknown',
147
    ExtendedStandardMessageCodec(),
148 149 150 151 152 153 154 155 156 157 158 159
  );
  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,
160
  BasicMessageChannel<T?> channel,
161 162 163
  T message,
) async {
  final List<dynamic> received = <dynamic>[];
164
  channel.setMessageHandler((T? message) async {
165
    received.add(message);
166
    return message;
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
  });
  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,
188
  BasicMessageChannel<T?> channel,
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
) 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) {
208
  if (message is ByteData) {
209 210 211
    return message.buffer
        .asUint8List(message.offsetInBytes, message.lengthInBytes)
        .toString();
212
  } else {
213
    return '$message';
214
  }
215
}