// 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.

// SharedOptions=--enable-experiment=dot-shorthands
// @dart = 3.9

import 'dart:developer';

import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';

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

const String shortFile = 'dot_shorthands_test.dart';

// AUTOGENERATED START
//
// Update these constants by running:
//
// dart pkg/vm_service/test/update_line_numbers.dart pkg/vm_service/test/dot_shorthands_test.dart
//
const LINE_A = 34;
const LINE_B = 37;
const LINE_C = 38;
const LINE_D = 45;
const LINE_E = 47;
const LINE_F = 49;
// AUTOGENERATED END

class C {
  int value;
  C(this.value); // LINE_A

  static C two = C(2);
  static C get three => C(3); // LINE_B
  static C four() => C(4); // LINE_C
}

void testeeMain() {
  C c = C(1);
  debugger();
  // ignore: experiment_not_enabled
  c = .two; // LINE_D
  // ignore: experiment_not_enabled
  c = .three; // LINE_E
  // ignore: experiment_not_enabled
  c = .four(); // LINE_F
  print(c.value);
}

List<String> stops = [];

const List<String> expected = [
  '$shortFile:$LINE_D:7', // on '.'
  '$shortFile:$LINE_E:7', // on '.'
  '$shortFile:$LINE_B:22', // on '=' of '=>'
  '$shortFile:$LINE_B:25', // on 'C'
  '$shortFile:$LINE_A:10', // on 'v' of 'value'
  '$shortFile:$LINE_A:16', // on ';'
  '$shortFile:$LINE_B:25', // on 'C'
  '$shortFile:$LINE_F:7', // on '.'
  '$shortFile:$LINE_C:16', // on '('
  '$shortFile:$LINE_C:22', // on 'C'
  '$shortFile:$LINE_A:10', // on 'v' of 'value'
  '$shortFile:$LINE_A:16', // on ';'
  '$shortFile:$LINE_C:22', // on 'C'
];

final tests = <IsolateTest>[
  hasStoppedAtBreakpoint,

  // Test interaction of expression evaluation with dot shorthands.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;

    InstanceRef response =
        await service.evaluateInFrame(isolateId, 0, '(c = .two).value')
            as InstanceRef;
    expect(response.valueAsString, '2');

    response =
        await service.evaluateInFrame(isolateId, 0, '(c = .three).value')
            as InstanceRef;
    expect(response.valueAsString, '3');

    response =
        await service.evaluateInFrame(isolateId, 0, '(c = .four()).value')
            as InstanceRef;
    expect(response.valueAsString, '4');
  },

  // Test interaction of breakpoints with dot shorthands.
  (VmService service, IsolateRef isolateRef) async {
    final isolateId = isolateRef.id!;
    final isolate = await service.getIsolate(isolateId);
    final lib =
        (await service.getObject(isolateId, isolate.rootLib!.id!)) as Library;
    final scriptId = lib.scripts!.first.id!;

    Breakpoint breakpoint = await service.addBreakpoint(
      isolateId,
      scriptId,
      LINE_D,
    );
    var (_, (line, column)) = await breakpoint.getLocation(service, isolateRef);
    expect(breakpoint.enabled, true);
    expect(line, LINE_D);
    expect(column, 7); // on '.'

    breakpoint = await service.addBreakpoint(isolateId, scriptId, LINE_E);
    (_, (line, column)) = await breakpoint.getLocation(service, isolateRef);
    expect(breakpoint.enabled, true);
    expect(line, LINE_E);
    expect(column, 7); // on '.'
    await service.removeBreakpoint(isolateId, breakpoint.id!);

    breakpoint = await service.addBreakpoint(isolateId, scriptId, LINE_F);
    (_, (line, column)) = await breakpoint.getLocation(service, isolateRef);
    expect(breakpoint.enabled, true);
    expect(line, LINE_F);
    expect(column, 7); // on '.'
    await service.removeBreakpoint(isolateId, breakpoint.id!);
  },

  // Test interaction of single-stepping with dot shorthands.
  runStepIntoThroughProgramRecordingStops(stops),
  checkRecordedStops(stops, expected),
];

void main([args = const <String>[]]) => runIsolateTests(
  args,
  tests,
  'dot_shorthands_test.dart',
  pauseOnExit: true,
  testeeConcurrent: testeeMain,
);
