| Index: packages/analyzer/test/reflective_tests.dart
|
| diff --git a/packages/analyzer/test/reflective_tests.dart b/packages/analyzer/test/reflective_tests.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8180cf7800bd85737844932ba1fbdd051637b7fc
|
| --- /dev/null
|
| +++ b/packages/analyzer/test/reflective_tests.dart
|
| @@ -0,0 +1,121 @@
|
| +// Copyright (c) 2014, 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.
|
| +
|
| +library reflective_tests;
|
| +
|
| +@MirrorsUsed(metaTargets: 'ReflectiveTest')
|
| +import 'dart:mirrors';
|
| +import 'dart:async';
|
| +
|
| +import 'package:unittest/unittest.dart';
|
| +
|
| +/**
|
| + * 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.
|
| + *
|
| + * Each method is run with a new instance of [type].
|
| + * So, [type] should have a default constructor.
|
| + *
|
| + * If [type] declares method `setUp`, it methods will be invoked before any test
|
| + * method invocation.
|
| + *
|
| + * If [type] declares method `tearDown`, it will be invoked after any test
|
| + * method invocation. If method returns [Future] to test some asyncronous
|
| + * behavior, then `tearDown` will be invoked in `Future.complete`.
|
| + */
|
| +void runReflectiveTests(Type type) {
|
| + ClassMirror classMirror = reflectClass(type);
|
| + if (!classMirror.metadata.any((InstanceMirror annotation) =>
|
| + 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) {
|
| + // we need only methods
|
| + if (memberMirror is! MethodMirror || !memberMirror.isRegularMethod) {
|
| + return;
|
| + }
|
| + String memberName = MirrorSystem.getName(symbol);
|
| + // test_
|
| + if (memberName.startsWith('test_')) {
|
| + test(memberName, () {
|
| + return _runTest(classMirror, symbol);
|
| + });
|
| + return;
|
| + }
|
| + // solo_test_
|
| + if (memberName.startsWith('solo_test_')) {
|
| + solo_test(memberName, () {
|
| + return _runTest(classMirror, symbol);
|
| + });
|
| + }
|
| + // fail_test_
|
| + if (memberName.startsWith('fail_')) {
|
| + test(memberName, () {
|
| + return _runFailingTest(classMirror, symbol);
|
| + });
|
| + }
|
| + // solo_fail_test_
|
| + if (memberName.startsWith('solo_fail_')) {
|
| + solo_test(memberName, () {
|
| + return _runFailingTest(classMirror, symbol);
|
| + });
|
| + }
|
| + });
|
| + });
|
| +}
|
| +
|
| +Future _invokeSymbolIfExists(InstanceMirror instanceMirror, Symbol symbol) {
|
| + var invocationResult = null;
|
| + try {
|
| + invocationResult = instanceMirror.invoke(symbol, []).reflectee;
|
| + } on NoSuchMethodError {}
|
| + if (invocationResult is Future) {
|
| + return invocationResult;
|
| + } else {
|
| + return new Future.value(invocationResult);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Run a test that is expected to fail, and confirm that it fails.
|
| + *
|
| + * This properly handles the following cases:
|
| + * - The test fails by throwing an exception
|
| + * - The test returns a future which completes with an error.
|
| + *
|
| + * However, it does not handle the case where the test creates an asynchronous
|
| + * callback using expectAsync(), and that callback generates a failure.
|
| + */
|
| +Future _runFailingTest(ClassMirror classMirror, Symbol symbol) {
|
| + return new Future(() => _runTest(classMirror, symbol)).then((_) {
|
| + fail('Test passed - expected to fail.');
|
| + }, onError: (_) {});
|
| +}
|
| +
|
| +_runTest(ClassMirror classMirror, Symbol symbol) {
|
| + InstanceMirror instanceMirror = classMirror.newInstance(new Symbol(''), []);
|
| + return _invokeSymbolIfExists(instanceMirror, #setUp)
|
| + .then((_) => instanceMirror.invoke(symbol, []).reflectee)
|
| + .whenComplete(() => _invokeSymbolIfExists(instanceMirror, #tearDown));
|
| +}
|
| +
|
| +/**
|
| + * A marker annotation used to instruct dart2js to keep reflection information
|
| + * for the annotated classes.
|
| + */
|
| +class ReflectiveTest {
|
| + const ReflectiveTest();
|
| +}
|
| +
|
| +/**
|
| + * A marker annotation used to instruct dart2js to keep reflection information
|
| + * for the annotated classes.
|
| + */
|
| +const ReflectiveTest reflectiveTest = const ReflectiveTest();
|
|
|