| // 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_generated.dart'; |
| import 'package:analysis_server/src/plugin/plugin_manager.dart'; |
| import 'package:analyzer/file_system/file_system.dart'; |
| import 'package:analyzer/instrumentation/service.dart'; |
| import 'package:analyzer/src/test_utilities/package_config_file_builder.dart'; |
| import 'package:analyzer_plugin/protocol/protocol.dart' as plugin; |
| import 'package:analyzer_plugin/protocol/protocol_common.dart'; |
| import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import '../analysis_server_base.dart'; |
| import '../src/plugin/plugin_manager_test.dart'; |
| |
| void main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(FixesTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class FixesTest extends PubPackageAnalysisServerTest { |
| @override |
| Future<void> setUp() async { |
| super.setUp(); |
| await setRoots(included: [workspaceRootPath], excluded: []); |
| } |
| |
| Future<void> test_fileOutsideRoot() async { |
| final outsideFile = '/foo/test.dart'; |
| newFile(outsideFile, 'bad code to create error'); |
| |
| // Set up the original project, as the code fix code won't run at all |
| // if there are no contexts. |
| await waitForTasksFinished(); |
| |
| var request = |
| EditGetFixesParams(convertPath(outsideFile), 0).toRequest('0'); |
| var response = await handleRequest(request); |
| assertResponseFailure( |
| response, |
| requestId: '0', |
| errorCode: RequestErrorCode.GET_FIXES_INVALID_FILE, |
| ); |
| } |
| |
| Future<void> test_fixUndefinedClass() async { |
| addTestFile(''' |
| void f() { |
| Completer<String> x = null; |
| print(x); |
| } |
| '''); |
| await waitForTasksFinished(); |
| var errorFixes = await _getFixesAt(testFile, 'Completer<String>'); |
| expect(errorFixes, hasLength(1)); |
| var fixes = errorFixes[0].fixes; |
| expect(fixes, hasLength(3)); |
| expect(fixes[0].message, matches('Import library')); |
| expect(fixes[1].message, matches('Create class')); |
| expect(fixes[2].message, matches('Create mixin')); |
| } |
| |
| Future<void> test_fromPlugins() async { |
| PluginInfo info = DiscoveredPluginInfo('a', 'b', 'c', |
| TestNotificationManager(), InstrumentationService.NULL_SERVICE); |
| var fixes = plugin.AnalysisErrorFixes(AnalysisError( |
| AnalysisErrorSeverity.ERROR, |
| AnalysisErrorType.HINT, |
| Location('', 0, 0, 0, 0, endLine: 0, endColumn: 0), |
| 'message', |
| 'code')); |
| var result = plugin.EditGetFixesResult(<plugin.AnalysisErrorFixes>[fixes]); |
| pluginManager.broadcastResults = <PluginInfo, Future<plugin.Response>>{ |
| info: Future.value(result.toResponse('-', 1)) |
| }; |
| |
| addTestFile('void f() {}'); |
| await waitForTasksFinished(); |
| var errorFixes = await _getFixesAt(testFile, 'f('); |
| expect(errorFixes, hasLength(1)); |
| } |
| |
| Future<void> test_hasFixes() async { |
| addTestFile(''' |
| foo() { |
| print(1) |
| } |
| bar() { |
| print(10) print(20) |
| } |
| '''); |
| await waitForTasksFinished(); |
| // print(1) |
| { |
| var errorFixes = await _getFixesAt(testFile, 'print(1)'); |
| expect(errorFixes, hasLength(1)); |
| _isSyntacticErrorWithSingleFix(errorFixes[0]); |
| } |
| // print(10) |
| { |
| var errorFixes = await _getFixesAt(testFile, 'print(10)'); |
| expect(errorFixes, hasLength(2)); |
| _isSyntacticErrorWithSingleFix(errorFixes[0]); |
| _isSyntacticErrorWithSingleFix(errorFixes[1]); |
| } |
| } |
| |
| Future<void> test_invalidFilePathFormat_notAbsolute() async { |
| var request = EditGetFixesParams('test.dart', 0).toRequest('0'); |
| var response = await handleRequest(request); |
| assertResponseFailure( |
| response, |
| requestId: '0', |
| errorCode: RequestErrorCode.INVALID_FILE_PATH_FORMAT, |
| ); |
| } |
| |
| Future<void> test_invalidFilePathFormat_notNormalized() async { |
| var request = EditGetFixesParams(convertPath('/foo/../bar/test.dart'), 0) |
| .toRequest('0'); |
| var response = await handleRequest(request); |
| assertResponseFailure( |
| response, |
| requestId: '0', |
| errorCode: RequestErrorCode.INVALID_FILE_PATH_FORMAT, |
| ); |
| } |
| |
| Future<void> test_overlayOnlyFile() async { |
| await _addOverlay(testFile.path, ''' |
| void f() { |
| print(1) |
| } |
| '''); |
| |
| var file = server.resourceProvider.getFile(testFile.path); |
| |
| // ask for fixes |
| await waitForTasksFinished(); |
| var errorFixes = await _getFixesAt(file, 'print(1)'); |
| expect(errorFixes, hasLength(1)); |
| _isSyntacticErrorWithSingleFix(errorFixes[0]); |
| } |
| |
| Future<void> test_suggestImportFromDifferentAnalysisRoot() async { |
| newPackageConfigJsonFile( |
| '$workspaceRootPath/aaa', |
| (PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: '$workspaceRootPath/aaa') |
| ..add(name: 'bbb', rootPath: '$workspaceRootPath/bbb')) |
| .toContent(toUriStr: toUriStr), |
| ); |
| newPubspecYamlFile('$workspaceRootPath/aaa', r''' |
| dependencies: |
| bbb: any |
| '''); |
| |
| newPackageConfigJsonFile( |
| '$workspaceRootPath/bbb', |
| (PackageConfigFileBuilder() |
| ..add(name: 'bbb', rootPath: '$workspaceRootPath/bbb')) |
| .toContent(toUriStr: toUriStr), |
| ); |
| newFile('$workspaceRootPath/bbb/lib/target.dart', 'class Foo() {}'); |
| newFile( |
| '$workspaceRootPath/bbb/lib/target.generated.dart', 'class Foo() {}'); |
| newFile( |
| '$workspaceRootPath/bbb/lib/target.template.dart', 'class Foo() {}'); |
| |
| // Configure the test file. |
| final file = |
| newFile('$workspaceRootPath/aaa/main.dart', 'void f() { new Foo(); }'); |
| |
| await waitForTasksFinished(); |
| |
| var fixes = (await _getFixesAt(file, 'Foo()')) |
| .single |
| .fixes |
| .map((f) => f.message) |
| .toList(); |
| expect(fixes, contains("Import library 'package:bbb/target.dart'")); |
| expect( |
| fixes, contains("Import library 'package:bbb/target.generated.dart'")); |
| |
| // Context: http://dartbug.com/39401 |
| expect(fixes.contains("Import library 'package:bbb/target.template.dart'"), |
| isFalse); |
| } |
| |
| Future<void> _addOverlay(String name, String contents) async { |
| await handleSuccessfulRequest( |
| AnalysisUpdateContentParams({ |
| name: AddContentOverlay(contents), |
| }).toRequest('0'), |
| ); |
| } |
| |
| Future<List<AnalysisErrorFixes>> _getFixes(File file, int offset) async { |
| var request = EditGetFixesParams(file.path, offset).toRequest('0'); |
| var response = await handleSuccessfulRequest(request); |
| var result = EditGetFixesResult.fromResponse(response); |
| return result.fixes; |
| } |
| |
| Future<List<AnalysisErrorFixes>> _getFixesAt(File file, String search) async { |
| var offset = offsetInFile(file, search); |
| return await _getFixes(file, offset); |
| } |
| |
| void _isSyntacticErrorWithSingleFix(AnalysisErrorFixes fixes) { |
| var error = fixes.error; |
| expect(error.severity, AnalysisErrorSeverity.ERROR); |
| expect(error.type, AnalysisErrorType.SYNTACTIC_ERROR); |
| expect(fixes.fixes, hasLength(1)); |
| } |
| } |