class ModuleHandlerTest
Same name in this branch
- 10 core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php \Drupal\Tests\system\Kernel\Extension\ModuleHandlerTest
- 10 core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerTest.php \Drupal\KernelTests\Core\Extension\ModuleHandlerTest
Same name in other branches
- 9 core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php \Drupal\Tests\system\Kernel\Extension\ModuleHandlerTest
- 9 core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerTest.php \Drupal\KernelTests\Core\Extension\ModuleHandlerTest
- 9 core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php \Drupal\Tests\Core\Extension\ModuleHandlerTest
- 8.9.x core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php \Drupal\Tests\system\Kernel\Extension\ModuleHandlerTest
- 8.9.x core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerTest.php \Drupal\KernelTests\Core\Extension\ModuleHandlerTest
- 8.9.x core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php \Drupal\Tests\Core\Extension\ModuleHandlerTest
- 11.x core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php \Drupal\Tests\system\Kernel\Extension\ModuleHandlerTest
- 11.x core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerTest.php \Drupal\KernelTests\Core\Extension\ModuleHandlerTest
- 11.x core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php \Drupal\Tests\Core\Extension\ModuleHandlerTest
@coversDefaultClass \Drupal\Core\Extension\ModuleHandler @runTestsInSeparateProcesses
@group Extension
Hierarchy
- class \Drupal\Tests\UnitTestCase extends \PHPUnit\Framework\TestCase uses \Drupal\Tests\Traits\PhpUnitWarnings, \Drupal\Tests\PhpUnitCompatibilityTrait, \Prophecy\PhpUnit\ProphecyTrait, \Symfony\Bridge\PhpUnit\ExpectDeprecationTrait, \Drupal\Tests\RandomGeneratorTrait
- class \Drupal\Tests\Core\Extension\ModuleHandlerTest extends \Drupal\Tests\UnitTestCase
Expanded class hierarchy of ModuleHandlerTest
File
-
core/
tests/ Drupal/ Tests/ Core/ Extension/ ModuleHandlerTest.php, line 19
Namespace
Drupal\Tests\Core\ExtensionView source
class ModuleHandlerTest extends UnitTestCase {
/**
* The mocked cache backend.
*
* @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $cacheBackend;
/**
* {@inheritdoc}
*
* @covers ::__construct
*/
protected function setUp() : void {
parent::setUp();
// We can mock the cache handler here, but not the module handler.
$this->cacheBackend = $this->createMock(CacheBackendInterface::class);
}
/**
* Get a module handler object to test.
*
* Since we have to run these tests in separate processes, we have to use
* test objects which are serializable. Since ModuleHandler will populate
* itself with Extension objects, and since Extension objects will try to
* access DRUPAL_ROOT when they're unserialized, we can't store our mocked
* ModuleHandler objects as a property in unit tests. They must be generated
* by the test method by calling this method.
*
* @return \Drupal\Core\Extension\ModuleHandler
* The module handler to test.
*/
protected function getModuleHandler() {
$module_handler = new ModuleHandler($this->root, [
'module_handler_test' => [
'type' => 'module',
'pathname' => 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml',
'filename' => 'module_handler_test.module',
],
], $this->cacheBackend);
return $module_handler;
}
/**
* Tests loading a module.
*
* @covers ::load
*/
public function testLoadModule() : void {
$module_handler = $this->getModuleHandler();
$this->assertFalse(function_exists('module_handler_test_hook'));
$this->assertTrue($module_handler->load('module_handler_test'));
$this->assertTrue(function_exists('module_handler_test_hook'));
$module_handler->addModule('module_handler_test_added', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test_added');
$this->assertFalse(function_exists('module_handler_test_added_hook'), 'Function does not exist before being loaded.');
$this->assertTrue($module_handler->load('module_handler_test_added'));
$this->assertTrue(function_exists('module_handler_test_added_helper'), 'Function exists after being loaded.');
$this->assertTrue($module_handler->load('module_handler_test_added'));
$this->assertFalse($module_handler->load('module_handler_test_dne'), 'Non-existent modules returns false.');
}
/**
* Tests loading all modules.
*
* @covers ::loadAll
*/
public function testLoadAllModules() : void {
$module_handler = $this->getModuleHandler();
$module_handler->addModule('module_handler_test_all1', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test_all1');
$module_handler->addModule('module_handler_test_all2', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test_all2');
$this->assertFalse(function_exists('module_handler_test_all1_hook'), 'Function does not exist before being loaded.');
$this->assertFalse(function_exists('module_handler_test_all2_hook'), 'Function does not exist before being loaded.');
$module_handler->loadAll();
$this->assertTrue(function_exists('module_handler_test_all1_hook'), 'Function exists after being loaded.');
$this->assertTrue(function_exists('module_handler_test_all2_hook'), 'Function exists after being loaded.');
}
/**
* Tests reload method.
*
* @covers ::reload
*/
public function testModuleReloading() : void {
$module_handler = $this->getMockBuilder(ModuleHandler::class)
->setConstructorArgs([
$this->root,
[
'module_handler_test' => [
'type' => 'module',
'pathname' => 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml',
'filename' => 'module_handler_test.module',
],
],
$this->cacheBackend,
])
->onlyMethods([
'load',
])
->getMock();
$calls = [
// First reload.
'module_handler_test',
// Second reload.
'module_handler_test',
'module_handler_test_added',
];
$module_handler->expects($this->exactly(count($calls)))
->method('load')
->with($this->callback(function (string $module) use (&$calls) : bool {
return $module === array_shift($calls);
}));
$module_handler->reload();
$module_handler->addModule('module_handler_test_added', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test_added');
$module_handler->reload();
}
/**
* Tests isLoaded accessor.
*
* @covers ::isLoaded
*/
public function testIsLoaded() : void {
$module_handler = $this->getModuleHandler();
$this->assertFalse($module_handler->isLoaded());
$module_handler->loadAll();
$this->assertTrue($module_handler->isLoaded());
}
/**
* Confirm we get back the modules set in the constructor.
*
* @covers ::getModuleList
*/
public function testGetModuleList() : void {
$this->assertEquals($this->getModuleHandler()
->getModuleList(), [
'module_handler_test' => new Extension($this->root, 'module', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml', 'module_handler_test.module'),
]);
}
/**
* Confirm we get back a module from the module list.
*
* @covers ::getModule
*/
public function testGetModuleWithExistingModule() : void {
$this->assertEquals($this->getModuleHandler()
->getModule('module_handler_test'), new Extension($this->root, 'module', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml', 'module_handler_test.module'));
}
/**
* @covers ::getModule
*/
public function testGetModuleWithNonExistingModule() : void {
$this->expectException(UnknownExtensionException::class);
$this->getModuleHandler()
->getModule('claire_alice_watch_my_little_pony_module_that_does_not_exist');
}
/**
* Ensure setting the module list replaces the module list and resets internal structures.
*
* @covers ::setModuleList
*/
public function testSetModuleList() : void {
$fixture_module_handler = $this->getModuleHandler();
$module_handler = $this->getMockBuilder(ModuleHandler::class)
->setConstructorArgs([
$this->root,
[],
$this->cacheBackend,
])
->onlyMethods([
'resetImplementations',
])
->getMock();
// Ensure we reset implementations when settings a new modules list.
$module_handler->expects($this->once())
->method('resetImplementations');
// Make sure we're starting empty.
$this->assertEquals([], $module_handler->getModuleList());
// Replace the list with a prebuilt list.
$module_handler->setModuleList($fixture_module_handler->getModuleList());
// Ensure those changes are stored.
$this->assertEquals($fixture_module_handler->getModuleList(), $module_handler->getModuleList());
}
/**
* Tests adding a module.
*
* @covers ::addModule
* @covers ::add
*/
public function testAddModule() : void {
$module_handler = $this->getMockBuilder(ModuleHandler::class)
->setConstructorArgs([
$this->root,
[],
$this->cacheBackend,
])
->onlyMethods([
'resetImplementations',
])
->getMock();
// Ensure we reset implementations when settings a new modules list.
$module_handler->expects($this->once())
->method('resetImplementations');
$module_handler->addModule('module_handler_test', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test');
$this->assertTrue($module_handler->moduleExists('module_handler_test'));
}
/**
* Tests adding a profile.
*
* @covers ::addProfile
* @covers ::add
*/
public function testAddProfile() : void {
$module_handler = $this->getMockBuilder(ModuleHandler::class)
->setConstructorArgs([
$this->root,
[],
$this->cacheBackend,
])
->onlyMethods([
'resetImplementations',
])
->getMock();
// Ensure we reset implementations when settings a new modules list.
$module_handler->expects($this->once())
->method('resetImplementations');
// @todo this should probably fail since its a module not a profile.
$module_handler->addProfile('module_handler_test', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test');
$this->assertTrue($module_handler->moduleExists('module_handler_test'));
}
/**
* Tests module exists returns correct module status.
*
* @covers ::moduleExists
*/
public function testModuleExists() : void {
$module_handler = $this->getModuleHandler();
$this->assertTrue($module_handler->moduleExists('module_handler_test'));
$this->assertFalse($module_handler->moduleExists('module_handler_test_added'));
}
/**
* @covers ::loadAllIncludes
*/
public function testLoadAllIncludes() : void {
$this->assertTrue(TRUE);
$module_handler = $this->getMockBuilder(ModuleHandler::class)
->setConstructorArgs([
$this->root,
[
'module_handler_test' => [
'type' => 'module',
'pathname' => 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml',
'filename' => 'module_handler_test.module',
],
],
$this->cacheBackend,
])
->onlyMethods([
'loadInclude',
])
->getMock();
// Ensure we reset implementations when settings a new modules list.
$module_handler->expects($this->once())
->method('loadInclude');
$module_handler->loadAllIncludes('hook');
}
/**
* @covers ::loadInclude
*
* Note we load code, so isolate the test.
*
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testLoadInclude() : void {
$module_handler = $this->getModuleHandler();
// Include exists.
$this->assertEquals(__DIR__ . '/modules/module_handler_test/hook_include.inc', $module_handler->loadInclude('module_handler_test', 'inc', 'hook_include'));
$this->assertTrue(function_exists('module_handler_test_hook_include'));
// Include doesn't exist.
$this->assertFalse($module_handler->loadInclude('module_handler_test', 'install'));
}
/**
* Tests invoke methods when module is enabled.
*
* @covers ::invoke
*/
public function testInvokeModuleEnabled() : void {
$module_handler = $this->getModuleHandler();
$this->assertTrue($module_handler->invoke('module_handler_test', 'hook', [
TRUE,
]), 'Installed module runs hook.');
$this->assertFalse($module_handler->invoke('module_handler_test', 'hook', [
FALSE,
]), 'Installed module runs hook.');
$this->assertNull($module_handler->invoke('module_handler_test_fake', 'hook', [
FALSE,
]), 'Installed module runs hook.');
}
/**
* Tests implementations methods when module is enabled.
*
* @covers ::hasImplementations
* @covers ::loadAllIncludes
*/
public function testImplementsHookModuleEnabled() : void {
$module_handler = $this->getModuleHandler();
$this->assertTrue($module_handler->hasImplementations('hook', 'module_handler_test'), 'Installed module implementation found.');
$module_handler->addModule('module_handler_test_added', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test_added');
$this->assertTrue($module_handler->hasImplementations('hook', 'module_handler_test_added'), 'Runtime added module with implementation in include found.');
$module_handler->addModule('module_handler_test_no_hook', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test_no_hook');
$this->assertFalse($module_handler->hasImplementations('hook', 'module_handler_test_no_hook'), 'Missing implementation not found.');
}
/**
* Tests hasImplementations.
*
* @covers ::hasImplementations
*/
public function testHasImplementations() : void {
$module_handler = $this->getMockBuilder(ModuleHandler::class)
->setConstructorArgs([
$this->root,
[],
$this->cacheBackend,
])
->onlyMethods([
'buildImplementationInfo',
])
->getMock();
$module_handler->expects($this->exactly(2))
->method('buildImplementationInfo')
->with('hook')
->willReturnOnConsecutiveCalls([], [
'my_module' => FALSE,
]);
// ModuleHandler::buildImplementationInfo mock returns no implementations.
$this->assertFalse($module_handler->hasImplementations('hook'));
// Reset static caches.
$module_handler->resetImplementations();
// ModuleHandler::buildImplementationInfo mock returns an implementation.
$this->assertTrue($module_handler->hasImplementations('hook'));
}
/**
* Tests getImplementations.
*
* @covers ::invokeAllWith
*/
public function testCachedGetImplementations() : void {
$this->cacheBackend
->expects($this->exactly(1))
->method('get')
->willReturn((object) [
'data' => [
'hook' => [
'module_handler_test' => 'test',
],
],
]);
// Ensure buildImplementationInfo doesn't get called and that we work off cached results.
$module_handler = $this->getMockBuilder(ModuleHandler::class)
->setConstructorArgs([
$this->root,
[
'module_handler_test' => [
'type' => 'module',
'pathname' => 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml',
'filename' => 'module_handler_test.module',
],
],
$this->cacheBackend,
])
->onlyMethods([
'buildImplementationInfo',
'loadInclude',
])
->getMock();
$module_handler->load('module_handler_test');
$module_handler->expects($this->never())
->method('buildImplementationInfo');
$module_handler->expects($this->once())
->method('loadInclude');
$implementors = [];
$module_handler->invokeAllWith('hook', function (callable $hook, string $module) use (&$implementors) {
$implementors[] = $module;
});
$this->assertEquals([
'module_handler_test',
], $implementors);
}
/**
* Tests getImplementations.
*
* @covers ::invokeAllWith
*/
public function testCachedGetImplementationsMissingMethod() : void {
$this->cacheBackend
->expects($this->exactly(1))
->method('get')
->willReturn((object) [
'data' => [
'hook' => [
'module_handler_test' => [],
'module_handler_test_missing' => [],
],
],
]);
// Ensure buildImplementationInfo doesn't get called and that we work off cached results.
$module_handler = $this->getMockBuilder(ModuleHandler::class)
->setConstructorArgs([
$this->root,
[
'module_handler_test' => [
'type' => 'module',
'pathname' => 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test/module_handler_test.info.yml',
'filename' => 'module_handler_test.module',
],
],
$this->cacheBackend,
])
->onlyMethods([
'buildImplementationInfo',
])
->getMock();
$module_handler->load('module_handler_test');
$module_handler->expects($this->never())
->method('buildImplementationInfo');
$implementors = [];
$module_handler->invokeAllWith('hook', function (callable $hook, string $module) use (&$implementors) {
$implementors[] = $module;
});
$this->assertEquals([
'module_handler_test',
], $implementors);
}
/**
* Tests invoke all.
*
* @covers ::invokeAll
*/
public function testInvokeAll() : void {
$module_handler = $this->getModuleHandler();
$module_handler->addModule('module_handler_test_all1', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test_all1');
$module_handler->addModule('module_handler_test_all2', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test_all2');
$this->assertEquals([
TRUE,
TRUE,
TRUE,
], $module_handler->invokeAll('hook', [
TRUE,
]));
}
/**
* Tests that write cache calls through to cache library correctly.
*
* @covers ::writeCache
*/
public function testWriteCache() : void {
$module_handler = $this->getModuleHandler();
$this->cacheBackend
->expects($this->exactly(2))
->method('get')
->willReturn(NULL);
$this->cacheBackend
->expects($this->exactly(2))
->method('set')
->with($this->logicalOr('module_implements', 'hook_info'));
$module_handler->invokeAllWith('hook', function (callable $hook, string $module) {
});
$module_handler->writeCache();
}
/**
* Tests hook_hook_info() fetching through getHookInfo().
*
* @covers ::getHookInfo
* @covers ::buildHookInfo
*/
public function testGetHookInfo() : void {
$module_handler = $this->getModuleHandler();
// Set up some synthetic results.
$this->cacheBackend
->expects($this->exactly(2))
->method('get')
->willReturn(NULL, (object) [
'data' => [
'hook_foo' => [
'group' => 'hook',
],
],
]);
// Results from building from mocked environment.
$this->assertEquals([
'hook' => [
'group' => 'hook',
],
], $module_handler->getHookInfo());
// Reset local cache so we get our synthetic result from the cache handler.
$module_handler->resetImplementations();
$this->assertEquals([
'hook_foo' => [
'group' => 'hook',
],
], $module_handler->getHookInfo());
}
/**
* Tests internal implementation cache reset.
*
* @covers ::resetImplementations
*/
public function testResetImplementations() : void {
$module_handler = $this->getModuleHandler();
// Prime caches
$module_handler->invokeAllWith('hook', function (callable $hook, string $module) {
});
$module_handler->getHookInfo();
// Reset all caches internal and external.
$this->cacheBackend
->expects($this->once())
->method('delete')
->with('hook_info');
$this->cacheBackend
->expects($this->exactly(2))
->method('set')
->with($this->logicalOr('module_implements', 'hook_info'));
$module_handler->resetImplementations();
// Request implementation and ensure hook_info and module_implements skip
// local caches.
$this->cacheBackend
->expects($this->exactly(2))
->method('get')
->with($this->logicalOr('module_implements', 'hook_info'));
$module_handler->invokeAllWith('hook', function (callable $hook, string $module) {
});
}
/**
* @covers ::getModuleDirectories
*/
public function testGetModuleDirectories() : void {
$module_handler = $this->getModuleHandler();
$module_handler->setModuleList([]);
$module_handler->addModule('node', 'core/modules/node');
$this->assertEquals([
'node' => $this->root . '/core/modules/node',
], $module_handler->getModuleDirectories());
}
}
Members
Title Sort descending | Deprecated | Modifiers | Object type | Summary | Overriden Title | Overrides |
---|---|---|---|---|---|---|
ModuleHandlerTest::$cacheBackend | protected | property | The mocked cache backend. | |||
ModuleHandlerTest::getModuleHandler | protected | function | Get a module handler object to test. | |||
ModuleHandlerTest::setUp | protected | function | @covers ::__construct | Overrides UnitTestCase::setUp | ||
ModuleHandlerTest::testAddModule | public | function | Tests adding a module. | |||
ModuleHandlerTest::testAddProfile | public | function | Tests adding a profile. | |||
ModuleHandlerTest::testCachedGetImplementations | public | function | Tests getImplementations. | |||
ModuleHandlerTest::testCachedGetImplementationsMissingMethod | public | function | Tests getImplementations. | |||
ModuleHandlerTest::testGetHookInfo | public | function | Tests hook_hook_info() fetching through getHookInfo(). | |||
ModuleHandlerTest::testGetModuleDirectories | public | function | @covers ::getModuleDirectories | |||
ModuleHandlerTest::testGetModuleList | public | function | Confirm we get back the modules set in the constructor. | |||
ModuleHandlerTest::testGetModuleWithExistingModule | public | function | Confirm we get back a module from the module list. | |||
ModuleHandlerTest::testGetModuleWithNonExistingModule | public | function | @covers ::getModule | |||
ModuleHandlerTest::testHasImplementations | public | function | Tests hasImplementations. | |||
ModuleHandlerTest::testImplementsHookModuleEnabled | public | function | Tests implementations methods when module is enabled. | |||
ModuleHandlerTest::testInvokeAll | public | function | Tests invoke all. | |||
ModuleHandlerTest::testInvokeModuleEnabled | public | function | Tests invoke methods when module is enabled. | |||
ModuleHandlerTest::testIsLoaded | public | function | Tests isLoaded accessor. | |||
ModuleHandlerTest::testLoadAllIncludes | public | function | @covers ::loadAllIncludes | |||
ModuleHandlerTest::testLoadAllModules | public | function | Tests loading all modules. | |||
ModuleHandlerTest::testLoadInclude | public | function | @covers ::loadInclude | |||
ModuleHandlerTest::testLoadModule | public | function | Tests loading a module. | |||
ModuleHandlerTest::testModuleExists | public | function | Tests module exists returns correct module status. | |||
ModuleHandlerTest::testModuleReloading | public | function | Tests reload method. | |||
ModuleHandlerTest::testResetImplementations | public | function | Tests internal implementation cache reset. | |||
ModuleHandlerTest::testSetModuleList | public | function | Ensure setting the module list replaces the module list and resets internal structures. | |||
ModuleHandlerTest::testWriteCache | public | function | Tests that write cache calls through to cache library correctly. | |||
PhpUnitWarnings::$deprecationWarnings | private static | property | Deprecation warnings from PHPUnit to raise with @trigger_error(). | |||
PhpUnitWarnings::addWarning | public | function | Converts PHPUnit deprecation warnings to E_USER_DEPRECATED. | |||
RandomGeneratorTrait::getRandomGenerator | protected | function | Gets the random generator for the utility methods. | |||
RandomGeneratorTrait::randomMachineName | protected | function | Generates a unique random string containing letters and numbers. | |||
RandomGeneratorTrait::randomObject | public | function | Generates a random PHP object. | |||
RandomGeneratorTrait::randomString | public | function | Generates a pseudo-random string of ASCII characters of codes 32 to 126. | |||
RandomGeneratorTrait::randomStringValidate | Deprecated | public | function | Callback for random string validation. | ||
UnitTestCase::$root | protected | property | The app root. | 1 | ||
UnitTestCase::getClassResolverStub | protected | function | Returns a stub class resolver. | |||
UnitTestCase::getConfigFactoryStub | public | function | Returns a stub config factory that behaves according to the passed array. | |||
UnitTestCase::getConfigStorageStub | public | function | Returns a stub config storage that returns the supplied configuration. | |||
UnitTestCase::getContainerWithCacheTagsInvalidator | protected | function | Sets up a container with a cache tags invalidator. | |||
UnitTestCase::getStringTranslationStub | public | function | Returns a stub translation manager that just returns the passed string. | |||
UnitTestCase::setUpBeforeClass | public static | function | ||||
UnitTestCase::__get | public | function |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.