// Copyright (c) 2017, 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.

import 'dart:async';
import 'dart:io' as io;

import 'package:analysis_server/src/plugin/notification_manager.dart';
import 'package:analysis_server/src/plugin/plugin_manager.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/src/context/context_root.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/channel/channel.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart'
    hide ContextRoot;
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:watcher/watcher.dart' as watcher;

main() {
  defineReflectiveSuite(() {
    defineReflectiveTests(BuiltInPluginInfoTest);
    defineReflectiveTests(DiscoveredPluginInfoTest);
    defineReflectiveTests(PluginManagerTest);
    defineReflectiveTests(PluginManagerFromDiskTest);
    defineReflectiveTests(PluginSessionTest);
    defineReflectiveTests(PluginSessionFromDiskTest);
  });
}

ContextRoot _newContextRoot(String root, {List<String> exclude: const []}) {
  return new ContextRoot(root, exclude, pathContext: path.context);
}

@reflectiveTest
class BuiltInPluginInfoTest {
  TestNotificationManager notificationManager;
  BuiltInPluginInfo plugin;

  void setUp() {
    notificationManager = new TestNotificationManager();
    plugin = new BuiltInPluginInfo(null, 'test plugin', notificationManager,
        InstrumentationService.NULL_SERVICE);
  }

  test_addContextRoot() {
    ContextRoot contextRoot1 = _newContextRoot('/pkg1');
    plugin.addContextRoot(contextRoot1);
    expect(plugin.contextRoots, [contextRoot1]);
    plugin.addContextRoot(contextRoot1);
    expect(plugin.contextRoots, [contextRoot1]);
  }

  test_creation() {
    expect(plugin.pluginId, 'test plugin');
    expect(plugin.notificationManager, notificationManager);
    expect(plugin.contextRoots, isEmpty);
    expect(plugin.currentSession, isNull);
  }

  test_removeContextRoot() {
    ContextRoot contextRoot1 = _newContextRoot('/pkg1');
    ContextRoot contextRoot2 = _newContextRoot('/pkg2');
    plugin.addContextRoot(contextRoot1);
    expect(plugin.contextRoots, unorderedEquals([contextRoot1]));
    plugin.addContextRoot(contextRoot2);
    expect(plugin.contextRoots, unorderedEquals([contextRoot1, contextRoot2]));
    plugin.removeContextRoot(contextRoot1);
    expect(plugin.contextRoots, unorderedEquals([contextRoot2]));
    plugin.removeContextRoot(contextRoot2);
    expect(plugin.contextRoots, isEmpty);
  }

  @failingTest
  test_start_notRunning() {
    fail('Not tested');
  }

  test_start_running() async {
    plugin.currentSession = new PluginSession(plugin);
    try {
      await plugin.start('', '');
      fail('Expected a StateError');
    } on StateError {
      // Expected.
    }
  }

  test_stop_notRunning() {
    expect(() => plugin.stop(), throwsStateError);
  }

  test_stop_running() async {
    PluginSession session = new PluginSession(plugin);
    TestServerCommunicationChannel channel =
        new TestServerCommunicationChannel(session);
    plugin.currentSession = session;
    await plugin.stop();
    expect(plugin.currentSession, isNull);
    expect(channel.sentRequests, hasLength(1));
    expect(channel.sentRequests[0].method, 'plugin.shutdown');
  }
}

@reflectiveTest
class DiscoveredPluginInfoTest {
  TestNotificationManager notificationManager;
  String pluginPath = '/pluginDir';
  String executionPath = '/pluginDir/bin/plugin.dart';
  String packagesPath = '/pluginDir/.packages';
  DiscoveredPluginInfo plugin;

  void setUp() {
    notificationManager = new TestNotificationManager();
    plugin = new DiscoveredPluginInfo(pluginPath, executionPath, packagesPath,
        notificationManager, InstrumentationService.NULL_SERVICE);
  }

