// 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/protocol/protocol.dart'; import 'package:analysis_server/protocol/protocol_generated.dart'; import 'package:analysis_server/src/plugin/plugin_manager.dart'; import 'package:analysis_server/src/provisional/completion/completion_core.dart'; import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart'; import 'package:analysis_server/src/services/completion/dart/completion_manager.dart'; import 'package:analysis_server/src/services/completion/dart/contribution_sorter.dart'; import 'package:analyzer_plugin/protocol/protocol.dart' as plugin; import 'package:analyzer_plugin/protocol/protocol_common.dart'; import 'package:analyzer_plugin/protocol/protocol_constants.dart' as plugin; 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 'domain_completion_util.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(CompletionDomainHandlerTest); }); } @reflectiveTest class CompletionDomainHandlerTest extends AbstractCompletionDomainTest { test_ArgumentList_constructor_named_fieldFormalParam() async { // https://github.com/dart-lang/sdk/issues/31023 addTestFile(''' main() { new A(field: ^);} class A { A({this.field: -1}) {} } '''); await getSuggestions(); } test_ArgumentList_constructor_named_param_label() async { addTestFile('main() { new A(^);}' 'class A { A({one, two}) {} }'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'one: ', relevance: DART_RELEVANCE_NAMED_PARAMETER); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'two: ', relevance: DART_RELEVANCE_NAMED_PARAMETER); expect(suggestions, hasLength(2)); } test_ArgumentList_factory_named_param_label() async { addTestFile('main() { new A(^);}' 'class A { factory A({one, two}) => null; }'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'one: ', relevance: DART_RELEVANCE_NAMED_PARAMETER); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'two: ', relevance: DART_RELEVANCE_NAMED_PARAMETER); expect(suggestions, hasLength(2)); } test_ArgumentList_imported_function_named_param() async { addTestFile('main() { int.parse("16", ^);}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'radix: ', relevance: DART_RELEVANCE_NAMED_PARAMETER); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'onError: ', relevance: DART_RELEVANCE_NAMED_PARAMETER); expect(suggestions, hasLength(2)); } test_ArgumentList_imported_function_named_param1() async { addTestFile('main() { foo(o^);} foo({one, two}) {}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'one: ', relevance: DART_RELEVANCE_NAMED_PARAMETER); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'two: ', relevance: DART_RELEVANCE_NAMED_PARAMETER); expect(suggestions, hasLength(2)); } test_ArgumentList_imported_function_named_param2() async { addTestFile('mainx() {A a = new A(); a.foo(one: 7, ^);}' 'class A { foo({one, two}) {} }'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'two: ', relevance: DART_RELEVANCE_NAMED_PARAMETER); expect(suggestions, hasLength(1)); } test_ArgumentList_imported_function_named_param_label1() async { addTestFile('main() { int.parse("16", r^: 16);}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'radix', relevance: DART_RELEVANCE_NAMED_PARAMETER); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'onError', relevance: DART_RELEVANCE_NAMED_PARAMETER); expect(suggestions, hasLength(2)); } test_ArgumentList_imported_function_named_param_label3() async { addTestFile('main() { int.parse("16", ^: 16);}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'radix: ', relevance: DART_RELEVANCE_NAMED_PARAMETER); assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'onError: ', relevance: DART_RELEVANCE_NAMED_PARAMETER); expect(suggestions, hasLength(2)); } test_catch() async { addTestFile('main() {try {} ^}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.KEYWORD, 'on', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.KEYWORD, 'catch', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.KEYWORD, 'finally', relevance: DART_RELEVANCE_KEYWORD); expect(suggestions, hasLength(3)); } test_catch2() async { addTestFile('main() {try {} on Foo {} ^}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.KEYWORD, 'on', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.KEYWORD, 'catch', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.KEYWORD, 'finally', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.KEYWORD, 'for', relevance: DART_RELEVANCE_KEYWORD); suggestions.firstWhere( (CompletionSuggestion suggestion) => suggestion.kind != CompletionSuggestionKind.KEYWORD, orElse: () { fail('Expected suggestions other than keyword suggestions'); }); } test_catch3() async { addTestFile('main() {try {} catch (e) {} finally {} ^}'); await getSuggestions(); assertNoResult('on'); assertNoResult('catch'); assertNoResult('finally'); assertHasResult(CompletionSuggestionKind.KEYWORD, 'for', relevance: DART_RELEVANCE_KEYWORD); suggestions.firstWhere( (CompletionSuggestion suggestion) => suggestion.kind != CompletionSuggestionKind.KEYWORD, orElse: () { fail('Expected suggestions other than keyword suggestions'); }); } test_catch4() async { addTestFile('main() {try {} finally {} ^}'); await getSuggestions(); assertNoResult('on'); assertNoResult('catch'); assertNoResult('finally'); assertHasResult(CompletionSuggestionKind.KEYWORD, 'for', relevance: DART_RELEVANCE_KEYWORD); suggestions.firstWhere( (CompletionSuggestion suggestion) => suggestion.kind != CompletionSuggestionKind.KEYWORD, orElse: () { fail('Expected suggestions other than keyword suggestions'); }); } test_catch5() async { addTestFile('main() {try {} ^ finally {}}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.KEYWORD, 'on', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.KEYWORD, 'catch', relevance: DART_RELEVANCE_KEYWORD); expect(suggestions, hasLength(2)); } test_constructor() async { addTestFile('class A {bool foo; A() : ^;}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.KEYWORD, 'super', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.INVOCATION, 'foo', relevance: DART_RELEVANCE_LOCAL_FIELD); } test_constructor2() async { addTestFile('class A {bool foo; A() : s^;}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.KEYWORD, 'super', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.INVOCATION, 'foo', relevance: DART_RELEVANCE_LOCAL_FIELD); } test_constructor3() async { addTestFile('class A {bool foo; A() : a=7,^;}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.KEYWORD, 'super', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.INVOCATION, 'foo', relevance: DART_RELEVANCE_LOCAL_FIELD); } test_constructor4() async { addTestFile('class A {bool foo; A() : a=7,s^;}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.KEYWORD, 'super', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.INVOCATION, 'foo', relevance: DART_RELEVANCE_LOCAL_FIELD); } test_constructor5() async { addTestFile('class A {bool foo; A() : a=7,s^}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.KEYWORD, 'super', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.INVOCATION, 'foo', relevance: DART_RELEVANCE_LOCAL_FIELD); } test_constructor6() async { addTestFile('class A {bool foo; A() : a=7,^ void bar() {}}'); await getSuggestions(); assertHasResult(CompletionSuggestionKind.KEYWORD, 'super', relevance: DART_RELEVANCE_KEYWORD); assertHasResult(CompletionSuggestionKind.INVOCATION, 'foo', relevance: DART_RELEVANCE_LOCAL_FIELD); } test_html() { // // We no longer support the analysis of non-dart files. // testFile = resourceProvider.convertPath('/project/web/test.html'); addTestFile(''' ^ '''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); expect(suggestions, hasLength(0)); }); } test_import_uri_with_trailing() { final filePath = '/project/bin/testA.dart'; final incompleteImportText = convertPathForImport('/project/bin/t'); newFile(filePath, content: 'library libA;'); addTestFile(''' import "$incompleteImportText^.dart"; main() {}'''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset - incompleteImportText.length)); expect(replacementLength, equals(5 + incompleteImportText.length)); assertHasResult( CompletionSuggestionKind.IMPORT, convertPathForImport(filePath)); assertNoResult('test'); }); } test_imports() { addTestFile(''' import 'dart:html'; main() {^} '''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object', elementKind: ElementKind.CLASS); assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement', elementKind: ElementKind.CLASS); assertNoResult('test'); }); } test_imports_aborted_new_request() async { addTestFile(''' class foo { } c^'''); // Make a request for suggestions Request request1 = new CompletionGetSuggestionsParams(testFile, completionOffset) .toRequest('7'); Future responseFuture1 = waitResponse(request1); // Make another request before the first request completes Request request2 = new CompletionGetSuggestionsParams(testFile, completionOffset) .toRequest('8'); Future responseFuture2 = waitResponse(request2); // Await first response Response response1 = await responseFuture1; var result1 = new CompletionGetSuggestionsResult.fromResponse(response1); assertValidId(result1.id); // Await second response Response response2 = await responseFuture2; var result2 = new CompletionGetSuggestionsResult.fromResponse(response2); assertValidId(result2.id); // Wait for all processing to be complete await analysisHandler.server.analysisDriverScheduler.waitForIdle(); await pumpEventQueue(); // Assert that first request has been aborted expect(allSuggestions[result1.id], hasLength(0)); // Assert valid results for the second request expect(allSuggestions[result2.id], same(suggestions)); assertHasResult(CompletionSuggestionKind.KEYWORD, 'class', relevance: DART_RELEVANCE_HIGH); } @failingTest test_imports_aborted_source_changed() async { // TODO(brianwilkerson) Figure out whether this test makes sense when // running the new driver. It waits for an initial empty notification then // waits for a new notification. But I think that under the driver we only // ever send one notification. addTestFile(''' class foo { } c^'''); // Make a request for suggestions Request request = new CompletionGetSuggestionsParams(testFile, completionOffset) .toRequest('0'); Future responseFuture = waitResponse(request); // Simulate user deleting text after request but before suggestions returned server.updateContent('uc1', {testFile: new AddContentOverlay(testCode)}); server.updateContent('uc2', { testFile: new ChangeContentOverlay( [new SourceEdit(completionOffset - 1, 1, '')]) }); // Await a response Response response = await responseFuture; completionId = response.id; assertValidId(completionId); // Wait for all processing to be complete await analysisHandler.server.analysisDriverScheduler.waitForIdle(); await pumpEventQueue(); // Assert that request has been aborted expect(suggestionsDone, isTrue); expect(suggestions, hasLength(0)); } test_imports_incremental() async { addTestFile('''library foo; e^ import "dart:async"; import "package:foo/foo.dart"; class foo { }'''); await waitForTasksFinished(); server.updateContent('uc1', {testFile: new AddContentOverlay(testCode)}); server.updateContent('uc2', { testFile: new ChangeContentOverlay([new SourceEdit(completionOffset, 0, 'xp')]) }); completionOffset += 2; await getSuggestions(); expect(replacementOffset, completionOffset - 3); expect(replacementLength, 3); assertHasResult(CompletionSuggestionKind.KEYWORD, 'export \'\';', selectionOffset: 8, relevance: DART_RELEVANCE_HIGH); assertHasResult(CompletionSuggestionKind.KEYWORD, 'import \'\';', selectionOffset: 8, relevance: DART_RELEVANCE_HIGH); assertNoResult('extends'); assertNoResult('library'); } test_imports_partial() async { addTestFile('''^ import "package:foo/foo.dart"; import "package:bar/bar.dart"; class Baz { }'''); // Wait for analysis then edit the content await waitForTasksFinished(); String revisedContent = testCode.substring(0, completionOffset) + 'i' + testCode.substring(completionOffset); ++completionOffset; server.handleRequest(new AnalysisUpdateContentParams( {testFile: new AddContentOverlay(revisedContent)}).toRequest('add1')); // Request code completion immediately after edit Response response = await waitResponse( new CompletionGetSuggestionsParams(testFile, completionOffset) .toRequest('0')); completionId = response.id; assertValidId(completionId); await waitForTasksFinished(); // wait for response to arrive // because although the analysis is complete (waitForTasksFinished) // the response may not yet have been processed while (replacementOffset == null) { await new Future.delayed(new Duration(milliseconds: 5)); } expect(replacementOffset, completionOffset - 1); expect(replacementLength, 1); assertHasResult(CompletionSuggestionKind.KEYWORD, 'library', relevance: DART_RELEVANCE_HIGH); assertHasResult(CompletionSuggestionKind.KEYWORD, 'import \'\';', selectionOffset: 8, relevance: DART_RELEVANCE_HIGH); assertHasResult(CompletionSuggestionKind.KEYWORD, 'export \'\';', selectionOffset: 8, relevance: DART_RELEVANCE_HIGH); assertHasResult(CompletionSuggestionKind.KEYWORD, 'part \'\';', selectionOffset: 6, relevance: DART_RELEVANCE_HIGH); assertNoResult('extends'); } test_imports_prefixed() { addTestFile(''' import 'dart:html' as foo; main() {^} '''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object', elementKind: ElementKind.CLASS); assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo'); assertNoResult('HtmlElement'); assertNoResult('test'); }); } test_imports_prefixed2() { addTestFile(''' import 'dart:html' as foo; main() {foo.^} '''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement'); assertNoResult('test'); }); } test_inComment_block_beforeNode() async { addTestFile(''' main(aaa, bbb) { /* text ^ */ print(42); } '''); await getSuggestions(); expect(suggestions, isEmpty); } test_inComment_endOfLine_beforeNode() async { addTestFile(''' main(aaa, bbb) { // text ^ print(42); } '''); await getSuggestions(); expect(suggestions, isEmpty); } test_inComment_endOfLine_beforeToken() async { addTestFile(''' main(aaa, bbb) { // text ^ } '''); await getSuggestions(); expect(suggestions, isEmpty); } test_inDartDoc1() async { addTestFile(''' /// ^ main(aaa, bbb) {} '''); await getSuggestions(); expect(suggestions, isEmpty); } test_inDartDoc2() async { addTestFile(''' /// Some text^ main(aaa, bbb) {} '''); await getSuggestions(); expect(suggestions, isEmpty); } test_inDartDoc_reference1() async { newFile('/testA.dart', content: ''' part of libA; foo(bar) => 0;'''); addTestFile(''' library libA; part "${convertPathForImport('/testA.dart')}"; import "dart:math"; /// The [^] main(aaa, bbb) {} '''); await getSuggestions(); assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'main', relevance: DART_RELEVANCE_LOCAL_FUNCTION); assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo', relevance: DART_RELEVANCE_LOCAL_FUNCTION); assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'min'); } test_inDartDoc_reference2() async { addTestFile(''' /// The [m^] main(aaa, bbb) {} '''); await getSuggestions(); assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'main', relevance: DART_RELEVANCE_LOCAL_FUNCTION); } test_inherited() { newFile('/libA.dart', content: 'class A {m() {}}'); addTestFile(''' import ${convertPathForImport('/libA.dart')}; class B extends A { x() {^} } '''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'm'); }); } test_invocation() { addTestFile('class A {b() {}} main() {A a; a.^}'); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'b'); }); } test_invocation_sdk_relevancy_off() { var originalSorter = DartCompletionManager.contributionSorter; var mockSorter = new MockRelevancySorter(); DartCompletionManager.contributionSorter = mockSorter; addTestFile('main() {Map m; m.^}'); return getSuggestions().then((_) { // Assert that the CommonUsageComputer has been replaced expect(suggestions.any((s) => s.relevance == DART_RELEVANCE_COMMON_USAGE), isFalse); DartCompletionManager.contributionSorter = originalSorter; mockSorter.enabled = false; }); } test_invocation_sdk_relevancy_on() { addTestFile('main() {Map m; m.^}'); return getSuggestions().then((_) { // Assert that the CommonUsageComputer is working expect(suggestions.any((s) => s.relevance == DART_RELEVANCE_COMMON_USAGE), isTrue); }); } test_invocation_withTrailingStmt() { addTestFile('class A {b() {}} main() {A a; a.^ int x = 7;}'); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'b'); }); } test_keyword() { addTestFile('library A; cl^'); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset - 2)); expect(replacementLength, equals(2)); assertHasResult(CompletionSuggestionKind.KEYWORD, 'export \'\';', selectionOffset: 8, relevance: DART_RELEVANCE_HIGH); assertHasResult(CompletionSuggestionKind.KEYWORD, 'class', relevance: DART_RELEVANCE_HIGH); }); } test_local_implicitCreation() async { addTestFile(''' class A { A(); A.named(); } main() { ^ } '''); await getSuggestions(); expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); // The class is suggested. assertHasResult(CompletionSuggestionKind.INVOCATION, 'A', elementKind: ElementKind.CLASS); // Both constructors - default and named, are suggested. assertHasResult(CompletionSuggestionKind.INVOCATION, 'A', elementKind: ElementKind.CONSTRUCTOR); assertHasResult(CompletionSuggestionKind.INVOCATION, 'A.named', elementKind: ElementKind.CONSTRUCTOR); } test_local_named_constructor() { addTestFile('class A {A.c(); x() {new A.^}}'); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'c'); assertNoResult('A'); }); } test_local_override() { newFile('/libA.dart', content: 'class A {m() {}}'); addTestFile(''' import '/libA.dart'; class B extends A { m() {} x() {^} } '''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'm', relevance: DART_RELEVANCE_LOCAL_METHOD); }); } test_local_shadowClass() async { addTestFile(''' class A { A(); A.named(); } main() { int A = 0; ^ } '''); await getSuggestions(); expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); // The class is suggested. assertHasResult(CompletionSuggestionKind.INVOCATION, 'A', relevance: DART_RELEVANCE_LOCAL_VARIABLE); // Class and all its constructors are shadowed by the local variable. assertNoResult('A', elementKind: ElementKind.CLASS); assertNoResult('A', elementKind: ElementKind.CONSTRUCTOR); assertNoResult('A.named', elementKind: ElementKind.CONSTRUCTOR); } test_locals() { addTestFile('class A {var a; x() {var b;^}} class DateTime { }'); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'A', elementKind: ElementKind.CLASS); assertHasResult(CompletionSuggestionKind.INVOCATION, 'a', relevance: DART_RELEVANCE_LOCAL_FIELD); assertHasResult(CompletionSuggestionKind.INVOCATION, 'b', relevance: DART_RELEVANCE_LOCAL_VARIABLE); assertHasResult(CompletionSuggestionKind.INVOCATION, 'x', relevance: DART_RELEVANCE_LOCAL_METHOD); assertHasResult(CompletionSuggestionKind.INVOCATION, 'DateTime', elementKind: ElementKind.CLASS); }); } test_offset_past_eof() async { addTestFile('main() { }', offset: 300); Request request = new CompletionGetSuggestionsParams(testFile, completionOffset) .toRequest('0'); Response response = await waitResponse(request); expect(response.id, '0'); expect(response.error.code, RequestErrorCode.INVALID_PARAMETER); } test_overrides() { newFile('/libA.dart', content: 'class A {m() {}}'); addTestFile(''' import '/libA.dart'; class B extends A {m() {^}} '''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'm', relevance: DART_RELEVANCE_LOCAL_METHOD); }); } test_partFile() { newFile('/project/bin/testA.dart', content: ''' library libA; part "${convertPathForImport(testFile)}"; import 'dart:html'; class A { } '''); addTestFile(''' part of libA; main() {^}'''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object', elementKind: ElementKind.CLASS); assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement', elementKind: ElementKind.CLASS); assertHasResult(CompletionSuggestionKind.INVOCATION, 'A', elementKind: ElementKind.CLASS); assertNoResult('test'); }); } test_partFile2() { newFile('/testA.dart', content: ''' part of libA; class A { }'''); addTestFile(''' library libA; part "${convertPathForImport("/testA.dart")}"; import 'dart:html'; main() {^} '''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object', elementKind: ElementKind.CLASS); assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement', elementKind: ElementKind.CLASS); assertHasResult(CompletionSuggestionKind.INVOCATION, 'A', elementKind: ElementKind.CLASS); assertNoResult('test'); }); } test_sentToPlugins() async { addTestFile(''' void main() { ^ } '''); PluginInfo info = new DiscoveredPluginInfo('a', 'b', 'c', null, null); plugin.CompletionGetSuggestionsResult result = new plugin.CompletionGetSuggestionsResult( testFile.indexOf('^'), 0, [ new CompletionSuggestion(CompletionSuggestionKind.IDENTIFIER, DART_RELEVANCE_DEFAULT, 'plugin completion', 3, 0, false, false) ]); pluginManager.broadcastResults = >{ info: new Future.value(result.toResponse('-', 1)) }; await getSuggestions(); assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'plugin completion', selectionOffset: 3); } test_simple() { addTestFile(''' void main() { ^ } '''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object', elementKind: ElementKind.CLASS); assertNoResult('HtmlElement'); assertNoResult('test'); }); } test_static() { addTestFile('class A {static b() {} c() {}} main() {A.^}'); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset)); expect(replacementLength, equals(0)); assertHasResult(CompletionSuggestionKind.INVOCATION, 'b'); assertNoResult('c'); }); } test_topLevel() { addTestFile(''' typedef foo(); var test = ''; main() {tes^t} '''); return getSuggestions().then((_) { expect(replacementOffset, equals(completionOffset - 3)); expect(replacementLength, equals(4)); // Suggestions based upon imported elements are partially filtered //assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object'); assertHasResult(CompletionSuggestionKind.INVOCATION, 'test', relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE); assertNoResult('HtmlElement'); }); } } class MockRelevancySorter implements DartContributionSorter { bool enabled = true; @override Future sort( CompletionRequest request, Iterable suggestions) { if (!enabled) { throw 'unexpected sort'; } return new Future.value(); } }