Index: lib/src/backend/declarer.dart |
diff --git a/lib/src/backend/declarer.dart b/lib/src/backend/declarer.dart |
index f8dae47cb5568709bcdf4ebb82d8537074db3f24..46a52d9e387da63ddbc9c6049445db6cc4239805 100644 |
--- a/lib/src/backend/declarer.dart |
+++ b/lib/src/backend/declarer.dart |
@@ -9,9 +9,10 @@ import 'dart:async'; |
import '../frontend/timeout.dart'; |
import '../utils.dart'; |
import 'group.dart'; |
+import 'group_entry.dart'; |
import 'invoker.dart'; |
import 'metadata.dart'; |
-import 'group_entry.dart'; |
+import 'test.dart'; |
/// A class that manages the state of tests as they're declared. |
/// |
@@ -34,12 +35,18 @@ class Declarer { |
/// and of the test suite. |
final Metadata _metadata; |
- /// The set-up functions for this group. |
+ /// The set-up functions to run for each test in this group. |
final _setUps = new List<AsyncFunction>(); |
- /// The tear-down functions for this group. |
+ /// The tear-down functions to run for each test in this group. |
final _tearDowns = new List<AsyncFunction>(); |
+ /// The set-up functions to run once for this group. |
+ final _setUpAlls = new List<AsyncFunction>(); |
+ |
+ /// The tear-down functions to run once for this group. |
+ final _tearDownAlls = new List<AsyncFunction>(); |
+ |
/// The children of this group, either tests or sub-groups. |
final _entries = new List<GroupEntry>(); |
@@ -67,9 +74,7 @@ class Declarer { |
/// Defines a test case with the given name and body. |
void test(String name, body(), {String testOn, Timeout timeout, skip, |
Map<String, dynamic> onPlatform}) { |
- if (_built) { |
- throw new StateError("Can't call test() once tests have begun running."); |
- } |
+ _checkNotBuilt("test"); |
var metadata = _metadata.merge(new Metadata.parse( |
testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform)); |
@@ -90,9 +95,7 @@ class Declarer { |
/// Creates a group of tests. |
void group(String name, void body(), {String testOn, Timeout timeout, skip, |
Map<String, dynamic> onPlatform}) { |
- if (_built) { |
- throw new StateError("Can't call group() once tests have begun running."); |
- } |
+ _checkNotBuilt("group"); |
var metadata = _metadata.merge(new Metadata.parse( |
testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform)); |
@@ -113,31 +116,45 @@ class Declarer { |
/// Registers a function to be run before each test in this group. |
void setUp(callback()) { |
- if (_built) { |
- throw new StateError("Can't call setUp() once tests have begun running."); |
- } |
- |
+ _checkNotBuilt("setUp"); |
_setUps.add(callback); |
} |
/// Registers a function to be run after each test in this group. |
void tearDown(callback()) { |
- if (_built) { |
- throw new StateError( |
- "Can't call tearDown() once tests have begun running."); |
- } |
- |
+ _checkNotBuilt("tearDown"); |
_tearDowns.add(callback); |
} |
+ /// Registers a function to be run once before all tests. |
+ void setUpAll(callback()) { |
+ _checkNotBuilt("setUpAll"); |
+ _setUpAlls.add(callback); |
+ } |
+ |
+ /// Registers a function to be run once after all tests. |
+ void tearDownAll(callback()) { |
+ _checkNotBuilt("tearDownAll"); |
+ _tearDownAlls.add(callback); |
+ } |
+ |
/// Finalizes and returns the group being declared. |
Group build() { |
- if (_built) { |
- throw new StateError("Can't call Declarer.build() more than once."); |
- } |
+ _checkNotBuilt("build"); |
_built = true; |
- return new Group(_name, _entries.toList(), metadata: _metadata); |
+ return new Group(_name, _entries.toList(), |
+ metadata: _metadata, |
+ setUpAll: _setUpAll, |
+ tearDownAll: _tearDownAll); |
+ } |
+ |
+ /// Throws a [StateError] if [build] has been called. |
+ /// |
+ /// [name] should be the name of the method being called. |
+ void _checkNotBuilt(String name) { |
+ if (!_built) return; |
+ throw new StateError("Can't call $name() once tests have begun running."); |
} |
/// Run the set-up functions for this and any parent groups. |
@@ -173,6 +190,26 @@ class Declarer { |
}); |
} |
+ /// Returns a [Test] that runs the callbacks in [_setUpAll]. |
+ Test get _setUpAll { |
+ if (_setUpAlls.isEmpty) return null; |
+ |
+ return new LocalTest(_prefix("(setUpAll)"), _metadata, () { |
+ return Future.forEach(_setUpAlls, (setUp) => setUp()); |
+ }); |
+ } |
+ |
+ /// Returns a [Test] that runs the callbacks in [_tearDownAll]. |
+ Test get _tearDownAll { |
+ if (_tearDownAlls.isEmpty) return null; |
+ |
+ return new LocalTest(_prefix("(tearDownAll)"), _metadata, () { |
+ return Invoker.current.unclosable(() { |
+ return Future.forEach(_tearDownAlls.reversed, _errorsDontStopTest); |
+ }); |
+ }); |
+ } |
+ |
/// Runs [body] with special error-handling behavior. |
/// |
/// Errors emitted [body] will still cause the current test to fail, but they |