| // Copyright 2013 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:ffi'; |
| import 'dart:isolate'; |
| import 'dart:ui'; |
| |
| import 'package:ffi/ffi.dart'; |
| import 'package:test/test.dart'; |
| |
| // This import is used in a test, but not in a way that the analyzer can understand. |
| // ignore: unused_import |
| import 'spawn_helper.dart'; |
| |
| @Native<Handle Function(Pointer<Utf8>)>(symbol: 'LoadLibraryFromKernel') |
| external Object _loadLibraryFromKernel(Pointer<Utf8> path); |
| |
| @Native<Handle Function(Pointer<Utf8>, Pointer<Utf8>)>(symbol: 'LookupEntryPoint') |
| external Object _lookupEntryPoint(Pointer<Utf8> library, Pointer<Utf8> name); |
| |
| @Native<Void Function(Pointer<Utf8>, Pointer<Utf8>)>(symbol: 'Spawn') |
| external void _spawn(Pointer<Utf8> entrypoint, Pointer<Utf8> route); |
| |
| void spawn({required SendPort port, String entrypoint = 'main', String route = '/'}) { |
| assert( |
| entrypoint != 'main' || route != '/', |
| 'Spawn should not be used to spawn main with the default route name', |
| ); |
| IsolateNameServer.registerPortWithName(port, route); |
| final Pointer<Utf8> nativeEntrypoint = entrypoint.toNativeUtf8(); |
| final Pointer<Utf8> nativeRoute = route.toNativeUtf8(); |
| _spawn(nativeEntrypoint, nativeRoute); |
| malloc.free(nativeEntrypoint); |
| malloc.free(nativeRoute); |
| } |
| |
| const String kTestEntrypointRouteName = 'testEntrypoint'; |
| |
| @pragma('vm:entry-point') |
| void testEntrypoint() { |
| IsolateNameServer.lookupPortByName( |
| kTestEntrypointRouteName, |
| )!.send(PlatformDispatcher.instance.defaultRouteName); |
| } |
| |
| void main() { |
| const bool kReleaseMode = bool.fromEnvironment('dart.vm.product'); |
| const bool kProfileMode = bool.fromEnvironment('dart.vm.profile'); |
| |
| test('Spawn a different entrypoint with a special route name', () async { |
| final ReceivePort port = ReceivePort(); |
| spawn(port: port.sendPort, entrypoint: 'testEntrypoint', route: kTestEntrypointRouteName); |
| expect(await port.first, kTestEntrypointRouteName); |
| port.close(); |
| }); |
| |
| test('Lookup entrypoint and execute', () { |
| final Pointer<Utf8> libraryPath = |
| 'file://${const String.fromEnvironment('kFlutterSrcDirectory')}/testing/dart/spawn_helper.dart' |
| .toNativeUtf8(); |
| final Pointer<Utf8> entryPoint = 'echoInt'.toNativeUtf8(); |
| expect((_lookupEntryPoint(libraryPath, entryPoint) as int Function(int))(42), 42); |
| malloc.free(libraryPath); |
| malloc.free(entryPoint); |
| }); |
| |
| test('Load from kernel', () { |
| final Pointer<Utf8> kernelPath = |
| '${const String.fromEnvironment('kFlutterBuildDirectory')}/spawn_helper.dart.dill' |
| .toNativeUtf8(); |
| expect(_loadLibraryFromKernel(kernelPath) is void Function(), true); |
| malloc.free(kernelPath); |
| |
| final Pointer<Utf8> fakePath = 'fake-path'.toNativeUtf8(); |
| expect(_loadLibraryFromKernel(fakePath), null); |
| malloc.free(fakePath); |
| }, skip: kProfileMode || kReleaseMode); // ignore: avoid_redundant_argument_values |
| } |