Index: lib/test_reflective_loader.dart |
diff --git a/lib/test_reflective_loader.dart b/lib/test_reflective_loader.dart |
index f8387e34c595b6635bbd5bafebab963ea232f570..6e3c945a2778a7b7ba82ae05733c300f0a81c533 100644 |
--- a/lib/test_reflective_loader.dart |
+++ b/lib/test_reflective_loader.dart |
@@ -4,14 +4,50 @@ |
library test_reflective_loader; |
+import 'dart:async'; |
@MirrorsUsed(metaTargets: 'ReflectiveTest') |
import 'dart:mirrors'; |
-import 'dart:async'; |
import 'package:unittest/unittest.dart'; |
/** |
- * Define tests using methods existing in the given [type]. |
+ * A marker annotation used to annotate overridden test methods (so we cannot |
+ * rename them to `fail_`) which are expected to fail at `assert` in the |
+ * checked mode. |
+ */ |
+const _AssertFailingTest assertFailingTest = const _AssertFailingTest(); |
+ |
+/** |
+ * A marker annotation used to annotate overridden test methods (so we cannot |
+ * rename them to `fail_`) which are expected to fail. |
+ */ |
+const _FailingTest failingTest = const _FailingTest(); |
+ |
+/** |
+ * A marker annotation used to instruct dart2js to keep reflection information |
+ * for the annotated classes. |
+ */ |
+const ReflectiveTest reflectiveTest = const ReflectiveTest(); |
+ |
+/** |
+ * Test classes annotated with this annotation are run using [solo_group]. |
+ */ |
+const _SoloTest soloTest = const _SoloTest(); |
+ |
+/** |
+ * Is `true` the application is running in the checked mode. |
+ */ |
+final bool _isCheckedMode = () { |
+ try { |
+ assert(false); |
+ return false; |
+ } catch (_) { |
+ return true; |
+ } |
+}(); |
+ |
+/** |
+ * Runs test methods existing in the given [type]. |
* |
* Methods with names starting with `test` are run using [test] function. |
* Methods with names starting with `solo_test` are run using [solo_test] function. |
@@ -23,20 +59,20 @@ import 'package:unittest/unittest.dart'; |
* method invocation. |
* |
* If [type] declares method `tearDown`, it will be invoked after any test |
- * method invocation. If method returns [Future] to test some asyncronous |
+ * method invocation. If method returns [Future] to test some asynchronous |
* behavior, then `tearDown` will be invoked in `Future.complete`. |
*/ |
void defineReflectiveTests(Type type) { |
ClassMirror classMirror = reflectClass(type); |
if (!classMirror.metadata.any((InstanceMirror annotation) => |
- annotation.type.reflectedType == ReflectiveTest)) { |
+ annotation.type.reflectedType == ReflectiveTest)) { |
String name = MirrorSystem.getName(classMirror.qualifiedName); |
throw new Exception('Class $name must have annotation "@reflectiveTest" ' |
'in order to be run by runReflectiveTests.'); |
} |
- String className = MirrorSystem.getName(classMirror.simpleName); |
- group(className, () { |
- classMirror.instanceMembers.forEach((symbol, memberMirror) { |
+ void runMembers() { |
+ classMirror.instanceMembers |
+ .forEach((Symbol symbol, MethodMirror memberMirror) { |
// we need only methods |
if (memberMirror is! MethodMirror || !memberMirror.isRegularMethod) { |
return; |
@@ -45,7 +81,12 @@ void defineReflectiveTests(Type type) { |
// test_ |
if (memberName.startsWith('test_')) { |
test(memberName, () { |
- return _runTest(classMirror, symbol); |
+ if (_hasFailingTestAnnotation(memberMirror) || |
+ _isCheckedMode && _hasAssertFailingTestAnnotation(memberMirror)) { |
+ return _runFailingTest(classMirror, symbol); |
+ } else { |
+ return _runTest(classMirror, symbol); |
+ } |
}); |
return; |
} |
@@ -68,19 +109,36 @@ void defineReflectiveTests(Type type) { |
}); |
} |
}); |
- }); |
+ } |
+ String className = MirrorSystem.getName(classMirror.simpleName); |
+ if (_hasAnnotationInstance(classMirror, soloTest)) { |
+ solo_group(className, runMembers); |
+ } else { |
+ group(className, runMembers); |
+ } |
} |
+bool _hasAnnotationInstance(DeclarationMirror declaration, instance) => |
+ declaration.metadata.any((InstanceMirror annotation) => |
+ identical(annotation.reflectee, instance)); |
+ |
+bool _hasAssertFailingTestAnnotation(MethodMirror method) => |
+ _hasAnnotationInstance(method, assertFailingTest); |
+ |
+bool _hasFailingTestAnnotation(MethodMirror method) => |
+ _hasAnnotationInstance(method, failingTest); |
+ |
Future _invokeSymbolIfExists(InstanceMirror instanceMirror, Symbol symbol) { |
var invocationResult = null; |
+ InstanceMirror closure; |
try { |
- invocationResult = instanceMirror.invoke(symbol, []).reflectee; |
+ closure = instanceMirror.getField(symbol); |
} on NoSuchMethodError {} |
- if (invocationResult is Future) { |
- return invocationResult; |
- } else { |
- return new Future.value(invocationResult); |
+ |
+ if (closure is ClosureMirror) { |
+ invocationResult = closure.apply([]).reflectee; |
} |
+ return new Future.value(invocationResult); |
} |
/** |
@@ -115,7 +173,26 @@ class ReflectiveTest { |
} |
/** |
- * A marker annotation used to instruct dart2js to keep reflection information |
- * for the annotated classes. |
+ * A marker annotation used to annotate overridden test methods (so we cannot |
+ * rename them to `fail_`) which are expected to fail at `assert` in the |
+ * checked mode. |
*/ |
-const ReflectiveTest reflectiveTest = const ReflectiveTest(); |
+class _AssertFailingTest { |
+ const _AssertFailingTest(); |
+} |
+ |
+/** |
+ * A marker annotation used to annotate overridden test methods (so we cannot |
+ * rename them to `fail_`) which are expected to fail. |
+ */ |
+class _FailingTest { |
+ const _FailingTest(); |
+} |
+ |
+/** |
+ * A marker annotation used to annotate a test class to run it using |
+ * [solo_group]. |
+ */ |
+class _SoloTest { |
+ const _SoloTest(); |
+} |