Move into nested docroot

This commit is contained in:
Rob Davies 2017-02-13 15:31:17 +00:00
parent 83a0d3a149
commit c8b70abde9
13405 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,83 @@
<?php
namespace Drupal\Tests\system\Functional;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
use GuzzleHttp\Cookie\CookieJar;
/**
* Tests protecting routes by requiring CSRF token in the request header.
*
* @group system
*/
class CsrfRequestHeaderTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['system', 'csrf_test'];
/**
* Tests access to routes protected by CSRF request header requirements.
*
* This checks one route that uses _csrf_request_header_token and one that
* uses the deprecated _access_rest_csrf.
*/
public function testRouteAccess() {
$client = \Drupal::httpClient();
$csrf_token_paths = ['deprecated/session/token', 'session/token'];
// Test using the both the current path and a test path that returns
// a token using the deprecated 'rest' value.
// Checking /deprecated/session/token can be removed in 8.3.
// @see \Drupal\Core\Access\CsrfRequestHeaderAccessCheck::access()
foreach ($csrf_token_paths as $csrf_token_path) {
// Check both test routes.
$route_names = ['csrf_test.protected', 'csrf_test.deprecated.protected'];
foreach ($route_names as $route_name) {
$user = $this->drupalCreateUser();
$this->drupalLogin($user);
$csrf_token = $this->drupalGet($csrf_token_path);
$url = Url::fromRoute($route_name)
->setAbsolute(TRUE)
->toString();
$domain = parse_url($url, PHP_URL_HOST);
$session_id = $this->getSession()->getCookie($this->getSessionName());
/** @var \GuzzleHttp\Cookie\CookieJar $cookies */
$cookies = CookieJar::fromArray([$this->getSessionName() => $session_id], $domain);
$post_options = [
'headers' => ['Accept' => 'text/plain'],
'http_errors' => FALSE,
];
// Test that access is allowed for anonymous user with no token in header.
$result = $client->post($url, $post_options);
$this->assertEquals(200, $result->getStatusCode());
// Add cookies to POST options so that all other requests are for the
// authenticated user.
$post_options['cookies'] = $cookies;
// Test that access is denied with no token in header.
$result = $client->post($url, $post_options);
$this->assertEquals(403, $result->getStatusCode());
// Test that access is allowed with correct token in header.
$post_options['headers']['X-CSRF-Token'] = $csrf_token;
$result = $client->post($url, $post_options);
$this->assertEquals(200, $result->getStatusCode());
// Test that access is denied with incorrect token in header.
$post_options['headers']['X-CSRF-Token'] = 'this-is-not-the-token-you-are-looking-for';
$result = $client->post($url, $post_options);
$this->assertEquals(403, $result->getStatusCode());
}
}
}
}

View file

@ -0,0 +1,58 @@
<?php
namespace Drupal\Tests\system\Functional\Render;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
/**
* Functional test verifying that messages set in placeholders always appear.
*
* @group Render
*/
class PlaceholderMessageTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['render_placeholder_message_test'];
/**
* Test rendering of message placeholder.
*/
public function testMessagePlaceholder() {
$messages_markup = '<div role="contentinfo" aria-label="Status message"';
$test_routes = [
// Messages placeholder rendered first.
'render_placeholder_message_test.first',
// Messages placeholder rendered after one, before another.
'render_placeholder_message_test.middle',
// Messages placeholder rendered last.
'render_placeholder_message_test.last',
];
$assert = $this->assertSession();
foreach ($test_routes as $route) {
// Verify that we start off with zero messages queued.
$this->drupalGet(Url::fromRoute('render_placeholder_message_test.queued'));
$assert->responseNotContains($messages_markup);
// Verify the test case at this route behaves as expected.
$this->drupalGet(Url::fromRoute($route));
$assert->elementContains('css', 'p.logged-message:nth-of-type(1)', 'Message: P1');
$assert->elementContains('css', 'p.logged-message:nth-of-type(2)', 'Message: P2');
$assert->responseContains($messages_markup);
$assert->elementExists('css', 'div[aria-label="Status message"] ul');
$assert->elementContains('css', 'div[aria-label="Status message"] ul li:nth-of-type(1)', 'P1');
$assert->elementContains('css', 'div[aria-label="Status message"] ul li:nth-of-type(2)', 'P2');
// Verify that we end with all messages printed, hence again zero queued.
$this->drupalGet(Url::fromRoute('render_placeholder_message_test.queued'));
$assert->responseNotContains($messages_markup);
}
}
}

View file

@ -0,0 +1,101 @@
<?php
namespace Drupal\Tests\system\Kernel\Action;
use Drupal\Core\Action\ActionInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\system\Entity\Action;
use Drupal\user\RoleInterface;
/**
* Tests action plugins.
*
* @group Action
*/
class ActionTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = array('system', 'field', 'user', 'action_test');
/**
* The action manager.
*
* @var \Drupal\Core\Action\ActionManager
*/
protected $actionManager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->actionManager = $this->container->get('plugin.manager.action');
$this->installEntitySchema('user');
$this->installSchema('system', array('sequences'));
}
/**
* Tests the functionality of test actions.
*/
public function testOperations() {
// Test that actions can be discovered.
$definitions = $this->actionManager->getDefinitions();
$this->assertTrue(count($definitions) > 1, 'Action definitions are found.');
$this->assertTrue(!empty($definitions['action_test_no_type']), 'The test action is among the definitions found.');
$definition = $this->actionManager->getDefinition('action_test_no_type');
$this->assertTrue(!empty($definition), 'The test action definition is found.');
$definitions = $this->actionManager->getDefinitionsByType('user');
$this->assertTrue(empty($definitions['action_test_no_type']), 'An action with no type is not found.');
// Create an instance of the 'save entity' action.
$action = $this->actionManager->createInstance('action_test_save_entity');
$this->assertTrue($action instanceof ActionInterface, 'The action implements the correct interface.');
// Create a new unsaved user.
$name = $this->randomMachineName();
$user_storage = $this->container->get('entity.manager')->getStorage('user');
$account = $user_storage->create(array('name' => $name, 'bundle' => 'user'));
$loaded_accounts = $user_storage->loadMultiple();
$this->assertEqual(count($loaded_accounts), 0);
// Execute the 'save entity' action.
$action->execute($account);
$loaded_accounts = $user_storage->loadMultiple();
$this->assertEqual(count($loaded_accounts), 1);
$account = reset($loaded_accounts);
$this->assertEqual($name, $account->label());
}
/**
* Tests the dependency calculation of actions.
*/
public function testDependencies() {
// Create a new action that depends on a user role.
$action = Action::create(array(
'id' => 'user_add_role_action.' . RoleInterface::ANONYMOUS_ID,
'type' => 'user',
'label' => t('Add the anonymous role to the selected users'),
'configuration' => array(
'rid' => RoleInterface::ANONYMOUS_ID,
),
'plugin' => 'user_add_role_action',
));
$action->save();
$expected = array(
'config' => array(
'user.role.' . RoleInterface::ANONYMOUS_ID,
),
'module' => array(
'user',
),
);
$this->assertIdentical($expected, $action->calculateDependencies()->getDependencies());
}
}

View file

@ -0,0 +1,311 @@
<?php
namespace Drupal\Tests\system\Kernel\Block;
use Drupal\KernelTests\KernelTestBase;
use Drupal\system\Entity\Menu;
use Drupal\block\Entity\Block;
use Drupal\Core\Render\Element;
use Drupal\system\Tests\Routing\MockRouteProvider;
use Drupal\Tests\Core\Menu\MenuLinkMock;
use Drupal\user\Entity\User;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* Tests \Drupal\system\Plugin\Block\SystemMenuBlock.
*
* @group Block
* @todo Expand test coverage to all SystemMenuBlock functionality, including
* block_menu_delete().
*
* @see \Drupal\system\Plugin\Derivative\SystemMenuBlock
* @see \Drupal\system\Plugin\Block\SystemMenuBlock
*/
class SystemMenuBlockTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array(
'system',
'block',
'menu_test',
'menu_link_content',
'field',
'user',
'link',
);
/**
* The block under test.
*
* @var \Drupal\system\Plugin\Block\SystemMenuBlock
*/
protected $block;
/**
* The menu for testing.
*
* @var \Drupal\system\MenuInterface
*/
protected $menu;
/**
* The menu link tree service.
*
* @var \Drupal\Core\Menu\MenuLinkTree
*/
protected $linkTree;
/**
* The menu link plugin manager service.
*
* @var \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager
*/
protected $menuLinkManager;
/**
* The block manager service.
*
* @var \Drupal\Core\block\BlockManagerInterface
*/
protected $blockManager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', 'sequences');
$this->installEntitySchema('user');
$this->installEntitySchema('menu_link_content');
$account = User::create([
'name' => $this->randomMachineName(),
'status' => 1,
]);
$account->save();
$this->container->get('current_user')->setAccount($account);
$this->menuLinkManager = $this->container->get('plugin.manager.menu.link');
$this->linkTree = $this->container->get('menu.link_tree');
$this->blockManager = $this->container->get('plugin.manager.block');
$routes = new RouteCollection();
$requirements = array('_access' => 'TRUE');
$options = array('_access_checks' => array('access_check.default'));
$routes->add('example1', new Route('/example1', array(), $requirements, $options));
$routes->add('example2', new Route('/example2', array(), $requirements, $options));
$routes->add('example3', new Route('/example3', array(), $requirements, $options));
$routes->add('example4', new Route('/example4', array(), $requirements, $options));
$routes->add('example5', new Route('/example5', array(), $requirements, $options));
$routes->add('example6', new Route('/example6', array(), $requirements, $options));
$routes->add('example7', new Route('/example7', array(), $requirements, $options));
$routes->add('example8', new Route('/example8', array(), $requirements, $options));
$mock_route_provider = new MockRouteProvider($routes);
$this->container->set('router.route_provider', $mock_route_provider);
// Add a new custom menu.
$menu_name = 'mock';
$label = $this->randomMachineName(16);
$this->menu = Menu::create(array(
'id' => $menu_name,
'label' => $label,
'description' => 'Description text',
));
$this->menu->save();
// This creates a tree with the following structure:
// - 1
// - 2
// - 3
// - 4
// - 5
// - 7
// - 6
// - 8
// With link 6 being the only external link.
$links = array(
1 => MenuLinkMock::create(array('id' => 'test.example1', 'route_name' => 'example1', 'title' => 'foo', 'parent' => '', 'weight' => 0)),
2 => MenuLinkMock::create(array('id' => 'test.example2', 'route_name' => 'example2', 'title' => 'bar', 'parent' => '', 'route_parameters' => array('foo' => 'bar'), 'weight' => 1)),
3 => MenuLinkMock::create(array('id' => 'test.example3', 'route_name' => 'example3', 'title' => 'baz', 'parent' => 'test.example2', 'weight' => 2)),
4 => MenuLinkMock::create(array('id' => 'test.example4', 'route_name' => 'example4', 'title' => 'qux', 'parent' => 'test.example3', 'weight' => 3)),
5 => MenuLinkMock::create(array('id' => 'test.example5', 'route_name' => 'example5', 'title' => 'foofoo', 'parent' => '', 'expanded' => TRUE, 'weight' => 4)),
6 => MenuLinkMock::create(array('id' => 'test.example6', 'route_name' => '', 'url' => 'https://www.drupal.org/', 'title' => 'barbar', 'parent' => '', 'weight' => 5)),
7 => MenuLinkMock::create(array('id' => 'test.example7', 'route_name' => 'example7', 'title' => 'bazbaz', 'parent' => 'test.example5', 'weight' => 6)),
8 => MenuLinkMock::create(array('id' => 'test.example8', 'route_name' => 'example8', 'title' => 'quxqux', 'parent' => '', 'weight' => 7)),
);
foreach ($links as $instance) {
$this->menuLinkManager->addDefinition($instance->getPluginId(), $instance->getPluginDefinition());
}
}
/**
* Tests calculation of a system menu block's configuration dependencies.
*/
public function testSystemMenuBlockConfigDependencies() {
$block = Block::create(array(
'plugin' => 'system_menu_block:' . $this->menu->id(),
'region' => 'footer',
'id' => 'machinename',
'theme' => 'stark',
));
$dependencies = $block->calculateDependencies()->getDependencies();
$expected = array(
'config' => array(
'system.menu.' . $this->menu->id()
),
'module' => array(
'system'
),
'theme' => array(
'stark'
),
);
$this->assertIdentical($expected, $dependencies);
}
/**
* Tests the config start level and depth.
*/
public function testConfigLevelDepth() {
// Helper function to generate a configured block instance.
$place_block = function ($level, $depth) {
return $this->blockManager->createInstance('system_menu_block:' . $this->menu->id(), array(
'region' => 'footer',
'id' => 'machinename',
'theme' => 'stark',
'level' => $level,
'depth' => $depth,
));
};
// All the different block instances we're going to test.
$blocks = [
'all' => $place_block(1, 0),
'level_1_only' => $place_block(1, 1),
'level_2_only' => $place_block(2, 1),
'level_3_only' => $place_block(3, 1),
'level_1_and_beyond' => $place_block(1, 0),
'level_2_and_beyond' => $place_block(2, 0),
'level_3_and_beyond' => $place_block(3, 0),
];
// Scenario 1: test all block instances when there's no active trail.
$no_active_trail_expectations = [];
$no_active_trail_expectations['all'] = [
'test.example1' => [],
'test.example2' => [],
'test.example5' => [
'test.example7' => [],
],
'test.example6' => [],
'test.example8' => [],
];
$no_active_trail_expectations['level_1_only'] = [
'test.example1' => [],
'test.example2' => [],
'test.example5' => [],
'test.example6' => [],
'test.example8' => [],
];
$no_active_trail_expectations['level_2_only'] = [
'test.example7' => [],
];
$no_active_trail_expectations['level_3_only'] = [];
$no_active_trail_expectations['level_1_and_beyond'] = $no_active_trail_expectations['all'];
$no_active_trail_expectations['level_2_and_beyond'] = $no_active_trail_expectations['level_2_only'];
$no_active_trail_expectations['level_3_and_beyond'] = [];
foreach ($blocks as $id => $block) {
$block_build = $block->build();
$items = isset($block_build['#items']) ? $block_build['#items'] : [];
$this->assertIdentical($no_active_trail_expectations[$id], $this->convertBuiltMenuToIdTree($items), format_string('Menu block %id with no active trail renders the expected tree.', ['%id' => $id]));
}
// Scenario 2: test all block instances when there's an active trail.
$route = $this->container->get('router.route_provider')->getRouteByName('example3');
$request = new Request();
$request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'example3');
$request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, $route);
$this->container->get('request_stack')->push($request);
// \Drupal\Core\Menu\MenuActiveTrail uses the cache collector pattern, which
// includes static caching. Since this second scenario simulates a second
// request, we must also simulate it for the MenuActiveTrail service, by
// clearing the cache collector's static cache.
\Drupal::service('menu.active_trail')->clear();
$active_trail_expectations = [];
$active_trail_expectations['all'] = [
'test.example1' => [],
'test.example2' => [
'test.example3' => [
'test.example4' => [],
]
],
'test.example5' => [
'test.example7' => [],
],
'test.example6' => [],
'test.example8' => [],
];
$active_trail_expectations['level_1_only'] = [
'test.example1' => [],
'test.example2' => [],
'test.example5' => [],
'test.example6' => [],
'test.example8' => [],
];
$active_trail_expectations['level_2_only'] = [
'test.example3' => [],
'test.example7' => [],
];
$active_trail_expectations['level_3_only'] = [
'test.example4' => [],
];
$active_trail_expectations['level_1_and_beyond'] = $active_trail_expectations['all'];
$active_trail_expectations['level_2_and_beyond'] = [
'test.example3' => [
'test.example4' => [],
],
'test.example7' => [],
];
$active_trail_expectations['level_3_and_beyond'] = $active_trail_expectations['level_3_only'];
foreach ($blocks as $id => $block) {
$block_build = $block->build();
$items = isset($block_build['#items']) ? $block_build['#items'] : [];
$this->assertIdentical($active_trail_expectations[$id], $this->convertBuiltMenuToIdTree($items), format_string('Menu block %id with an active trail renders the expected tree.', ['%id' => $id]));
}
}
/**
* Helper method to allow for easy menu link tree structure assertions.
*
* Converts the result of MenuLinkTree::build() in a "menu link ID tree".
*
* @param array $build
* The return value of MenuLinkTree::build()
*
* @return array
* The "menu link ID tree" representation of the given render array.
*/
protected function convertBuiltMenuToIdTree(array $build) {
$level = [];
foreach (Element::children($build) as $id) {
$level[$id] = [];
if (isset($build[$id]['below'])) {
$level[$id] = $this->convertBuiltMenuToIdTree($build[$id]['below']);
}
}
return $level;
}
}

