| 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");
|
| + });
|
| + });
|
| +}
|
|
|