// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// Dart test program for testing dart:ffi async callbacks.
//
// VMOptions=
// VMOptions=--stacktrace-every=100
// VMOptions=--use-slow-path
// VMOptions=--use-slow-path --stacktrace-every=100
// VMOptions=--dwarf_stack_traces --no-retain_function_objects --no-retain_code_objects
// VMOptions=--test_il_serialization
// VMOptions=--profiler --profile_vm=true
// VMOptions=--profiler --profile_vm=false
// SharedObjects=ffi_test_functions

import 'dart:async';
import 'dart:ffi';
import 'dart:isolate';

import "package:expect/expect.dart";

import 'dylib_utils.dart';

main(args, message) async {
  testNativeCallableStatic();
  testNativeCallableClosure();
  testNativeCallableDoubleCloseError();
  testNativeCallableNestedCloseCallStatic();
  testNativeCallableNestedCloseCallClosure();
  testNativeCallableExceptionalReturnStatic();
  testNativeCallableExceptionalReturnClosure();
  await testNativeCallableDontKeepAliveStatic();
  await testNativeCallableDontKeepAliveClosure();
  testNativeCallableKeepAliveGetter();
  print("All tests completed :)");
}

final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");

typedef TwoIntFnNativeType = Int32 Function(Pointer, Int32, Int32);
typedef TwoIntFnType = int Function(Pointer, int, int);
final callTwoIntFunction = ffiTestFunctions
    .lookupFunction<TwoIntFnNativeType, TwoIntFnType>("CallTwoIntFunction");

typedef CallbackNativeType = Int32 Function(Int32, Int32);
int add(int a, int b) {
  return a + b;
}

testNativeCallableStatic() {
  final callback = NativeCallable<CallbackNativeType>.isolateLocal(
    add,
    exceptionalReturn: 0,
  );

  Expect.equals(1234, callTwoIntFunction(callback.nativeFunction, 1000, 234));

  callback.close();
}

testNativeCallableClosure() {
  int c = 70000;

  final callback = NativeCallable<CallbackNativeType>.isolateLocal(
    (int a, int b) => a + b + c,
    exceptionalReturn: 0,
  );

  Expect.equals(71234, callTwoIntFunction(callback.nativeFunction, 1000, 234));

  c = 80000;
  Expect.equals(81234, callTwoIntFunction(callback.nativeFunction, 1000, 234));

  callback.close();
}

testNativeCallableDoubleCloseError() {
  final callback = NativeCallable<CallbackNativeType>.isolateLocal(
    add,
    exceptionalReturn: 0,
  );
  Expect.notEquals(nullptr, callback.nativeFunction);
  callback.close();

  Expect.throwsStateError(() {
    final _ = callback.nativeFunction;
  });

  // Expect that these do not throw.
  callback.close();
  callback.keepIsolateAlive = true;
  Expect.isFalse(callback.keepIsolateAlive);
}

late NativeCallable selfClosingStaticCallback;
int selfClosingStatic(int a, int b) {
  selfClosingStaticCallback.close();
  return a + b;
}

testNativeCallableNestedCloseCallStatic() {
  selfClosingStaticCallback = NativeCallable<CallbackNativeType>.isolateLocal(
    selfClosingStatic,
    exceptionalReturn: 0,
  );

  Expect.equals(
    1234,
    callTwoIntFunction(selfClosingStaticCallback.nativeFunction, 1000, 234),
  );

  // The callback is already closed.
  Expect.throwsStateError(() {
    final _ = selfClosingStaticCallback.nativeFunction;
  });
}

testNativeCallableNestedCloseCallClosure() {
  late NativeCallable callback;

  callback = NativeCallable<CallbackNativeType>.isolateLocal((int a, int b) {
    callback.close();
    return a + b;
  }, exceptionalReturn: 0);

  Expect.equals(1234, callTwoIntFunction(callback.nativeFunction, 1000, 234));

  // The callback is already closed.
  Expect.throwsStateError(() {
    final _ = callback.nativeFunction;
  });
}

int throwerCallback(int a, int b) {
  if (a != 1000) {
    throw "Oh no!";
  }
  return a + b;
}

testNativeCallableExceptionalReturnStatic() {
  final callback = NativeCallable<CallbackNativeType>.isolateLocal(
    throwerCallback,
    exceptionalReturn: 5678,
  );

  Expect.equals(1234, callTwoIntFunction(callback.nativeFunction, 1000, 234));
  Expect.equals(5678, callTwoIntFunction(callback.nativeFunction, 0, 0));

  callback.close();
}

testNativeCallableExceptionalReturnClosure() {
  final callback = NativeCallable<CallbackNativeType>.isolateLocal((
    int a,
    int b,
  ) {
    if (a != 1000) {
      throw "Oh no!";
    }
    return a + b;
  }, exceptionalReturn: 5678);

  Expect.equals(1234, callTwoIntFunction(callback.nativeFunction, 1000, 234));
  Expect.equals(5678, callTwoIntFunction(callback.nativeFunction, 0, 0));

  callback.close();
}

Future<void> testNativeCallableDontKeepAliveStatic() async {
  final exitPort = ReceivePort();
  await Isolate.spawn(
    (_) async {
      final callback = NativeCallable<CallbackNativeType>.isolateLocal(
        add,
        exceptionalReturn: 0,
      );

      Expect.equals(
        1234,
        callTwoIntFunction(callback.nativeFunction, 1000, 234),
      );

      callback.keepIsolateAlive = false;
    },
    null,
    onExit: exitPort.sendPort,
  );
  await exitPort.first;
  exitPort.close();
}

Future<void> testNativeCallableDontKeepAliveClosure() async {
  int c = 70000;

  final exitPort = ReceivePort();
  await Isolate.spawn(
    (_) async {
      final callback = NativeCallable<CallbackNativeType>.isolateLocal(
        (int a, int b) => a + b + c,
        exceptionalReturn: 0,
      );

      Expect.equals(
        71234,
        callTwoIntFunction(callback.nativeFunction, 1000, 234),
      );

      callback.keepIsolateAlive = false;
    },
    null,
    onExit: exitPort.sendPort,
  );
  await exitPort.first;
  exitPort.close();
}

testNativeCallableKeepAliveGetter() {
  final callback = NativeCallable<CallbackNativeType>.isolateLocal(
    add,
    exceptionalReturn: 0,
  );
  // Check that only the flag changes are counted by decrementing and
  // incrementing a lot, and by different amounts.
  for (int i = 0; i < 100; ++i) {
    callback.keepIsolateAlive = false;
    Expect.isFalse(callback.keepIsolateAlive);
  }
  for (int i = 0; i < 200; ++i) {
    callback.keepIsolateAlive = true;
    Expect.isTrue(callback.keepIsolateAlive);
  }
  callback.close();
}
