| // Copyright (c) 2018, 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_folding.dart'; | |
| import 'package:analysis_server/src/protocol_server.dart'; | |
| import 'package:analyzer/src/test_utilities/test_code_format.dart'; | |
| import 'package:analyzer_testing/src/abstract_context.dart'; | |
| import 'package:test/test.dart'; | |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; | |
| void main() { | |
| defineReflectiveSuite(() { | |
| defineReflectiveTests(FoldingComputerTest); | |
| }); | |
| } | |
| @reflectiveTest | |
| class FoldingComputerTest extends AbstractContextTest { | |
| static const commentKinds = { | |
| FoldingKind.FILE_HEADER, | |
| FoldingKind.COMMENT, | |
| FoldingKind.DOCUMENTATION_COMMENT, | |
| }; | |
| late String sourcePath; | |
| late TestCode code; | |
| List<FoldingRegion> regions = []; | |
| /// Expects no [FoldingRegion]s. | |
| /// | |
| /// If [onlyVerify] is provided, folding regions of other kinds are allowed. | |
| void expectNoRegions({Set<FoldingKind>? onlyVerify}) { | |
| expectRegions({}, onlyVerify: onlyVerify); | |
| } | |
| /// Expects to find a [FoldingRegion] for the code marked [index] with a | |
| /// [FoldingKind] of [kind]. | |
| /// | |
| /// If [onlyVerify] is provided, only folding regions with matching kinds will | |
| /// be verified. | |
| void expectRegions( | |
| Map<int, FoldingKind> expected, { | |
| Set<FoldingKind>? onlyVerify, | |
| }) { | |
| var expectedRegions = expected.entries.map((entry) { | |
| var range = code.ranges[entry.key].sourceRange; | |
| return FoldingRegion(entry.value, range.offset, range.length); | |
| }).toSet(); | |
| var actualRegions = onlyVerify == null | |
| ? regions.toSet() | |
| : regions.where((region) => onlyVerify.contains(region.kind)).toSet(); | |
| expect(actualRegions, expectedRegions); | |
| } | |
| @override | |
| void setUp() { | |
| super.setUp(); | |
| sourcePath = convertPath('$testPackageLibPath/test.dart'); | |
| } | |
| Future<void> test_annotations_class() async { | |
| var content = ''' | |
| @folded.classAnnotation1/*[0*/() | |
| @foldedClassAnnotation2/*0]*/ | |
| class MyClass {} | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.ANNOTATIONS}); | |
| } | |
| Future<void> test_annotations_class_constructor() async { | |
| var content = ''' | |
| class MyClass { | |
| @constructorAnnotation1/*[0*/ | |
| @constructorAnnotation1/*0]*/ | |
| MyClass() {} | |
| @constructorAnnotation1/*[1*/ | |
| @constructorAnnotation1/*1]*/ | |
| MyClass.named() {} | |
| } | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions( | |
| {0: FoldingKind.ANNOTATIONS, 1: FoldingKind.ANNOTATIONS}, | |
| onlyVerify: {FoldingKind.ANNOTATIONS}, | |
| ); | |
| } | |
| Future<void> test_annotations_class_field() async { | |
| var content = ''' | |
| class MyClass { | |
| @fieldAnnotation1/*[0*/ | |
| @fieldAnnotation2/*0]*/ | |
| int myField; | |
| } | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions( | |
| {0: FoldingKind.ANNOTATIONS}, | |
| onlyVerify: {FoldingKind.ANNOTATIONS}, | |
| ); | |
| } | |
| Future<void> test_annotations_class_getterSetter() async { | |
| var content = ''' | |
| class MyClass { | |
| @getterAnnotation1/*[0*/ | |
| @getterAnnotation2/*0]*/ | |
| int get myThing => 1; | |
| @setterAnnotation1/*[1*/ | |
| @setterAnnotation2/*1]*/ | |
| void set myThing(int value) {} | |
| } | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions( | |
| {0: FoldingKind.ANNOTATIONS, 1: FoldingKind.ANNOTATIONS}, | |
| onlyVerify: {FoldingKind.ANNOTATIONS}, | |
| ); | |
| } | |
| Future<void> test_annotations_class_method() async { | |
| var content = ''' | |
| class MyClass { | |
| @methodAnnotation1/*[0*/ | |
| @methodAnnotation2/*0]*/ | |
| void myMethod() {} | |
| } | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions( | |
| {0: FoldingKind.ANNOTATIONS}, | |
| onlyVerify: {FoldingKind.ANNOTATIONS}, | |
| ); | |
| } | |
| Future<void> test_annotations_multiline() async { | |
| var content = ''' | |
| @myMultilineAnnotation/*[0*/( | |
| "this", | |
| "is a test" | |
| )/*0]*/ | |
| void f() {} | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions( | |
| {0: FoldingKind.ANNOTATIONS}, | |
| onlyVerify: {FoldingKind.ANNOTATIONS}, | |
| ); | |
| } | |
| Future<void> test_annotations_multiple() async { | |
| var content = ''' | |
| @multipleAnnotations1/*[0*/( | |
| /*[1*/"this", | |
| "is a test" | |
| /*1]*/) | |
| @multipleAnnotations2() | |
| @multipleAnnotations3/*0]*/ | |
| main3() {} | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions( | |
| {0: FoldingKind.ANNOTATIONS}, | |
| onlyVerify: {FoldingKind.ANNOTATIONS}, | |
| ); | |
| } | |
| Future<void> test_annotations_singleLine() async { | |
| var content = ''' | |
| @noFoldNecessary | |
| main2() {} | |
| @noFoldsForSingleClassAnnotation | |
| class MyClass {} | |
| '''; | |
| await _computeRegions(content); | |
| expectNoRegions(); | |
| } | |
| Future<void> test_assertInitializer() async { | |
| var content = ''' | |
| class C {/*[0*/ | |
| C/*[1*/() : assert( | |
| /*[2*/true, | |
| '' | |
| /*2]*/);/*1]*/ | |
| /*0]*/} | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.CLASS_BODY, | |
| 1: FoldingKind.FUNCTION_BODY, | |
| 2: FoldingKind.INVOCATION, | |
| }); | |
| } | |
| Future<void> test_assertStatement() async { | |
| var content = ''' | |
| void f/*[0*/() { | |
| assert(/*[1*/ | |
| true, | |
| '' | |
| /*1]*/); | |
| }/*0]*/ | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY, 1: FoldingKind.INVOCATION}); | |
| } | |
| Future<void> test_class() async { | |
| var content = ''' | |
| // Content before | |
| class Person {/*[0*/ | |
| Person/*[1*/() { | |
| print("Hello, world!"); | |
| }/*1]*/ | |
| void sayHello/*[2*/() { | |
| print("Hello, world!"); | |
| }/*2]*/ | |
| /*0]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.CLASS_BODY, | |
| 1: FoldingKind.FUNCTION_BODY, | |
| 2: FoldingKind.FUNCTION_BODY, | |
| }); | |
| } | |
| Future<void> test_class_emptyBody() async { | |
| var content = ''' | |
| // Content before | |
| class C; | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectNoRegions(); | |
| } | |
| Future<void> test_comment_is_not_considered_file_header() async { | |
| var content = """ | |
| // This is not the file header/*[0*/ | |
| // It's just a comment/*0]*/ | |
| void f() {} | |
| """; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.COMMENT}); | |
| } | |
| Future<void> test_comment_multiline() async { | |
| var content = ''' | |
| /*/*[0*/ | |
| * comment 1 | |
| *//*0]*/ | |
| /* this comment starts on the same line as delimiters/*[1*/ | |
| * second line | |
| *//*1]*/ | |
| void f() {} | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.COMMENT, 1: FoldingKind.COMMENT}); | |
| } | |
| Future<void> test_comment_singleFollowedByBlankLine() async { | |
| var content = ''' | |
| void f() { | |
| // this is/*[0*/ | |
| // a comment/*0]*/ | |
| /// this is not part of it | |
| } | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.COMMENT}, onlyVerify: commentKinds); | |
| } | |
| Future<void> test_comment_singleFollowedByMulti() async { | |
| var content = ''' | |
| void f() { | |
| // this is/*[0*/ | |
| // a comment/*0]*/ | |
| /* this is not part of it */ | |
| String foo; | |
| } | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.COMMENT}, onlyVerify: commentKinds); | |
| } | |
| Future<void> test_comment_singleFollowedByTripleSlash() async { | |
| var content = ''' | |
| void f() { | |
| // this is/*[0*/ | |
| // a comment/*0]*/ | |
| /// this is not part of it | |
| } | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.COMMENT}, onlyVerify: commentKinds); | |
| } | |
| Future<void> test_constructor() async { | |
| var content = ''' | |
| // Content before | |
| class C {/*[0*/ | |
| C/*[1*/() { | |
| // | |
| }/*1]*/ | |
| /*0]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.CLASS_BODY, 1: FoldingKind.FUNCTION_BODY}); | |
| } | |
| Future<void> test_constructor_emptyBody_semicolon() async { | |
| var content = ''' | |
| // Content before | |
| class C {/*[0*/ | |
| C(); | |
| /*0]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.CLASS_BODY}); | |
| } | |
| Future<void> test_constructor_invocations() async { | |
| var content = ''' | |
| // Content before | |
| final a = new Text(/*[0*/ | |
| "Hello, world!", | |
| /*0]*/); | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.INVOCATION}); | |
| } | |
| Future<void> test_constructor_named() async { | |
| var content = ''' | |
| // Content before | |
| class C {/*[0*/ | |
| C.foo/*[1*/() { | |
| // | |
| }/*1]*/ | |
| /*0]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.CLASS_BODY, 1: FoldingKind.FUNCTION_BODY}); | |
| } | |
| Future<void> test_constructor_new() async { | |
| var content = ''' | |
| // Content before | |
| class C {/*[0*/ | |
| new/*[1*/() { | |
| // | |
| }/*1]*/ | |
| /*0]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.CLASS_BODY, 1: FoldingKind.FUNCTION_BODY}); | |
| } | |
| Future<void> test_extensionType() async { | |
| var content = ''' | |
| // Content before | |
| extension type E(int it) {/*[0*/ | |
| void m/*[1*/() { | |
| }/*1]*/ | |
| /*0]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.CLASS_BODY, 1: FoldingKind.FUNCTION_BODY}); | |
| } | |
| Future<void> test_file_header() async { | |
| var content = """ | |
| // Copyright some year by some people/*[0*/ | |
| // See LICENCE etc./*0]*/ | |
| // This is not the file header | |
| // It's just a comment | |
| void f() {} | |
| """; | |
| await _computeRegions(content); | |
| expectRegions( | |
| {0: FoldingKind.FILE_HEADER}, | |
| onlyVerify: {FoldingKind.FILE_HEADER}, | |
| ); | |
| } | |
| Future<void> test_file_header_does_not_include_block_comments() async { | |
| var content = """ | |
| /* | |
| * Copyright some year by some people | |
| * See LICENCE etc. | |
| */ | |
| /* This shouldn't be part of the file header */ | |
| void f() {} | |
| """; | |
| await _computeRegions(content); | |
| expectNoRegions(onlyVerify: {FoldingKind.FILE_HEADER}); | |
| } | |
| Future<void> test_file_header_with_no_function_comment() async { | |
| var content = ''' | |
| // Copyright some year by some people/*[0*/ | |
| // See LICENCE etc./*0]*/ | |
| void f() {} | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FILE_HEADER}); | |
| } | |
| Future<void> test_file_header_with_non_end_of_line_comment() async { | |
| var content = """ | |
| // Copyright some year by some people/*[0*/ | |
| // See LICENCE etc./*0]*/ | |
| /* This shouldn't be part of the file header */ | |
| void f() {} | |
| """; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FILE_HEADER}); | |
| } | |
| Future<void> test_file_header_with_script_prefix() async { | |
| var content = """ | |
| #! /usr/bin/dart | |
| // Copyright some year by some people/*[0*/ | |
| // See LICENCE etc./*0]*/ | |
| // This is not the file header | |
| // It's just a comment | |
| void f() {} | |
| """; | |
| await _computeRegions(content); | |
| expectRegions( | |
| {0: FoldingKind.FILE_HEADER}, | |
| onlyVerify: {FoldingKind.FILE_HEADER}, | |
| ); | |
| } | |
| Future<void> test_fileHeader_singleFollowedByBlank() async { | |
| var content = ''' | |
| // this is/*[0*/ | |
| // a file header/*0]*/ | |
| // this is not part of it | |
| void f() {} | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FILE_HEADER}); | |
| } | |
| Future<void> test_function() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| print("Hello, world!"); | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY}); | |
| } | |
| Future<void> test_function_expression_invocation() async { | |
| var content = ''' | |
| // Content before | |
| getFunc/*[0*/() => (String a, String b) { | |
| print(a); | |
| };/*0]*/ | |
| main2/*[1*/() { | |
| getFunc()(/*[2*/ | |
| "one", | |
| "two" | |
| /*2]*/); | |
| }/*1]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.FUNCTION_BODY, | |
| 2: FoldingKind.INVOCATION, | |
| }); | |
| } | |
| Future<void> test_function_expression_underscore_preWildcards() async { | |
| var content = ''' | |
| // /*[0*/ | |
| // @dart = 3.4 | |
| // (pre wildcard-variables)/*0]*/ | |
| // Content before | |
| void f/*[1*/() { | |
| _/*[2*/(){ | |
| }/*2]*/ | |
| }/*1]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FILE_HEADER, | |
| 1: FoldingKind.FUNCTION_BODY, | |
| 2: FoldingKind.FUNCTION_BODY, | |
| }); | |
| } | |
| Future<void> test_function_expression_wildcard() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| _/*[1*/(){ | |
| }/*1]*/ | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY, 1: FoldingKind.FUNCTION_BODY}); | |
| } | |
| Future<void> test_function_with_dart_doc() async { | |
| var content = ''' | |
| // Content before | |
| /// This is a doc comment/*[0*/ | |
| /// that spans lines/*0]*/ | |
| void f/*[1*/() { | |
| print("Hello, world!"); | |
| }/*1]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.DOCUMENTATION_COMMENT, | |
| 1: FoldingKind.FUNCTION_BODY, | |
| }); | |
| } | |
| Future<void> test_invocations() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| print(/*[1*/ | |
| "Hello, world!", | |
| /*1]*/); | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY, 1: FoldingKind.INVOCATION}); | |
| } | |
| Future<void> test_literal_list() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final List<String> things = <String>[/*[1*/ | |
| "one", | |
| "two" | |
| /*1]*/]; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY, 1: FoldingKind.LITERAL}); | |
| } | |
| Future<void> test_literal_list_insideNullAwareElement() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final List<List<String>> things = <List<String>>[/*[1*/ | |
| ?<String>[/*[2*/ | |
| "one", | |
| "two" | |
| /*2]*/]; | |
| /*1]*/]; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.LITERAL, | |
| 2: FoldingKind.LITERAL, | |
| }); | |
| } | |
| Future<void> test_literal_list_insideNullAwareKey() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final Map<List<String>, bool> things = <List<String>, bool>{/*[1*/ | |
| ?<String>[/*[2*/ | |
| "one", | |
| "two" | |
| /*2]*/]: true | |
| /*1]*/}; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.LITERAL, | |
| 2: FoldingKind.LITERAL, | |
| }); | |
| } | |
| Future<void> test_literal_list_insideNullAwareValue() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final Map<Symbol, List<String>> things = <Symbol, List<String>>{/*[1*/ | |
| #key: ?<String>[/*[2*/ | |
| "one", | |
| "two" | |
| /*2]*/] | |
| /*1]*/}; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.LITERAL, | |
| 2: FoldingKind.LITERAL, | |
| }); | |
| } | |
| Future<void> test_literal_list_withNullAwareElement() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final List<String> things = <String>[/*[1*/ | |
| "one", | |
| ?null | |
| "two" | |
| /*1]*/]; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY, 1: FoldingKind.LITERAL}); | |
| } | |
| Future<void> test_literal_map() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final Map<String, String> things = <String, String>{/*[1*/ | |
| "one": "one", | |
| "two": "two" | |
| /*1]*/}; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY, 1: FoldingKind.LITERAL}); | |
| } | |
| Future<void> test_literal_map_insideNullAwareKey() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final Map<Map<String, int>, false> things = <Map<String, int>, false>{/*[1*/ | |
| ?<String, int>{/*[2*/ | |
| "one": 1, | |
| "two": 2 | |
| /*2]*/}: true | |
| /*1]*/}; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.LITERAL, | |
| 2: FoldingKind.LITERAL, | |
| }); | |
| } | |
| Future<void> test_literal_map_insideNullAwareValue() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final Map<Symbol, Map<String, int>> things = <Symbol, Map<String, int>>{/*[1*/ | |
| #key: ?<String, int>{/*[2*/ | |
| "one": 1, | |
| "two": 2 | |
| /*2]*/} | |
| /*1]*/}; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.LITERAL, | |
| 2: FoldingKind.LITERAL, | |
| }); | |
| } | |
| Future<void> test_literal_map_withNullAwareKey() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final Map<String, int> things = <String, int>{/*[1*/ | |
| "one": 1, | |
| ?null: 0, | |
| "two": 2 | |
| /*1]*/}; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY, 1: FoldingKind.LITERAL}); | |
| } | |
| Future<void> test_literal_map_withNullAwareValue() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final Map<String, int> things = <String, int>{/*[1*/ | |
| "one": 1, | |
| "null": ?null, | |
| "two": 2 | |
| /*1]*/}; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY, 1: FoldingKind.LITERAL}); | |
| } | |
| Future<void> test_literal_record() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final r = (/*[1*/ | |
| "one", | |
| 2, | |
| (/*[2*/ | |
| 'nested', | |
| 3, | |
| 'field record', | |
| /*2]*/), | |
| /*1]*/); | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.LITERAL, | |
| 2: FoldingKind.LITERAL, | |
| }); | |
| } | |
| Future<void> test_literal_set_insideNullAwareElement() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final Set<Set<String>> things = <Set<String>>{/*[1*/ | |
| ?<String>{/*[2*/ | |
| "one", | |
| "two" | |
| /*2]*/} | |
| /*1]*/}; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.LITERAL, | |
| 2: FoldingKind.LITERAL, | |
| }); | |
| } | |
| Future<void> test_literal_set_insideNullAwareKey() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final Map<Set<String>, bool> things = <Set<String>, bool>{/*[1*/ | |
| ?<String>{/*[2*/ | |
| "one", | |
| "two" | |
| /*2]*/}: true | |
| /*1]*/}; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.LITERAL, | |
| 2: FoldingKind.LITERAL, | |
| }); | |
| } | |
| Future<void> test_literal_set_insideNullAwareValue() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final Map<Symbol, Set<String>> things = <Symbol, Set<String>>{/*[1*/ | |
| #key: ?<String>{/*[2*/ | |
| "one", | |
| "two" | |
| /*2]*/} | |
| /*1]*/}; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.LITERAL, | |
| 2: FoldingKind.LITERAL, | |
| }); | |
| } | |
| Future<void> test_literal_set_withNullAwareElement() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| final Set<String> things = <String>{/*[1*/ | |
| "one", | |
| ?null | |
| "two" | |
| /*1]*/}; | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY, 1: FoldingKind.LITERAL}); | |
| } | |
| Future<void> test_mixin() async { | |
| var content = ''' | |
| // Content before | |
| mixin M {/*[0*/ | |
| void m/*[1*/() { | |
| print("Got to m"); | |
| }/*1]*/ | |
| /*0]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.CLASS_BODY, 1: FoldingKind.FUNCTION_BODY}); | |
| } | |
| Future<void> test_multiple_directive_types() async { | |
| var content = """ | |
| import/*[0*/ 'dart:async'; | |
| // We can have comments | |
| import 'package:a/b.dart'; | |
| import 'package:b/c.dart'; | |
| export '../a.dart';/*0]*/ | |
| void f() {} | |
| """; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.DIRECTIVES}); | |
| } | |
| Future<void> test_multiple_import_directives() async { | |
| var content = """ | |
| import/*[0*/ 'dart:async'; | |
| // We can have comments | |
| import 'package:a/b.dart'; | |
| import 'package:b/c.dart'; | |
| import '../a.dart';/*0]*/ | |
| void f() {} | |
| """; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.DIRECTIVES}); | |
| } | |
| Future<void> test_multiple_import_directives_partFile() async { | |
| var content = """ | |
| part of/*[0*/ 'part.dart'; | |
| import 'dart:async'; | |
| // We can have comments | |
| import 'package:a/b.dart'; | |
| import 'package:b/c.dart'; | |
| import '../a.dart';/*0]*/ | |
| void f() {} | |
| """; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.DIRECTIVES}); | |
| } | |
| Future<void> test_nested_function() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| doPrint/*[1*/() { | |
| print("Hello, world!"); | |
| }/*1]*/ | |
| doPrint(); | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY, 1: FoldingKind.FUNCTION_BODY}); | |
| } | |
| Future<void> test_nested_invocations() async { | |
| var content = ''' | |
| // Content before | |
| void f/*[0*/() { | |
| a(/*[1*/ | |
| b(/*[2*/ | |
| c(/*[3*/ | |
| d() | |
| /*3]*/), | |
| /*2]*/), | |
| /*1]*/); | |
| }/*0]*/ | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.INVOCATION, | |
| 2: FoldingKind.INVOCATION, | |
| 3: FoldingKind.INVOCATION, | |
| }); | |
| } | |
| Future<void> test_parameters_function() async { | |
| var content = ''' | |
| foo/*[0*/( | |
| /*[1*/String aaaaa, | |
| String bbbbb, { | |
| String ccccc, | |
| }/*1]*/) {}/*0]*/ | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.FUNCTION_BODY, 1: FoldingKind.PARAMETERS}); | |
| } | |
| Future<void> test_parameters_method() async { | |
| var content = ''' | |
| class C {/*[0*/ | |
| C/*[1*/( | |
| /*[2*/String aaaaa, | |
| String bbbbb, | |
| /*2]*/) : super();/*1]*/ | |
| /*0]*/} | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.CLASS_BODY, | |
| 1: FoldingKind.FUNCTION_BODY, | |
| 2: FoldingKind.PARAMETERS, | |
| }); | |
| } | |
| Future<void> test_primaryConstructor_constructorBody() async { | |
| var content = ''' | |
| // Content before | |
| class C(/*[0*/ | |
| var int x, | |
| var int y, | |
| /*0]*/) {/*[1*/ | |
| this/*[2*/ { | |
| print(''); | |
| }/*2]*/ | |
| /*1]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.PARAMETERS, | |
| 1: FoldingKind.CLASS_BODY, | |
| 2: FoldingKind.FUNCTION_BODY, | |
| }); | |
| } | |
| Future<void> test_primaryConstructor_constructorInitializer() async { | |
| var content = ''' | |
| // Content before | |
| class C(/*[0*/ | |
| var int x, | |
| var int y, | |
| /*0]*/) {/*[1*/ | |
| this/*[2*/ : xPlus = x+1, | |
| yPlus = y+1;/*2]*/ | |
| /*1]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.PARAMETERS, | |
| 1: FoldingKind.CLASS_BODY, | |
| 2: FoldingKind.FUNCTION_BODY, | |
| }); | |
| } | |
| Future<void> test_primaryConstructor_docComment_multiLine() async { | |
| var content = ''' | |
| // Content before | |
| class C(/*[0*/ | |
| var int x, | |
| /// The comment for [y]/*[1*/ | |
| /// needs multiple lines./*1]*/ | |
| var int y/*0]*/) {/*[2*/ | |
| void m1() {} | |
| void m2() {} | |
| /*2]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.PARAMETERS, | |
| 1: FoldingKind.DOCUMENTATION_COMMENT, | |
| 2: FoldingKind.CLASS_BODY, | |
| }); | |
| } | |
| Future<void> test_primaryConstructor_docComment_singleLine() async { | |
| var content = ''' | |
| // Content before | |
| class C(/*[0*/ | |
| var int x, | |
| /// The comment for [y]. | |
| var int y/*0]*/) {/*[1*/ | |
| void m1() {} | |
| void m2() {} | |
| /*1]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.PARAMETERS, 1: FoldingKind.CLASS_BODY}); | |
| } | |
| Future<void> test_primaryConstructor_emptyClassBody_braces() async { | |
| var content = ''' | |
| // Content before | |
| class C(/*[0*/ | |
| var int x, | |
| var int y, | |
| /*0]*/) extends Object {} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.PARAMETERS}); | |
| } | |
| Future<void> test_primaryConstructor_emptyClassBody_semicolon() async { | |
| var content = ''' | |
| // Content before | |
| class C(/*[0*/ | |
| var int x, | |
| var int y, | |
| /*0]*/) extends Object; | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.PARAMETERS}); | |
| } | |
| Future<void> test_primaryConstructor_nonEmptyClassBody() async { | |
| var content = ''' | |
| // Content before | |
| class C(/*[0*/ | |
| var int x, | |
| var int y, | |
| /*0]*/) {/*[1*/ | |
| // | |
| /*1]*/} | |
| // Content after | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({0: FoldingKind.PARAMETERS, 1: FoldingKind.CLASS_BODY}); | |
| } | |
| Future<void> test_single_import_directives() async { | |
| var content = """ | |
| import 'dart:async'; | |
| void f() {} | |
| """; | |
| await _computeRegions(content); | |
| expectNoRegions(); | |
| } | |
| Future<void> test_tryCatchFinally() async { | |
| var content = ''' | |
| void f/*[0*/() { | |
| try {/*[1*/ | |
| print(''); | |
| print('');/*1]*/ | |
| } on ArgumentError catch (_) {/*[2*/ | |
| print(''); | |
| print('');/*2]*/ | |
| } catch (e) {/*[3*/ | |
| print(''); | |
| print('');/*3]*/ | |
| } finally {/*[4*/ | |
| print(''); | |
| print('');/*4]*/ | |
| } | |
| }/*0]*/ | |
| '''; | |
| await _computeRegions(content); | |
| expectRegions({ | |
| 0: FoldingKind.FUNCTION_BODY, | |
| 1: FoldingKind.BLOCK, | |
| 2: FoldingKind.BLOCK, | |
| 3: FoldingKind.BLOCK, | |
| 4: FoldingKind.BLOCK, | |
| }); | |
| } | |
| Future<void> _computeRegions(String sourceContent) async { | |
| code = TestCode.parseNormalized(sourceContent); | |
| var file = newFile(sourcePath, code.code); | |
| var result = await getResolvedUnit(file); | |
| var computer = DartUnitFoldingComputer(result.lineInfo, result.unit); | |
| regions = computer.compute(); | |
| } | |
| } |