| // 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/lsp_protocol/protocol_generated.dart'; |
| import 'package:analyzer/source/line_info.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import 'server_abstract.dart'; |
| |
| void main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(SelectionRangeTest); |
| }); |
| } |
| |
| /// Additional tests are in |
| /// |
| /// test/src/computer/selection_range_computer_test.dart |
| @reflectiveTest |
| class SelectionRangeTest extends AbstractLspAnalysisServerTest { |
| Future<void> test_multiple() async { |
| final content = ''' |
| class Foo { |
| void a() { /*1*/ } |
| void b() { /*2*/ } |
| } |
| '''; |
| |
| await initialize(); |
| await openFile(mainFileUri, content); |
| final lineInfo = LineInfo.fromContent(content); |
| |
| // Send a request for two positions. |
| final regions = await getSelectionRanges(mainFileUri, [ |
| positionFromOffset(content.indexOf('/*1*/'), content), |
| positionFromOffset(content.indexOf('/*2*/'), content), |
| ]); |
| expect(regions!.length, equals(2)); |
| final firstTexts = |
| _getSelectionRangeText(lineInfo, content, regions[0]).toList(); |
| final secondTexts = |
| _getSelectionRangeText(lineInfo, content, regions[1]).toList(); |
| |
| expect( |
| firstTexts, |
| equals([ |
| '{ /*1*/ }', |
| 'void a() { /*1*/ }', |
| content.trim(), // Whole content minus the trailing newline |
| ])); |
| expect( |
| secondTexts, |
| equals([ |
| '{ /*2*/ }', |
| 'void b() { /*2*/ }', |
| content.trim(), // Whole content minus the trailing newline |
| ])); |
| } |
| |
| Future<void> test_single() async { |
| final content = ''' |
| class Foo<T> { |
| void a(String b) { |
| print((1 ^+ 2) * 3); |
| } |
| } |
| '''; |
| final contentWithoutMarker = withoutMarkers(content); |
| |
| await initialize(); |
| await openFile(mainFileUri, contentWithoutMarker); |
| final lineInfo = LineInfo.fromContent(contentWithoutMarker); |
| |
| // The returned List corresponds to the input list of positions, and not |
| // the set of ranges - each range within that list has a (recusrive) parent |
| // to walk up all ranges for that position. |
| final regions = |
| await getSelectionRanges(mainFileUri, [positionFromMarker(content)]); |
| expect(regions!.length, equals(1)); // Only one position was sent. |
| final regionTexts = |
| _getSelectionRangeText(lineInfo, contentWithoutMarker, regions.first) |
| .toList(); |
| |
| expect( |
| regionTexts, |
| equals([ |
| '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}', |
| ])); |
| } |
| |
| Iterable<String> _getSelectionRangeText( |
| LineInfo lineInfo, String content, SelectionRange range) sync* { |
| yield _rangeOfText(lineInfo, content, range.range); |
| final parent = range.parent; |
| if (parent != null) { |
| yield* _getSelectionRangeText(lineInfo, content, parent); |
| } |
| } |
| |
| String _rangeOfText(LineInfo lineInfo, String content, Range range) { |
| final startPos = range.start; |
| final endPos = range.end; |
| final start = lineInfo.getOffsetOfLine(startPos.line) + startPos.character; |
| final end = lineInfo.getOffsetOfLine(endPos.line) + endPos.character; |
| return content.substring(start, end); |
| } |
| } |