blob: 5cfef6af8a66b75d7c21f0fd4faf0513c5454c01 [file] [log] [blame]
// 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;
import 'dart:async';
@MirrorsUsed(metaTargets: 'ReflectiveTestCase')
import 'dart:mirrors';
import 'package:unittest/unittest.dart';
/**
* A marker annotation used to instruct dart2js to keep reflection information
* for the annotated classes.
*/
class ReflectiveTestCase {
const ReflectiveTestCase();
}
/**
* 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);
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_')) {
String testName = memberName.substring('test_'.length);
test(testName, () {
return _runTest(classMirror, symbol);
});
return;
}
// solo_test_
if (memberName.startsWith('solo_test_')) {
String testName = memberName.substring('solo_test_'.length);
solo_test(testName, () {
return _runTest(classMirror, symbol);
});
}
});
}
_runTest(ClassMirror classMirror, Symbol symbol) {
InstanceMirror instanceMirror = classMirror.newInstance(new Symbol(''), []);
bool shouldRunTearDown = true;
_invokeSymbolIfExists(instanceMirror, #setUp);
try {
var testReturn = instanceMirror.invoke(symbol, []).reflectee;
if (testReturn is Future) {
shouldRunTearDown = false;
return testReturn.whenComplete(() {
_invokeTearDown(instanceMirror);
});
} else {
return testReturn;
}
} finally {
if (shouldRunTearDown) {
_invokeTearDown(instanceMirror);
}
}
}
void _invokeTearDown(InstanceMirror instanceMirror) {
_invokeSymbolIfExists(instanceMirror, #tearDown);
}
void _invokeSymbolIfExists(InstanceMirror instanceMirror, Symbol symbol) {
try {
instanceMirror.invoke(symbol, []);
} on NoSuchMethodError catch (e) {
}
}