// Copyright (c) 2021, 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.

// VMOptions=--enable-isolate-groups --no-enable-fast-object-copy
// VMOptions=--enable-isolate-groups --enable-fast-object-copy
// VMOptions=--enable-isolate-groups --no-enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation
// VMOptions=--enable-isolate-groups --enable-fast-object-copy --gc-on-foc-slow-path --force-evacuation

// The tests in this file will only succeed when isolate groups are enabled
// (hence the VMOptions above).

// @dart = 2.9

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

import 'package:expect/expect.dart';

import 'fast_object_copy_test.dart' show ClassWithNativeFields;

class HashThrower {
  static bool throwOnHashCode = true;

  const HashThrower();

  int get hashCode => throwOnHashCode ? throw 'failing' : 2;
  bool operator ==(other) => identical(this, other);
}

Future testWithClosure<T>(
    void Function(SendPort) entrypoint, T expectedResult) async {
  final rp = ReceivePort();
  try {
    await Isolate.spawn(entrypoint, rp.sendPort);
    Expect.equals(expectedResult, await rp.first);
  } finally {
    rp.close();
  }
}

class ClosureEntrypointTester {
  int instanceValue = 42;

  void send42(SendPort sendPort) => sendPort.send(42);

  Future run() async {
    await noCapturedVariablesTest();
    await capturedInt();
    await capturedInstanceInt();
    await captureThisViaMethodTearOff();
    await captureInvalidObject();
    await captureRehashThrower();
  }

  Future noCapturedVariablesTest() async {
    print('noCapturedVariablesTest');
    await testWithClosure((SendPort s) => s.send(42), 42);
  }

  Future capturedInt() async {
    print('capturedInt');
    int value = 42;
    await testWithClosure((SendPort s) => s.send(value), 42);
  }

  Future capturedInstanceInt() async {
    print('capturedInstanceValue');
    await testWithClosure((SendPort s) => s.send(this.instanceValue), 42);
  }

  Future captureThisViaMethodTearOff() async {
    print('captureThisViaMethodTearOff');
    await testWithClosure(send42, 42);
  }

  Future captureInvalidObject() async {
    print('captureInvalidObject');
    final invalidObject = ClassWithNativeFields();
    send42(SendPort sendPort) {
      '$invalidObject'; // Use an object that cannot be copied.
      sendPort.send(42);
    }

    throwsAsync<ArgumentError>(() => testWithClosure(send42, 42));
  }

  Future captureRehashThrower() async {
    print('captureRehashThrower');
    HashThrower.throwOnHashCode = false;
    final hashThrower = {HashThrower()};
    send42(SendPort sendPort) {
      '$hashThrower'; // Use an object that cannot be deserialized.
      sendPort.send(42);
    }

    throwsAsync<IsolateSpawnException>(() => testWithClosure(send42, 42));
  }

  Future throwsAsync<T>(Future Function() fun) async {
    try {
      await fun();
    } catch (e) {
      if (e is T) return;
      rethrow;
    }
    throw 'Function failed to throw ArgumentError';
  }
}

main() async {
  await ClosureEntrypointTester().run();
}
