From 5b387b5cc612f02937fd5c1d88ea431c8bf25c44 Mon Sep 17 00:00:00 2001
From: Natalie Weizenbaum <nweiz@google.com>
Date: Tue, 31 Mar 2015 18:10:43 -0700
Subject: [PATCH] Move the executable's implementation into lib.

R=kevmoo@google.com

Review URL: https://codereview.chromium.org//1049903002
---
 bin/test.dart           | 168 +-------------------------------------
 lib/src/executable.dart | 174 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 175 insertions(+), 167 deletions(-)
 create mode 100644 lib/src/executable.dart

diff --git a/bin/test.dart b/bin/test.dart
index b2eb10f9..0b40282a 100644
--- a/bin/test.dart
+++ b/bin/test.dart
@@ -2,170 +2,4 @@
 // 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.
 
-library test.test;
-
-import 'dart:async';
-import 'dart:io';
-import 'dart:isolate';
-
-import 'package:args/args.dart';
-import 'package:stack_trace/stack_trace.dart';
-
-import 'package:test/src/backend/test_platform.dart';
-import 'package:test/src/runner/reporter/compact.dart';
-import 'package:test/src/runner/load_exception.dart';
-import 'package:test/src/runner/loader.dart';
-import 'package:test/src/util/exit_codes.dart' as exit_codes;
-import 'package:test/src/util/io.dart';
-import 'package:test/src/utils.dart';
-
-/// The argument parser used to parse the executable arguments.
-final _parser = new ArgParser(allowTrailingOptions: true);
-
-void main(List<String> args) {
-  _parser.addFlag("help", abbr: "h", negatable: false,
-      help: "Shows this usage information.");
-  _parser.addOption("package-root", hide: true);
-  _parser.addOption("name",
-      abbr: 'n',
-      help: 'A substring of the name of the test to run.\n'
-          'Regular expression syntax is supported.');
-  _parser.addOption("plain-name",
-      abbr: 'N',
-      help: 'A plain-text substring of the name of the test to run.');
-  _parser.addOption("platform",
-      abbr: 'p',
-      help: 'The platform(s) on which to run the tests.',
-      allowed: TestPlatform.all.map((platform) => platform.identifier).toList(),
-      defaultsTo: 'vm',
-      allowMultiple: true);
-  _parser.addFlag("color", defaultsTo: null,
-      help: 'Whether to use terminal colors.\n(auto-detected by default)');
-
-  var options;
-  try {
-    options = _parser.parse(args);
-  } on FormatException catch (error) {
-    _printUsage(error.message);
-    exitCode = exit_codes.usage;
-    return;
-  }
-
-  if (options["help"]) {
-    _printUsage();
-    return;
-  }
-
-  var color = options["color"];
-  if (color == null) color = canUseSpecialChars;
-
-  var platforms = options["platform"].map(TestPlatform.find);
-  var loader = new Loader(platforms,
-      packageRoot: options["package-root"], color: color);
-  new Future.sync(() {
-    var paths = options.rest;
-    if (paths.isEmpty) {
-      if (!new Directory("test").existsSync()) {
-        throw new LoadException("test",
-            "No test files were passed and the default directory doesn't "
-                "exist.");
-      }
-      paths = ["test"];
-    }
-
-    return Future.wait(paths.map((path) {
-      if (new Directory(path).existsSync()) return loader.loadDir(path);
-      if (new File(path).existsSync()) return loader.loadFile(path);
-      throw new LoadException(path, 'Does not exist.');
-    }));
-  }).then((suites) {
-    suites = flatten(suites);
-
-    var pattern;
-    if (options["name"] != null) {
-      if (options["plain-name"] != null) {
-        _printUsage("--name and --plain-name may not both be passed.");
-        exitCode = exit_codes.data;
-        return null;
-      }
-      pattern = new RegExp(options["name"]);
-    } else if (options["plain-name"] != null) {
-      pattern = options["plain-name"];
-    }
-
-    if (pattern != null) {
-      suites = suites.map((suite) {
-        return suite.change(
-            tests: suite.tests.where((test) => test.name.contains(pattern)));
-      }).toList();
-
-      if (suites.every((suite) => suite.tests.isEmpty)) {
-        stderr.write('No tests match ');
-
-        if (pattern is RegExp) {
-          stderr.write('regular expression "${pattern.pattern}".');
-        } else {
-          stderr.writeln('"$pattern".');
-        }
-        exitCode = exit_codes.data;
-        return null;
-      }
-    }
-
-    var reporter = new CompactReporter(flatten(suites), color: color);
-    return reporter.run().then((success) {
-      exitCode = success ? 0 : 1;
-    }).whenComplete(() => reporter.close());
-  }).catchError((error, stackTrace) {
-    if (error is LoadException) {
-      stderr.writeln(error.toString(color: color));
-
-      // Only print stack traces for load errors that come from the user's 
-      if (error.innerError is! IOException &&
-          error.innerError is! IsolateSpawnException &&
-          error.innerError is! FormatException &&
-          error.innerError is! String) {
-        stderr.write(terseChain(stackTrace));
-      }
-
-      exitCode = error.innerError is IOException
-          ? exit_codes.io
-          : exit_codes.data;
-    } else {
-      stderr.writeln(getErrorMessage(error));
-      stderr.writeln(new Trace.from(stackTrace).terse);
-      stderr.writeln(
-          "This is an unexpected error. Please file an issue at "
-              "http://github.com/dart-lang/test\n"
-          "with the stack trace and instructions for reproducing the error.");
-      exitCode = exit_codes.software;
-    }
-  }).whenComplete(() {
-    return loader.close().then((_) {
-      // If we're on a Dart version that doesn't support Isolate.kill(), we have
-      // to manually exit so that dangling isolates don't prevent it.
-      if (!supportsIsolateKill) exit(exitCode);
-    });
-  });
-}
-
-/// Print usage information for this command.
-///
-/// If [error] is passed, it's used in place of the usage message and the whole
-/// thing is printed to stderr instead of stdout.
-void _printUsage([String error]) {
-  var output = stdout;
-
-  var message = "Runs tests in this package.";
-  if (error != null) {
-    message = error;
-    output = stderr;
-  }
-
-  output.write("""$message
-
-Usage: pub run test:test [files or directories...]
-
-${_parser.usage}
-""");
-}
+export 'package:test/src/executable.dart';
diff --git a/lib/src/executable.dart b/lib/src/executable.dart
new file mode 100644
index 00000000..fe403b2a
--- /dev/null
+++ b/lib/src/executable.dart
@@ -0,0 +1,174 @@
+// 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.
+
+// TODO(nweiz): This is under lib so that it can be used by the unittest dummy
+// package. Once that package is no longer being updated, move this back into
+// bin.
+library test.executable;
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:isolate';
+
+import 'package:args/args.dart';
+import 'package:stack_trace/stack_trace.dart';
+
+import 'backend/test_platform.dart';
+import 'runner/reporter/compact.dart';
+import 'runner/load_exception.dart';
+import 'runner/loader.dart';
+import 'util/exit_codes.dart' as exit_codes;
+import 'util/io.dart';
+import 'utils.dart';
+
+/// The argument parser used to parse the executable arguments.
+final _parser = new ArgParser(allowTrailingOptions: true);
+
+void main(List<String> args) {
+  _parser.addFlag("help", abbr: "h", negatable: false,
+      help: "Shows this usage information.");
+  _parser.addOption("package-root", hide: true);
+  _parser.addOption("name",
+      abbr: 'n',
+      help: 'A substring of the name of the test to run.\n'
+          'Regular expression syntax is supported.');
+  _parser.addOption("plain-name",
+      abbr: 'N',
+      help: 'A plain-text substring of the name of the test to run.');
+  _parser.addOption("platform",
+      abbr: 'p',
+      help: 'The platform(s) on which to run the tests.',
+      allowed: TestPlatform.all.map((platform) => platform.identifier).toList(),
+      defaultsTo: 'vm',
+      allowMultiple: true);
+  _parser.addFlag("color", defaultsTo: null,
+      help: 'Whether to use terminal colors.\n(auto-detected by default)');
+
+  var options;
+  try {
+    options = _parser.parse(args);
+  } on FormatException catch (error) {
+    _printUsage(error.message);
+    exitCode = exit_codes.usage;
+    return;
+  }
+
+  if (options["help"]) {
+    _printUsage();
+    return;
+  }
+
+  var color = options["color"];
+  if (color == null) color = canUseSpecialChars;
+
+  var platforms = options["platform"].map(TestPlatform.find);
+  var loader = new Loader(platforms,
+      packageRoot: options["package-root"], color: color);
+  new Future.sync(() {
+    var paths = options.rest;
+    if (paths.isEmpty) {
+      if (!new Directory("test").existsSync()) {
+        throw new LoadException("test",
+            "No test files were passed and the default directory doesn't "
+                "exist.");
+      }
+      paths = ["test"];
+    }
+
+    return Future.wait(paths.map((path) {
+      if (new Directory(path).existsSync()) return loader.loadDir(path);
+      if (new File(path).existsSync()) return loader.loadFile(path);
+      throw new LoadException(path, 'Does not exist.');
+    }));
+  }).then((suites) {
+    suites = flatten(suites);
+
+    var pattern;
+    if (options["name"] != null) {
+      if (options["plain-name"] != null) {
+        _printUsage("--name and --plain-name may not both be passed.");
+        exitCode = exit_codes.data;
+        return null;
+      }
+      pattern = new RegExp(options["name"]);
+    } else if (options["plain-name"] != null) {
+      pattern = options["plain-name"];
+    }
+
+    if (pattern != null) {
+      suites = suites.map((suite) {
+        return suite.change(
+            tests: suite.tests.where((test) => test.name.contains(pattern)));
+      }).toList();
+
+      if (suites.every((suite) => suite.tests.isEmpty)) {
+        stderr.write('No tests match ');
+
+        if (pattern is RegExp) {
+          stderr.write('regular expression "${pattern.pattern}".');
+        } else {
+          stderr.writeln('"$pattern".');
+        }
+        exitCode = exit_codes.data;
+        return null;
+      }
+    }
+
+    var reporter = new CompactReporter(flatten(suites), color: color);
+    return reporter.run().then((success) {
+      exitCode = success ? 0 : 1;
+    }).whenComplete(() => reporter.close());
+  }).catchError((error, stackTrace) {
+    if (error is LoadException) {
+      stderr.writeln(error.toString(color: color));
+
+      // Only print stack traces for load errors that come from the user's 
+      if (error.innerError is! IOException &&
+          error.innerError is! IsolateSpawnException &&
+          error.innerError is! FormatException &&
+          error.innerError is! String) {
+        stderr.write(terseChain(stackTrace));
+      }
+
+      exitCode = error.innerError is IOException
+          ? exit_codes.io
+          : exit_codes.data;
+    } else {
+      stderr.writeln(getErrorMessage(error));
+      stderr.writeln(new Trace.from(stackTrace).terse);
+      stderr.writeln(
+          "This is an unexpected error. Please file an issue at "
+              "http://github.com/dart-lang/test\n"
+          "with the stack trace and instructions for reproducing the error.");
+      exitCode = exit_codes.software;
+    }
+  }).whenComplete(() {
+    return loader.close().then((_) {
+      // If we're on a Dart version that doesn't support Isolate.kill(), we have
+      // to manually exit so that dangling isolates don't prevent it.
+      if (!supportsIsolateKill) exit(exitCode);
+    });
+  });
+}
+
+/// Print usage information for this command.
+///
+/// If [error] is passed, it's used in place of the usage message and the whole
+/// thing is printed to stderr instead of stdout.
+void _printUsage([String error]) {
+  var output = stdout;
+
+  var message = "Runs tests in this package.";
+  if (error != null) {
+    message = error;
+    output = stderr;
+  }
+
+  output.write("""$message
+
+Usage: pub run test:test [files or directories...]
+
+${_parser.usage}
+""");
+}
-- 
GitLab