Skip to content

Commit 48b7b37

Browse files
DanTupCommit Queue
authored andcommitted
[analysis_server] Add imports for test/group snippets
Fixes Dart-Code/Dart-Code#5421 Change-Id: I70b1bac0e86117c19324d482ba993f950b5be931 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/411002 Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent e9c22e4 commit 48b7b37

File tree

10 files changed

+314
-18
lines changed

10 files changed

+314
-18
lines changed

pkg/analysis_server/lib/src/services/snippets/dart/test_definition.dart

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
import 'package:analysis_server/src/services/snippets/snippet.dart';
66
import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
7+
import 'package:analyzer/dart/analysis/results.dart';
8+
import 'package:analyzer/src/dart/analysis/session_helper.dart';
79
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
10+
import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
811

912
/// Produces a [Snippet] that creates a `test()` block.
10-
class TestDefinition extends DartSnippetProducer {
13+
class TestDefinition extends DartSnippetProducer with TestSnippetMixin {
1114
static const prefix = 'test';
1215
static const label = 'test';
1316

@@ -21,7 +24,8 @@ class TestDefinition extends DartSnippetProducer {
2124
var builder = ChangeBuilder(session: request.analysisSession);
2225
var indent = utils.getLinePrefix(request.offset);
2326

24-
await builder.addDartFileEdit(request.filePath, (builder) {
27+
await builder.addDartFileEdit(request.filePath, (builder) async {
28+
await addRequiredImports(builder);
2529
builder.addReplacement(request.replacementRange, (builder) {
2630
void writeIndented(String string) => builder.write('$indent$string');
2731
builder.write("test('");
@@ -46,3 +50,35 @@ class TestDefinition extends DartSnippetProducer {
4650
return isInTestDirectory;
4751
}
4852
}
53+
54+
mixin TestSnippetMixin {
55+
final _flutterTestUri = Uri.parse('package:flutter_test/flutter_test.dart');
56+
57+
final _dartTestUri = Uri.parse('package:test/test.dart');
58+
59+
AnalysisSessionHelper get sessionHelper;
60+
61+
/// Adds imports for `test`/`group` if required.
62+
///
63+
/// Both 'package:test' and 'package:flutter_test' are checked because Flutter
64+
/// projects can use either and we don't want to add the other.
65+
Future<void> addRequiredImports(DartFileEditBuilder builder) async {
66+
if (builder.importsLibrary(_dartTestUri) ||
67+
builder.importsLibrary(_flutterTestUri)) {
68+
return;
69+
}
70+
71+
var testUri = await getTestLibraryUri();
72+
builder.importLibrary(testUri);
73+
}
74+
75+
/// Gets the URI for the test library to import depending on whether
76+
/// flutter_test is available or not.
77+
Future<Uri> getTestLibraryUri() async {
78+
var flutterTest = await sessionHelper.session.getLibraryByUri(
79+
_flutterTestUri.toString(),
80+
);
81+
82+
return flutterTest is LibraryElementResult ? _flutterTestUri : _dartTestUri;
83+
}
84+
}

pkg/analysis_server/lib/src/services/snippets/dart/test_group_definition.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analysis_server/src/services/snippets/dart/test_definition.dart';
56
import 'package:analysis_server/src/services/snippets/snippet.dart';
67
import 'package:analysis_server/src/services/snippets/snippet_producer.dart';
78
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
89

910
/// Produces a [Snippet] that creates a `group()` block.
10-
class TestGroupDefinition extends DartSnippetProducer {
11+
class TestGroupDefinition extends DartSnippetProducer with TestSnippetMixin {
1112
static const prefix = 'group';
1213
static const label = 'group';
1314

@@ -21,7 +22,8 @@ class TestGroupDefinition extends DartSnippetProducer {
2122
var builder = ChangeBuilder(session: request.analysisSession);
2223
var indent = utils.getLinePrefix(request.offset);
2324

24-
await builder.addDartFileEdit(request.filePath, (builder) {
25+
await builder.addDartFileEdit(request.filePath, (builder) async {
26+
await addRequiredImports(builder);
2527
builder.addReplacement(request.replacementRange, (builder) {
2628
void writeIndented(String string) => builder.write('$indent$string');
2729
builder.write("group('");

pkg/analysis_server/test/lsp/completion_dart_test.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4596,6 +4596,8 @@ void f() {
45964596
);
45974597

45984598
expect(updated, r'''
4599+
import 'package:test/test.dart';
4600+
45994601
void f() {
46004602
test('${1:test name}', () {
46014603
$0
@@ -4620,6 +4622,8 @@ void f() {
46204622
);
46214623

46224624
expect(updated, r'''
4625+
import 'package:test/test.dart';
4626+
46234627
void f() {
46244628
group('${1:group name}', () {
46254629
$0

pkg/analysis_server/test/services/snippets/dart/test_definition_test.dart

Lines changed: 116 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'package:analysis_server/src/protocol_server.dart';
65
import 'package:analysis_server/src/services/snippets/dart/test_definition.dart';
76
import 'package:analyzer/src/test_utilities/test_code_format.dart';
87
import 'package:test/test.dart';
@@ -27,6 +26,117 @@ class TestDefinitionTest extends DartSnippetProducerTest {
2726
@override
2827
String get prefix => TestDefinition.prefix;
2928

29+
Future<void> test_import_dart() async {
30+
testFilePath = convertPath('$testPackageLibPath/test/foo_test.dart');
31+
var code = TestCode.parse(r'''
32+
void f() {
33+
test^
34+
}
35+
''');
36+
var snippet = await expectValidSnippet(code);
37+
var result = applySnippet(code, snippet);
38+
expect(result, '''
39+
import 'package:test/test.dart';
40+
41+
void f() {
42+
test('test name', () {
43+
44+
});
45+
}
46+
''');
47+
}
48+
49+
Future<void> test_import_dart_existing() async {
50+
testFilePath = convertPath('$testPackageLibPath/test/foo_test.dart');
51+
var code = TestCode.parse(r'''
52+
import 'package:test/test.dart';
53+
54+
void f() {
55+
test^
56+
}
57+
''');
58+
var snippet = await expectValidSnippet(code);
59+
var result = applySnippet(code, snippet);
60+
expect(result, '''
61+
import 'package:test/test.dart';
62+
63+
void f() {
64+
test('test name', () {
65+
66+
});
67+
}
68+
''');
69+
}
70+
71+
Future<void> test_import_flutter() async {
72+
writeTestPackageConfig(flutter_test: true);
73+
testFilePath = convertPath('$testPackageLibPath/test/foo_test.dart');
74+
var code = TestCode.parse(r'''
75+
void f() {
76+
test^
77+
}
78+
''');
79+
var snippet = await expectValidSnippet(code);
80+
var result = applySnippet(code, snippet);
81+
expect(result, '''
82+
import 'package:flutter_test/flutter_test.dart';
83+
84+
void f() {
85+
test('test name', () {
86+
87+
});
88+
}
89+
''');
90+
}
91+
92+
Future<void> test_import_flutter_existing() async {
93+
writeTestPackageConfig(flutter_test: true);
94+
testFilePath = convertPath('$testPackageLibPath/test/foo_test.dart');
95+
var code = TestCode.parse(r'''
96+
import 'package:flutter_test/flutter_test.dart';
97+
98+
void f() {
99+
test^
100+
}
101+
''');
102+
var snippet = await expectValidSnippet(code);
103+
var result = applySnippet(code, snippet);
104+
expect(result, '''
105+
import 'package:flutter_test/flutter_test.dart';
106+
107+
void f() {
108+
test('test name', () {
109+
110+
});
111+
}
112+
''');
113+
}
114+
115+
/// Ensure we don't import package:flutter_test if package:test is already
116+
/// imported.
117+
Future<void> test_import_flutter_existingDart() async {
118+
writeTestPackageConfig(flutter_test: true);
119+
testFilePath = convertPath('$testPackageLibPath/test/foo_test.dart');
120+
var code = TestCode.parse(r'''
121+
import 'package:test/test.dart';
122+
123+
void f() {
124+
test^
125+
}
126+
''');
127+
var snippet = await expectValidSnippet(code);
128+
var result = applySnippet(code, snippet);
129+
expect(result, '''
130+
import 'package:test/test.dart';
131+
132+
void f() {
133+
test('test name', () {
134+
135+
});
136+
}
137+
''');
138+
}
139+
30140
Future<void> test_inTestFile() async {
31141
testFilePath = convertPath('$testPackageLibPath/test/foo_test.dart');
32142
var code = TestCode.parse(r'''
@@ -38,23 +148,22 @@ void f() {
38148
expect(snippet.prefix, prefix);
39149
expect(snippet.label, label);
40150
expect(snippet.change.edits, hasLength(1));
41-
var result = code.code;
42-
for (var edit in snippet.change.edits) {
43-
result = SourceEdit.applySequence(result, edit.edits);
44-
}
151+
var result = applySnippet(code, snippet);
45152
expect(result, '''
153+
import 'package:test/test.dart';
154+
46155
void f() {
47156
test('test name', () {
48157
49158
});
50159
}
51160
''');
52161
expect(snippet.change.selection!.file, testFile.path);
53-
expect(snippet.change.selection!.offset, 40);
162+
expect(snippet.change.selection!.offset, 74);
54163
expect(snippet.change.linkedEditGroups.map((group) => group.toJson()), [
55164
{
56165
'positions': [
57-
{'file': testFile.path, 'offset': 19},
166+
{'file': testFile.path, 'offset': 53},
58167
],
59168
'length': 9,
60169
'suggestions': [],

0 commit comments

Comments
 (0)