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

import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import '../analysis_server_base.dart';

void main() {
  defineReflectiveSuite(() {
    defineReflectiveTests(GetErrorsTest);
  });
}

@reflectiveTest
class GetErrorsTest extends PubPackageAnalysisServerTest {
  static const String _requestId = 'test-getError';

  @override
  Future<void> setUp() async {
    super.setUp();
    await setRoots(included: [workspaceRootPath], excluded: []);
  }

  Future<void> test_afterAnalysisComplete() async {
    newFile(testFilePath, '''
void f() {
  print(42)
}
''');

    await waitForTasksFinished();

    var errors = await _getErrors(testFile.path);
    expect(errors, hasLength(1));
  }

  Future<void> test_errorInPart() async {
    var libraryFile = newFile('$testPackageLibPath/a.dart', r'''
part 'b.dart';
class A {}
''');

    var partFile = newFile('$testPackageLibPath/b.dart', r'''
part of 'a.dart';
class A {}
''');

    {
      var libErrors = await _getErrors(libraryFile.path);
      expect(libErrors, isEmpty);
    }
    {
      var partErrors = await _getErrors(partFile.path);
      expect(partErrors, hasLength(1));
    }
  }

  Future<void> test_fileWithoutContext() async {
    await setRoots(included: [], excluded: []);

    var request = _createGetErrorsRequest(testFile.path);
    var response = await serverChannel.simulateRequestFromClient(request);
    assertResponseFailure(
      response,
      requestId: _requestId,
      errorCode: RequestErrorCode.GET_ERRORS_INVALID_FILE,
    );
  }

  Future<void> test_hasErrors() async {
    newFile(testFilePath, '''
void f() {
  print(42)
}
''');

    var errors = await _getErrors(testFile.path);
    expect(errors, hasLength(1));
    {
      var error = errors[0];
      expect(error.severity, AnalysisErrorSeverity.ERROR);
      expect(error.type, AnalysisErrorType.SYNTACTIC_ERROR);
      expect(error.location.file, testFile.path);
      expect(error.location.startLine, 2);
    }
  }

  Future<void> test_invalidFilePathFormat_notAbsolute() async {
    var request = _createGetErrorsRequest('test.dart');
    var response = await handleRequest(request);
    assertResponseFailure(
      response,
      requestId: _requestId,
      errorCode: RequestErrorCode.INVALID_FILE_PATH_FORMAT,
    );
  }

  Future<void> test_invalidFilePathFormat_notNormalized() async {
    var request = _createGetErrorsRequest(convertPath('/foo/../bar/test.dart'));
    var response = await handleRequest(request);
    assertResponseFailure(
      response,
      requestId: _requestId,
      errorCode: RequestErrorCode.INVALID_FILE_PATH_FORMAT,
    );
  }

  Future<void> test_noErrors() async {
    newFile(testFilePath, '''
void f() {
  print(42);
}
''');

    var errors = await _getErrors(testFile.path);
    expect(errors, isEmpty);
  }

  Request _createGetErrorsRequest(String path) {
    return AnalysisGetErrorsParams(
      path,
    ).toRequest(_requestId, clientUriConverter: server.uriConverter);
  }

  Future<List<AnalysisError>> _getErrors(String path) async {
    var request = _createGetErrorsRequest(path);
    var response = await handleSuccessfulRequest(request);
    return AnalysisGetErrorsResult.fromResponse(
      response,
      clientUriConverter: server.uriConverter,
    ).errors;
  }
}