  test_addContextRoot() {
    String optionsFilePath = '/pkg1/analysis_options.yaml';
    ContextRoot contextRoot1 = _newContextRoot('/pkg1');
    contextRoot1.optionsFilePath = optionsFilePath;
    PluginSession session = new PluginSession(plugin);
    TestServerCommunicationChannel channel =
        new TestServerCommunicationChannel(session);
    plugin.currentSession = session;
    plugin.addContextRoot(contextRoot1);
    expect(plugin.contextRoots, [contextRoot1]);
    plugin.addContextRoot(contextRoot1);
    expect(plugin.contextRoots, [contextRoot1]);
    List<Request> sentRequests = channel.sentRequests;
    expect(sentRequests, hasLength(1));
    List<Map> roots = sentRequests[0].params['roots'];
    expect(roots[0]['optionsFile'], optionsFilePath);
  }

  test_creation() {
    expect(plugin.path, pluginPath);
    expect(plugin.executionPath, executionPath);
    expect(plugin.notificationManager, notificationManager);
    expect(plugin.contextRoots, isEmpty);
    expect(plugin.currentSession, isNull);
  }

  test_removeContextRoot() {
    ContextRoot contextRoot1 = _newContextRoot('/pkg1');
    ContextRoot contextRoot2 = _newContextRoot('/pkg2');
    plugin.addContextRoot(contextRoot1);
    expect(plugin.contextRoots, unorderedEquals([contextRoot1]));
    plugin.addContextRoot(contextRoot2);
    expect(plugin.contextRoots, unorderedEquals([contextRoot1, contextRoot2]));
    plugin.removeContextRoot(contextRoot1);
    expect(plugin.contextRoots, unorderedEquals([contextRoot2]));
    plugin.removeContextRoot(contextRoot2);
    expect(plugin.contextRoots, isEmpty);
  }

  @failingTest
  test_start_notRunning() {
    fail('Not tested');
  }

  test_start_running() async {
    plugin.currentSession = new PluginSession(plugin);
    try {
      await plugin.start('', '');
      fail('Expected a StateError');
    } on StateError {
      // Expected.
    }
  }

  test_stop_notRunning() {
    expect(() => plugin.stop(), throwsStateError);
  }

  test_stop_running() async {
    PluginSession session = new PluginSession(plugin);
    TestServerCommunicationChannel channel =
        new TestServerCommunicationChannel(session);
    plugin.currentSession = session;
    await plugin.stop();
    expect(plugin.currentSession, isNull);
    expect(channel.sentRequests, hasLength(1));
    expect(channel.sentRequests[0].method, 'plugin.shutdown');
  }
}

@reflectiveTest
class PluginManagerFromDiskTest extends PluginTestSupport {
  String byteStorePath = '/byteStore';
  PluginManager manager;

  void setUp() {
    super.setUp();
    manager = new PluginManager(resourceProvider, byteStorePath, '',
        notificationManager, InstrumentationService.NULL_SERVICE);
  }

  test_addPluginToContextRoot() async {
    io.Directory pkg1Dir = io.Directory.systemTemp.createTempSync('pkg1');
    String pkgPath = pkg1Dir.resolveSymbolicLinksSync();
    await withPlugin(test: (String pluginPath) async {
      ContextRoot contextRoot = _newContextRoot(pkgPath);
      await manager.addPluginToContextRoot(contextRoot, pluginPath);
      await manager.stopAll();
    });
    pkg1Dir.deleteSync(recursive: true);
  }

  @failingTest
  test_addPluginToContextRoot_pubspec() async {
    // We can't successfully run pub until after the analyzer_plugin package has
    // been published.
    fail('Cannot run pub');
//    io.Directory pkg1Dir = io.Directory.systemTemp.createTempSync('pkg1');
//    String pkgPath = pkg1Dir.resolveSymbolicLinksSync();
//    await withPubspecPlugin(test: (String pluginPath) async {
//      ContextRoot contextRoot = _newContextRoot(pkgPath);
//      await manager.addPluginToContextRoot(contextRoot, pluginPath);
//      String packagesPath =
//          resourceProvider.pathContext.join(pluginPath, '.packages');
//      File packagesFile = resourceProvider.getFile(packagesPath);
//      bool exists = packagesFile.exists;
//      await manager.stopAll();
//      expect(exists, isTrue, reason: '.packages file was not created');
//    });
//    pkg1Dir.deleteSync(recursive: true);
  }