View file

@ -0,0 +1,82 @@
<?php
namespace Drupal\Tests\system\Kernel\Common;
use Drupal\KernelTests\KernelTestBase;
/**
* Test page rendering hooks.
*
* @group system
*/
class PageRenderTest extends KernelTestBase {
/**
* Tests hook_page_attachments() exceptions.
*/
function testHookPageAttachmentsExceptions() {
$this->enableModules(['common_test', 'system']);
\Drupal::service('router.builder')->rebuild();
$this->assertPageRenderHookExceptions('common_test', 'hook_page_attachments');
}
/**
* Tests hook_page_attachments_alter() exceptions.
*/
function testHookPageAlter() {
$this->enableModules(['common_test', 'system']);
\Drupal::service('router.builder')->rebuild();
$this->assertPageRenderHookExceptions('common_test', 'hook_page_attachments_alter');
}
/**
* Asserts whether expected exceptions are thrown for invalid hook implementations.
*
* @param string $module
* The module whose invalid logic in its hooks to enable.
* @param string $hook
* The page render hook to assert expected exceptions for.
*/
function assertPageRenderHookExceptions($module, $hook) {
$html_renderer = \Drupal::getContainer()->get('main_content_renderer.html');
// Assert a valid hook implementation doesn't trigger an exception.
$page = [];
$html_renderer->invokePageAttachmentHooks($page);
// Assert that hooks can set cache tags.
$this->assertEqual($page['#cache']['tags'], ['example']);
$this->assertEqual($page['#cache']['contexts'], ['user.permissions']);
// Assert an invalid hook implementation doesn't trigger an exception.
\Drupal::state()->set($module . '.' . $hook . '.descendant_attached', TRUE);
$assertion = $hook . '() implementation that sets #attached on a descendant triggers an exception';
$page = [];
try {
$html_renderer->invokePageAttachmentHooks($page);
$this->error($assertion);
}
catch (\LogicException $e) {
$this->pass($assertion);
$this->assertEqual($e->getMessage(), 'Only #attached and #cache may be set in ' . $hook . '().');
}
\Drupal::state()->set('bc_test.' . $hook . '.descendant_attached', FALSE);
// Assert an invalid hook implementation doesn't trigger an exception.
\Drupal::state()->set('bc_test.' . $hook . '.render_array', TRUE);
$assertion = $hook . '() implementation that sets a child render array triggers an exception';
$page = [];
try {
$html_renderer->invokePageAttachmentHooks($page);
$this->error($assertion);
}
catch (\LogicException $e) {
$this->pass($assertion);
$this->assertEqual($e->getMessage(), 'Only #attached and #cache may be set in ' . $hook . '().');
}
\Drupal::state()->set($module . '.' . $hook . '.render_array', FALSE);
}
}

View file

@ -0,0 +1,76 @@
<?php
namespace Drupal\Tests\system\Kernel\Common;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests scanning system directories in drupal_system_listing().
*
* @group Common
*/
class SystemListingTest extends KernelTestBase {
/**
* Tests that files in different directories take precedence as expected.
*/
function testDirectoryPrecedence() {
// Define the module files we will search for, and the directory precedence
// we expect.
$expected_directories = array(
// When both copies of the module are compatible with Drupal core, the
// copy in the profile directory takes precedence.
'drupal_system_listing_compatible_test' => array(
'core/profiles/testing/modules',
'core/modules/system/tests/modules',
),
);
// This test relies on two versions of the same module existing in
// different places in the filesystem. Without that, the test has no
// meaning, so assert their presence first.
foreach ($expected_directories as $module => $directories) {
foreach ($directories as $directory) {
$filename = "$directory/$module/$module.info.yml";
$this->assertTrue(file_exists(\Drupal::root() . '/' . $filename), format_string('@filename exists.', array('@filename' => $filename)));
}
}
// Now scan the directories and check that the files take precedence as
// expected.
$listing = new ExtensionDiscovery(\Drupal::root());
$listing->setProfileDirectories(array('core/profiles/testing'));
$files = $listing->scan('module');
foreach ($expected_directories as $module => $directories) {
$expected_directory = array_shift($directories);
$expected_uri = "$expected_directory/$module/$module.info.yml";
$this->assertEqual($files[$module]->getPathname(), $expected_uri, format_string('Module @actual was found at @expected.', array(
'@actual' => $files[$module]->getPathname(),
'@expected' => $expected_uri,
)));
}
}
/**
* Tests that directories matching file_scan_ignore_directories are ignored
*/
public function testFileScanIgnoreDirectory() {
$listing = new ExtensionDiscovery(\Drupal::root(), FALSE);
$listing->setProfileDirectories(array('core/profiles/testing'));
$files = $listing->scan('module');
$this->assertArrayHasKey('drupal_system_listing_compatible_test', $files);
// Reset the static to force a rescan of the directories.
$reflected_class = new \ReflectionClass(ExtensionDiscovery::class);
$reflected_property = $reflected_class->getProperty('files');
$reflected_property->setAccessible(TRUE);
$reflected_property->setValue($reflected_class, []);
$this->setSetting('file_scan_ignore_directories', ['drupal_system_listing_compatible_test']);
$listing = new ExtensionDiscovery(\Drupal::root(), FALSE);
$listing->setProfileDirectories(array('core/profiles/testing'));
$files = $listing->scan('module');
$this->assertArrayNotHasKey('drupal_system_listing_compatible_test', $files);
}
}

View file

@ -0,0 +1,200 @@
<?php
namespace Drupal\Tests\system\Kernel\Entity;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\NodeType;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests entity reference selection plugins.
*
* @group entity_reference
*/
class EntityReferenceSelectionReferenceableTest extends KernelTestBase {
use EntityReferenceTestTrait;
/**
* Bundle of 'entity_test_no_label' entity.
*
* @var string
*/
protected $bundle;
/**
* Labels to be tested.
*
* @var array
*/
protected static $labels = ['abc', 'Xyz_', 'xyabz_', 'foo_', 'bar_', 'baz_', 'șz_', NULL, '<strong>'];
/**
* The selection handler.
*
* @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface.
*/
protected $selectionHandler;
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'user', 'field', 'entity_reference', 'node', 'entity_test'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test_no_label');
/** @var \Drupal\Core\Entity\EntityStorageInterface $storage */
$storage = $this->container->get('entity.manager')
->getStorage('entity_test_no_label');
// Create a new node-type.
NodeType::create([
'type' => $node_type = Unicode::strtolower($this->randomMachineName()),
'name' => $this->randomString(),
])->save();
// Create an entity reference field targeting 'entity_test_no_label'
// entities.
$field_name = Unicode::strtolower($this->randomMachineName());
$this->createEntityReferenceField('node', $node_type, $field_name, $this->randomString(), 'entity_test_no_label');
$field_config = FieldConfig::loadByName('node', $node_type, $field_name);
$this->selectionHandler = $this->container->get('plugin.manager.entity_reference_selection')->getSelectionHandler($field_config);
// Generate a bundle name to be used with 'entity_test_no_label'.
$this->bundle = Unicode::strtolower($this->randomMachineName());
// Create 6 entities to be referenced by the field.
foreach (static::$labels as $name) {
$storage->create([
'id' => Unicode::strtolower($this->randomMachineName()),
'name' => $name,
'type' => $this->bundle,
])->save();
}
}
/**
* Tests values returned by SelectionInterface::getReferenceableEntities()
* when the target entity type has no 'label' key.
*
* @param mixed $match
* The input text to be checked.
* @param string $match_operator
* The matching operator.
* @param int $limit
* The limit of returning records.
* @param int $count_limited
* The expected number of limited entities to be retrieved.
* @param array $items
* Array of entity labels expected to be returned.
* @param int $count_all
* The total number (unlimited) of entities to be retrieved.
*
* @dataProvider providerTestCases
*/
public function testReferenceablesWithNoLabelKey($match, $match_operator, $limit, $count_limited, array $items, $count_all) {
// Test ::getReferenceableEntities().
$referenceables = $this->selectionHandler->getReferenceableEntities($match, $match_operator, $limit);
// Number of returned items.
if (empty($count_limited)) {
$this->assertTrue(empty($referenceables[$this->bundle]));
}
else {
$this->assertSame(count($referenceables[$this->bundle]), $count_limited);
}
// Test returned items.
foreach ($items as $item) {
// SelectionInterface::getReferenceableEntities() always return escaped
// entity labels.
// @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface::getReferenceableEntities()
$item = is_string($item) ? Html::escape($item) : $item;
$this->assertTrue(array_search($item, $referenceables[$this->bundle]) !== FALSE);
}
// Test ::countReferenceableEntities().
$count_referenceables = $this->selectionHandler->countReferenceableEntities($match, $match_operator);
$this->assertSame($count_referenceables, $count_all);
}
/**
* Provides test cases for ::testReferenceablesWithNoLabelKey() test.
*
* @return array[]
*/
public function providerTestCases() {
return [
// All referenceables, no limit. Expecting 9 items.
[NULL, 'CONTAINS', 0, 9, static::$labels, 9],
// Referenceables containing 'w', no limit. Expecting no item.
['w', 'CONTAINS', 0, 0, [], 0],
// Referenceables starting with 'w', no limit. Expecting no item.
['w', 'STARTS_WITH', 0, 0, [], 0],
// Referenceables containing 'ab', no limit. Expecting 2 items ('abc',
// 'xyabz').
['ab', 'CONTAINS', 0, 2, ['abc', 'xyabz_'], 2],
// Referenceables starting with 'A', no limit. Expecting 1 item ('abc').
['A', 'STARTS_WITH', 0, 1, ['abc'], 1],
// Referenceables containing '_', limited to 3. Expecting 3 limited items
// ('Xyz_', 'xyabz_', 'foo_') and 5 total.
['_', 'CONTAINS', 3, 3, ['Xyz_', 'xyabz_', 'foo_'], 6],
// Referenceables ending with 'z_', limited to 3. Expecting 3 limited
// items ('Xyz_', 'xyabz_', 'baz_') and 4 total.
['z_', 'ENDS_WITH', 3, 3, ['Xyz_', 'xyabz_', 'baz_'], 4],
// Referenceables identical with 'xyabz_', no limit. Expecting 1 item
// ('xyabz_').
['xyabz_', '=', 0, 1, ['xyabz_'], 1],
// Referenceables greater than 'foo', no limit. Expecting 4 items ('Xyz_',
// 'xyabz_', 'foo_', 'șz_').
['foo', '>', 0, 4, ['Xyz_', 'xyabz_', 'foo_', 'șz_'], 4],
// Referenceables greater or identical with 'baz_', no limit. Expecting 5
// items ('Xyz_', 'xyabz_', 'foo_', 'baz_', 'șz_').
['baz_', '>=', 0, 5, ['Xyz_', 'xyabz_', 'foo_', 'baz_', 'șz_'], 5],
// Referenceables less than 'foo', no limit. Expecting 5 items ('abc',
// 'bar_', 'baz_', NULL, '<strong>').
['foo', '<', 0, 5, ['abc', 'bar_', 'baz_', NULL, '<strong>'], 5],
// Referenceables less or identical with 'baz_', no limit. Expecting 5
// items ('abc', 'bar_', 'baz_', NULL, '<strong>').
['baz_', '<=', 0, 5, ['abc', 'bar_', 'baz_', NULL, '<strong>'], 5],
// Referenceables not identical with 'baz_', no limit. Expecting 7 items
// ('abc', 'Xyz_', 'xyabz_', 'foo_', 'bar_', 'șz_', NULL, '<strong>').
['baz_', '<>', 0, 8, ['abc', 'Xyz_', 'xyabz_', 'foo_', 'bar_', 'șz_', NULL, '<strong>'], 8],
// Referenceables in ('bar_', 'baz_'), no limit. Expecting 2 items
// ('bar_', 'baz_')
[['bar_', 'baz_'], 'IN', 0, 2, ['bar_', 'baz_'], 2],
// Referenceables not in ('bar_', 'baz_'), no limit. Expecting 6 items
// ('abc', 'Xyz_', 'xyabz_', 'foo_', 'șz_', NULL, '<strong>')
[['bar_', 'baz_'], 'NOT IN', 0, 7, ['abc', 'Xyz_', 'xyabz_', 'foo_', 'șz_', NULL, '<strong>'], 7],
// Referenceables not null, no limit. Expecting 9 items ('abc', 'Xyz_',
// 'xyabz_', 'foo_', 'bar_', 'baz_', 'șz_', NULL, '<strong>').
//
// Note: Even we set the name as NULL, when retrieving the label from the
// entity we'll get an empty string, meaning that this match operator
// will return TRUE every time.
[NULL, 'IS NOT NULL', 0, 9, static::$labels, 9],
// Referenceables null, no limit. Expecting 9 items ('abc', 'Xyz_',
// 'xyabz_', 'foo_', 'bar_', 'baz_', 'șz_', NULL, '<strong>').
//
// Note: Even we set the name as NULL, when retrieving the label from the
// entity we'll get an empty string, meaning that this match operator
// will return FALSE every time.
[NULL, 'IS NULL', 0, 9, static::$labels, 9],
// Referenceables containing '<strong>' markup, no limit. Expecting 1 item
// ('<strong>').
['<strong>', 'CONTAINS', 0, 1, ['<strong>'], 1],
// Test an unsupported operator. We expect no items.
['abc', '*unsupported*', 0, 0, [], 0],
];
}
}

