[analysis_server] Update setState + closure completions to use the correct line endings
+ update completion tests to always use normalized code
Change-Id: If6e2f838f23c8cdbb0590a7e408d51897d8b4a46
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/443560
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/candidate_suggestion.dart b/pkg/analysis_server/lib/src/services/completion/dart/candidate_suggestion.dart
index 0304159..4ce4e5d 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/candidate_suggestion.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/candidate_suggestion.dart
@@ -81,6 +81,9 @@
/// The identation to be used for a multi-line completion.
final String indent;
+ /// The EOL marker to be used for a multi-line completion.
+ final String endOfLine;
+
/// Initialize a newly created candidate suggestion to suggest a closure that
/// conforms to the given [functionType].
///
@@ -92,6 +95,7 @@
required super.matcherScore,
required this.includeTypes,
required this.indent,
+ required this.endOfLine,
this.useBlockStatement = true,
});
@@ -125,10 +129,11 @@
int selectionOffset;
if (useBlockStatement) {
displayText = '$parametersDisplayString {}';
- stringBuffer.writeln(' {');
+ stringBuffer.write(' {');
+ stringBuffer.write(endOfLine);
stringBuffer.write('$indent ');
selectionOffset = stringBuffer.length;
- stringBuffer.writeln();
+ stringBuffer.write(endOfLine);
stringBuffer.write('$indent}');
} else {
displayText = '$parametersDisplayString =>';
@@ -981,11 +986,15 @@
/// The identation to be used for a multi-line completion.
final String indent;
+ /// The EOL marker to be used for a multi-line completion.
+ final String endOfLine;
+
/// Initialize a newly created candidate suggestion to suggest the [element].
SetStateMethodSuggestion({
required this.element,
required this.referencingInterface,
required this.indent,
+ required this.endOfLine,
required super.importData,
required super.matcherScore,
required super.replacementRange,
@@ -1011,10 +1020,11 @@
// Build the completion and the selection offset.
var buffer = StringBuffer();
- buffer.writeln('setState(() {');
+ buffer.write('setState(() {');
+ buffer.write(endOfLine);
buffer.write('$indent ');
var selectionOffset = buffer.length;
- buffer.writeln();
+ buffer.write(endOfLine);
buffer.write('$indent});');
var completion = buffer.toString();
_data = _Data(completion, selectionOffset, displayText: 'setState(() {});');
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart
index d6badd2..47ed054 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_state.dart
@@ -2,6 +2,8 @@
// 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:io';
+
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analysis_server_plugin/src/utilities/selection.dart';
@@ -11,6 +13,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/utilities/completion_matcher.dart';
+import 'package:analyzer_plugin/src/utilities/extensions/string_extension.dart';
/// The information used to compute the suggestions for a completion request.
class CompletionState {
@@ -47,6 +50,9 @@
return selection.coveringNode.thisOrAncestorOfType<ClassMember>();
}
+ /// The EOL marker for the completion text.
+ String get endOfLine => request.content.endOfLine ?? Platform.lineTerminator;
+
/// Indicates if types should be specified whenever possible.
bool get includeTypes => codeStyleOptions.specifyTypes;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
index d63b802..d6e9e5a 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
@@ -2058,6 +2058,7 @@
referencingInterface: referencingInterface,
matcherScore: matcherScore,
indent: state.indent,
+ endOfLine: state.endOfLine,
addTypeAnnotation: addTypeAnnotation,
keyword: keyword,
);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart
index 6532d63..4c6299b 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart
@@ -3300,6 +3300,7 @@
matcherScore: 0.0,
includeTypes: includeTypes,
indent: state.indent,
+ endOfLine: state.endOfLine,
),
);
collector.addSuggestion(
@@ -3310,6 +3311,7 @@
useBlockStatement: false,
includeTypes: includeTypes,
indent: state.indent,
+ endOfLine: state.endOfLine,
),
);
}
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index 65cb0b3..1aa6c242 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -63,6 +63,9 @@
abstract class AbstractCompletionTest extends AbstractLspAnalysisServerTest
with CompletionTestMixin {
+ late String content;
+ late final code = TestCode.parseNormalized(content);
+
AbstractCompletionTest() {
defaultInitializationOptions = {
// Default to a high budget for tests because everything is cold and
@@ -91,7 +94,7 @@
void _enableLints(List<String> lintNames) {
registerLintRules();
- var lintsYaml = lintNames.map((name) => ' - $name\n').join();
+ var lintsYaml = lintNames.map((name) => ' - $name$eol').join();
newFile(analysisOptionsPath, '''
linter:
rules:
@@ -102,9 +105,6 @@
@reflectiveTest
class CompletionDocumentationResolutionTest extends AbstractCompletionTest {
- late String content;
- late final code = TestCode.parse(content);
-
Future<CompletionItem> getCompletionItem(String label) async {
var completions = await getCompletion(mainFileUri, code.position.position);
return completions.singleWhere((c) => c.label == label);
@@ -269,7 +269,6 @@
''';
await initializeServer();
- var code = TestCode.parse(content);
var completion = await getCompletionItem('value');
expect(completion, isNotNull);
@@ -282,7 +281,7 @@
]);
expect(
newContent,
- equals('''
+ equalsNormalized('''
class A {
A([this.value]);
A? value;
@@ -305,7 +304,6 @@
''';
await initializeServer();
- var code = TestCode.parse(content);
var completion = await getCompletionItem('name');
expect(completion, isNotNull);
@@ -318,7 +316,7 @@
]);
expect(
newContent,
- equals('''
+ equalsNormalized('''
void f(({int name, int other}) r) {
if (r case (:var name)) {}
}
@@ -342,7 +340,7 @@
''';
_enableLints([LintNames.always_specify_types]);
await initializeServer();
- var code = TestCode.parse(content);
+
var completion = await getCompletionItem('name');
expect(completion, isNotNull);
var resolved = await resolveCompletion(completion);
@@ -351,7 +349,7 @@
]);
expect(
newContent,
- equals('''
+ equalsNormalized('''
import 'my_types.dart' hide MyType2;
void f(Other r) {
@@ -378,7 +376,7 @@
''';
_enableLints([LintNames.always_specify_types]);
await initializeServer();
- var code = TestCode.parse(content);
+
var completion = await getCompletionItem('name');
var resolved = await resolveCompletion(completion);
var newContent = applyTextEdits(
@@ -389,7 +387,7 @@
);
expect(
newContent,
- equals('''
+ equalsNormalized('''
import 'package:test/my_types.dart';
import 'other.dart';
@@ -416,7 +414,7 @@
''';
_enableLints([LintNames.always_specify_types]);
await initializeServer();
- var code = TestCode.parse(content);
+
var completion = await getCompletionItem('name');
expect(completion, isNotNull);
var resolved = await resolveCompletion(completion);
@@ -425,7 +423,7 @@
]);
expect(
newContent,
- equals('''
+ equalsNormalized('''
import 'my_types.dart' show Other, MyType;
void f(Other r) {
@@ -449,7 +447,7 @@
''';
_enableLints([LintNames.always_specify_types]);
await initializeServer();
- var code = TestCode.parse(content);
+
var completion = await getCompletionItem('name');
expect(completion, isNotNull);
var resolved = await resolveCompletion(completion);
@@ -458,7 +456,7 @@
]);
expect(
newContent,
- equals('''
+ equalsNormalized('''
import 'my_types.dart' as t;
void f(t.Other r) {
@@ -509,7 +507,6 @@
}) async {
completionFileUri ??= mainFileUri;
- var code = TestCode.parse(content);
await initialize();
await openFile(completionFileUri, code.code);
@@ -533,7 +530,7 @@
if (completion == null) {
fail(
'Did not find completion "$label" with detail "$detail" in completion results:'
- '\n ${completions.map((c) => '${c.label} (${c.detail})').join('\n ')}',
+ '$eol ${completions.map((c) => '${c.label} (${c.detail})').join('$eol ')}',
);
}
@@ -583,7 +580,7 @@
}
Future<void> test_combinator_function() async {
- var content = '''
+ content = '''
import 'dart:math' show min^
''';
@@ -598,7 +595,7 @@
}
Future<void> test_constructor_argument() async {
- var content = '''
+ content = '''
var a = Foo(^);
class Foo {
@@ -618,7 +615,7 @@
}
Future<void> test_constructor_factory_argument() async {
- var content = '''
+ content = '''
var a = Foo(^);
class Foo {
@@ -642,7 +639,7 @@
newFile(fileAPath, '''
String a(String a, {String b}) {}
''');
- var content = '''
+ content = '''
import 'a.dart';
void f() {
a^
@@ -663,7 +660,7 @@
newFile(fileAPath, '''
String a() {}
''');
- var content = '''
+ content = '''
import 'a.dart';
String f() {
a^
@@ -684,7 +681,7 @@
newFile(fileAPath, '''
void a(String a, {String b}) {}
''');
- var content = '''
+ content = '''
import 'a.dart';
void f() {
a^
@@ -705,7 +702,7 @@
newFile(fileAPath, '''
void a() {}
''');
- var content = '''
+ content = '''
import 'a.dart';
void f() {
a^
@@ -723,7 +720,7 @@
}
Future<void> test_local_function_returnType_args() async {
- var content = '''
+ content = '''
String f(String a, {String b}) {
f^
}
@@ -739,7 +736,7 @@
}
Future<void> test_local_function_returnType_noArgs() async {
- var content = '''
+ content = '''
String f() {
f^
}
@@ -756,7 +753,7 @@
}
Future<void> test_local_function_void_args() async {
- var content = '''
+ content = '''
void f(String a, {String b}) {
f^
}
@@ -773,7 +770,7 @@
}
Future<void> test_local_function_void_noArgs() async {
- var content = '''
+ content = '''
void f() {
f^
}
@@ -790,7 +787,7 @@
}
Future<void> test_local_getter() async {
- var content = '''
+ content = '''
String a => '';
void f() {
a^
@@ -807,7 +804,7 @@
}
Future<void> test_local_getterAndSetter() async {
- var content = '''
+ content = '''
set a(String value) {}
String get a => '';
void f() {
@@ -825,7 +822,7 @@
}
Future<void> test_local_override_annotation_equals() async {
- var content = '''
+ content = '''
class Base {
}
@@ -844,7 +841,7 @@
}
Future<void> test_local_override_annotation_method() async {
- var content = '''
+ content = '''
class Base {
String aa(String a) => '';
}
@@ -867,7 +864,7 @@
///
/// https://github.com/dart-lang/sdk/issues/59929
Future<void> test_local_override_getterAndSetter() async {
- var content = '''
+ content = '''
class A {
int? value;
}
@@ -900,7 +897,7 @@
}
Future<void> test_local_override_name() async {
- var content = '''
+ content = '''
class Base {
String aa(String a) => '';
}
@@ -920,7 +917,7 @@
}
Future<void> test_local_setter() async {
- var content = '''
+ content = '''
set a(String value) {}
void f() {
a^
@@ -940,7 +937,7 @@
newFile(fileAPath, '''
String a(String a, {String b}) {}
''');
- var content = '''
+ content = '''
void f() {
a^
}
@@ -961,7 +958,7 @@
newFile(fileAPath, '''
String a() {}
''');
- var content = '''
+ content = '''
String f() {
a^
}
@@ -982,7 +979,7 @@
newFile(fileAPath, '''
void a(String a, {String b}) {}
''');
- var content = '''
+ content = '''
void f() {
a^
}
@@ -1003,7 +1000,7 @@
newFile(fileAPath, '''
void a() {}
''');
- var content = '''
+ content = '''
void f() {
a^
}
@@ -1027,7 +1024,7 @@
newFile(testFileAPath, '''
void a(String a, {String b}) {}
''');
- var content = '''
+ content = '''
void f() {
a^
}
@@ -1046,7 +1043,7 @@
}
Future<void> test_nullNotEmpty() async {
- var content = '''
+ content = '''
bool a = ^
''';
@@ -1063,7 +1060,7 @@
}
Future<void> test_record() async {
- var content = r'''
+ content = r'''
void f((int, int) record) {
record.$^
}
@@ -1080,7 +1077,7 @@
}
Future<void> test_variable() async {
- var content = r'''
+ content = r'''
void f(int variable) {
varia^
}
@@ -1106,7 +1103,7 @@
required bool includesSummary,
required bool includesFull,
}) async {
- var content = '''
+ content = '''
/// Summary.
///
/// Full.
@@ -1118,7 +1115,7 @@
await provideConfig(initialize, {
if (preference != null) 'documentation': preference,
});
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -1151,7 +1148,7 @@
class InOtherFile {}
''');
- var content = '''
+ content = '''
void f() {
InOtherF^
}
@@ -1160,7 +1157,7 @@
await provideConfig(initialize, {
if (preference != null) 'documentation': preference,
});
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -1190,9 +1187,11 @@
required String? editText,
InsertTextFormat? insertTextFormat,
}) async {
+ this.content = content;
+
setCompletionItemSnippetSupport();
await provideConfig(initialize, {'completeFunctionCalls': true});
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var item = res.singleWhere(
@@ -1230,7 +1229,7 @@
String colorHex,
) async {
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var completion = res.singleWhere((c) => c.label == label);
@@ -1245,7 +1244,7 @@
(markup) => markup.value,
(string) => string,
);
- expect(docs, anyOf(equals(colorHex), endsWith('\n\n$colorHex')));
+ expect(docs, anyOf(equals(colorHex), endsWith('$eol$eol$colorHex')));
}
/// Expect [item] to use the default edit range, inserting the value [text].
@@ -1262,7 +1261,7 @@
}
Future<void> test_annotation_beforeMember() async {
- var content = '''
+ content = '''
class B {
@^
int a = 1;
@@ -1270,7 +1269,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var completions = await getCompletion(mainFileUri, code.position.position);
var labels = completions.map((c) => c.label).toList();
@@ -1280,14 +1279,14 @@
}
Future<void> test_annotation_endOfClass() async {
- var content = '''
+ content = '''
class B {
@^
}
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var completions = await getCompletion(mainFileUri, code.position.position);
var labels = completions.map((c) => c.label).toList();
@@ -1297,7 +1296,7 @@
}
Future<void> test_closure() async {
- var content = '''
+ content = '''
void f({void Function(int a, String b) closure}) {}
void g() {
@@ -1323,7 +1322,7 @@
}
Future<void> test_closure_requiredNamed() async {
- var content = '''
+ content = '''
void f({void Function({int a, required String b}) closure}) {}
void g() {
@@ -1351,7 +1350,7 @@
}
Future<void> test_color_material() async {
- var content = '''
+ content = '''
import 'package:flutter/material.dart';
var a = Colors.re^
''';
@@ -1360,7 +1359,7 @@
}
Future<void> test_color_materialAccent() async {
- var content = '''
+ content = '''
import 'package:flutter/material.dart';
var a = Colors.redAcce^
''';
@@ -1369,13 +1368,13 @@
}
Future<void> test_comment() async {
- var content = '''
+ content = '''
// foo ^
void f() {}
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res, isEmpty);
@@ -1384,12 +1383,12 @@
Future<void> test_comment_endOfFile_withNewline() async {
// Checks for a previous bug where invoking completion inside a comment
// at the end of a file would return results.
- var content = '''
+ content = '''
// foo ^
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res, isEmpty);
@@ -1398,10 +1397,10 @@
Future<void> test_comment_endOfFile_withoutNewline() async {
// Checks for a previous bug where invoking completion inside a comment
// at the very end of a file with no trailing newline would return results.
- var content = '// foo ^';
+ content = '// foo ^';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res, isEmpty);
@@ -1602,7 +1601,7 @@
// Flutter's setState method has special handling inside SuggestionBuilder
// that already adds in a selection (which overlaps with completeFunctionCalls).
// Ensure we don't end up with two sets of parens/placeholders in this case.
- var content = '''
+ content = '''
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
@@ -1621,7 +1620,7 @@
setCompletionItemSnippetSupport();
await provideConfig(initialize, {'completeFunctionCalls': true});
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var item = res.singleWhere((c) => c.label.startsWith('setState('));
@@ -1635,7 +1634,7 @@
expect(item.insertTextFormat, equals(InsertTextFormat.Snippet));
expect(item.insertText, isNull);
var textEdit = toTextEdit(item.textEdit!);
- expect(textEdit.newText, 'setState(() {\n \$0\n });');
+ expect(textEdit.newText, 'setState(() {$eol \$0$eol });');
expect(textEdit.range, equals(code.range.range));
}
@@ -1656,7 +1655,7 @@
}
Future<void> test_completeFunctionCalls_noParameters() async {
- var content = '''
+ content = '''
void myFunction() {}
void f() {
@@ -1673,7 +1672,7 @@
}
Future<void> test_completeFunctionCalls_optionalParameters() async {
- var content = '''
+ content = '''
void myFunction({int a}) {}
void f() {
@@ -1691,7 +1690,7 @@
}
Future<void> test_completeFunctionCalls_requiredNamed() async {
- var content = '''
+ content = '''
void myFunction(String a, int b, {required String c, String d = ''}) {}
void f() {
@@ -1701,7 +1700,7 @@
setCompletionItemSnippetSupport();
await provideConfig(initialize, {'completeFunctionCalls': true});
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var item = res.singleWhere((c) => c.label == 'myFunction(…)');
@@ -1720,7 +1719,7 @@
otherFile,
"void myFunction(String a, int b, {required String c, String d = ''}) {}",
);
- var content = '''
+ content = '''
void f() {
[!myFu^!]
}
@@ -1728,7 +1727,7 @@
setCompletionItemSnippetSupport();
await provideConfig(initialize, {'completeFunctionCalls': true});
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -1760,7 +1759,7 @@
// not provided both `insertText` and `textEdit` back in the resolve call.
//
// Now, we never supply `insertText` and always use `textEdit`.
- var content = '''
+ content = '''
final a = Stri^
''';
@@ -1777,7 +1776,7 @@
setCompletionItemSnippetSupport();
await provideConfig(initialize, {'completeFunctionCalls': true});
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -1792,13 +1791,13 @@
}
Future<void> test_completeFunctionCalls_show() async {
- var content = '''
+ content = '''
import 'dart:math' show mi^
''';
setCompletionItemSnippetSupport();
await provideConfig(initialize, {'completeFunctionCalls': true});
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var item = res.singleWhere((c) => c.label == 'min(…)');
@@ -1840,10 +1839,10 @@
newFile(join(projectFolderPath, 'file.dart'), '');
newFolder(join(projectFolderPath, 'folder'));
- var content = "import '^';";
+ content = "import '^';";
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
@@ -1865,10 +1864,10 @@
CompletionItemKind.Module,
]);
- var content = "import '^';";
+ content = "import '^';";
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
@@ -1884,7 +1883,7 @@
// Tell the server we only support the Field CompletionItemKind.
setCompletionItemKinds([CompletionItemKind.Field]);
- var content = '''
+ content = '''
class MyClass {
String abcdefghij;
}
@@ -1896,7 +1895,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var kinds = res.map((item) => item.kind).toList();
@@ -1910,7 +1909,7 @@
Future<void> test_completionTrigger_brace_block() async {
// Brace should not trigger completion if a normal code block.
- var content = r'''
+ content = r'''
main () {^}
''';
await _checkResultsForTriggerCharacters(content, ['{'], isEmpty);
@@ -1919,7 +1918,7 @@
Future<void>
test_completionTrigger_brace_interpolatedStringExpression() async {
// Brace should trigger completion if at the start of an interpolated expression
- var content = r'''
+ content = r'''
var a = '${^';
''';
await _checkResultsForTriggerCharacters(content, [r'{'], isNotEmpty);
@@ -1927,7 +1926,7 @@
Future<void> test_completionTrigger_brace_rawString() async {
// Brace should not trigger completion if in a raw string.
- var content = r'''
+ content = r'''
var a = r'${^';
''';
await _checkResultsForTriggerCharacters(content, [r'{'], isEmpty);
@@ -1936,7 +1935,7 @@
Future<void> test_completionTrigger_brace_string() async {
// Brace should not trigger completion if not at the start of an interpolated
// expression.
- var content = r'''
+ content = r'''
var a = '{^';
''';
await _checkResultsForTriggerCharacters(content, [r'{'], isEmpty);
@@ -1944,7 +1943,7 @@
Future<void> test_completionTrigger_colon_argument() async {
// Colons should trigger completion after argument names.
- var content = r'''
+ content = r'''
void f({int? a}) {
f(a:^
}
@@ -1954,7 +1953,7 @@
Future<void> test_completionTrigger_colon_case() async {
// Colons should not trigger completion in a switch case.
- var content = r'''
+ content = r'''
void f(int a) {
switch (a) {
case:^
@@ -1966,7 +1965,7 @@
Future<void> test_completionTrigger_colon_default() async {
// Colons should not trigger completion in a switch case.
- var content = r'''
+ content = r'''
void f(int a) {
switch (a) {
default:^
@@ -1978,7 +1977,7 @@
Future<void> test_completionTrigger_colon_import() async {
// Colons should trigger completion after argument names.
- var content = r'''
+ content = r'''
import 'package:^';
''';
await _checkResultsForTriggerCharacters(content, [r':'], isNotEmpty);
@@ -1986,32 +1985,32 @@
Future<void> test_completionTrigger_quotes_endingString() async {
// Completion triggered by a quote ending a string should not return results.
- var content = "foo(''^);";
+ content = "foo(''^);";
await _checkResultsForTriggerCharacters(content, ["'", '"'], isEmpty);
}
Future<void> test_completionTrigger_quotes_startingImport() async {
// Completion triggered by a quote for import should return results.
- var content = "import '^'";
+ content = "import '^'";
await _checkResultsForTriggerCharacters(content, ["'", '"'], isNotEmpty);
}
Future<void> test_completionTrigger_quotes_startingString() async {
// Completion triggered by a quote for normal string should not return results.
- var content = "foo('^');";
+ content = "foo('^');";
await _checkResultsForTriggerCharacters(content, ["'", '"'], isEmpty);
}
Future<void> test_completionTrigger_quotes_terminatingImport() async {
// Completion triggered by a quote ending an import should not return results.
- var content = "import ''^";
+ content = "import ''^";
await _checkResultsForTriggerCharacters(content, ["'", '"'], isEmpty);
}
Future<void> test_completionTrigger_slash_directivePath() async {
// Slashes should trigger completion when typing in directive paths, eg.
// after typing 'package:foo/' completion should give the next folder segments.
- var content = r'''
+ content = r'''
import 'package:test/^';
''';
await _checkResultsForTriggerCharacters(content, [r'/'], isNotEmpty);
@@ -2019,7 +2018,7 @@
Future<void> test_completionTrigger_slash_divide() async {
// Slashes should not trigger completion when typing in a normal expression.
- var content = r'''
+ content = r'''
var a = 1 /^
''';
await _checkResultsForTriggerCharacters(content, [r'/'], isEmpty);
@@ -2128,7 +2127,7 @@
Future<void> test_filterText_constructorParens() async {
// Constructor parens should not be included in filterText.
- var content = '''
+ content = '''
class MyClass {}
void f() {
@@ -2137,7 +2136,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'MyClass()'), isTrue);
@@ -2156,7 +2155,7 @@
// of the label. That text should _not_ appear in filterText as it will
// affect the editors relevance ranking as the user types.
// https://github.com/dart-lang/sdk/issues/45157
- var content = '''
+ content = '''
abstract class Person {
String get name;
}
@@ -2167,7 +2166,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var item = res.singleWhere((c) => c.label == 'override name => …');
@@ -2180,7 +2179,7 @@
// of the label. That text should _not_ appear in filterText as it will
// affect the editors relevance ranking as the user types.
// https://github.com/dart-lang/sdk/issues/45157
- var content = '''
+ content = '''
abstract class Base {
void myMethod() {};
}
@@ -2191,7 +2190,6 @@
''';
await initialize();
- var code = TestCode.parse(content);
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var item = res.singleWhere((c) => c.label == 'override myMethod() { … }');
@@ -2204,7 +2202,7 @@
///
/// https://github.com/Dart-Code/Dart-Code/issues/4499
Future<void> test_getter_narrowedBySubclass() async {
- var content = '''
+ content = '''
void f(MyItem item) {
item.na^
}
@@ -2222,7 +2220,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var name = res.singleWhere((c) => c.label == 'name');
@@ -2230,7 +2228,7 @@
}
Future<void> test_gettersAndSetters() async {
- var content = '''
+ content = '''
class MyClass {
String get justGetter => '';
set justSetter(String value) {}
@@ -2245,7 +2243,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var getter = res.singleWhere((c) => c.label == 'justGetter');
@@ -2260,72 +2258,72 @@
}
Future<void> test_import() async {
- var content = '''
+ content = '''
import '^';
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'dart:async'), isTrue);
}
Future<void> test_import_configuration() async {
- var content = '''
+ content = '''
import 'dart:core' if (dart.library.io) '^';
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'dart:async'), isTrue);
}
Future<void> test_import_configuration_eof() async {
- var content = '''
+ content = '''
import 'dart:core' if (dart.library.io) '^
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'dart:async'), isTrue);
}
Future<void> test_import_configuration_partial() async {
- var content = '''
+ content = '''
import 'dart:core' if (dart.library.io) 'dart:^';
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'dart:async'), isTrue);
}
Future<void> test_import_eof() async {
- var content = '''
+ content = '''
import '^
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'dart:async'), isTrue);
}
Future<void> test_import_partial() async {
- var content = '''
+ content = '''
import 'dart:^';
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'dart:async'), isTrue);
@@ -2341,7 +2339,7 @@
var myVariable = 1;
''');
- var content = '''
+ content = '''
import 'import.dart' hide myVariable;
void main() {
@@ -2375,7 +2373,7 @@
}
''');
- var content = '''
+ content = '''
import 'import.dart' show MyEnum;
void main() {
@@ -2404,7 +2402,7 @@
Future<void> test_insertReplaceRanges() async {
setCompletionItemInsertReplaceSupport();
- var content = '''
+ content = '''
class MyClass {
String abcdefghij;
}
@@ -2416,7 +2414,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'abcdefghij'), isTrue);
@@ -2426,18 +2424,18 @@
var replaced = applyTextEdits(code.code, [
textEditForReplace(item.textEdit!),
]);
- expect(replaced, contains('a.abcdefghij\n'));
+ expect(replaced, contains('a.abcdefghij$eol'));
// When using the insert range, we should retain what was after the caret
// ("def" in this case).
var inserted = applyTextEdits(code.code, [
textEditForInsert(item.textEdit!),
]);
- expect(inserted, contains('a.abcdefghijdef\n'));
+ expect(inserted, contains('a.abcdefghijdef$eol'));
}
Future<void> test_insertTextMode_multiline() async {
setCompletionItemInsertTextModeSupport();
- var content = '''
+ content = '''
import 'package:flutter/material.dart';
class _MyWidgetState extends State<MyWidget> {
@@ -2450,7 +2448,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var item = res.singleWhere((c) => c.label.startsWith('setState'));
@@ -2458,21 +2456,21 @@
// Multiline completions should always set insertTextMode.asIs.
expect(item.insertText, isNull);
var textEdit = toTextEdit(item.textEdit!);
- expect(textEdit.newText, contains('\n'));
+ expect(textEdit.newText, contains(eol));
expect(item.insertTextMode, equals(InsertTextMode.asIs));
}
Future<void> test_insertTextMode_singleLine() async {
setCompletionItemInsertTextModeSupport();
- var content = '''
+ content = '''
void foo() {
^
}
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var item = res.singleWhere((c) => c.label.startsWith('foo'));
@@ -2499,33 +2497,33 @@
}
Future<void> test_inside_nonLateFinal() async {
- var content = '''
+ content = '''
class MyClass {
String get myGetter => '';
final myField = myG^
}
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res, isEmpty);
}
Future<void> test_insideString() async {
- var content = '''
+ content = '''
var a = "This is ^a test"
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res, isEmpty);
}
Future<void> test_isDeprecated_notSupported() async {
- var content = '''
+ content = '''
class MyClass {
@deprecated
String abcdefghij;
@@ -2538,7 +2536,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var item = res.singleWhere((c) => c.label == 'abcdefghij');
@@ -2550,7 +2548,7 @@
Future<void> test_isDeprecated_supportedFlag() async {
setCompletionItemDeprecatedFlagSupport();
- var content = '''
+ content = '''
class MyClass {
@deprecated
String abcdefghij;
@@ -2563,7 +2561,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var item = res.singleWhere((c) => c.label == 'abcdefghij');
@@ -2576,7 +2574,7 @@
Future<void> test_isDeprecated_supportedTag() async {
setCompletionItemTagSupport([CompletionItemTag.Deprecated]);
- var content = '''
+ content = '''
class MyClass {
@deprecated
String abcdefghij;
@@ -2589,7 +2587,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var item = res.singleWhere((c) => c.label == 'abcdefghij');
@@ -2600,14 +2598,13 @@
}
Future<void> test_isIncomplete_falseIfAllIncluded() async {
- var content = '''
+ content = '''
import 'a.dart';
void f() {
A a = A();
a.^
}
''';
- var code = TestCode.parse(content);
// Create a class with fields aaa1 to aaa500 in the other file.
newFile(
@@ -2616,7 +2613,7 @@
'class A {',
for (var i = 1; i <= 500; i++) 'String get aaa$i => "";',
'}',
- ].join('\n'),
+ ].join(eol),
);
await initialize();
@@ -2630,14 +2627,13 @@
}
Future<void> test_isIncomplete_trueIfNotAllIncluded() async {
- var content = '''
+ content = '''
import 'a.dart';
void f() {
A a = A();
a.^
}
''';
- var code = TestCode.parse(content);
// Create a class with fields aaa1 to aaa500 in the other file.
newFile(
@@ -2647,7 +2643,7 @@
for (var i = 1; i <= 500; i++) ' String get aaa$i => "";',
' String get aaa => "";',
'}',
- ].join('\n'),
+ ].join(eol),
);
await provideConfig(initialize, {'maxCompletionItems': 200});
@@ -2664,12 +2660,11 @@
setCompletionItemInsertReplaceSupport();
setCompletionListDefaults(['editRange']);
- var content = '''
+ content = '''
void myFunction() {
[!myFunctio^!]
}
''';
- var code = TestCode.parse(content);
await initialize();
await openFile(mainFileUri, code.code);
@@ -2701,12 +2696,11 @@
//
// Additionally, because the caret is before the identifier, we will have
// separate default insert/replace ranges.
- var content = '''
+ content = '''
void f(String a, {String? b}) {
f([!^b!]);
}
''';
- var code = TestCode.parse(content);
await initialize();
await openFile(mainFileUri, code.code);
@@ -2746,7 +2740,7 @@
// We only normally set InsertTextMode on multiline completions (where it
// matters), so ensure there's a multiline completion in the results for
// testing.
- var content = '''
+ content = '''
import 'package:flutter/material.dart';
class _MyWidgetState extends State<MyWidget> {
@@ -2757,7 +2751,6 @@
}
}
''';
- var code = TestCode.parse(content);
await initialize();
await openFile(mainFileUri, code.code);
@@ -2773,13 +2766,12 @@
/// Exact matches should always be included when completion lists are
/// truncated, even if they ranked poorly.
Future<void> test_maxCompletionItems_doesNotExcludeExactMatches() async {
- var content = '''
+ content = '''
import 'a.dart';
void f() {
var a = Item^
}
''';
- var code = TestCode.parse(content);
// Create classes `Item1` to `Item20` along with a field named `item`.
// The classes will rank higher in the position above and push
@@ -2789,7 +2781,7 @@
[
'String item = "";',
for (var i = 1; i <= 20; i++) 'class Item$i {}',
- ].join('\n'),
+ ].join(eol),
);
await provideConfig(initialize, {'maxCompletionItems': 10});
@@ -2808,13 +2800,12 @@
/// because they are not ranked like other completions and might be
/// truncated when they are exactly what the user wants.
Future<void> test_maxCompletionItems_doesNotExcludeSnippets() async {
- var content = '''
+ content = '''
import 'a.dart';
void f() {
fo^
}
''';
- var code = TestCode.parse(content);
// Create fields for1 to for20 in the other file.
newFile(
@@ -2823,7 +2814,7 @@
for (var i = 1; i <= 20; i++)
'String for$i = '
';',
- ].join('\n'),
+ ].join(eol),
);
setCompletionItemSnippetSupport();
@@ -2847,7 +2838,7 @@
}
Future<void> test_namedArg_flutterChildren() async {
- var content = '''
+ content = '''
import 'package:flutter/widgets.dart';
final a = Flex(c^);
@@ -2872,7 +2863,7 @@
// Flutter's widget classes have special handling that adds `[]` after the
// children named arg, but this should not occur if there's already a value
// for this named arg.
- var content = '''
+ content = '''
import 'package:flutter/widgets.dart';
final a = Flex(c^: []);
@@ -2901,7 +2892,7 @@
required String expectedReplace,
required String expectedInsert,
}) async {
- var content = '''
+ content = '''
class A { const A({int argOne, int argTwo, String argThree}); }
final varOne = '';
$code
@@ -2990,7 +2981,7 @@
// identifier to be used as the `targetPrefix` which would filter out
// other symbol.
// https://github.com/Dart-Code/Dart-Code/issues/2672#issuecomment-666085575
- var content = '''
+ content = '''
void f() {
myFunction(
^
@@ -3002,21 +2993,21 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'aaab: '), isTrue);
}
Future<void> test_namedArg_plainText() async {
- var content = '''
+ content = '''
class A { const A({int one}); }
@A(^)
void f() { }
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'one: '), isTrue);
@@ -3033,7 +3024,7 @@
}
Future<void> test_namedArg_snippetStringSelection_endOfString() async {
- var content = '''
+ content = '''
class A { const A({int one}); }
@A(^)
void f() { }
@@ -3041,7 +3032,7 @@
setCompletionItemSnippetSupport();
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'one: '), isTrue);
@@ -3061,7 +3052,7 @@
Future<void>
test_namedArgTrailing_snippetStringSelection_insideString() async {
- var content = '''
+ content = '''
void f({int one, int two}) {
f(
^
@@ -3072,7 +3063,7 @@
setCompletionItemSnippetSupport();
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'one: '), isTrue);
@@ -3102,7 +3093,7 @@
}
Future<void> test_noOperators_propertyAccessExternal() async {
- var content = '''
+ content = '''
class A {
int operator-() => 0;
int operator-(int other) => 0;
@@ -3114,7 +3105,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var completions = await getCompletion(mainFileUri, code.position.position);
var labels = completions.map((c) => c.label).toList();
@@ -3124,7 +3115,7 @@
}
Future<void> test_noOperators_propertyAccessInternal() async {
- var content = '''
+ content = '''
class A {
int operator-() => 0;
int operator-(int other) => 0;
@@ -3136,7 +3127,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var completions = await getCompletion(mainFileUri, code.position.position);
var labels = completions.map((c) => c.label).toList();
@@ -3146,7 +3137,7 @@
}
Future<void> test_noOperators_superPropertyAccess() async {
- var content = '''
+ content = '''
class A {
int operator-() => 0;
int operator-(int other) => 0;
@@ -3160,7 +3151,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var completions = await getCompletion(mainFileUri, code.position.position);
var labels = completions.map((c) => c.label).toList();
@@ -3170,7 +3161,7 @@
}
Future<void> test_nullableTypes() async {
- var content = '''
+ content = '''
String? foo(int? a, [int b = 1]) {}
void f() {
@@ -3179,7 +3170,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -3189,7 +3180,7 @@
}
Future<void> test_operators_override() async {
- var content = '''
+ content = '''
class A {
int operator-() => 0;
int operator-(int other) => 0;
@@ -3201,7 +3192,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var completions = await getCompletion(mainFileUri, code.position.position);
var labels = completions.map((c) => c.label).toList();
@@ -3211,7 +3202,7 @@
}
Future<void> test_plainText() async {
- var content = '''
+ content = '''
class MyClass {
String abcdefghij;
}
@@ -3223,7 +3214,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'abcdefghij'), isTrue);
@@ -3238,7 +3229,7 @@
}
Future<void> test_prefixed_enumMember() async {
- var content = '''
+ content = '''
import 'main.dart' as self;
enum MyEnum {
@@ -3252,14 +3243,14 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'one'), isTrue);
}
Future<void> test_prefixFilter_endOfSymbol() async {
- var content = '''
+ content = '''
class UniqueNamedClassForLspOne {}
class UniqueNamedClassForLspTwo {}
class UniqueNamedClassForLspThree {}
@@ -3271,7 +3262,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'UniqueNamedClassForLspOne'), isFalse);
@@ -3280,7 +3271,7 @@
}
Future<void> test_prefixFilter_midSymbol() async {
- var content = '''
+ content = '''
class UniqueNamedClassForLspOne {}
class UniqueNamedClassForLspTwo {}
class UniqueNamedClassForLspThree {}
@@ -3292,7 +3283,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'UniqueNamedClassForLspOne'), isFalse);
@@ -3301,7 +3292,7 @@
}
Future<void> test_prefixFilter_startOfSymbol() async {
- var content = '''
+ content = '''
class UniqueNamedClassForLspOne {}
class UniqueNamedClassForLspTwo {}
class UniqueNamedClassForLspThree {}
@@ -3313,7 +3304,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.label == 'UniqueNamedClassForLspOne'), isTrue);
@@ -3322,7 +3313,7 @@
}
Future<void> test_setters() async {
- var content = '''
+ content = '''
class MyClass {
set stringSetter(String a) {}
set noArgSetter() {}
@@ -3337,7 +3328,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var setters =
@@ -3356,7 +3347,7 @@
}
Future<void> test_sort_sortsByRelevance() async {
- var content = '''
+ content = '''
class UniquePrefixABC {}
class UniquePrefixAaBbCc {}
@@ -3378,7 +3369,7 @@
}
Future<void> test_sort_truncatesByFuzzyScore() async {
- var content = '''
+ content = '''
class UniquePrefixABC {}
class UniquePrefixAaBbCc {}
@@ -3408,14 +3399,14 @@
class InOtherFile {}
''');
- var content = '''
+ content = '''
void f() {
InOtherF^
}
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -3463,7 +3454,7 @@
// Ensure both edits were made - the completion, and the inserted import.
expect(
newContent,
- equals('''
+ equalsNormalized('''
import '../other_file.dart';
void f() {
@@ -3520,7 +3511,7 @@
export 'source_file.dart';
''');
- var content = '''
+ content = '''
import 'reexport1.dart';
import 'reexport2.dart';
@@ -3530,7 +3521,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -3552,7 +3543,7 @@
export 'source_file.dart';
''');
- var content = '''
+ content = '''
import 'reexport1.dart';
void f() {
@@ -3561,7 +3552,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -3585,14 +3576,14 @@
'class MyDuplicatedClass {}',
);
- var content = '''
+ content = '''
void f() {
MyDuplicated^
}
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -3622,7 +3613,7 @@
void x(MyExportedEnum e) {}
''');
- var content = '''
+ content = '''
import 'package:test/function_x.dart';
void f() {
@@ -3631,7 +3622,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -3678,7 +3669,7 @@
// Ensure both edits were made - the completion, and the inserted import.
expect(
newContent,
- equals('''
+ equalsNormalized('''
import 'package:test/enum.dart';
import 'package:test/function_x.dart';
@@ -3702,7 +3693,7 @@
export 'enum.dart';
''');
- var content = '''
+ content = '''
import 'reexport1.dart';
void f() {
@@ -3711,7 +3702,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -3740,14 +3731,14 @@
'import "extensions.dart";',
);
- var content = '''
+ content = '''
void f(String a) {
a.empt^
}
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -3772,7 +3763,7 @@
);
expect(
newContent,
- equals('''
+ equalsNormalized('''
import 'package:test/extensions.dart';
void f(String a) {
@@ -3793,7 +3784,7 @@
export 'source_file.dart';
''');
- var content = '''
+ content = '''
import 'reexport1.dart';
void f() {
@@ -3802,7 +3793,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -3820,7 +3811,7 @@
'class MyClass {}',
);
- var content = '''
+ content = '''
void f() {
MyClas^
}
@@ -3852,7 +3843,7 @@
}
''');
- var content = '''
+ content = '''
void f() {
''.myExtensionMet^
}
@@ -3887,14 +3878,14 @@
export 'source_file.dart';
''');
- var content = '''
+ content = '''
void f() {
MyExported^
}
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -3920,14 +3911,14 @@
class InOtherFile {}
''');
- var content = '''
+ content = '''
void f() {
InOtherF^il
}
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -3983,7 +3974,7 @@
// Ensure both edits were made - the completion, and the inserted import.
expect(
newContentReplaceMode,
- equals('''
+ equalsNormalized('''
import '../other_file.dart';
void f() {
@@ -3994,7 +3985,7 @@
// In insert mode, we'd have the trailing "il" still after the caret.
expect(
newContentInsertMode,
- equals('''
+ equalsNormalized('''
import '../other_file.dart';
void f() {
@@ -4017,7 +4008,7 @@
newFile(join(projectFolderPath, 'lib', 'parent.dart'), parentContent);
// File that we're invoking completion in.
- var content = '''
+ content = '''
part of 'parent.dart';
void f() {
InOtherF^
@@ -4025,7 +4016,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -4051,7 +4042,7 @@
);
expect(
newContent,
- equals('''
+ equalsNormalized('''
part of 'parent.dart';
void f() {
InOtherFile
@@ -4069,12 +4060,11 @@
Future<void>
test_unimportedSymbols_isIncompleteNotSetIfBudgetNotExhausted() async {
- var content = '''
+ content = '''
void f() {
InOtherF^
}
''';
- var code = TestCode.parse(content);
await initialize(
initializationOptions: {
@@ -4097,12 +4087,11 @@
'class InOtherFile {}',
);
- var content = '''
+ content = '''
void f() {
InOtherF^
}
''';
- var code = TestCode.parse(content);
await initialize(
initializationOptions: {
@@ -4127,7 +4116,7 @@
class MyClass3 {}
''');
- var content = '''
+ content = '''
import 'package:test/my_classes.dart' hide MyClass1, MyClass2;
void f() {
MyClas^
@@ -4157,7 +4146,7 @@
class MyClass2 {}
''');
- var content = '''
+ content = '''
import 'package:test/my_classes.dart' hide MyClass1;
void f() {
MyClas^
@@ -4187,7 +4176,7 @@
class MyClass2 {}
''');
- var content = '''
+ content = '''
import 'package:test/my_classes.dart' show MyClass2;
void f() {
MyClas^
@@ -4220,7 +4209,7 @@
class MyClass2 {}
''');
- var content = '''
+ content = '''
import 'package:test/my_classes.dart' as p1 show MyClass2;
void f() {
MyClas^
@@ -4254,9 +4243,9 @@
var otherFilePath = join(projectFolderPath, 'lib', 'other_file.dart');
var otherFileUri = pathContext.toUri(otherFilePath);
- var mainFileCode = TestCode.parse('MyOtherClass^');
+ content = 'MyOtherClass^';
await initialize();
- await openFile(mainFileUri, mainFileCode.code);
+ await openFile(mainFileUri, code.code);
await initialAnalysis;
// Start with a blank file.
@@ -4270,10 +4259,7 @@
await pumpEventQueue(times: 5000);
// Ensure the class appears in completion.
- var completions = await getCompletion(
- mainFileUri,
- mainFileCode.position.position,
- );
+ var completions = await getCompletion(mainFileUri, code.position.position);
var matching = completions.where((c) => c.label == 'MyOtherClass').toList();
expect(matching, hasLength(1));
}
@@ -4286,14 +4272,14 @@
}
''');
- var content = '''
+ content = '''
void f() {
var a = InOtherF^
}
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -4326,7 +4312,7 @@
// Ensure both edits were made - the completion, and the inserted import.
expect(
newContent,
- equals('''
+ equalsNormalized('''
import '../other_file.dart';
void f() {
@@ -4356,7 +4342,7 @@
// A will already be imported
// B will already be imported but with a prefix
// C & D are not imported and need importing (return + parameter types)
- var content = '''
+ content = '''
import 'package:test/a.dart';
import 'package:test/b.dart' as b;
import 'package:test/base.dart';
@@ -4367,7 +4353,7 @@
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -4386,7 +4372,7 @@
expect(
newContent,
- equals('''
+ equalsNormalized('''
import 'package:test/a.dart';
import 'package:test/b.dart' as b;
import 'package:test/base.dart';
@@ -4424,7 +4410,7 @@
// Create a file that will be auto-imported from completion.
newFile(importedFilePath, 'class MyClass {}');
- var content = '''
+ content = '''
void f() {
MyClas^
}
@@ -4470,7 +4456,7 @@
// Create a file that will be auto-imported from completion.
newFile(importedFilePath, 'class MyClass {}');
- var content = '''
+ content = '''
void f() {
MyClas^
}
@@ -4497,7 +4483,7 @@
Future<void> test_unimportedSymbols_unavailableIfDisabled() async {
newFile(join(projectFolderPath, 'other_file.dart'), 'class InOtherFile {}');
- var content = '''
+ content = '''
void f() {
InOtherF^
}
@@ -4510,7 +4496,7 @@
'suggestFromUnimportedLibraries': false,
},
);
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -4528,14 +4514,14 @@
newFile(join(projectFolderPath, 'other_file.dart'), 'class InOtherFile {}');
- var content = '''
+ content = '''
void f() {
InOtherF^
}
''';
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
await initialAnalysis;
var res = await getCompletion(mainFileUri, code.position.position);
@@ -4547,7 +4533,7 @@
}
Future<void> test_unopenFile() async {
- var content = '''
+ content = '''
class MyClass {
String abcdefghij;
}
@@ -4557,7 +4543,6 @@
a.abc^
}
''';
- var code = TestCode.parse(content);
newFile(mainFilePath, code.code);
await initialize();
@@ -4584,7 +4569,6 @@
String completionLabel,
String expectedContent,
) async {
- var code = TestCode.parse(content);
await initialize();
await openFile(fileUri, code.code);
await initialAnalysis;
@@ -4601,7 +4585,7 @@
].followedBy(resolvedCompletion.additionalTextEdits!).toList(),
);
- expect(newContent, equals(expectedContent));
+ expect(newContent, equalsNormalized(expectedContent));
}
Future<void> _checkResultsForTriggerCharacters(
@@ -4609,7 +4593,6 @@
List<String> triggerCharacters,
Matcher expectedResults,
) async {
- var code = TestCode.parse(content);
await initialize();
await openFile(mainFileUri, code.code);
@@ -4635,28 +4618,30 @@
@reflectiveTest
class DartSnippetCompletionTest extends SnippetCompletionTest {
Future<void> test_snippets_class() async {
- var content = '''
+ content = '''
clas^
''';
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: ClassDeclaration.prefix,
label: ClassDeclaration.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
class ${1:ClassName} {
$0
}
-''');
+'''),
+ );
}
/// Checks that the `enableSnippets` setting can disable snippets even if the
/// client supports them.
Future<void> test_snippets_disabled() async {
- var content = '^';
+ content = '^';
// Support is set in setUp, but here we disable the user preference.
await provideConfig(initialize, {'enableSnippets': false});
@@ -4665,7 +4650,7 @@
}
Future<void> test_snippets_doWhile() async {
- var content = '''
+ content = '''
void f() {
do^
}
@@ -4673,18 +4658,20 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: DoStatement.prefix,
label: DoStatement.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
void f() {
do {
$0
} while (${1:condition});
}
-''');
+'''),
+ );
}
/// Snippets completions may abort if documents are modified (because they
@@ -4692,12 +4679,11 @@
/// prevent non-Snippet completion results from being returned (because this
/// happens frequently while typing).
Future<void> test_snippets_failureDoesNotPreventNonSnippets() async {
- var content = '''
+ content = '''
void f() {
^
}
''';
- var code = TestCode.parse(content);
await initialize();
await openFile(mainFileUri, code.code);
@@ -4729,7 +4715,7 @@
Future<void>
test_snippets_flutterStateless_notAvailable_notFlutterProject() async {
- var content = '''
+ content = '''
class A {}
stle^
@@ -4742,7 +4728,7 @@
}
Future<void> test_snippets_for() async {
- var content = '''
+ content = '''
void f() {
for^
}
@@ -4750,22 +4736,24 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: ForStatement.prefix,
label: ForStatement.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
void f() {
for (var i = 0; i < ${1:count}; i++) {
$0
}
}
-''');
+'''),
+ );
}
Future<void> test_snippets_forIn() async {
- var content = '''
+ content = '''
void f() {
forin^
}
@@ -4773,22 +4761,24 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: ForInStatement.prefix,
label: ForInStatement.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
void f() {
for (var ${1:element} in ${2:collection}) {
$0
}
}
-''');
+'''),
+ );
}
Future<void> test_snippets_functionClassMember() async {
- var content = '''
+ content = '''
class A {
fun^
}
@@ -4796,22 +4786,24 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: FunctionDeclaration.prefix,
label: FunctionDeclaration.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
class A {
${1:void} ${2:name}(${3:params}) {
$0
}
}
-''');
+'''),
+ );
}
Future<void> test_snippets_functionNested() async {
- var content = '''
+ content = '''
void a() {
fun^
}
@@ -4819,41 +4811,45 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: FunctionDeclaration.prefix,
label: FunctionDeclaration.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
void a() {
${1:void} ${2:name}(${3:params}) {
$0
}
}
-''');
+'''),
+ );
}
Future<void> test_snippets_functionTopLevel() async {
- var content = '''
+ content = '''
fun^
''';
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: FunctionDeclaration.prefix,
label: FunctionDeclaration.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
${1:void} ${2:name}(${3:params}) {
$0
}
-''');
+'''),
+ );
}
Future<void> test_snippets_if() async {
- var content = '''
+ content = '''
void f() {
if^
}
@@ -4861,22 +4857,24 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: IfStatement.prefix,
label: IfStatement.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
void f() {
if (${1:condition}) {
$0
}
}
-''');
+'''),
+ );
}
Future<void> test_snippets_ifElse() async {
- var content = '''
+ content = '''
void f() {
if^
}
@@ -4884,12 +4882,13 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: IfElseStatement.prefix,
label: IfElseStatement.label,
);
var fourSpaces = ' ';
- expect(updated, '''
+ expect(
+ updated,
+ equalsNormalized('''
void f() {
if (\${1:condition}) {
\$0
@@ -4897,7 +4896,8 @@
$fourSpaces
}
}
-''');
+'''),
+ );
}
/// Fetch snippets with itemDefaults enabled to ensure we don't return any
@@ -4909,26 +4909,28 @@
'insertTextMode',
'insertTextFormat',
]);
- var content = '''
+ content = '''
fu^
''';
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: FunctionDeclaration.prefix,
label: FunctionDeclaration.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
${1:void} ${2:name}(${3:params}) {
$0
}
-''');
+'''),
+ );
}
Future<void> test_snippets_mainFunction() async {
- var content = '''
+ content = '''
class A {}
main^
@@ -4938,12 +4940,13 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: MainFunction.prefix,
label: MainFunction.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
class A {}
void main(List<String> args) {
@@ -4951,24 +4954,25 @@
}
class B {}
-''');
+'''),
+ );
}
Future<void> test_snippets_notSupported() async {
- var content = '^';
+ content = '^';
// If we don't send support for Snippet CompletionItem kinds, we don't
// expect any snippets at all.
setCompletionItemSnippetSupport(false);
await initialize();
- var code = TestCode.parse(content);
+
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
expect(res.any((c) => c.kind == CompletionItemKind.Snippet), isFalse);
}
Future<void> test_snippets_switch() async {
- var content = '''
+ content = '''
void f() {
swi^
}
@@ -4976,12 +4980,13 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: SwitchStatement.prefix,
label: SwitchStatement.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
void f() {
switch (${1:expression}) {
case ${2:value}:
@@ -4990,12 +4995,13 @@
default:
}
}
-''');
+'''),
+ );
}
Future<void> test_snippets_testBlock() async {
mainFilePath = join(projectFolderPath, 'test', 'foo_test.dart');
- var content = '''
+ content = '''
void f() {
test^
}
@@ -5003,12 +5009,13 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: TestDefinition.prefix,
label: TestDefinition.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
import 'package:test/test.dart';
void f() {
@@ -5016,12 +5023,13 @@
$0
});
}
-''');
+'''),
+ );
}
Future<void> test_snippets_testGroupBlock() async {
mainFilePath = join(projectFolderPath, 'test', 'foo_test.dart');
- var content = '''
+ content = '''
void f() {
group^
}
@@ -5029,12 +5037,13 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: TestGroupDefinition.prefix,
label: TestGroupDefinition.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
import 'package:test/test.dart';
void f() {
@@ -5042,11 +5051,12 @@
$0
});
}
-''');
+'''),
+ );
}
Future<void> test_snippets_tryCatch() async {
- var content = '''
+ content = '''
void f() {
tr^
}
@@ -5054,12 +5064,13 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: TryCatchStatement.prefix,
label: TryCatchStatement.label,
);
var fourSpaces = ' ';
- expect(updated, '''
+ expect(
+ updated,
+ equalsNormalized('''
void f() {
try {
\$0
@@ -5067,11 +5078,12 @@
$fourSpaces
}
}
-''');
+'''),
+ );
}
Future<void> test_snippets_while() async {
- var content = '''
+ content = '''
void f() {
while^
}
@@ -5079,18 +5091,20 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: WhileStatement.prefix,
label: WhileStatement.label,
);
- expect(updated, r'''
+ expect(
+ updated,
+ equalsNormalized(r'''
void f() {
while (${1:condition}) {
$0
}
}
-''');
+'''),
+ );
}
}
@@ -5110,7 +5124,7 @@
}
Future<void> test_snippets_flutterStateful() async {
- var content = '''
+ content = '''
import 'package:flutter/widgets.dart';
class A {}
@@ -5122,12 +5136,13 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: FlutterStatefulWidget.prefix,
label: FlutterStatefulWidget.label,
);
- expect(updated, '''
+ expect(
+ updated,
+ equalsNormalized('''
import 'package:flutter/widgets.dart';
class A {}
@@ -5147,11 +5162,12 @@
}
class B {}
-''');
+'''),
+ );
}
Future<void> test_snippets_flutterStatefulWithAnimationController() async {
- var content = '''
+ content = '''
import 'package:flutter/widgets.dart';
class A {}
@@ -5163,12 +5179,13 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: FlutterStatefulWidgetWithAnimationController.prefix,
label: FlutterStatefulWidgetWithAnimationController.label,
);
- expect(updated, '''
+ expect(
+ updated,
+ equalsNormalized('''
import 'package:flutter/widgets.dart';
class A {}
@@ -5203,11 +5220,12 @@
}
class B {}
-''');
+'''),
+ );
}
Future<void> test_snippets_flutterStateless() async {
- var content = '''
+ content = '''
import 'package:flutter/widgets.dart';
class A {}
@@ -5219,12 +5237,13 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: FlutterStatelessWidget.prefix,
label: FlutterStatelessWidget.label,
);
- expect(updated, '''
+ expect(
+ updated,
+ equalsNormalized('''
import 'package:flutter/widgets.dart';
class A {}
@@ -5239,11 +5258,12 @@
}
class B {}
-''');
+'''),
+ );
}
Future<void> test_snippets_flutterStateless_addsImports() async {
- var content = '''
+ content = '''
class A {}
stle^
@@ -5253,12 +5273,13 @@
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: FlutterStatelessWidget.prefix,
label: FlutterStatelessWidget.label,
);
- expect(updated, '''
+ expect(
+ updated,
+ equalsNormalized('''
$expectedImports
class A {}
@@ -5273,22 +5294,24 @@
}
class B {}
-''');
+'''),
+ );
}
Future<void> test_snippets_flutterStateless_addsImports_onlyPrefix() async {
- var content = '''
+ content = '''
stless^
''';
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: FlutterStatelessWidget.prefix,
label: FlutterStatelessWidget.label,
);
- expect(updated, '''
+ expect(
+ updated,
+ equalsNormalized('''
$expectedImports
class \${1:MyWidget} extends StatelessWidget {
@@ -5299,22 +5322,24 @@
return \${0:const Placeholder()};
}
}
-''');
+'''),
+ );
}
Future<void> test_snippets_flutterStateless_addsImports_zeroOffset() async {
- var content = '''
+ content = '''
^
'''; // Deliberate trailing newline to ensure imports aren't inserted at "end".
await initialize();
var updated = await expectAndApplySnippet(
- content,
prefix: FlutterStatelessWidget.prefix,
label: FlutterStatelessWidget.label,
);
- expect(updated, '''
+ expect(
+ updated,
+ equalsNormalized('''
$expectedImports
class \${1:MyWidget} extends StatelessWidget {
@@ -5325,11 +5350,12 @@
return \${0:const Placeholder()};
}
}
-''');
+'''),
+ );
}
Future<void> test_snippets_flutterStateless_notAvailable_notTopLevel() async {
- var content = '''
+ content = '''
class A {
stle^
@@ -5342,10 +5368,9 @@
}
Future<void> test_snippets_flutterStateless_outsideAnalysisRoot() async {
- var content = '''
+ content = '''
stle^
''';
- var code = TestCode.parse(content);
await initialize();
var otherFileUri = pathContext.toUri(convertPath('/other/file.dart'));
@@ -5358,14 +5383,15 @@
abstract class SnippetCompletionTest extends AbstractLspAnalysisServerTest
with CompletionTestMixin {
+ late String content;
+ late final code = TestCode.parseNormalized(content);
+
/// Expect that there is a snippet for [prefix] at [position] with the label
/// [label] and return the results of applying it to [content].
- Future<String> expectAndApplySnippet(
- String content, {
+ Future<String> expectAndApplySnippet({
required String prefix,
required String label,
}) async {
- var code = TestCode.parse(content);
var (snippet: snippet, defaults: defaults) = await expectSnippet(
code,
prefix: prefix,
@@ -5408,7 +5434,6 @@
/// Expect that there is no snippet for [prefix] at the position of `^` within
/// [content].
Future<void> expectNoSnippet(String content, String prefix) async {
- var code = TestCode.parse(content);
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var hasSnippet = res.any((c) => c.filterText == prefix);
@@ -5417,7 +5442,6 @@
/// Expect that there are no snippets at the position of `^` within [content].
Future<void> expectNoSnippets(String content) async {
- var code = TestCode.parse(content);
await openFile(mainFileUri, code.code);
var res = await getCompletion(mainFileUri, code.position.position);
var hasAnySnippet = res.any((c) => c.kind == CompletionItemKind.Snippet);
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index d679ceb..cc08490 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -17,6 +17,7 @@
import 'package:analysis_server/src/utilities/mocks.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
+import 'package:analyzer/src/test_utilities/platform.dart';
import 'package:analyzer/src/test_utilities/test_code_format.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
@@ -78,6 +79,9 @@
LspClientCapabilities get editorClientCapabilities =>
server.editorClientCapabilities!;
+ /// The line terminator being used for test files and to be expected in edits.
+ String get eol => testEol;
+
String get mainFileAugmentationPath => fromUri(mainFileAugmentationUri);
/// The path that is not in [projectFolderPath], contains external packages.
@@ -140,6 +144,12 @@
return info;
}
+ /// Returns a matcher that checks that the input matches [expected] after
+ /// newlines have been normalized to the current platforms (only in
+ /// [expected]).
+ Matcher equalsNormalized(String expected) =>
+ equals(normalizeNewlinesForPlatform(expected));
+
void expectContextBuilds() => expect(
server.contextBuilds - _previousContextBuilds,
greaterThan(0),
diff --git a/pkg/analysis_server/test/services/completion/postfix/postfix_completion_test.dart b/pkg/analysis_server/test/services/completion/postfix/postfix_completion_test.dart
index 653eefd..8205bf8 100644
--- a/pkg/analysis_server/test/services/completion/postfix/postfix_completion_test.dart
+++ b/pkg/analysis_server/test/services/completion/postfix/postfix_completion_test.dart
@@ -37,7 +37,7 @@
if (change.edits.isNotEmpty) {
// We use a carat in the expected code to prevent lines containing only
// whitespace from being made empty.
- var expectedCode = TestCode.parse(normalizeSource(expected));
+ var expectedCode = TestCode.parseNormalized(expected);
var resultCode = SourceEdit.applySequence(
testCode,
change.edits[0].edits,
@@ -68,7 +68,7 @@
}
Future<void> _prepareProcessor(String key, String code) async {
- testCodeCode = TestCode.parse(normalizeSource(code));
+ testCodeCode = TestCode.parseNormalized(code);
verifyNoTestUnitErrors = false;
await resolveTestCode(testCodeCode.code);
diff --git a/pkg/analysis_server/test/services/snippets/snippet_request_test.dart b/pkg/analysis_server/test/services/snippets/snippet_request_test.dart
index e590d9a..01ad7d3 100644
--- a/pkg/analysis_server/test/services/snippets/snippet_request_test.dart
+++ b/pkg/analysis_server/test/services/snippets/snippet_request_test.dart
@@ -4,7 +4,6 @@
import 'package:analysis_server/src/services/snippets/dart_snippet_request.dart';
import 'package:analysis_server/src/services/snippets/snippet_context.dart';
-import 'package:analyzer/src/test_utilities/platform.dart';
import 'package:analyzer/src/test_utilities/test_code_format.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -625,7 +624,7 @@
String content,
SnippetContext expectedContext,
) async {
- var code = TestCode.parse(normalizeNewlinesForPlatform(content));
+ var code = TestCode.parseNormalized(content);
var offset = code.position.offset;
var expectedReplacementRange = code.range.sourceRange;
await resolveTestCode(code.code);
diff --git a/pkg/analyzer/lib/src/test_utilities/platform.dart b/pkg/analyzer/lib/src/test_utilities/platform.dart
index 6157220..c076b4c 100644
--- a/pkg/analyzer/lib/src/test_utilities/platform.dart
+++ b/pkg/analyzer/lib/src/test_utilities/platform.dart
@@ -4,6 +4,13 @@
import 'dart:io';
+/// The EOL being used for file content in the current test run.
+String get testEol =>
+ // TODO(dantup): Support overridding this with an env var to allow testing
+ // `\n` on Windows or `\r\n` on non-Windows, to ensure we don't have any
+ // code just assuming the platform EOL (instead of the files EOL).
+ Platform.lineTerminator;
+
/// Normalizes content to use platform-specific newlines.
///
/// This ensures that when running on Windows, '\r\n' is used, even though
@@ -16,5 +23,5 @@
}
var newlinePattern = RegExp(r'\r?\n'); // Either '\r\n' or '\n'.
- return input.replaceAll(newlinePattern, Platform.lineTerminator);
+ return input.replaceAll(newlinePattern, testEol);
}
diff --git a/pkg/analyzer/lib/src/test_utilities/test_code_format.dart b/pkg/analyzer/lib/src/test_utilities/test_code_format.dart
index d128cda..2ffffd2 100644
--- a/pkg/analyzer/lib/src/test_utilities/test_code_format.dart
+++ b/pkg/analyzer/lib/src/test_utilities/test_code_format.dart
@@ -4,6 +4,7 @@
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/source/source_range.dart';
+import 'package:analyzer/src/test_utilities/platform.dart';
import 'package:collection/collection.dart';
/// A class for parsing and representing test code that contains special markup
@@ -183,6 +184,23 @@
ranges: ranges.values.toList(),
);
}
+
+ /// A version of [TestCode.parse] that normalizes newlines in the code to
+ /// match that for the current platform so that tests on Windows test using
+ /// `\r\n` and tests on other platforms test using `\n`.
+ static TestCode parseNormalized(
+ String markedCode, {
+ bool positionShorthand = true,
+ bool rangeShorthand = true,
+ bool zeroWidthMarker = true,
+ }) {
+ return parse(
+ normalizeNewlinesForPlatform(markedCode),
+ positionShorthand: positionShorthand,
+ rangeShorthand: rangeShorthand,
+ zeroWidthMarker: zeroWidthMarker,
+ );
+ }
}
/// A marked position in the test code.