  test_broadcastRequest_many() async {
    io.Directory pkg1Dir = io.Directory.systemTemp.createTempSync('pkg1');
    String pkgPath = pkg1Dir.resolveSymbolicLinksSync();
    await withPlugin(
        pluginName: 'plugin1',
        test: (String plugin1Path) async {
          await withPlugin(
              pluginName: 'plugin2',
              test: (String plugin2Path) async {
                ContextRoot contextRoot = _newContextRoot(pkgPath);
                await manager.addPluginToContextRoot(contextRoot, plugin1Path);
                await manager.addPluginToContextRoot(contextRoot, plugin2Path);

                Map<PluginInfo, Future<Response>> responses =
                    manager.broadcastRequest(
                        new CompletionGetSuggestionsParams(
                            '/pkg1/lib/pkg1.dart', 100),
                        contextRoot: contextRoot);
                expect(responses, hasLength(2));

                await manager.stopAll();
              });
        });
    pkg1Dir.deleteSync(recursive: true);
  }

  test_broadcastRequest_many_noContextRoot() async {
    io.Directory pkg1Dir = io.Directory.systemTemp.createTempSync('pkg1');
    String pkgPath = pkg1Dir.resolveSymbolicLinksSync();
    await withPlugin(
        pluginName: 'plugin1',
        test: (String plugin1Path) async {
          await withPlugin(
              pluginName: 'plugin2',
              test: (String plugin2Path) async {
                ContextRoot contextRoot = _newContextRoot(pkgPath);
                await manager.addPluginToContextRoot(contextRoot, plugin1Path);
                await manager.addPluginToContextRoot(contextRoot, plugin2Path);

                Map<PluginInfo, Future<Response>> responses =
                    manager.broadcastRequest(new CompletionGetSuggestionsParams(
                        '/pkg1/lib/pkg1.dart', 100));
                expect(responses, hasLength(2));

                await manager.stopAll();
              });
        });
    pkg1Dir.deleteSync(recursive: true);
  }

  test_broadcastWatchEvent() async {
    io.Directory pkg1Dir = io.Directory.systemTemp.createTempSync('pkg1');
    String pkgPath = pkg1Dir.resolveSymbolicLinksSync();
    await withPlugin(
        pluginName: 'plugin1',
        test: (String plugin1Path) async {
          ContextRoot contextRoot = _newContextRoot(pkgPath);
          await manager.addPluginToContextRoot(contextRoot, plugin1Path);
          List<PluginInfo> plugins = manager.pluginsForContextRoot(contextRoot);
          expect(plugins, hasLength(1));
          watcher.WatchEvent watchEvent = new watcher.WatchEvent(
              watcher.ChangeType.MODIFY, path.join(pkgPath, 'lib', 'lib.dart'));
          List<Future<Response>> responses =
              await manager.broadcastWatchEvent(watchEvent);
          expect(responses, hasLength(1));
          Response response = await responses[0];
          expect(response, isNotNull);
          expect(response.error, isNull);
          await manager.stopAll();
        });
    pkg1Dir.deleteSync(recursive: true);
  }

  test_pluginsForContextRoot_multiple() async {
    io.Directory pkg1Dir = io.Directory.systemTemp.createTempSync('pkg1');
    String pkgPath = pkg1Dir.resolveSymbolicLinksSync();
    await withPlugin(
        pluginName: 'plugin1',
        test: (String plugin1Path) async {
          await withPlugin(
              pluginName: 'plugin2',
              test: (String plugin2Path) async {
                ContextRoot contextRoot = _newContextRoot(pkgPath);
                await manager.addPluginToContextRoot(contextRoot, plugin1Path);
                await manager.addPluginToContextRoot(contextRoot, plugin2Path);

                List<PluginInfo> plugins =
                    manager.pluginsForContextRoot(contextRoot);
                expect(plugins, hasLength(2));
                List<String> paths = plugins
                    .map((PluginInfo plugin) => plugin.pluginId)
                    .toList();
                expect(paths, unorderedEquals([plugin1Path, plugin2Path]));

                await manager.stopAll();
              });
        });
    pkg1Dir.deleteSync(recursive: true);
  }

