Use @isTest and @isTestGroup to understand executable element as a test/group.
R=brianwilkerson@google.com, devoncarew@google.com
Bug: https://github.com/flutter/flutter-intellij/issues/2055
Change-Id: I7c8e7639d111eca63df0780ebdec182573493047
Reviewed-on: https://dart-review.googlesource.com/53690
Reviewed-by: Devon Carew <devoncarew@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/computer/computer_outline.dart b/pkg/analysis_server/lib/src/computer/computer_outline.dart
index 3516bbe..c086d92 100644
--- a/pkg/analysis_server/lib/src/computer/computer_outline.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_outline.dart
@@ -365,6 +365,9 @@
* test package.
*/
bool isGroup(engine.ExecutableElement element) {
+ if (element != null && element.hasIsTestGroup) {
+ return true;
+ }
return element is engine.FunctionElement &&
element.name == 'group' &&
_isInsideTestPackage(element);
@@ -375,6 +378,9 @@
* test package.
*/
bool isTest(engine.ExecutableElement element) {
+ if (element != null && element.hasIsTest) {
+ return true;
+ }
return element is engine.FunctionElement &&
element.name == 'test' &&
_isInsideTestPackage(element);
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index dccf6a6..eb77a4a 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -68,12 +68,24 @@
Source addMetaPackageSource() => addPackageSource('meta', 'meta.dart', r'''
library meta;
+const _IsTest isTest = const _IsTest();
+
+const _IsTestGroup isTestGroup = const _IsTestGroup();
+
const Required required = const Required();
class Required {
final String reason;
const Required([this.reason]);
}
+
+class _IsTest {
+ const _IsTest();
+}
+
+class _IsTestGroup {
+ const _IsTestGroup();
+}
''');
Source addPackageSource(String packageName, String filePath, String content) {
diff --git a/pkg/analysis_server/test/src/computer/outline_computer_test.dart b/pkg/analysis_server/test/src/computer/outline_computer_test.dart
index 316cf31..7f3a6ce 100644
--- a/pkg/analysis_server/test/src/computer/outline_computer_test.dart
+++ b/pkg/analysis_server/test/src/computer/outline_computer_test.dart
@@ -546,6 +546,124 @@
expect(outline, isNotNull);
}
+ test_isTest_isTestGroup() async {
+ addMetaPackageSource();
+ Outline outline = await _computeOutline('''
+import 'package:meta/meta.dart';
+
+@isTestGroup
+void myGroup(name, body()) {}
+
+@isTest
+void myTest(name) {}
+
+void main() {
+ myGroup('group1', () {
+ myGroup('group1_1', () {
+ myTest('test1_1_1');
+ myTest('test1_1_2');
+ });
+ myGroup('group1_2', () {
+ myTest('test1_2_1');
+ });
+ });
+ myGroup('group2', () {
+ myTest('test2_1');
+ myTest('test2_2');
+ });
+}
+''');
+ // unit
+ List<Outline> unit_children = outline.children;
+ expect(unit_children, hasLength(3));
+ // main
+ Outline main_outline = unit_children[2];
+ _expect(main_outline,
+ kind: ElementKind.FUNCTION,
+ name: 'main',
+ offset: testCode.indexOf("main() {"),
+ parameters: '()',
+ returnType: 'void');
+ List<Outline> main_children = main_outline.children;
+ expect(main_children, hasLength(2));
+ // group1
+ Outline group1_outline = main_children[0];
+ _expect(group1_outline,
+ kind: ElementKind.UNIT_TEST_GROUP,
+ length: 7,
+ name: 'group("group1")',
+ offset: testCode.indexOf("myGroup('group1'"));
+ List<Outline> group1_children = group1_outline.children;
+ expect(group1_children, hasLength(2));
+ // group1_1
+ Outline group1_1_outline = group1_children[0];
+ _expect(group1_1_outline,
+ kind: ElementKind.UNIT_TEST_GROUP,
+ length: 7,
+ name: 'group("group1_1")',
+ offset: testCode.indexOf("myGroup('group1_1'"));
+ List<Outline> group1_1_children = group1_1_outline.children;
+ expect(group1_1_children, hasLength(2));
+ // test1_1_1
+ Outline test1_1_1_outline = group1_1_children[0];
+ _expect(test1_1_1_outline,
+ kind: ElementKind.UNIT_TEST_TEST,
+ leaf: true,
+ length: 6,
+ name: 'test("test1_1_1")',
+ offset: testCode.indexOf("myTest('test1_1_1'"));
+ // test1_1_1
+ Outline test1_1_2_outline = group1_1_children[1];
+ _expect(test1_1_2_outline,
+ kind: ElementKind.UNIT_TEST_TEST,
+ leaf: true,
+ length: 6,
+ name: 'test("test1_1_2")',
+ offset: testCode.indexOf("myTest('test1_1_2'"));
+ // group1_2
+ Outline group1_2_outline = group1_children[1];
+ _expect(group1_2_outline,
+ kind: ElementKind.UNIT_TEST_GROUP,
+ length: 7,
+ name: 'group("group1_2")',
+ offset: testCode.indexOf("myGroup('group1_2'"));
+ List<Outline> group1_2_children = group1_2_outline.children;
+ expect(group1_2_children, hasLength(1));
+ // test2_1
+ Outline test1_2_1_outline = group1_2_children[0];
+ _expect(test1_2_1_outline,
+ kind: ElementKind.UNIT_TEST_TEST,
+ leaf: true,
+ length: 6,
+ name: 'test("test1_2_1")',
+ offset: testCode.indexOf("myTest('test1_2_1'"));
+ // group2
+ Outline group2_outline = main_children[1];
+ _expect(group2_outline,
+ kind: ElementKind.UNIT_TEST_GROUP,
+ length: 7,
+ name: 'group("group2")',
+ offset: testCode.indexOf("myGroup('group2'"));
+ List<Outline> group2_children = group2_outline.children;
+ expect(group2_children, hasLength(2));
+ // test2_1
+ Outline test2_1_outline = group2_children[0];
+ _expect(test2_1_outline,
+ kind: ElementKind.UNIT_TEST_TEST,
+ leaf: true,
+ length: 6,
+ name: 'test("test2_1")',
+ offset: testCode.indexOf("myTest('test2_1'"));
+ // test2_2
+ Outline test2_2_outline = group2_children[1];
+ _expect(test2_2_outline,
+ kind: ElementKind.UNIT_TEST_TEST,
+ leaf: true,
+ length: 6,
+ name: 'test("test2_2")',
+ offset: testCode.indexOf("myTest('test2_2'"));
+ }
+
test_localFunctions() async {
Outline unitOutline = await _computeOutline('''
class A {
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 5b2237b..ea8ebbb 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -618,6 +618,16 @@
bool get hasFactory;
/**
+ * Return `true` if this element has an annotation of the form `@isTest`.
+ */
+ bool get hasIsTest;
+
+ /**
+ * Return `true` if this element has an annotation of the form `@isTestGroup`.
+ */
+ bool get hasIsTestGroup;
+
+ /**
* Return `true` if this element has an annotation of the form `@JS(..)`.
*/
bool get hasJS;
@@ -889,6 +899,18 @@
bool get isImmutable;
/**
+ * Return `true` if this annotation marks the associated member as running
+ * a single test.
+ */
+ bool get isIsTest;
+
+ /**
+ * Return `true` if this annotation marks the associated member as running
+ * a test group.
+ */
+ bool get isIsTestGroup;
+
+ /**
* Return `true` if this annotation marks the associated element with the `JS`
* annotation.
*/
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 8fa0d0b..c81779b 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -2854,6 +2854,18 @@
static String _IMMUTABLE_VARIABLE_NAME = "immutable";
/**
+ * The name of the top-level variable used to mark a function as running
+ * a single test.
+ */
+ static String _IS_TEST_VARIABLE_NAME = "isTest";
+
+ /**
+ * The name of the top-level variable used to mark a function as running
+ * a test group.
+ */
+ static String _IS_TEST_GROUP_VARIABLE_NAME = "isTestGroup";
+
+ /**
* The name of the class used to JS annotate an element.
*/
static String _JS_CLASS_NAME = "JS";
@@ -2983,6 +2995,18 @@
element.library?.name == _META_LIB_NAME;
@override
+ bool get isIsTest =>
+ element is PropertyAccessorElement &&
+ element.name == _IS_TEST_VARIABLE_NAME &&
+ element.library?.name == _META_LIB_NAME;
+
+ @override
+ bool get isIsTestGroup =>
+ element is PropertyAccessorElement &&
+ element.name == _IS_TEST_GROUP_VARIABLE_NAME &&
+ element.library?.name == _META_LIB_NAME;
+
+ @override
bool get isJS =>
element is ConstructorElement &&
element.enclosingElement.name == _JS_CLASS_NAME &&
@@ -3214,6 +3238,14 @@
}
@override
+ bool get hasIsTest =>
+ metadata.any((ElementAnnotation annotation) => annotation.isIsTest);
+
+ @override
+ bool get hasIsTestGroup =>
+ metadata.any((ElementAnnotation annotation) => annotation.isIsTestGroup);
+
+ @override
bool get hasJS =>
metadata.any((ElementAnnotation annotation) => annotation.isJS);
@@ -7556,6 +7588,12 @@
bool get hasFactory => false;
@override
+ bool get hasIsTest => false;
+
+ @override
+ bool get hasIsTestGroup => false;
+
+ @override
bool get hasJS => false;
@override
diff --git a/pkg/analyzer/lib/src/dart/element/handle.dart b/pkg/analyzer/lib/src/dart/element/handle.dart
index a5f7cbe..541f0d0 100644
--- a/pkg/analyzer/lib/src/dart/element/handle.dart
+++ b/pkg/analyzer/lib/src/dart/element/handle.dart
@@ -363,6 +363,12 @@
int get hashCode => _location.hashCode;
@override
+ bool get hasIsTest => actualElement.hasIsTest;
+
+ @override
+ bool get hasIsTestGroup => actualElement.hasIsTestGroup;
+
+ @override
bool get hasJS => actualElement.hasJS;
@override
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 026a7ef..a304d9f 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -400,6 +400,12 @@
bool get hasFactory => _baseElement.hasFactory;
@override
+ bool get hasIsTest => _baseElement.hasIsTest;
+
+ @override
+ bool get hasIsTestGroup => _baseElement.hasIsTestGroup;
+
+ @override
bool get hasJS => _baseElement.hasJS;
@override