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

5
import 'dart:io';
6
import 'dart:isolate';
7 8
import 'package:file/file.dart';
import 'package:file/local.dart';
9
import 'package:flutter/foundation.dart';
10
import 'package:flutter_test/flutter_test.dart';
11
import 'package:platform/platform.dart';
12

13 14
final Matcher throwsRemoteError = throwsA(isA<RemoteError>());

15 16 17 18 19 20 21 22
int test1(int value) {
  return value + 1;
}

int test2(int value) {
  throw 2;
}

23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
int test3(int value) {
  Isolate.exit();
}

int test4(int value) {
  Isolate.current.kill();

  return value + 1;
}

int test5(int value) {
  Isolate.current.kill(priority: Isolate.immediate);

  return value + 1;
}

39 40 41 42 43 44 45 46
Future<int> test1Async(int value) async {
  return value + 1;
}

Future<int> test2Async(int value) async {
  throw 2;
}

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
Future<int> test3Async(int value) async {
  Isolate.exit();
}

Future<int> test4Async(int value) async {
  Isolate.current.kill();

  return value + 1;
}

Future<int> test5Async(int value) async {
  Isolate.current.kill(priority: Isolate.immediate);

  return value + 1;
}

Future<int> test1CallCompute(int value) {
  return compute(test1, value);
}

Future<int> test2CallCompute(int value) {
  return compute(test2, value);
}

Future<int> test3CallCompute(int value) {
  return compute(test3, value);
}

Future<int> test4CallCompute(int value) {
  return compute(test4, value);
}

Future<int> test5CallCompute(int value) {
  return compute(test5, value);
}

83
Future<void> expectFileSuccessfullyCompletes(String filename) async {
84 85 86 87 88 89
  // Run a Dart script that calls compute().
  // The Dart process will terminate only if the script exits cleanly with
  // all isolate ports closed.
  const FileSystem fs = LocalFileSystem();
  const Platform platform = LocalPlatform();
  final String flutterRoot = platform.environment['FLUTTER_ROOT']!;
90 91
  final String dartPath =
      fs.path.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', 'dart');
92
  final String packageRoot = fs.path.dirname(fs.path.fromUri(platform.script));
93 94
  final String scriptPath =
      fs.path.join(packageRoot, 'test', 'foundation', filename);
95 96

  // Enable asserts to also catch potentially invalid assertions.
97
  final ProcessResult result = await Process.run(
98
      dartPath, <String>['run', '--enable-asserts', scriptPath]);
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
  expect(result.exitCode, 0);
}

class ComputeTestSubject {
  ComputeTestSubject(this.base, [this.additional]);

  final int base;
  final dynamic additional;

  int method(int x) {
    return base * x;
  }

  static int staticMethod(int square) {
    return square * square;
  }
}

Future<int> computeStaticMethod(int square) {
  return compute(ComputeTestSubject.staticMethod, square);
}

Future<int> computeClosure(int square) {
  return compute((_) => square * square, null);
}

Future<int> computeInvalidClosure(int square) {
  final ReceivePort r = ReceivePort();

  return compute((_) {
    r.sendPort.send('Computing!');

    return square * square;
  }, null);
}

Future<int> computeInstanceMethod(int square) {
  final ComputeTestSubject subject = ComputeTestSubject(square);
  return compute(subject.method, square);
}

Future<int> computeInvalidInstanceMethod(int square) {
  final ComputeTestSubject subject = ComputeTestSubject(square, ReceivePort());
  return compute(subject.method, square);
}

dynamic testInvalidResponse(int square) {
  final ReceivePort r = ReceivePort();
  try {
    return r;
  } finally {
    r.close();
  }
}

dynamic testInvalidError(int square) {
  final ReceivePort r = ReceivePort();
  try {
    throw r;
  } finally {
    r.close();
  }
}

String? testDebugName(_) {
  return Isolate.current.debugName;
}

167 168 169 170
int? testReturnNull(_) {
  return null;
}

171 172 173
void main() {
  test('compute()', () async {
    expect(await compute(test1, 0), 1);
174 175 176 177
    expect(compute(test2, 0), throwsA(2));
    expect(compute(test3, 0), throwsRemoteError);
    expect(await compute(test4, 0), 1);
    expect(compute(test5, 0), throwsRemoteError);
178 179

    expect(await compute(test1Async, 0), 1);
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
    expect(compute(test2Async, 0), throwsA(2));
    expect(compute(test3Async, 0), throwsRemoteError);
    expect(await compute(test4Async, 0), 1);
    expect(compute(test5Async, 0), throwsRemoteError);

    expect(await compute(test1CallCompute, 0), 1);
    expect(compute(test2CallCompute, 0), throwsA(2));
    expect(compute(test3CallCompute, 0), throwsRemoteError);
    expect(await compute(test4CallCompute, 0), 1);
    expect(compute(test5CallCompute, 0), throwsRemoteError);

    expect(compute(testInvalidResponse, 0), throwsRemoteError);
    expect(compute(testInvalidError, 0), throwsRemoteError);

    expect(await computeStaticMethod(10), 100);
    expect(await computeClosure(10), 100);
    expect(computeInvalidClosure(10), throwsArgumentError);
    expect(await computeInstanceMethod(10), 100);
    expect(computeInvalidInstanceMethod(10), throwsArgumentError);

200 201
    expect(await compute(testDebugName, null, debugLabel: 'debug_name'),
        'debug_name');
202
    expect(await compute(testReturnNull, null), null);
203
  }, skip: kIsWeb); // [intended] isn't supported on the web.
204

205
  group('compute() closes all ports', () {
206
    test('with valid message', () async {
207
      await expectFileSuccessfullyCompletes('_compute_caller.dart');
208 209
    });
    test('with invalid message', () async {
210 211
      await expectFileSuccessfullyCompletes(
          '_compute_caller_invalid_message.dart');
212 213
    });
    test('with valid error', () async {
214
      await expectFileSuccessfullyCompletes('_compute_caller.dart');
215 216
    });
    test('with invalid error', () async {
217 218
      await expectFileSuccessfullyCompletes(
          '_compute_caller_invalid_message.dart');
219 220
    });
  }, skip: kIsWeb); // [intended] isn't supported on the web.
221
}