  test_pluginsForContextRoot_one() async {
    io.Directory pkg1Dir = io.Directory.systemTemp.createTempSync('pkg1');
    String pkgPath = pkg1Dir.resolveSymbolicLinksSync();
    await withPlugin(test: (String pluginPath) async {
      ContextRoot contextRoot = _newContextRoot(pkgPath);
      await manager.addPluginToContextRoot(contextRoot, pluginPath);

      List<PluginInfo> plugins = manager.pluginsForContextRoot(contextRoot);
      expect(plugins, hasLength(1));
      expect(plugins[0].pluginId, pluginPath);

      await manager.stopAll();
    });
    pkg1Dir.deleteSync(recursive: true);
  }

  test_removedContextRoot() async {
    io.Directory pkg1Dir = io.Directory.systemTemp.createTempSync('pkg1');
    String pkgPath = pkg1Dir.resolveSymbolicLinksSync();
    await withPlugin(test: (String pluginPath) async {
      ContextRoot contextRoot = _newContextRoot(pkgPath);
      await manager.addPluginToContextRoot(contextRoot, pluginPath);

      manager.removedContextRoot(contextRoot);

      await manager.stopAll();
    });
    pkg1Dir.deleteSync(recursive: true);
  }

  @TestTimeout(const Timeout.factor(4))
  test_restartPlugins() async {
    io.Directory pkg1Dir = io.Directory.systemTemp.createTempSync('pkg1');
    String pkg1Path = pkg1Dir.resolveSymbolicLinksSync();
    io.Directory pkg2Dir = io.Directory.systemTemp.createTempSync('pkg2');
    String pkg2Path = pkg2Dir.resolveSymbolicLinksSync();
    await withPlugin(
        pluginName: 'plugin1',
        test: (String plugin1Path) async {
          await withPlugin(
              pluginName: 'plugin2',
              test: (String plugin2Path) async {
                ContextRoot contextRoot1 = _newContextRoot(pkg1Path);
                ContextRoot contextRoot2 = _newContextRoot(pkg2Path);
                await manager.addPluginToContextRoot(contextRoot1, plugin1Path);
                await manager.addPluginToContextRoot(contextRoot1, plugin2Path);
                await manager.addPluginToContextRoot(contextRoot2, plugin1Path);

                await manager.restartPlugins();
                List<PluginInfo> plugins = manager.plugins;
                expect(plugins, hasLength(2));
                expect(plugins[0].currentSession, isNotNull);
                expect(plugins[1].currentSession, isNotNull);
                if (plugins[0].pluginId.contains('plugin1')) {
                  expect(plugins[0].contextRoots,
                      unorderedEquals([contextRoot1, contextRoot2]));
                  expect(
                      plugins[1].contextRoots, unorderedEquals([contextRoot1]));
                } else {
                  expect(
                      plugins[0].contextRoots, unorderedEquals([contextRoot1]));
                  expect(plugins[1].contextRoots,
                      unorderedEquals([contextRoot1, contextRoot2]));
                }
                await manager.stopAll();
              });
        });
    pkg1Dir.deleteSync(recursive: true);
  }
}

@reflectiveTest
class PluginManagerTest extends Object with ResourceProviderMixin {
  String byteStorePath;
  String sdkPath;
  TestNotificationManager notificationManager;
  PluginManager manager;

  void setUp() {
    byteStorePath = resourceProvider.convertPath('/byteStore');
    sdkPath = resourceProvider.convertPath('/sdk');
    notificationManager = new TestNotificationManager();
    manager = new PluginManager(resourceProvider, byteStorePath, sdkPath,
        notificationManager, InstrumentationService.NULL_SERVICE);
  }

