blob: 15562d6bc53ff955f0ed81dc471f91a30d9ff5a5 [file] [log] [blame]
// 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/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/completion/dart_completion_manager.dart';
import 'package:analysis_server/src/services/search/search_engine_internal.dart';
import 'package:analysis_testing/abstract_single_unit.dart';
import 'package:analysis_testing/reflective_tests.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:unittest/unittest.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));
}
@ReflectiveTestCase()
class DartCompletionManagerTest extends AbstractSingleUnitTest {
Index index;
SearchEngineImpl searchEngine;
Source source;
DartCompletionManager manager;
MockCompletionComputer computer1;
MockCompletionComputer computer2;
CompletionSuggestion suggestion1;
CompletionSuggestion suggestion2;
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', '');
manager = new DartCompletionManager(context, searchEngine, source, 17);
suggestion1 = new CompletionSuggestion(
CompletionSuggestionKind.CLASS,
CompletionRelevance.DEFAULT,
"suggestion1",
1,
1,
false,
false);
suggestion2 = new CompletionSuggestion(
CompletionSuggestionKind.CLASS,
CompletionRelevance.DEFAULT,
"suggestion2",
2,
2,
false,
false);
}
test_compute_fastAndFull() {
computer1 = new MockCompletionComputer(suggestion1, null);
computer2 = new MockCompletionComputer(null, suggestion2);
manager.computers = [computer1, computer2];
int count = 0;
bool done = false;
manager.results().listen((CompletionResult r) {
switch (++count) {
case 1:
computer1.assertCalls(context, source, 17, searchEngine);
computer2.assertCalls(context, source, 17, 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;
manager.results().listen((CompletionResult r) {
switch (++count) {
case 1:
computer1.assertCalls(context, source, 17, searchEngine);
computer2.assertCalls(context, source, 17, 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);
});
}
}
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);
}
}