| Index: pkg/metatest/lib/metatest.dart
|
| diff --git a/pkg/scheduled_test/test/metatest.dart b/pkg/metatest/lib/metatest.dart
|
| similarity index 65%
|
| rename from pkg/scheduled_test/test/metatest.dart
|
| rename to pkg/metatest/lib/metatest.dart
|
| index 3c0cd9acb39f8189e56dcc284fac685d4ddd79f9..c8b5660a9bc750ce331d9452322bb18c27ee3ccf 100644
|
| --- a/pkg/scheduled_test/test/metatest.dart
|
| +++ b/pkg/metatest/lib/metatest.dart
|
| @@ -1,4 +1,4 @@
|
| -// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
| +// Copyright (c) 2014, 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.
|
|
|
| @@ -10,14 +10,88 @@
|
| library metatest;
|
|
|
| import 'dart:async';
|
| -import 'dart:io';
|
| import 'dart:isolate';
|
|
|
| -import 'package:path/path.dart' as path;
|
| import 'package:unittest/unittest.dart';
|
| -import 'package:scheduled_test/scheduled_test.dart' as scheduled_test;
|
|
|
| -import 'utils.dart';
|
| +import 'src/utils.dart';
|
| +
|
| +/// Whether or not we're running in a child isolate that's supposed to run a
|
| +/// test.
|
| +bool _inChildIsolate;
|
| +
|
| +/// The port with which the child isolate should communicate with the parent
|
| +/// isolate.
|
| +///
|
| +/// `null` in the parent isolate.
|
| +SendPort _replyTo;
|
| +
|
| +/// The only value of the configuration used in metatest.
|
| +final _metaConfiguration = new _MetaConfiguration();
|
| +
|
| +/// The function holding the tests to be run.
|
| +Function _testBody;
|
| +
|
| +/// The description of the test to run in the child isolate.
|
| +///
|
| +/// `null` in the parent isolate.
|
| +String _testToRun;
|
| +
|
| +/// Stores the optional timeout used to override the default unittest timeout.
|
| +Duration _timeoutOverride;
|
| +
|
| +/// Runs [setUpFn] before every metatest.
|
| +///
|
| +/// Note that [setUpFn] will be overwritten if the test itself calls [setUp].
|
| +void metaSetUp(void setUpFn()) {
|
| + if (_inChildIsolate) setUp(setUpFn);
|
| +}
|
| +
|
| +/// Runs a set of tests defined in `body` and checks the result by comparing
|
| +/// with values in `expectedResults`.
|
| +///
|
| +/// [expectedResults] is a list which should have a [Map] value for each test
|
| +/// that is run. Each [Map] key corresponds to values from a completed test
|
| +/// case: "description", "message", "result", and "stackTrace".
|
| +///
|
| +/// The value of "result" can be one of: 'pass', 'fail', or 'error'.
|
| +///
|
| +/// The value for "stackTrace" is the [String] 'null' if the property is `null`
|
| +/// on the source test case. Otherwise, it is the output of `toString`. The
|
| +/// format is not guaranteed.
|
| +///
|
| +/// Here's an example of a `expectedResults` value for two tests, where the
|
| +/// where the first fails and the second passes.
|
| +///
|
| +/// ```dart
|
| +/// [{
|
| +/// 'description': 'test',
|
| +/// 'message': 'Caught error!',
|
| +/// 'result': 'fail',
|
| +/// }, {
|
| +/// 'description': 'follow up',
|
| +/// 'result': 'pass',
|
| +/// }]
|
| +/// ```
|
| +void expectTestResults(String description, void body(),
|
| + List<Map> expectedResults) {
|
| + _setUpTest(description, body, (resultsMap) {
|
| + var list = resultsMap['results'];
|
| + expect(list, hasLength(expectedResults.length),
|
| + reason: 'The number of tests run does not match the number of expected'
|
| + ' results.');
|
| +
|
| + for (var i = 0; i < list.length; i++) {
|
| + var expectedMap = expectedResults[i];
|
| + var map = list[i];
|
| +
|
| + expectedMap.forEach((key, value) {
|
| + expect(map, containsPair(key, value), reason: 'A test did not match the'
|
| + ' expected value for "$key" at index $i.');
|
| + });
|
| + }
|
| + });
|
| +}
|
|
|
| /// Declares a test with the given [description] and [body]. [body] corresponds
|
| /// to the `main` method of a test file, and will be run in an isolate. By
|
| @@ -26,12 +100,12 @@ import 'utils.dart';
|
| void expectTestsPass(String description, void body(), {List<String> passing}) {
|
| _setUpTest(description, body, (results) {
|
| if (_hasError(results)) {
|
| - throw 'Expected all tests to pass, but got error(s):\n'
|
| - '${_summarizeTests(results)}';
|
| + fail('Expected all tests to pass, but got error(s):\n'
|
| + '${_summarizeTests(results)}');
|
| } else if (passing == null) {
|
| if (results['failed'] != 0) {
|
| - throw 'Expected all tests to pass, but some failed:\n'
|
| - '${_summarizeTests(results)}';
|
| + fail('Expected all tests to pass, but some failed:\n'
|
| + '${_summarizeTests(results)}');
|
| }
|
| } else {
|
| var shouldPass = new Set.from(passing);
|
| @@ -42,7 +116,7 @@ void expectTestsPass(String description, void body(), {List<String> passing}) {
|
| if (!shouldPass.containsAll(didPass) ||
|
| !didPass.containsAll(shouldPass)) {
|
| String stringify(Set<String> tests) =>
|
| - '{${tests.map((t) => '"$t"').join(', ')}}';
|
| + '{${tests.map((t) => '"$t"').join(', ')}}';
|
|
|
| fail('Expected exactly ${stringify(shouldPass)} to pass, but '
|
| '${stringify(didPass)} passed.\n'
|
| @@ -52,38 +126,6 @@ void expectTestsPass(String description, void body(), {List<String> passing}) {
|
| });
|
| }
|
|
|
| -/// Declares a test with the given [description] and [body].
|
| -///
|
| -/// [body] corresponds
|
| -/// to the `main` method of a test file, and will be run in an isolate.
|
| -///
|
| -/// All tests must have an expected result in [expectedResults].
|
| -void expectTests(String description, void body(),
|
| - Map<String, String> expectedResults) {
|
| - _setUpTest(description, body, (results) {
|
| - expectedResults = new Map.from(expectedResults);
|
| -
|
| - for (var testResult in results['results']) {
|
| - var description = testResult['description'];
|
| -
|
| - expect(expectedResults, contains(description),
|
| - reason: '"$description" did not have an expected result set.\n'
|
| - '${_summarizeTests(results)}');
|
| -
|
| - var result = testResult['result'];
|
| -
|
| - expect(expectedResults, containsPair(description, result),
|
| - reason: 'The test "$description" not not have the expected result.\n'
|
| - '${_summarizeTests(results)}');
|
| -
|
| - expectedResults.remove(description);
|
| - }
|
| - expect(expectedResults, isEmpty,
|
| - reason: 'Unexpected additional test results\n'
|
| - '${_summarizeTests(results)}');
|
| - });
|
| -}
|
| -
|
| /// Declares a test with the given [description] and [body]. [body] corresponds
|
| /// to the `main` method of a test file, and will be run in an isolate. Expects
|
| /// all tests defined by [body] to fail.
|
| @@ -99,45 +141,27 @@ void expectTestsFail(String description, void body()) {
|
| });
|
| }
|
|
|
| -/// Runs [setUpFn] before every metatest. Note that [setUpFn] will be
|
| -/// overwritten if the test itself calls [setUp].
|
| -void metaSetUp(void setUpFn()) {
|
| - if (_inChildIsolate) scheduled_test.setUp(setUpFn);
|
| -}
|
| -
|
| /// Sets up a test with the given [description] and [body]. After the test runs,
|
| /// calls [validate] with the result map.
|
| -void _setUpTest(String description, void body(), void validate(Map)) {
|
| +void _setUpTest(String description, void body(), void validate(Map map)) {
|
| if (_inChildIsolate) {
|
| _ensureInitialized();
|
| if (_testToRun == description) body();
|
| } else {
|
| test(description, () {
|
| - expect(_runInIsolate(description).then(validate), completes);
|
| + return _runInIsolate(description).then(validate);
|
| });
|
| }
|
| }
|
|
|
| -/// The description of the test to run in the child isolate.
|
| -///
|
| -/// `null` in the parent isolate.
|
| -String _testToRun;
|
| -
|
| -/// The port with which the child isolate should communicate with the parent
|
| -/// isolate.
|
| -///
|
| -/// `null` in the parent isolate.
|
| -SendPort _replyTo;
|
| -
|
| -/// Whether or not we're running in a child isolate that's supposed to run a
|
| -/// test.
|
| -bool _inChildIsolate;
|
| -
|
| /// Initialize metatest.
|
| ///
|
| /// [message] should be the second argument to [main]. It's used to determine
|
| /// whether this test is in the parent isolate or a child isolate.
|
| -void initMetatest(message) {
|
| +///
|
| +/// [timeout], when specified, overrides the default timeout for unittest.
|
| +void initMetatest(message, {Duration timeout}) {
|
| + _timeoutOverride = timeout;
|
| if (message == null) {
|
| _inChildIsolate = false;
|
| } else {
|
| @@ -147,22 +171,27 @@ void initMetatest(message) {
|
| }
|
| }
|
|
|
| -/// Runs the test described by [description] in its own isolate. Returns a map
|
| -/// describing the results of that test run.
|
| +// TODO(kevmoo) We need to capture the main method to allow running in an
|
| +// isolate. There is no mechanism to capture the current executing URI between
|
| +// browser and vm. Issue 1145 and/or Issue 8440
|
| +void initTests(void testBody(message)) {
|
| + _testBody = testBody;
|
| + _testBody(null);
|
| +}
|
| +
|
| +/// Runs the test described by [description] in its own isolate.
|
| +///
|
| +/// Returns a map describing the results of that test run.
|
| Future<Map> _runInIsolate(String description) {
|
| + if (_testBody == null) {
|
| + throw new StateError('initTests was not called.');
|
| + }
|
| +
|
| var replyPort = new ReceivePort();
|
| - // TODO(nweiz): Don't use path here once issue 8440 is fixed.
|
| - var uri = path.toUri(path.absolute(path.fromUri(Platform.script)));
|
| - return Isolate.spawnUri(uri, [], {
|
| + return Isolate.spawn(_testBody, {
|
| 'testToRun': description,
|
| 'replyTo': replyPort.sendPort
|
| - }).then((_) {
|
| - // TODO(nweiz): Remove this timeout once issue 8875 is fixed and we can
|
| - // capture top-level exceptions.
|
| - return timeout(replyPort.first, 30 * 1000, () {
|
| - throw 'Timed out waiting for test to complete.';
|
| - });
|
| - });
|
| + }).then((_) => replyPort.first);
|
| }
|
|
|
| /// Returns whether [results] (a test result map) describes a test run in which
|
| @@ -211,11 +240,12 @@ String _indent(String str) {
|
|
|
| /// Ensure that the metatest configuration is loaded.
|
| void _ensureInitialized() {
|
| - unittestConfiguration = _singleton;
|
| + unittestConfiguration = _metaConfiguration;
|
| + if (_timeoutOverride != null) {
|
| + unittestConfiguration.timeout = _timeoutOverride;
|
| + }
|
| }
|
|
|
| -final _singleton = new _MetaConfiguration();
|
| -
|
| /// Special test configuration for use within the child isolates. This hides all
|
| /// output and reports data back to the parent isolate.
|
| class _MetaConfiguration extends Configuration {
|
|
|