  void test_broadcastRequest_none() {
    ContextRoot contextRoot = _newContextRoot('/pkg1');
    Map<PluginInfo, Future<Response>> responses = manager.broadcastRequest(
        new CompletionGetSuggestionsParams('/pkg1/lib/pkg1.dart', 100),
        contextRoot: contextRoot);
    expect(responses, hasLength(0));
  }

  void test_creation() {
    expect(manager.resourceProvider, resourceProvider);
    expect(manager.byteStorePath, byteStorePath);
    expect(manager.sdkPath, sdkPath);
    expect(manager.notificationManager, notificationManager);
  }

  void test_pathsFor_withPackagesFile() {
    //
    // Build the minimal directory structure for a plugin package that includes
    // a .packages file.
    //
    String pluginDirPath = newFolder('/plugin').path;
    String pluginFilePath = newFile('/plugin/bin/plugin.dart').path;
    String packagesFilePath = newFile('/plugin/.packages').path;
    //
    // Test path computation.
    //
    List<String> paths = manager.pathsFor(pluginDirPath);
    expect(paths, hasLength(2));
    expect(paths[0], pluginFilePath);
    expect(paths[1], packagesFilePath);
  }

  void test_pathsFor_withPubspec_inBazelWorkspace() {
    //
    // Build a Bazel workspace containing four packages, including the plugin.
    //
    newFile('/workspaceRoot/WORKSPACE');
    newFolder('/workspaceRoot/bazel-bin');
    newFolder('/workspaceRoot/bazel-genfiles');

    String newPackage(String packageName, [List<String> dependencies]) {
      String packageRoot =
          newFolder('/workspaceRoot/third_party/dart/$packageName').path;
      newFile('$packageRoot/lib/$packageName.dart');
      StringBuffer buffer = new StringBuffer();
      if (dependencies != null) {
        buffer.writeln('dependencies:');
        for (String dependency in dependencies) {
          buffer.writeln('  $dependency: any');
        }
      }
      newFile('$packageRoot/pubspec.yaml', content: buffer.toString());
      return packageRoot;
    }

    String pluginDirPath = newPackage('plugin', ['b', 'c']);
    newPackage('b', ['d']);
    newPackage('c', ['d']);
    newPackage('d');
    String pluginFilePath = newFile('$pluginDirPath/bin/plugin.dart').path;
    //
    // Test path computation.
    //
    List<String> paths = manager.pathsFor(pluginDirPath);
    expect(paths, hasLength(2));
    expect(paths[0], pluginFilePath);
    File packagesFile = getFile(paths[1]);
    expect(packagesFile.exists, isTrue);
    String content = packagesFile.readAsStringSync();
    List<String> lines = content.split('\n');
    String asFileUri(String input) =>
        new Uri.file(convertPath(input)).toString();
    expect(
        lines,
        unorderedEquals([
          'plugin:${asFileUri('/workspaceRoot/third_party/dart/plugin/lib')}',
          'b:${asFileUri('/workspaceRoot/third_party/dart/b/lib')}',
          'c:${asFileUri('/workspaceRoot/third_party/dart/c/lib')}',
          'd:${asFileUri('/workspaceRoot/third_party/dart/d/lib')}',
          ''
        ]));
  }

  void test_pluginsForContextRoot_none() {
    ContextRoot contextRoot = _newContextRoot('/pkg1');
    expect(manager.pluginsForContextRoot(contextRoot), isEmpty);
  }

  void test_stopAll_none() {
    manager.stopAll();
  }
}

@reflectiveTest
class PluginSessionFromDiskTest extends PluginTestSupport {
  test_start_notRunning() async {
    await withPlugin(test: (String pluginPath) async {
      String packagesPath = path.join(pluginPath, '.packages');
      String mainPath = path.join(pluginPath, 'bin', 'plugin.dart');
      String byteStorePath = path.join(pluginPath, 'byteStore');
      new io.Directory(byteStorePath).createSync();
      PluginInfo plugin = new DiscoveredPluginInfo(
          pluginPath,
          mainPath,
          packagesPath,
          notificationManager,
          InstrumentationService.NULL_SERVICE);
      PluginSession session = new PluginSession(plugin);
      plugin.currentSession = session;
      expect(await session.start(byteStorePath, ''), isTrue);
      await session.stop();
    });
  }
}

