| // 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 'dart:async'; |
| |
| import 'package:analysis_server/src/protocol_server.dart'; |
| import 'package:analyzer/file_system/file_system.dart'; |
| import 'package:analyzer/src/test_utilities/package_config_file_builder.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import 'analysis_server_base.dart'; |
| import 'mocks.dart'; |
| import 'services/completion/dart/completion_check.dart'; |
| import 'services/completion/dart/completion_printer.dart' as printer; |
| import 'services/completion/dart/text_expectations.dart'; |
| |
| void main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(CompletionDomainHandlerGetSuggestionDetails2Test); |
| defineReflectiveTests(CompletionDomainHandlerGetSuggestions2Test); |
| }); |
| } |
| |
| @reflectiveTest |
| class CompletionDomainHandlerGetSuggestionDetails2Test |
| extends PubPackageAnalysisServerTest { |
| void assertDetailsText( |
| CompletionGetSuggestionDetails2Result result, |
| String expected, { |
| bool printIfFailed = true, |
| }) { |
| var buffer = StringBuffer(); |
| _SuggestionDetailsPrinter( |
| resourceProvider: resourceProvider, |
| fileDisplayMap: {testFile: 'testFile'}, |
| buffer: buffer, |
| result: result, |
| ).writeResult(); |
| var actual = buffer.toString(); |
| |
| if (actual != expected) { |
| if (printIfFailed) { |
| print(actual); |
| } |
| TextExpectationsCollector.add(actual); |
| } |
| expect(actual, expected); |
| } |
| |
| Future<void> test_alreadyImported() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var details = await _getTestCodeDetails(''' |
| import 'dart:math'; |
| void f() { |
| Rand^ |
| } |
| ''', completion: 'Random', libraryUri: 'dart:math'); |
| |
| assertDetailsText(details, r''' |
| completion: Random |
| change |
| '''); |
| } |
| |
| Future<void> test_import_dart() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var details = await _getTestCodeDetails(''' |
| void f() { |
| R^ |
| } |
| ''', completion: 'Random', libraryUri: 'dart:math'); |
| |
| assertDetailsText(details, r''' |
| completion: Random |
| change |
| testFile |
| offset: 0 |
| length: 0 |
| replacement: import 'dart:math';\n\n |
| '''); |
| } |
| |
| Future<void> test_import_package_dependencies() async { |
| writeTestPackagePubspecYamlFile(r''' |
| name: test |
| dependencies: |
| aaa: any |
| '''); |
| |
| var aaaRoot = getFolder('$workspaceRootPath/packages/aaa'); |
| newFile('${aaaRoot.path}/lib/f.dart', ''' |
| class Test {} |
| '''); |
| |
| writeTestPackageConfig( |
| config: PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaRoot.path), |
| ); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var details = await _getTestCodeDetails(''' |
| void f() { |
| T^ |
| } |
| ''', completion: 'Test', libraryUri: 'package:aaa/a.dart'); |
| |
| assertDetailsText(details, r''' |
| completion: Test |
| change |
| testFile |
| offset: 0 |
| length: 0 |
| replacement: import 'package:aaa/a.dart';\n\n |
| '''); |
| } |
| |
| Future<void> test_import_package_this() async { |
| newFile('$testPackageLibPath/a.dart', ''' |
| class Test {} |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var details = await _getTestCodeDetails(''' |
| void f() { |
| T^ |
| } |
| ''', completion: 'Test', libraryUri: 'package:test/a.dart'); |
| |
| assertDetailsText(details, r''' |
| completion: Test |
| change |
| testFile |
| offset: 0 |
| length: 0 |
| replacement: import 'package:test/a.dart';\n\n |
| '''); |
| } |
| |
| Future<void> test_invalidLibraryUri() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var request = CompletionGetSuggestionDetails2Params( |
| testFile.path, 0, 'Random', '[foo]:bar') |
| .toRequest('0', clientUriConverter: server.uriConverter); |
| |
| var response = await handleRequest(request); |
| expect(response.error?.code, RequestErrorCode.INVALID_PARAMETER); |
| // TODO(scheglov): Check that says "libraryUri". |
| } |
| |
| Future<void> test_invalidPath() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var request = |
| CompletionGetSuggestionDetails2Params('foo', 0, 'Random', 'dart:math') |
| .toRequest('0', clientUriConverter: server.uriConverter); |
| |
| var response = await handleRequest(request); |
| expect(response.error?.code, RequestErrorCode.INVALID_FILE_PATH_FORMAT); |
| } |
| |
| Future<void> _configureWithWorkspaceRoot() async { |
| await setRoots(included: [workspaceRootPath], excluded: []); |
| await server.onAnalysisComplete; |
| } |
| |
| Future<CompletionGetSuggestionDetails2Result> _getCodeDetails({ |
| required String path, |
| required String content, |
| required String completion, |
| required String libraryUri, |
| }) async { |
| var completionOffset = content.indexOf('^'); |
| expect(completionOffset, isNot(equals(-1)), reason: 'missing ^'); |
| |
| var nextOffset = content.indexOf('^', completionOffset + 1); |
| expect(nextOffset, equals(-1), reason: 'too many ^'); |
| |
| newFile( |
| path, |
| content.substring(0, completionOffset) + |
| content.substring(completionOffset + 1)); |
| |
| return await _getDetails( |
| path: path, |
| completionOffset: completionOffset, |
| completion: completion, |
| libraryUri: libraryUri, |
| ); |
| } |
| |
| Future<CompletionGetSuggestionDetails2Result> _getDetails({ |
| required String path, |
| required int completionOffset, |
| required String completion, |
| required String libraryUri, |
| }) async { |
| var request = CompletionGetSuggestionDetails2Params( |
| path, |
| completionOffset, |
| completion, |
| libraryUri, |
| ).toRequest('0', clientUriConverter: server.uriConverter); |
| |
| var response = await handleSuccessfulRequest(request); |
| return CompletionGetSuggestionDetails2Result.fromResponse(response, |
| clientUriConverter: server.uriConverter); |
| } |
| |
| Future<CompletionGetSuggestionDetails2Result> _getTestCodeDetails( |
| String content, { |
| required String completion, |
| required String libraryUri, |
| }) async { |
| return _getCodeDetails( |
| path: convertPath(testFilePath), |
| content: content, |
| completion: completion, |
| libraryUri: libraryUri, |
| ); |
| } |
| } |
| |
| @reflectiveTest |
| class CompletionDomainHandlerGetSuggestions2Test |
| extends PubPackageAnalysisServerTest { |
| printer.Configuration printerConfiguration = printer.Configuration( |
| filter: (suggestion) { |
| var completion = suggestion.completion; |
| if (completion.startsWith('A0')) { |
| return suggestion.isClass; |
| } |
| return const {'foo0'}.any(completion.startsWith); |
| }, |
| withIsNotImported: true, |
| withLibraryUri: true, |
| ); |
| |
| /// Asserts that the [response] has the [expected] textual dump produced |
| /// using [printerConfiguration]. |
| void assertResponseText( |
| CompletionResponseForTesting response, |
| String expected, { |
| bool printIfFailed = true, |
| }) { |
| var buffer = StringBuffer(); |
| printer.CompletionResponsePrinter( |
| buffer: buffer, |
| configuration: printerConfiguration, |
| response: response, |
| ).writeResponse(); |
| var actual = buffer.toString(); |
| |
| if (actual != expected) { |
| if (printIfFailed) { |
| print(actual); |
| } |
| TextExpectationsCollector.add(actual); |
| } |
| expect(actual, expected); |
| } |
| |
| @override |
| void setUp() { |
| super.setUp(); |
| server.completionState.budgetDuration = const Duration(seconds: 30); |
| } |
| |
| Future<void> test_abort_onAnotherCompletionRequest() async { |
| var abortedIdSet = <String>{}; |
| server.discardedRequests.stream.listen((request) { |
| abortedIdSet.add(request.id); |
| }); |
| |
| newFile(testFilePath, ''); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| // Send three requests, the first two should be aborted. |
| var request0 = _sendTestCompletionRequest('0', 0); |
| var request1 = _sendTestCompletionRequest('1', 0); |
| var request2 = _sendTestCompletionRequest('2', 0); |
| |
| // Wait for all three. |
| var response0 = await request0.toResponse(); |
| var response1 = await request1.toResponse(); |
| var response2 = await request2.toResponse(); |
| |
| // The first two should be aborted. |
| expect(abortedIdSet, {'0', '1'}); |
| |
| printerConfiguration.filter = (suggestion) { |
| if (suggestion.isClass) { |
| return const {'int'}.contains(suggestion.completion); |
| } |
| return false; |
| }; |
| |
| assertResponseText(response0, r''' |
| suggestions |
| '''); |
| |
| assertResponseText(response1, r''' |
| suggestions |
| '''); |
| |
| assertResponseText(response2, r''' |
| suggestions |
| int |
| kind: class |
| isNotImported: null |
| libraryUri: dart:core |
| '''); |
| } |
| |
| Future<void> test_abort_onUpdateContent() async { |
| var abortedIdSet = <String>{}; |
| server.discardedRequests.stream.listen((request) { |
| abortedIdSet.add(request.id); |
| }); |
| |
| newFile(testFilePath, ''); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| // Schedule a completion request. |
| var request = _sendTestCompletionRequest('0', 0); |
| |
| // Simulate typing in the IDE. |
| await handleSuccessfulRequest( |
| AnalysisUpdateContentParams({ |
| testFile.path: AddContentOverlay('void f() {}'), |
| }).toRequest('1', clientUriConverter: server.uriConverter), |
| ); |
| |
| // The request should be aborted. |
| var response = await request.toResponse(); |
| expect(abortedIdSet, {'0'}); |
| |
| assertResponseText(response, r''' |
| suggestions |
| '''); |
| } |
| |
| Future<void> test_applyPendingFileChanges() async { |
| await _configureWithWorkspaceRoot(); |
| |
| // Request with the empty content. |
| await _getTestCodeSuggestions('^'); |
| |
| // Change the file, and request again. |
| // Should apply pending file changes before resolving. |
| var response = await _getTestCodeSuggestions('Str^'); |
| |
| printerConfiguration.filter = (suggestion) { |
| if (suggestion.isClass) { |
| return const {'String'}.contains(suggestion.completion); |
| } |
| return false; |
| }; |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 3 |
| suggestions |
| String |
| kind: class |
| isNotImported: null |
| libraryUri: dart:core |
| '''); |
| } |
| |
| Future<void> test_isNotImportedFeature_prefixed_classInstanceMethod() async { |
| newFile('$testPackageLibPath/a.dart', ''' |
| class A { |
| void foo01() {} |
| } |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| import 'a.dart'; |
| |
| class B extends A { |
| void foo02() {} |
| } |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'b.dart'; |
| |
| void f(B b) { |
| b.foo0^ |
| } |
| '''); |
| |
| // The fact that `b.dart` is imported, and `a.dart` is not, does not affect |
| // the order of suggestions added with an expression prefix. We are not |
| // going to import anything, so this does not matter. |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_notImported_dart() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| void f() { |
| Rand^ |
| } |
| '''); |
| |
| printerConfiguration.filter = (suggestion) { |
| return suggestion.isClass; |
| }; |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| Random |
| kind: class |
| isNotImported: true |
| libraryUri: dart:math |
| '''); |
| } |
| |
| Future<void> test_notImported_emptyBudget() async { |
| await _configureWithWorkspaceRoot(); |
| |
| // Empty budget, so no not yet imported libraries. |
| server.completionState.budgetDuration = const Duration(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| void f() { |
| Rand^ |
| } |
| '''); |
| |
| printerConfiguration.filter = (_) => true; |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| '''); |
| } |
| |
| Future<void> test_notImported_lowerRelevance_extension_getter() async { |
| await _configureWithWorkspaceRoot(); |
| printerConfiguration.sorting = |
| printer.Sorting.relevanceThenCompletionThenKind; |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| extension E1 on int { |
| int get foo01 => 0; |
| } |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| extension E2 on int { |
| int get foo02 => 0; |
| } |
| '''); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| import 'b.dart'; |
| |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| // `foo01` relevance is decreased because it is not yet imported. |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo02 |
| kind: getter |
| isNotImported: null |
| libraryUri: null |
| foo01 |
| kind: getter |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_lowerRelevance_extension_method() async { |
| await _configureWithWorkspaceRoot(); |
| printerConfiguration.sorting = |
| printer.Sorting.relevanceThenCompletionThenKind; |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| extension E1 on int { |
| void foo01() {} |
| } |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| extension E2 on int { |
| void foo02() {} |
| } |
| '''); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| import 'b.dart'; |
| |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| // `foo01` relevance is decreased because it is not yet imported. |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo02 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| foo01 |
| kind: methodInvocation |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_lowerRelevance_extension_setter() async { |
| await _configureWithWorkspaceRoot(); |
| printerConfiguration.sorting = |
| printer.Sorting.relevanceThenCompletionThenKind; |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| extension E1 on int { |
| set foo01(int _) {} |
| } |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| extension E2 on int { |
| set foo02(int _) {} |
| } |
| '''); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| import 'b.dart'; |
| |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| // `foo01` relevance is decreased because it is not yet imported. |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo02 |
| kind: setter |
| isNotImported: null |
| libraryUri: null |
| foo01 |
| kind: setter |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_lowerRelevance_topLevel_class() async { |
| newFile('$testPackageLibPath/a.dart', ''' |
| class A01 {} |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| class A02 {} |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| printerConfiguration.sorting = |
| printer.Sorting.relevanceThenCompletionThenKind; |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'b.dart'; |
| |
| void f() { |
| A0^ |
| } |
| '''); |
| |
| // `A01` relevance is decreased because it is not yet imported. |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A02 |
| kind: class |
| isNotImported: null |
| libraryUri: package:test/b.dart |
| A01 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_lowerRelevance_topLevel_getter() async { |
| newFile('$testPackageLibPath/a.dart', ''' |
| int get foo01 => 0; |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| int get foo02 => 0; |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| printerConfiguration.sorting = |
| printer.Sorting.relevanceThenCompletionThenKind; |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'b.dart'; |
| |
| void f() { |
| foo0^ |
| } |
| '''); |
| |
| // `foo01` relevance is decreased because it is not yet imported. |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo02 |
| kind: getter |
| isNotImported: null |
| libraryUri: package:test/b.dart |
| foo01 |
| kind: getter |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_lowerRelevance_topLevel_setter() async { |
| newFile('$testPackageLibPath/a.dart', ''' |
| set foo01(int _) {} |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| set foo02(int _) {} |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| printerConfiguration.sorting = |
| printer.Sorting.relevanceThenCompletionThenKind; |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'b.dart'; |
| |
| void f() { |
| foo0^ |
| } |
| '''); |
| |
| // `foo01` relevance is decreased because it is not yet imported. |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo02 |
| kind: setter |
| isNotImported: null |
| libraryUri: package:test/b.dart |
| foo01 |
| kind: setter |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_lowerRelevance_topLevel_variable() async { |
| newFile('$testPackageLibPath/a.dart', ''' |
| var foo01 = 0; |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| var foo02 = 0; |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| printerConfiguration.sorting = |
| printer.Sorting.relevanceThenCompletionThenKind; |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'b.dart'; |
| |
| void f() { |
| foo0^ |
| } |
| '''); |
| |
| // `foo01` relevance is decreased because it is not yet imported. |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo02 |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: package:test/b.dart |
| foo01 |
| kind: topLevelVariable |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_pub_dependencies_inBin() async { |
| writeTestPackagePubspecYamlFile(r''' |
| name: test |
| dependencies: |
| aaa: any |
| dev_dependencies: |
| bbb: any |
| '''); |
| |
| var aaaRoot = getFolder('$workspaceRootPath/packages/aaa'); |
| newFile('${aaaRoot.path}/lib/f.dart', ''' |
| class A01 {} |
| '''); |
| |
| var bbbRoot = getFolder('$workspaceRootPath/packages/bbb'); |
| newFile('${bbbRoot.path}/lib/f.dart', ''' |
| class A02 {} |
| '''); |
| |
| writeTestPackageConfig( |
| config: PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaRoot.path) |
| ..add(name: 'bbb', rootPath: bbbRoot.path), |
| ); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var binPath = convertPath('$testPackageRootPath/bin/main.dart'); |
| var response = await _getCodeSuggestions( |
| path: binPath, |
| content: ''' |
| void f() { |
| A0^ |
| } |
| ''', |
| ); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A01 |
| kind: class |
| isNotImported: true |
| libraryUri: package:aaa/f.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_pub_dependencies_inLib() async { |
| writeTestPackagePubspecYamlFile(r''' |
| name: test |
| dependencies: |
| aaa: any |
| dev_dependencies: |
| bbb: any |
| '''); |
| |
| var aaaRoot = getFolder('$workspaceRootPath/packages/aaa'); |
| newFile('${aaaRoot.path}/lib/f.dart', ''' |
| class A01 {} |
| '''); |
| newFile('${aaaRoot.path}/lib/src/f.dart', ''' |
| class A02 {} |
| '''); |
| |
| var bbbRoot = getFolder('$workspaceRootPath/packages/bbb'); |
| newFile('${bbbRoot.path}/lib/f.dart', ''' |
| class A03 {} |
| '''); |
| newFile('${bbbRoot.path}/lib/src/f.dart', ''' |
| class A04 {} |
| '''); |
| |
| writeTestPackageConfig( |
| config: PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaRoot.path) |
| ..add(name: 'bbb', rootPath: bbbRoot.path), |
| ); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| void f() { |
| A0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A01 |
| kind: class |
| isNotImported: true |
| libraryUri: package:aaa/f.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_pub_dependencies_inTest() async { |
| writeTestPackagePubspecYamlFile(r''' |
| name: test |
| dependencies: |
| aaa: any |
| dev_dependencies: |
| bbb: any |
| '''); |
| |
| var aaaRoot = getFolder('$workspaceRootPath/packages/aaa'); |
| newFile('${aaaRoot.path}/lib/f.dart', ''' |
| class A01 {} |
| '''); |
| newFile('${aaaRoot.path}/lib/src/f.dart', ''' |
| class A02 {} |
| '''); |
| |
| var bbbRoot = getFolder('$workspaceRootPath/packages/bbb'); |
| newFile('${bbbRoot.path}/lib/f.dart', ''' |
| class A03 {} |
| '''); |
| newFile('${bbbRoot.path}/lib/src/f.dart', ''' |
| class A04 {} |
| '''); |
| |
| writeTestPackageConfig( |
| config: PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaRoot.path) |
| ..add(name: 'bbb', rootPath: bbbRoot.path), |
| ); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var test_path = convertPath('$testPackageTestPath/test.dart'); |
| var response = await _getCodeSuggestions( |
| path: test_path, |
| content: ''' |
| void f() { |
| A0^ |
| } |
| ''', |
| ); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A01 |
| kind: class |
| isNotImported: true |
| libraryUri: package:aaa/f.dart |
| A03 |
| kind: class |
| isNotImported: true |
| libraryUri: package:bbb/f.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_pub_dependencies_inWeb() async { |
| writeTestPackagePubspecYamlFile(r''' |
| name: test |
| dependencies: |
| aaa: any |
| dev_dependencies: |
| bbb: any |
| '''); |
| |
| var aaaRoot = getFolder('$workspaceRootPath/packages/aaa'); |
| newFile('${aaaRoot.path}/lib/f.dart', ''' |
| class A01 {} |
| '''); |
| |
| var bbbRoot = getFolder('$workspaceRootPath/packages/bbb'); |
| newFile('${bbbRoot.path}/lib/f.dart', ''' |
| class A02 {} |
| '''); |
| |
| writeTestPackageConfig( |
| config: PackageConfigFileBuilder() |
| ..add(name: 'aaa', rootPath: aaaRoot.path) |
| ..add(name: 'bbb', rootPath: bbbRoot.path), |
| ); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var webPath = convertPath('$testPackageRootPath/web/main.dart'); |
| var response = await _getCodeSuggestions( |
| path: webPath, |
| content: ''' |
| void f() { |
| A0^ |
| } |
| ''', |
| ); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A01 |
| kind: class |
| isNotImported: true |
| libraryUri: package:aaa/f.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_pub_this() async { |
| newFile('$testPackageLibPath/a.dart', ''' |
| class A01 {} |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| class A02 {} |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| void f() { |
| A0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A01 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| A02 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/b.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_pub_this_hasImport() async { |
| newFile('$testPackageLibPath/a.dart', ''' |
| class A01 {} |
| class A02 {} |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| class A03 {} |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'a.dart'; |
| |
| void f() { |
| A0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A01 |
| kind: class |
| isNotImported: null |
| libraryUri: package:test/a.dart |
| A02 |
| kind: class |
| isNotImported: null |
| libraryUri: package:test/a.dart |
| A03 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/b.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_pub_this_hasImport_hasShow() async { |
| newFile('$testPackageLibPath/a.dart', ''' |
| class A01 {} |
| class A02 {} |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| class A03 {} |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| printerConfiguration.sorting = |
| printer.Sorting.relevanceThenCompletionThenKind; |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'a.dart' show A02; |
| |
| void f() { |
| A0^ |
| } |
| '''); |
| |
| // Note: |
| // 1. A02 is the first, because it is already imported. |
| // 2. A01 is still suggested, but with lower relevance. |
| // 3. A03 has the same relevance (not tested), but sorted by name. |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A02 |
| kind: class |
| isNotImported: null |
| libraryUri: package:test/a.dart |
| A01 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| A03 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/b.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_pub_this_inLib_excludesTest() async { |
| writeTestPackagePubspecYamlFile(r''' |
| name: test |
| '''); |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| class A01 {} |
| '''); |
| |
| newFile('$testPackageTestPath/b.dart', ''' |
| class A02 {} |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| void f() { |
| A0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A01 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_pub_this_inLib_includesThisSrc() async { |
| writeTestPackagePubspecYamlFile(r''' |
| name: test |
| '''); |
| |
| newFile('$testPackageLibPath/f.dart', ''' |
| class A01 {} |
| '''); |
| |
| newFile('$testPackageLibPath/src/f.dart', ''' |
| class A02 {} |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| void f() { |
| A0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A01 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/f.dart |
| A02 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/src/f.dart |
| '''); |
| } |
| |
| Future<void> test_notImported_pub_this_inTest_includesTest() async { |
| writeTestPackagePubspecYamlFile(r''' |
| name: test |
| '''); |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| class A01 {} |
| '''); |
| |
| var b = newFile('$testPackageTestPath/b.dart', ''' |
| class A02 {} |
| '''); |
| var b_uriStr = toUriStr(b.path); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var test_path = convertPath('$testPackageTestPath/test.dart'); |
| var response = await _getCodeSuggestions( |
| path: test_path, |
| content: ''' |
| void f() { |
| A0^ |
| } |
| ''', |
| ); |
| |
| assertResponseText(response, ''' |
| replacement |
| left: 2 |
| suggestions |
| A01 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| A02 |
| kind: class |
| isNotImported: true |
| libraryUri: $b_uriStr |
| '''); |
| } |
| |
| Future<void> test_notImported_pub_this_inTest_includesThisSrc() async { |
| writeTestPackagePubspecYamlFile(r''' |
| name: test |
| '''); |
| |
| newFile('$testPackageLibPath/f.dart', ''' |
| class A01 {} |
| '''); |
| |
| newFile('$testPackageLibPath/src/f.dart', ''' |
| class A02 {} |
| '''); |
| |
| await _configureWithWorkspaceRoot(); |
| |
| var test_path = convertPath('$testPackageTestPath/test.dart'); |
| var response = await _getCodeSuggestions( |
| path: test_path, |
| content: ''' |
| void f() { |
| A0^ |
| } |
| ''', |
| ); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A01 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/f.dart |
| A02 |
| kind: class |
| isNotImported: true |
| libraryUri: package:test/src/f.dart |
| '''); |
| } |
| |
| Future<void> test_numResults_class_methods() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| class A { |
| void foo01() {} |
| void foo02() {} |
| void foo03() {} |
| } |
| |
| void f(A a) { |
| a.foo0^ |
| } |
| ''', maxResults: 2); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_numResults_topLevelVariables() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| var foo01 = 0; |
| var foo02 = 0; |
| var foo03 = 0; |
| |
| void f() { |
| foo0^ |
| } |
| ''', maxResults: 2); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_numResults_topLevelVariables_imported_withPrefix() async { |
| await _configureWithWorkspaceRoot(); |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| var foo01 = 0; |
| var foo02 = 0; |
| var foo03 = 0; |
| '''); |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'a.dart' as prefix; |
| |
| void f() { |
| prefix.^ |
| } |
| ''', maxResults: 2); |
| |
| assertResponseText(response, r''' |
| suggestions |
| foo01 |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: package:test/a.dart |
| foo02 |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_prefixed_class_constructors() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| class A { |
| A.foo01(); |
| A.foo02(); |
| } |
| |
| void f() { |
| A.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: constructorInvocation |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: constructorInvocation |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_prefixed_class_getters() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| class A { |
| int get foo01 => 0; |
| int get foo02 => 0; |
| } |
| |
| void f(A a) { |
| a.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: getter |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: getter |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_prefixed_class_methods_instance() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| class A { |
| void foo01() {} |
| void foo02() {} |
| } |
| |
| void f(A a) { |
| a.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_prefixed_class_methods_static() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| class A { |
| static void foo01() {} |
| static void foo02() {} |
| } |
| |
| void f() { |
| A.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_prefixed_expression_extensionGetters() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| extension E1 on int { |
| int get foo01 => 0; |
| int get foo02 => 0; |
| int get bar => 0; |
| } |
| |
| extension E2 on double { |
| int get foo03 => 0; |
| } |
| |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: getter |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: getter |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_prefixed_expression_extensionGetters_notImported() async { |
| await _configureWithWorkspaceRoot(); |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| extension E1 on int { |
| int get foo01 => 0; |
| int get bar => 0; |
| } |
| |
| extension E2 on int { |
| int get foo02 => 0; |
| } |
| |
| extension E3 on double { |
| int get foo03 => 0; |
| } |
| '''); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: getter |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| foo02 |
| kind: getter |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> |
| test_prefixed_expression_extensionGetters_notImported_private() async { |
| await _configureWithWorkspaceRoot(); |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| extension E1 on int { |
| int get foo01 => 0; |
| } |
| |
| extension _E2 on int { |
| int get foo02 => 0; |
| } |
| |
| extension on int { |
| int get foo03 => 0; |
| } |
| '''); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: getter |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_prefixed_expression_extensionMethods() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| extension E1 on int { |
| void foo01() {} |
| void foo02() {} |
| void bar() {} |
| } |
| |
| extension E2 on double { |
| void foo03() {} |
| } |
| |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_prefixed_expression_extensionMethods_notImported() async { |
| await _configureWithWorkspaceRoot(); |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| extension E1 on int { |
| void foo01() {} |
| void bar() {} |
| } |
| |
| extension E2 on int { |
| void foo02() {} |
| } |
| |
| extension E3 on double { |
| void foo03() {} |
| } |
| '''); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: methodInvocation |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| foo02 |
| kind: methodInvocation |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_prefixed_expression_extensionSetters() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| extension E1 on int { |
| set foo01(int _) {} |
| set foo02(int _) {} |
| set bar(int _) {} |
| } |
| |
| extension E2 on double { |
| set foo03(int _) {} |
| } |
| |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: setter |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: setter |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_prefixed_expression_extensionSetters_notImported() async { |
| await _configureWithWorkspaceRoot(); |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| extension E1 on int { |
| set foo01(int _) {} |
| set bar(int _) {} |
| } |
| |
| extension E2 on int { |
| set foo02(int _) {} |
| } |
| |
| extension E3 on double { |
| set foo03(int _) {} |
| } |
| '''); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: setter |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| foo02 |
| kind: setter |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> |
| test_prefixed_expression_extensionSetters_notImported_private() async { |
| await _configureWithWorkspaceRoot(); |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| extension E1 on int { |
| set foo01(int _) {} |
| } |
| |
| extension _E2 on int { |
| set foo02(int _) {} |
| } |
| |
| extension on int { |
| set foo03(int _) {} |
| } |
| '''); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: setter |
| isNotImported: true |
| libraryUri: package:test/a.dart |
| '''); |
| } |
| |
| Future<void> test_prefixed_extensionGetters_imported() async { |
| await _configureWithWorkspaceRoot(); |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| extension E1 on int { |
| int get foo01 => 0; |
| int get foo02 => 0; |
| int get bar => 0; |
| } |
| |
| extension E2 on double { |
| int get foo03 => 0; |
| } |
| '''); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| import 'a.dart'; |
| |
| void f() { |
| 0.foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: getter |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: getter |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_prefixed_extensionOverride_extensionGetters() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| extension E1 on int { |
| int get foo01 => 0; |
| } |
| |
| extension E2 on int { |
| int get foo02 => 0; |
| } |
| |
| void f() { |
| E1(0).foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: getter |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_prefixed_extensionOverride_extensionMethods() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| extension E1 on int { |
| void foo01() {} |
| } |
| |
| extension E2 on int { |
| void foo01() {} |
| } |
| |
| void f() { |
| E1(0).foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: methodInvocation |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_prefixed_importPrefix_class() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'dart:math' as math; |
| |
| void f() { |
| math.Rand^ |
| } |
| '''); |
| |
| printerConfiguration.filter = (_) => true; |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| Random |
| kind: class |
| isNotImported: null |
| libraryUri: dart:math |
| Random |
| kind: constructorInvocation |
| isNotImported: null |
| libraryUri: dart:math |
| '''); |
| } |
| |
| Future<void> test_unprefixed_filters() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| var foo01 = 0; |
| var foo02 = 0; |
| var bar01 = 0; |
| var bar02 = 0; |
| |
| void f() { |
| foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: null |
| foo02 |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: null |
| '''); |
| } |
| |
| Future<void> test_unprefixed_imported_class() async { |
| await _configureWithWorkspaceRoot(); |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| class A01 {} |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| class A02 {} |
| '''); |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'a.dart'; |
| import 'b.dart'; |
| |
| void f() { |
| A0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 2 |
| suggestions |
| A01 |
| kind: class |
| isNotImported: null |
| libraryUri: package:test/a.dart |
| A02 |
| kind: class |
| isNotImported: null |
| libraryUri: package:test/b.dart |
| '''); |
| } |
| |
| Future<void> test_unprefixed_imported_topLevelVariable() async { |
| await _configureWithWorkspaceRoot(); |
| |
| newFile('$testPackageLibPath/a.dart', ''' |
| var foo01 = 0; |
| '''); |
| |
| newFile('$testPackageLibPath/b.dart', ''' |
| var foo02 = 0; |
| '''); |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'a.dart'; |
| import 'b.dart'; |
| |
| void f() { |
| foo0^ |
| } |
| '''); |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo01 |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: package:test/a.dart |
| foo02 |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: package:test/b.dart |
| '''); |
| } |
| |
| Future<void> test_unprefixed_imported_withPrefix_class() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(''' |
| import 'dart:math' as math; |
| |
| void f() { |
| Rand^ |
| } |
| '''); |
| |
| printerConfiguration.filter = (suggestion) { |
| return suggestion.isClass; |
| }; |
| |
| // No suggestion without the `math` prefix. |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| math.Random |
| kind: class |
| isNotImported: null |
| libraryUri: dart:math |
| '''); |
| } |
| |
| Future<void> test_unprefixed_sorts_byScore() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| var fooAB = 0; |
| var fooBB = 0; |
| |
| void f() { |
| fooB^ |
| } |
| '''); |
| |
| printerConfiguration |
| ..filter = (suggestion) { |
| return suggestion.completion.startsWith('foo'); |
| } |
| ..sorting = printer.Sorting.asIs |
| ..withRelevance = true; |
| |
| // `fooBB` has better score than `fooAB` - prefix match |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| fooBB |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: null |
| relevance: 503 |
| fooAB |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: null |
| relevance: 503 |
| '''); |
| } |
| |
| Future<void> test_unprefixed_sorts_byType() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var response = await _getTestCodeSuggestions(r''' |
| var foo01 = 0.0; |
| var foo02 = 0; |
| |
| void f() { |
| int v = foo0^ |
| } |
| '''); |
| |
| printerConfiguration |
| ..sorting = printer.Sorting.asIs |
| ..withRelevance = true; |
| |
| assertResponseText(response, r''' |
| replacement |
| left: 4 |
| suggestions |
| foo02 |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: null |
| relevance: 558 |
| foo01 |
| kind: topLevelVariable |
| isNotImported: null |
| libraryUri: null |
| relevance: 510 |
| '''); |
| } |
| |
| Future<void> test_yaml_analysisOptions_root() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var path = convertPath('$testPackageRootPath/analysis_options.yaml'); |
| var response = await _getCodeSuggestions( |
| path: path, |
| content: '^', |
| ); |
| |
| printerConfiguration |
| ..filter = ((_) => true) |
| ..withIsNotImported = false |
| ..withLibraryUri = false; |
| |
| assertResponseText(response, r''' |
| suggestions |
| |analyzer: | |
| kind: identifier |
| |code-style: | |
| kind: identifier |
| |include: | |
| kind: identifier |
| |linter: | |
| kind: identifier |
| '''); |
| } |
| |
| Future<void> test_yaml_fixData_root() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var path = convertPath('$testPackageRootPath/fix_data.yaml'); |
| var response = await _getCodeSuggestions( |
| path: path, |
| content: '^', |
| ); |
| |
| printerConfiguration |
| ..filter = ((_) => true) |
| ..withIsNotImported = false |
| ..withLibraryUri = false; |
| |
| assertResponseText(response, r''' |
| suggestions |
| transforms: |
| kind: identifier |
| |version: | |
| kind: identifier |
| '''); |
| } |
| |
| Future<void> test_yaml_pubspec_root() async { |
| await _configureWithWorkspaceRoot(); |
| |
| var path = convertPath('$testPackageRootPath/pubspec.yaml'); |
| var response = await _getCodeSuggestions( |
| path: path, |
| content: '^', |
| ); |
| |
| printerConfiguration |
| ..filter = ((_) => true) |
| ..withIsNotImported = false |
| ..withLibraryUri = false; |
| |
| assertResponseText(response, r''' |
| suggestions |
| |dependencies: | |
| kind: identifier |
| |dependency_overrides: | |
| kind: identifier |
| |description: | |
| kind: identifier |
| |dev_dependencies: | |
| kind: identifier |
| |documentation: | |
| kind: identifier |
| |environment: | |
| kind: identifier |
| |executables: | |
| kind: identifier |
| |flutter: | |
| kind: identifier |
| |homepage: | |
| kind: identifier |
| |issue_tracker: | |
| kind: identifier |
| |name: | |
| kind: identifier |
| |publish_to: | |
| kind: identifier |
| |repository: | |
| kind: identifier |
| |resolution: | |
| kind: identifier |
| screenshots: |
| kind: identifier |
| |topics: | |
| kind: identifier |
| |version: | |
| kind: identifier |
| workspace: |
| kind: identifier |
| '''); |
| } |
| |
| Future<void> _configureWithWorkspaceRoot() async { |
| await setRoots(included: [workspaceRootPath], excluded: []); |
| await server.onAnalysisComplete; |
| } |
| |
| Future<CompletionResponseForTesting> _getCodeSuggestions({ |
| required String path, |
| required String content, |
| int maxResults = 1 << 10, |
| }) async { |
| var completionOffset = content.indexOf('^'); |
| expect(completionOffset, isNot(equals(-1)), reason: 'missing ^'); |
| |
| var nextOffset = content.indexOf('^', completionOffset + 1); |
| expect(nextOffset, equals(-1), reason: 'too many ^'); |
| |
| newFile( |
| path, |
| content.substring(0, completionOffset) + |
| content.substring(completionOffset + 1), |
| ); |
| |
| return await _getSuggestions( |
| path: path, |
| completionOffset: completionOffset, |
| maxResults: maxResults, |
| ); |
| } |
| |
| Future<CompletionResponseForTesting> _getSuggestions({ |
| required String path, |
| required int completionOffset, |
| required int maxResults, |
| }) async { |
| var request = CompletionGetSuggestions2Params( |
| path, |
| completionOffset, |
| maxResults, |
| ).toRequest('0', clientUriConverter: server.uriConverter); |
| |
| var response = await handleSuccessfulRequest(request); |
| var result = CompletionGetSuggestions2Result.fromResponse(response, |
| clientUriConverter: server.uriConverter); |
| |
| // Extract the internal request object. |
| var dartRequest = server.completionState.currentRequest; |
| |
| return CompletionResponseForTesting( |
| requestOffset: completionOffset, |
| requestLocationName: dartRequest?.collectorLocationName, |
| opTypeLocationName: dartRequest?.opType.completionLocation, |
| replacementOffset: result.replacementOffset, |
| replacementLength: result.replacementLength, |
| isIncomplete: result.isIncomplete, |
| suggestions: result.suggestions, |
| ); |
| } |
| |
| Future<CompletionResponseForTesting> _getTestCodeSuggestions( |
| String content, { |
| int maxResults = 1 << 10, |
| }) { |
| return _getCodeSuggestions( |
| path: convertPath(testFilePath), |
| content: content, |
| maxResults: maxResults, |
| ); |
| } |
| |
| RequestWithFutureResponse _sendTestCompletionRequest(String id, int offset) { |
| var request = CompletionGetSuggestions2Params( |
| testFile.path, |
| 0, |
| 1 << 10, |
| ).toRequest(id, clientUriConverter: server.uriConverter); |
| var futureResponse = handleRequest(request); |
| return RequestWithFutureResponse(offset, request, futureResponse); |
| } |
| } |
| |
| class RequestWithFutureResponse { |
| final int offset; |
| final Request request; |
| final Future<Response> futureResponse; |
| |
| RequestWithFutureResponse(this.offset, this.request, this.futureResponse); |
| |
| Future<CompletionResponseForTesting> toResponse() async { |
| var response = await futureResponse; |
| expect(response, isResponseSuccess(request.id)); |
| var result = CompletionGetSuggestions2Result.fromResponse(response, |
| clientUriConverter: null); |
| return CompletionResponseForTesting( |
| requestOffset: offset, |
| requestLocationName: null, |
| opTypeLocationName: null, |
| replacementOffset: result.replacementOffset, |
| replacementLength: result.replacementLength, |
| isIncomplete: result.isIncomplete, |
| suggestions: result.suggestions, |
| ); |
| } |
| } |
| |
| class _SuggestionDetailsPrinter { |
| final StringBuffer buffer; |
| final CompletionGetSuggestionDetails2Result result; |
| final ResourceProvider resourceProvider; |
| final Map<File, String> fileDisplayMap; |
| |
| String _indent = ''; |
| |
| _SuggestionDetailsPrinter({ |
| required this.buffer, |
| required this.result, |
| required this.resourceProvider, |
| required this.fileDisplayMap, |
| }); |
| |
| void writeResult() { |
| _writelnWithIndent('completion: ${result.completion}'); |
| _withIndent(() { |
| _writeChange(result.change); |
| }); |
| } |
| |
| void _withIndent(void Function() f) { |
| var indent = _indent; |
| _indent = '$_indent '; |
| f(); |
| _indent = indent; |
| } |
| |
| void _writeChange(SourceChange change) { |
| _writelnWithIndent('change'); |
| _withIndent(() { |
| for (var fileEdit in change.edits) { |
| _writeSourceFileEdit(fileEdit); |
| } |
| }); |
| } |
| |
| void _writelnWithIndent(String line) { |
| buffer.write(_indent); |
| buffer.writeln(line); |
| } |
| |
| void _writeSourceEdit(SourceEdit edit) { |
| _writelnWithIndent('offset: ${edit.offset}'); |
| _writelnWithIndent('length: ${edit.length}'); |
| |
| var replacementStr = edit.replacement.replaceAll('\n', r'\n'); |
| _writelnWithIndent('replacement: $replacementStr'); |
| } |
| |
| void _writeSourceFileEdit(SourceFileEdit fileEdit) { |
| var file = resourceProvider.getFile(fileEdit.file); |
| var fileStr = fileDisplayMap[file] ?? fail('No display name: $file'); |
| _writelnWithIndent(fileStr); |
| |
| _withIndent(() { |
| for (var edit in fileEdit.edits) { |
| _writeSourceEdit(edit); |
| } |
| }); |
| } |
| } |
| |
| extension on CompletionSuggestion { |
| bool get isClass { |
| return kind == CompletionSuggestionKind.IDENTIFIER && |
| element?.kind == ElementKind.CLASS; |
| } |
| } |