Generate native executables to use when running the integration tests.

There are two test suites that spawn Dart executables to validate the
CLI behavior. Those are painfully slow when running the programs from
source. This precompiles them to native executes and then spawns those.

On my machine it takes the tests from ~4 minutes down to ~40 seconds.
diff --git a/pubspec.yaml b/pubspec.yaml
index 38c2dae..cc50185 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
 name: dart_style
 # Note: See tool/grind.dart for how to bump the version.
-version: 1.3.4
+version: 1.3.5-dev
 description: >-
   Opinionated, automatic Dart source code formatter.
   Provides an API and a CLI tool.
diff --git a/test/command_line_test.dart b/test/command_line_test.dart
index 9bbaf07..9dbadf9 100644
--- a/test/command_line_test.dart
+++ b/test/command_line_test.dart
@@ -13,6 +13,8 @@
 import 'utils.dart';
 
 void main() {
+  compileFormatterExecutable();
+
   test('formats a directory', () async {
     await d.dir('code', [
       d.file('a.dart', unformattedSource),
diff --git a/test/command_test.dart b/test/command_test.dart
index 32ed262..20a1928 100644
--- a/test/command_test.dart
+++ b/test/command_test.dart
@@ -11,6 +11,8 @@
 import 'utils.dart';
 
 void main() {
+  compileCommandExecutable();
+
   test('formats a directory', () async {
     await d.dir('code', [
       d.file('a.dart', unformattedSource),
diff --git a/test/utils.dart b/test/utils.dart
index da3d766..1ea15de 100644
--- a/test/utils.dart
+++ b/test/utils.dart
@@ -25,17 +25,89 @@
 final _indentPattern = RegExp(r'\(indent (\d+)\)');
 final _fixPattern = RegExp(r'\(fix ([a-x-]+)\)');
 
-/// Runs the command line formatter, passing it [args].
-Future<TestProcess> runFormatter([List<String> args]) {
+/// If tool/command_shell.dart has been compiled to a snapshot, this is the path
+/// to it.
+String _commandExecutablePath;
+
+/// If bin/format.dart has been compiled to a snapshot, this is the path to it.
+String _formatterExecutablePath;
+
+/// Compiles format.dart to a native executable for tests to use.
+void compileFormatterExecutable() {
+  setUpAll(() async {
+    _formatterExecutablePath = await _compileExecutable('bin/format.dart');
+  });
+
+  tearDownAll(() async {
+    await _deleteExecutable(_formatterExecutablePath);
+    _formatterExecutablePath = null;
+  });
+}
+
+/// Compiles command_shell.dart to a native executable for tests to use.
+void compileCommandExecutable() {
+  setUpAll(() async {
+    _commandExecutablePath =
+        await _compileExecutable('tool/command_shell.dart');
+  });
+
+  tearDownAll(() async {
+    await _deleteExecutable(_commandExecutablePath);
+    _commandExecutablePath = null;
+  });
+}
+
+/// Compile the Dart [script] to a native executable.
+///
+/// We do this instead of spawning the script from source each time because it's
+/// much faster when the same script needs to be run several times.
+Future<String> _compileExecutable(String script) async {
+  var scriptName = p.basename(script);
+  var tempDir =
+      await Directory.systemTemp.createTemp(p.withoutExtension(scriptName));
+  var executable = p.join(tempDir.path, '$scriptName.aot');
+
+  var dart2Native =
+      p.join(p.dirname(Platform.resolvedExecutable), 'dart2native');
+
   // Locate the "test" directory. Use mirrors so that this works with the test
   // package, which loads this suite into an isolate.
   var testDir = p.dirname(currentMirrorSystem()
       .findLibrary(#dart_style.test.utils)
       .uri
       .toFilePath());
+  var scriptPath = p.normalize(p.join(p.dirname(testDir), script));
 
-  var formatterPath = p.normalize(p.join(testDir, '../bin/format.dart'));
-  return TestProcess.start(Platform.executable, [formatterPath, ...?args],
+  var compileResult = await Process.run(
+      dart2Native, [scriptPath, '--output', executable]);
+
+  if (compileResult.exitCode != 0) {
+    fail('Could not compile $scriptName to a snapshot (exit code '
+        '${compileResult.exitCode}):\n${compileResult.stdout}\n\n'
+        '${compileResult.stderr}');
+  }
+
+  return executable;
+}
+
+/// Attempts to delete to temporary directory created for [executable] by
+/// [_createSnapshot()].
+Future<void> _deleteExecutable(String executable) async {
+  try {
+    await Directory(p.dirname(executable)).delete(recursive: true);
+  } on IOException {
+    // Do nothing if we failed to delete it. The OS will eventually clean it
+    // up.
+  }
+}
+
+/// Runs the command line formatter, passing it [args].
+Future<TestProcess> runFormatter([List<String> args]) {
+  if (_formatterExecutablePath == null) {
+    fail('Must call createFormatterExecutable() before running commands.');
+  }
+
+  return TestProcess.start(_formatterExecutablePath, args ?? <String>[],
       workingDirectory: d.sandbox);
 }
 
@@ -47,17 +119,11 @@
 
 /// Runs the test shell for the [Command]-based formatter, passing it [args].
 Future<TestProcess> runCommand([List<String> args]) {
-  // Locate the "test" directory. Use mirrors so that this works with the test
-  // package, which loads this suite into an isolate.
-  var testDir = p.dirname(currentMirrorSystem()
-      .findLibrary(#dart_style.test.utils)
-      .uri
-      .toFilePath());
+  if (_commandExecutablePath == null) {
+    fail('Must call createCommandExecutable() before running commands.');
+  }
 
-  var formatterPath =
-      p.normalize(p.join(testDir, '../tool/command_shell.dart'));
-  return TestProcess.start(
-      Platform.executable, [formatterPath, 'format', ...?args],
+  return TestProcess.start(_commandExecutablePath, ['format', ...?args],
       workingDirectory: d.sandbox);
 }