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

// Verifies that debugger correctly detects `catchError` even when it occurs
// without a value listener, as in `Future(...).catchError(...)`.
//
// Regression test for https://github.com/flutter/flutter/issues/141882.
import 'dart:async';

import 'package:vm_service/vm_service.dart';

import 'common/service_test_common.dart';
import 'common/test_helper.dart';

// AUTOGENERATED START
//
// Update these constants by running:
//
// dart pkg/vm_service/test/update_line_numbers.dart pkg/vm_service/test/pause_on_unhandled_async_exceptions5_test.dart
//
const LINE_A = 29;
const LINE_B = 33;
const LINE_C = 38;
// AUTOGENERATED END

Future<void> doThrowAsync() async {
  await null;
  throw 'Exception'; // LINE_A
}

Future<void> doThrowSync() async {
  throw 'Exception'; // LINE_B
}

Future<void> testeeMain() async {
  await testCatchErrorVariants();
  await doThrowAsync(); // LINE_C
}

Future<void> testCatchErrorVariants() async {
  await testCatchError(doThrowSync);
  await testCatchError(doThrowAsync);
  await testCatchError(() async {
    await doThrowSync();
  });
  await testCatchError(() async {
    await doThrowAsync();
  });
}

Future<void> testCatchError(void Function() f) async {
  await Future<void>(f).catchError((_) {});

  final c = Completer<void>();
  Future(f).catchError(c.completeError); // ignore:unawaited_futures
  try {
    await c.future;
  } catch (_) {}
}

var tests = <IsolateTest>[
  hasStoppedWithUnhandledException,
  stoppedAtLine(LINE_A),
  (VmService service, IsolateRef isolate) async {
    final stack = await service.getStack(isolate.id!);
    final frames = stack.asyncCausalFrames!;
    await expectFrame(
      service,
      isolate,
      frames[0],
      functionName: 'doThrowAsync',
      line: LINE_A,
    );
    await expectFrame(
      service,
      isolate,
      frames[1],
      kind: 'AsyncSuspensionMarker',
    );
    await expectFrame(
      service,
      isolate,
      frames[2],
      kind: 'AsyncCausal',
      functionName: 'testeeMain',
      line: LINE_C,
    );
  }
];

void main([args = const <String>[]]) => runIsolateTests(
      args,
      tests,
      'pause_on_unhandled_async_exceptions5_test.dart',
      pauseOnUnhandledExceptions: true,
      testeeConcurrent: testeeMain,
      extraArgs: extraDebuggingArgs,
    );
