| // 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:litetest/litetest.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() { |
| expect(PlatformDispatcher.instance.defaultRouteName, kTestEntrypointRouteName); |
| IsolateNameServer.lookupPortByName(kTestEntrypointRouteName)!.send(null); |
| } |
| |
| 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, isNull); |
| 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 |
| } |