blob: 3f2cbaf4319e9b2b75e05223753100127610d20a [file] [log] [blame]
// 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.
// ignore_for_file: avoid_print
import 'dart:async';
import 'dart:isolate';
import 'dart:typed_data';
import 'dart:ui';
import 'split_lib_test.dart' deferred as splitlib;
void main() {}
@pragma('vm:entry-point')
void sayHi() {
print('Hi');
}
@pragma('vm:entry-point')
void throwExceptionNow() {
throw AssertionError('Hello');
}
@pragma('vm:entry-point')
Future<void> canRegisterNativeCallback() async {
print('In function canRegisterNativeCallback');
notifyNative();
print('Called native method from canRegisterNativeCallback');
}
Future<void>? splitLoadFuture;
@pragma('vm:entry-point')
void canCallDeferredLibrary() {
print('In function canCallDeferredLibrary');
splitLoadFuture = splitlib
.loadLibrary()
.then((_) {
print('Deferred load complete');
notifySuccess(splitlib.splitAdd(10, 23) == 33);
})
.catchError((_) {
print('Deferred load error');
notifySuccess(false);
});
notifyNative();
}
@pragma('vm:external-name', 'NotifyNative')
external void notifyNative();
@pragma('vm:entry-point')
void testIsolateShutdown() {}
@pragma('vm:external-name', 'NotifyNative')
external void notifyResult(bool success);
@pragma('vm:external-name', 'PassMessage')
external void passMessage(String message);
void secondaryIsolateMain(String message) {
print('Secondary isolate got message: $message');
passMessage('Hello from code is secondary isolate.');
notifyNative();
}
@pragma('vm:entry-point')
void testCanLaunchSecondaryIsolate() {
final onExit = RawReceivePort((_) {
notifyNative();
});
Isolate.spawn(secondaryIsolateMain, 'Hello from root isolate.', onExit: onExit.sendPort);
}
@pragma('vm:entry-point')
Future<void> testIsolateStartupFailure() async {
Future<void> mainTest(void _) async {
Future<void> testSuccessfullIsolateLaunch() async {
final onMessage = ReceivePort();
final onExit = ReceivePort();
final messages = StreamIterator<dynamic>(onMessage);
final exits = StreamIterator<dynamic>(onExit);
await Isolate.spawn(
(SendPort port) => port.send('good'),
onMessage.sendPort,
onExit: onExit.sendPort,
);
if (!await messages.moveNext()) {
throw AssertionError('Failed to receive message');
}
if (messages.current != 'good') {
throw AssertionError('Failed to receive correct message');
}
if (!await exits.moveNext()) {
throw AssertionError('Failed to receive onExit');
}
messages.cancel();
exits.cancel();
}
Future<void> testUnsuccessfullIsolateLaunch() async {
IsolateSpawnException? error;
try {
await Isolate.spawn((_) {}, null);
} on IsolateSpawnException catch (e) {
error = e;
}
if (error == null) {
throw AssertionError('Expected isolate spawn to fail.');
}
}
await testSuccessfullIsolateLaunch();
makeNextIsolateSpawnFail();
await testUnsuccessfullIsolateLaunch();
notifyNative();
}
// The root isolate will not run an eventloop, so we have to run the actual
// test in an isolate.
Isolate.spawn(mainTest, null);
}
@pragma('vm:external-name', 'MakeNextIsolateSpawnFail')
external void makeNextIsolateSpawnFail();
@pragma('vm:entry-point')
void testCanReceiveArguments(List<String> args) {
notifyResult(args.length == 1 && args[0] == 'arg1');
}
@pragma('vm:entry-point')
void trampoline() {
notifyNative();
}
@pragma('vm:external-name', 'NotifySuccess')
external void notifySuccess(bool success);
@pragma('vm:entry-point')
void testCanConvertEmptyList(List<int> args) {
notifySuccess(args.isEmpty);
}
@pragma('vm:entry-point')
void testCanConvertListOfStrings(List<String> args) {
notifySuccess(
args.length == 4 &&
args[0] == 'tinker' &&
args[1] == 'tailor' &&
args[2] == 'soldier' &&
args[3] == 'sailor',
);
}
@pragma('vm:entry-point')
void testCanConvertListOfDoubles(List<double> args) {
notifySuccess(
args.length == 4 && args[0] == 1.0 && args[1] == 2.0 && args[2] == 3.0 && args[3] == 4.0,
);
}
@pragma('vm:entry-point')
void testCanConvertListOfInts(List<int> args) {
notifySuccess(args.length == 4 && args[0] == 1 && args[1] == 2 && args[2] == 3 && args[3] == 4);
}
bool didCallRegistrantBeforeEntrypoint = false;
// Test the Dart plugin registrant.
@pragma('vm:entry-point')
class _PluginRegistrant {
@pragma('vm:entry-point')
static void register() {
if (didCallRegistrantBeforeEntrypoint) {
throw AssertionError('_registerPlugins is being called twice');
}
didCallRegistrantBeforeEntrypoint = true;
}
}
@pragma('vm:entry-point')
void mainForPluginRegistrantTest() {
if (didCallRegistrantBeforeEntrypoint) {
passMessage('_PluginRegistrant.register() was called');
} else {
passMessage('_PluginRegistrant.register() was not called');
}
}
@pragma('vm:entry-point')
void mainForPlatformIsolates() {
passMessage('Platform isolate is ready');
}
@pragma('vm:entry-point')
void emptyMain(List<Object?> args) {}
@pragma('vm:entry-point')
Function createEntryPointForPlatIsoSendAndRecvTest() {
final port = RawReceivePort();
port.handler = (Object? message) {
port.close();
(message! as SendPort).send('Hello from root isolate!');
};
final SendPort sendPort = port.sendPort;
return () {
final replyPort = RawReceivePort();
replyPort.handler = (Object? message) {
replyPort.close();
passMessage('Platform isolate received: $message');
};
sendPort.send(replyPort.sendPort);
};
}
@pragma('vm:entry-point')
void mainForPlatformIsolatesThrowError() {
throw AssertionError('Error from platform isolate');
}
@pragma('vm:entry-point')
void sendSemanticsUpdate() {
final builder = SemanticsUpdateBuilder();
const identifier = 'identifier';
const label = 'label';
final labelAttributes = <StringAttribute>[
SpellOutStringAttribute(range: const TextRange(start: 1, end: 2)),
];
const value = 'value';
final valueAttributes = <StringAttribute>[
SpellOutStringAttribute(range: const TextRange(start: 2, end: 3)),
];
const increasedValue = 'increasedValue';
final increasedValueAttributes = <StringAttribute>[
SpellOutStringAttribute(range: const TextRange(start: 4, end: 5)),
];
const decreasedValue = 'decreasedValue';
final decreasedValueAttributes = <StringAttribute>[
SpellOutStringAttribute(range: const TextRange(start: 5, end: 6)),
];
const hint = 'hint';
final hintAttributes = <StringAttribute>[
LocaleStringAttribute(
locale: const Locale('en', 'MX'),
range: const TextRange(start: 0, end: 1),
),
];
const tooltip = 'tooltip';
final transform = Float64List(16);
final childrenInTraversalOrder = Int32List(0);
final childrenInHitTestOrder = Int32List(0);
final additionalActions = Int32List(0);
transform[0] = 1;
transform[1] = 0;
transform[2] = 0;
transform[3] = 0;
transform[4] = 0;
transform[5] = 1;
transform[6] = 0;
transform[7] = 0;
transform[8] = 0;
transform[9] = 0;
transform[10] = 1;
transform[11] = 0;
transform[12] = 0;
transform[13] = 0;
transform[14] = 0;
transform[15] = 0;
builder.updateNode(
id: 0,
flags: SemanticsFlags(),
actions: 0,
maxValueLength: 0,
currentValueLength: 0,
textSelectionBase: -1,
textSelectionExtent: -1,
platformViewId: -1,
scrollChildren: 0,
scrollIndex: 0,
traversalParent: 0,
scrollPosition: 0,
scrollExtentMax: 0,
scrollExtentMin: 0,
rect: const Rect.fromLTRB(0, 0, 10, 10),
identifier: identifier,
label: label,
labelAttributes: labelAttributes,
value: value,
valueAttributes: valueAttributes,
increasedValue: increasedValue,
increasedValueAttributes: increasedValueAttributes,
decreasedValue: decreasedValue,
decreasedValueAttributes: decreasedValueAttributes,
hint: hint,
hintAttributes: hintAttributes,
tooltip: tooltip,
textDirection: TextDirection.ltr,
transform: transform,
hitTestTransform: transform,
childrenInTraversalOrder: childrenInTraversalOrder,
childrenInHitTestOrder: childrenInHitTestOrder,
additionalActions: additionalActions,
controlsNodes: null,
inputType: SemanticsInputType.none,
locale: null,
minValue: '0',
maxValue: '0',
);
_semanticsUpdate(builder.build());
}
@pragma('vm:external-name', 'SemanticsUpdate')
external void _semanticsUpdate(SemanticsUpdate update);