// 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.

library test.operation;

import 'package:plugin/plugin.dart';
import 'package:plugin/src/plugin_impl.dart';
import 'package:unittest/unittest.dart';

main() {
  groupSep = ' | ';

  group('ExtensionManager', () {
    test('processPlugins', () {
      TestPlugin plugin1 = new TestPlugin('plugin1');
      TestPlugin plugin2 = new TestPlugin('plugin1');
      ExtensionManagerImpl manager = new ExtensionManagerImpl();
      manager.processPlugins([plugin1, plugin2]);
      expect(plugin1.extensionPointsRegistered, true);
      expect(plugin1.extensionsRegistered, true);
      expect(plugin2.extensionPointsRegistered, true);
      expect(plugin2.extensionsRegistered, true);
    });

    test('registerExtension - valid', () {
      Plugin plugin = new TestPlugin('plugin');
      ExtensionManagerImpl manager = new ExtensionManagerImpl();
      ExtensionPoint point = new ExtensionPoint(plugin, 'point', null);
      manager.registerExtensionPoint(point);
      expect(point, isNotNull);
      Object extension = 'extension';
      manager.registerExtension('plugin.point', extension);
      List<Object> extensions = point.extensions;
      expect(extensions, isNotNull);
      expect(extensions, hasLength(1));
      expect(extensions[0], extension);
    });

    test('registerExtension - non existent', () {
      ExtensionManagerImpl manager = new ExtensionManagerImpl();
      expect(() => manager.registerExtension('does not exist', 'extension'),
          throwsA(new isInstanceOf<ExtensionError>()));
      ;
    });

    test('registerExtensionPoint - non-conflicting', () {
      Plugin plugin1 = new TestPlugin('plugin1');
      Plugin plugin2 = new TestPlugin('plugin2');
      ExtensionManagerImpl manager = new ExtensionManagerImpl();
      manager
          .registerExtensionPoint(new ExtensionPoint(plugin1, 'point1', null));
      manager
          .registerExtensionPoint(new ExtensionPoint(plugin1, 'point2', null));
      manager
          .registerExtensionPoint(new ExtensionPoint(plugin2, 'point1', null));
      manager
          .registerExtensionPoint(new ExtensionPoint(plugin2, 'point2', null));
    });

    test('registerExtensionPoint - conflicting - same plugin', () {
      Plugin plugin1 = new TestPlugin('plugin1');
      ExtensionManagerImpl manager = new ExtensionManagerImpl();
      manager
          .registerExtensionPoint(new ExtensionPoint(plugin1, 'point1', null));
      expect(
          () => manager.registerExtensionPoint(
              new ExtensionPoint(plugin1, 'point1', null)),
          throwsA(new isInstanceOf<ExtensionError>()));
    });

    test('registerExtensionPoint - conflicting - different plugins', () {
      Plugin plugin1 = new TestPlugin('plugin1');
      Plugin plugin2 = new TestPlugin('plugin1');
      ExtensionManagerImpl manager = new ExtensionManagerImpl();
      manager
          .registerExtensionPoint(new ExtensionPoint(plugin1, 'point1', null));
      expect(
          () => manager.registerExtensionPoint(
              new ExtensionPoint(plugin2, 'point1', null)),
          throwsA(new isInstanceOf<ExtensionError>()));
    });
  });

  group('ExtensionPointImpl', () {
    test('extensions - empty', () {
      Plugin plugin = new TestPlugin('plugin');
      ExtensionPointImpl point = new ExtensionPointImpl(plugin, 'point', null);
      List<Object> extensions = point.extensions;
      expect(extensions, isNotNull);
      expect(extensions, isEmpty);
    });

    test('uniqueIdentifier', () {
      Plugin plugin = new TestPlugin('plugin');
      ExtensionPointImpl point = new ExtensionPointImpl(plugin, 'point', null);
      expect(point.uniqueIdentifier, 'plugin.point');
    });

    test('add - single', () {
      Plugin plugin = new TestPlugin('plugin');
      ExtensionPointImpl point = new ExtensionPointImpl(plugin, 'point', null);
      Object extension = 'extension';
      point.add(extension);
      List<Object> extensions = point.extensions;
      expect(extensions, isNotNull);
      expect(extensions, hasLength(1));
      expect(extensions[0], extension);
    });

    test('add - multiple', () {
      Plugin plugin = new TestPlugin('plugin');
      ExtensionPointImpl point = new ExtensionPointImpl(plugin, 'point', null);
      point.add('extension 1');
      point.add('extension 2');
      point.add('extension 3');
      List<Object> extensions = point.extensions;
      expect(extensions, isNotNull);
      expect(extensions, hasLength(3));
    });

    test('add - with validator - valid', () {
      Plugin plugin = new TestPlugin('plugin');
      ExtensionPointImpl point =
          new ExtensionPointImpl(plugin, 'point', (Object extension) {
        if (extension is! String) {
          throw new ExtensionError('');
        }
      });
      point.add('extension');
    });

    test('add - with validator - invalid', () {
      Plugin plugin = new TestPlugin('plugin');
      ExtensionPointImpl point =
          new ExtensionPointImpl(plugin, 'point', (Object extension) {
        if (extension is! String) {
          throw new ExtensionError('');
        }
      });
      expect(() => point.add(1), throwsA(new isInstanceOf<ExtensionError>()));
    });
  });
}

/**
 * A simple plugin that can be used by tests.
 */
class TestPlugin extends Plugin {
  /**
   * A flag indicating whether the method [registerExtensionPoints] has been
   * invoked.
   */
  bool extensionPointsRegistered = false;

  /**
   * A flag indicating whether the method [registerExtensions] has been invoked.
   */
  bool extensionsRegistered = false;

  @override
  String uniqueIdentifier;

  /**
   * Initialize a newly created plugin to have the given identifier.
   */
  TestPlugin(this.uniqueIdentifier);

  @override
  void registerExtensionPoints(RegisterExtensionPoint register) {
    extensionPointsRegistered = true;
  }

  @override
  void registerExtensions(RegisterExtension register) {
    extensionsRegistered = true;
  }
}
