// Copyright (c) 2016, 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=--verbose_debug

import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
import 'service_test_common.dart';
import 'test_helper.dart';
import 'dart:developer';

testParameters(int jjjj, int oooo, [int hhhh, int nnnn]) {
  debugger();
}

testMain() {
  int xxx, yyyy, zzzzz;
  for (int i = 0; i < 1; i++) {
    var foo = () {};
    debugger();
  }
  var bar = () {
    print(xxx);
    print(yyyy);
    debugger();
  };
  bar();
  testParameters(0, 0);
}

var tests = <IsolateTest>[
  hasStoppedAtBreakpoint,
  stoppedInFunction('testMain'),
  (Isolate isolate) async {
    var stack = await isolate.getStack();
    expect(stack.type, equals('Stack'));
    expect(stack['frames'].length, greaterThanOrEqualTo(1));
    // Grab the top frame.
    Frame frame = stack['frames'][0];
    // Grab the script.
    Script script = frame.location.script;
    await script.load();

    // Ensure that the token at each declaration position is the name of the
    // variable.
    for (var variable in frame.variables) {
      final int declarationTokenPos = variable['declarationTokenPos'];
      final String name = variable['name'];
      final String token = script.getToken(declarationTokenPos);
      expect(name, token);
    }
  },
  resumeIsolate,
  hasStoppedAtBreakpoint,
  // We have stopped in the anonymous closure assigned to bar. Verify that
  // variables captured in the context have valid declaration positions.
  (Isolate isolate) async {
    var stack = await isolate.getStack();
    expect(stack.type, equals('Stack'));
    expect(stack['frames'].length, greaterThanOrEqualTo(1));
    // Grab the top frame.
    Frame frame = stack['frames'][0];
    // Grab the script.
    Script script = frame.location.script;
    await script.load();
    print(frame);
    expect(frame.variables.length, greaterThanOrEqualTo(1));
    for (var variable in frame.variables) {
      final int declarationTokenPos = variable['declarationTokenPos'];
      final String name = variable['name'];
      final String token = script.getToken(declarationTokenPos);
      expect(name, token);
    }
  },
  resumeIsolate,
  hasStoppedAtBreakpoint,
  stoppedInFunction('testParameters'),
  (Isolate isolate) async {
    var stack = await isolate.getStack();
    expect(stack.type, equals('Stack'));
    expect(stack['frames'].length, greaterThanOrEqualTo(1));
    // Grab the top frame.
    Frame frame = stack['frames'][0];
    // Grab the script.
    Script script = frame.location.script;
    await script.load();

    // Ensure that the token at each declaration position is the name of the
    // variable.
    expect(frame.variables.length, greaterThanOrEqualTo(1));
    for (var variable in frame.variables) {
      final int declarationTokenPos = variable['declarationTokenPos'];
      final String name = variable['name'];
      final String token = script.getToken(declarationTokenPos);
      expect(name, token);
    }
  }
];

main(args) => runIsolateTests(args, tests, testeeConcurrent: testMain);
