| Index: pkg/unittest/lib/unittest.dart
|
| ===================================================================
|
| --- pkg/unittest/lib/unittest.dart (revision 21853)
|
| +++ pkg/unittest/lib/unittest.dart (working copy)
|
| @@ -205,12 +205,6 @@
|
| void logMessage(String message) =>
|
| _config.onLogMessage(currentTestCase, message);
|
|
|
| -/**
|
| - * Description text of the current test group. If multiple groups are nested,
|
| - * this will contain all of their text concatenated.
|
| - */
|
| -String _currentGroup = '';
|
| -
|
| /** Separator used between group names and test names. */
|
| String groupSep = ' ';
|
|
|
| @@ -219,12 +213,78 @@
|
| /** Tests executed in this suite. */
|
| final List<TestCase> testCases = new UnmodifiableListView<TestCase>(_testCases);
|
|
|
| -/** Setup function called before each test in a group */
|
| -Function _testSetup;
|
| +/**
|
| + * Setup and teardown functions for a group and its parents, the latter
|
| + * for chaining.
|
| + */
|
| +class GroupContext {
|
| + final GroupContext parent;
|
|
|
| -/** Teardown function called after each test in a group */
|
| -Function _testTeardown;
|
| + /** Description text of the current test group. */
|
| + final String _name;
|
|
|
| + /** Setup function called before each test in a group. */
|
| + Function _testSetup;
|
| +
|
| + get testSetup => _testSetup;
|
| +
|
| + get parentSetup => (parent == null) ? null : parent.testSetup;
|
| +
|
| + set testSetup(Function setup) {
|
| + var preSetup = parentSetup;
|
| + if (preSetup == null) {
|
| + _testSetup = setup;
|
| + } else {
|
| + _testSetup = () {
|
| + var f = preSetup();
|
| + if (f is Future) {
|
| + return f.then((_) => setup());
|
| + } else {
|
| + return setup();
|
| + }
|
| + };
|
| + }
|
| + }
|
| +
|
| + /** Teardown function called after each test in a group. */
|
| + Function _testTeardown;
|
| +
|
| + get testTeardown => _testTeardown;
|
| +
|
| + get parentTeardown => (parent == null) ? null : parent.testTeardown;
|
| +
|
| + set testTeardown(Function teardown) {
|
| + var postTeardown = parentTeardown;
|
| + if (postTeardown == null) {
|
| + _testTeardown = teardown;
|
| + } else {
|
| + _testTeardown = () {
|
| + var f = teardown();
|
| + if (f is Future) {
|
| + return f.then((_) => postTeardown());
|
| + } else {
|
| + return postTeardown();
|
| + }
|
| + };
|
| + }
|
| + }
|
| +
|
| + String get fullName => (parent == null || parent == _rootContext)
|
| + ? _name
|
| + : "${parent.fullName}$groupSep$_name";
|
| +
|
| + GroupContext([this.parent, this._name = '']) {
|
| + _testSetup = parentSetup;
|
| + _testTeardown = parentTeardown;
|
| + }
|
| +}
|
| +
|
| +// We use a 'dummy' context for the top level to eliminate null
|
| +// checks when querying the context. This allows us to easily
|
| +// support top-level setUp/tearDown functions as well.
|
| +GroupContext _rootContext = new GroupContext();
|
| +GroupContext _currentContext = _rootContext;
|
| +
|
| int _currentTestCaseIndex = 0;
|
|
|
| /** [TestCase] currently being executed. */
|
| @@ -596,46 +656,27 @@
|
| */
|
| void group(String description, void body()) {
|
| ensureInitialized();
|
| - // Concatenate the new group.
|
| - final parentGroup = _currentGroup;
|
| - if (_currentGroup != '') {
|
| - // Add a space.
|
| - _currentGroup = '$_currentGroup$groupSep$description';
|
| - } else {
|
| - // The first group.
|
| - _currentGroup = description;
|
| - }
|
| -
|
| - // Groups can be nested, so we need to preserve the current
|
| - // settings for test setup/teardown.
|
| - Function parentSetup = _testSetup;
|
| - Function parentTeardown = _testTeardown;
|
| -
|
| + _currentContext = new GroupContext(_currentContext, description);
|
| try {
|
| - _testSetup = null;
|
| - _testTeardown = null;
|
| body();
|
| } catch (e, trace) {
|
| var stack = (trace == null) ? '' : ': ${trace.toString()}';
|
| _uncaughtErrorMessage = "${e.toString()}$stack";
|
| } finally {
|
| // Now that the group is over, restore the previous one.
|
| - _currentGroup = parentGroup;
|
| - _testSetup = parentSetup;
|
| - _testTeardown = parentTeardown;
|
| + _currentContext = _currentContext.parent;
|
| }
|
| }
|
|
|
| /**
|
| * Register a [setUp] function for a test [group]. This function will
|
| - * be called before each test in the group is run. Note that if groups
|
| - * are nested only the most locally scoped [setUpTest] function will be run.
|
| + * be called before each test in the group is run.
|
| * [setUp] and [tearDown] should be called within the [group] before any
|
| * calls to [test]. The [setupTest] function can be asynchronous; in this
|
| * case it must return a [Future].
|
| */
|
| void setUp(Function setupTest) {
|
| - _testSetup = setupTest;
|
| + _currentContext.testSetup = setupTest;
|
| }
|
|
|
| /**
|
| @@ -647,7 +688,7 @@
|
| * case it must return a [Future].
|
| */
|
| void tearDown(Function teardownTest) {
|
| - _testTeardown = teardownTest;
|
| + _currentContext.testTeardown = teardownTest;
|
| }
|
|
|
| /** Advance to the next test case. */
|
| @@ -712,7 +753,6 @@
|
| void runTests() {
|
| _ensureInitialized(false);
|
| _currentTestCaseIndex = 0;
|
| - _currentGroup = '';
|
|
|
| // If we are soloing a test, remove all the others.
|
| if (_soloTest != null) {
|
| @@ -811,8 +851,9 @@
|
| }
|
|
|
| String _fullSpec(String spec) {
|
| - if (spec == null) return '$_currentGroup';
|
| - return _currentGroup != '' ? '$_currentGroup$groupSep$spec' : spec;
|
| + var group = '${_currentContext.fullName}';
|
| + if (spec == null) return group;
|
| + return group != '' ? '$group$groupSep$spec' : spec;
|
| }
|
|
|
| /**
|
|
|