@reflectiveTest
class PluginSessionTest extends Object with ResourceProviderMixin {
  TestNotificationManager notificationManager;
  String pluginPath;
  String executionPath;
  String packagesPath;
  String sdkPath;
  PluginInfo plugin;
  PluginSession session;

  void setUp() {
    notificationManager = new TestNotificationManager();
    pluginPath = resourceProvider.convertPath('/pluginDir');
    executionPath = resourceProvider.convertPath('/pluginDir/bin/plugin.dart');
    packagesPath = resourceProvider.convertPath('/pluginDir/.packages');
    sdkPath = resourceProvider.convertPath('/sdk');
    plugin = new DiscoveredPluginInfo(pluginPath, executionPath, packagesPath,
        notificationManager, InstrumentationService.NULL_SERVICE);
    session = new PluginSession(plugin);
  }

  void test_handleNotification() {
    Notification notification =
        new AnalysisErrorsParams('/test.dart', <AnalysisError>[])
            .toNotification();
    expect(notificationManager.notifications, hasLength(0));
    session.handleNotification(notification);
    expect(notificationManager.notifications, hasLength(1));
    expect(notificationManager.notifications[0], notification);
  }

  void test_handleOnDone() {
    TestServerCommunicationChannel channel =
        new TestServerCommunicationChannel(session);
    session.handleOnDone();
    expect(channel.closeCount, 1);
    expect(session.pluginStoppedCompleter.isCompleted, isTrue);
  }

  @failingTest
  void test_handleOnError() {
    session.handleOnError(<String>['message', 'trace']);
    fail('The method handleOnError is not implemented');
  }

  test_handleResponse() async {
    new TestServerCommunicationChannel(session);
    Response response = new PluginVersionCheckResult(
            true, 'name', 'version', <String>[],
            contactInfo: 'contactInfo')
        .toResponse('0', 1);
    Future<Response> future =
        session.sendRequest(new PluginVersionCheckParams('', '', ''));
    expect(session.pendingRequests, hasLength(1));
    session.handleResponse(response);
    expect(session.pendingRequests, hasLength(0));
    Response result = await future;
    expect(result, same(response));
  }

  void test_nextRequestId() {
    expect(session.requestId, 0);
    expect(session.nextRequestId, '0');
    expect(session.requestId, 1);
  }

  void test_sendRequest() {
    TestServerCommunicationChannel channel =
        new TestServerCommunicationChannel(session);
    session.sendRequest(new PluginVersionCheckParams('', '', ''));
    expect(channel.sentRequests, hasLength(1));
    expect(channel.sentRequests[0].method, 'plugin.versionCheck');
  }

  test_start_notCompatible() async {
    session.isCompatible = false;
    expect(await session.start(path.join(pluginPath, 'byteStore'), sdkPath),
        isFalse);
  }

  test_start_running() async {
    new TestServerCommunicationChannel(session);
    try {
      await session.start(null, '');
      fail('Expected a StateError to be thrown');
    } on StateError {
      // Expected behavior
    }
  }

  test_stop_notRunning() {
    expect(() => session.stop(), throwsStateError);
  }

  test_stop_running() async {
    TestServerCommunicationChannel channel =
        new TestServerCommunicationChannel(session);
    await session.stop();
    expect(channel.sentRequests, hasLength(1));
    expect(channel.sentRequests[0].method, 'plugin.shutdown');
  }
}

/**
 * A class designed to be used as a superclass for test classes that define
 * tests that require plugins to be created on disk.
 */
abstract class PluginTestSupport {
  PhysicalResourceProvider resourceProvider;
  TestNotificationManager notificationManager;

  /**
   * The content to be used for the '.packages' file, or `null` if the content
   * has not yet been computed.
   */
  String _packagesFileContent;

