From c3025c9edac314e7ca3f4ed628fb03dd4fa5092b Mon Sep 17 00:00:00 2001
From: Andreas Hennings <andreas@dqxtech.net>
Date: Tue, 20 May 2014 04:11:33 +0200
Subject: [PATCH] Add ModuleImplementsAlterTest.

---
 .../Tests/Module/ModuleImplementsAlterTest.php     | 115 +++++++++++++++++++++
 .../module_test/module_test.implementations.inc    |  10 ++
 .../tests/modules/module_test/module_test.module   |  20 ++++
 3 files changed, 145 insertions(+)
 create mode 100644 core/modules/system/lib/Drupal/system/Tests/Module/ModuleImplementsAlterTest.php
 create mode 100644 core/modules/system/tests/modules/module_test/module_test.implementations.inc

diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleImplementsAlterTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleImplementsAlterTest.php
new file mode 100644
index 0000000..6fb459e
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleImplementsAlterTest.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Module\ModuleApiTest.
+ */
+
+namespace Drupal\system\Tests\Module;
+
+use Drupal\Core\Extension\ModuleHandler;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Unit tests for the module API.
+ */
+class ModuleImplementsAlterTest extends WebTestBase {
+
+  /**
+   * This test requires Standard profile modules/dependencies.
+   *
+   * @see \Drupal\simpletest\WebTestBase::$profile
+   *
+   * @var string
+   */
+  protected $profile = 'standard';
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Module implementation alteration.',
+      'description' => 'Test hook_module_implements_alter().',
+      'group' => 'Module',
+    );
+  }
+
+  /**
+   * Tests hook_module_implements_alter() adding an implementation.
+   *
+   * @see \Drupal\Core\Extension\ModuleHandler::buildImplementationInfo()
+   * @see module_test_module_implements_alter()
+   */
+  function testModuleImplementsAlter() {
+
+    // Get an instance of the module handler, to observe how it is going to be
+    // replaced.
+    $module_handler = \Drupal::moduleHandler();
+
+    $this->assertTrue($module_handler === \Drupal::moduleHandler(),
+      'Module handler instance is still the same.');
+
+    // Install the module_test module.
+    \Drupal::moduleHandler()->install(array('module_test'));
+
+    // Assert that the \Drupal::moduleHandler() instance has been replaced.
+    $this->assertFalse($module_handler === \Drupal::moduleHandler(),
+      'The \Drupal::moduleHandler() instance has been replaced during \Drupal::moduleHandler()->install().');
+
+    // Assert that module_test.module is now included.
+    $this->assertTrue(function_exists('module_test_permission'),
+      'The file module_test.module was successfully included.');
+
+    $this->assertTrue(array_key_exists('module_test', \Drupal::moduleHandler()->getModuleList()),
+      'module_test is in the module list.');
+
+    $this->assertTrue(in_array('module_test', \Drupal::moduleHandler()->getImplementations('permission')),
+      'module_test implements hook_permission().');
+
+    $this->assertTrue(in_array('module_test', \Drupal::moduleHandler()->getImplementations('module_implements_alter')),
+      'module_test implements hook_module_implements_alter().');
+
+    // Assert that module_test.implementations.inc is not included yet.
+    $this->assertFalse(function_exists('module_test_altered_test_hook'),
+      'The file module_test.implementations.inc is not included yet.');
+
+    // Trigger hook discovery for hook_altered_test_hook().
+    // Assert that module_test_module_implements_alter(*, 'altered_test_hook')
+    // has added an implementation.
+    $this->assertTrue(in_array('module_test', \Drupal::moduleHandler()->getImplementations('altered_test_hook')),
+      'module_test implements hook_altered_test_hook().');
+
+    // Assert that module_test.implementations.inc was included as part of the process.
+    $this->assertTrue(function_exists('module_test_altered_test_hook'),
+      'The file module_test.implementations.inc was included.');
+  }
+
+  /**
+   * Tests what happens if hook_module_implements_alter() adds a nonexisting
+   * function to the implementations.
+   *
+   * @see \Drupal\Core\Extension\ModuleHandler::buildImplementationInfo()
+   * @see module_test_module_implements_alter()
+   */
+  function testModuleImplementsAlterNonexistingImplementation() {
+
+    // Install the module_test module.
+    \Drupal::moduleHandler()->install(array('module_test'));
+
+    try {
+      // Trigger hook discovery.
+      \Drupal::moduleHandler()->getImplementations('unimplemented_test_hook');
+    }
+    catch (\Exception $e) {
+      $this->assertEqual(
+        $e->getMessage(),
+        "An invalid implementation 'module_test_unimplemented_test_hook' was added by hook_module_implements_alter()",
+        'An exception was thrown for the nonexisting implementation, and the exception message is as expected.'
+      );
+      return;
+    }
+    $this->fail('An exception should have been thrown for the nonexisting implementation.');
+  }
+
+}
diff --git a/core/modules/system/tests/modules/module_test/module_test.implementations.inc b/core/modules/system/tests/modules/module_test/module_test.implementations.inc
new file mode 100644
index 0000000..63c866e
--- /dev/null
+++ b/core/modules/system/tests/modules/module_test/module_test.implementations.inc
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * Implements hook_altered_test_hook()
+ *
+ * @see module_test_module_implements_alter()
+ */
+function module_test_altered_test_hook() {
+  return __FUNCTION__;
+}
diff --git a/core/modules/system/tests/modules/module_test/module_test.module b/core/modules/system/tests/modules/module_test/module_test.module
index 0968c68..14e1e80 100644
--- a/core/modules/system/tests/modules/module_test/module_test.module
+++ b/core/modules/system/tests/modules/module_test/module_test.module
@@ -140,3 +140,23 @@ function module_test_modules_uninstalled($modules) {
   // can check that the modules were uninstalled in the correct sequence.
   \Drupal::state()->set('module_test.uninstall_order', $modules);
 }
+
+/**
+ * Implements hook_module_implements_alter()
+ *
+ * @see module_test_altered_test_hook()
+ * @see \Drupal\system\Tests\Module\ModuleApiTest::testModuleImplementsAlter()
+ */
+function module_test_module_implements_alter(&$implementations, $hook) {
+  if ($hook === 'altered_test_hook') {
+    // Add a hook implementation, that will be found in
+    // module_test.implementation.inc.
+    $implementations['module_test'] = 'implementations';
+  }
+  if ($hook === 'unimplemented_test_hook') {
+    // Add the nonexisting function module_test_unimplemented_test_hook(). This
+    // should cause an exception to be thrown in
+    // \Drupal\Core\Extension\ModuleHandler::buildImplementationInfo('unimplemented_test_hook').
+    $implementations['module_test'] = FALSE;
+  }
+}
-- 
1.8.5.1

