| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library test.services.completion.suggestion; | 5 library test.services.completion.suggestion; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:analysis_services/completion/completion_computer.dart'; | 9 import 'package:analysis_services/completion/completion_manager.dart'; |
| 10 import 'package:analysis_services/completion/completion_suggestion.dart'; | 10 import 'package:analysis_services/completion/completion_suggestion.dart'; |
| 11 import 'package:analysis_services/index/index.dart'; | 11 import 'package:analysis_services/index/index.dart'; |
| 12 import 'package:analysis_services/index/local_memory_index.dart'; | 12 import 'package:analysis_services/index/local_memory_index.dart'; |
| 13 import 'package:analysis_services/search/search_engine.dart'; | 13 import 'package:analysis_services/search/search_engine.dart'; |
| 14 import 'package:analysis_services/src/completion/dart_completion_manager.dart'; | 14 import 'package:analysis_services/src/completion/dart_completion_manager.dart'; |
| 15 import 'package:analysis_services/src/search/search_engine.dart'; | 15 import 'package:analysis_services/src/search/search_engine.dart'; |
| 16 import 'package:analysis_testing/abstract_context.dart'; | |
| 17 import 'package:analysis_testing/abstract_single_unit.dart'; | 16 import 'package:analysis_testing/abstract_single_unit.dart'; |
| 18 import 'package:analysis_testing/reflective_tests.dart'; | 17 import 'package:analysis_testing/reflective_tests.dart'; |
| 19 import 'package:analyzer/src/generated/ast.dart'; | |
| 20 import 'package:analyzer/src/generated/engine.dart'; | 18 import 'package:analyzer/src/generated/engine.dart'; |
| 21 import 'package:analyzer/src/generated/source.dart'; | 19 import 'package:analyzer/src/generated/source.dart'; |
| 22 import 'package:unittest/unittest.dart'; | 20 import 'package:unittest/unittest.dart'; |
| 23 | 21 |
| 24 main() { | 22 main() { |
| 25 groupSep = ' | '; | 23 groupSep = ' | '; |
| 26 runReflectiveTests(CompletionManagerTest); | |
| 27 runReflectiveTests(DartCompletionManagerTest); | 24 runReflectiveTests(DartCompletionManagerTest); |
| 28 } | 25 } |
| 29 | 26 |
| 30 /** | 27 /** |
| 31 * Returns a [Future] that completes after pumping the event queue [times] | 28 * Returns a [Future] that completes after pumping the event queue [times] |
| 32 * times. By default, this should pump the event queue enough times to allow | 29 * times. By default, this should pump the event queue enough times to allow |
| 33 * any code to run, as long as it's not waiting on some external event. | 30 * any code to run, as long as it's not waiting on some external event. |
| 34 */ | 31 */ |
| 35 Future pumpEventQueue([int times = 20]) { | 32 Future pumpEventQueue([int times = 20]) { |
| 36 if (times == 0) return new Future.value(); | 33 if (times == 0) return new Future.value(); |
| 37 // We use a delayed future to allow microtask events to finish. The | 34 // We use a delayed future to allow microtask events to finish. The |
| 38 // Future.value or Future() constructors use scheduleMicrotask themselves and | 35 // Future.value or Future() constructors use scheduleMicrotask themselves and |
| 39 // would therefore not wait for microtask callbacks that are scheduled after | 36 // would therefore not wait for microtask callbacks that are scheduled after |
| 40 // invoking this method. | 37 // invoking this method. |
| 41 return new Future.delayed(Duration.ZERO, () => pumpEventQueue(times - 1)); | 38 return new Future.delayed(Duration.ZERO, () => pumpEventQueue(times - 1)); |
| 42 } | 39 } |
| 43 | 40 |
| 44 @ReflectiveTestCase() | 41 @ReflectiveTestCase() |
| 45 class CompletionManagerTest extends AbstractContextTest { | |
| 46 | |
| 47 test_dart() { | |
| 48 Source source = addSource('/does/not/exist.dart', ''); | |
| 49 var manager = CompletionManager.create(context, source, 0, null); | |
| 50 expect(manager.runtimeType, DartCompletionManager); | |
| 51 } | |
| 52 | |
| 53 test_html() { | |
| 54 Source source = addSource('/does/not/exist.html', ''); | |
| 55 var manager = CompletionManager.create(context, source, 0, null); | |
| 56 expect(manager.runtimeType, NoOpCompletionManager); | |
| 57 } | |
| 58 | |
| 59 test_null_context() { | |
| 60 Source source = addSource('/does/not/exist.dart', ''); | |
| 61 var manager = CompletionManager.create(null, source, 0, null); | |
| 62 expect(manager.runtimeType, NoOpCompletionManager); | |
| 63 } | |
| 64 | |
| 65 test_other() { | |
| 66 Source source = addSource('/does/not/exist.foo', ''); | |
| 67 var manager = CompletionManager.create(context, source, 0, null); | |
| 68 expect(manager.runtimeType, NoOpCompletionManager); | |
| 69 } | |
| 70 } | |
| 71 | |
| 72 @ReflectiveTestCase() | |
| 73 class DartCompletionManagerTest extends AbstractSingleUnitTest { | 42 class DartCompletionManagerTest extends AbstractSingleUnitTest { |
| 74 Index index; | 43 Index index; |
| 75 SearchEngineImpl searchEngine; | 44 SearchEngineImpl searchEngine; |
| 76 Source source; | 45 Source source; |
| 77 DartCompletionManager manager; | 46 DartCompletionManager manager; |
| 78 MockCompletionComputer computer1; | 47 MockCompletionComputer computer1; |
| 79 MockCompletionComputer computer2; | 48 MockCompletionComputer computer2; |
| 80 CompletionSuggestion suggestion1; | 49 CompletionSuggestion suggestion1; |
| 81 CompletionSuggestion suggestion2; | 50 CompletionSuggestion suggestion2; |
| 82 | 51 |
| 52 void resolveLibrary() { |
| 53 context.resolveCompilationUnit( |
| 54 source, |
| 55 context.computeLibraryElement(source)); |
| 56 } |
| 57 |
| 83 @override | 58 @override |
| 84 void setUp() { | 59 void setUp() { |
| 85 super.setUp(); | 60 super.setUp(); |
| 86 index = createLocalMemoryIndex(); | 61 index = createLocalMemoryIndex(); |
| 87 searchEngine = new SearchEngineImpl(index); | 62 searchEngine = new SearchEngineImpl(index); |
| 88 source = addSource('/does/not/exist.dart', ''); | 63 source = addSource('/does/not/exist.dart', ''); |
| 89 manager = new DartCompletionManager(context, source, 17, searchEngine); | 64 manager = new DartCompletionManager(context, searchEngine, source, 17); |
| 90 suggestion1 = new CompletionSuggestion( | 65 suggestion1 = new CompletionSuggestion( |
| 91 CompletionSuggestionKind.CLASS, | 66 CompletionSuggestionKind.CLASS, |
| 92 CompletionRelevance.DEFAULT, | 67 CompletionRelevance.DEFAULT, |
| 93 "suggestion1", | 68 "suggestion1", |
| 94 1, | 69 1, |
| 95 1, | 70 1, |
| 96 false, | 71 false, |
| 97 false); | 72 false); |
| 98 suggestion2 = new CompletionSuggestion( | 73 suggestion2 = new CompletionSuggestion( |
| 99 CompletionSuggestionKind.CLASS, | 74 CompletionSuggestionKind.CLASS, |
| 100 CompletionRelevance.DEFAULT, | 75 CompletionRelevance.DEFAULT, |
| 101 "suggestion2", | 76 "suggestion2", |
| 102 2, | 77 2, |
| 103 2, | 78 2, |
| 104 false, | 79 false, |
| 105 false); | 80 false); |
| 106 } | 81 } |
| 107 | 82 |
| 108 test_compute_fastOnly() { | 83 test_compute_fastAndFull() { |
| 109 computer1 = new MockCompletionComputer(suggestion1, null); | 84 computer1 = new MockCompletionComputer(suggestion1, null); |
| 110 computer2 = new MockCompletionComputer(suggestion2, null); | 85 computer2 = new MockCompletionComputer(null, suggestion2); |
| 111 manager.computers = [computer1, computer2]; | 86 manager.computers = [computer1, computer2]; |
| 112 int count = 0; | 87 int count = 0; |
| 113 bool done = false; | 88 bool done = false; |
| 114 manager.results().listen((CompletionResult r) { | 89 manager.results().listen((CompletionResult r) { |
| 115 switch (++count) { | 90 switch (++count) { |
| 116 case 1: | 91 case 1: |
| 117 computer1.assertCalls(context, source, 17, searchEngine); | 92 computer1.assertCalls(context, source, 17, searchEngine); |
| 118 computer2.assertCalls(context, source, 17, searchEngine); | 93 computer2.assertCalls(context, source, 17, searchEngine); |
| 94 expect(r.last, isFalse); |
| 95 expect(r.suggestions, hasLength(1)); |
| 96 expect(r.suggestions, contains(suggestion1)); |
| 97 resolveLibrary(); |
| 98 break; |
| 99 case 2: |
| 100 computer1.assertFull(0); |
| 101 computer2.assertFull(1); |
| 119 expect(r.last, isTrue); | 102 expect(r.last, isTrue); |
| 120 expect(r.suggestions, hasLength(2)); | 103 expect(r.suggestions, hasLength(2)); |
| 121 expect(r.suggestions, contains(suggestion1)); | 104 expect(r.suggestions, contains(suggestion1)); |
| 122 expect(r.suggestions, contains(suggestion2)); | 105 expect(r.suggestions, contains(suggestion2)); |
| 123 break; | 106 break; |
| 124 default: | 107 default: |
| 125 fail('unexpected'); | 108 fail('unexpected'); |
| 126 } | 109 } |
| 127 }, onDone: () { | 110 }, onDone: () { |
| 128 done = true; | 111 done = true; |
| 129 expect(count, equals(1)); | 112 expect(count, equals(2)); |
| 130 }); | 113 }); |
| 131 return pumpEventQueue().then((_) { | 114 return pumpEventQueue().then((_) { |
| 132 expect(done, isTrue); | 115 expect(done, isTrue); |
| 133 }); | 116 }); |
| 134 } | 117 } |
| 135 | 118 |
| 136 test_compute_fastAndFull() { | 119 test_compute_fastOnly() { |
| 137 computer1 = new MockCompletionComputer(suggestion1, null); | 120 computer1 = new MockCompletionComputer(suggestion1, null); |
| 138 computer2 = new MockCompletionComputer(null, suggestion2); | 121 computer2 = new MockCompletionComputer(suggestion2, null); |
| 139 manager.computers = [computer1, computer2]; | 122 manager.computers = [computer1, computer2]; |
| 140 int count = 0; | 123 int count = 0; |
| 141 bool done = false; | 124 bool done = false; |
| 142 manager.results().listen((CompletionResult r) { | 125 manager.results().listen((CompletionResult r) { |
| 143 switch (++count) { | 126 switch (++count) { |
| 144 case 1: | 127 case 1: |
| 145 computer1.assertCalls(context, source, 17, searchEngine); | 128 computer1.assertCalls(context, source, 17, searchEngine); |
| 146 computer2.assertCalls(context, source, 17, searchEngine); | 129 computer2.assertCalls(context, source, 17, searchEngine); |
| 147 expect(r.last, isFalse); | |
| 148 expect(r.suggestions, hasLength(1)); | |
| 149 expect(r.suggestions, contains(suggestion1)); | |
| 150 resolveLibrary(); | |
| 151 break; | |
| 152 case 2: | |
| 153 computer1.assertFull(0); | |
| 154 computer2.assertFull(1); | |
| 155 expect(r.last, isTrue); | 130 expect(r.last, isTrue); |
| 156 expect(r.suggestions, hasLength(2)); | 131 expect(r.suggestions, hasLength(2)); |
| 157 expect(r.suggestions, contains(suggestion1)); | 132 expect(r.suggestions, contains(suggestion1)); |
| 158 expect(r.suggestions, contains(suggestion2)); | 133 expect(r.suggestions, contains(suggestion2)); |
| 159 break; | 134 break; |
| 160 default: | 135 default: |
| 161 fail('unexpected'); | 136 fail('unexpected'); |
| 162 } | 137 } |
| 163 }, onDone: () { | 138 }, onDone: () { |
| 164 done = true; | 139 done = true; |
| 165 expect(count, equals(2)); | 140 expect(count, equals(1)); |
| 166 }); | 141 }); |
| 167 return pumpEventQueue().then((_) { | 142 return pumpEventQueue().then((_) { |
| 168 expect(done, isTrue); | 143 expect(done, isTrue); |
| 169 }); | 144 }); |
| 170 } | 145 } |
| 171 | |
| 172 void resolveLibrary() { | |
| 173 context.resolveCompilationUnit( | |
| 174 source, | |
| 175 context.computeLibraryElement(source)); | |
| 176 } | |
| 177 } | 146 } |
| 178 | 147 |
| 179 class MockCompletionComputer extends CompletionComputer { | 148 class MockCompletionComputer extends DartCompletionComputer { |
| 180 final CompletionSuggestion fastSuggestion; | 149 final CompletionSuggestion fastSuggestion; |
| 181 final CompletionSuggestion fullSuggestion; | 150 final CompletionSuggestion fullSuggestion; |
| 182 int fastCount = 0; | 151 int fastCount = 0; |
| 183 int fullCount = 0; | 152 int fullCount = 0; |
| 153 DartCompletionRequest request; |
| 184 | 154 |
| 185 MockCompletionComputer(this.fastSuggestion, this.fullSuggestion); | 155 MockCompletionComputer(this.fastSuggestion, this.fullSuggestion); |
| 186 | 156 |
| 187 assertCalls(AnalysisContext context, Source source, int offset, | 157 assertCalls(AnalysisContext context, Source source, int offset, |
| 188 SearchEngine searchEngine) { | 158 SearchEngine searchEngine) { |
| 189 expect(this.context, equals(context)); | 159 expect(request.context, equals(context)); |
| 190 expect(this.source, equals(source)); | 160 expect(request.source, equals(source)); |
| 191 expect(this.offset, equals(offset)); | 161 expect(request.offset, equals(offset)); |
| 192 expect(this.searchEngine, equals(searchEngine)); | 162 expect(request.searchEngine, equals(searchEngine)); |
| 193 expect(this.fastCount, equals(1)); | 163 expect(this.fastCount, equals(1)); |
| 194 expect(this.fullCount, equals(0)); | 164 expect(this.fullCount, equals(0)); |
| 195 } | 165 } |
| 196 | 166 |
| 197 assertFull(int fullCount) { | 167 assertFull(int fullCount) { |
| 198 expect(this.fastCount, equals(1)); | 168 expect(this.fastCount, equals(1)); |
| 199 expect(this.fullCount, equals(fullCount)); | 169 expect(this.fullCount, equals(fullCount)); |
| 200 } | 170 } |
| 201 | 171 |
| 202 @override | 172 @override |
| 203 bool computeFast(CompilationUnit unit, AstNode node, | 173 bool computeFast(DartCompletionRequest request) { |
| 204 List<CompletionSuggestion> suggestions) { | 174 this.request = request; |
| 205 fastCount++; | 175 fastCount++; |
| 206 if (fastSuggestion != null) { | 176 if (fastSuggestion != null) { |
| 207 suggestions.add(fastSuggestion); | 177 request.suggestions.add(fastSuggestion); |
| 208 } | 178 } |
| 209 return fastSuggestion != null; | 179 return fastSuggestion != null; |
| 210 } | 180 } |
| 211 | 181 |
| 212 @override | 182 @override |
| 213 Future<bool> computeFull(CompilationUnit unit, AstNode node, | 183 Future<bool> computeFull(DartCompletionRequest request) { |
| 214 List<CompletionSuggestion> suggestions) { | 184 this.request = request; |
| 215 fullCount++; | 185 fullCount++; |
| 216 if (fullSuggestion != null) { | 186 if (fullSuggestion != null) { |
| 217 suggestions.add(fullSuggestion); | 187 request.suggestions.add(fullSuggestion); |
| 218 } | 188 } |
| 219 return new Future.value(fullSuggestion != null); | 189 return new Future.value(fullSuggestion != null); |
| 220 } | 190 } |
| 221 } | 191 } |
| OLD | NEW |