| Index: pkg/testing/lib/src/run.dart
|
| diff --git a/pkg/testing/lib/src/run.dart b/pkg/testing/lib/src/run.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d1d6d3ae653a2a8b3bede857f76b06debda4aa29
|
| --- /dev/null
|
| +++ b/pkg/testing/lib/src/run.dart
|
| @@ -0,0 +1,229 @@
|
| +// Copyright (c) 2016, 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.md file.
|
| +
|
| +library testing.run;
|
| +
|
| +import 'dart:async' show
|
| + Future,
|
| + Stream;
|
| +
|
| +import 'dart:convert' show
|
| + JSON;
|
| +
|
| +import 'dart:io' show
|
| + Platform;
|
| +
|
| +import 'dart:isolate' show
|
| + Isolate,
|
| + ReceivePort;
|
| +
|
| +import 'test_root.dart' show
|
| + TestRoot;
|
| +
|
| +import 'test_description.dart' show
|
| + TestDescription;
|
| +
|
| +import 'error_handling.dart' show
|
| + withErrorHandling;
|
| +
|
| +import 'chain.dart' show
|
| + CreateContext;
|
| +
|
| +import '../testing.dart' show
|
| + Chain,
|
| + ChainContext,
|
| + TestDescription,
|
| + listTests;
|
| +
|
| +import 'analyze.dart' show
|
| + Analyze;
|
| +
|
| +import 'log.dart' show
|
| + isVerbose,
|
| + logMessage,
|
| + logNumberedLines,
|
| + splitLines;
|
| +
|
| +import 'suite.dart' show
|
| + Dart,
|
| + Suite;
|
| +
|
| +import 'zone_helper.dart' show
|
| + acknowledgeControlMessages;
|
| +
|
| +Future<TestRoot> computeTestRoot(String configurationPath, Uri base) {
|
| + Uri configuration = configurationPath == null
|
| + ? Uri.base.resolve("testing.json")
|
| + : base.resolve(configurationPath);
|
| + return TestRoot.fromUri(configuration);
|
| +}
|
| +
|
| +/// This is called from a Chain suite, and helps implement main. In most cases,
|
| +/// main will look like this:
|
| +///
|
| +/// main(List<String> arguments) => runMe(arguments, createContext);
|
| +///
|
| +/// The optional argument [configurationPath] should be used when
|
| +/// `testing.json` isn't located in the current working directory and is a path
|
| +/// relative to `Platform.script`.
|
| +Future<Null> runMe(
|
| + List<String> arguments, CreateContext f, [String configurationPath]) {
|
| + return withErrorHandling(() async {
|
| + TestRoot testRoot =
|
| + await computeTestRoot(configurationPath, Platform.script);
|
| + for (Chain suite in testRoot.toolChains) {
|
| + if (Platform.script == suite.source) {
|
| + print("Running suite ${suite.name}...");
|
| + ChainContext context = await f(suite, <String, String>{});
|
| + await context.run(suite, new Set<String>());
|
| + }
|
| + }
|
| + });
|
| +}
|
| +
|
| +/// This is called from a `_test.dart` file, and helps integration in other
|
| +/// test runner frameworks.
|
| +///
|
| +/// For example, to run the suite `my_suite` from `test.dart`, create a file
|
| +/// with this content:
|
| +///
|
| +/// import 'package:async_helper/async_helper.dart' show asyncTest;
|
| +///
|
| +/// import 'package:testing/testing.dart' show run;
|
| +///
|
| +/// main(List<String> arguments) => asyncTest(run(arguments, ["my_suite"]));
|
| +///
|
| +/// To run run the same suite from `package:test`, create a file with this
|
| +/// content:
|
| +///
|
| +/// import 'package:test/test.dart' show Timeout, test;
|
| +///
|
| +/// import 'package:testing/testing.dart' show run;
|
| +///
|
| +/// main() {
|
| +/// test("my_suite", () => run([], ["my_suite"]),
|
| +/// timeout: new Timeout(new Duration(minutes: 5)));
|
| +/// }
|
| +///
|
| +/// The optional argument [configurationPath] should be used when
|
| +/// `testing.json` isn't located in the current working directory and is a path
|
| +/// relative to `Uri.base`.
|
| +Future<Null> run(
|
| + List<String> arguments, List<String> suiteNames,
|
| + [String configurationPath]) {
|
| + return withErrorHandling(() async {
|
| + TestRoot root = await computeTestRoot(configurationPath, Uri.base);
|
| + List<Suite> suites = root.suites.where(
|
| + (Suite suite) => suiteNames.contains(suite.name)).toList();
|
| + SuiteRunner runner = new SuiteRunner(suites, <String, String>{}, null);
|
| + String program = await runner.generateDartProgram();
|
| + await runner.analyze(root.packages);
|
| + if (program != null) {
|
| + await runProgram(program, root.packages);
|
| + }
|
| + });
|
| +}
|
| +
|
| +Future<Null> runProgram(String program, Uri packages) async {
|
| + logMessage("Running:");
|
| + logNumberedLines(program);
|
| + Uri dataUri = new Uri.dataFromString(program);
|
| + ReceivePort exitPort = new ReceivePort();
|
| + Isolate isolate = await Isolate.spawnUri(dataUri, <String>[], null,
|
| + paused: true, onExit: exitPort.sendPort, errorsAreFatal: false,
|
| + checked: true, packageConfig: packages);
|
| + List error;
|
| + var subscription = isolate.errors.listen((data) {
|
| + error = data;
|
| + exitPort.close();
|
| + });
|
| + await acknowledgeControlMessages(isolate, resume: isolate.pauseCapability);
|
| + await for (var _ in exitPort) {
|
| + exitPort.close();
|
| + }
|
| + subscription.cancel();
|
| + return error == null
|
| + ? null
|
| + : new Future<Null>.error(error[0], new StackTrace.fromString(error[1]));
|
| +}
|
| +
|
| +class SuiteRunner {
|
| + final List<Suite> suites;
|
| +
|
| + final Map<String, String> environment;
|
| +
|
| + final List<String> selectors;
|
| +
|
| + List<Uri> testUris;
|
| +
|
| + SuiteRunner(this.suites, this.environment, Iterable<String> selectors)
|
| + : selectors = selectors.toList(growable: false);
|
| +
|
| + Future<String> generateDartProgram() async {
|
| + List<TestDescription> descriptions = await list().toList();
|
| + testUris = <Uri>[];
|
| + StringBuffer imports = new StringBuffer();
|
| + StringBuffer dart = new StringBuffer();
|
| + StringBuffer chain = new StringBuffer();
|
| +
|
| + for (TestDescription description in descriptions) {
|
| + testUris.add(await Isolate.resolvePackageUri(description.uri));
|
| + description.writeImportOn(imports);
|
| + description.writeClosureOn(dart);
|
| + }
|
| +
|
| + for (Chain suite in suites.where((Suite suite) => suite is Chain)) {
|
| + testUris.add(await Isolate.resolvePackageUri(suite.source));
|
| + suite.writeImportOn(imports);
|
| + suite.writeClosureOn(chain);
|
| + }
|
| +
|
| + if (testUris.isEmpty) return null;
|
| +
|
| + return """
|
| +library testing.generated;
|
| +
|
| +import 'dart:async' show Future;
|
| +
|
| +import 'dart:convert' show JSON;
|
| +
|
| +import 'package:testing/src/run_tests.dart' show runTests;
|
| +
|
| +import 'package:testing/src/chain.dart' show runChain;
|
| +
|
| +import 'package:testing/src/log.dart' show enableVerboseOutput, isVerbose;
|
| +
|
| +${imports.toString().trim()}
|
| +
|
| +Future<Null> main() async {
|
| + if ($isVerbose) enableVerboseOutput();
|
| + Map<String, String> environment = JSON.decode('${JSON.encode(environment)}');
|
| + Set<String> selectors = JSON.decode('${JSON.encode(selectors)}').toSet();
|
| + await runTests(<String, Function> {
|
| + ${splitLines(dart.toString().trim()).join(' ')}
|
| + });
|
| + ${splitLines(chain.toString().trim()).join(' ')}
|
| +}
|
| +""";
|
| + }
|
| +
|
| + Future<Null> analyze(Uri packages) async {
|
| + for (Analyze suite in suites.where((Suite suite) => suite is Analyze)) {
|
| + await suite.run(packages, testUris);
|
| + }
|
| + }
|
| +
|
| + Stream<TestDescription> list() async* {
|
| + for (Dart suite in suites.where((Suite suite) => suite is Dart)) {
|
| + await for (TestDescription description in
|
| + listTests(<Uri>[suite.uri], pattern: "")) {
|
| + String path = description.file.uri.path;
|
| + if (suite.exclude.any((RegExp r) => path.contains(r))) continue;
|
| + if (suite.pattern.any((RegExp r) => path.contains(r))) {
|
| + yield description;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
|
|