View file

@ -0,0 +1,321 @@
<?php
namespace Drupal\Tests\system\Kernel\Extension;
use Drupal\Core\Extension\MissingDependencyException;
use \Drupal\Core\Extension\ModuleUninstallValidatorException;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests ModuleHandler functionality.
*
* @group Extension
*/
class ModuleHandlerTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// @todo ModuleInstaller calls system_rebuild_module_data which is part of
// system.module, see https://www.drupal.org/node/2208429.
include_once $this->root . '/core/modules/system/system.module';
// Set up the state values so we know where to find the files when running
// drupal_get_filename().
// @todo Remove as part of https://www.drupal.org/node/2186491
system_rebuild_module_data();
}
/**
* The basic functionality of retrieving enabled modules.
*/
function testModuleList() {
$module_list = ['system'];
$this->assertModuleList($module_list, 'Initial');
// Try to install a new module.
$this->moduleInstaller()->install(array('ban'));
$module_list[] = 'ban';
sort($module_list);
$this->assertModuleList($module_list, 'After adding a module');
// Try to mess with the module weights.
module_set_weight('ban', 20);
// Move ban to the end of the array.
unset($module_list[array_search('ban', $module_list)]);
$module_list[] = 'ban';
$this->assertModuleList($module_list, 'After changing weights');
// Test the fixed list feature.
$fixed_list = array(
'system' => 'core/modules/system/system.module',
'menu' => 'core/modules/menu/menu.module',
);
$this->moduleHandler()->setModuleList($fixed_list);
$new_module_list = array_combine(array_keys($fixed_list), array_keys($fixed_list));
$this->assertModuleList($new_module_list, t('When using a fixed list'));
}
/**
* Assert that the extension handler returns the expected values.
*
* @param array $expected_values
* The expected values, sorted by weight and module name.
* @param $condition
*/
protected function assertModuleList(array $expected_values, $condition) {
$expected_values = array_values(array_unique($expected_values));
$enabled_modules = array_keys($this->container->get('module_handler')->getModuleList());
$this->assertEqual($expected_values, $enabled_modules, format_string('@condition: extension handler returns correct results', array('@condition' => $condition)));
}
/**
* Tests dependency resolution.
*
* Intentionally using fake dependencies added via hook_system_info_alter()
* for modules that normally do not have any dependencies.
*
* To simplify things further, all of the manipulated modules are either
* purely UI-facing or live at the "bottom" of all dependency chains.
*
* @see module_test_system_info_alter()
* @see https://www.drupal.org/files/issues/dep.gv__0.png
*/
function testDependencyResolution() {
$this->enableModules(array('module_test'));
$this->assertTrue($this->moduleHandler()->moduleExists('module_test'), 'Test module is enabled.');
// Ensure that modules are not enabled.
$this->assertFalse($this->moduleHandler()->moduleExists('color'), 'Color module is disabled.');
$this->assertFalse($this->moduleHandler()->moduleExists('config'), 'Config module is disabled.');
$this->assertFalse($this->moduleHandler()->moduleExists('help'), 'Help module is disabled.');
// Create a missing fake dependency.
// Color will depend on Config, which depends on a non-existing module Foo.
// Nothing should be installed.
\Drupal::state()->set('module_test.dependency', 'missing dependency');
drupal_static_reset('system_rebuild_module_data');
try {
$result = $this->moduleInstaller()->install(array('color'));
$this->fail(t('ModuleInstaller::install() throws an exception if dependencies are missing.'));
}
catch (MissingDependencyException $e) {
$this->pass(t('ModuleInstaller::install() throws an exception if dependencies are missing.'));
}
$this->assertFalse($this->moduleHandler()->moduleExists('color'), 'ModuleInstaller::install() aborts if dependencies are missing.');
// Fix the missing dependency.
// Color module depends on Config. Config depends on Help module.
\Drupal::state()->set('module_test.dependency', 'dependency');
drupal_static_reset('system_rebuild_module_data');
$result = $this->moduleInstaller()->install(array('color'));
$this->assertTrue($result, 'ModuleInstaller::install() returns the correct value.');
// Verify that the fake dependency chain was installed.
$this->assertTrue($this->moduleHandler()->moduleExists('config') && $this->moduleHandler()->moduleExists('help'), 'Dependency chain was installed.');
// Verify that the original module was installed.
$this->assertTrue($this->moduleHandler()->moduleExists('color'), 'Module installation with dependencies succeeded.');
// Verify that the modules were enabled in the correct order.
$module_order = \Drupal::state()->get('module_test.install_order') ?: array();
$this->assertEqual($module_order, array('help', 'config', 'color'));
// Uninstall all three modules explicitly, but in the incorrect order,
// and make sure that ModuleInstaller::uninstall() uninstalled them in the
// correct sequence.
$result = $this->moduleInstaller()->uninstall(array('config', 'help', 'color'));
$this->assertTrue($result, 'ModuleInstaller::uninstall() returned TRUE.');
foreach (array('color', 'config', 'help') as $module) {
$this->assertEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, "$module module was uninstalled.");
}
$uninstalled_modules = \Drupal::state()->get('module_test.uninstall_order') ?: array();
$this->assertEqual($uninstalled_modules, array('color', 'config', 'help'), 'Modules were uninstalled in the correct order.');
// Enable Color module again, which should enable both the Config module and
// Help module. But, this time do it with Config module declaring a
// dependency on a specific version of Help module in its info file. Make
// sure that Drupal\Core\Extension\ModuleInstaller::install() still works.
\Drupal::state()->set('module_test.dependency', 'version dependency');
drupal_static_reset('system_rebuild_module_data');
$result = $this->moduleInstaller()->install(array('color'));
$this->assertTrue($result, 'ModuleInstaller::install() returns the correct value.');
// Verify that the fake dependency chain was installed.
$this->assertTrue($this->moduleHandler()->moduleExists('config') && $this->moduleHandler()->moduleExists('help'), 'Dependency chain was installed.');
// Verify that the original module was installed.
$this->assertTrue($this->moduleHandler()->moduleExists('color'), 'Module installation with version dependencies succeeded.');
// Finally, verify that the modules were enabled in the correct order.
$enable_order = \Drupal::state()->get('module_test.install_order') ?: array();
$this->assertIdentical($enable_order, array('help', 'config', 'color'));
}
/**
* Tests uninstalling a module that is a "dependency" of a profile.
*/
function testUninstallProfileDependency() {
$profile = 'minimal';
$dependency = 'dblog';
$this->setSetting('install_profile', $profile);
// Prime the drupal_get_filename() static cache with the location of the
// minimal profile as it is not the currently active profile and we don't
// yet have any cached way to retrieve its location.
// @todo Remove as part of https://www.drupal.org/node/2186491
drupal_get_filename('profile', $profile, 'core/profiles/' . $profile . '/' . $profile . '.info.yml');
$this->enableModules(array('module_test', $profile));
drupal_static_reset('system_rebuild_module_data');
$data = system_rebuild_module_data();
$this->assertTrue(isset($data[$profile]->requires[$dependency]));
$this->moduleInstaller()->install(array($dependency));
$this->assertTrue($this->moduleHandler()->moduleExists($dependency));
// Uninstall the profile module "dependency".
$result = $this->moduleInstaller()->uninstall(array($dependency));
$this->assertTrue($result, 'ModuleInstaller::uninstall() returns TRUE.');
$this->assertFalse($this->moduleHandler()->moduleExists($dependency));
$this->assertEqual(drupal_get_installed_schema_version($dependency), SCHEMA_UNINSTALLED, "$dependency module was uninstalled.");
// Verify that the installation profile itself was not uninstalled.
$uninstalled_modules = \Drupal::state()->get('module_test.uninstall_order') ?: array();
$this->assertTrue(in_array($dependency, $uninstalled_modules), "$dependency module is in the list of uninstalled modules.");
$this->assertFalse(in_array($profile, $uninstalled_modules), 'The installation profile is not in the list of uninstalled modules.');
}
/**
* Tests uninstalling a module that has content.
*/
function testUninstallContentDependency() {
$this->enableModules(array('module_test', 'entity_test', 'text', 'user', 'help'));
$this->assertTrue($this->moduleHandler()->moduleExists('entity_test'), 'Test module is enabled.');
$this->assertTrue($this->moduleHandler()->moduleExists('module_test'), 'Test module is enabled.');
$this->installSchema('user', 'users_data');
$entity_types = \Drupal::entityManager()->getDefinitions();
foreach ($entity_types as $entity_type) {
if ('entity_test' == $entity_type->getProvider()) {
$this->installEntitySchema($entity_type->id());
}
}
// Create a fake dependency.
// entity_test will depend on help. This way help can not be uninstalled
// when there is test content preventing entity_test from being uninstalled.
\Drupal::state()->set('module_test.dependency', 'dependency');
drupal_static_reset('system_rebuild_module_data');
// Create an entity so that the modules can not be disabled.
$entity = EntityTest::create(array('name' => $this->randomString()));
$entity->save();
// Uninstalling entity_test is not possible when there is content.
try {
$message = 'ModuleInstaller::uninstall() throws ModuleUninstallValidatorException upon uninstalling a module which does not pass validation.';
$this->moduleInstaller()->uninstall(array('entity_test'));
$this->fail($message);
}
catch (ModuleUninstallValidatorException $e) {
$this->pass(get_class($e) . ': ' . $e->getMessage());
}
// Uninstalling help needs entity_test to be un-installable.
try {
$message = 'ModuleInstaller::uninstall() throws ModuleUninstallValidatorException upon uninstalling a module which does not pass validation.';
$this->moduleInstaller()->uninstall(array('help'));
$this->fail($message);
}
catch (ModuleUninstallValidatorException $e) {
$this->pass(get_class($e) . ': ' . $e->getMessage());
}
// Deleting the entity.
$entity->delete();
$result = $this->moduleInstaller()->uninstall(array('help'));
$this->assertTrue($result, 'ModuleInstaller::uninstall() returns TRUE.');
$this->assertEqual(drupal_get_installed_schema_version('entity_test'), SCHEMA_UNINSTALLED, "entity_test module was uninstalled.");
}
/**
* Tests whether the correct module metadata is returned.
*/
function testModuleMetaData() {
// Generate the list of available modules.
$modules = system_rebuild_module_data();
// Check that the mtime field exists for the system module.
$this->assertTrue(!empty($modules['system']->info['mtime']), 'The system.info.yml file modification time field is present.');
// Use 0 if mtime isn't present, to avoid an array index notice.
$test_mtime = !empty($modules['system']->info['mtime']) ? $modules['system']->info['mtime'] : 0;
// Ensure the mtime field contains a number that is greater than zero.
$this->assertTrue(is_numeric($test_mtime) && ($test_mtime > 0), 'The system.info.yml file modification time field contains a timestamp.');
}
/**
* Tests whether module-provided stream wrappers are registered properly.
*/
public function testModuleStreamWrappers() {
// file_test.module provides (among others) a 'dummy' stream wrapper.
// Verify that it is not registered yet to prevent false positives.
$stream_wrappers = \Drupal::service('stream_wrapper_manager')->getWrappers();
$this->assertFalse(isset($stream_wrappers['dummy']));
$this->moduleInstaller()->install(['file_test']);
// Verify that the stream wrapper is available even without calling
// \Drupal::service('stream_wrapper_manager')->getWrappers() again.
// If the stream wrapper is not available file_exists() will raise a notice.
file_exists('dummy://');
$stream_wrappers = \Drupal::service('stream_wrapper_manager')->getWrappers();
$this->assertTrue(isset($stream_wrappers['dummy']));
}
/**
* Tests whether the correct theme metadata is returned.
*/
function testThemeMetaData() {
// Generate the list of available themes.
$themes = \Drupal::service('theme_handler')->rebuildThemeData();
// Check that the mtime field exists for the bartik theme.
$this->assertTrue(!empty($themes['bartik']->info['mtime']), 'The bartik.info.yml file modification time field is present.');
// Use 0 if mtime isn't present, to avoid an array index notice.
$test_mtime = !empty($themes['bartik']->info['mtime']) ? $themes['bartik']->info['mtime'] : 0;
// Ensure the mtime field contains a number that is greater than zero.
$this->assertTrue(is_numeric($test_mtime) && ($test_mtime > 0), 'The bartik.info.yml file modification time field contains a timestamp.');
}
/**
* Returns the ModuleHandler.
*
* @return \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected function moduleHandler() {
return $this->container->get('module_handler');
}
/**
* Returns the ModuleInstaller.
*
* @return \Drupal\Core\Extension\ModuleInstallerInterface
*/
protected function moduleInstaller() {
return $this->container->get('module_installer');
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\system\Kernel\Form;
use Drupal\KernelTests\KernelTestBase;
use Symfony\Component\CssSelector\CssSelectorConverter;
/**
* Tests for form_element_label theme hook.
*
* @group Form
*/
class FormElementLabelTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system'];
/**
* Ensures that attributes can be placed for form element label.
*/
public function testAttributes() {
$render_array = [
'#type' => 'label',
'#attributes' => ['class' => ['kitten']],
'#title' => 'Kittens',
'#title_display' => 'above',
];
$css_selector_converter = new CssSelectorConverter();
$this->render($render_array);
$elements = $this->xpath($css_selector_converter->toXPath('.kitten'));
$this->assertCount(1, $elements);
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace Drupal\Tests\system\Kernel\Installer;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests that we handle the absence of a module dependency during install.
*
* @group Installer
*/
class InstallerMissingDependenciesTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system'];
/**
* Verifies that the exception message in the profile step is correct.
*/
public function testSetUpWithMissingDependencies() {
// Prime the drupal_get_filename() static cache with the location of the
// testing profile as it is not the currently active profile and we don't
// yet have any cached way to retrieve its location.
// @todo Remove as part of https://www.drupal.org/node/2186491
drupal_get_filename('profile', 'testing_missing_dependencies', 'core/profiles/testing_missing_dependencies/testing_missing_dependencies.info.yml');
$info = drupal_verify_profile([
'parameters' => ['profile' => 'testing_missing_dependencies'],
'profile_info' => install_profile_info('testing_missing_dependencies'),
]);
$message = $info['required_modules']['description']->render();
$this->assertContains('Missing_module1', $message);
$this->assertContains('Missing_module2', $message);
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\Core\Datetime\Entity\DateFormat;
use Drupal\Core\Database\Database;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade date formats to core.date_format.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateDateFormatTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d6_date_formats');
}
/**
* Tests the Drupal 6 date formats to Drupal 8 migration.
*/
public function testDateFormats() {
$short_date_format = DateFormat::load('short');
$this->assertIdentical('\S\H\O\R\T m/d/Y - H:i', $short_date_format->getPattern());
$medium_date_format = DateFormat::load('medium');
$this->assertIdentical('\M\E\D\I\U\M D, m/d/Y - H:i', $medium_date_format->getPattern());
$long_date_format = DateFormat::load('long');
$this->assertIdentical('\L\O\N\G l, F j, Y - H:i', $long_date_format->getPattern());
// Test that we can re-import using the EntityDateFormat destination.
Database::getConnection('default', 'migrate')
->update('variable')
->fields(array('value' => serialize('\S\H\O\R\T d/m/Y - H:i')))
->condition('name', 'date_format_short')
->execute();
$migration = $this->getMigration('d6_date_formats');
\Drupal::database()
->truncate($migration->getIdMap()->mapTableName())
->execute();
$this->executeMigration($migration);
$short_date_format = DateFormat::load('short');
$this->assertIdentical('\S\H\O\R\T d/m/Y - H:i', $short_date_format->getPattern());
}
}

View file

@ -0,0 +1,53 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\Core\Database\Database;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
use Drupal\system\Entity\Menu;
/**
* Upgrade menus to system.menu.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateMenuTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d6_menu');
}
/**
* Tests the Drupal 6 menu to Drupal 8 migration.
*/
public function testMenu() {
$navigation_menu = Menu::load('navigation');
$this->assertSame('navigation', $navigation_menu->id());
$this->assertSame('Navigation', $navigation_menu->label());
$expected = <<<EOT
The navigation menu is provided by Drupal and is the main interactive menu for any site. It is usually the only menu that contains personalized links for authenticated users, and is often not even visible to anonymous users.
EOT;
$this->assertSame($expected, $navigation_menu->getDescription());
// Test that we can re-import using the ConfigEntityBase destination.
Database::getConnection('default', 'migrate')
->update('menu_custom')
->fields(array('title' => 'Home Navigation'))
->condition('menu_name', 'navigation')
->execute();
$migration = $this->getMigration('d6_menu');
\Drupal::database()
->truncate($migration->getIdMap()->mapTableName())
->execute();
$this->executeMigration($migration);
$navigation_menu = Menu::load('navigation');
$this->assertSame('Home Navigation', $navigation_menu->label());
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade cron variable to system.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateSystemCronTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d6_system_cron');
}
/**
* Tests migration of system (cron) variables to system.cron.yml.
*/
public function testSystemCron() {
$config = $this->config('system.cron');
$this->assertIdentical(172800, $config->get('threshold.requirements_warning'));
$this->assertIdentical(1209600, $config->get('threshold.requirements_error'));
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade date time variables to system.date config
*
* @group migrate_drupal_6
*/
class MigrateSystemDateTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d6_system_date');
}
/**
* Tests migration of user variables to system_date.yml.
*/
public function testSystemDate() {
$config = $this->config('system.date');
$this->assertIdentical(4, $config->get('first_day'));
$this->assertIdentical(FALSE, $config->get('timezone.user.configurable'));
$this->assertIdentical("Europe/Paris", $config->get('timezone.default'));
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade variables to system.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateSystemFileTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d6_system_file');
}
/**
* Tests migration of system (file) variables to system.file.yml.
*/
public function testSystemFile() {
$config = \Drupal::configFactory()->getEditable('system.file');
$this->assertIdentical('files/temp', $config->get('path.temporary'));
$this->assertIdentical(TRUE, $config->get('allow_insecure_uploads'));
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade image gd variables to system.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateSystemImageGdTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('system_image_gd');
}
/**
* Tests migration of system (image GD) variables to system.image.gd.yml.
*/
public function testSystemImageGd() {
$config = $this->config('system.image.gd');
$this->assertIdentical(75, $config->get('jpeg_quality'));
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade image variables to system.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateSystemImageTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('system_image');
}
/**
* Tests migration of system (image) variables to system.image.yml.
*/
public function testSystemImage() {
$config = $this->config('system.image');
$this->assertIdentical('gd', $config->get('toolkit'));
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\config\Tests\SchemaCheckTestTrait;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade error_level variable to system.logging.yml.
*
* @group migrate_drupal_6
*/
class MigrateSystemLoggingTest extends MigrateDrupal6TestBase {
use SchemaCheckTestTrait;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('system_logging');
}
/**
* Tests migration of system error_level variables to system.logging.yml.
*/
public function testSystemLogging() {
$config = $this->config('system.logging');
$this->assertIdentical('some', $config->get('error_level'));
$this->assertConfigSchema(\Drupal::service('config.typed'), 'system.logging', $config->get());
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade maintenance variables to system.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateSystemMaintenanceTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('system_maintenance');
}
/**
* Tests migration of system (maintenance) variables to system.maintenance.yml.
*/
public function testSystemMaintenance() {
$config = $this->config('system.maintenance');
$this->assertIdentical('Drupal is currently under maintenance. We should be back shortly. Thank you for your patience.', $config->get('message'));
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade performance variables to system.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateSystemPerformanceTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d6_system_performance');
}
/**
* Tests migration of system (Performance) variables to system.performance.yml.
*/
public function testSystemPerformance() {
$config = $this->config('system.performance');
$this->assertIdentical(FALSE, $config->get('css.preprocess'));
$this->assertIdentical(FALSE, $config->get('js.preprocess'));
$this->assertIdentical(0, $config->get('cache.page.max_age'));
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade rss variable to system.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateSystemRssTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('system_rss');
}
/**
* Tests migration of system (rss) variables to system.rss.yml.
*/
public function testSystemRss() {
$config = $this->config('system.rss');
$this->assertIdentical(10, $config->get('items.limit'));
$this->assertIdentical('title', $config->get('items.view_mode'));
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
/**
* Upgrade site variables to system.*.yml.
*
* @group migrate_drupal_6
*/
class MigrateSystemSiteTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('system_site');
}
/**
* Tests migration of system (site) variables to system.site.yml.
*/
public function testSystemSite() {
$config = $this->config('system.site');
$this->assertIdentical('site_name', $config->get('name'));
$this->assertIdentical('site_mail@example.com', $config->get('mail'));
$this->assertIdentical('Migrate rocks', $config->get('slogan'));
$this->assertIdentical('/user', $config->get('page.403'));
$this->assertIdentical('/page-not-found', $config->get('page.404'));
$this->assertIdentical('/node', $config->get('page.front'));
$this->assertIdentical(FALSE, $config->get('admin_compact_mode'));
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d7;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
/**
* Tests migration of global theme settings variables to configuration.
*
* @group system
*/
class MigrateGlobalThemeSettingsTest extends MigrateDrupal7TestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d7_global_theme_settings');
}
/**
* Tests migration of global theme settings to configuration.
*/
public function testMigrateThemeSettings() {
$config = $this->config('system.theme.global');
$this->assertSame('image/png', $config->get('favicon.mimetype'));
$this->assertSame('public://somefavicon.png', $config->get('favicon.path'));
$this->assertFalse($config->get('favicon.use_default'));
$this->assertFalse($config->get('features.comment_user_picture'));
$this->assertFalse($config->get('features.comment_user_verification'));
$this->assertFalse($config->get('features.favicon'));
$this->assertFalse($config->get('features.node_user_picture'));
$this->assertFalse($config->get('features.logo'));
$this->assertTrue($config->get('features.name'));
$this->assertFalse($config->get('features.slogan'));
$this->assertSame('public://customlogo.png', $config->get('logo.path'));
$this->assertTrue($config->get('logo.use_default'));
}
}

View file

@ -0,0 +1,68 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d7;
use Drupal\Core\Database\Database;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
use Drupal\system\Entity\Menu;
/**
* Upgrade menus to system.menu.*.yml.
*
* @group migrate_drupal_7
*/
class MigrateMenuTest extends MigrateDrupal7TestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->executeMigration('d7_menu');
}
/**
* Asserts various aspects of a menu.
*
* @param $id
* The menu ID.
* @param $label
* The menu label.
* @param $description
* The menu description.
*/
protected function assertEntity($id, $label, $description) {
$navigation_menu = Menu::load($id);
$this->assertSame($id, $navigation_menu->id());
$this->assertSame($label, $navigation_menu->label());
$this->assertSame($description, $navigation_menu->getDescription());
}
/**
* Tests the Drupal 7 menu to Drupal 8 migration.
*/
public function testMenu() {
$this->assertEntity('main', 'Main menu', 'The <em>Main</em> menu is used on many sites to show the major sections of the site, often in a top navigation bar.');
$this->assertEntity('admin', 'Management', 'The <em>Management</em> menu contains links for administrative tasks.');
$this->assertEntity('menu-test-menu', 'Test Menu', 'Test menu description.');
$this->assertEntity('tools', 'Navigation', 'The <em>Navigation</em> menu contains links intended for site visitors. Links are added to the <em>Navigation</em> menu automatically by some modules.');
$this->assertEntity('account', 'User menu', 'The <em>User</em> menu contains links related to the user\'s account, as well as the \'Log out\' link.');
// Test that we can re-import using the ConfigEntityBase destination.
Database::getConnection('default', 'migrate')
->update('menu_custom')
->fields(array('title' => 'Home Navigation'))
->condition('menu_name', 'navigation')
->execute();
$migration = $this->getMigration('d7_menu');
\Drupal::database()
->truncate($migration->getIdMap()->mapTableName())
->execute();
$this->executeMigration($migration);
$navigation_menu = Menu::load('tools');
$this->assertSame('Home Navigation', $navigation_menu->label());
}
}

