Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Unified Diff: test/vm_listener_test.dart

Issue 914963003: Add a VmListener and IsolateTest class for running tests in other isolates. (Closed) Base URL: git@github.com:dart-lang/unittest@master
Patch Set: Code review changes Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « test/utils.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/vm_listener_test.dart
diff --git a/test/vm_listener_test.dart b/test/vm_listener_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..b626ad151a72a86cf4cb05c007053674145c1d22
--- /dev/null
+++ b/test/vm_listener_test.dart
@@ -0,0 +1,308 @@
+// 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.
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:unittest/src/declarer.dart';
+import 'package:unittest/src/invoker.dart';
+import 'package:unittest/src/isolate_test.dart';
+import 'package:unittest/src/live_test.dart';
+import 'package:unittest/src/state.dart';
+import 'package:unittest/src/suite.dart';
+import 'package:unittest/src/vm_listener.dart';
+import 'package:unittest/unittest.dart';
+
+import 'utils.dart';
+
+/// The current declarer.
+Declarer get _declarer => Zone.current[#unittest.declarer];
+
+/// An isolate that's been spun up for the current test.
+///
+/// This is tracked so that it can be killed once the test is done.
+Isolate _isolate;
+
+/// A live test that's running for the current test.
+///
+/// This is tracked so that it can be closed once the test is done.
+LiveTest _liveTest;
+
+void main() {
+ tearDown(() {
+ if (_isolate != null) _isolate.kill(Isolate.IMMEDIATE);
+ _isolate = null;
+
+ if (_liveTest != null) _liveTest.close();
+ _liveTest = null;
+ });
+
+ test("sends a list of available tests on startup", () {
+ return _spawnIsolate(_successfulTests).then((receivePort) {
+ return receivePort.first;
+ }).then((tests) {
+ expect(tests, hasLength(3));
+ expect(tests[0], containsPair("name", "successful 1"));
+ expect(tests[1], containsPair("name", "successful 2"));
+ expect(tests[2], containsPair("name", "successful 3"));
+ });
+ });
+
+ group("in a successful test", () {
+ test("the state changes from pending to running to complete", () {
+ return _isolateTest(_successfulTests).then((liveTest) {
+ liveTest.onError.listen(expectAsync((_) {}, count: 0));
+
+ expect(liveTest.state,
+ equals(const State(Status.pending, Result.success)));
+
+ var future = liveTest.run();
+
+ expect(liveTest.state,
+ equals(const State(Status.running, Result.success)));
+
+ return future.then((_) {
+ expect(liveTest.state,
+ equals(const State(Status.complete, Result.success)));
+ });
+ });
+ });
+
+ test("onStateChange fires for each state change", () {
+ return _isolateTest(_successfulTests).then((liveTest) {
+ liveTest.onError.listen(expectAsync((_) {}, count: 0));
+
+ var first = true;
+ liveTest.onStateChange.listen(expectAsync((state) {
+ if (first) {
+ expect(state.status, equals(Status.running));
+ first = false;
+ } else {
+ expect(state.status, equals(Status.complete));
+ }
+ expect(state.result, equals(Result.success));
+ }, count: 2, max: 2));
+
+ return liveTest.run();
+ });
+ });
+ });
+
+ group("in a test with failures", () {
+ test("a failure reported causes the test to fail", () {
+ return _isolateTest(_failingTest).then((liveTest) {
+ expectSingleFailure(liveTest);
+ return liveTest.run();
+ });
+ });
+
+ test("a failure reported asynchronously after the test causes it to error",
+ () {
+ return _isolateTest(_failAfterSucceedTest).then((liveTest) {
+ expectStates(liveTest, [
+ const State(Status.running, Result.success),
+ const State(Status.complete, Result.success),
+ const State(Status.complete, Result.failure),
+ const State(Status.complete, Result.error)
+ ]);
+
+ expectErrors(liveTest, [(error) {
+ expect(lastState,
+ equals(const State(Status.complete, Result.failure)));
+ expect(error, isTestFailure("oh no"));
+ }, (error) {
+ expect(lastState, equals(const State(Status.complete, Result.error)));
+ expect(error, isRemoteException(
+ "This test failed after it had already completed. Make sure to "
+ "use [expectAsync]\n"
+ "or the [completes] matcher when testing async code."));
+ }]);
+
+ return liveTest.run();
+ });
+ });
+
+ test("multiple asynchronous failures are reported", () {
+ return _isolateTest(_multiFailTest).then((liveTest) {
+ expectStates(liveTest, [
+ const State(Status.running, Result.success),
+ const State(Status.complete, Result.failure)
+ ]);
+
+ expectErrors(liveTest, [(error) {
+ expect(lastState.status, equals(Status.complete));
+ expect(error, isTestFailure("one"));
+ }, (error) {
+ expect(error, isTestFailure("two"));
+ }, (error) {
+ expect(error, isTestFailure("three"));
+ }, (error) {
+ expect(error, isTestFailure("four"));
+ }]);
+
+ return liveTest.run();
+ });
+ });
+ });
+
+ group("in a test with errors", () {
+ test("an error reported causes the test to error", () {
+ return _isolateTest(_errorTest).then((liveTest) {
+ expectStates(liveTest, [
+ const State(Status.running, Result.success),
+ const State(Status.complete, Result.error)
+ ]);
+
+ expectErrors(liveTest, [(error) {
+ expect(lastState.status, equals(Status.complete));
+ expect(error, isRemoteException("oh no"));
+ }]);
+
+ return liveTest.run();
+ });
+ });
+
+ test("an error reported asynchronously after the test causes it to error",
+ () {
+ return _isolateTest(_errorAfterSucceedTest).then((liveTest) {
+ expectStates(liveTest, [
+ const State(Status.running, Result.success),
+ const State(Status.complete, Result.success),
+ const State(Status.complete, Result.error)
+ ]);
+
+ expectErrors(liveTest, [(error) {
+ expect(lastState,
+ equals(const State(Status.complete, Result.error)));
+ expect(error, isRemoteException("oh no"));
+ }, (error) {
+ expect(error, isRemoteException(
+ "This test failed after it had already completed. Make sure to "
+ "use [expectAsync]\n"
+ "or the [completes] matcher when testing async code."));
+ }]);
+
+ return liveTest.run();
+ });
+ });
+
+ test("multiple asynchronous errors are reported", () {
+ return _isolateTest(_multiErrorTest).then((liveTest) {
+ expectStates(liveTest, [
+ const State(Status.running, Result.success),
+ const State(Status.complete, Result.error)
+ ]);
+
+ expectErrors(liveTest, [(error) {
+ expect(lastState.status, equals(Status.complete));
+ expect(error, isRemoteException("one"));
+ }, (error) {
+ expect(error, isRemoteException("two"));
+ }, (error) {
+ expect(error, isRemoteException("three"));
+ }, (error) {
+ expect(error, isRemoteException("four"));
+ }]);
+
+ return liveTest.run();
+ });
+ });
+ });
+}
+
+/// Loads the first test defined in [entryPoint] in another isolate.
+///
+/// This test will be automatically closed when the test is finished.
+Future<LiveTest> _isolateTest(void entryPoint(SendPort sendPort)) {
+ return _spawnIsolate(entryPoint).then((receivePort) {
+ return receivePort.first;
+ }).then((response) {
+ var testMap = response.first;
+ var test = new IsolateTest(testMap["name"], testMap["sendPort"]);
+ var suite = new Suite("suite", [test]);
+ _liveTest = test.load(suite);
+ return _liveTest;
+ });
+}
+
+/// Spawns an isolate from [entryPoint], sends it a new [SendPort], and returns
+/// the corresponding [ReceivePort].
+///
+/// This isolate will be automatically killed when the test is finished.
+Future<ReceivePort> _spawnIsolate(void entryPoint(SendPort sendPort)) {
+ var receivePort = new ReceivePort();
+ return Isolate.spawn(entryPoint, receivePort.sendPort).then((isolate) {
+ _isolate = isolate;
+ return receivePort;
+ });
+}
+
+/// An isolate entrypoint that defines three tests that succeed.
+void _successfulTests(SendPort sendPort) {
+ VmListener.start(sendPort, () {
+ _declarer.test("successful 1", () {});
+ _declarer.test("successful 2", () {});
+ _declarer.test("successful 3", () {});
+ });
+}
+
+/// An isolate entrypoint that defines a test that fails.
+void _failingTest(SendPort sendPort) {
+ VmListener.start(sendPort, () {
+ _declarer.test("failure", () => throw new TestFailure('oh no'));
+ });
+}
+
+/// An isolate entrypoint that defines a test that fails after succeeding.
+void _failAfterSucceedTest(SendPort sendPort) {
+ VmListener.start(sendPort, () {
+ _declarer.test("fail after succeed", () {
+ pumpEventQueue().then((_) {
+ throw new TestFailure('oh no');
+ });
+ });
+ });
+}
+
+/// An isolate entrypoint that defines a test that fails multiple times.
+void _multiFailTest(SendPort sendPort) {
+ VmListener.start(sendPort, () {
+ _declarer.test("multiple failures", () {
+ Invoker.current.addOutstandingCallback();
+ new Future(() => throw new TestFailure("one"));
+ new Future(() => throw new TestFailure("two"));
+ new Future(() => throw new TestFailure("three"));
+ new Future(() => throw new TestFailure("four"));
+ });
+ });
+}
+
+/// An isolate entrypoint that defines a test that errors.
+void _errorTest(SendPort sendPort) {
+ VmListener.start(sendPort, () {
+ _declarer.test("error", () => throw 'oh no');
+ });
+}
+
+/// An isolate entrypoint that defines a test that errors after succeeding.
+void _errorAfterSucceedTest(SendPort sendPort) {
+ VmListener.start(sendPort, () {
+ _declarer.test("error after succeed", () {
+ pumpEventQueue().then((_) => throw 'oh no');
+ });
+ });
+}
+
+/// An isolate entrypoint that defines a test that errors multiple times.
+void _multiErrorTest(SendPort sendPort) {
+ VmListener.start(sendPort, () {
+ _declarer.test("multiple errors", () {
+ Invoker.current.addOutstandingCallback();
+ new Future(() => throw "one");
+ new Future(() => throw "two");
+ new Future(() => throw "three");
+ new Future(() => throw "four");
+ });
+ });
+}
« no previous file with comments | « test/utils.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698