  void setUp() {
    resourceProvider = PhysicalResourceProvider.INSTANCE;
    notificationManager = new TestNotificationManager();
  }

  /**
   * Create a directory structure representing a plugin on disk, run the given
   * [test] function, and then remove the directory. The directory will have the
   * following structure:
   * ```
   * pluginDirectory
   *   .packages
   *   bin
   *     plugin.dart
   * ```
   * The name of the plugin directory will be the [pluginName], if one is
   * provided (in order to allow more than one plugin to be created by a single
   * test). The 'plugin.dart' file will contain the given [content], or default
   * content that implements a minimal plugin if the contents are not given. The
   * [test] function will be passed the path of the directory that was created.
   */
  Future<void> withPlugin(
      {String content,
      String pluginName,
      Future<void> test(String pluginPath)}) async {
    io.Directory tempDirectory =
        io.Directory.systemTemp.createTempSync(pluginName ?? 'test_plugin');
    try {
      String pluginPath = tempDirectory.resolveSymbolicLinksSync();
      //
      // Create a .packages file.
      //
      io.File packagesFile = new io.File(path.join(pluginPath, '.packages'));
      packagesFile.writeAsStringSync(_getPackagesFileContent());
      //
      // Create the 'bin' directory.
      //
      String binPath = path.join(pluginPath, 'bin');
      new io.Directory(binPath).createSync();
      //
      // Create the 'plugin.dart' file.
      //
      io.File pluginFile = new io.File(path.join(binPath, 'plugin.dart'));
      pluginFile.writeAsStringSync(content ?? _defaultPluginContent());
      //
      // Run the actual test code.
      //
      await test(pluginPath);
    } finally {
      tempDirectory.deleteSync(recursive: true);
    }
  }

  /**
   * Create a directory structure representing a plugin on disk, run the given
   * [test] function, and then remove the directory. The directory will have the
   * following structure:
   * ```
   * pluginDirectory
   *   pubspec.yaml
   *   bin
   *     plugin.dart
   * ```
   * The name of the plugin directory will be the [pluginName], if one is
   * provided (in order to allow more than one plugin to be created by a single
   * test). The 'plugin.dart' file will contain the given [content], or default
   * content that implements a minimal plugin if the contents are not given. The
   * [test] function will be passed the path of the directory that was created.
   */
  Future<void> withPubspecPlugin(
      {String content,
      String pluginName,
      Future<void> test(String pluginPath)}) async {
    io.Directory tempDirectory =
        io.Directory.systemTemp.createTempSync(pluginName ?? 'test_plugin');
    try {
      String pluginPath = tempDirectory.resolveSymbolicLinksSync();
      //
      // Create a pubspec.yaml file.
      //
      io.File pubspecFile = new io.File(path.join(pluginPath, 'pubspec.yaml'));
      pubspecFile.writeAsStringSync(_getPubspecFileContent());
      //
      // Create the 'bin' directory.
      //
      String binPath = path.join(pluginPath, 'bin');
      new io.Directory(binPath).createSync();
      //
      // Create the 'plugin.dart' file.
      //
      io.File pluginFile = new io.File(path.join(binPath, 'plugin.dart'));
      pluginFile.writeAsStringSync(content ?? _defaultPluginContent());
      //
      // Run the actual test code.
      //
      await test(pluginPath);
    } finally {
      tempDirectory.deleteSync(recursive: true);
    }
  }

  /**
   * Convert the [sdkPackageMap] into a plugin-specific map by applying the
   * given relative path [delta] to each line.
   */
  String _convertPackageMap(String sdkDirPath, List<String> sdkPackageMap) {
    StringBuffer buffer = new StringBuffer();
    for (String line in sdkPackageMap) {
      if (!line.startsWith('#')) {
        int index = line.indexOf(':');
        String packageName = line.substring(0, index + 1);
        String relativePath = line.substring(index + 1);
        String absolutePath = path.join(sdkDirPath, relativePath);
        // Convert to file:/// URI since that's how absolute paths in
        // .packages must be for windows
        absolutePath = new Uri.file(absolutePath).toString();
        buffer.write(packageName);
        buffer.writeln(absolutePath);
      }
    }
    return buffer.toString();
  }

