<?php

/**
 * @file
 * Contains \Drupal\Tests\service_container\Plugin\ContainerAwarePluginManagerTest
 */

namespace Drupal\Tests\service_container\Plugin;

use Drupal\service_container\DependencyInjection\Container;
use Drupal\service_container\DependencyInjection\ContainerInterface;
use Drupal\service_container\Plugin\ContainerAwarePluginManager;

use Mockery;

/**
 * @coversDefaultClass \Drupal\service_container\Plugin\ContainerAwarePluginManager
 * @group dic
 */
class ContainerAwarePluginManagerTest extends \PHPUnit_Framework_TestCase {

  /**
   * {@inheritdoc}
   */
  public function setUp() {
    $this->containerDefinition = $this->getContainerDefinition();
    $this->container = new Container($this->containerDefinition);
    $this->controllerPluginManager = $this->container->get('service_container.controller');
  }

  /**
   * @covers ::__construct()
   * @covers ::getDefinition()
   */
  public function test_getDefinition() {
    $this->assertEquals($this->containerDefinition['services']['service_container.controller.internal.block'], $this->controllerPluginManager->getDefinition('block'), 'service_container.controller.internal.block definition matches.');
  }

  /**
   * @covers ::getDefinitions()
   */
  public function test_getDefinitions() {
    $filtered_definitions = array(
      'service_container.controller.internal.block' => $this->containerDefinition['services']['service_container.controller.internal.block'],
    );
    $this->assertEquals($filtered_definitions, $this->controllerPluginManager->getDefinitions(), 'getDefinitions() returns only definitions matching the prefix.');
  }

  public function test_hasDefinition() {
    $this->assertTrue($this->controllerPluginManager->hasDefinition('block'), 'service_container.controller.internal.block definition exists.');
    $this->assertFalse($this->controllerPluginManager->hasDefinition('not_exists'), 'service_container.controller.internal.not_exists definition exists not.');
  }

  /**
   * @covers ::createInstance()
   */
  public function test_createInstance() {
    $block_controller = $this->controllerPluginManager->createInstance('block');
    $this->assertInstanceof('\Drupal\render_cache_block\RenderCache\Controller\BlockController', $block_controller, 'createInstance() returns the right class.');
    $block_controller2 = $this->controllerPluginManager->createInstance('block');
    $this->assertNotSame($block_controller, $block_controller2, 'createInstance() returns not the same instance when called twice.');
  }

  /**
   * @covers ::getInstance()
   */
  public function test_getInstance() {
    $block_controller = $this->controllerPluginManager->getInstance(array('id' => 'block'));
    $this->assertInstanceof('\Drupal\render_cache_block\RenderCache\Controller\BlockController', $block_controller, 'getInstance() returns the right class.');
    $block_controller2 = $this->controllerPluginManager->getInstance(array());
    $this->assertFalse($block_controller2, 'getInstance() returns the null, when definition not specified.');
  }

  /**
   * Returns a container definition used for testing.
   *
   * @return array
   *   The container definition with services and parameters.
   */
  protected function getContainerDefinition() {
    $parameters = array();

    // This are just example classes.
    $mock_render_stack = Mockery::mock('\Drupal\render_cache\Cache\RenderStackInterface');
    $mock_cache_adapter = Mockery::mock('\Drupal\render_cache\Cache\RenderCacheBackendAdapterInterface');
    $mock_block_controller = Mockery::mock('\Drupal\render_cache_block\RenderCache\Controller\BlockController');
    $services = array();
    $services['service_container'] = array(
      'class' => '\Drupal\service_container\DependencyInjection\Container',
    );
    $services['render_stack'] = array(
      'class' => get_class($mock_render_stack),
    );
    $services['service_container.cache'] = array(
      'class' => get_class($mock_cache_adapter),
      'arguments' => array('@render_stack'),
    );
    $services['service_container.controller'] = array(
      'class' => '\Drupal\service_container\Plugin\ContainerAwarePluginManager',
      'arguments' => array('service_container.controller.internal.'),
      'calls' => array(
        array('setContainer', array('@service_container')),
      ),
      'tags' => array(
        array('ctools.plugin', array(
          'owner' => 'service_container',
          'type' => 'controller',
          'prefix' => 'service_container.controller.internal.')
        ),
      ),
    );
    // This would have been autogenerated by the ctools.plugin tag definition.
    $services['service_container.controller.internal.block'] = array(
      'class' => get_class($mock_block_controller),
      'arguments' => array(
         array(
          'class' => get_class($mock_block_controller),
          'name' => 'Block',
          'arguments' => array('@render_stack', '@service_container.cache'),
        ),
        '@render_stack',
        '@service_container.cache',
      ),
      'public' => FALSE,
    );

    return array(
      'parameters' => $parameters,
      'services' => $services,
    );
  }
}
