Version 1
[yaffs-website] / web / core / modules / user / tests / src / Unit / PermissionHandlerTest.php
diff --git a/web/core/modules/user/tests/src/Unit/PermissionHandlerTest.php b/web/core/modules/user/tests/src/Unit/PermissionHandlerTest.php
new file mode 100644 (file)
index 0000000..2918d2f
--- /dev/null
@@ -0,0 +1,463 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\user\Unit\PermissionHandlerTest.
+ */
+
+namespace Drupal\Tests\user\Unit;
+
+use Drupal\Core\Extension\Extension;
+use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\user\PermissionHandler;
+use org\bovigo\vfs\vfsStream;
+use org\bovigo\vfs\vfsStreamDirectory;
+use org\bovigo\vfs\vfsStreamWrapper;
+
+/**
+ * Tests the permission handler.
+ *
+ * @group user
+ *
+ * @coversDefaultClass \Drupal\user\PermissionHandler
+ */
+class PermissionHandlerTest extends UnitTestCase {
+
+  /**
+   * The tested permission handler.
+   *
+   * @var \Drupal\Tests\user\Unit\TestPermissionHandler|\Drupal\user\PermissionHandler
+   */
+  protected $permissionHandler;
+
+  /**
+   * The mocked module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $moduleHandler;
+
+  /**
+   * The mocked string translation.
+   *
+   * @var \Drupal\Tests\user\Unit\TestTranslationManager
+   */
+  protected $stringTranslation;
+
+  /**
+   * The mocked controller resolver.
+   *
+   * @var \Drupal\Core\Controller\ControllerResolverInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $controllerResolver;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->stringTranslation = new TestTranslationManager();
+    $this->controllerResolver = $this->getMock('Drupal\Core\Controller\ControllerResolverInterface');
+  }
+
+  /**
+   * Provides an extension object for a given module with a human name.
+   *
+   * @param string $module
+   *   The module machine name.
+   * @param string $name
+   *   The module human name.
+   *
+   * @return \Drupal\Core\Extension\Extension
+   *   The extension object.
+   */
+  protected function mockModuleExtension($module, $name) {
+    $extension = new Extension($this->root, $module, "modules/$module");
+    $extension->info['name'] = $name;
+    return $extension;
+  }
+
+  /**
+   * Tests permissions provided by YML files.
+   *
+   * @covers ::__construct
+   * @covers ::getPermissions
+   * @covers ::buildPermissionsYaml
+   * @covers ::moduleProvidesPermissions
+   */
+  public function testBuildPermissionsYaml() {
+    vfsStreamWrapper::register();
+    $root = new vfsStreamDirectory('modules');
+    vfsStreamWrapper::setRoot($root);
+
+    $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $this->moduleHandler->expects($this->once())
+      ->method('getModuleDirectories')
+      ->willReturn([
+        'module_a' => vfsStream::url('modules/module_a'),
+        'module_b' => vfsStream::url('modules/module_b'),
+        'module_c' => vfsStream::url('modules/module_c'),
+      ]);
+
+    $url = vfsStream::url('modules');
+    mkdir($url . '/module_a');
+    file_put_contents($url . '/module_a/module_a.permissions.yml', "access_module_a: single_description");
+    mkdir($url . '/module_b');
+    file_put_contents($url . '/module_b/module_b.permissions.yml', <<<EOF
+'access module b':
+  title: 'Access B'
+  description: 'bla bla'
+'access module a via module b':
+  title: 'Access A via B'
+  provider: 'module_a'
+EOF
+    );
+    mkdir($url . '/module_c');
+    file_put_contents($url . '/module_c/module_c.permissions.yml', <<<EOF
+'access_module_c':
+  title: 'Access C'
+  description: 'bla bla'
+  'restrict access': TRUE
+EOF
+    );
+    $modules = ['module_a', 'module_b', 'module_c'];
+    $extensions = [
+      'module_a' => $this->mockModuleExtension('module_a', 'Module a'),
+      'module_b' => $this->mockModuleExtension('module_b', 'Module b'),
+      'module_c' => $this->mockModuleExtension('module_c', 'Module c'),
+    ];
+    $this->moduleHandler->expects($this->any())
+      ->method('getImplementations')
+      ->with('permission')
+      ->willReturn([]);
+
+    $this->moduleHandler->expects($this->any())
+      ->method('getModuleList')
+      ->willReturn(array_flip($modules));
+
+    $this->controllerResolver->expects($this->never())
+      ->method('getControllerFromDefinition');
+
+    $this->permissionHandler = new TestPermissionHandler($this->moduleHandler, $this->stringTranslation, $this->controllerResolver);
+
+    // Setup system_rebuild_module_data().
+    $this->permissionHandler->setSystemRebuildModuleData($extensions);
+
+    $actual_permissions = $this->permissionHandler->getPermissions();
+    $this->assertPermissions($actual_permissions);
+
+    $this->assertTrue($this->permissionHandler->moduleProvidesPermissions('module_a'));
+    $this->assertTrue($this->permissionHandler->moduleProvidesPermissions('module_b'));
+    $this->assertTrue($this->permissionHandler->moduleProvidesPermissions('module_c'));
+    $this->assertFalse($this->permissionHandler->moduleProvidesPermissions('module_d'));
+  }
+
+  /**
+   * Tests permissions sort inside a module.
+   *
+   * @covers ::__construct
+   * @covers ::getPermissions
+   * @covers ::buildPermissionsYaml
+   * @covers ::sortPermissions
+   */
+  public function testBuildPermissionsSortPerModule() {
+    vfsStreamWrapper::register();
+    $root = new vfsStreamDirectory('modules');
+    vfsStreamWrapper::setRoot($root);
+
+    $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $this->moduleHandler->expects($this->once())
+      ->method('getModuleDirectories')
+      ->willReturn([
+        'module_a' => vfsStream::url('modules/module_a'),
+        'module_b' => vfsStream::url('modules/module_b'),
+        'module_c' => vfsStream::url('modules/module_c'),
+      ]);
+    $this->moduleHandler->expects($this->exactly(3))
+      ->method('getName')
+      ->will($this->returnValueMap([
+        ['module_a', 'Module a'],
+        ['module_b', 'Module b'],
+        ['module_c', 'A Module'],
+      ]));
+
+    $url = vfsStream::url('modules');
+    mkdir($url . '/module_a');
+    file_put_contents($url . '/module_a/module_a.permissions.yml', <<<EOF
+access_module_a2: single_description2
+access_module_a1: single_description1
+EOF
+    );
+    mkdir($url . '/module_b');
+    file_put_contents($url . '/module_b/module_b.permissions.yml',
+      "access_module_a3: single_description"
+    );
+    mkdir($url . '/module_c');
+    file_put_contents($url . '/module_c/module_c.permissions.yml',
+      "access_module_a4: single_description"
+    );
+
+    $modules = ['module_a', 'module_b', 'module_c'];
+    $this->moduleHandler->expects($this->once())
+      ->method('getModuleList')
+      ->willReturn(array_flip($modules));
+
+    $permissionHandler = new TestPermissionHandler($this->moduleHandler, $this->stringTranslation, $this->controllerResolver);
+    $actual_permissions = $permissionHandler->getPermissions();
+    $this->assertEquals(['access_module_a4', 'access_module_a1', 'access_module_a2', 'access_module_a3'],
+      array_keys($actual_permissions));
+  }
+
+  /**
+   * Tests dynamic callback permissions provided by YML files.
+   *
+   * @covers ::__construct
+   * @covers ::getPermissions
+   * @covers ::buildPermissionsYaml
+   */
+  public function testBuildPermissionsYamlCallback() {
+    vfsStreamWrapper::register();
+    $root = new vfsStreamDirectory('modules');
+    vfsStreamWrapper::setRoot($root);
+
+    $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $this->moduleHandler->expects($this->once())
+      ->method('getModuleDirectories')
+      ->willReturn([
+        'module_a' => vfsStream::url('modules/module_a'),
+        'module_b' => vfsStream::url('modules/module_b'),
+        'module_c' => vfsStream::url('modules/module_c'),
+      ]);
+
+    $url = vfsStream::url('modules');
+    mkdir($url . '/module_a');
+    file_put_contents($url . '/module_a/module_a.permissions.yml', <<<EOF
+permission_callbacks:
+  - 'Drupal\\user\\Tests\\TestPermissionCallbacks::singleDescription'
+EOF
+    );
+    mkdir($url . '/module_b');
+    file_put_contents($url . '/module_b/module_b.permissions.yml', <<<EOF
+permission_callbacks:
+  - 'Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescription'
+  - 'Drupal\\user\\Tests\\TestPermissionCallbacks::titleProvider'
+EOF
+    );
+    mkdir($url . '/module_c');
+    file_put_contents($url . '/module_c/module_c.permissions.yml', <<<EOF
+permission_callbacks:
+  - 'Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescriptionRestrictAccess'
+EOF
+    );
+
+    $modules = ['module_a', 'module_b', 'module_c'];
+    $extensions = [
+      'module_a' => $this->mockModuleExtension('module_a', 'Module a'),
+      'module_b' => $this->mockModuleExtension('module_b', 'Module b'),
+      'module_c' => $this->mockModuleExtension('module_c', 'Module c'),
+    ];
+
+    $this->moduleHandler->expects($this->any())
+      ->method('getImplementations')
+      ->with('permission')
+      ->willReturn([]);
+
+    $this->moduleHandler->expects($this->any())
+      ->method('getModuleList')
+      ->willReturn(array_flip($modules));
+
+    $this->controllerResolver->expects($this->at(0))
+      ->method('getControllerFromDefinition')
+      ->with('Drupal\\user\\Tests\\TestPermissionCallbacks::singleDescription')
+      ->willReturn([new TestPermissionCallbacks(), 'singleDescription']);
+    $this->controllerResolver->expects($this->at(1))
+      ->method('getControllerFromDefinition')
+      ->with('Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescription')
+      ->willReturn([new TestPermissionCallbacks(), 'titleDescription']);
+    $this->controllerResolver->expects($this->at(2))
+      ->method('getControllerFromDefinition')
+      ->with('Drupal\\user\\Tests\\TestPermissionCallbacks::titleProvider')
+      ->willReturn([new TestPermissionCallbacks(), 'titleProvider']);
+    $this->controllerResolver->expects($this->at(3))
+      ->method('getControllerFromDefinition')
+      ->with('Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescriptionRestrictAccess')
+      ->willReturn([new TestPermissionCallbacks(), 'titleDescriptionRestrictAccess']);
+
+    $this->permissionHandler = new TestPermissionHandler($this->moduleHandler, $this->stringTranslation, $this->controllerResolver);
+
+    // Setup system_rebuild_module_data().
+    $this->permissionHandler->setSystemRebuildModuleData($extensions);
+
+    $actual_permissions = $this->permissionHandler->getPermissions();
+    $this->assertPermissions($actual_permissions);
+  }
+
+  /**
+   * Tests a YAML file containing both static permissions and a callback.
+   */
+  public function testPermissionsYamlStaticAndCallback() {
+    vfsStreamWrapper::register();
+    $root = new vfsStreamDirectory('modules');
+    vfsStreamWrapper::setRoot($root);
+
+    $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $this->moduleHandler->expects($this->once())
+      ->method('getModuleDirectories')
+      ->willReturn([
+        'module_a' => vfsStream::url('modules/module_a'),
+      ]);
+
+    $url = vfsStream::url('modules');
+    mkdir($url . '/module_a');
+    file_put_contents($url . '/module_a/module_a.permissions.yml', <<<EOF
+'access module a':
+  title: 'Access A'
+  description: 'bla bla'
+permission_callbacks:
+  - 'Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescription'
+EOF
+    );
+
+    $modules = ['module_a'];
+    $extensions = [
+      'module_a' => $this->mockModuleExtension('module_a', 'Module a'),
+    ];
+
+    $this->moduleHandler->expects($this->any())
+      ->method('getImplementations')
+      ->with('permission')
+      ->willReturn([]);
+
+    $this->moduleHandler->expects($this->any())
+      ->method('getModuleList')
+      ->willReturn(array_flip($modules));
+
+    $this->controllerResolver->expects($this->once())
+      ->method('getControllerFromDefinition')
+      ->with('Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescription')
+      ->willReturn([new TestPermissionCallbacks(), 'titleDescription']);
+
+    $this->permissionHandler = new TestPermissionHandler($this->moduleHandler, $this->stringTranslation, $this->controllerResolver);
+
+    // Setup system_rebuild_module_data().
+    $this->permissionHandler->setSystemRebuildModuleData($extensions);
+
+    $actual_permissions = $this->permissionHandler->getPermissions();
+
+    $this->assertCount(2, $actual_permissions);
+    $this->assertEquals($actual_permissions['access module a']['title'], 'Access A');
+    $this->assertEquals($actual_permissions['access module a']['provider'], 'module_a');
+    $this->assertEquals($actual_permissions['access module a']['description'], 'bla bla');
+    $this->assertEquals($actual_permissions['access module b']['title'], 'Access B');
+    $this->assertEquals($actual_permissions['access module b']['provider'], 'module_a');
+    $this->assertEquals($actual_permissions['access module b']['description'], 'bla bla');
+  }
+
+  /**
+   * Checks that the permissions are like expected.
+   *
+   * @param array $actual_permissions
+   *   The actual permissions
+   */
+  protected function assertPermissions(array $actual_permissions) {
+    $this->assertCount(4, $actual_permissions);
+    $this->assertEquals($actual_permissions['access_module_a']['title'], 'single_description');
+    $this->assertEquals($actual_permissions['access_module_a']['provider'], 'module_a');
+    $this->assertEquals($actual_permissions['access module b']['title'], 'Access B');
+    $this->assertEquals($actual_permissions['access module b']['provider'], 'module_b');
+    $this->assertEquals($actual_permissions['access_module_c']['title'], 'Access C');
+    $this->assertEquals($actual_permissions['access_module_c']['provider'], 'module_c');
+    $this->assertEquals($actual_permissions['access_module_c']['restrict access'], TRUE);
+    $this->assertEquals($actual_permissions['access module a via module b']['provider'], 'module_a');
+  }
+
+}
+
+class TestPermissionHandler extends PermissionHandler {
+
+  /**
+   * Test module data.
+   *
+   * @var array
+   */
+  protected $systemModuleData;
+
+  protected function systemRebuildModuleData() {
+    return $this->systemModuleData;
+  }
+
+  public function setSystemRebuildModuleData(array $extensions) {
+    $this->systemModuleData = $extensions;
+  }
+
+}
+
+class TestPermissionCallbacks {
+
+  public function singleDescription() {
+    return [
+      'access_module_a' => 'single_description'
+    ];
+  }
+
+  public function titleDescription() {
+    return [
+      'access module b' => [
+        'title' => 'Access B',
+        'description' => 'bla bla',
+      ],
+    ];
+  }
+
+  public function titleDescriptionRestrictAccess() {
+    return [
+      'access_module_c' => [
+        'title' => 'Access C',
+        'description' => 'bla bla',
+        'restrict access' => TRUE,
+      ],
+    ];
+  }
+
+  public function titleProvider() {
+    return [
+      'access module a via module b' => [
+        'title' => 'Access A via B',
+        'provider' => 'module_a',
+      ],
+    ];
+  }
+
+}
+
+/**
+ * Implements a translation manager in tests.
+ */
+class TestTranslationManager implements TranslationInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function translate($string, array $args = [], array $options = []) {
+    return new TranslatableMarkup($string, $args, $options, $this);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function translateString(TranslatableMarkup $translated_string) {
+    return $translated_string->getUntranslatedString();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function formatPlural($count, $singular, $plural, array $args = [], array $options = []) {
+    return new PluralTranslatableMarkup($count, $singular, $plural, $args, $options, $this);
+  }
+
+}