| 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();
|
| +}
|
|
|