| // 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. |
| |
| library test.services.completion.suggestion; |
| |
| import 'dart:async'; |
| |
| import 'package:analysis_server/src/protocol.dart'; |
| import 'package:analysis_server/src/services/completion/completion_manager.dart'; |
| import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'; |
| import 'package:analysis_server/src/services/index/index.dart'; |
| import 'package:analysis_server/src/services/index/local_memory_index.dart'; |
| import 'package:analysis_server/src/services/search/search_engine.dart'; |
| import 'package:analysis_server/src/services/search/search_engine_internal.dart'; |
| import 'package:analyzer/src/generated/engine.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:unittest/unittest.dart'; |
| |
| import '../../abstract_single_unit.dart'; |
| import '../../reflective_tests.dart'; |
| |
| main() { |
| groupSep = ' | '; |
| runReflectiveTests(DartCompletionManagerTest); |
| } |
| |
| /** |
| * Returns a [Future] that completes after pumping the event queue [times] |
| * times. By default, this should pump the event queue enough times to allow |
| * any code to run, as long as it's not waiting on some external event. |
| */ |
| Future pumpEventQueue([int times = 20]) { |
| if (times == 0) return new Future.value(); |
| // We use a delayed future to allow microtask events to finish. The |
| // Future.value or Future() constructors use scheduleMicrotask themselves and |
| // would therefore not wait for microtask callbacks that are scheduled after |
| // invoking this method. |
| return new Future.delayed(Duration.ZERO, () => pumpEventQueue(times - 1)); |
| } |
| |
| @reflectiveTest |
| class DartCompletionManagerTest extends AbstractSingleUnitTest { |
| Index index; |
| SearchEngineImpl searchEngine; |
| Source source; |
| CompletionPerformance perf; |
| DartCompletionManager manager; |
| MockCompletionComputer computer1; |
| MockCompletionComputer computer2; |
| CompletionSuggestion suggestion1; |
| CompletionSuggestion suggestion2; |
| bool _continuePerformingAnalysis = true; |
| |
| void resolveLibrary() { |
| context.resolveCompilationUnit( |
| source, |
| context.computeLibraryElement(source)); |
| } |
| |
| @override |
| void setUp() { |
| super.setUp(); |
| index = createLocalMemoryIndex(); |
| searchEngine = new SearchEngineImpl(index); |
| source = addSource('/does/not/exist.dart', ''); |
| perf = new CompletionPerformance(); |
| manager = new DartCompletionManager.create(context, searchEngine, source); |
| suggestion1 = new CompletionSuggestion( |
| CompletionSuggestionKind.INVOCATION, |
| COMPLETION_RELEVANCE_DEFAULT, |
| "suggestion1", |
| 1, |
| 1, |
| false, |
| false); |
| suggestion2 = new CompletionSuggestion( |
| CompletionSuggestionKind.IDENTIFIER, |
| COMPLETION_RELEVANCE_DEFAULT, |
| "suggestion2", |
| 2, |
| 2, |
| false, |
| false); |
| new Future(_performAnalysis); |
| } |
| |
| @override |
| void tearDown() { |
| _continuePerformingAnalysis = false; |
| } |
| |
| test_compute_fastAndFull() { |
| computer1 = new MockCompletionComputer(suggestion1, null); |
| computer2 = new MockCompletionComputer(null, suggestion2); |
| manager.computers = [computer1, computer2]; |
| int count = 0; |
| bool done = false; |
| CompletionRequest completionRequest = new CompletionRequest(0, perf); |
| manager.results(completionRequest).listen((CompletionResult r) { |
| switch (++count) { |
| case 1: |
| computer1.assertCalls(context, source, 0, searchEngine); |
| computer2.assertCalls(context, source, 0, searchEngine); |
| expect(r.last, isFalse); |
| expect(r.suggestions, hasLength(1)); |
| expect(r.suggestions, contains(suggestion1)); |
| resolveLibrary(); |
| break; |
| case 2: |
| computer1.assertFull(0); |
| computer2.assertFull(1); |
| expect(r.last, isTrue); |
| expect(r.suggestions, hasLength(2)); |
| expect(r.suggestions, contains(suggestion1)); |
| expect(r.suggestions, contains(suggestion2)); |
| break; |
| default: |
| fail('unexpected'); |
| } |
| }, onDone: () { |
| done = true; |
| expect(count, equals(2)); |
| }); |
| return pumpEventQueue().then((_) { |
| expect(done, isTrue); |
| }); |
| } |
| |
| test_compute_fastOnly() { |
| computer1 = new MockCompletionComputer(suggestion1, null); |
| computer2 = new MockCompletionComputer(suggestion2, null); |
| manager.computers = [computer1, computer2]; |
| int count = 0; |
| bool done = false; |
| CompletionRequest completionRequest = new CompletionRequest(0, perf); |
| manager.results(completionRequest).listen((CompletionResult r) { |
| switch (++count) { |
| case 1: |
| computer1.assertCalls(context, source, 0, searchEngine); |
| computer2.assertCalls(context, source, 0, searchEngine); |
| expect(r.last, isTrue); |
| expect(r.suggestions, hasLength(2)); |
| expect(r.suggestions, contains(suggestion1)); |
| expect(r.suggestions, contains(suggestion2)); |
| break; |
| default: |
| fail('unexpected'); |
| } |
| }, onDone: () { |
| done = true; |
| expect(count, equals(1)); |
| }); |
| return pumpEventQueue().then((_) { |
| expect(done, isTrue); |
| }); |
| } |
| |
| void _performAnalysis() { |
| if (!_continuePerformingAnalysis) { |
| return; |
| } |
| context.performAnalysisTask(); |
| new Future(_performAnalysis); |
| } |
| } |
| |
| class MockCompletionComputer extends DartCompletionComputer { |
| final CompletionSuggestion fastSuggestion; |
| final CompletionSuggestion fullSuggestion; |
| int fastCount = 0; |
| int fullCount = 0; |
| DartCompletionRequest request; |
| |
| MockCompletionComputer(this.fastSuggestion, this.fullSuggestion); |
| |
| assertCalls(AnalysisContext context, Source source, int offset, |
| SearchEngine searchEngine) { |
| expect(request.context, equals(context)); |
| expect(request.source, equals(source)); |
| expect(request.offset, equals(offset)); |
| expect(request.searchEngine, equals(searchEngine)); |
| expect(this.fastCount, equals(1)); |
| expect(this.fullCount, equals(0)); |
| } |
| |
| assertFull(int fullCount) { |
| expect(this.fastCount, equals(1)); |
| expect(this.fullCount, equals(fullCount)); |
| } |
| |
| @override |
| bool computeFast(DartCompletionRequest request) { |
| this.request = request; |
| fastCount++; |
| if (fastSuggestion != null) { |
| request.suggestions.add(fastSuggestion); |
| } |
| return fastSuggestion != null; |
| } |
| |
| @override |
| Future<bool> computeFull(DartCompletionRequest request) { |
| this.request = request; |
| fullCount++; |
| if (fullSuggestion != null) { |
| request.suggestions.add(fullSuggestion); |
| } |
| return new Future.value(fullSuggestion != null); |
| } |
| } |