Index: lib/src/engine.dart |
diff --git a/lib/src/engine.dart b/lib/src/engine.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7bd6958899129492a64c8717905e5ee0d12cde73 |
--- /dev/null |
+++ b/lib/src/engine.dart |
@@ -0,0 +1,67 @@ |
+// Copyright (c) 2015, 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 unittest.engine; |
+ |
+import 'dart:async'; |
+import 'dart:collection'; |
+ |
+import 'live_test.dart'; |
+import 'state.dart'; |
+import 'suite.dart'; |
+import 'utils.dart'; |
+ |
+/// An [Engine] manages a run that encompasses multiple test suites. |
+/// |
+/// The current status of every test is visible via [liveTests]. [onTestStarted] |
+/// can also be used to be notified when a test is about to be run. |
+/// |
+/// Suites will be run in the order they're provided to [new Engine]. Tests |
+/// within those suites will likewise be run in the order of [Suite.tests]. |
+class Engine { |
+ /// Whether [run] has been called yet. |
+ var _runCalled = false; |
+ |
+ /// An unmodifiable list of tests to run. |
+ /// |
+ /// These are [LiveTest]s, representing the in-progress state of each test. |
+ /// Tests that have not yet begun running are marked [Status.pending]; tests |
+ /// that have finished are marked [Status.complete]. |
+ /// |
+ /// [LiveTest.run] must not be called on these tests. |
+ final List<LiveTest> liveTests; |
+ |
+ /// A stream that emits each [LiveTest] as it's about to start running. |
+ /// |
+ /// This is guaranteed to fire before [LiveTest.onStateChange] first fires. |
+ Stream<LiveTest> get onTestStarted => _onTestStartedController.stream; |
+ final _onTestStartedController = new StreamController<LiveTest>.broadcast(); |
+ |
+ /// Creates an [Engine] that will run all tests in [suites]. |
+ Engine(Iterable<Suite> suites) |
+ : liveTests = new UnmodifiableListView(flatten(suites.map((suite) => |
+ suite.tests.map((test) => test.load(suite))))); |
+ |
+ /// Runs all tests in all suites defined by this engine. |
+ /// |
+ /// This returns `true` if all tests succeed, and `false` otherwise. It will |
+ /// only return once all tests have finished running. |
+ Future<bool> run() { |
+ if (_runCalled) { |
+ throw new StateError("Engine.run() may not be called more than once."); |
+ } |
+ _runCalled = true; |
+ |
+ return Future.forEach(liveTests, (liveTest) { |
+ _onTestStartedController.add(liveTest); |
+ |
+ // First, schedule a microtask to ensure that [onTestStarted] fires before |
+ // the first [LiveTest.onStateChange] event. Once the test finishes, use |
+ // [new Future] to do a coarse-grained event loop pump to avoid starving |
+ // the DOM or other non-microtask events. |
+ return new Future.microtask(liveTest.run).then((_) => new Future(() {})); |
+ }).then((_) => |
+ liveTests.every((liveTest) => liveTest.state.result == Result.success)); |
+ } |
+} |