  /**
   * The default content of the plugin. This is a minimal plugin that will only
   * respond correctly to version checks and to shutdown requests.
   */
  String _defaultPluginContent() {
    return r'''
import 'dart:async';
import 'dart:isolate';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer_plugin/plugin/plugin.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/starter.dart';
import 'package:pub_semver/pub_semver.dart';

void main(List<String> args, SendPort sendPort) {
  MinimalPlugin plugin = new MinimalPlugin(PhysicalResourceProvider.INSTANCE);
  new ServerPluginStarter(plugin).start(sendPort);
}

class MinimalPlugin extends ServerPlugin {
  MinimalPlugin(ResourceProvider provider) : super(provider);

  @override
  List<String> get fileGlobsToAnalyze => <String>['**/*.dart'];

  @override
  String get name => 'minimal';

  @override
  String get version => '0.0.1';

  @override
  AnalysisDriverGeneric createAnalysisDriver(ContextRoot contextRoot) => null;

  @override
  Future<AnalysisHandleWatchEventsResult> handleAnalysisHandleWatchEvents(
      AnalysisHandleWatchEventsParams parameters) async =>
    new AnalysisHandleWatchEventsResult();

  @override
  bool isCompatibleWith(Version serverVersion) => true;
}
''';
  }

  /**
   * Return the content to be used for the '.packages' file.
   */
  String _getPackagesFileContent() {
    if (_packagesFileContent == null) {
      io.File sdkPackagesFile = new io.File(_sdkPackagesPath());
      List<String> sdkPackageMap = sdkPackagesFile.readAsLinesSync();
      _packagesFileContent =
          _convertPackageMap(path.dirname(sdkPackagesFile.path), sdkPackageMap);
    }
    return _packagesFileContent;
  }

  /**
   * Return the content to be used for the 'pubspec.yaml' file.
   */
  String _getPubspecFileContent() {
    return '''
name: 'test'
dependencies:
  analyzer: any
  analyzer_plugin: any
''';
  }

  /**
   * Return the path to the '.packages' file in the root of the SDK checkout.
   */
  String _sdkPackagesPath() {
    String packagesPath = io.Platform.script.toFilePath();
    while (packagesPath.isNotEmpty &&
        path.basename(packagesPath) != 'analysis_server') {
      packagesPath = path.dirname(packagesPath);
    }
    packagesPath = path.dirname(packagesPath);
    packagesPath = path.dirname(packagesPath);
    return path.join(packagesPath, '.packages');
  }
}

class TestNotificationManager implements NotificationManager {
  List<Notification> notifications = <Notification>[];

  Map<String, Map<String, List<AnalysisError>>> recordedErrors =
      <String, Map<String, List<AnalysisError>>>{};

  @override
  void handlePluginNotification(String pluginId, Notification notification) {
    notifications.add(notification);
  }

  @override
  noSuchMethod(Invocation invocation) {
    fail('Unexpected invocation of ${invocation.memberName}');
  }

  @override
  void recordAnalysisErrors(
      String pluginId, String filePath, List<AnalysisError> errorData) {
    recordedErrors.putIfAbsent(
        pluginId, () => <String, List<AnalysisError>>{})[filePath] = errorData;
  }
}

class TestServerCommunicationChannel implements ServerCommunicationChannel {
  final PluginSession session;
  int closeCount = 0;
  List<Request> sentRequests = <Request>[];

  TestServerCommunicationChannel(this.session) {
    session.channel = this;
  }

  @override
  void close() {
    closeCount++;
  }

  void kill() {
    fail('Unexpected invocation of kill');
  }

  @override
  void listen(void onResponse(Response response),
      void onNotification(Notification notification),
      {void onError(dynamic error), void onDone()}) {
    fail('Unexpected invocation of listen');
  }

  @override
  void sendRequest(Request request) {
    sentRequests.add(request);
    if (request.method == 'plugin.shutdown') {
      session.handleOnDone();
    }
  }
}