View file

@ -0,0 +1,169 @@
<?php
namespace Drupal\Tests\system\Kernel\Migrate\d7;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
/**
* Migrates various configuration objects owned by the System module.
*
* @group migrate_drupal_7
*/
class MigrateSystemConfigurationTest extends MigrateDrupal7TestBase {
public static $modules = ['action', 'file', 'system'];
protected $expectedConfig = [
'system.authorize' => [
'filetransfer_default' => 'ftp',
],
'system.cron' => [
'threshold' => [
// autorun is not handled by the migration.
// 'autorun' => 0,
'requirements_warning' => 172800,
'requirements_error' => 1209600,
],
],
'system.date' => [
'country' => [
'default' => 'US',
],
'first_day' => 1,
'timezone' => [
'default' => 'America/Chicago',
'user' => [
'configurable' => TRUE,
'warn' => TRUE,
// DRUPAL_USER_TIMEZONE_SELECT (D7 API)
'default' => 2,
],
],
],
'system.file' => [
'allow_insecure_uploads' => TRUE,
// default_scheme is not handled by the migration.
'default_scheme' => 'public',
'path' => [
'temporary' => '/tmp',
],
// temporary_maximum_age is not handled by the migration.
'temporary_maximum_age' => 21600,
],
'system.image.gd' => [
'jpeg_quality' => 80,
],
'system.image' => [
'toolkit' => 'gd',
],
'system.logging' => [
'error_level' => 'some',
],
'system.mail' => [
'interface' => [
'default' => 'php_mail',
],
],
'system.maintenance' => [
'message' => 'This is a custom maintenance mode message.',
// langcode is not handled by the migration.
'langcode' => 'en',
],
'system.performance' => [
'cache' => [
'page' => [
'max_age' => 300,
],
],
'css' => [
'preprocess' => TRUE,
// gzip is not handled by the migration.
'gzip' => TRUE,
],
// fast_404 is not handled by the migration.
'fast_404' => [
'enabled' => TRUE,
'paths' => '/\.(?:txt|png|gif|jpe?g|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$/i',
'exclude_paths' => '/\/(?:styles|imagecache)\//',
'html' => '<!DOCTYPE html><html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>',
],
'js' => [
'preprocess' => FALSE,
// gzip is not handled by the migration.
'gzip' => TRUE,
],
// stale_file_threshold is not handled by the migration.
'stale_file_threshold' => 2592000,
'response' => [
'gzip' => TRUE,
],
],
'system.rss' => [
'channel' => [
'description' => '',
],
'items' => [
'limit' => 27,
'view_mode' => 'fulltext',
],
'langcode' => 'en',
],
'system.site' => [
// uuid is not handled by the migration.
'uuid' => '',
'name' => 'The Site Name',
'mail' => 'joseph@flattandsons.com',
'slogan' => 'The Slogan',
'page' => [
'403' => '/node',
'404' => '/node',
'front' => '/node',
],
'admin_compact_mode' => TRUE,
'weight_select_max' => 40,
// langcode and default_langcode are not handled by the migration.
'langcode' => 'en',
'default_langcode' => 'en',
],
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$migrations = [
'd7_system_authorize',
'd7_system_cron',
'd7_system_date',
'd7_system_file',
'system_image_gd',
'system_image',
'system_logging',
'd7_system_mail',
'system_maintenance',
'd7_system_performance',
'system_rss',
'system_site',
];
$this->executeMigrations($migrations);
}
/**
* Tests that all expected configuration gets migrated.
*/
public function testConfigurationMigration() {
foreach ($this->expectedConfig as $config_id => $values) {
if ($config_id == 'system.mail') {
$actual = \Drupal::config($config_id)->getRawData();
}
else {
$actual = \Drupal::config($config_id)->get();
}
unset($actual['_core']);
$this->assertSame($actual, $values, $config_id . ' matches expected values.');
}
}
}

