| Index: lib/src/executable.dart
|
| diff --git a/lib/src/executable.dart b/lib/src/executable.dart
|
| index bf619b2af8e314702745953d9131994c50dc946b..7e543d139772e6305558ec87b9f0e383223df0b3 100644
|
| --- a/lib/src/executable.dart
|
| +++ b/lib/src/executable.dart
|
| @@ -12,6 +12,7 @@ import 'dart:io';
|
| import 'dart:math' as math;
|
|
|
| import 'package:args/args.dart';
|
| +import 'package:async/async.dart';
|
| import 'package:stack_trace/stack_trace.dart';
|
| import 'package:yaml/yaml.dart';
|
|
|
| @@ -20,7 +21,7 @@ import 'backend/test_platform.dart';
|
| import 'runner/engine.dart';
|
| import 'runner/application_exception.dart';
|
| import 'runner/load_exception.dart';
|
| -import 'runner/load_exception_suite.dart';
|
| +import 'runner/load_suite.dart';
|
| import 'runner/loader.dart';
|
| import 'runner/reporter/compact.dart';
|
| import 'runner/reporter/expanded.dart';
|
| @@ -211,8 +212,10 @@ transformers:
|
| metadata: metadata,
|
| jsTrace: options["js-trace"]);
|
|
|
| + var closed = false;
|
| var signalSubscription;
|
| signalSubscription = _signals.listen((_) {
|
| + closed = true;
|
| signalSubscription.cancel();
|
| loader.close();
|
| });
|
| @@ -235,6 +238,7 @@ transformers:
|
| // Override the signal handler to close [reporter]. [loader] will still be
|
| // closed in the [whenComplete] below.
|
| signalSubscription.onData((_) async {
|
| + closed = true;
|
| signalSubscription.cancel();
|
|
|
| // Wait a bit to print this message, since printing it eagerly looks weird
|
| @@ -247,6 +251,8 @@ transformers:
|
| print("Press Control-C again to terminate immediately.");
|
| });
|
|
|
| + // Make sure we close the engine *before* the loader. Otherwise,
|
| + // LoadSuites provided by the loader may get into bad states.
|
| await engine.close();
|
| timer.cancel();
|
| await loader.close();
|
| @@ -258,6 +264,8 @@ transformers:
|
| engine.run()
|
| ], eagerError: true);
|
|
|
| + if (closed) return;
|
| +
|
| // Explicitly check "== true" here because [engine.run] can return `null`
|
| // if the engine was closed prematurely.
|
| exitCode = results.last == true ? 0 : 1;
|
| @@ -301,29 +309,34 @@ transformers:
|
| /// run the engine.
|
| Future _loadSuites(List<String> paths, Pattern pattern, Loader loader,
|
| Engine engine) async {
|
| - var completer = new Completer();
|
| + var group = new FutureGroup();
|
|
|
| mergeStreams(paths.map((path) {
|
| if (new Directory(path).existsSync()) return loader.loadDir(path);
|
| if (new File(path).existsSync()) return loader.loadFile(path);
|
|
|
| - return new Stream.fromFuture(new Future.error(
|
| - new LoadException(path, 'Does not exist.'),
|
| - new Trace.current()));
|
| - })).map((suite) {
|
| - if (pattern == null) return suite;
|
| - return suite.change(
|
| - tests: suite.tests.where((test) => test.name.contains(pattern)));
|
| - }).listen((suite) => engine.suiteSink.add(suite),
|
| - onError: (error, stackTrace) {
|
| - if (error is LoadException) {
|
| - engine.suiteSink.add(new LoadExceptionSuite(error, stackTrace));
|
| - } else if (!completer.isCompleted) {
|
| - completer.completeError(error, stackTrace);
|
| - }
|
| - }, onDone: () => completer.complete());
|
| + return new Stream.fromIterable([
|
| + new LoadSuite("loading $path", () =>
|
| + throw new LoadException(path, 'Does not exist.'))
|
| + ]);
|
| + })).listen((loadSuite) {
|
| + group.add(new Future.sync(() async {
|
| + engine.suiteSink.add(loadSuite);
|
| +
|
| + var suite = await loadSuite.suite;
|
| + if (suite == null) return;
|
| + if (pattern != null) {
|
| + suite = suite.change(
|
| + tests: suite.tests.where((test) => test.name.contains(pattern)));
|
| + }
|
| +
|
| + engine.suiteSink.add(suite);
|
| + }));
|
| + }, onError: (error, stackTrace) {
|
| + group.add(new Future.error(error, stackTrace));
|
| + }, onDone: group.close);
|
|
|
| - await completer.future;
|
| + await group.future;
|
|
|
| // Once we've loaded all the suites, notify the engine that no more will be
|
| // coming.
|
|
|