Files
sdk/pkg/analysis_server/test/client/completion_driver_test.dart
T
Brian Wilkerson 69dd787ff0 Cleanup invalid declarations of main, part 1
The purpose of this CL is to clean up test code that references `main`
in a way that will be invalid when the tests are converted to analyze
the test code under null safety by default. This is the first of three
such CLs.

In all three I only touched test files that contained an invalid use of
`main`, but in any file I touched I removed any use of `main` where the
name of the function/method was not critical to the test.

Change-Id: Ib753302a4c3ffc7eb5f248e9c6000e80dc77fca9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/205062
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
2021-06-28 18:13:24 +00:00

722 lines
17 KiB
Dart

// Copyright (c) 2020, 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 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:meta/meta.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../services/completion/dart/completion_contributor_util.dart';
import 'impl/completion_driver.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(BasicCompletionTest);
defineReflectiveTests(CompletionWithSuggestionsTest);
});
}
abstract class AbstractCompletionDriverTest with ResourceProviderMixin {
late CompletionDriver driver;
Map<String, String> packageRoots = {};
late List<CompletionSuggestion> suggestions;
String get projectName => 'project';
String get projectPath => '/$projectName';
AnalysisServerOptions get serverOptions => AnalysisServerOptions();
bool get supportsAvailableSuggestions;
String get testFilePath => '$projectPath/bin/test.dart';
Future<void> addProjectFile(String relativePath, String content) async {
newFile('$projectPath/$relativePath', content: content);
// todo (pq): handle more than lib
expect(relativePath, startsWith('lib/'));
var packageRelativePath = relativePath.substring(4);
var uriStr = 'package:$projectName/$packageRelativePath';
await driver.waitForSetWithUri(uriStr);
}
Future<List<CompletionSuggestion>> addTestFile(String content,
{int? offset}) async {
driver.addTestFile(content, offset: offset);
await getSuggestions();
// For sanity, ensure that there are no errors recorded for project files
// since that may lead to unexpected results.
_assertNoErrorsInProjectFiles();
return suggestions;
}
void assertNoSuggestion({
required String completion,
ElementKind? element,
CompletionSuggestionKind? kind,
String? file,
}) {
expect(
suggestionsWith(
completion: completion,
element: element,
kind: kind,
file: file,
),
isEmpty);
}
void assertSuggestion({
bool allowMultiple = false,
required String completion,
ElementKind? element,
CompletionSuggestionKind? kind,
String? file,
}) {
expect(
suggestionWith(
allowMultiple: allowMultiple,
completion: completion,
element: element,
kind: kind,
file: file,
),
isNotNull);
}
void assertSuggestions({
required String completion,
ElementKind? element,
CompletionSuggestionKind? kind,
String? file,
}) {
expect(
suggestionWith(
completion: completion,
element: element,
kind: kind,
file: file,
),
isNotNull);
}
Future<List<CompletionSuggestion>> getSuggestions() async {
if (supportsAvailableSuggestions) {
// todo (pq): consider moving
const internalLibs = [
'dart:async2',
'dart:_interceptors',
'dart:_internal',
];
for (var lib in driver.sdk.sdkLibraries) {
var uri = lib.shortName;
if (!internalLibs.contains(uri)) {
await driver.waitForSetWithUri(uri);
}
}
}
suggestions = await driver.getSuggestions();
return suggestions;
}
/// Display sorted suggestions.
void printSuggestions() {
suggestions.sort(completionComparator);
for (var s in suggestions) {
print(
'[${s.relevance}] ${s.completion}${s.element?.kind.name ?? ""} ${s.kind.name} ${s.element?.location?.file ?? ""}');
}
}
@mustCallSuper
void setUp() {
driver = CompletionDriver(
supportsAvailableSuggestions: supportsAvailableSuggestions,
projectPath: projectPath,
testFilePath: testFilePath,
resourceProvider: resourceProvider,
serverOptions: serverOptions,
);
driver.createProject(packageRoots: packageRoots);
newPubspecYamlFile(projectPath, '');
newDotPackagesFile(projectPath, content: '''
project:${toUri('$projectPath/lib')}
''');
// todo (pq): add logic (possibly to driver) that waits for SDK suggestions
}
SuggestionMatcher suggestionHas({
required String completion,
ElementKind? element,
CompletionSuggestionKind? kind,
String? file,
}) =>
(CompletionSuggestion s) {
if (s.completion != completion) {
return false;
}
if (element != null && s.element?.kind != element) {
return false;
}
if (kind != null && s.kind != kind) {
return false;
}
if (file != null && s.element?.location?.file != convertPath(file)) {
return false;
}
return true;
};
Iterable<CompletionSuggestion> suggestionsWith({
required String completion,
ElementKind? element,
CompletionSuggestionKind? kind,
String? file,
}) =>
suggestions.where(suggestionHas(
completion: completion, element: element, kind: kind, file: file));
CompletionSuggestion suggestionWith({
bool allowMultiple = false,
required String completion,
ElementKind? element,
CompletionSuggestionKind? kind,
String? file,
}) {
final matches = suggestionsWith(
completion: completion, element: element, kind: kind, file: file);
if (!allowMultiple) {
expect(matches, hasLength(1));
}
return matches.first;
}
void _assertNoErrorsInProjectFiles() {
var errors = <AnalysisError>[];
driver.filesErrors.forEach((file, fileErrors) {
// Completion test files are likely to be incomplete and so may have
// errors
if (file != convertPath(testFilePath)) {
errors.addAll(fileErrors);
}
});
expect(errors, isEmpty);
}
}
@reflectiveTest
class BasicCompletionTest extends AbstractCompletionDriverTest {
@override
bool get supportsAvailableSuggestions => false;
/// Duplicates (and potentially replaces DeprecatedMemberRelevanceTest).
Future<void> test_deprecated_member_relevance() async {
await addTestFile('''
class A {
void a1() { }
@deprecated
void a2() { }
}
void f() {
var a = A();
a.^
}
''');
expect(
suggestionWith(
completion: 'a2',
element: ElementKind.METHOD,
kind: CompletionSuggestionKind.INVOCATION)
.relevance,
lessThan(suggestionWith(
completion: 'a1',
element: ElementKind.METHOD,
kind: CompletionSuggestionKind.INVOCATION)
.relevance));
}
}
@reflectiveTest
class CompletionWithSuggestionsTest extends AbstractCompletionDriverTest {
@override
bool get supportsAvailableSuggestions => true;
@override
String get testFilePath => '$projectPath/lib/test.dart';
Future<void> test_project_filterImports_defaultConstructor() async {
await addProjectFile('lib/a.dart', r'''
class A {}
''');
await addProjectFile('lib/b.dart', r'''
export 'a.dart';
''');
await addTestFile('''
import 'a.dart';
void f() {
^
}
''');
// TODO(brianwilkerson) There should be a single suggestion here after we
// figure out how to stop the duplication.
assertSuggestion(
allowMultiple: true,
completion: 'A',
element: ElementKind.CONSTRUCTOR,
kind: CompletionSuggestionKind.INVOCATION);
}
/// See: https://github.com/dart-lang/sdk/issues/40620
Future<void> test_project_filterImports_enumValues() async {
await addProjectFile('lib/a.dart', r'''
enum E {
e,
}
''');
await addProjectFile('lib/b.dart', r'''
export 'a.dart';
''');
await addTestFile('''
import 'a.dart';
void f() {
^
}
''');
// TODO(brianwilkerson) There should be a single suggestion here after we
// figure out how to stop the duplication.
assertSuggestion(
allowMultiple: true,
completion: 'E.e',
element: ElementKind.ENUM_CONSTANT,
kind: CompletionSuggestionKind.INVOCATION);
}
/// See: https://github.com/dart-lang/sdk/issues/40620
Future<void> test_project_filterImports_namedConstructors() async {
await addProjectFile('lib/a.dart', r'''
class A {
A.a();
}
''');
await addProjectFile('lib/b.dart', r'''
export 'a.dart';
''');
await addTestFile('''
import 'a.dart';
void f() {
^
}
''');
// TODO(brianwilkerson) There should be a single suggestion here after we
// figure out how to stop the duplication.
assertSuggestion(
allowMultiple: true,
completion: 'A.a',
element: ElementKind.CONSTRUCTOR,
kind: CompletionSuggestionKind.INVOCATION);
}
Future<void> test_project_filterMultipleImports() async {
await addProjectFile('lib/a.dart', r'''
class A {}
''');
await addProjectFile('lib/b.dart', r'''
export 'a.dart';
''');
await addTestFile('''
import 'a.dart';
import 'b.dart';
void f() {
^
}
''');
assertSuggestion(
completion: 'A',
element: ElementKind.CLASS,
kind: CompletionSuggestionKind.INVOCATION);
}
Future<void> test_project_lib() async {
await addProjectFile('lib/a.dart', r'''
class A {}
enum E {
e,
}
extension Ex on A {}
mixin M { }
typedef T = Function(Object);
var v = 0;
''');
await addTestFile('''
void f() {
^
}
''');
assertSuggestion(
completion: 'A',
element: ElementKind.CONSTRUCTOR,
kind: CompletionSuggestionKind.INVOCATION);
assertSuggestion(
completion: 'A',
element: ElementKind.CLASS,
kind: CompletionSuggestionKind.INVOCATION);
assertSuggestion(
completion: 'E',
element: ElementKind.ENUM,
kind: CompletionSuggestionKind.INVOCATION);
assertSuggestion(
completion: 'Ex',
element: ElementKind.EXTENSION,
kind: CompletionSuggestionKind.INVOCATION);
assertSuggestion(
completion: 'M',
element: ElementKind.MIXIN,
kind: CompletionSuggestionKind.INVOCATION);
assertSuggestion(
completion: 'T',
element: ElementKind.FUNCTION_TYPE_ALIAS,
kind: CompletionSuggestionKind.INVOCATION);
assertSuggestion(
completion: 'v',
element: ElementKind.TOP_LEVEL_VARIABLE,
kind: CompletionSuggestionKind.INVOCATION);
}
Future<void> test_project_lib_fields_class() async {
await addProjectFile('lib/a.dart', r'''
class A {
int f = 0;
}
''');
await addTestFile('''
void m() {
^
}
''');
assertNoSuggestion(completion: 'f');
}
Future<void> test_project_lib_fields_static() async {
await addProjectFile('lib/a.dart', r'''
class A {
static int f = 0;
}
''');
await addTestFile('''
void f() {
^
}
''');
assertSuggestion(
completion: 'A.f',
element: ElementKind.FIELD,
kind: CompletionSuggestionKind.INVOCATION);
}
Future<void> test_project_lib_getters_class() async {
await addProjectFile('lib/a.dart', r'''
class A {
int get g => 0;
}
''');
await addTestFile('''
void f() {
^
}
''');
assertNoSuggestion(completion: 'g');
}
Future<void> test_project_lib_getters_static() async {
await addProjectFile('lib/a.dart', r'''
class A {
static int get g => 0;
}
''');
await addTestFile('''
void f() {
^
}
''');
assertSuggestion(
completion: 'A.g',
element: ElementKind.GETTER,
kind: CompletionSuggestionKind.INVOCATION);
}
/// See: https://github.com/dart-lang/sdk/issues/40626
Future<void> test_project_lib_getters_topLevel() async {
await addProjectFile('lib/a.dart', r'''
int get g => 0;
''');
await addTestFile('''
void f() {
^
}
''');
assertSuggestion(
completion: 'g',
element: ElementKind.GETTER,
kind: CompletionSuggestionKind.INVOCATION);
}
@failingTest
Future<void> test_project_lib_multipleExports() async {
await addProjectFile('lib/a.dart', r'''
class A {}
''');
await addProjectFile('lib/b.dart', r'''
export 'a.dart';
''');
await addTestFile('''
void f() {
^
}
''');
// Should only have one suggestion.
assertSuggestion(
completion: 'A',
element: ElementKind.CONSTRUCTOR,
kind: CompletionSuggestionKind.INVOCATION);
}
Future<void> test_project_lib_setters_class() async {
await addProjectFile('lib/a.dart', r'''
class A {
set s(int s) {}
}
''');
await addTestFile('''
void f() {
^
}
''');
assertNoSuggestion(completion: 's');
}
Future<void> test_project_lib_setters_static() async {
await addProjectFile('lib/a.dart', r'''
class A {
static set g(int g) {}
}
''');
await addTestFile('''
void f() {
^
}
''');
assertNoSuggestion(completion: 'A.g');
}
/// See: https://github.com/dart-lang/sdk/issues/40626
Future<void> test_project_lib_setters_topLevel() async {
await addProjectFile('lib/a.dart', r'''
set s(int s) {}
''');
await addTestFile('''
void f() {
^
}
''');
assertSuggestion(
completion: 's',
element: ElementKind.SETTER,
kind: CompletionSuggestionKind.INVOCATION);
}
@FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38739')
Future<void>
test_project_suggestionRelevance_constructorParameterType() async {
await addProjectFile('lib/a.dart', r'''
import 'b.dart';
class A {
A.b({O o});
}
''');
await addProjectFile('lib/b.dart', r'''
class O { }
''');
await addTestFile('''
import 'a.dart';
void f(List<String> args) {
var a = A.b(o: ^)
}
''');
expect(
suggestionWith(
completion: 'O',
element: ElementKind.CONSTRUCTOR,
kind: CompletionSuggestionKind.INVOCATION)
.relevance,
greaterThan(suggestionWith(
completion: 'args',
element: ElementKind.PARAMETER,
kind: CompletionSuggestionKind.INVOCATION)
.relevance));
}
Future<void> test_project_suggestionRelevance_constructorsAndTypes() async {
await addProjectFile('lib/a.dart', r'''
class A { }
''');
await addTestFile('''
import 'a.dart';
void f(List<String> args) {
var a = ^
}
''');
expect(
suggestionWith(
completion: 'A',
element: ElementKind.CONSTRUCTOR,
kind: CompletionSuggestionKind.INVOCATION)
.relevance,
greaterThan(suggestionWith(
completion: 'A',
element: ElementKind.CLASS,
kind: CompletionSuggestionKind.INVOCATION)
.relevance));
}
/// See: https://github.com/dart-lang/sdk/issues/35529
Future<void> test_project_suggestMixins() async {
await addProjectFile('lib/a.dart', r'''
mixin M { }
class A { }
''');
await addTestFile('''
class C extends Object with ^
''');
assertSuggestion(
completion: 'M',
element: ElementKind.MIXIN,
kind: CompletionSuggestionKind.INVOCATION);
assertSuggestion(
completion: 'A',
element: ElementKind.CLASS,
kind: CompletionSuggestionKind.INVOCATION);
}
Future<void> test_sdk_lib_future_isNotDuplicated() async {
await addTestFile('''
void f() {
^
}
''');
// TODO(brianwilkerson) There should be a single suggestion here after we
// figure out how to stop the duplication.
expect(
suggestionsWith(
completion: 'Future.value',
file: '/sdk/lib/async/async.dart',
element: ElementKind.CONSTRUCTOR,
kind: CompletionSuggestionKind.INVOCATION),
hasLength(2));
}
Future<void> test_sdk_lib_suggestions() async {
await addTestFile('''
void f() {
^
}
''');
// A kind-filtered set of SDK suggestions.
// Constructors should be visible.
assertSuggestion(
completion: 'Timer',
file: '/sdk/lib/async/async.dart',
element: ElementKind.CONSTRUCTOR,
kind: CompletionSuggestionKind.INVOCATION);
// But not methods.
assertNoSuggestion(
// dart:async (StreamSubscription)
completion: 'asFuture',
element: ElementKind.METHOD,
kind: CompletionSuggestionKind.INVOCATION);
// + Functions.
assertSuggestion(
completion: 'print',
file: '/sdk/lib/core/core.dart',
element: ElementKind.FUNCTION,
kind: CompletionSuggestionKind.INVOCATION);
assertSuggestion(
completion: 'tan',
file: '/sdk/lib/math/math.dart',
element: ElementKind.FUNCTION,
kind: CompletionSuggestionKind.INVOCATION);
// + Classes.
assertSuggestion(
completion: 'HashMap',
file: '/sdk/lib/collection/collection.dart',
element: ElementKind.CLASS,
kind: CompletionSuggestionKind.INVOCATION);
// + Top level variables.
assertSuggestion(
completion: 'pi',
file: '/sdk/lib/math/math.dart',
element: ElementKind.TOP_LEVEL_VARIABLE,
kind: CompletionSuggestionKind.INVOCATION);
// (No typedefs, enums, extensions defined in the Mock SDK.)
}
}