View file

@ -0,0 +1,55 @@
<?php
namespace Drupal\Tests\system\Kernel;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Path\AliasManagerInterface;
use Drupal\KernelTests\KernelTestBase;
use Prophecy\Argument;
/**
* @group Drupal
*/
class PathHooksTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
static public $modules = ['system'];
/**
* Test system_path_*() correctly clears caches.
*/
public function testPathHooks() {
$source = '/' . $this->randomMachineName();
$alias = '/' . $this->randomMachineName();
// Check system_path_insert();
$alias_manager = $this->prophesize(AliasManagerInterface::class);
$alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(1);
$alias_manager->cacheClear($source)->shouldBeCalledTimes(1);
\Drupal::getContainer()->set('path.alias_manager', $alias_manager->reveal());
$alias_storage = \Drupal::service('path.alias_storage');
$alias_storage->save($source, $alias);
$new_source = '/' . $this->randomMachineName();
$path = $alias_storage->load(['source' => $source]);
// Check system_path_update();
$alias_manager = $this->prophesize(AliasManagerInterface::class);
$alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(2);
$alias_manager->cacheClear($source)->shouldBeCalledTimes(1);
$alias_manager->cacheClear($new_source)->shouldBeCalledTimes(1);
\Drupal::getContainer()->set('path.alias_manager', $alias_manager->reveal());
$alias_storage->save($new_source, $alias, LanguageInterface::LANGCODE_NOT_SPECIFIED, $path['pid']);
// Check system_path_delete();
$alias_manager = $this->prophesize(AliasManagerInterface::class);
$alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(1);
$alias_manager->cacheClear($new_source)->shouldBeCalledTimes(1);
\Drupal::getContainer()->set('path.alias_manager', $alias_manager->reveal());
$alias_storage->delete(['pid' => $path['pid']]);
}
}

View file

@ -0,0 +1,106 @@
<?php
namespace Drupal\Tests\system\Kernel\PhpStorage;
use Drupal\Component\PhpStorage\MTimeProtectedFileStorage;
use Drupal\Core\PhpStorage\PhpStorageFactory;
use Drupal\Core\Site\Settings;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\system\PhpStorage\MockPhpStorage;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the PHP storage factory.
*
* @group PhpStorage
* @see \Drupal\Core\PhpStorage\PhpStorageFactory
*/
class PhpStorageFactoryTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Empty the PHP storage settings, as KernelTestBase sets it by default.
$settings = Settings::getAll();
unset($settings['php_storage']);
new Settings($settings);
}
/**
* Tests the get() method with no settings.
*/
public function testGetNoSettings() {
$php = PhpStorageFactory::get('test');
// This should be the default class used.
$this->assertTrue($php instanceof MTimeProtectedFileStorage, 'An MTimeProtectedFileStorage instance was returned with no settings.');
}
/**
* Tests the get() method using the 'default' settings.
*/
public function testGetDefault() {
$this->setSettings();
$php = PhpStorageFactory::get('test');
$this->assertTrue($php instanceof MockPhpStorage, 'A FileReadOnlyStorage instance was returned with default settings.');
}
/**
* Tests the get() method with overridden settings.
*/
public function testGetOverride() {
$this->setSettings('test');
$php = PhpStorageFactory::get('test');
// The FileReadOnlyStorage should be used from settings.
$this->assertTrue($php instanceof MockPhpStorage, 'A MockPhpStorage instance was returned from overridden settings.');
// Test that the name is used for the bin when it is NULL.
$this->setSettings('test', array('bin' => NULL));
$php = PhpStorageFactory::get('test');
$this->assertTrue($php instanceof MockPhpStorage, 'An MockPhpStorage instance was returned from overridden settings.');
$this->assertSame('test', $php->getConfigurationValue('bin'), 'Name value was used for bin.');
// Test that a default directory is set if it's empty.
$this->setSettings('test', array('directory' => NULL));
$php = PhpStorageFactory::get('test');
$this->assertTrue($php instanceof MockPhpStorage, 'An MockPhpStorage instance was returned from overridden settings.');
$this->assertSame(PublicStream::basePath() . '/php', $php->getConfigurationValue('directory'), 'Default file directory was used.');
// Test that a default storage class is set if it's empty.
$this->setSettings('test', array('class' => NULL));
$php = PhpStorageFactory::get('test');
$this->assertTrue($php instanceof MTimeProtectedFileStorage, 'An MTimeProtectedFileStorage instance was returned from overridden settings with no class.');
// Test that a default secret is not returned if it's set in the override.
$this->setSettings('test');
$php = PhpStorageFactory::get('test');
$this->assertNotEquals('mock hash salt', $php->getConfigurationValue('secret'), 'The default secret is not used if a secret is set in the overridden settings.');
// Test that a default secret is set if it's empty.
$this->setSettings('test', array('secret' => NULL));
$php = PhpStorageFactory::get('test');
$this->assertSame('mock hash salt', $php->getConfigurationValue('secret'), 'The default secret is used if one is not set in the overridden settings.');
}
/**
* Sets the Settings() singleton.
*
* @param string $name
* The storage bin name to set.
* @param array $configuration
* An array of configuration to set. Will be merged with default values.
*/
protected function setSettings($name = 'default', array $configuration = array()) {
$settings['php_storage'][$name] = $configuration + array(
'class' => 'Drupal\system\PhpStorage\MockPhpStorage',
'directory' => 'tmp://',
'secret' => $this->randomString(),
'bin' => 'test',
);
$settings['hash_salt'] = 'mock hash salt';
new Settings($settings);
}
}

View file

@ -0,0 +1,47 @@
<?php
namespace Drupal\Tests\system\Kernel\Plugin\migrate\source;
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
/**
* Tests menu source plugin.
*
* @covers Drupal\system\Plugin\migrate\source\Menu
*
* @group system
*/
class MenuTest extends MigrateSqlSourceTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'migrate_drupal'];
/**
* {@inheritdoc}
*/
public function providerSource() {
$tests = [];
// The source data.
$tests[0]['source_data']['menu_custom'] = [
[
'menu_name' => 'menu-name-1',
'title' => 'menu custom value 1',
'description' => 'menu custom description value 1',
],
[
'menu_name' => 'menu-name-2',
'title' => 'menu custom value 2',
'description' => 'menu custom description value 2',
],
];
// The expected results are identical to the source data.
$tests[0]['expected_data'] = $tests[0]['source_data']['menu_custom'];
return $tests;
}
}

View file

@ -0,0 +1,49 @@
<?php
namespace Drupal\Tests\system\Kernel\Render;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the Classy theme.
*
* @group Theme
*/
class ClassyTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = array('system', 'twig_theme_test');
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
// Use the classy theme.
$this->container->get('theme_installer')->install(['classy']);
$this->container->get('config.factory')
->getEditable('system.theme')
->set('default', 'classy')
->save();
// Clear the theme registry.
$this->container->set('theme.registry', NULL);
}
/**
* Test the classy theme.
*/
function testClassyTheme() {
drupal_set_message('An error occurred', 'error');
drupal_set_message('But then something nice happened');
$messages = array(
'#type' => 'status_messages',
);
$this->render($messages);
$this->assertNoText('custom-test-messages-class', 'The custom class attribute value added in the status messages preprocess function is not displayed as page content.');
}
}

View file

@ -0,0 +1,137 @@
<?php
/**
* @file
* Contains \Drupal\Tests\system\Kernel\Scripts\DbCommandBaseTest.
*/
namespace Drupal\Tests\system\Kernel\Scripts;
use Drupal\Core\Command\DbCommandBase;
use Drupal\Core\Database\Database;
use Drupal\KernelTests\KernelTestBase;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Tester\CommandTester;
/**
* Test that the DbToolsApplication works correctly.
*
* The way console application's run it is impossible to test. For now we only
* test that we are registering the correct commands.
*
* @group console
*/
class DbCommandBaseTest extends KernelTestBase {
/**
* Test specifying a database key.
*/
public function testSpecifyDatabaseKey() {
$command = new DbCommandBaseTester();
$command_tester = new CommandTester($command);
Database::addConnectionInfo('magic_db', 'default', Database::getConnectionInfo('default')['default']);
$command_tester->execute([
'--database' => 'magic_db'
]);
$this->assertEquals('magic_db', $command->getDatabaseConnection($command_tester->getInput())->getKey(),
'Special db key is returned');
}
/**
* Invalid database names will throw a useful exception.
*
* @expectedException \Drupal\Core\Database\ConnectionNotDefinedException
*/
public function testSpecifyDatabaseDoesNotExist() {
$command = new DbCommandBaseTester();
$command_tester = new CommandTester($command);
$command_tester->execute([
'--database' => 'dne'
]);
$command->getDatabaseConnection($command_tester->getInput());
}
/**
* Test supplying database connection as a url.
*/
public function testSpecifyDbUrl() {
$connection_info = Database::getConnectionInfo('default')['default'];
$command = new DbCommandBaseTester();
$command_tester = new CommandTester($command);
$command_tester->execute([
'-db-url' => $connection_info['driver'] . '://' . $connection_info['username'] . ':' . $connection_info['password'] . '@' . $connection_info['host'] . '/' . $connection_info['database']
]);
$this->assertEquals('db-tools', $command->getDatabaseConnection($command_tester->getInput())->getKey());
Database::removeConnection('db-tools');
$command_tester->execute([
'--database-url' => $connection_info['driver'] . '://' . $connection_info['username'] . ':' . $connection_info['password'] . '@' . $connection_info['host'] . '/' . $connection_info['database']
]);
$this->assertEquals('db-tools', $command->getDatabaseConnection($command_tester->getInput())->getKey());
}
/**
* Test specifying a prefix for different connections.
*/
public function testPrefix() {
if (Database::getConnection()->driver() == 'sqlite') {
$this->markTestSkipped('SQLITE modifies the prefixes so we cannot effectively test it');
}
Database::addConnectionInfo('magic_db', 'default', Database::getConnectionInfo('default')['default']);
$command = new DbCommandBaseTester();
$command_tester = new CommandTester($command);
$command_tester->execute([
'--database' => 'magic_db',
'--prefix' => 'extra',
]);
$this->assertEquals('extra', $command->getDatabaseConnection($command_tester->getInput())->tablePrefix());
$connection_info = Database::getConnectionInfo('default')['default'];
$command_tester->execute([
'-db-url' => $connection_info['driver'] . '://' . $connection_info['username'] . ':' . $connection_info['password'] . '@' . $connection_info['host'] . '/' . $connection_info['database'],
'--prefix' => 'extra2',
]);
$this->assertEquals('extra2', $command->getDatabaseConnection($command_tester->getInput())->tablePrefix());
// This breaks simpletest cleanup.
// $command_tester->execute([
// '--prefix' => 'notsimpletest',
// ]);
// $this->assertEquals('notsimpletest', $command->getDatabaseConnection($command_tester->getInput())->tablePrefix());
}
}
/**
* Concrete command implementation for testing base features.
*/
class DbCommandBaseTester extends DbCommandBase {
/**
* {@inheritdoc}
*/
public function configure() {
parent::configure();
$this->setName('test');
}
/**
* {@inheritdoc}
*/
public function getDatabaseConnection(InputInterface $input) {
return parent::getDatabaseConnection($input);
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output) {
// Empty implementation for testing.
}
}

View file

@ -0,0 +1,85 @@
<?php
namespace Drupal\Tests\system\Kernel\Scripts;
use Drupal\Core\Command\DbDumpCommand;
use Drupal\Core\Database\Database;
use Drupal\KernelTests\KernelTestBase;
use Symfony\Component\Console\Tester\CommandTester;
/**
* Test that the DbDumpCommand works correctly.
*
* @group console
*/
class DbDumpCommandTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Determine what database backend is running, and set the skip flag.
if (Database::getConnection()->databaseType() !== 'mysql') {
$this->markTestSkipped("Skipping test since the DbDumpCommand is currently only compatible with MySQL");
}
// Rebuild the router to ensure a routing table.
\Drupal::service('router.builder')->rebuild();
/** @var \Drupal\Core\Database\Connection $connection */
$connection = $this->container->get('database');
$connection->insert('router')->fields(['name', 'path', 'pattern_outline'])->values(['test', 'test', 'test'])->execute();
}
/**
* Test the command directly.
*/
public function testDbDumpCommand() {
$command = new DbDumpCommand();
$command_tester = new CommandTester($command);
$command_tester->execute([]);
// Assert that insert exists and that some expected fields exist.
$output = $command_tester->getDisplay();
$this->assertContains("createTable('router", $output, 'Table router found');
$this->assertContains("insert('router", $output, 'Insert found');
$this->assertContains("'name' => 'test", $output, 'Insert name field found');
$this->assertContains("'path' => 'test", $output, 'Insert path field found');
$this->assertContains("'pattern_outline' => 'test", $output, 'Insert pattern_outline field found');
$this->assertContains("// @codingStandardsIgnoreFile", $output);
}
/**
* Test schema only option.
*/
public function testSchemaOnly() {
$command = new DbDumpCommand();
$command_tester = new CommandTester($command);
$command_tester->execute(['--schema-only' => 'router']);
// Assert that insert statement doesn't exist for schema only table.
$output = $command_tester->getDisplay();
$this->assertContains("createTable('router", $output, 'Table router found');
$this->assertNotContains("insert('router", $output, 'Insert not found');
$this->assertNotContains("'name' => 'test", $output, 'Insert name field not found');
$this->assertNotContains("'path' => 'test", $output, 'Insert path field not found');
$this->assertNotContains("'pattern_outline' => 'test", $output, 'Insert pattern_outline field not found');
// Assert that insert statement doesn't exist for wildcard schema only match.
$command_tester->execute(['--schema-only' => 'route.*']);
$output = $command_tester->getDisplay();
$this->assertContains("createTable('router", $output, 'Table router found');
$this->assertNotContains("insert('router", $output, 'Insert not found');
$this->assertNotContains("'name' => 'test", $output, 'Insert name field not found');
$this->assertNotContains("'path' => 'test", $output, 'Insert path field not found');
$this->assertNotContains("'pattern_outline' => 'test", $output, 'Insert pattern_outline field not found');
}
}

View file

