blob: 09785322b5ce72e0d94b4a0eafcd906860f1d0de [file] [log] [blame]
// Copyright (c) 2021, 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/computer/computer_selection_ranges.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';
import '../../abstract_context.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(SelectionRangeComputerTest);
});
}
@reflectiveTest
class SelectionRangeComputerTest extends AbstractContextTest {
late String sourcePath;
@override
void setUp() {
super.setUp();
sourcePath = convertPath('$testPackageLibPath/test.dart');
}
Future<void> test_arguments() async {
var content = TestCode.parse('''
class Foo {
Foo({String arg1});
}
final foo = Foo(arg1: "^test");
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'"test"',
'arg1: "test"',
'(arg1: "test")',
'Foo(arg1: "test")',
'foo = Foo(arg1: "test")',
'final foo = Foo(arg1: "test")',
'final foo = Foo(arg1: "test");',
],
);
}
Future<void> test_class_augmentation() async {
newFile('$testPackageLibPath/a.dart', '''
part 'test.dart';
class Foo {}
''');
var content = TestCode.parse('''
part of a.dart;
augment class Foo {
void a(String b) {
print((1 ^+ 2) * 3);
}
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'1 + 2',
'(1 + 2)',
'(1 + 2) * 3',
'((1 + 2) * 3)',
'print((1 + 2) * 3)',
'print((1 + 2) * 3);',
'{\n print((1 + 2) * 3);\n }',
'void a(String b) {\n print((1 + 2) * 3);\n }',
'augment class Foo {\n void a(String b) {\n print((1 + 2) * 3);\n }\n}',
],
);
}
Future<void> test_class_definition() async {
var content = TestCode.parse('^class Foo<T> {}');
var regions = await _computeSelectionRanges(content);
_expectRegions(regions, content, ['class Foo<T> {}']);
}
Future<void> test_class_fields() async {
var content = TestCode.parse('''
class Foo<T> {
^String a = 'test';
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'String',
"String a = 'test'",
"String a = 'test';",
"class Foo<T> {\n String a = 'test';\n}",
],
);
}
Future<void> test_class_fields_augmentation() async {
newFile('$testPackageLibPath/a.dart', '''
part 'test.dart';
class Foo {
String a = 'test';
}
''');
var content = TestCode.parse('''
part of 'a.dart';
augment class Foo {
augment ^String get a => 'test2';
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'String',
"augment String get a => 'test2';",
"augment class Foo {\n augment String get a => 'test2';\n}",
],
);
}
Future<void> test_constructor_augmentation() async {
newFile('$testPackageLibPath/a.dart', '''
part 'test.dart';
class Foo {
Foo();
}
''');
var content = TestCode.parse('''
part of 'a.dart';
augment class Foo {
augment Foo(^);
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'()',
'augment Foo();',
'augment class Foo {\n augment Foo();\n}',
],
);
}
Future<void> test_constructorCall() async {
var content = TestCode.parse('''
class Foo {
Foo(String b);
}
final foo = Foo("^test");
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'"test"',
'("test")',
'Foo("test")',
'foo = Foo("test")',
'final foo = Foo("test")',
'final foo = Foo("test");',
],
);
}
Future<void> test_extensionType() async {
var content = TestCode.parse('''
extension type E<T>(int it) {
void void foo() {
(1 ^+ 2) * 3;
}
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'1 + 2',
'(1 + 2)',
'(1 + 2) * 3',
'(1 + 2) * 3;',
'{\n'
' (1 + 2) * 3;\n'
' }',
'void foo() {\n'
' (1 + 2) * 3;\n'
' }',
'extension type E<T>(int it) {\n'
' void void foo() {\n'
' (1 + 2) * 3;\n'
' }\n'
'}',
],
);
}
Future<void> test_field_recordType() async {
var content = TestCode.parse('''
class C<T> {
(^int, int) r = (0, 1);
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'int',
'(int, int)',
'(int, int) r = (0, 1)',
'(int, int) r = (0, 1);',
'class C<T> {\n (int, int) r = (0, 1);\n}',
],
);
}
Future<void> test_method() async {
var content = TestCode.parse('''
class Foo<T> {
void a(String b) {
print((1 ^+ 2) * 3);
}
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'1 + 2',
'(1 + 2)',
'(1 + 2) * 3',
'((1 + 2) * 3)',
'print((1 + 2) * 3)',
'print((1 + 2) * 3);',
'{\n print((1 + 2) * 3);\n }',
'void a(String b) {\n print((1 + 2) * 3);\n }',
'class Foo<T> {\n void a(String b) {\n print((1 + 2) * 3);\n }\n}',
],
);
}
Future<void> test_method_augmentation() async {
newFile('$testPackageLibPath/a.dart', '''
part 'test.dart';
class Foo {
void f() {}
}
''');
var content = TestCode.parse('''
part of 'a.dart';
augment class Foo {
augment void f() {
print((1 ^+ 2) * 3);
}
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'1 + 2',
'(1 + 2)',
'(1 + 2) * 3',
'((1 + 2) * 3)',
'print((1 + 2) * 3)',
'print((1 + 2) * 3);',
'{\n print((1 + 2) * 3);\n }',
'augment void f() {\n print((1 + 2) * 3);\n }',
'augment class Foo {\n augment void f() {\n print((1 + 2) * 3);\n }\n}',
],
);
}
Future<void> test_methodLambda() async {
var content = TestCode.parse('''
class Foo<T> {
void a(String b) => print((1 ^+ 2) * 3);
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'1 + 2',
'(1 + 2)',
'(1 + 2) * 3',
'((1 + 2) * 3)',
'print((1 + 2) * 3)',
'=> print((1 + 2) * 3);',
'void a(String b) => print((1 + 2) * 3);',
'class Foo<T> {\n void a(String b) => print((1 + 2) * 3);\n}',
],
);
}
Future<void> test_mixin_augmentation() async {
newFile('$testPackageLibPath/a.dart', '''
part 'test.dart';
mixin Foo {
void a(String b){}
}
''');
var content = TestCode.parse('''
part of 'a.dart';
augment mixin Foo {
augment void a(String b) {
print((1 ^+ 2) * 3);
}
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'1 + 2',
'(1 + 2)',
'(1 + 2) * 3',
'((1 + 2) * 3)',
'print((1 + 2) * 3)',
'print((1 + 2) * 3);',
'{\n print((1 + 2) * 3);\n }',
'augment void a(String b) {\n print((1 + 2) * 3);\n }',
'augment mixin Foo {\n augment void a(String b) {\n print((1 + 2) * 3);\n }\n}',
],
);
}
Future<void> test_pattern_relational() async {
var content = TestCode.parse('''
final a = switch(123) {
== ^0 => 'zero',
_ => 'other'
};
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(regions, content, [
'0',
'== 0',
'== 0 => \'zero\'',
'switch(123) {\n'
' == 0 => \'zero\',\n'
' _ => \'other\'\n'
'}',
'a = switch(123) {\n'
' == 0 => \'zero\',\n'
' _ => \'other\'\n'
'}',
'final a = switch(123) {\n'
' == 0 => \'zero\',\n'
' _ => \'other\'\n'
'}',
'final a = switch(123) {\n'
' == 0 => \'zero\',\n'
' _ => \'other\'\n'
'};'
]);
}
Future<void> test_pattern_types() async {
var content = TestCode.parse('''
final a = switch (Object()) {
Square(length: v^ar l) => l * l,
Circle(radius: var r) => math.pi * r * r
};
class Square {
final int length;
Square(this.length);
}
class Circle {
final int length;
Circle(this.radius);
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(regions, content, [
'var l',
'length: var l',
'Square(length: var l)',
'Square(length: var l) => l * l',
'switch (Object()) {\n'
' Square(length: var l) => l * l,\n'
' Circle(radius: var r) => math.pi * r * r\n'
'}',
'a = switch (Object()) {\n'
' Square(length: var l) => l * l,\n'
' Circle(radius: var r) => math.pi * r * r\n'
'}',
'final a = switch (Object()) {\n'
' Square(length: var l) => l * l,\n'
' Circle(radius: var r) => math.pi * r * r\n'
'}',
'final a = switch (Object()) {\n'
' Square(length: var l) => l * l,\n'
' Circle(radius: var r) => math.pi * r * r\n'
'};'
]);
}
Future<void> test_topLevelFunction() async {
var content = TestCode.parse('''
void a(String b) {
print((1 ^+ 2) * 3);
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'1 + 2',
'(1 + 2)',
'(1 + 2) * 3',
'((1 + 2) * 3)',
'print((1 + 2) * 3)',
'print((1 + 2) * 3);',
'{\n print((1 + 2) * 3);\n}',
'(String b) {\n print((1 + 2) * 3);\n}',
'void a(String b) {\n print((1 + 2) * 3);\n}',
],
);
}
Future<void> test_topLevelFunction_augmentation() async {
newFile('$testPackageLibPath/a.dart', '''
part 'test.dart';
void a(String b) {}
''');
var content = TestCode.parse('''
part of 'a.dart';
augment void a(String b) {
print((1 ^+ 2) * 3);
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'1 + 2',
'(1 + 2)',
'(1 + 2) * 3',
'((1 + 2) * 3)',
'print((1 + 2) * 3)',
'print((1 + 2) * 3);',
'{\n print((1 + 2) * 3);\n}',
'(String b) {\n print((1 + 2) * 3);\n}',
'augment void a(String b) {\n print((1 + 2) * 3);\n}',
],
);
}
Future<void> test_topLevelFunction_record() async {
var content = TestCode.parse('''
void f() {
var r = (x: 3, ^y: 2);
}
''');
var regions = await _computeSelectionRanges(content);
_expectRegions(
regions,
content,
[
'y',
'y:',
'y: 2',
'(x: 3, y: 2)',
'r = (x: 3, y: 2)',
'var r = (x: 3, y: 2)',
'var r = (x: 3, y: 2);',
'{\n var r = (x: 3, y: 2);\n}',
'() {\n var r = (x: 3, y: 2);\n}',
'void f() {\n var r = (x: 3, y: 2);\n}',
],
);
}
Future<void> test_whitespace() async {
var content = TestCode.parse('^ class Foo {}');
var regions = await _computeSelectionRanges(content);
expect(regions, isEmpty);
}
Future<List<SelectionRange>?> _computeSelectionRanges(TestCode code) async {
var file = newFile(sourcePath, code.code);
var result = await getResolvedUnit(file);
var computer =
DartSelectionRangeComputer(result.unit, code.position.offset);
return computer.compute();
}
/// Checks the text of [regions] against [expected].
void _expectRegions(
List<SelectionRange>? regions, TestCode code, List<String> expected) {
var actual = regions!
.map((region) =>
code.code.substring(region.offset, region.offset + region.length))
.toList();
expect(actual, equals(expected));
}
}