// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// @dart = 2.8

import 'package:file/file.dart';
import 'package:matcher/matcher.dart';
import 'package:vm_service/vm_service.dart';

import '../integration.shard/test_data/basic_project.dart';
import '../integration.shard/test_data/tests_project.dart';
import '../integration.shard/test_driver.dart';
import '../integration.shard/test_utils.dart';
import '../src/common.dart';

void batch1() {
  final BasicProject _project = BasicProject();
  Directory tempDir;
  FlutterRunTestDriver _flutter;

  Future<void> initProject() async {
    tempDir = createResolvedTempDirectorySync('run_expression_eval_test.');
    await _project.setUpIn(tempDir);
    _flutter = FlutterRunTestDriver(tempDir);
  }

  Future<void> cleanProject() async {
    await _flutter.stop();
    tryToDelete(tempDir);
  }

  Future<void> start({bool expressionEvaluation}) {
    // The non-test project has a loop around its breakpoints.
    // No need to start paused as all breakpoint would be eventually reached.
    return  _flutter.run(
      withDebugger: true, chrome: true,
      expressionEvaluation: expressionEvaluation,
      additionalCommandArgs: <String>['--verbose']);
  }

  Future<void> breakInBuildMethod(FlutterTestDriver flutter) async {
    await _flutter.breakAt(
      _project.buildMethodBreakpointUri,
      _project.buildMethodBreakpointLine,
    );
  }

  Future<void> breakInTopLevelFunction(FlutterTestDriver flutter) async {
    await _flutter.breakAt(
      _project.topLevelFunctionBreakpointUri,
      _project.topLevelFunctionBreakpointLine,
    );
  }

  testWithoutContext('flutter run expression evaluation - error if expression evaluation disabled', () async {
    await initProject();
    await start(expressionEvaluation: false);
    await breakInTopLevelFunction(_flutter);
    await failToEvaluateExpression(_flutter);
    await cleanProject();
  });

 testWithoutContext('flutter run expression evaluation - no native javascript objects in static scope', () async {
    await initProject();
    await start(expressionEvaluation: true);
    await breakInTopLevelFunction(_flutter);
    await checkStaticScope(_flutter);
    await cleanProject();
  });

  testWithoutContext('flutter run expression evaluation - can handle compilation errors', () async {
    await initProject();
    await start(expressionEvaluation: true);
    await breakInTopLevelFunction(_flutter);
    await evaluateErrorExpressions(_flutter);
    await cleanProject();
  });

  testWithoutContext('flutter run expression evaluation - can evaluate trivial expressions in top level function', () async {
    await initProject();
    await start(expressionEvaluation: true);
    await breakInTopLevelFunction(_flutter);
    await evaluateTrivialExpressions(_flutter);
    await cleanProject();
  });

  testWithoutContext('flutter run expression evaluation - can evaluate trivial expressions in build method', () async {
    await initProject();
    await start(expressionEvaluation: true);
    await breakInBuildMethod(_flutter);
    await evaluateTrivialExpressions(_flutter);
    await cleanProject();
  });

  testWithoutContext('flutter run expression evaluation - can evaluate complex expressions in top level function', () async {
    await initProject();
    await start(expressionEvaluation: true);
    await breakInTopLevelFunction(_flutter);
    await evaluateComplexExpressions(_flutter);
    await cleanProject();
  });

  testWithoutContext('flutter run expression evaluation - can evaluate complex expressions in build method', () async {
    await initProject();
    await _flutter.run(withDebugger: true, chrome: true);
    await breakInBuildMethod(_flutter);
    await evaluateComplexExpressions(_flutter);
    await cleanProject();
  });
}

void batch2() {
  final TestsProject _project = TestsProject();
  Directory tempDir;
  FlutterRunTestDriver _flutter;

  Future<void> initProject() async {
    tempDir = createResolvedTempDirectorySync('test_expression_eval_test.');
    await _project.setUpIn(tempDir);
    _flutter = FlutterRunTestDriver(tempDir);
  }

  Future<void> cleanProject() async {
    await _flutter.stop();
    tryToDelete(tempDir);
  }

  Future<void> breakInMethod(FlutterTestDriver flutter) async {
    await _flutter.addBreakpoint(
      _project.breakpointAppUri,
      _project.breakpointLine,
    );
    await _flutter.resume();
    await _flutter.waitForPause();
  }

  Future<void> startPaused({bool expressionEvaluation}) {
    // The test project does not have a loop around its breakpoints.
    // Start paused so we can set a breakpoint before passing it
    // in the execution.
    return  _flutter.run(
      withDebugger: true, chrome: true,
      expressionEvaluation: expressionEvaluation,
      startPaused: true, script: _project.testFilePath,
      additionalCommandArgs: <String>['--verbose']);
  }

  testWithoutContext('flutter test expression evaluation - error if expression evaluation disabled', () async {
    await initProject();
    await startPaused(expressionEvaluation: false);
    await breakInMethod(_flutter);
    await failToEvaluateExpression(_flutter);
    await cleanProject();
  });

  testWithoutContext('flutter test expression evaluation - can evaluate trivial expressions in a test', () async {
    await initProject();
    await startPaused(expressionEvaluation: true);
    await breakInMethod(_flutter);
    await evaluateTrivialExpressions(_flutter);
    await cleanProject();
  });

  testWithoutContext('flutter test expression evaluation - can evaluate complex expressions in a test', () async {
    await initProject();
    await startPaused(expressionEvaluation: true);
    await breakInMethod(_flutter);
    await evaluateComplexExpressions(_flutter);
    await cleanProject();
  }, skip: 'https://github.com/dart-lang/sdk/issues/41480');
}

Future<void> failToEvaluateExpression(FlutterTestDriver flutter) async {
  ObjRef res;
  try {
    res = await flutter.evaluateInFrame('"test"');
  } on RPCError catch (e) {
    expect(e.message, contains('Expression evaluation is not supported for this configuration'));
  }
  expect(res, null);
}

Future<void> checkStaticScope(FlutterTestDriver flutter) async {
  final Frame res = await flutter.getTopStackFrame();
  expect(res.vars, equals(<BoundVariable>[]));
}

Future<void> evaluateErrorExpressions(FlutterTestDriver flutter) async {
  final ObjRef res = await flutter.evaluateInFrame('typo');
  expectError(res, 'CompilationError: Getter not found: \'typo\'.\ntypo\n^^^^');
}

Future<void> evaluateTrivialExpressions(FlutterTestDriver flutter) async {
  ObjRef res;

  res = await flutter.evaluateInFrame('"test"');
  expectInstance(res, InstanceKind.kString, 'test');

  res = await flutter.evaluateInFrame('1');
  expectInstance(res, InstanceKind.kDouble, 1.toString());

  res = await flutter.evaluateInFrame('true');
  expectInstance(res, InstanceKind.kBool, true.toString());
}

Future<void> evaluateComplexExpressions(FlutterTestDriver flutter) async {
  final ObjRef res = await flutter.evaluateInFrame('new DateTime.now().year');
  expectInstance(res, InstanceKind.kDouble, DateTime.now().year.toString());
}

void expectInstance(ObjRef result, String kind, String message) {
  expect(result,
    const TypeMatcher<InstanceRef>()
      .having((InstanceRef instance) => instance.kind, 'kind', kind)
      .having((InstanceRef instance) => instance.valueAsString, 'valueAsString', message));
}

void expectError(ObjRef result, String message) {
  expect(result,
    const TypeMatcher<ErrorRef>()
      .having((ErrorRef instance) => instance.message, 'message', message));
}

void main() {
  batch1();
  batch2();
}