@ -0,0 +1,76 @@
<?php
namespace Drupal\Tests\system\Kernel\Scripts;
use Drupal\Core\Command\DbImportCommand;
use Drupal\Core\Database\Database;
use Drupal\KernelTests\KernelTestBase;
use Symfony\Component\Console\Tester\CommandTester;
/**
* Test that the DbImportCommand works correctly.
*
* @group console
*/
class DbImportCommandTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'config', 'dblog', 'menu_link_content', 'link', 'block_content', 'file', 'user'];
/**
* Tables that should be part of the exported script.
*
* @var array
*/
protected $tables = [
'block_content',
'block_content_field_data',
'block_content_field_revision',
'block_content_revision',
'cachetags',
'config',
'cache_discovery',
'cache_bootstrap',
'file_managed',
'key_value_expire',
'menu_link_content',
'menu_link_content_data',
'sessions',
'url_alias',
'user__roles',
'users',
'users_field_data',
'watchdog',
];
/**
* Test the command directly.
*
* @requires extension pdo_sqlite
*/
public function testDbImportCommand() {
$connection_info = array(
'driver' => 'sqlite',
'database' => ':memory:',
);
Database::addConnectionInfo($this->databasePrefix, 'default', $connection_info);
$command = new DbImportCommand();
$command_tester = new CommandTester($command);
$command_tester->execute([
'script' => __DIR__ . '/../../../fixtures/update/drupal-8.bare.standard.php.gz',
'--database' => $this->databasePrefix,
]);
// The tables should now exist.
$connection = Database::getConnection('default', $this->databasePrefix);
foreach ($this->tables as $table) {
$this->assertTrue($connection
->schema()
->tableExists($table), strtr('Table @table created by the database script.', ['@table' => $table]));
}
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\system\Kernel\Scripts;
use Drupal\Core\Command\DbToolsApplication;
use Drupal\KernelTests\KernelTestBase;
/**
* Test that the DbToolsApplication works correctly.
*
* The way console application's run it is impossible to test. For now we only
* test that we are registering the correct commands.
*
* @group console
*/
class DbToolsApplicationTest extends KernelTestBase {
/**
* Test that the dump command is correctly registered.
*/
public function testDumpCommandRegistration() {
$application = new DbToolsApplication();
$command = $application->find('dump');
$this->assertInstanceOf('\Drupal\Core\Command\DbDumpCommand', $command);
}
/**
* Test that the dump command is correctly registered.
*/
public function testImportCommandRegistration() {
$application = new DbToolsApplication();
$command = $application->find('import');
$this->assertInstanceOf('\Drupal\Core\Command\DbImportCommand', $command);
}
}

View file

@ -0,0 +1,112 @@
<?php
namespace Drupal\Tests\system\Kernel\System;
use Drupal\Core\Database\Database;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the Cron Queue runner.
*
* @group system
*/
class CronQueueTest extends KernelTestBase {
/**
* The modules to enable.
*
* @var array
*/
public static $modules = ['system', 'cron_queue_test'];
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* The cron service.
*
* @var \Drupal\Core\Cron
*/
protected $cron;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// These additional tables are necessary because $this->cron->run() calls
// system_cron().
$this->installSchema('system', ['key_value_expire']);
$this->connection = Database::getConnection();
$this->cron = \Drupal::service('cron');
}
/**
* Tests that exceptions thrown by workers are handled properly.
*/
public function testExceptions() {
// Get the queue to test the normal Exception.
$queue = $this->container->get('queue')->get('cron_queue_test_exception');
// Enqueue an item for processing.
$queue->createItem(array($this->randomMachineName() => $this->randomMachineName()));
// Run cron; the worker for this queue should throw an exception and handle
// it.
$this->cron->run();
$this->assertEqual(\Drupal::state()->get('cron_queue_test_exception'), 1);
// The item should be left in the queue.
$this->assertEqual($queue->numberOfItems(), 1, 'Failing item still in the queue after throwing an exception.');
// Expire the queue item manually. system_cron() relies in REQUEST_TIME to
// find queue items whose expire field needs to be reset to 0. This is a
// Kernel test, so REQUEST_TIME won't change when cron runs.
// @see system_cron()
// @see \Drupal\Core\Cron::processQueues()
$this->connection->update('queue')
->condition('name', 'cron_queue_test_exception')
->fields(['expire' => REQUEST_TIME - 1])
->execute();
$this->cron->run();
$this->assertEqual(\Drupal::state()->get('cron_queue_test_exception'), 2);
$this->assertEqual($queue->numberOfItems(), 0, 'Item was processed and removed from the queue.');
// Get the queue to test the specific SuspendQueueException.
$queue = $this->container->get('queue')->get('cron_queue_test_broken_queue');
// Enqueue several item for processing.
$queue->createItem('process');
$queue->createItem('crash');
$queue->createItem('ignored');
// Run cron; the worker for this queue should process as far as the crashing
// item.
$this->cron->run();
// Only one item should have been processed.
$this->assertEqual($queue->numberOfItems(), 2, 'Failing queue stopped processing at the failing item.');
// Check the items remaining in the queue. The item that throws the
// exception gets released by cron, so we can claim it again to check it.
$item = $queue->claimItem();
$this->assertEqual($item->data, 'crash', 'Failing item remains in the queue.');
$item = $queue->claimItem();
$this->assertEqual($item->data, 'ignored', 'Item beyond the failing item remains in the queue.');
// Test the requeueing functionality.
$queue = $this->container->get('queue')->get('cron_queue_test_requeue_exception');
$queue->createItem([]);
$this->cron->run();
$this->assertEqual(\Drupal::state()->get('cron_queue_test_requeue_exception'), 2);
$this->assertFalse($queue->numberOfItems());
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\system\Kernel\System;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the effectiveness of hook_system_info_alter().
*
* @group system
*/
class InfoAlterTest extends KernelTestBase {
public static $modules = array('system');
/**
* Tests that theme .info.yml data is rebuild after enabling a module.
*
* Tests that info data is rebuilt after a module that implements
* hook_system_info_alter() is enabled. Also tests if core *_list() functions
* return freshly altered info.
*/
function testSystemInfoAlter() {
\Drupal::state()->set('module_required_test.hook_system_info_alter', TRUE);
$info = system_rebuild_module_data();
$this->assertFalse(isset($info['node']->info['required']), 'Before the module_required_test is installed the node module is not required.');
// Enable the test module.
\Drupal::service('module_installer')->install(array('module_required_test'), FALSE);
$this->assertTrue(\Drupal::moduleHandler()->moduleExists('module_required_test'), 'Test required module is enabled.');
$info = system_rebuild_module_data();
$this->assertTrue($info['node']->info['required'], 'After the module_required_test is installed the node module is required.');
}
}

View file

@ -0,0 +1,157 @@
<?php
namespace Drupal\Tests\system\Kernel\Token;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Render\BubbleableMetadata;
/**
* Generates text using placeholders for dummy content to check token
* replacement.
*
* @group system
*/
class TokenReplaceKernelTest extends TokenReplaceKernelTestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Set the site name to something other than an empty string.
$this->config('system.site')->set('name', 'Drupal')->save();
}
/**
* Test whether token-replacement works in various contexts.
*/
public function testSystemTokenRecognition() {
// Generate prefixes and suffixes for the token context.
$tests = array(
array('prefix' => 'this is the ', 'suffix' => ' site'),
array('prefix' => 'this is the', 'suffix' => 'site'),
array('prefix' => '[', 'suffix' => ']'),
array('prefix' => '', 'suffix' => ']]]'),
array('prefix' => '[[[', 'suffix' => ''),
array('prefix' => ':[:', 'suffix' => '--]'),
array('prefix' => '-[-', 'suffix' => ':]:'),
array('prefix' => '[:', 'suffix' => ']'),
array('prefix' => '[site:', 'suffix' => ':name]'),
array('prefix' => '[site:', 'suffix' => ']'),
);
// Check if the token is recognized in each of the contexts.
foreach ($tests as $test) {
$input = $test['prefix'] . '[site:name]' . $test['suffix'];
$expected = $test['prefix'] . 'Drupal' . $test['suffix'];
$output = $this->tokenService->replace($input, array(), array('langcode' => $this->interfaceLanguage->getId()));
$this->assertTrue($output == $expected, format_string('Token recognized in string %string', array('%string' => $input)));
}
// Test token replacement when the string contains no tokens.
$this->assertEqual($this->tokenService->replace('No tokens here.'), 'No tokens here.');
}
/**
* Tests the clear parameter.
*/
public function testClear() {
// Valid token.
$source = '[site:name]';
// No user passed in, should be untouched.
$source .= '[user:name]';
// Non-existing token.
$source .= '[bogus:token]';
// Replace with the clear parameter, only the valid token should remain.
$target = Html::escape($this->config('system.site')->get('name'));
$result = $this->tokenService->replace($source, array(), array('langcode' => $this->interfaceLanguage->getId(), 'clear' => TRUE));
$this->assertEqual($target, $result, 'Valid tokens replaced while invalid tokens ignored.');
$target .= '[user:name]';
$target .= '[bogus:token]';
$result = $this->tokenService->replace($source, array(), array('langcode' => $this->interfaceLanguage->getId()));
$this->assertEqual($target, $result, 'Valid tokens replaced while invalid tokens ignored.');
}
/**
* Tests the generation of all system site information tokens.
*/
public function testSystemSiteTokenReplacement() {
$url_options = array(
'absolute' => TRUE,
'language' => $this->interfaceLanguage,
);
$slogan = '<blink>Slogan</blink>';
$safe_slogan = Xss::filterAdmin($slogan);
// Set a few site variables.
$config = $this->config('system.site');
$config
->set('name', '<strong>Drupal<strong>')
->set('slogan', $slogan)
->set('mail', 'simpletest@example.com')
->save();
// Generate and test tokens.
$tests = array();
$tests['[site:name]'] = Html::escape($config->get('name'));
$tests['[site:slogan]'] = $safe_slogan;
$tests['[site:mail]'] = $config->get('mail');
$tests['[site:url]'] = \Drupal::url('<front>', [], $url_options);
$tests['[site:url-brief]'] = preg_replace(array('!^https?://!', '!/$!'), '', \Drupal::url('<front>', [], $url_options));
$tests['[site:login-url]'] = \Drupal::url('user.page', [], $url_options);
$base_bubbleable_metadata = new BubbleableMetadata();
$metadata_tests = [];
$metadata_tests['[site:name]'] = BubbleableMetadata::createFromObject(\Drupal::config('system.site'));
$metadata_tests['[site:slogan]'] = BubbleableMetadata::createFromObject(\Drupal::config('system.site'));
$metadata_tests['[site:mail]'] = BubbleableMetadata::createFromObject(\Drupal::config('system.site'));
$bubbleable_metadata = clone $base_bubbleable_metadata;
$metadata_tests['[site:url]'] = $bubbleable_metadata->addCacheContexts(['url.site']);
$metadata_tests['[site:url-brief]'] = $bubbleable_metadata;
$metadata_tests['[site:login-url]'] = $bubbleable_metadata;
// Test to make sure that we generated something for each token.
$this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
foreach ($tests as $input => $expected) {
$bubbleable_metadata = new BubbleableMetadata();
$output = $this->tokenService->replace($input, array(), array('langcode' => $this->interfaceLanguage->getId()), $bubbleable_metadata);
$this->assertEqual($output, $expected, new FormattableMarkup('System site information token %token replaced.', ['%token' => $input]));
$this->assertEqual($bubbleable_metadata, $metadata_tests[$input]);
}
}
/**
* Tests the generation of all system date tokens.
*/
public function testSystemDateTokenReplacement() {
// Set time to one hour before request.
$date = REQUEST_TIME - 3600;
// Generate and test tokens.
$tests = array();
$date_formatter = \Drupal::service('date.formatter');
$tests['[date:short]'] = $date_formatter->format($date, 'short', '', NULL, $this->interfaceLanguage->getId());
$tests['[date:medium]'] = $date_formatter->format($date, 'medium', '', NULL, $this->interfaceLanguage->getId());
$tests['[date:long]'] = $date_formatter->format($date, 'long', '', NULL, $this->interfaceLanguage->getId());
$tests['[date:custom:m/j/Y]'] = $date_formatter->format($date, 'custom', 'm/j/Y', NULL, $this->interfaceLanguage->getId());
$tests['[date:since]'] = $date_formatter->formatTimeDiffSince($date, array('langcode' => $this->interfaceLanguage->getId()));
$tests['[date:raw]'] = Xss::filter($date);
// Test to make sure that we generated something for each token.
$this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
foreach ($tests as $input => $expected) {
$output = $this->tokenService->replace($input, array('date' => $date), array('langcode' => $this->interfaceLanguage->getId()));
$this->assertEqual($output, $expected, format_string('Date token %token replaced.', array('%token' => $input)));
}
}
}

View file

@ -0,0 +1,43 @@
<?php
namespace Drupal\Tests\system\Kernel\Token;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
/**
* Base class for token replacement tests.
*/
abstract class TokenReplaceKernelTestBase extends EntityKernelTestBase {
/**
* The interface language.
*
* @var \Drupal\Core\Language\LanguageInterface
*/
protected $interfaceLanguage;
/**
* Token service.
*
* @var \Drupal\Core\Utility\Token
*/
protected $tokenService;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
protected function setUp() {
parent::setUp();
// Install default system configuration.
$this->installConfig(array('system'));
\Drupal::service('router.builder')->rebuild();
$this->interfaceLanguage = \Drupal::languageManager()->getCurrentLanguage();
$this->tokenService = \Drupal::token();
}
}

View file

