4
4
5
5
library test_reflective_loader;
6
6
7
+ import 'dart:async' ;
7
8
@MirrorsUsed (metaTargets: 'ReflectiveTest' )
8
9
import 'dart:mirrors' ;
9
- import 'dart:async' ;
10
10
11
11
import 'package:unittest/unittest.dart' ;
12
12
13
13
/**
14
- * Define tests using methods existing in the given [type] .
14
+ * A marker annotation used to annotate overridden test methods (so we cannot
15
+ * rename them to `fail_` ) which are expected to fail at `assert` in the
16
+ * checked mode.
17
+ */
18
+ const _AssertFailingTest assertFailingTest = const _AssertFailingTest ();
19
+
20
+ /**
21
+ * A marker annotation used to annotate overridden test methods (so we cannot
22
+ * rename them to `fail_` ) which are expected to fail.
23
+ */
24
+ const _FailingTest failingTest = const _FailingTest ();
25
+
26
+ /**
27
+ * A marker annotation used to instruct dart2js to keep reflection information
28
+ * for the annotated classes.
29
+ */
30
+ const ReflectiveTest reflectiveTest = const ReflectiveTest ();
31
+
32
+ /**
33
+ * Test classes annotated with this annotation are run using [solo_group] .
34
+ */
35
+ const _SoloTest soloTest = const _SoloTest ();
36
+
37
+ /**
38
+ * Is `true` the application is running in the checked mode.
39
+ */
40
+ final bool _isCheckedMode = () {
41
+ try {
42
+ assert (false );
43
+ return false ;
44
+ } catch (_) {
45
+ return true ;
46
+ }
47
+ }();
48
+
49
+ /**
50
+ * Runs test methods existing in the given [type] .
15
51
*
16
52
* Methods with names starting with `test` are run using [test] function.
17
53
* Methods with names starting with `solo_test` are run using [solo_test] function.
@@ -23,20 +59,20 @@ import 'package:unittest/unittest.dart';
23
59
* method invocation.
24
60
*
25
61
* If [type] declares method `tearDown` , it will be invoked after any test
26
- * method invocation. If method returns [Future] to test some asyncronous
62
+ * method invocation. If method returns [Future] to test some asynchronous
27
63
* behavior, then `tearDown` will be invoked in `Future.complete` .
28
64
*/
29
65
void defineReflectiveTests (Type type) {
30
66
ClassMirror classMirror = reflectClass (type);
31
67
if (! classMirror.metadata.any ((InstanceMirror annotation) =>
32
- annotation.type.reflectedType == ReflectiveTest )) {
68
+ annotation.type.reflectedType == ReflectiveTest )) {
33
69
String name = MirrorSystem .getName (classMirror.qualifiedName);
34
70
throw new Exception ('Class $name must have annotation "@reflectiveTest" '
35
71
'in order to be run by runReflectiveTests.' );
36
72
}
37
- String className = MirrorSystem . getName (classMirror.simpleName);
38
- group (className, () {
39
- classMirror.instanceMembers. forEach ((symbol, memberMirror) {
73
+ void runMembers () {
74
+ classMirror.instanceMembers
75
+ . forEach ((Symbol symbol, MethodMirror memberMirror) {
40
76
// we need only methods
41
77
if (memberMirror is ! MethodMirror || ! memberMirror.isRegularMethod) {
42
78
return ;
@@ -45,7 +81,12 @@ void defineReflectiveTests(Type type) {
45
81
// test_
46
82
if (memberName.startsWith ('test_' )) {
47
83
test (memberName, () {
48
- return _runTest (classMirror, symbol);
84
+ if (_hasFailingTestAnnotation (memberMirror) ||
85
+ _isCheckedMode && _hasAssertFailingTestAnnotation (memberMirror)) {
86
+ return _runFailingTest (classMirror, symbol);
87
+ } else {
88
+ return _runTest (classMirror, symbol);
89
+ }
49
90
});
50
91
return ;
51
92
}
@@ -68,19 +109,36 @@ void defineReflectiveTests(Type type) {
68
109
});
69
110
}
70
111
});
71
- });
112
+ }
113
+ String className = MirrorSystem .getName (classMirror.simpleName);
114
+ if (_hasAnnotationInstance (classMirror, soloTest)) {
115
+ solo_group (className, runMembers);
116
+ } else {
117
+ group (className, runMembers);
118
+ }
72
119
}
73
120
121
+ bool _hasAnnotationInstance (DeclarationMirror declaration, instance) =>
122
+ declaration.metadata.any ((InstanceMirror annotation) =>
123
+ identical (annotation.reflectee, instance));
124
+
125
+ bool _hasAssertFailingTestAnnotation (MethodMirror method) =>
126
+ _hasAnnotationInstance (method, assertFailingTest);
127
+
128
+ bool _hasFailingTestAnnotation (MethodMirror method) =>
129
+ _hasAnnotationInstance (method, failingTest);
130
+
74
131
Future _invokeSymbolIfExists (InstanceMirror instanceMirror, Symbol symbol) {
75
132
var invocationResult = null ;
133
+ InstanceMirror closure;
76
134
try {
77
- invocationResult = instanceMirror.invoke (symbol, []).reflectee ;
135
+ closure = instanceMirror.getField (symbol) ;
78
136
} on NoSuchMethodError {}
79
- if (invocationResult is Future ) {
80
- return invocationResult;
81
- } else {
82
- return new Future .value (invocationResult);
137
+
138
+ if (closure is ClosureMirror ) {
139
+ invocationResult = closure.apply ([]).reflectee;
83
140
}
141
+ return new Future .value (invocationResult);
84
142
}
85
143
86
144
/**
@@ -115,7 +173,26 @@ class ReflectiveTest {
115
173
}
116
174
117
175
/**
118
- * A marker annotation used to instruct dart2js to keep reflection information
119
- * for the annotated classes.
176
+ * A marker annotation used to annotate overridden test methods (so we cannot
177
+ * rename them to `fail_` ) which are expected to fail at `assert` in the
178
+ * checked mode.
120
179
*/
121
- const ReflectiveTest reflectiveTest = const ReflectiveTest ();
180
+ class _AssertFailingTest {
181
+ const _AssertFailingTest ();
182
+ }
183
+
184
+ /**
185
+ * A marker annotation used to annotate overridden test methods (so we cannot
186
+ * rename them to `fail_` ) which are expected to fail.
187
+ */
188
+ class _FailingTest {
189
+ const _FailingTest ();
190
+ }
191
+
192
+ /**
193
+ * A marker annotation used to annotate a test class to run it using
194
+ * [solo_group] .
195
+ */
196
+ class _SoloTest {
197
+ const _SoloTest ();
198
+ }
0 commit comments