Version 1
[yaffs-website] / web / core / tests / Drupal / Tests / Core / DependencyInjection / Compiler / TaggedHandlersPassTest.php
diff --git a/web/core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/TaggedHandlersPassTest.php b/web/core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/TaggedHandlersPassTest.php
new file mode 100644 (file)
index 0000000..7e7381f
--- /dev/null
@@ -0,0 +1,385 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\DependencyInjection\Compiler\TaggedHandlersPassTest.
+ */
+
+namespace Drupal\Tests\Core\DependencyInjection\Compiler;
+
+use Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Exception\LogicException;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * @coversDefaultClass \Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass
+ * @group DependencyInjection
+ */
+class TaggedHandlersPassTest extends UnitTestCase {
+
+  protected function buildContainer($environment = 'dev') {
+    $container = new ContainerBuilder();
+    $container->setParameter('kernel.environment', $environment);
+    return $container;
+  }
+
+  /**
+   * Tests without any consumers.
+   *
+   * @covers ::process
+   */
+  public function testProcessNoConsumers() {
+    $container = $this->buildContainer();
+    $container
+      ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer');
+
+    $handler_pass = new TaggedHandlersPass();
+    $handler_pass->process($container);
+
+    $this->assertCount(1, $container->getDefinitions());
+    $this->assertFalse($container->getDefinition('consumer_id')->hasMethodCall('addHandler'));
+  }
+
+  /**
+   * Tests a required consumer with no handlers.
+   *
+   * @covers ::process
+   */
+  public function testProcessRequiredHandlers() {
+    $container = $this->buildContainer();
+    $container
+      ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
+      ->addTag('service_collector', [
+        'required' => TRUE,
+      ]);
+
+    $handler_pass = new TaggedHandlersPass();
+    $this->setExpectedException(LogicException::class, "At least one service tagged with 'consumer_id' is required.");
+    $handler_pass->process($container);
+  }
+
+  /**
+   * Tests consumer with missing interface in non-production environment.
+   *
+   * @covers ::process
+   */
+  public function testProcessMissingInterface() {
+    $container = $this->buildContainer();
+    $container
+      ->register('consumer_id0', __NAMESPACE__ . '\ValidConsumer')
+      ->addTag('service_collector');
+    $container
+      ->register('consumer_id1', __NAMESPACE__ . '\InvalidConsumer')
+      ->addTag('service_collector');
+
+    $handler_pass = new TaggedHandlersPass();
+    $this->setExpectedException(LogicException::class, "Service consumer 'consumer_id1' class method Drupal\Tests\Core\DependencyInjection\Compiler\InvalidConsumer::addHandler() has to type-hint an interface.");
+    $handler_pass->process($container);
+  }
+
+  /**
+   * Tests one consumer and two handlers.
+   *
+   * @covers ::process
+   */
+  public function testProcess() {
+    $container = $this->buildContainer();
+    $container
+      ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
+      ->addTag('service_collector');
+
+    $container
+      ->register('handler1', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id');
+    $container
+      ->register('handler2', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id');
+
+    $handler_pass = new TaggedHandlersPass();
+    $handler_pass->process($container);
+
+    $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
+    $this->assertCount(2, $method_calls);
+  }
+
+  /**
+   * Tests handler priority sorting.
+   *
+   * @covers ::process
+   */
+  public function testProcessPriority() {
+    $container = $this->buildContainer();
+    $container
+      ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
+      ->addTag('service_collector');
+
+    $container
+      ->register('handler1', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id');
+    $container
+      ->register('handler2', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id', [
+        'priority' => 10,
+      ]);
+
+    $handler_pass = new TaggedHandlersPass();
+    $handler_pass->process($container);
+
+    $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
+    $this->assertCount(2, $method_calls);
+    $this->assertEquals(new Reference('handler2'), $method_calls[0][1][0]);
+    $this->assertEquals(10, $method_calls[0][1][1]);
+    $this->assertEquals(new Reference('handler1'), $method_calls[1][1][0]);
+    $this->assertEquals(0, $method_calls[1][1][1]);
+  }
+
+  /**
+   * Tests consumer method without priority parameter.
+   *
+   * @covers ::process
+   */
+  public function testProcessNoPriorityParam() {
+    $container = $this->buildContainer();
+    $container
+      ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
+      ->addTag('service_collector', [
+        'call' => 'addNoPriority',
+      ]);
+
+    $container
+      ->register('handler1', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id');
+    $container
+      ->register('handler2', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id', [
+        'priority' => 10,
+      ]);
+
+    $handler_pass = new TaggedHandlersPass();
+    $handler_pass->process($container);
+
+    $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
+    $this->assertCount(2, $method_calls);
+    $this->assertEquals(new Reference('handler2'), $method_calls[0][1][0]);
+    $this->assertCount(1, $method_calls[0][1]);
+    $this->assertEquals(new Reference('handler1'), $method_calls[1][1][0]);
+    $this->assertCount(1, $method_calls[0][1]);
+  }
+
+  /**
+   * Tests consumer method with an ID parameter.
+   *
+   * @covers ::process
+   */
+  public function testProcessWithIdParameter() {
+    $container = $this->buildContainer();
+    $container
+      ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
+      ->addTag('service_collector', [
+        'call' => 'addWithId',
+      ]);
+
+    $container
+      ->register('handler1', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id');
+    $container
+      ->register('handler2', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id', [
+        'priority' => 10,
+      ]);
+
+    $handler_pass = new TaggedHandlersPass();
+    $handler_pass->process($container);
+
+    $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
+    $this->assertCount(2, $method_calls);
+    $this->assertEquals(new Reference('handler2'), $method_calls[0][1][0]);
+    $this->assertEquals('handler2', $method_calls[0][1][1]);
+    $this->assertEquals(10, $method_calls[0][1][2]);
+    $this->assertEquals(new Reference('handler1'), $method_calls[1][1][0]);
+    $this->assertEquals('handler1', $method_calls[1][1][1]);
+    $this->assertEquals(0, $method_calls[1][1][2]);
+  }
+
+  /**
+   * Tests interface validation in non-production environment.
+   *
+   * @covers ::process
+   */
+  public function testProcessInterfaceMismatch() {
+    $container = $this->buildContainer();
+
+    $container
+      ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
+      ->addTag('service_collector');
+    $container
+      ->register('handler1', __NAMESPACE__ . '\InvalidHandler')
+      ->addTag('consumer_id');
+    $container
+      ->register('handler2', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id', [
+        'priority' => 10,
+      ]);
+
+    $handler_pass = new TaggedHandlersPass();
+    $this->setExpectedException(LogicException::class);
+    $handler_pass->process($container);
+  }
+
+  /**
+   * Tests consumer method with extra parameters.
+   *
+   * @covers ::process
+   */
+  public function testProcessWithExtraArguments() {
+    $container = $this->buildContainer();
+
+    $container
+      ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
+      ->addTag('service_collector');
+
+    $container
+      ->register('handler1', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id', [
+          'extra1' => 'extra1',
+          'extra2' => 'extra2',
+        ]);
+
+    $handler_pass = new TaggedHandlersPass();
+    $handler_pass->process($container);
+
+    $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
+    $this->assertCount(4, $method_calls[0][1]);
+    $this->assertEquals(new Reference('handler1'), $method_calls[0][1][0]);
+    $this->assertEquals(0, $method_calls[0][1][1]);
+    $this->assertEquals('extra1', $method_calls[0][1][2]);
+    $this->assertEquals('extra2', $method_calls[0][1][3]);
+  }
+
+  /**
+   * Tests consumer method with extra parameters and no priority.
+   *
+   * @covers ::process
+   */
+  public function testProcessNoPriorityAndExtraArguments() {
+    $container = $this->buildContainer();
+
+    $container
+      ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
+      ->addTag('service_collector', [
+        'call' => 'addNoPriority'
+      ]);
+
+    $container
+      ->register('handler1', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id', [
+        'extra' => 'extra',
+      ]);
+
+    $handler_pass = new TaggedHandlersPass();
+    $handler_pass->process($container);
+
+    $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
+    $this->assertCount(2, $method_calls[0][1]);
+    $this->assertEquals(new Reference('handler1'), $method_calls[0][1][0]);
+    $this->assertEquals('extra', $method_calls[0][1][1]);
+  }
+
+  /**
+   * Tests consumer method with priority, id and extra parameters.
+   *
+   * @covers ::process
+   */
+  public function testProcessWithIdAndExtraArguments() {
+    $container = $this->buildContainer();
+
+    $container
+      ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
+      ->addTag('service_collector', [
+        'call' => 'addWithId'
+      ]);
+
+    $container
+      ->register('handler1', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id', [
+        'extra1' => 'extra1',
+      ]);
+
+    $handler_pass = new TaggedHandlersPass();
+    $handler_pass->process($container);
+
+    $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
+    $this->assertCount(5, $method_calls[0][1]);
+    $this->assertEquals(new Reference('handler1'), $method_calls[0][1][0]);
+    $this->assertEquals('handler1', $method_calls[0][1][1]);
+    $this->assertEquals(0, $method_calls[0][1][2]);
+    $this->assertEquals('extra1', $method_calls[0][1][3]);
+    $this->assertNull($method_calls[0][1][4]);
+  }
+
+  /**
+   * Tests consumer method with priority and extra parameters in different order.
+   *
+   * @covers ::process
+   */
+  public function testProcessWithDifferentArgumentsOrderAndDefaultValue() {
+    $container = $this->buildContainer();
+
+    $container
+      ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
+      ->addTag('service_collector', [
+        'call' => 'addWithDifferentOrder'
+      ]);
+
+    $container
+      ->register('handler1', __NAMESPACE__ . '\ValidHandler')
+      ->addTag('consumer_id', [
+        'priority' => 0,
+        'extra1' => 'extra1',
+        'extra3' => 'extra3'
+      ]);
+
+    $handler_pass = new TaggedHandlersPass();
+    $handler_pass->process($container);
+
+    $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
+    $this->assertCount(5, $method_calls[0][1]);
+    $expected = [new Reference('handler1'), 'extra1', 0, 'default2', 'extra3'];
+    $this->assertEquals($expected, array_values($method_calls[0][1]));
+  }
+
+}
+
+interface HandlerInterface {
+}
+class ValidConsumer {
+  public function addHandler(HandlerInterface $instance, $priority = 0) {
+  }
+  public function addNoPriority(HandlerInterface $instance) {
+  }
+  public function addWithId(HandlerInterface $instance, $id, $priority = 0) {
+  }
+
+}
+class InvalidConsumer {
+  public function addHandler($instance, $priority = 0) {
+  }
+
+}
+class ValidConsumerWithExtraArguments {
+  public function addHandler(HandlerInterface $instance, $priority = 0, $extra1 = '', $extra2 = '') {
+  }
+  public function addNoPriority(HandlerInterface $instance, $extra) {
+  }
+  public function addWithId(HandlerInterface $instance, $id, $priority = 0, $extra1 = '', $extra2 = NULL) {
+  }
+  public function addWithDifferentOrder(HandlerInterface $instance, $extra1, $priority = 0, $extra2 = 'default2', $extra3 = 'default3') {
+  }
+
+}
+class ValidHandler implements HandlerInterface {
+}
+class InvalidHandler {
+}