@ -0,0 +1,402 @@
<?php
/**
* @file
* Contains \Drupal\Tests\system\Unit\Breadcrumbs\PathBasedBreadcrumbBuilderTest.
*/
namespace Drupal\Tests\system\Unit\Breadcrumbs;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Link;
use Drupal\Core\Access\AccessResultAllowed;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Url;
use Drupal\Core\Utility\LinkGeneratorInterface;
use Drupal\system\PathBasedBreadcrumbBuilder;
use Drupal\Tests\UnitTestCase;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
/**
* @coversDefaultClass \Drupal\system\PathBasedBreadcrumbBuilder
* @group system
*/
class PathBasedBreadcrumbBuilderTest extends UnitTestCase {
/**
* The path based breadcrumb builder object to test.
*
* @var \Drupal\system\PathBasedBreadcrumbBuilder
*/
protected $builder;
/**
* The mocked title resolver.
*
* @var \Drupal\Core\Controller\TitleResolverInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $titleResolver;
/**
* The mocked access manager.
*
* @var \Drupal\Core\Access\AccessManagerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $accessManager;
/**
* The request matching mock object.
*
* @var \Symfony\Component\Routing\Matcher\RequestMatcherInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $requestMatcher;
/**
* The mocked route request context.
*
* @var \Drupal\Core\Routing\RequestContext|\PHPUnit_Framework_MockObject_MockObject
*/
protected $context;
/**
* The mocked current user.
*
* @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $currentUser;
/**
* The mocked path processor.
*
* @var \Drupal\Core\PathProcessor\InboundPathProcessorInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $pathProcessor;
/**
* The mocked current path.
*
* @var \Drupal\Core\Path\CurrentPathStack|\PHPUnit_Framework_MockObject_MockObject
*/
protected $currentPath;
/**
* {@inheritdoc}
*
* @covers ::__construct
*/
protected function setUp() {
parent::setUp();
$this->requestMatcher = $this->getMock('\Symfony\Component\Routing\Matcher\RequestMatcherInterface');
$config_factory = $this->getConfigFactoryStub(array('system.site' => array('front' => 'test_frontpage')));
$this->pathProcessor = $this->getMock('\Drupal\Core\PathProcessor\InboundPathProcessorInterface');
$this->context = $this->getMock('\Drupal\Core\Routing\RequestContext');
$this->accessManager = $this->getMock('\Drupal\Core\Access\AccessManagerInterface');
$this->titleResolver = $this->getMock('\Drupal\Core\Controller\TitleResolverInterface');
$this->currentUser = $this->getMock('Drupal\Core\Session\AccountInterface');
$this->currentPath = $this->getMockBuilder('Drupal\Core\Path\CurrentPathStack')
->disableOriginalConstructor()
->getMock();
$this->builder = new TestPathBasedBreadcrumbBuilder(
$this->context,
$this->accessManager,
$this->requestMatcher,
$this->pathProcessor,
$config_factory,
$this->titleResolver,
$this->currentUser,
$this->currentPath
);
$this->builder->setStringTranslation($this->getStringTranslationStub());
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
->disableOriginalConstructor()
->getMock();
$cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
$cache_contexts_manager->expects($this->any())
->method('validate_tokens');
$container = new Container();
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
}
/**
* Tests the build method on the frontpage.
*
* @covers ::build
*/
public function testBuildOnFrontpage() {
$this->context->expects($this->once())
->method('getPathInfo')
->will($this->returnValue('/'));
$breadcrumb = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
/**
* Tests the build method with one path element.
*
* @covers ::build
*/
public function testBuildWithOnePathElement() {
$this->context->expects($this->once())
->method('getPathInfo')
->will($this->returnValue('/example'));
$breadcrumb = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([0 => new Link('Home', new Url('<front>'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
/**
* Tests the build method with two path elements.
*
* @covers ::build
* @covers ::getRequestForPath
*/
public function testBuildWithTwoPathElements() {
$this->context->expects($this->once())
->method('getPathInfo')
->will($this->returnValue('/example/baz'));
$this->setupStubPathProcessor();
$route_1 = new Route('/example');
$this->requestMatcher->expects($this->exactly(1))
->method('matchRequest')
->will($this->returnCallback(function(Request $request) use ($route_1) {
if ($request->getPathInfo() == '/example') {
return array(
RouteObjectInterface::ROUTE_NAME => 'example',
RouteObjectInterface::ROUTE_OBJECT => $route_1,
'_raw_variables' => new ParameterBag(array()),
);
}
}));
$this->setupAccessManagerToAllow();
$breadcrumb = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([0 => new Link('Home', new Url('<front>')), 1 => new Link('Example', new Url('example'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent', 'user.permissions'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
/**
* Tests the build method with three path elements.
*
* @covers ::build
* @covers ::getRequestForPath
*/
public function testBuildWithThreePathElements() {
$this->context->expects($this->once())
->method('getPathInfo')
->will($this->returnValue('/example/bar/baz'));
$this->setupStubPathProcessor();
$route_1 = new Route('/example/bar');
$route_2 = new Route('/example');
$this->requestMatcher->expects($this->exactly(2))
->method('matchRequest')
->will($this->returnCallback(function(Request $request) use ($route_1, $route_2) {
if ($request->getPathInfo() == '/example/bar') {
return array(
RouteObjectInterface::ROUTE_NAME => 'example_bar',
RouteObjectInterface::ROUTE_OBJECT => $route_1,
'_raw_variables' => new ParameterBag(array()),
);
}
elseif ($request->getPathInfo() == '/example') {
return array(
RouteObjectInterface::ROUTE_NAME => 'example',
RouteObjectInterface::ROUTE_OBJECT => $route_2,
'_raw_variables' => new ParameterBag(array()),
);
}
}));
$this->accessManager->expects($this->any())
->method('check')
->willReturnOnConsecutiveCalls(
AccessResult::allowed()->cachePerPermissions(),
AccessResult::allowed()->addCacheContexts(['bar'])->addCacheTags(['example'])
);
$breadcrumb = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([
new Link('Home', new Url('<front>')),
new Link('Example', new Url('example')),
new Link('Bar', new Url('example_bar')),
], $breadcrumb->getLinks());
$this->assertEquals(['bar', 'url.path.parent', 'user.permissions'], $breadcrumb->getCacheContexts());
$this->assertEquals(['example'], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
/**
* Tests that exceptions during request matching are caught.
*
* @covers ::build
* @covers ::getRequestForPath
*
* @dataProvider providerTestBuildWithException
*/
public function testBuildWithException($exception_class, $exception_argument) {
$this->context->expects($this->once())
->method('getPathInfo')
->will($this->returnValue('/example/bar'));
$this->setupStubPathProcessor();
$this->requestMatcher->expects($this->any())
->method('matchRequest')
->will($this->throwException(new $exception_class($exception_argument)));
$breadcrumb = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
// No path matched, though at least the frontpage is displayed.
$this->assertEquals([0 => new Link('Home', new Url('<front>'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
/**
* Provides exception types for testBuildWithException.
*
* @return array
* The list of exception test cases.
*
* @see \Drupal\Tests\system\Unit\Breadcrumbs\PathBasedBreadcrumbBuilderTest::testBuildWithException()
*/
public function providerTestBuildWithException() {
return array(
array('Drupal\Core\ParamConverter\ParamNotConvertedException', ''),
array('Symfony\Component\Routing\Exception\MethodNotAllowedException', array()),
array('Symfony\Component\Routing\Exception\ResourceNotFoundException', ''),
);
}
/**
* Tests the build method with a non processed path.
*
* @covers ::build
* @covers ::getRequestForPath
*/
public function testBuildWithNonProcessedPath() {
$this->context->expects($this->once())
->method('getPathInfo')
->will($this->returnValue('/example/bar'));
$this->pathProcessor->expects($this->once())
->method('processInbound')
->will($this->returnValue(FALSE));
$this->requestMatcher->expects($this->any())
->method('matchRequest')
->will($this->returnValue(array()));
$breadcrumb = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
// No path matched, though at least the frontpage is displayed.
$this->assertEquals([0 => new Link('Home', new Url('<front>'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
/**
* Tests the applied method.
*
* @covers ::applies
*/
public function testApplies() {
$this->assertTrue($this->builder->applies($this->getMock('Drupal\Core\Routing\RouteMatchInterface')));
}
/**
* Tests the breadcrumb for a user path.
*
* @covers ::build
* @covers ::getRequestForPath
*/
public function testBuildWithUserPath() {
$this->context->expects($this->once())
->method('getPathInfo')
->will($this->returnValue('/user/1/edit'));
$this->setupStubPathProcessor();
$route_1 = new Route('/user/1');
$this->requestMatcher->expects($this->exactly(1))
->method('matchRequest')
->will($this->returnCallback(function(Request $request) use ($route_1) {
if ($request->getPathInfo() == '/user/1') {
return array(
RouteObjectInterface::ROUTE_NAME => 'user_page',
RouteObjectInterface::ROUTE_OBJECT => $route_1,
'_raw_variables' => new ParameterBag(array()),
);
}
}));
$this->setupAccessManagerToAllow();
$this->titleResolver->expects($this->once())
->method('getTitle')
->with($this->anything(), $route_1)
->will($this->returnValue('Admin'));
$breadcrumb = $this->builder->build($this->getMock('Drupal\Core\Routing\RouteMatchInterface'));
$this->assertEquals([0 => new Link('Home', new Url('<front>')), 1 => new Link('Admin', new Url('user_page'))], $breadcrumb->getLinks());
$this->assertEquals(['url.path.parent', 'user.permissions'], $breadcrumb->getCacheContexts());
$this->assertEquals([], $breadcrumb->getCacheTags());
$this->assertEquals(Cache::PERMANENT, $breadcrumb->getCacheMaxAge());
}
/**
* Setup the access manager to always allow access to routes.
*/
public function setupAccessManagerToAllow() {
$this->accessManager->expects($this->any())
->method('check')
->willReturn((new AccessResultAllowed())->cachePerPermissions());
}
protected function setupStubPathProcessor() {
$this->pathProcessor->expects($this->any())
->method('processInbound')
->will($this->returnArgument(0));
}
}
/**
* Helper class for testing purposes only.
*/
class TestPathBasedBreadcrumbBuilder extends PathBasedBreadcrumbBuilder {
public function setStringTranslation(TranslationInterface $string_translation) {
$this->stringTranslation = $string_translation;
}
public function setLinkGenerator(LinkGeneratorInterface $link_generator) {
$this->linkGenerator = $link_generator;
}
}

View file

@ -0,0 +1,76 @@
<?php
namespace Drupal\Tests\system\Unit\Installer;
use Drupal\Core\StringTranslation\Translator\FileTranslation;
use Drupal\Tests\UnitTestCase;
/**
* Tests for installer language support.
*
* @group Installer
*/
class InstallTranslationFilePatternTest extends UnitTestCase {
/**
* @var \Drupal\Core\StringTranslation\Translator\FileTranslation
*/
protected $fileTranslation;
/**
* @var \ReflectionMethod
*/
protected $filePatternMethod;
/**
* {@inheritdoc}
*/
protected function setup() {
parent::setUp();
$this->fileTranslation = new FileTranslation('filename');
$method = new \ReflectionMethod('\Drupal\Core\StringTranslation\Translator\FileTranslation', 'getTranslationFilesPattern');
$method->setAccessible(TRUE);
$this->filePatternMethod = $method;
}
/**
* @dataProvider providerValidTranslationFiles
*/
public function testFilesPatternValid($langcode, $filename) {
$pattern = $this->filePatternMethod->invoke($this->fileTranslation, $langcode);
$this->assertNotEmpty(preg_match($pattern, $filename));
}
/**
* @return array
*/
public function providerValidTranslationFiles() {
return array(
array('hu', 'drupal-8.0.0-alpha1.hu.po'),
array('ta', 'drupal-8.10.10-beta12.ta.po'),
array('hi', 'drupal-8.0.0.hi.po'),
);
}
/**
* @dataProvider providerInvalidTranslationFiles
*/
public function testFilesPatternInvalid($langcode, $filename) {
$pattern = $this->filePatternMethod->invoke($this->fileTranslation, $langcode);
$this->assertEmpty(preg_match($pattern, $filename));
}
/**
* @return array
*/
public function providerInvalidTranslationFiles() {
return array(
array('hu', 'drupal-alpha1-*-hu.po'),
array('ta', 'drupal-beta12.ta'),
array('hi', 'drupal-hi.po'),
array('de', 'drupal-dummy-de.po'),
array('hu', 'drupal-10.0.1.alpha1-hu.po'),
);
}
}

View file

@ -0,0 +1,281 @@
<?php
namespace Drupal\Tests\system\Unit\Menu;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\Cache;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Menu\MenuLinkTree;
use Drupal\Core\Menu\MenuLinkTreeElement;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Url;
use Drupal\Tests\Core\Menu\MenuLinkMock;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Menu\MenuLinkTree
* @group Menu
*/
class MenuLinkTreeTest extends UnitTestCase {
/**
* The tested menu link tree service.
*
* @var \Drupal\Core\Menu\MenuLinkTree
*/
protected $menuLinkTree;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->menuLinkTree = new MenuLinkTree(
$this->getMock('\Drupal\Core\Menu\MenuTreeStorageInterface'),
$this->getMock('\Drupal\Core\Menu\MenuLinkManagerInterface'),
$this->getMock('\Drupal\Core\Routing\RouteProviderInterface'),
$this->getMock('\Drupal\Core\Menu\MenuActiveTrailInterface'),
$this->getMock('\Drupal\Core\Controller\ControllerResolverInterface')
);
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
->disableOriginalConstructor()
->getMock();
$cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
$container = new ContainerBuilder();
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
}
/**
* @covers ::build
*
* MenuLinkTree::build() gathers both:
* 1. the tree's access cacheability: the cacheability of the access result
* of checking a link in a menu tree's access. Callers can opt out of
* this by MenuLinkTreeElement::access to NULL (the default) value, in
* which case the menu link is always visible. Only when an
* AccessResultInterface object is specified, we gather this cacheability
* metadata.
* This means there are three cases:
* a. no access result (NULL): menu link is visible
* b. AccessResultInterface object that is allowed: menu link is visible
* c. AccessResultInterface object that is not allowed: menu link is
* invisible, but cacheability metadata is still applicable
* 2. the tree's menu links' cacheability: the cacheability of a menu link
* itself, because it may be dynamic. For this reason, MenuLinkInterface
* extends CacheableDependencyInterface. It allows any menu link plugin to
* mark itself as uncacheable (max-age=0) or dynamic (by specifying cache
* tags and/or contexts), to indicate the extent of dynamism.
* This means there are two cases:
* a. permanently cacheable, no cache tags, no cache contexts
* b. anything else: non-permanently cacheable, and/or cache tags, and/or
* cache contexts.
*
* Finally, there are four important shapes of trees, all of which we want to
* test:
* 1. the empty tree
* 2. a single-element tree
* 3. a single-level tree (>1 element; just 1 element is case 2)
* 4. a multi-level tree
*
* The associated data provider aims to test the handling of both of these
* types of cacheability, and for all four tree shapes, for each of the types
* of values for the two types of cacheability.
*
* There is another level of cacheability involved when actually rendering
* built menu trees (i.e. when invoking RendererInterface::render() on the
* return value of MenuLinkTreeInterface::build()): the cacheability of the
* generated URLs.
* Fortunately, that doesn't need additional test coverage here because that
* cacheability is handled at the level of the Renderer (i.e. menu.html.twig
* template's link() function invocation). It also has its own test coverage.
*
* @see \Drupal\menu_link_content\Tests\MenuLinkContentCacheabilityBubblingTest
*
* @dataProvider providerTestBuildCacheability
*/
public function testBuildCacheability($description, $tree, $expected_build, $access, array $access_cache_contexts = []) {
if ($access !== NULL) {
$access->addCacheContexts($access_cache_contexts);
}
$build = $this->menuLinkTree->build($tree);
sort($expected_build['#cache']['contexts']);
$this->assertEquals($expected_build, $build, $description);
}
/**
* Provides the test cases to test for ::testBuildCacheability().
*
* As explained in the documentation for ::testBuildCacheability(), this
* generates 1 + (3 * 2 * 3) = 19 test cases.
*
* @see testBuildCacheability
*/
public function providerTestBuildCacheability() {
$base_expected_build_empty = [
'#cache' => [
'contexts' => [],
'tags' => [],
'max-age' => Cache::PERMANENT,
],
];
$base_expected_build = [
'#cache' => [
'contexts' => [],
'tags' => [
'config:system.menu.mock',
],
'max-age' => Cache::PERMANENT,
],
'#sorted' => TRUE,
'#menu_name' => 'mock',
'#theme' => 'menu__mock',
'#items' => [
// To be filled when generating test cases, using $get_built_element().
]
];
$get_built_element = function(MenuLinkTreeElement $element) {
$return = [
'attributes' => new Attribute(),
'title' => $element->link->getTitle(),
'url' => new Url($element->link->getRouteName(), $element->link->getRouteParameters(), ['set_active_class' => TRUE]),
'below' => [],
'original_link' => $element->link,
'is_expanded' => FALSE,
'is_collapsed' => FALSE,
'in_active_trail' => FALSE,
];
if ($element->hasChildren && !empty($element->subtree)) {
$return['is_expanded'] = TRUE;
}
elseif ($element->hasChildren) {
$return['is_collapsed'] = TRUE;
}
if ($element->inActiveTrail) {
$return['in_active_trail'] = TRUE;
}
return $return;
};
// The three access scenarios described in this method's documentation.
$access_scenarios = [
[NULL, []],
[AccessResult::allowed(), ['access:allowed']],
[AccessResult::neutral(), ['access:neutral']],
];
// The two links scenarios described in this method's documentation.
$cache_defaults = ['cache_max_age' => Cache::PERMANENT, 'cache_tags' => []];
$links_scenarios = [
[
MenuLinkMock::create(['id' => 'test.example1', 'route_name' => 'example1', 'title' => 'Example 1']),
MenuLinkMock::create(['id' => 'test.example2', 'route_name' => 'example1', 'title' => 'Example 2', 'metadata' => ['cache_contexts' => ['llama']] + $cache_defaults]),
],
[
MenuLinkMock::create(['id' => 'test.example1', 'route_name' => 'example1', 'title' => 'Example 1', 'metadata' => ['cache_contexts' => ['foo']] + $cache_defaults]),
MenuLinkMock::create(['id' => 'test.example2', 'route_name' => 'example1', 'title' => 'Example 2', 'metadata' => ['cache_contexts' => ['bar']] + $cache_defaults]),
],
];
$data = [];
// Empty tree.
$data[] = [
'description' => 'Empty tree.',
'tree' => [],
'expected_build' => $base_expected_build_empty,
'access' => NULL,
'access_cache_contexts' => [],
];
for ($i = 0; $i < count($access_scenarios); $i++) {
list($access, $access_cache_contexts) = $access_scenarios[$i];
for ($j = 0; $j < count($links_scenarios); $j++) {
$links = $links_scenarios[$j];
// Single-element tree.
$tree = [
new MenuLinkTreeElement($links[0], FALSE, 0, FALSE, []),
];
$tree[0]->access = $access;
if ($access === NULL || $access->isAllowed()) {
$expected_build = $base_expected_build;
$expected_build['#items']['test.example1'] = $get_built_element($tree[0]);
}
else {
$expected_build = $base_expected_build_empty;
}
$expected_build['#cache']['contexts'] = array_merge($expected_build['#cache']['contexts'], $access_cache_contexts, $links[0]->getCacheContexts());
$data[] = [
'description' => "Single-item tree; access=$i; link=$j.",
'tree' => $tree,
'expected_build' => $expected_build,
'access' => $access,
'access_cache_contexts' => $access_cache_contexts,
];
// Single-level tree.
$tree = [
new MenuLinkTreeElement($links[0], FALSE, 0, FALSE, []),
new MenuLinkTreeElement($links[1], FALSE, 0, FALSE, []),
];
$tree[0]->access = $access;
$expected_build = $base_expected_build;
if ($access === NULL || $access->isAllowed()) {
$expected_build['#items']['test.example1'] = $get_built_element($tree[0]);
}
$expected_build['#items']['test.example2'] = $get_built_element($tree[1]);
$expected_build['#cache']['contexts'] = array_merge($expected_build['#cache']['contexts'], $access_cache_contexts, $links[0]->getCacheContexts(), $links[1]->getCacheContexts());
$data[] = [
'description' => "Single-level tree; access=$i; link=$j.",
'tree' => $tree,
'expected_build' => $expected_build,
'access' => $access,
'access_cache_contexts' => $access_cache_contexts,
];
// Multi-level tree.
$multi_level_root_a = MenuLinkMock::create(['id' => 'test.roota', 'route_name' => 'roota', 'title' => 'Root A']);
$multi_level_root_b = MenuLinkMock::create(['id' => 'test.rootb', 'route_name' => 'rootb', 'title' => 'Root B']);
$multi_level_parent_c = MenuLinkMock::create(['id' => 'test.parentc', 'route_name' => 'parentc', 'title' => 'Parent C']);
$tree = [
new MenuLinkTreeElement($multi_level_root_a, TRUE, 0, FALSE, [
new MenuLinkTreeElement($multi_level_parent_c, TRUE, 0, FALSE, [
new MenuLinkTreeElement($links[0], FALSE, 0, FALSE, []),
])
]),
new MenuLinkTreeElement($multi_level_root_b, TRUE, 0, FALSE, [
new MenuLinkTreeElement($links[1], FALSE, 1, FALSE, [])
]),
];
$tree[0]->subtree[0]->subtree[0]->access = $access;
$expected_build = $base_expected_build;
$expected_build['#items']['test.roota'] = $get_built_element($tree[0]);
$expected_build['#items']['test.roota']['below']['test.parentc'] = $get_built_element($tree[0]->subtree[0]);
if ($access === NULL || $access->isAllowed()) {
$expected_build['#items']['test.roota']['below']['test.parentc']['below']['test.example1'] = $get_built_element($tree[0]->subtree[0]->subtree[0]);
}
$expected_build['#items']['test.rootb'] = $get_built_element($tree[1]);
$expected_build['#items']['test.rootb']['below']['test.example2'] = $get_built_element($tree[1]->subtree[0]);
$expected_build['#cache']['contexts'] = array_merge($expected_build['#cache']['contexts'], $access_cache_contexts, $links[0]->getCacheContexts(), $links[1]->getCacheContexts());
$data[] = [
'description' => "Multi-level tree; access=$i; link=$j.",
'tree' => $tree,
'expected_build' => $expected_build,
'access' => $access,
'access_cache_contexts' => $access_cache_contexts,
];
}
}
return $data;
}
}

View file

@ -0,0 +1,71 @@
<?php
namespace Drupal\Tests\system\Unit\Menu;
use Drupal\Core\Extension\Extension;
use Drupal\Tests\Core\Menu\LocalTaskIntegrationTestBase;
/**
* Tests existence of system local tasks.
*
* @group system
*/
class SystemLocalTasksTest extends LocalTaskIntegrationTestBase {
/**
* The mocked theme handler.
*
* @var \Drupal\Core\Extension\ThemeHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $themeHandler;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->directoryList = array(
'system' => 'core/modules/system',
);
$this->themeHandler = $this->getMock('Drupal\Core\Extension\ThemeHandlerInterface');
$theme = new Extension($this->root, 'theme', '/core/themes/bartik', 'bartik.info.yml');
$theme->status = 1;
$theme->info = array('name' => 'bartik');
$this->themeHandler->expects($this->any())
->method('listInfo')
->will($this->returnValue(array(
'bartik' => $theme,
)));
$this->themeHandler->expects($this->any())
->method('hasUi')
->with('bartik')
->willReturn(TRUE);
$this->container->set('theme_handler', $this->themeHandler);
}
/**
* Tests local task existence.
*
* @dataProvider getSystemAdminRoutes
*/
public function testSystemAdminLocalTasks($route, $expected) {
$this->assertLocalTasks($route, $expected);
}
/**
* Provides a list of routes to test.
*/
public function getSystemAdminRoutes() {
return array(
array('system.admin_content', array(array('system.admin_content'))),
array('system.theme_settings_theme', array(
array('system.themes_page', 'system.theme_settings'),
array('system.theme_settings_global', 'system.theme_settings_theme:bartik'),
)),
);
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\system\Unit;
use Drupal\system\SystemRequirements;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\system\SystemRequirements
* @group system
*/
class SystemRequirementsTest extends UnitTestCase {
/**
* @covers ::phpVersionWithPdoDisallowMultipleStatements
* @dataProvider providerTestPhpVersionWithPdoDisallowMultipleStatements
*/
public function testPhpVersionWithPdoDisallowMultipleStatements($version, $expected) {
$this->assertEquals($expected, SystemRequirements::phpVersionWithPdoDisallowMultipleStatements($version));
}
public function providerTestPhpVersionWithPdoDisallowMultipleStatements() {
$data = [];
$data[] = ['5.4.2', FALSE];
$data[] = ['5.4.21', FALSE];
$data[] = ['5.5.9', FALSE];
$data[] = ['5.5.20', FALSE];
$data[] = ['5.5.21', TRUE];
$data[] = ['5.5.30', TRUE];
$data[] = ['5.6.2', FALSE];
$data[] = ['5.6.5', TRUE];
$data[] = ['5.5.21', TRUE];
return $data;
}
}

View file

@ -0,0 +1,120 @@
<?php
namespace Drupal\Tests\system\Unit\Transliteration;
use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Tests\UnitTestCase;
use Drupal\Component\Transliteration\PhpTransliteration;
use Drupal\system\MachineNameController;
use Prophecy\Argument;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
/**
* Tests that the machine name controller can transliterate strings as expected.
*
* @group system
*/
class MachineNameControllerTest extends UnitTestCase {
/**
* The machine name controller.
*
* @var \Drupal\system\MachineNameController
*/
protected $machineNameController;
/**
* The CSRF token generator.
*
* @var \Drupal\Core\Access\CsrfTokenGenerator
*/
protected $tokenGenerator;
protected function setUp() {
parent::setUp();
// Create the machine name controller.
$this->tokenGenerator = $this->prophesize(CsrfTokenGenerator::class);
$this->tokenGenerator->validate(Argument::cetera())->will(function ($args) {
return $args[0] === 'token-' . $args[1];
});
$this->machineNameController = new MachineNameController(new PhpTransliteration(), $this->tokenGenerator->reveal());
}
/**
* Data provider for testMachineNameController().
*
* @see testMachineNameController()
*
* @return array
* An array containing:
* - An array of request parameters.
* - The expected content of the JSONresponse.
*/
public function providerTestMachineNameController() {
$valid_data = array(
array(array('text' => 'Bob', 'langcode' => 'en'), '"Bob"'),
array(array('text' => 'Bob', 'langcode' => 'en', 'lowercase' => TRUE), '"bob"'),
array(array('text' => 'Bob', 'langcode' => 'en', 'replace' => 'Alice', 'replace_pattern' => 'Bob'), '"Alice"'),
array(array('text' => 'Bob', 'langcode' => 'en', 'replace' => 'Alice', 'replace_pattern' => 'Tom'), '"Bob"'),
array(array('text' => 'Äwesome', 'langcode' => 'en', 'lowercase' => TRUE), '"awesome"'),
array(array('text' => 'Äwesome', 'langcode' => 'de', 'lowercase' => TRUE), '"aewesome"'),
// Tests special characters replacement in the input text.
array(array('text' => 'B?!"@\/-ob@e', 'langcode' => 'en', 'lowercase' => TRUE, 'replace' => '_', 'replace_pattern' => '[^a-z0-9_.]+'), '"b_ob_e"'),
// Tests @ character in the replace_pattern regex.
array(array('text' => 'Bob@e\0', 'langcode' => 'en', 'lowercase' => TRUE, 'replace' => '_', 'replace_pattern' => '[^a-z0-9_.@]+'), '"bob@e_0"'),
// Tests null byte in the replace_pattern regex.
array(array('text' => 'Bob', 'langcode' => 'en', 'lowercase' => TRUE, 'replace' => 'fail()', 'replace_pattern' => ".*@e\0"), '"bob"'),
array(array('text' => 'Bob@e', 'langcode' => 'en', 'lowercase' => TRUE, 'replace' => 'fail()', 'replace_pattern' => ".*@e\0"), '"fail()"'),
);
$valid_data = array_map(function ($data) {
if (isset($data[0]['replace_pattern'])) {
$data[0]['replace_token'] = 'token-' . $data[0]['replace_pattern'];
}
return $data;
}, $valid_data);
return $valid_data;
}
/**
* Tests machine name controller's transliteration functionality.
*
* @param array $request_params
* An array of request parameters.
* @param $expected_content
* The expected content of the JSONresponse.
*
* @see \Drupal\system\MachineNameController::transliterate()
*
* @dataProvider providerTestMachineNameController
*/
public function testMachineNameController(array $request_params, $expected_content) {
$request = Request::create('', 'GET', $request_params);
$json = $this->machineNameController->transliterate($request);
$this->assertEquals($expected_content, $json->getContent());
}
/**
* Tests the pattern validation.
*/
public function testMachineNameControllerWithInvalidReplacePattern() {
$request = Request::create('', 'GET', ['text' => 'Bob', 'langcode' => 'en', 'replace' => 'Alice', 'replace_pattern' => 'Bob', 'replace_token' => 'invalid']);
$this->setExpectedException(AccessDeniedHttpException::class, "Invalid 'replace_token' query parameter.");
$this->machineNameController->transliterate($request);
}
/**
* Tests the pattern validation with a missing token.
*/
public function testMachineNameControllerWithMissingToken() {
$request = Request::create('', 'GET', ['text' => 'Bob', 'langcode' => 'en', 'replace' => 'Alice', 'replace_pattern' => 'Bob']);
$this->setExpectedException(AccessDeniedHttpException::class, "Missing 'replace_token' query parameter.");
$this->machineNameController->transliterate($request);
}
}