| // Copyright (c) 2018, 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:analysis_server/src/edit/edit_dartfix.dart'; |
| import 'package:analyzer_plugin/protocol/protocol_common.dart'; |
| import 'package:linter/src/rules.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import 'analysis_abstract.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(EditDartfixDomainHandlerTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class EditDartfixDomainHandlerTest extends AbstractAnalysisTest { |
| int requestId = 30; |
| String libPath; |
| |
| String get nextRequestId => (++requestId).toString(); |
| |
| void expectEdits(List<SourceFileEdit> fileEdits, String expectedSource) { |
| expect(fileEdits, hasLength(1)); |
| expect(fileEdits[0].file, testFile); |
| List<SourceEdit> edits = fileEdits[0].edits; |
| String source = testCode; |
| for (SourceEdit edit in edits) { |
| source = edit.apply(source); |
| } |
| expect(source, expectedSource); |
| } |
| |
| void expectSuggestion(DartFixSuggestion suggestion, String partialText, |
| [int offset, int length]) { |
| expect(suggestion.description, contains(partialText)); |
| if (offset == null) { |
| expect(suggestion.location, isNull); |
| } else { |
| expect(suggestion.location.offset, offset); |
| expect(suggestion.location.length, length); |
| } |
| } |
| |
| Future<EditDartfixResult> performFix({List<String> includedFixes}) async { |
| final id = nextRequestId; |
| final params = new EditDartfixParams([projectPath]); |
| params.includedFixes = includedFixes; |
| final request = new Request(id, 'edit.dartfix', params.toJson()); |
| |
| final response = await new EditDartFix(server, request).compute(); |
| expect(response.id, id); |
| |
| return EditDartfixResult.fromResponse(response); |
| } |
| |
| @override |
| void setUp() { |
| super.setUp(); |
| registerLintRules(); |
| libPath = resourceProvider.convertPath('/project/lib'); |
| testFile = resourceProvider.convertPath('/project/lib/fileToBeFixed.dart'); |
| } |
| |
| test_dartfix_convertClassToMixin() async { |
| addTestFile(''' |
| class A {} |
| class B extends A {} |
| class C with B {} |
| '''); |
| createProject(); |
| EditDartfixResult result = await performFix(); |
| expect(result.suggestions, hasLength(1)); |
| expectSuggestion(result.suggestions[0], 'mixin', 17, 1); |
| expectEdits(result.edits, ''' |
| class A {} |
| mixin B implements A {} |
| class C with B {} |
| '''); |
| } |
| |
| test_dartfix_convertToIntLiteral() async { |
| addTestFile(''' |
| const double myDouble = 42.0; |
| '''); |
| createProject(); |
| EditDartfixResult result = await performFix(); |
| expect(result.suggestions, hasLength(1)); |
| expectSuggestion(result.suggestions[0], 'int literal', 24, 4); |
| expectEdits(result.edits, ''' |
| const double myDouble = 42; |
| '''); |
| } |
| |
| test_dartfix_moveTypeArgumentToClass() async { |
| addTestFile(''' |
| class A<T> { A.from(Object obj) { } } |
| main() { |
| print(new A.from<String>([])); |
| } |
| '''); |
| createProject(); |
| EditDartfixResult result = await performFix(); |
| expect(result.suggestions, hasLength(1)); |
| expectSuggestion(result.suggestions[0], 'type arguments', 65, 8); |
| expectEdits(result.edits, ''' |
| class A<T> { A.from(Object obj) { } } |
| main() { |
| print(new A<String>.from([])); |
| } |
| '''); |
| } |
| |
| test_dartfix_non_nullable() async { |
| // Add analysis options to enable non-nullable analysis |
| newFile('/project/analysis_options.yaml', content: ''' |
| analyzer: |
| enable-experiment: |
| - non-nullable |
| '''); |
| addTestFile(''' |
| int f(int i) => 0; |
| int g(int i) => f(i); |
| void test() { |
| g(null); |
| } |
| '''); |
| createProject(); |
| EditDartfixResult result = |
| await performFix(includedFixes: ['non-nullable']); |
| expect(result.suggestions.length, greaterThanOrEqualTo(1)); |
| expect(result.hasErrors, isFalse); |
| expectEdits(result.edits, ''' |
| int f(int? i) => 0; |
| int g(int? i) => f(i); |
| void test() { |
| g(null); |
| } |
| '''); |
| } |
| |
| test_dartfix_excludedSource() async { |
| // Add analysis options to exclude the lib directory then reanalyze |
| newFile('/project/analysis_options.yaml', content: ''' |
| analyzer: |
| exclude: |
| - lib/** |
| '''); |
| |
| addTestFile(''' |
| const double myDouble = 42.0; |
| '''); |
| createProject(); |
| |
| // Assert no suggestions now that source has been excluded |
| final result = await performFix(); |
| expect(result.suggestions, hasLength(0)); |
| expect(result.edits, hasLength(0)); |
| } |
| |
| test_dartfix_partFile() async { |
| newFile('/project/lib/lib.dart', content: ''' |
| library lib2; |
| part 'fileToBeFixed.dart'; |
| '''); |
| addTestFile(''' |
| part of lib2; |
| const double myDouble = 42.0; |
| '''); |
| createProject(); |
| |
| // Assert dartfix suggestions |
| EditDartfixResult result = await performFix(); |
| expect(result.suggestions, hasLength(1)); |
| expectSuggestion(result.suggestions[0], 'int literal', 38, 4); |
| expectEdits(result.edits, ''' |
| part of lib2; |
| const double myDouble = 42; |
| '''); |
| } |
| |
| test_dartfix_partFile_loose() async { |
| addTestFile(''' |
| part of lib2; |
| const double myDouble = 42.0; |
| '''); |
| createProject(); |
| |
| // Assert dartfix suggestions |
| EditDartfixResult result = await performFix(); |
| expect(result.suggestions, hasLength(1)); |
| expectSuggestion(result.suggestions[0], 'int literal', 38, 4); |
| expectEdits(result.edits, ''' |
| part of lib2; |
| const double myDouble = 42; |
| '''); |
| } |
| } |