Update to Drupal 8.2.0. For more information, see https://www.drupal.org/project/drupal/releases/8.2.0

This commit is contained in:
Pantheon Automation 2016-10-06 15:16:20 -07:00 committed by Greg Anderson
parent 2f563ab520
commit f1c8716f57
1732 changed files with 52334 additions and 11780 deletions

View file

@ -1,5 +1,5 @@
uuid: ''
name: ''
name: 'Drupal'
mail: ''
slogan: ''
page:

View file

@ -5,7 +5,7 @@
.container-inline div,
.container-inline label {
display: inline;
display: inline-block;
}
/* Details contents always need to be rendered as block. */
.container-inline .details-wrapper {

View file

@ -0,0 +1,12 @@
id: d7_system_authorize
migration_tags:
- Drupal 7
source:
plugin: variable
variables:
- authorize_filetransfer_default
process:
filetransfer_default: authorize_filetransfer_default
destination:
plugin: config
config_name: system.authorize

View file

@ -0,0 +1,15 @@
id: d7_system_cron
label: Drupal 7 cron settings
migration_tags:
- Drupal 7
source:
plugin: variable
variables:
- cron_threshold_warning
- cron_threshold_error
process:
'threshold/requirements_warning': cron_threshold_warning
'threshold/requirements_error': cron_threshold_error
destination:
plugin: config
config_name: system.cron

View file

@ -0,0 +1,22 @@
id: d7_system_date
migration_tags:
- Drupal 7
source:
plugin: variable
variables:
- site_default_country
- date_first_day
- date_default_timezone
- configurable_timezones
- empty_timezone_message
- user_default_timezone
process:
'country/default': site_default_country
first_day: date_first_day
'timezone/default': date_default_timezone
'timezone/user/configurable': configurable_timezones
'timezone/user/warn': empty_timezone_message
'timezone/user/default': user_default_timezone
destination:
plugin: config
config_name: system.date

View file

@ -0,0 +1,20 @@
id: d7_system_file
label: Drupal 7 file system configuration
migration_tags:
- Drupal 7
source:
plugin: variable
variables:
- allow_insecure_uploads
- file_temporary_path
process:
allow_insecure_uploads:
plugin: static_map
source: allow_insecure_uploads
map:
0: FALSE
1: TRUE
'path/temporary': file_temporary_path
destination:
plugin: config
config_name: system.file

View file

@ -0,0 +1,17 @@
id: d7_system_mail
migration_tags:
- Drupal 7
source:
plugin: variable
variables:
- mail_system
process:
'interface/default':
plugin: static_map
source: 'mail_system/default-system'
map:
DefaultMailSystem: php_mail
MailTestCase: test_mail_collector
destination:
plugin: config
config_name: system.mail

View file

@ -0,0 +1,19 @@
id: d7_system_performance
label: Drupal 7 performance configuration
migration_tags:
- Drupal 7
source:
plugin: variable
variables:
- preprocess_css
- preprocess_js
- cache_lifetime
- page_compression
process:
'css/preprocess': preprocess_css
'js/preprocess': preprocess_js
'cache/page/max_age': cache_lifetime
'response/gzip': page_compression
destination:
plugin: config
config_name: system.performance

View file

@ -1,7 +1,8 @@
id: d6_system_image
id: system_image
label: Image toolkit configuration
migration_tags:
- Drupal 6
- Drupal 7
source:
plugin: variable
variables:

View file

@ -1,7 +1,8 @@
id: d6_system_image_gd
id: system_image_gd
label: Image quality configuration
migration_tags:
- Drupal 6
- Drupal 7
source:
plugin: variable
variables:

View file

@ -1,7 +1,8 @@
id: d6_system_logging
id: system_logging
label: System logging
migration_tags:
- Drupal 6
- Drupal 7
source:
plugin: variable
variables:

View file

@ -1,7 +1,8 @@
id: d6_system_maintenance
id: system_maintenance
label: Maintenance page configuration
migration_tags:
- Drupal 6
- Drupal 7
source:
plugin: variable
variables:

View file

@ -1,7 +1,8 @@
id: d6_system_rss
id: system_rss
label: RSS configuration
migration_tags:
- Drupal 6
- Drupal 7
source:
plugin: variable
variables:

View file

@ -1,7 +1,8 @@
id: d6_system_site
id: system_site
label: Site configuration
migration_tags:
- Drupal 6
- Drupal 7
source:
plugin: variable
constants:

View file

@ -0,0 +1,52 @@
<?php
namespace Drupal\system\Controller;
use Drupal\Core\Access\CsrfRequestHeaderAccessCheck;
use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
/**
* Returns responses for CSRF token routes.
*/
class CsrfTokenController implements ContainerInjectionInterface {
/**
* The CSRF token generator.
*
* @var \Drupal\Core\Access\CsrfTokenGenerator
*/
protected $tokenGenerator;
/**
* Constructs a new CsrfTokenController object.
*
* @param \Drupal\Core\Access\CsrfTokenGenerator $token_generator
* The CSRF token generator.
*/
public function __construct(CsrfTokenGenerator $token_generator) {
$this->tokenGenerator = $token_generator;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('csrf_token')
);
}
/**
* Returns a CSRF protecting session token.
*
* @return \Symfony\Component\HttpFoundation\Response
* The response object.
*/
public function csrfToken() {
return new Response($this->tokenGenerator->get(CsrfRequestHeaderAccessCheck::TOKEN_KEY), 200, ['Content-Type' => 'text/plain']);
}
}

View file

@ -74,7 +74,7 @@ class SystemController extends ControllerBase {
* The form builder.
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
* The theme handler.
* @param \Drupal\Core\Menu\MenuLinkTreeInterface
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_link_tree
* The menu link tree service.
*/
public function __construct(SystemManager $systemManager, QueryFactory $queryFactory, ThemeAccessCheck $theme_access, FormBuilderInterface $form_builder, ThemeHandlerInterface $theme_handler, MenuLinkTreeInterface $menu_link_tree) {
@ -307,7 +307,7 @@ class SystemController extends ControllerBase {
$theme->notes[] = $this->t('default theme');
}
if ($theme->is_admin) {
$theme->notes[] = $this->t('admin theme');
$theme->notes[] = $this->t('administration theme');
}
// Sort installed and uninstalled themes into their own groups.

View file

@ -60,7 +60,7 @@ class ThemeController extends ControllerBase {
* the token is invalid.
*/
public function uninstall(Request $request) {
$theme = $request->get('theme');
$theme = $request->query->get('theme');
$config = $this->config('system.theme');
if (isset($theme)) {
@ -102,7 +102,7 @@ class ThemeController extends ControllerBase {
* the token is invalid.
*/
public function install(Request $request) {
$theme = $request->get('theme');
$theme = $request->query->get('theme');
if (isset($theme)) {
try {

View file

@ -0,0 +1,256 @@
<?php
namespace Drupal\system\Form;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Provides a form removing module content entities data before uninstallation.
*/
class PrepareModulesEntityUninstallForm extends ConfirmFormBase {
/**
* The entity type ID of the entities to delete.
*
* @var string
*/
protected $entityTypeId;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Constructs a PrepareModulesEntityUninstallForm object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'system_prepare_modules_entity_uninstall';
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
$entity_type = $this->entityTypeManager->getDefinition($this->entityTypeId);
return $this->t('Are you sure you want to delete all @entity_type_plural?', ['@entity_type_plural' => $entity_type->getPluralLabel()]);
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->t('This action cannot be undone.<br />Make a backup of your database if you want to be able to restore these items.');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
$entity_type = $this->entityTypeManager->getDefinition($this->entityTypeId);
return $this->t('Delete all @entity_type_plural', ['@entity_type_plural' => $entity_type->getPluralLabel()]);
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return Url::fromRoute('system.modules_uninstall');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL) {
$this->entityTypeId = $entity_type_id;
if (!$this->entityTypeManager->hasDefinition($this->entityTypeId)) {
throw new NotFoundHttpException();
}
$form = parent::buildForm($form, $form_state);
$storage = $this->entityTypeManager->getStorage($entity_type_id);
$count = $storage->getQuery()->count()->execute();
$form['entity_type_id'] = [
'#type' => 'value',
'#value' => $entity_type_id,
];
// Display a list of the 10 entity labels, if possible.
$entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
if ($count == 0) {
$form['total'] = [
'#markup' => $this->t(
'There are 0 @entity_type_plural to delete.',
['@entity_type_plural' => $entity_type->getPluralLabel()]
),
];
}
elseif ($entity_type->hasKey('label')) {
$recent_entity_ids = $storage->getQuery()
->sort($entity_type->getKey('id'), 'DESC')
->pager(10)
->execute();
$recent_entities = $storage->loadMultiple($recent_entity_ids);
$labels = [];
foreach ($recent_entities as $entity) {
$labels[] = $entity->label();
}
if ($labels) {
$form['recent_entity_labels'] = [
'#theme' => 'item_list',
'#items' => $labels,
];
$more_count = $count - count($labels);
$form['total'] = [
'#markup' => $this->formatPlural(
$more_count,
'And <strong>@count</strong> more @entity_type_singular.',
'And <strong>@count</strong> more @entity_type_plural.',
[
'@entity_type_singular' => $entity_type->getSingularLabel(),
'@entity_type_plural' => $entity_type->getPluralLabel(),
]
),
'#access' => (bool) $more_count,
];
}
}
else {
$form['total'] = [
'#markup' => $this->formatPlural(
$count,
'This will delete <strong>@count</strong> @entity_type_singular.',
'This will delete <strong>@count</strong> @entity_type_plural.',
[
'@entity_type_singular' => $entity_type->getSingularLabel(),
'@entity_type_plural' => $entity_type->getPluralLabel(),
]
)
];
}
$form['description']['#prefix'] = '<p>';
$form['description']['#suffix'] = '</p>';
$form['description']['#weight'] = 5;
// Only show the delete button if there are entities to delete.
$form['actions']['submit']['#access'] = (bool) $count;
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$entity_type_id = $form_state->getValue('entity_type_id');
$entity_type_plural = $this->entityTypeManager->getDefinition($entity_type_id)->getPluralLabel();
$batch = [
'title' => t('Deleting @entity_type_plural', [
'@entity_type_plural' => $entity_type_plural,
]),
'operations' => [
[
[__CLASS__, 'deleteContentEntities'], [$entity_type_id],
],
],
'finished' => [__CLASS__, 'moduleBatchFinished'],
'progress_message' => '',
];
batch_set($batch);
}
/**
* Deletes the content entities of the specified entity type.
*
* @param string $entity_type_id
* The entity type ID from which data will be deleted.
* @param array|\ArrayAccess $context
* The batch context array, passed by reference.
*
* @internal
* This batch callback is only meant to be used by this form.
*/
public static function deleteContentEntities($entity_type_id, &$context) {
$storage = \Drupal::entityTypeManager()->getStorage($entity_type_id);
// Set the entity type ID in the results array so we can access it in the
// batch finished callback.
$context['results']['entity_type_id'] = $entity_type_id;
if (!isset($context['sandbox']['progress'])) {
$context['sandbox']['progress'] = 0;
$context['sandbox']['max'] = $storage->getQuery()->count()->execute();
}
$entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
$entity_ids = $storage->getQuery()
->sort($entity_type->getKey('id'), 'ASC')
->range(0, 10)
->execute();
if ($entities = $storage->loadMultiple($entity_ids)) {
$storage->delete($entities);
}
// Sometimes deletes cause secondary deletes. For example, deleting a
// taxonomy term can cause it's children to be be deleted too.
$context['sandbox']['progress'] = $context['sandbox']['max'] - $storage->getQuery()->count()->execute();
// Inform the batch engine that we are not finished and provide an
// estimation of the completion level we reached.
if (count($entity_ids) > 0 && $context['sandbox']['progress'] != $context['sandbox']['max']) {
$context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
$context['message'] = t('Deleting items... Completed @percentage% (@current of @total).', ['@percentage' => round(100 * $context['sandbox']['progress'] / $context['sandbox']['max']), '@current' => $context['sandbox']['progress'], '@total' => $context['sandbox']['max']]);
}
else {
$context['finished'] = 1;
}
}
/**
* Implements callback_batch_finished().
*
* Finishes the module batch, redirect to the uninstall page and output the
* successful data deletion message.
*/
public static function moduleBatchFinished($success, $results, $operations) {
$entity_type_plural = \Drupal::entityTypeManager()->getDefinition($results['entity_type_id'])->getPluralLabel();
drupal_set_message(t('All @entity_type_plural have been deleted.', ['@entity_type_plural' => $entity_type_plural]));
return new RedirectResponse(Url::fromRoute('system.modules_uninstall')->setAbsolute()->toString());
}
}

View file

@ -152,9 +152,8 @@ class ThemeSettingsForm extends ConfigFormBase {
$form['theme_settings'] = array(
'#type' => 'details',
'#title' => t('Toggle display'),
'#title' => t('Page element display'),
'#open' => TRUE,
'#description' => t('Enable or disable the display of certain page elements.'),
);
foreach ($toggles as $name => $title) {
if ((!$theme) || in_array($name, $features)) {
@ -176,12 +175,12 @@ class ThemeSettingsForm extends ConfigFormBase {
if ((!$theme || in_array('logo', $features)) && $this->moduleHandler->moduleExists('file')) {
$form['logo'] = array(
'#type' => 'details',
'#title' => t('Logo image settings'),
'#title' => t('Logo image'),
'#open' => TRUE,
);
$form['logo']['default_logo'] = array(
'#type' => 'checkbox',
'#title' => t('Use the default logo supplied by the theme'),
'#title' => t('Use the logo supplied by the theme'),
'#default_value' => theme_get_setting('logo.use_default', $theme),
'#tree' => FALSE,
);
@ -210,9 +209,9 @@ class ThemeSettingsForm extends ConfigFormBase {
if (((!$theme) || in_array('favicon', $features)) && $this->moduleHandler->moduleExists('file')) {
$form['favicon'] = array(
'#type' => 'details',
'#title' => t('Shortcut icon settings'),
'#title' => t('Favicon'),
'#open' => TRUE,
'#description' => t("Your shortcut icon, or 'favicon', is displayed in the address bar and bookmarks of most browsers."),
'#description' => t("Your shortcut icon, or favicon, is displayed in the address bar and bookmarks of most browsers."),
'#states' => array(
// Hide the shortcut icon settings fieldset when shortcut icon display
// is disabled.
@ -223,7 +222,7 @@ class ThemeSettingsForm extends ConfigFormBase {
);
$form['favicon']['default_favicon'] = array(
'#type' => 'checkbox',
'#title' => t('Use the default shortcut icon supplied by the theme'),
'#title' => t('Use the favicon supplied by the theme'),
'#default_value' => theme_get_setting('favicon.use_default', $theme),
);
$form['favicon']['settings'] = array(
@ -242,7 +241,7 @@ class ThemeSettingsForm extends ConfigFormBase {
);
$form['favicon']['settings']['favicon_upload'] = array(
'#type' => 'file',
'#title' => t('Upload icon image'),
'#title' => t('Upload favicon image'),
'#description' => t("If you don't have direct file access to the server, use this field to upload your shortcut icon.")
);
}

View file

@ -105,8 +105,7 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
'#type' => 'textarea',
'#title' => $this->t('Pages'),
'#default_value' => $this->configuration['pages'],
'#description' => $this->t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %user for the current user's page and %user-wildcard for every user page. %front is the front page.", array(
'%user' => '/user',
'#description' => $this->t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. An example path is %user-wildcard for every user page. %front is the front page.", array(
'%user-wildcard' => '/user/*',
'%front' => '<front>',
)),

View file

@ -162,7 +162,7 @@ class BulkForm extends FieldPluginBase implements CacheableDependencyInterface {
*/
protected function defineOptions() {
$options = parent::defineOptions();
$options['action_title'] = array('default' => $this->t('With selection'));
$options['action_title'] = array('default' => $this->t('Action'));
$options['include_exclude'] = array(
'default' => 'exclude',
);
@ -271,7 +271,7 @@ class BulkForm extends FieldPluginBase implements CacheableDependencyInterface {
}
// Replace the form submit button label.
$form['actions']['submit']['#value'] = $this->t('Apply');
$form['actions']['submit']['#value'] = $this->t('Apply to selected items');
// Ensure a consistent container for filters/operations in the view header.
$form['header'] = array(
@ -380,7 +380,6 @@ class BulkForm extends FieldPluginBase implements CacheableDependencyInterface {
else {
// Don't display the message unless there are some elements affected and
// there is no confirmation form.
$count = count(array_filter($form_state->getValue($this->options['id'])));
if ($count) {
drupal_set_message($this->formatPlural($count, '%action was applied to @count item.', '%action was applied to @count items.', array(
'%action' => $action->label(),

View file

@ -33,61 +33,61 @@ class AjaxFormPageCacheTest extends AjaxTestBase {
* Create a simple form, then submit the form via AJAX to change to it.
*/
public function testSimpleAJAXFormValue() {
$this->drupalGet('ajax_forms_test_get_form');
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
$build_id_initial = $this->getFormBuildId();
$this->drupalGet('ajax_forms_test_get_form');
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
$build_id_initial = $this->getFormBuildId();
$edit = ['select' => 'green'];
$commands = $this->drupalPostAjaxForm(NULL, $edit, 'select');
$build_id_first_ajax = $this->getFormBuildId();
$this->assertNotEqual($build_id_initial, $build_id_first_ajax, 'Build id is changed in the simpletest-DOM on first AJAX submission');
$expected = [
'command' => 'update_build_id',
'old' => $build_id_initial,
'new' => $build_id_first_ajax,
];
$this->assertCommand($commands, $expected, 'Build id change command issued on first AJAX submission');
$edit = ['select' => 'green'];
$commands = $this->drupalPostAjaxForm(NULL, $edit, 'select');
$build_id_first_ajax = $this->getFormBuildId();
$this->assertNotEqual($build_id_initial, $build_id_first_ajax, 'Build id is changed in the simpletest-DOM on first AJAX submission');
$expected = [
'command' => 'update_build_id',
'old' => $build_id_initial,
'new' => $build_id_first_ajax,
];
$this->assertCommand($commands, $expected, 'Build id change command issued on first AJAX submission');
$edit = ['select' => 'red'];
$commands = $this->drupalPostAjaxForm(NULL, $edit, 'select');
$build_id_second_ajax = $this->getFormBuildId();
$this->assertNotEqual($build_id_first_ajax, $build_id_second_ajax, 'Build id changes on subsequent AJAX submissions');
$expected = [
'command' => 'update_build_id',
'old' => $build_id_first_ajax,
'new' => $build_id_second_ajax,
];
$this->assertCommand($commands, $expected, 'Build id change command issued on subsequent AJAX submissions');
$edit = ['select' => 'red'];
$commands = $this->drupalPostAjaxForm(NULL, $edit, 'select');
$build_id_second_ajax = $this->getFormBuildId();
$this->assertNotEqual($build_id_first_ajax, $build_id_second_ajax, 'Build id changes on subsequent AJAX submissions');
$expected = [
'command' => 'update_build_id',
'old' => $build_id_first_ajax,
'new' => $build_id_second_ajax,
];
$this->assertCommand($commands, $expected, 'Build id change command issued on subsequent AJAX submissions');
// Repeat the test sequence but this time with a page loaded from the cache.
$this->drupalGet('ajax_forms_test_get_form');
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
$build_id_from_cache_initial = $this->getFormBuildId();
$this->assertEqual($build_id_initial, $build_id_from_cache_initial, 'Build id is the same as on the first request');
// Repeat the test sequence but this time with a page loaded from the cache.
$this->drupalGet('ajax_forms_test_get_form');
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
$build_id_from_cache_initial = $this->getFormBuildId();
$this->assertEqual($build_id_initial, $build_id_from_cache_initial, 'Build id is the same as on the first request');
$edit = ['select' => 'green'];
$commands = $this->drupalPostAjaxForm(NULL, $edit, 'select');
$build_id_from_cache_first_ajax = $this->getFormBuildId();
$this->assertNotEqual($build_id_from_cache_initial, $build_id_from_cache_first_ajax, 'Build id is changed in the simpletest-DOM on first AJAX submission');
$this->assertNotEqual($build_id_first_ajax, $build_id_from_cache_first_ajax, 'Build id from first user is not reused');
$expected = [
'command' => 'update_build_id',
'old' => $build_id_from_cache_initial,
'new' => $build_id_from_cache_first_ajax,
];
$this->assertCommand($commands, $expected, 'Build id change command issued on first AJAX submission');
$edit = ['select' => 'green'];
$commands = $this->drupalPostAjaxForm(NULL, $edit, 'select');
$build_id_from_cache_first_ajax = $this->getFormBuildId();
$this->assertNotEqual($build_id_from_cache_initial, $build_id_from_cache_first_ajax, 'Build id is changed in the simpletest-DOM on first AJAX submission');
$this->assertNotEqual($build_id_first_ajax, $build_id_from_cache_first_ajax, 'Build id from first user is not reused');
$expected = [
'command' => 'update_build_id',
'old' => $build_id_from_cache_initial,
'new' => $build_id_from_cache_first_ajax,
];
$this->assertCommand($commands, $expected, 'Build id change command issued on first AJAX submission');
$edit = ['select' => 'red'];
$commands = $this->drupalPostAjaxForm(NULL, $edit, 'select');
$build_id_from_cache_second_ajax = $this->getFormBuildId();
$this->assertNotEqual($build_id_from_cache_first_ajax, $build_id_from_cache_second_ajax, 'Build id changes on subsequent AJAX submissions');
$expected = [
'command' => 'update_build_id',
'old' => $build_id_from_cache_first_ajax,
'new' => $build_id_from_cache_second_ajax,
];
$this->assertCommand($commands, $expected, 'Build id change command issued on subsequent AJAX submissions');
}
$edit = ['select' => 'red'];
$commands = $this->drupalPostAjaxForm(NULL, $edit, 'select');
$build_id_from_cache_second_ajax = $this->getFormBuildId();
$this->assertNotEqual($build_id_from_cache_first_ajax, $build_id_from_cache_second_ajax, 'Build id changes on subsequent AJAX submissions');
$expected = [
'command' => 'update_build_id',
'old' => $build_id_from_cache_first_ajax,
'new' => $build_id_from_cache_second_ajax,
];
$this->assertCommand($commands, $expected, 'Build id change command issued on subsequent AJAX submissions');
}
/**
* Tests a form that uses an #ajax callback.

View file

@ -1,296 +0,0 @@
<?php
namespace Drupal\system\Tests\Asset;
use Drupal\Core\Asset\Exception\InvalidLibrariesExtendSpecificationException;
use Drupal\Core\Asset\Exception\InvalidLibrariesOverrideSpecificationException;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the library discovery and library discovery parser.
*
* @group Render
*/
class LibraryDiscoveryIntegrationTest extends KernelTestBase {
/**
* The library discovery service.
*
* @var \Drupal\Core\Asset\LibraryDiscoveryInterface
*/
protected $libraryDiscovery;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->container->get('theme_installer')->install(['test_theme', 'classy']);
$this->libraryDiscovery = $this->container->get('library.discovery');
}
/**
* Tests that hook_library_info is invoked and the cache is cleared.
*/
public function testHookLibraryInfoByTheme() {
// Activate test_theme and verify that the library 'kitten' is added using
// hook_library_info_alter().
$this->activateTheme('test_theme');
$this->assertTrue($this->libraryDiscovery->getLibraryByName('test_theme', 'kitten'));
// Now make classy the active theme and assert that library is not added.
$this->activateTheme('classy');
$this->assertFalse($this->libraryDiscovery->getLibraryByName('test_theme', 'kitten'));
}
/**
* Tests that libraries-override are applied to library definitions.
*/
public function testLibrariesOverride() {
// Assert some classy libraries that will be overridden or removed.
$this->activateTheme('classy');
$this->assertAssetInLibrary('core/themes/classy/css/components/button.css', 'classy', 'base', 'css');
$this->assertAssetInLibrary('core/themes/classy/css/components/collapse-processed.css', 'classy', 'base', 'css');
$this->assertAssetInLibrary('core/themes/classy/css/components/container-inline.css', 'classy', 'base', 'css');
$this->assertAssetInLibrary('core/themes/classy/css/components/details.css', 'classy', 'base', 'css');
$this->assertAssetInLibrary('core/themes/classy/css/components/dialog.css', 'classy', 'dialog', 'css');
// Confirmatory assert on core library to be removed.
$this->assertTrue($this->libraryDiscovery->getLibraryByName('core', 'drupal.progress'), 'Confirmatory test on "core/drupal.progress"');
// Activate test theme that defines libraries overrides.
$this->activateTheme('test_theme');
// Assert that entire library was correctly overridden.
$this->assertEqual($this->libraryDiscovery->getLibraryByName('core', 'drupal.collapse'), $this->libraryDiscovery->getLibraryByName('test_theme', 'collapse'), 'Entire library correctly overridden.');
// Assert that classy library assets were correctly overridden or removed.
$this->assertNoAssetInLibrary('core/themes/classy/css/components/button.css', 'classy', 'base', 'css');
$this->assertNoAssetInLibrary('core/themes/classy/css/components/collapse-processed.css', 'classy', 'base', 'css');
$this->assertNoAssetInLibrary('core/themes/classy/css/components/container-inline.css', 'classy', 'base', 'css');
$this->assertNoAssetInLibrary('core/themes/classy/css/components/details.css', 'classy', 'base', 'css');
$this->assertNoAssetInLibrary('core/themes/classy/css/components/dialog.css', 'classy', 'dialog', 'css');
$this->assertAssetInLibrary('core/modules/system/tests/themes/test_theme/css/my-button.css', 'classy', 'base', 'css');
$this->assertAssetInLibrary('core/modules/system/tests/themes/test_theme/css/my-collapse-processed.css', 'classy', 'base', 'css');
$this->assertAssetInLibrary('themes/my_theme/css/my-container-inline.css', 'classy', 'base', 'css');
$this->assertAssetInLibrary('themes/my_theme/css/my-details.css', 'classy', 'base', 'css');
// Assert that entire library was correctly removed.
$this->assertFalse($this->libraryDiscovery->getLibraryByName('core', 'drupal.progress'), 'Entire library correctly removed.');
// Assert that overridden library asset still retains attributes.
$library = $this->libraryDiscovery->getLibraryByName('core', 'jquery');
foreach ($library['js'] as $definition) {
if ($definition['data'] == 'core/modules/system/tests/themes/test_theme/js/collapse.js') {
$this->assertTrue($definition['minified'] && $definition['weight'] == -20, 'Previous attributes retained');
break;
}
}
}
/**
* Tests libraries-override on drupalSettings.
*/
public function testLibrariesOverrideDrupalSettings() {
// Activate test theme that attempts to override drupalSettings.
$this->activateTheme('test_theme_libraries_override_with_drupal_settings');
// Assert that drupalSettings cannot be overridden and throws an exception.
try {
$this->libraryDiscovery->getLibraryByName('core', 'drupal.ajax');
$this->fail('Throw Exception when trying to override drupalSettings');
}
catch (InvalidLibrariesOverrideSpecificationException $e) {
$expected_message = 'drupalSettings may not be overridden in libraries-override. Trying to override core/drupal.ajax/drupalSettings. Use hook_library_info_alter() instead.';
$this->assertEqual($e->getMessage(), $expected_message, 'Throw Exception when trying to override drupalSettings');
}
}
/**
* Tests libraries-override on malformed assets.
*/
public function testLibrariesOverrideMalformedAsset() {
// Activate test theme that overrides with a malformed asset.
$this->activateTheme('test_theme_libraries_override_with_invalid_asset');
// Assert that improperly formed asset "specs" throw an exception.
try {
$this->libraryDiscovery->getLibraryByName('core', 'drupal.dialog');
$this->fail('Throw Exception when specifying invalid override');
}
catch (InvalidLibrariesOverrideSpecificationException $e) {
$expected_message = 'Library asset core/drupal.dialog/css is not correctly specified. It should be in the form "extension/library_name/sub_key/path/to/asset.js".';
$this->assertEqual($e->getMessage(), $expected_message, 'Throw Exception when specifying invalid override');
}
}
/**
* Tests library assets with other ways for specifying paths.
*/
public function testLibrariesOverrideOtherAssetLibraryNames() {
// Activate a test theme that defines libraries overrides on other types of
// assets.
$this->activateTheme('test_theme');
// Assert Drupal-relative paths.
$this->assertAssetInLibrary('themes/my_theme/css/dropbutton.css', 'core', 'drupal.dropbutton', 'css');
// Assert stream wrapper paths.
$this->assertAssetInLibrary('public://my_css/vertical-tabs.css', 'core', 'drupal.vertical-tabs', 'css');
// Assert a protocol-relative URI.
$this->assertAssetInLibrary('//my-server/my_theme/css/jquery_ui.css', 'core', 'jquery.ui', 'css');
// Assert an absolute URI.
$this->assertAssetInLibrary('http://example.com/my_theme/css/farbtastic.css', 'core', 'jquery.farbtastic', 'css');
}
/**
* Tests that base theme libraries-override still apply in sub themes.
*/
public function testBaseThemeLibrariesOverrideInSubTheme() {
// Activate a test theme that has subthemes.
$this->activateTheme('test_subtheme');
// Assert that libraries-override specified in the base theme still applies
// in the sub theme.
$this->assertNoAssetInLibrary('core/misc/dialog/dialog.js', 'core', 'drupal.dialog', 'js');
$this->assertAssetInLibrary('core/modules/system/tests/themes/test_basetheme/css/farbtastic.css', 'core', 'jquery.farbtastic', 'css');
}
/**
* Tests libraries-extend.
*/
public function testLibrariesExtend() {
// Activate classy themes and verify the libraries are not extended.
$this->activateTheme('classy');
$this->assertNoAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/css/extend_1.css', 'classy', 'book-navigation', 'css');
$this->assertNoAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/js/extend_1.js', 'classy', 'book-navigation', 'js');
$this->assertNoAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/css/extend_2.css', 'classy', 'book-navigation', 'css');
// Activate the theme that extends the book-navigation library in classy.
$this->activateTheme('test_theme_libraries_extend');
$this->assertAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/css/extend_1.css', 'classy', 'book-navigation', 'css');
$this->assertAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/js/extend_1.js', 'classy', 'book-navigation', 'js');
$this->assertAssetInLibrary('core/modules/system/tests/themes/test_theme_libraries_extend/css/extend_2.css', 'classy', 'book-navigation', 'css');
// Activate a sub theme and confirm that it inherits the library assets
// extended in the base theme as well as its own.
$this->assertNoAssetInLibrary('core/modules/system/tests/themes/test_basetheme/css/base-libraries-extend.css', 'classy', 'base', 'css');
$this->assertNoAssetInLibrary('core/modules/system/tests/themes/test_subtheme/css/sub-libraries-extend.css', 'classy', 'base', 'css');
$this->activateTheme('test_subtheme');
$this->assertAssetInLibrary('core/modules/system/tests/themes/test_basetheme/css/base-libraries-extend.css', 'classy', 'base', 'css');
$this->assertAssetInLibrary('core/modules/system/tests/themes/test_subtheme/css/sub-libraries-extend.css', 'classy', 'base', 'css');
// Activate test theme that extends with a non-existent library. An
// exception should be thrown.
$this->activateTheme('test_theme_libraries_extend');
try {
$this->libraryDiscovery->getLibraryByName('core', 'drupal.dialog');
$this->fail('Throw Exception when specifying non-existent libraries-extend.');
}
catch (InvalidLibrariesExtendSpecificationException $e) {
$expected_message = 'The specified library "test_theme_libraries_extend/non_existent_library" does not exist.';
$this->assertEqual($e->getMessage(), $expected_message, 'Throw Exception when specifying non-existent libraries-extend.');
}
// Also, test non-string libraries-extend. An exception should be thrown.
$this->container->get('theme_installer')->install(['test_theme']);
try {
$this->libraryDiscovery->getLibraryByName('test_theme', 'collapse');
$this->fail('Throw Exception when specifying non-string libraries-extend.');
}
catch (InvalidLibrariesExtendSpecificationException $e) {
$expected_message = 'The libraries-extend specification for each library must be a list of strings.';
$this->assertEqual($e->getMessage(), $expected_message, 'Throw Exception when specifying non-string libraries-extend.');
}
}
/**
* Activates a specified theme.
*
* Installs the theme if not already installed and makes it the active theme.
*
* @param string $theme_name
* The name of the theme to be activated.
*/
protected function activateTheme($theme_name) {
$this->container->get('theme_installer')->install([$theme_name]);
/** @var \Drupal\Core\Theme\ThemeInitializationInterface $theme_initializer */
$theme_initializer = $this->container->get('theme.initialization');
/** @var \Drupal\Core\Theme\ThemeManagerInterface $theme_manager */
$theme_manager = $this->container->get('theme.manager');
$theme_manager->setActiveTheme($theme_initializer->getActiveThemeByName($theme_name));
$this->libraryDiscovery->clearCachedDefinitions();
// Assert message.
$this->pass(sprintf('Activated theme "%s"', $theme_name));
}
/**
* Asserts that the specified asset is in the given library.
*
* @param string $asset
* The asset file with the path for the file.
* @param string $extension
* The extension in which the $library is defined.
* @param string $library_name
* Name of the library.
* @param mixed $sub_key
* The library sub key where the given asset is defined.
* @param string $message
* (optional) A message to display with the assertion.
*
* @return bool
* TRUE if the specified asset is found in the library.
*/
protected function assertAssetInLibrary($asset, $extension, $library_name, $sub_key, $message = NULL) {
if (!isset($message)) {
$message = sprintf('Asset %s found in library "%s/%s"', $asset, $extension, $library_name);
}
$library = $this->libraryDiscovery->getLibraryByName($extension, $library_name);
foreach ($library[$sub_key] as $definition) {
if ($asset == $definition['data']) {
return $this->pass($message);
}
}
return $this->fail($message);
}
/**
* Asserts that the specified asset is not in the given library.
*
* @param string $asset
* The asset file with the path for the file.
* @param string $extension
* The extension in which the $library_name is defined.
* @param string $library_name
* Name of the library.
* @param mixed $sub_key
* The library sub key where the given asset is defined.
* @param string $message
* (optional) A message to display with the assertion.
*
* @return bool
* TRUE if the specified asset is not found in the library.
*/
protected function assertNoAssetInLibrary($asset, $extension, $library_name, $sub_key, $message = NULL) {
if (!isset($message)) {
$message = sprintf('Asset %s not found in library "%s/%s"', $asset, $extension, $library_name);
}
$library = $this->libraryDiscovery->getLibraryByName($extension, $library_name);
foreach ($library[$sub_key] as $definition) {
if ($asset == $definition['data']) {
return $this->fail($message);
}
}
return $this->pass($message);
}
}

View file

@ -1,195 +0,0 @@
<?php
namespace Drupal\system\Tests\Asset;
use Drupal\simpletest\KernelTestBase;
/**
* Tests that the asset files for all core libraries exist.
*
* This test also changes the active theme to each core theme to verify
* the libraries after theme-level libraries-override and libraries-extend are
* applied.
*
* @group Asset
*/
class ResolvedLibraryDefinitionsFilesMatchTest extends KernelTestBase {
/**
* The theme handler.
*
* @var \Drupal\Core\Extension\ThemeHandlerInterface
*/
protected $themeHandler;
/**
* The theme initialization.
*
* @var \Drupal\Core\Theme\ThemeInitializationInterface
*/
protected $themeInitialization;
/**
* The theme manager.
*
* @var \Drupal\Core\Theme\ThemeManagerInterface
*/
protected $themeManager;
/**
* The library discovery service.
*
* @var \Drupal\Core\Asset\LibraryDiscoveryInterface
*/
protected $libraryDiscovery;
/**
* A list of all core modules.
*
* @var string[]
*/
protected $allModules;
/**
* A list of all core themes.
*
* We hardcode this because test themes don't use a 'package' or 'hidden' key
* so we don't have a good way of filtering to only get "real" themes.
*
* @var string[]
*/
protected $allThemes = [
'bartik',
'classy',
'seven',
'stable',
'stark',
];
/**
* A list of libraries to skip checking, in the format extension/library_name.
*
* @var string[]
*/
protected $librariesToSkip = [
// Locale has a "dummy" library that does not actually exist.
'locale/translations',
];
/**
* A list of all paths that have been checked.
*
* @var array[]
*/
protected $pathsChecked;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->themeHandler = $this->container->get('theme_handler');
$this->themeInitialization = $this->container->get('theme.initialization');
$this->themeManager = $this->container->get('theme.manager');
$this->libraryDiscovery = $this->container->get('library.discovery');
// Install all core themes.
sort($this->allThemes);
$this->container->get('theme_installer')->install($this->allThemes);
// Enable all core modules.
$all_modules = system_rebuild_module_data();
$all_modules = array_filter($all_modules, function ($module) {
// Filter contrib, hidden, already enabled modules and modules in the
// Testing package.
if ($module->origin !== 'core' || !empty($module->info['hidden']) || $module->status == TRUE || $module->info['package'] == 'Testing') {
return FALSE;
}
return TRUE;
});
$this->allModules = array_keys($all_modules);
sort($this->allModules);
$this->enableModules($this->allModules);
}
/**
* Ensures that all core module and theme library files exist.
*/
public function testCoreLibraryCompleteness() {
// First verify all libraries with no active theme.
$this->verifyLibraryFilesExist($this->getAllLibraries());
// Then verify all libraries for each core theme. This may seem like
// overkill but themes can override and extend other extensions' libraries
// and these changes are only applied for the active theme.
foreach ($this->allThemes as $theme) {
$this->themeManager->setActiveTheme($this->themeInitialization->getActiveThemeByName($theme));
$this->libraryDiscovery->clearCachedDefinitions();
$this->verifyLibraryFilesExist($this->getAllLibraries());
}
}
/**
* Checks that all the library files exist.
*
* @param array[]
* An array of library definitions, keyed by extension, then by library, and
* so on.
*/
protected function verifyLibraryFilesExist($library_definitions) {
$root = \Drupal::root();
foreach ($library_definitions as $extension => $libraries) {
foreach ($libraries as $library_name => $library) {
if (in_array("$extension/$library_name", $this->librariesToSkip)) {
continue;
}
// Check that all the assets exist.
foreach (['css', 'js'] as $asset_type) {
foreach ($library[$asset_type] as $asset) {
$file = $asset['data'];
$path = $root . '/' . $file;
// Only check and assert each file path once.
if (!isset($this->pathsChecked[$path])) {
$this->assertTrue(is_file($path), "$file file referenced from the $extension/$library_name library exists.");
$this->pathsChecked[$path] = TRUE;
}
}
}
}
}
}
/**
* Gets all libraries for core and all installed modules.
*
* @return \Drupal\Core\Extension\Extension[]
*/
protected function getAllLibraries() {
$modules = \Drupal::moduleHandler()->getModuleList();
$extensions = $modules;
$module_list = array_keys($modules);
sort($module_list);
$this->assertEqual($this->allModules, $module_list, 'All core modules are installed.');
$themes = $this->themeHandler->listInfo();
$extensions += $themes;
$theme_list = array_keys($themes);
sort($theme_list);
$this->assertEqual($this->allThemes, $theme_list, 'All core themes are installed.');
$libraries['core'] = $this->libraryDiscovery->getLibrariesByExtension('core');
$root = \Drupal::root();
foreach ($extensions as $extension_name => $extension) {
$library_file = $extension->getPath() . '/' . $extension_name . '.libraries.yml';
if (is_file($root . '/' . $library_file)) {
$libraries[$extension_name] = $this->libraryDiscovery->getLibrariesByExtension($extension_name);
}
}
return $libraries;
}
}

View file

@ -1,61 +0,0 @@
<?php
namespace Drupal\system\Tests\Bootstrap;
use Drupal\simpletest\KernelTestBase;
/**
* Tests that drupal_get_filename() works correctly.
*
* @group Bootstrap
*/
class GetFilenameUnitTest extends KernelTestBase {
/**
* Tests that drupal_get_filename() works when the file is not in database.
*/
function testDrupalGetFilename() {
// drupal_get_profile() is using obtaining the profile from state if the
// install_state global is not set.
global $install_state;
$install_state['parameters']['profile'] = 'testing';
// Rebuild system.module.files state data.
// @todo Remove as part of https://www.drupal.org/node/2186491
drupal_static_reset('system_rebuild_module_data');
system_rebuild_module_data();
// Retrieving the location of a module.
$this->assertIdentical(drupal_get_filename('module', 'system'), 'core/modules/system/system.info.yml');
// Retrieving the location of a theme.
\Drupal::service('theme_handler')->install(array('stark'));
$this->assertIdentical(drupal_get_filename('theme', 'stark'), 'core/themes/stark/stark.info.yml');
// Retrieving the location of a theme engine.
$this->assertIdentical(drupal_get_filename('theme_engine', 'twig'), 'core/themes/engines/twig/twig.info.yml');
// Retrieving the location of a profile. Profiles are a special case with
// a fixed location and naming.
$this->assertIdentical(drupal_get_filename('profile', 'testing'), 'core/profiles/testing/testing.info.yml');
// Generate a non-existing module name.
$non_existing_module = uniqid("", TRUE);
// Set a custom error handler so we can ignore the file not found error.
set_error_handler(function($severity, $message, $file, $line) {
// Skip error handling if this is a "file not found" error.
if (strstr($message, 'is missing from the file system:')) {
\Drupal::state()->set('get_filename_test_triggered_error', TRUE);
return;
}
throw new \ErrorException($message, 0, $severity, $file, $line);
});
$this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for an item that does not exist returns NULL.');
$this->assertTrue(\Drupal::state()->get('get_filename_test_triggered_error'), 'Searching for an item that does not exist triggers an error.');
// Restore the original error handler.
restore_error_handler();
}
}

View file

@ -1,41 +0,0 @@
<?php
namespace Drupal\system\Tests\Bootstrap;
use Drupal\simpletest\KernelTestBase;
/**
* Tests that drupal_static() and drupal_static_reset() work.
*
* @group Bootstrap
*/
class ResettableStaticUnitTest extends KernelTestBase {
/**
* Tests drupal_static() function.
*
* Tests that a variable reference returned by drupal_static() gets reset when
* drupal_static_reset() is called.
*/
function testDrupalStatic() {
$name = __CLASS__ . '_' . __METHOD__;
$var = &drupal_static($name, 'foo');
$this->assertEqual($var, 'foo', 'Variable returned by drupal_static() was set to its default.');
// Call the specific reset and the global reset each twice to ensure that
// multiple resets can be issued without odd side effects.
$var = 'bar';
drupal_static_reset($name);
$this->assertEqual($var, 'foo', 'Variable was reset after first invocation of name-specific reset.');
$var = 'bar';
drupal_static_reset($name);
$this->assertEqual($var, 'foo', 'Variable was reset after second invocation of name-specific reset.');
$var = 'bar';
drupal_static_reset();
$this->assertEqual($var, 'foo', 'Variable was reset after first invocation of global reset.');
$var = 'bar';
drupal_static_reset();
$this->assertEqual($var, 'foo', 'Variable was reset after second invocation of global reset.');
}
}

View file

@ -1,207 +0,0 @@
<?php
namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\Apcu4Backend;
use Drupal\Core\Cache\ApcuBackend;
/**
* Tests the APCu cache backend.
*
* @group Cache
* @requires extension apcu
*/
class ApcuBackendUnitTest extends GenericCacheBackendUnitTestBase {
/**
* Get a list of failed requirements.
*
* This specifically bypasses checkRequirements because it fails tests. PHP 7
* does not have APCu and simpletest does not have a explicit "skip"
* functionality so to emulate it we override all test methods and explicitly
* pass when requirements are not met.
*
* @return array
*/
protected function getRequirements() {
$requirements = [];
if (!extension_loaded('apcu')) {
$requirements[] = 'APCu extension not found.';
}
else {
if (PHP_SAPI === 'cli' && !ini_get('apc.enable_cli')) {
$requirements[] = 'apc.enable_cli must be enabled to run this test.';
}
}
return $requirements;
}
/**
* Check if requirements fail.
*
* If the requirements fail the test method should return immediately instead
* of running any tests. Messages will be output to display why the test was
* skipped.
*/
protected function requirementsFail() {
$requirements = $this->getRequirements();
if (!empty($requirements)) {
foreach ($requirements as $message) {
$this->pass($message);
}
return TRUE;
}
return FALSE;
}
/**
* {@inheritdoc}
*/
protected function createCacheBackend($bin) {
if (version_compare(phpversion('apcu'), '5.0.0', '>=')) {
return new ApcuBackend($bin, $this->databasePrefix, \Drupal::service('cache_tags.invalidator.checksum'));
}
else {
return new Apcu4Backend($bin, $this->databasePrefix, \Drupal::service('cache_tags.invalidator.checksum'));
}
}
/**
* {@inheritdoc}
*/
protected function tearDown() {
foreach ($this->cachebackends as $bin => $cachebackend) {
$this->cachebackends[$bin]->removeBin();
}
parent::tearDown();
}
/**
* {@inheritdoc}
*/
public function testSetGet() {
if ($this->requirementsFail()) {
return;
}
parent::testSetGet();
// Make sure entries are permanent (i.e. no TTL).
$backend = $this->getCacheBackend($this->getTestBin());
$key = $backend->getApcuKey('TEST8');
if (class_exists('\APCUIterator')) {
$iterator = new \APCUIterator('/^' . $key . '/');
}
else {
$iterator = new \APCIterator('user', '/^' . $key . '/');
}
foreach ($iterator as $item) {
$this->assertEqual(0, $item['ttl']);
$found = TRUE;
}
$this->assertTrue($found);
}
/**
* {@inheritdoc}
*/
public function testDelete() {
if ($this->requirementsFail()) {
return;
}
parent::testDelete();
}
/**
* {@inheritdoc}
*/
public function testValueTypeIsKept() {
if ($this->requirementsFail()) {
return;
}
parent::testValueTypeIsKept();
}
/**
* {@inheritdoc}
*/
public function testGetMultiple() {
if ($this->requirementsFail()) {
return;
}
parent::testGetMultiple();
}
/**
* {@inheritdoc}
*/
public function testSetMultiple() {
if ($this->requirementsFail()) {
return;
}
parent::testSetMultiple();
}
/**
* {@inheritdoc}
*/
public function testDeleteMultiple() {
if ($this->requirementsFail()) {
return;
}
parent::testDeleteMultiple();
}
/**
* {@inheritdoc}
*/
public function testDeleteAll() {
if ($this->requirementsFail()) {
return;
}
parent::testDeleteAll();
}
/**
* {@inheritdoc}
*/
public function testInvalidate() {
if ($this->requirementsFail()) {
return;
}
parent::testInvalidate();
}
/**
* {@inheritdoc}
*/
public function testInvalidateTags() {
if ($this->requirementsFail()) {
return;
}
parent::testInvalidateTags();
}
/**
* {@inheritdoc}
*/
public function testInvalidateAll() {
if ($this->requirementsFail()) {
return;
}
parent::testInvalidateAll();
}
/**
* {@inheritdoc}
*/
public function testRemoveBin() {
if ($this->requirementsFail()) {
return;
}
parent::testRemoveBin();
}
}

View file

@ -40,6 +40,28 @@ trait AssertPageCacheContextsAndTagsTrait {
}
}
/**
* Asserts whether an expected cache context was present in the last response.
*
* @param string $expected_cache_context
* The expected cache context.
*/
protected function assertCacheContext($expected_cache_context) {
$cache_contexts = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Contexts'));
$this->assertTrue(in_array($expected_cache_context, $cache_contexts), "'" . $expected_cache_context . "' is present in the X-Drupal-Cache-Contexts header.");
}
/**
* Asserts that a cache context was not present in the last response.
*
* @param string $not_expected_cache_context
* The expected cache context.
*/
protected function assertNoCacheContext($not_expected_cache_context) {
$cache_contexts = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Contexts'));
$this->assertFalse(in_array($not_expected_cache_context, $cache_contexts), "'" . $not_expected_cache_context . "' is not present in the X-Drupal-Cache-Contexts header.");
}
/**
* Asserts page cache miss, then hit for the given URL; checks cache headers.
*
@ -120,7 +142,7 @@ trait AssertPageCacheContextsAndTagsTrait {
* @param bool $include_default_contexts
* (optional) Whether the default contexts should automatically be included.
*
* @return
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertCacheContexts(array $expected_contexts, $message = NULL, $include_default_contexts = TRUE) {
@ -137,12 +159,17 @@ trait AssertPageCacheContextsAndTagsTrait {
$actual_contexts = $this->getCacheHeaderValues('X-Drupal-Cache-Contexts');
sort($expected_contexts);
sort($actual_contexts);
$return = $this->assertIdentical($actual_contexts, $expected_contexts, $message);
if (!$return) {
$match = $actual_contexts === $expected_contexts;
if (!$match) {
debug('Unwanted cache contexts in response: ' . implode(',', array_diff($actual_contexts, $expected_contexts)));
debug('Missing cache contexts in response: ' . implode(',', array_diff($expected_contexts, $actual_contexts)));
}
return $return;
$this->assertIdentical($actual_contexts, $expected_contexts, $message);
// For compatibility with both BrowserTestBase and WebTestBase always return
// a boolean.
return $match;
}
/**

View file

@ -1,29 +0,0 @@
<?php
namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\BackendChain;
use Drupal\Core\Cache\MemoryBackend;
/**
* Unit test of the backend chain using the generic cache unit test base.
*
* @group Cache
*/
class BackendChainUnitTest extends GenericCacheBackendUnitTestBase {
protected function createCacheBackend($bin) {
$chain = new BackendChain($bin);
// We need to create some various backends in the chain.
$chain
->appendBackend(new MemoryBackend('foo'))
->prependBackend(new MemoryBackend('bar'))
->appendBackend(new MemoryBackend('baz'));
\Drupal::service('cache_tags.invalidator')->addInvalidator($chain);
return $chain;
}
}

View file

@ -1,119 +0,0 @@
<?php
namespace Drupal\system\Tests\Cache;
use Drupal\simpletest\KernelTestBase;
use Drupal\simpletest\UserCreationTrait;
use Drupal\user\Entity\Role;
/**
* Tests the cache context optimization.
*
* @group Render
*/
class CacheContextOptimizationTest extends KernelTestBase {
use UserCreationTrait;
/**
* Modules to enable.
*
* @var string[]
*/
public static $modules = ['user', 'system'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('user');
$this->installConfig(['user']);
$this->installSchema('system', ['sequences']);
}
/**
* Ensures that 'user.permissions' cache context is able to define cache tags.
*/
public function testUserPermissionCacheContextOptimization() {
$user1 = $this->createUser();
$this->assertEqual($user1->id(), 1);
$authenticated_user = $this->createUser(['administer permissions']);
$role = $authenticated_user->getRoles()[1];
$test_element = [
'#cache' => [
'keys' => ['test'],
'contexts' => ['user', 'user.permissions'],
],
];
\Drupal::service('account_switcher')->switchTo($authenticated_user);
$element = $test_element;
$element['#markup'] = 'content for authenticated users';
$output = \Drupal::service('renderer')->renderRoot($element);
$this->assertEqual($output, 'content for authenticated users');
// Verify that the render caching is working so that other tests can be
// trusted.
$element = $test_element;
$element['#markup'] = 'this should not be visible';
$output = \Drupal::service('renderer')->renderRoot($element);
$this->assertEqual($output, 'content for authenticated users');
// Even though the cache contexts have been optimized to only include 'user'
// cache context, the element should have been changed because
// 'user.permissions' cache context defined a cache tags for permission
// changes, which should have bubbled up for the element when it was
// optimized away.
Role::load($role)
->revokePermission('administer permissions')
->save();
$element = $test_element;
$element['#markup'] = 'this should be visible';
$output = \Drupal::service('renderer')->renderRoot($element);
$this->assertEqual($output, 'this should be visible');
}
/**
* Ensures that 'user.roles' still works when it is optimized away.
*/
public function testUserRolesCacheContextOptimization() {
$root_user = $this->createUser();
$this->assertEqual($root_user->id(), 1);
$authenticated_user = $this->createUser(['administer permissions']);
$role = $authenticated_user->getRoles()[1];
$test_element = [
'#cache' => [
'keys' => ['test'],
'contexts' => ['user', 'user.roles'],
],
];
\Drupal::service('account_switcher')->switchTo($authenticated_user);
$element = $test_element;
$element['#markup'] = 'content for authenticated users';
$output = \Drupal::service('renderer')->renderRoot($element);
$this->assertEqual($output, 'content for authenticated users');
// Verify that the render caching is working so that other tests can be
// trusted.
$element = $test_element;
$element['#markup'] = 'this should not be visible';
$output = \Drupal::service('renderer')->renderRoot($element);
$this->assertEqual($output, 'content for authenticated users');
// Even though the cache contexts have been optimized to only include 'user'
// cache context, the element should have been changed because 'user.roles'
// cache context defined a cache tag for user entity changes, which should
// have bubbled up for the element when it was optimized away.
$authenticated_user->removeRole($role);
$authenticated_user->save();
$element = $test_element;
$element['#markup'] = 'this should be visible';
$output = \Drupal::service('renderer')->renderRoot($element);
$this->assertEqual($output, 'this should be visible');
}
}

View file

@ -1,32 +0,0 @@
<?php
namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\ChainedFastBackend;
use Drupal\Core\Cache\DatabaseBackend;
use Drupal\Core\Cache\PhpBackend;
/**
* Unit test of the fast chained backend using the generic cache unit test base.
*
* @group Cache
*/
class ChainedFastBackendUnitTest extends GenericCacheBackendUnitTestBase {
/**
* Creates a new instance of ChainedFastBackend.
*
* @return \Drupal\Core\Cache\ChainedFastBackend
* A new ChainedFastBackend object.
*/
protected function createCacheBackend($bin) {
$consistent_backend = new DatabaseBackend(\Drupal::service('database'), \Drupal::service('cache_tags.invalidator.checksum'), $bin);
$fast_backend = new PhpBackend($bin, \Drupal::service('cache_tags.invalidator.checksum'));
$backend = new ChainedFastBackend($consistent_backend, $fast_backend, $bin);
// Explicitly register the cache bin as it can not work through the
// cache bin list in the container.
\Drupal::service('cache_tags.invalidator')->addInvalidator($backend);
return $backend;
}
}

View file

@ -1,60 +0,0 @@
<?php
namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\Cache;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\simpletest\KernelTestBase;
use Symfony\Component\DependencyInjection\Reference;
/**
* Tests DatabaseBackend cache tag implementation.
*
* @group Cache
*/
class DatabaseBackendTagTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
/**
* {@inheritdoc}
*/
public function containerBuild(ContainerBuilder $container) {
parent::containerBuild($container);
// Change container to database cache backends.
$container
->register('cache_factory', 'Drupal\Core\Cache\CacheFactory')
->addArgument(new Reference('settings'))
->addMethodCall('setContainer', array(new Reference('service_container')));
}
public function testTagInvalidations() {
// Create cache entry in multiple bins.
$tags = array('test_tag:1', 'test_tag:2', 'test_tag:3');
$bins = array('data', 'bootstrap', 'render');
foreach ($bins as $bin) {
$bin = \Drupal::cache($bin);
$bin->set('test', 'value', Cache::PERMANENT, $tags);
$this->assertTrue($bin->get('test'), 'Cache item was set in bin.');
}
$invalidations_before = intval(db_select('cachetags')->fields('cachetags', array('invalidations'))->condition('tag', 'test_tag:2')->execute()->fetchField());
Cache::invalidateTags(array('test_tag:2'));
// Test that cache entry has been invalidated in multiple bins.
foreach ($bins as $bin) {
$bin = \Drupal::cache($bin);
$this->assertFalse($bin->get('test'), 'Tag invalidation affected item in bin.');
}
// Test that only one tag invalidation has occurred.
$invalidations_after = intval(db_select('cachetags')->fields('cachetags', array('invalidations'))->condition('tag', 'test_tag:2')->execute()->fetchField());
$this->assertEqual($invalidations_after, $invalidations_before + 1, 'Only one addition cache tag invalidation has occurred after invalidating a tag used in multiple bins.');
}
}

View file

@ -1,51 +0,0 @@
<?php
namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\DatabaseBackend;
/**
* Unit test of the database backend using the generic cache unit test base.
*
* @group Cache
*/
class DatabaseBackendUnitTest extends GenericCacheBackendUnitTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
/**
* Creates a new instance of DatabaseBackend.
*
* @return
* A new DatabaseBackend object.
*/
protected function createCacheBackend($bin) {
return new DatabaseBackend($this->container->get('database'), $this->container->get('cache_tags.invalidator.checksum'), $bin);
}
/**
* {@inheritdoc}
*/
public function testSetGet() {
parent::testSetGet();
$backend = $this->getCacheBackend();
// Set up a cache ID that is not ASCII and longer than 255 characters so we
// can test cache ID normalization.
$cid_long = str_repeat('愛€', 500);
$cached_value_long = $this->randomMachineName();
$backend->set($cid_long, $cached_value_long);
$this->assertIdentical($cached_value_long, $backend->get($cid_long)->data, "Backend contains the correct value for long, non-ASCII cache id.");
$cid_short = '愛1€';
$cached_value_short = $this->randomMachineName();
$backend->set($cid_short, $cached_value_short);
$this->assertIdentical($cached_value_short, $backend->get($cid_short)->data, "Backend contains the correct value for short, non-ASCII cache id.");
}
}

View file

@ -15,6 +15,9 @@ use Drupal\simpletest\KernelTestBase;
*
* @see DatabaseBackendUnitTestCase
* For a full working implementation.
*
* @deprecated as of Drupal 8.2.x, will be removed before Drupal 9.0.0. Use
* \Drupal\KernelTests\Core\Cache\GenericCacheBackendUnitTestBase instead.
*/
abstract class GenericCacheBackendUnitTestBase extends KernelTestBase {

View file

@ -1,26 +0,0 @@
<?php
namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\MemoryBackend;
/**
* Unit test of the memory cache backend using the generic cache unit test base.
*
* @group Cache
*/
class MemoryBackendUnitTest extends GenericCacheBackendUnitTestBase {
/**
* Creates a new instance of MemoryBackend.
*
* @return
* A new MemoryBackend object.
*/
protected function createCacheBackend($bin) {
$backend = new MemoryBackend($bin);
\Drupal::service('cache_tags.invalidator')->addInvalidator($backend);
return $backend;
}
}

View file

@ -38,7 +38,7 @@ abstract class PageCacheTagsTestBase extends WebTestBase {
* @param string $hit_or_miss
* 'HIT' if a page cache hit is expected, 'MISS' otherwise.
*
* @param array|FALSE $tags
* @param array|false $tags
* When expecting a page cache hit, you may optionally specify an array of
* expected cache tags. While FALSE, the cache tags will not be verified.
*/

View file

@ -1,25 +0,0 @@
<?php
namespace Drupal\system\Tests\Cache;
use Drupal\Core\Cache\PhpBackend;
/**
* Unit test of the PHP cache backend using the generic cache unit test base.
*
* @group Cache
*/
class PhpBackendUnitTest extends GenericCacheBackendUnitTestBase {
/**
* Creates a new instance of MemoryBackend.
*
* @return
* A new MemoryBackend object.
*/
protected function createCacheBackend($bin) {
$backend = new PhpBackend($bin, \Drupal::service('cache_tags.invalidator.checksum'));
return $backend;
}
}

View file

@ -1,477 +0,0 @@
<?php
namespace Drupal\system\Tests\Common;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Asset\AttachedAssets;
use Drupal\simpletest\KernelTestBase;
/**
* Tests #attached assets: attached asset libraries and JavaScript settings.
*
* i.e. tests:
*
* @code
* $build['#attached']['library'] =
* $build['#attached']['drupalSettings'] =
* @endcode
*
* @group Common
* @group Asset
*/
class AttachedAssetsTest extends KernelTestBase {
/**
* The asset resolver service.
*
* @var \Drupal\Core\Asset\AssetResolverInterface
*/
protected $assetResolver;
/**
* The renderer service.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* {@inheritdoc}
*/
public static $modules = array('language', 'simpletest', 'common_test', 'system');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->container->get('router.builder')->rebuild();
$this->assetResolver = $this->container->get('asset.resolver');
$this->renderer = $this->container->get('renderer');
}
/**
* Tests that default CSS and JavaScript is empty.
*/
function testDefault() {
$assets = new AttachedAssets();
$this->assertEqual(array(), $this->assetResolver->getCssAssets($assets, FALSE), 'Default CSS is empty.');
list($js_assets_header, $js_assets_footer) = $this->assetResolver->getJsAssets($assets, FALSE);
$this->assertEqual(array(), $js_assets_header, 'Default header JavaScript is empty.');
$this->assertEqual(array(), $js_assets_footer, 'Default footer JavaScript is empty.');
}
/**
* Tests non-existing libraries.
*/
function testLibraryUnknown() {
$build['#attached']['library'][] = 'core/unknown';
$assets = AttachedAssets::createFromRenderArray($build);
$this->assertIdentical([], $this->assetResolver->getJsAssets($assets, FALSE)[0], 'Unknown library was not added to the page.');
}
/**
* Tests adding a CSS and a JavaScript file.
*/
function testAddFiles() {
$build['#attached']['library'][] = 'common_test/files';
$assets = AttachedAssets::createFromRenderArray($build);
$css = $this->assetResolver->getCssAssets($assets, FALSE);
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$this->assertTrue(array_key_exists('core/modules/system/tests/modules/common_test/bar.css', $css), 'CSS files are correctly added.');
$this->assertTrue(array_key_exists('core/modules/system/tests/modules/common_test/foo.js', $js), 'JavaScript files are correctly added.');
$css_render_array = \Drupal::service('asset.css.collection_renderer')->render($css);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_css = $this->renderer->renderPlain($css_render_array);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$query_string = $this->container->get('state')->get('system.css_js_query_string') ?: '0';
$this->assertNotIdentical(strpos($rendered_css, '<link rel="stylesheet" href="' . file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/bar.css')) . '?' . $query_string . '" media="all" />'), FALSE, 'Rendering an external CSS file.');
$this->assertNotIdentical(strpos($rendered_js, '<script src="' . file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/foo.js')) . '?' . $query_string . '"></script>'), FALSE, 'Rendering an external JavaScript file.');
}
/**
* Tests adding JavaScript settings.
*/
function testAddJsSettings() {
// Add a file in order to test default settings.
$build['#attached']['library'][] = 'core/drupalSettings';
$assets = AttachedAssets::createFromRenderArray($build);
$this->assertEqual([], $assets->getSettings(), 'JavaScript settings on $assets are empty.');
$javascript = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$this->assertTrue(array_key_exists('currentPath', $javascript['drupalSettings']['data']['path']), 'The current path JavaScript setting is set correctly.');
$this->assertTrue(array_key_exists('currentPath', $assets->getSettings()['path']), 'JavaScript settings on $assets are resolved after retrieving JavaScript assets, and are equal to the returned JavaScript settings.');
$assets->setSettings(['drupal' => 'rocks', 'dries' => 280342800]);
$javascript = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$this->assertEqual(280342800, $javascript['drupalSettings']['data']['dries'], 'JavaScript setting is set correctly.');
$this->assertEqual('rocks', $javascript['drupalSettings']['data']['drupal'], 'The other JavaScript setting is set correctly.');
}
/**
* Tests adding external CSS and JavaScript files.
*/
function testAddExternalFiles() {
$build['#attached']['library'][] = 'common_test/external';
$assets = AttachedAssets::createFromRenderArray($build);
$css = $this->assetResolver->getCssAssets($assets, FALSE);
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$this->assertTrue(array_key_exists('http://example.com/stylesheet.css', $css), 'External CSS files are correctly added.');
$this->assertTrue(array_key_exists('http://example.com/script.js', $js), 'External JavaScript files are correctly added.');
$css_render_array = \Drupal::service('asset.css.collection_renderer')->render($css);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_css = $this->renderer->renderPlain($css_render_array);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$this->assertNotIdentical(strpos($rendered_css, '<link rel="stylesheet" href="http://example.com/stylesheet.css" media="all" />'), FALSE, 'Rendering an external CSS file.');
$this->assertNotIdentical(strpos($rendered_js, '<script src="http://example.com/script.js"></script>'), FALSE, 'Rendering an external JavaScript file.');
}
/**
* Tests adding JavaScript files with additional attributes.
*/
function testAttributes() {
$build['#attached']['library'][] = 'common_test/js-attributes';
$assets = AttachedAssets::createFromRenderArray($build);
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$expected_1 = '<script src="http://example.com/deferred-external.js" foo="bar" defer></script>';
$expected_2 = '<script src="' . file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/deferred-internal.js')) . '?v=1" defer bar="foo"></script>';
$this->assertNotIdentical(strpos($rendered_js, $expected_1), FALSE, 'Rendered external JavaScript with correct defer and random attributes.');
$this->assertNotIdentical(strpos($rendered_js, $expected_2), FALSE, 'Rendered internal JavaScript with correct defer and random attributes.');
}
/**
* Tests that attributes are maintained when JS aggregation is enabled.
*/
function testAggregatedAttributes() {
$build['#attached']['library'][] = 'common_test/js-attributes';
$assets = AttachedAssets::createFromRenderArray($build);
$js = $this->assetResolver->getJsAssets($assets, TRUE)[1];
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$expected_1 = '<script src="http://example.com/deferred-external.js" foo="bar" defer></script>';
$expected_2 = '<script src="' . file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/deferred-internal.js')) . '?v=1" defer bar="foo"></script>';
$this->assertNotIdentical(strpos($rendered_js, $expected_1), FALSE, 'Rendered external JavaScript with correct defer and random attributes.');
$this->assertNotIdentical(strpos($rendered_js, $expected_2), FALSE, 'Rendered internal JavaScript with correct defer and random attributes.');
}
/**
* Integration test for CSS/JS aggregation.
*/
function testAggregation() {
$build['#attached']['library'][] = 'core/drupal.timezone';
$build['#attached']['library'][] = 'core/drupal.vertical-tabs';
$assets = AttachedAssets::createFromRenderArray($build);
$this->assertEqual(1, count($this->assetResolver->getCssAssets($assets, TRUE)), 'There is a sole aggregated CSS asset.');
list($header_js, $footer_js) = $this->assetResolver->getJsAssets($assets, TRUE);
$this->assertEqual([], \Drupal::service('asset.js.collection_renderer')->render($header_js), 'There are 0 JavaScript assets in the header.');
$rendered_footer_js = \Drupal::service('asset.js.collection_renderer')->render($footer_js);
$this->assertEqual(2, count($rendered_footer_js), 'There are 2 JavaScript assets in the footer.');
$this->assertEqual('drupal-settings-json', $rendered_footer_js[0]['#attributes']['data-drupal-selector'], 'The first of the two JavaScript assets in the footer has drupal settings.');
$this->assertEqual(0, strpos($rendered_footer_js[1]['#attributes']['src'], base_path()), 'The second of the two JavaScript assets in the footer has the sole aggregated JavaScript asset.');
}
/**
* Tests JavaScript settings.
*/
function testSettings() {
$build = array();
$build['#attached']['library'][] = 'core/drupalSettings';
// Nonsensical value to verify if it's possible to override path settings.
$build['#attached']['drupalSettings']['path']['pathPrefix'] = 'yarhar';
$assets = AttachedAssets::createFromRenderArray($build);
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->renderPlain($js_render_array);
// Parse the generated drupalSettings <script> back to a PHP representation.
$startToken = '{';
$endToken = '}';
$start = strpos($rendered_js, $startToken);
$end = strrpos($rendered_js, $endToken);
$json = Unicode::substr($rendered_js, $start, $end - $start + 1);
$parsed_settings = Json::decode($json);
// Test whether the settings for core/drupalSettings are available.
$this->assertTrue(isset($parsed_settings['path']['baseUrl']), 'drupalSettings.path.baseUrl is present.');
$this->assertIdentical($parsed_settings['path']['pathPrefix'], 'yarhar', 'drupalSettings.path.pathPrefix is present and has the correct (overridden) value.');
$this->assertIdentical($parsed_settings['path']['currentPath'], '', 'drupalSettings.path.currentPath is present and has the correct value.');
$this->assertIdentical($parsed_settings['path']['currentPathIsAdmin'], FALSE, 'drupalSettings.path.currentPathIsAdmin is present and has the correct value.');
$this->assertIdentical($parsed_settings['path']['isFront'], FALSE, 'drupalSettings.path.isFront is present and has the correct value.');
$this->assertIdentical($parsed_settings['path']['currentLanguage'], 'en', 'drupalSettings.path.currentLanguage is present and has the correct value.');
// Tests whether altering JavaScript settings via hook_js_settings_alter()
// is working as expected.
// @see common_test_js_settings_alter()
$this->assertIdentical($parsed_settings['pluralDelimiter'], '☃');
$this->assertIdentical($parsed_settings['foo'], 'bar');
}
/**
* Tests JS assets depending on the 'core/<head>' virtual library.
*/
function testHeaderHTML() {
$build['#attached']['library'][] = 'common_test/js-header';
$assets = AttachedAssets::createFromRenderArray($build);
$js = $this->assetResolver->getJsAssets($assets, FALSE)[0];
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$query_string = $this->container->get('state')->get('system.css_js_query_string') ?: '0';
$this->assertNotIdentical(strpos($rendered_js, '<script src="' . file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/header.js')) . '?' . $query_string . '"></script>'), FALSE, 'The JS asset in common_test/js-header appears in the header.');
$this->assertNotIdentical(strpos($rendered_js, '<script src="' . file_url_transform_relative(file_create_url('core/misc/drupal.js'))), FALSE, 'The JS asset of the direct dependency (core/drupal) of common_test/js-header appears in the header.');
$this->assertNotIdentical(strpos($rendered_js, '<script src="' . file_url_transform_relative(file_create_url('core/assets/vendor/domready/ready.min.js'))), FALSE, 'The JS asset of the indirect dependency (core/domready) of common_test/js-header appears in the header.');
}
/**
* Tests that for assets with cache = FALSE, Drupal sets preprocess = FALSE.
*/
function testNoCache() {
$build['#attached']['library'][] = 'common_test/no-cache';
$assets = AttachedAssets::createFromRenderArray($build);
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$this->assertFalse($js['core/modules/system/tests/modules/common_test/nocache.js']['preprocess'], 'Setting cache to FALSE sets preprocess to FALSE when adding JavaScript.');
}
/**
* Tests adding JavaScript within conditional comments.
*
* @see \Drupal\Core\Render\Element\HtmlTag::preRenderConditionalComments()
*/
function testBrowserConditionalComments() {
$default_query_string = $this->container->get('state')->get('system.css_js_query_string') ?: '0';
$build['#attached']['library'][] = 'common_test/browsers';
$assets = AttachedAssets::createFromRenderArray($build);
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$expected_1 = "<!--[if lte IE 8]>\n" . '<script src="' . file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/old-ie.js')) . '?' . $default_query_string . '"></script>' . "\n<![endif]-->";
$expected_2 = "<!--[if !IE]><!-->\n" . '<script src="' . file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/no-ie.js')) . '?' . $default_query_string . '"></script>' . "\n<!--<![endif]-->";
$this->assertNotIdentical(strpos($rendered_js, $expected_1), FALSE, 'Rendered JavaScript within downlevel-hidden conditional comments.');
$this->assertNotIdentical(strpos($rendered_js, $expected_2), FALSE, 'Rendered JavaScript within downlevel-revealed conditional comments.');
}
/**
* Tests JavaScript versioning.
*/
function testVersionQueryString() {
$build['#attached']['library'][] = 'core/backbone';
$build['#attached']['library'][] = 'core/domready';
$assets = AttachedAssets::createFromRenderArray($build);
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$this->assertTrue(strpos($rendered_js, 'core/assets/vendor/backbone/backbone-min.js?v=1.2.3') > 0 && strpos($rendered_js, 'core/assets/vendor/domready/ready.min.js?v=1.0.8') > 0, 'JavaScript version identifiers correctly appended to URLs');
}
/**
* Tests JavaScript and CSS asset ordering.
*/
function testRenderOrder() {
$build['#attached']['library'][] = 'common_test/order';
$assets = AttachedAssets::createFromRenderArray($build);
// Construct the expected result from the regex.
$expected_order_js = [
"-8_1",
"-8_2",
"-8_3",
"-8_4",
"-5_1", // The external script.
"-3_1",
"-3_2",
"0_1",
"0_2",
"0_3",
];
// Retrieve the rendered JavaScript and test against the regex.
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$matches = array();
if (preg_match_all('/weight_([-0-9]+_[0-9]+)/', $rendered_js, $matches)) {
$result = $matches[1];
}
else {
$result = array();
}
$this->assertIdentical($result, $expected_order_js, 'JavaScript is added in the expected weight order.');
// Construct the expected result from the regex.
$expected_order_css = [
// Base.
'base_weight_-101_1',
'base_weight_-8_1',
'layout_weight_-101_1',
'base_weight_0_1',
'base_weight_0_2',
// Layout.
'layout_weight_-8_1',
'component_weight_-101_1',
'layout_weight_0_1',
'layout_weight_0_2',
// Component.
'component_weight_-8_1',
'state_weight_-101_1',
'component_weight_0_1',
'component_weight_0_2',
// State.
'state_weight_-8_1',
'theme_weight_-101_1',
'state_weight_0_1',
'state_weight_0_2',
// Theme.
'theme_weight_-8_1',
'theme_weight_0_1',
'theme_weight_0_2',
];
// Retrieve the rendered CSS and test against the regex.
$css = $this->assetResolver->getCssAssets($assets, FALSE);
$css_render_array = \Drupal::service('asset.css.collection_renderer')->render($css);
$rendered_css = $this->renderer->renderPlain($css_render_array);
$matches = array();
if (preg_match_all('/([a-z]+)_weight_([-0-9]+_[0-9]+)/', $rendered_css, $matches)) {
$result = $matches[0];
}
else {
$result = array();
}
$this->assertIdentical($result, $expected_order_css, 'CSS is added in the expected weight order.');
}
/**
* Tests rendering the JavaScript with a file's weight above jQuery's.
*/
function testRenderDifferentWeight() {
// If a library contains assets A and B, and A is listed first, then B can
// still make itself appear first by defining a lower weight.
$build['#attached']['library'][] = 'core/jquery';
$build['#attached']['library'][] = 'common_test/weight';
$assets = AttachedAssets::createFromRenderArray($build);
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$this->assertTrue(strpos($rendered_js, 'lighter.css') < strpos($rendered_js, 'first.js'), 'Lighter CSS assets are rendered first.');
$this->assertTrue(strpos($rendered_js, 'lighter.js') < strpos($rendered_js, 'first.js'), 'Lighter JavaScript assets are rendered first.');
$this->assertTrue(strpos($rendered_js, 'before-jquery.js') < strpos($rendered_js, 'core/assets/vendor/jquery/jquery.min.js'), 'Rendering a JavaScript file above jQuery.');
}
/**
* Tests altering a JavaScript's weight via hook_js_alter().
*
* @see simpletest_js_alter()
*/
function testAlter() {
// Add both tableselect.js and simpletest.js.
$build['#attached']['library'][] = 'core/drupal.tableselect';
$build['#attached']['library'][] = 'simpletest/drupal.simpletest';
$assets = AttachedAssets::createFromRenderArray($build);
// Render the JavaScript, testing if simpletest.js was altered to be before
// tableselect.js. See simpletest_js_alter() to see where this alteration
// takes place.
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$this->assertTrue(strpos($rendered_js, 'simpletest.js') < strpos($rendered_js, 'core/misc/tableselect.js'), 'Altering JavaScript weight through the alter hook.');
}
/**
* Adds a JavaScript library to the page and alters it.
*
* @see common_test_library_info_alter()
*/
function testLibraryAlter() {
// Verify that common_test altered the title of Farbtastic.
/** @var \Drupal\Core\Asset\LibraryDiscoveryInterface $library_discovery */
$library_discovery = \Drupal::service('library.discovery');
$library = $library_discovery->getLibraryByName('core', 'jquery.farbtastic');
$this->assertEqual($library['version'], '0.0', 'Registered libraries were altered.');
// common_test_library_info_alter() also added a dependency on jQuery Form.
$build['#attached']['library'][] = 'core/jquery.farbtastic';
$assets = AttachedAssets::createFromRenderArray($build);
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$this->assertTrue(strpos($rendered_js, 'core/assets/vendor/jquery-form/jquery.form.min.js'), 'Altered library dependencies are added to the page.');
}
/**
* Dynamically defines an asset library and alters it.
*/
function testDynamicLibrary() {
/** @var \Drupal\Core\Asset\LibraryDiscoveryInterface $library_discovery */
$library_discovery = \Drupal::service('library.discovery');
// Retrieve a dynamic library definition.
// @see common_test_library_info_build()
\Drupal::state()->set('common_test.library_info_build_test', TRUE);
$library_discovery->clearCachedDefinitions();
$dynamic_library = $library_discovery->getLibraryByName('common_test', 'dynamic_library');
$this->assertTrue(is_array($dynamic_library));
if ($this->assertTrue(isset($dynamic_library['version']))) {
$this->assertIdentical('1.0', $dynamic_library['version']);
}
// Make sure the dynamic library definition could be altered.
// @see common_test_library_info_alter()
if ($this->assertTrue(isset($dynamic_library['dependencies']))) {
$this->assertIdentical(['core/jquery'], $dynamic_library['dependencies']);
}
}
/**
* Tests that multiple modules can implement libraries with the same name.
*
* @see common_test.library.yml
*/
function testLibraryNameConflicts() {
/** @var \Drupal\Core\Asset\LibraryDiscoveryInterface $library_discovery */
$library_discovery = \Drupal::service('library.discovery');
$farbtastic = $library_discovery->getLibraryByName('common_test', 'jquery.farbtastic');
$this->assertEqual($farbtastic['version'], '0.1', 'Alternative libraries can be added to the page.');
}
/**
* Tests JavaScript files that have querystrings attached get added right.
*/
function testAddJsFileWithQueryString() {
$build['#attached']['library'][] = 'common_test/querystring';
$assets = AttachedAssets::createFromRenderArray($build);
$css = $this->assetResolver->getCssAssets($assets, FALSE);
$js = $this->assetResolver->getJsAssets($assets, FALSE)[1];
$this->assertTrue(array_key_exists('core/modules/system/tests/modules/common_test/querystring.css?arg1=value1&arg2=value2', $css), 'CSS file with query string is correctly added.');
$this->assertTrue(array_key_exists('core/modules/system/tests/modules/common_test/querystring.js?arg1=value1&arg2=value2', $js), 'JavaScript file with query string is correctly added.');
$css_render_array = \Drupal::service('asset.css.collection_renderer')->render($css);
$rendered_css = $this->renderer->renderPlain($css_render_array);
$js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js);
$rendered_js = $this->renderer->renderPlain($js_render_array);
$query_string = $this->container->get('state')->get('system.css_js_query_string') ?: '0';
$this->assertNotIdentical(strpos($rendered_css, '<link rel="stylesheet" href="' . str_replace('&', '&amp;', file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/querystring.css?arg1=value1&arg2=value2'))) . '&amp;' . $query_string . '" media="all" />'), FALSE, 'CSS file with query string gets version query string correctly appended..');
$this->assertNotIdentical(strpos($rendered_js, '<script src="' . str_replace('&', '&amp;', file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/querystring.js?arg1=value1&arg2=value2'))) . '&amp;' . $query_string . '"></script>'), FALSE, 'JavaScript file with query string gets version query string correctly appended.');
}
}

View file

@ -1,243 +0,0 @@
<?php
namespace Drupal\system\Tests\Common;
use Drupal\Component\Utility\Html;
use Drupal\Core\Url;
use Drupal\simpletest\KernelTestBase;
/**
* Tests the markup of core render element types passed to drupal_render().
*
* @group Common
*/
class RenderElementTypesTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system', 'router_test');
protected function setUp() {
parent::setUp();
$this->installConfig(array('system'));
\Drupal::service('router.builder')->rebuild();
}
/**
* Asserts that an array of elements is rendered properly.
*
* @param array $elements
* The render element array to test.
* @param string $expected_html
* The expected markup.
* @param string $message
* Assertion message.
*/
protected function assertElements(array $elements, $expected_html, $message) {
$actual_html = (string) \Drupal::service('renderer')->renderRoot($elements);
$out = '<table><tr>';
$out .= '<td valign="top"><pre>' . Html::escape($expected_html) . '</pre></td>';
$out .= '<td valign="top"><pre>' . Html::escape($actual_html) . '</pre></td>';
$out .= '</tr></table>';
$this->verbose($out);
$this->assertIdentical($actual_html, $expected_html, Html::escape($message));
}
/**
* Tests system #type 'container'.
*/
function testContainer() {
// Basic container with no attributes.
$this->assertElements(array(
'#type' => 'container',
'#markup' => 'foo',
), "<div>foo</div>\n", "#type 'container' with no HTML attributes");
// Container with a class.
$this->assertElements(array(
'#type' => 'container',
'#markup' => 'foo',
'#attributes' => array(
'class' => array('bar'),
),
), '<div class="bar">foo</div>' . "\n", "#type 'container' with a class HTML attribute");
// Container with children.
$this->assertElements(array(
'#type' => 'container',
'child' => array(
'#markup' => 'foo',
),
), "<div>foo</div>\n", "#type 'container' with child elements");
}
/**
* Tests system #type 'html_tag'.
*/
function testHtmlTag() {
// Test void element.
$this->assertElements(array(
'#type' => 'html_tag',
'#tag' => 'meta',
'#value' => 'ignored',
'#attributes' => array(
'name' => 'description',
'content' => 'Drupal test',
),
), '<meta name="description" content="Drupal test" />' . "\n", "#type 'html_tag', void element renders properly");
// Test non-void element.
$this->assertElements(array(
'#type' => 'html_tag',
'#tag' => 'section',
'#value' => 'value',
'#attributes' => array(
'class' => array('unicorns'),
),
), '<section class="unicorns">value</section>' . "\n", "#type 'html_tag', non-void element renders properly");
// Test empty void element tag.
$this->assertElements(array(
'#type' => 'html_tag',
'#tag' => 'link',
), "<link />\n", "#type 'html_tag' empty void element renders properly");
// Test empty non-void element tag.
$this->assertElements(array(
'#type' => 'html_tag',
'#tag' => 'section',
), "<section></section>\n", "#type 'html_tag' empty non-void element renders properly");
}
/**
* Tests system #type 'more_link'.
*/
function testMoreLink() {
$elements = array(
array(
'name' => "#type 'more_link' anchor tag generation without extra classes",
'value' => array(
'#type' => 'more_link',
'#url' => Url::fromUri('https://www.drupal.org'),
),
'expected' => '//div[@class="more-link"]/a[@href="https://www.drupal.org" and text()="More"]',
),
array(
'name' => "#type 'more_link' anchor tag generation with different link text",
'value' => array(
'#type' => 'more_link',
'#url' => Url::fromUri('https://www.drupal.org'),
'#title' => 'More Titles',
),
'expected' => '//div[@class="more-link"]/a[@href="https://www.drupal.org" and text()="More Titles"]',
),
array(
'name' => "#type 'more_link' anchor tag generation with attributes on wrapper",
'value' => array(
'#type' => 'more_link',
'#url' => Url::fromUri('https://www.drupal.org'),
'#theme_wrappers' => array(
'container' => array(
'#attributes' => array(
'title' => 'description',
'class' => array('more-link', 'drupal', 'test'),
),
),
),
),
'expected' => '//div[@title="description" and contains(@class, "more-link") and contains(@class, "drupal") and contains(@class, "test")]/a[@href="https://www.drupal.org" and text()="More"]',
),
array(
'name' => "#type 'more_link' anchor tag with a relative path",
'value' => array(
'#type' => 'more_link',
'#url' => Url::fromRoute('router_test.1'),
),
'expected' => '//div[@class="more-link"]/a[@href="' . Url::fromRoute('router_test.1')->toString() . '" and text()="More"]',
),
array(
'name' => "#type 'more_link' anchor tag with a route",
'value' => array(
'#type' => 'more_link',
'#url' => Url::fromRoute('router_test.1'),
),
'expected' => '//div[@class="more-link"]/a[@href="' . \Drupal::urlGenerator()->generate('router_test.1') . '" and text()="More"]',
),
array(
'name' => "#type 'more_link' anchor tag with an absolute path",
'value' => array(
'#type' => 'more_link',
'#url' => Url::fromRoute('system.admin_content'),
'#options' => array('absolute' => TRUE),
),
'expected' => '//div[@class="more-link"]/a[@href="' . Url::fromRoute('system.admin_content')->setAbsolute()->toString() . '" and text()="More"]',
),
array(
'name' => "#type 'more_link' anchor tag to the front page",
'value' => array(
'#type' => 'more_link',
'#url' => Url::fromRoute('<front>'),
),
'expected' => '//div[@class="more-link"]/a[@href="' . Url::fromRoute('<front>')->toString() . '" and text()="More"]',
),
);
foreach ($elements as $element) {
$xml = new \SimpleXMLElement(\Drupal::service('renderer')->renderRoot($element['value']));
$result = $xml->xpath($element['expected']);
$this->assertTrue($result, '"' . $element['name'] . '" input rendered correctly by drupal_render().');
}
}
/**
* Tests system #type 'system_compact_link'.
*/
function testSystemCompactLink() {
$elements = array(
array(
'name' => "#type 'system_compact_link' when admin compact mode is off",
'value' => array(
'#type' => 'system_compact_link',
),
'expected' => '//div[@class="compact-link"]/a[contains(@href, "admin/compact/on?") and text()="Hide descriptions"]',
),
array(
'name' => "#type 'system_compact_link' when adding extra attributes",
'value' => array(
'#type' => 'system_compact_link',
'#attributes' => array(
'class' => array('kittens-rule'),
),
),
'expected' => '//div[@class="compact-link"]/a[contains(@href, "admin/compact/on?") and @class="kittens-rule" and text()="Hide descriptions"]',
),
);
foreach ($elements as $element) {
$xml = new \SimpleXMLElement(\Drupal::service('renderer')->renderRoot($element['value']));
$result = $xml->xpath($element['expected']);
$this->assertTrue($result, '"' . $element['name'] . '" is rendered correctly by drupal_render().');
}
// Set admin compact mode on for additional tests.
\Drupal::request()->cookies->set('Drupal_visitor_admin_compact_mode', TRUE);
$element = array(
'name' => "#type 'system_compact_link' when admin compact mode is on",
'value' => array(
'#type' => 'system_compact_link',
),
'expected' => '//div[@class="compact-link"]/a[contains(@href, "admin/compact?") and text()="Show descriptions"]',
);
$xml = new \SimpleXMLElement(\Drupal::service('renderer')->renderRoot($element['value']));
$result = $xml->xpath($element['expected']);
$this->assertTrue($result, '"' . $element['name'] . '" is rendered correctly by drupal_render().');
}
}

View file

@ -1,63 +0,0 @@
<?php
namespace Drupal\system\Tests\Common;
use Drupal\simpletest\KernelTestBase;
/**
* Performs functional tests on drupal_render().
*
* @group Common
*/
class RenderTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system', 'common_test');
/**
* Tests theme preprocess functions being able to attach assets.
*/
function testDrupalRenderThemePreprocessAttached() {
\Drupal::state()->set('theme_preprocess_attached_test', TRUE);
$test_element = [
'#theme' => 'common_test_render_element',
'foo' => [
'#markup' => 'Kittens!',
],
];
\Drupal::service('renderer')->renderRoot($test_element);
$expected_attached = [
'library' => [
'test/generic_preprocess',
'test/specific_preprocess',
]
];
$this->assertEqual($expected_attached, $test_element['#attached'], 'All expected assets from theme preprocess hooks attached.');
\Drupal::state()->set('theme_preprocess_attached_test', FALSE);
}
/**
* Tests that we get an exception when we try to attach an illegal type.
*/
public function testProcessAttached() {
// Specify invalid attachments in a render array.
$build['#attached']['library'][] = 'core/drupal.states';
$build['#attached']['drupal_process_states'][] = [];
$renderer = $this->container->get('bare_html_page_renderer');
try {
$renderer->renderBarePage($build, '', 'maintenance_page');
$this->fail("Invalid #attachment 'drupal_process_states' allowed");
}
catch (\LogicException $e) {
$this->pass("Invalid #attachment 'drupal_process_states' not allowed");
}
}
}

View file

@ -1,69 +0,0 @@
<?php
namespace Drupal\system\Tests\Common;
use Drupal\Component\Utility\Bytes;
use Drupal\simpletest\KernelTestBase;
/**
* Parse a predefined amount of bytes and compare the output with the expected
* value.
*
* @group Common
*/
class SizeUnitTest extends KernelTestBase {
protected $exactTestCases;
protected $roundedTestCases;
protected function setUp() {
parent::setUp();
$kb = Bytes::KILOBYTE;
$this->exactTestCases = array(
'1 byte' => 1,
'1 KB' => $kb,
'1 MB' => $kb * $kb,
'1 GB' => $kb * $kb * $kb,
'1 TB' => $kb * $kb * $kb * $kb,
'1 PB' => $kb * $kb * $kb * $kb * $kb,
'1 EB' => $kb * $kb * $kb * $kb * $kb * $kb,
'1 ZB' => $kb * $kb * $kb * $kb * $kb * $kb * $kb,
'1 YB' => $kb * $kb * $kb * $kb * $kb * $kb * $kb * $kb,
);
$this->roundedTestCases = array(
'2 bytes' => 2,
'1 MB' => ($kb * $kb) - 1, // rounded to 1 MB (not 1000 or 1024 kilobyte!)
round(3623651 / ($this->exactTestCases['1 MB']), 2) . ' MB' => 3623651, // megabytes
round(67234178751368124 / ($this->exactTestCases['1 PB']), 2) . ' PB' => 67234178751368124, // petabytes
round(235346823821125814962843827 / ($this->exactTestCases['1 YB']), 2) . ' YB' => 235346823821125814962843827, // yottabytes
);
}
/**
* Checks that format_size() returns the expected string.
*/
function testCommonFormatSize() {
foreach (array($this->exactTestCases, $this->roundedTestCases) as $test_cases) {
foreach ($test_cases as $expected => $input) {
$this->assertEqual(
($result = format_size($input, NULL)),
$expected,
$expected . ' == ' . $result . ' (' . $input . ' bytes)'
);
}
}
}
/**
* Cross-tests Bytes::toInt() and format_size().
*/
function testCommonParseSizeFormatSize() {
foreach ($this->exactTestCases as $size) {
$this->assertEqual(
$size,
($parsed_size = Bytes::toInt($string = format_size($size, NULL))),
$size . ' == ' . $parsed_size . ' (' . $string . ')'
);
}
}
}

View file

@ -1,141 +0,0 @@
<?php
namespace Drupal\system\Tests\Common;
use Drupal\Component\Utility\Html;
use Drupal\simpletest\KernelTestBase;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests table sorting.
*
* @group Common
*/
class TableSortExtenderUnitTest extends KernelTestBase {
/**
* Tests tablesort_init().
*/
function testTableSortInit() {
// Test simple table headers.
$headers = array('foo', 'bar', 'baz');
// Reset $request->query to prevent parameters from Simpletest and Batch API
// ending up in $ts['query'].
$expected_ts = array(
'name' => 'foo',
'sql' => '',
'sort' => 'asc',
'query' => array(),
);
$request = Request::createFromGlobals();
$request->query->replace(array());
\Drupal::getContainer()->get('request_stack')->push($request);
$ts = tablesort_init($headers);
$this->verbose(strtr('$ts: <pre>!ts</pre>', array('!ts' => Html::escape(var_export($ts, TRUE)))));
$this->assertEqual($ts, $expected_ts, 'Simple table headers sorted correctly.');
// Test with simple table headers plus $_GET parameters that should _not_
// override the default.
$request = Request::createFromGlobals();
$request->query->replace(array(
// This should not override the table order because only complex
// headers are overridable.
'order' => 'bar',
));
\Drupal::getContainer()->get('request_stack')->push($request);
$ts = tablesort_init($headers);
$this->verbose(strtr('$ts: <pre>!ts</pre>', array('!ts' => Html::escape(var_export($ts, TRUE)))));
$this->assertEqual($ts, $expected_ts, 'Simple table headers plus non-overriding $_GET parameters sorted correctly.');
// Test with simple table headers plus $_GET parameters that _should_
// override the default.
$request = Request::createFromGlobals();
$request->query->replace(array(
'sort' => 'DESC',
// Add an unrelated parameter to ensure that tablesort will include
// it in the links that it creates.
'alpha' => 'beta',
));
\Drupal::getContainer()->get('request_stack')->push($request);
$expected_ts['sort'] = 'desc';
$expected_ts['query'] = array('alpha' => 'beta');
$ts = tablesort_init($headers);
$this->verbose(strtr('$ts: <pre>!ts</pre>', array('!ts' => Html::escape(var_export($ts, TRUE)))));
$this->assertEqual($ts, $expected_ts, 'Simple table headers plus $_GET parameters sorted correctly.');
// Test complex table headers.
$headers = array(
'foo',
array(
'data' => '1',
'field' => 'one',
'sort' => 'asc',
'colspan' => 1,
),
array(
'data' => '2',
'field' => 'two',
'sort' => 'desc',
),
);
// Reset $_GET from previous assertion.
$request = Request::createFromGlobals();
$request->query->replace(array(
'order' => '2',
));
\Drupal::getContainer()->get('request_stack')->push($request);
$ts = tablesort_init($headers);
$expected_ts = array(
'name' => '2',
'sql' => 'two',
'sort' => 'desc',
'query' => array(),
);
$this->verbose(strtr('$ts: <pre>!ts</pre>', array('!ts' => Html::escape(var_export($ts, TRUE)))));
$this->assertEqual($ts, $expected_ts, 'Complex table headers sorted correctly.');
// Test complex table headers plus $_GET parameters that should _not_
// override the default.
$request = Request::createFromGlobals();
$request->query->replace(array(
// This should not override the table order because this header does not
// exist.
'order' => 'bar',
));
\Drupal::getContainer()->get('request_stack')->push($request);
$ts = tablesort_init($headers);
$expected_ts = array(
'name' => '1',
'sql' => 'one',
'sort' => 'asc',
'query' => array(),
);
$this->verbose(strtr('$ts: <pre>!ts</pre>', array('!ts' => Html::escape(var_export($ts, TRUE)))));
$this->assertEqual($ts, $expected_ts, 'Complex table headers plus non-overriding $_GET parameters sorted correctly.');
// Test complex table headers plus $_GET parameters that _should_
// override the default.
$request = Request::createFromGlobals();
$request->query->replace(array(
'order' => '1',
'sort' => 'ASC',
// Add an unrelated parameter to ensure that tablesort will include
// it in the links that it creates.
'alpha' => 'beta',
));
\Drupal::getContainer()->get('request_stack')->push($request);
$expected_ts = array(
'name' => '1',
'sql' => 'one',
'sort' => 'asc',
'query' => array('alpha' => 'beta'),
);
$ts = tablesort_init($headers);
$this->verbose(strtr('$ts: <pre>!ts</pre>', array('!ts' => Html::escape(var_export($ts, TRUE)))));
$this->assertEqual($ts, $expected_ts, 'Complex table headers plus $_GET parameters sorted correctly.');
}
}

View file

@ -1,57 +0,0 @@
<?php
namespace Drupal\system\Tests\Common;
use Drupal\Component\Utility\UrlHelper;
use Drupal\simpletest\KernelTestBase;
/**
* Confirm that \Drupal\Component\Utility\Xss::filter() and check_url() work
* correctly, including invalid multi-byte sequences.
*
* @group Common
*/
class XssUnitTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('filter', 'system');
protected function setUp() {
parent::setUp();
$this->installConfig(array('system'));
}
/**
* Tests t() functionality.
*/
function testT() {
$text = t('Simple text');
$this->assertEqual($text, 'Simple text', 't leaves simple text alone.');
$text = t('Escaped text: @value', array('@value' => '<script>'));
$this->assertEqual($text, 'Escaped text: &lt;script&gt;', 't replaces and escapes string.');
$text = t('Placeholder text: %value', array('%value' => '<script>'));
$this->assertEqual($text, 'Placeholder text: <em class="placeholder">&lt;script&gt;</em>', 't replaces, escapes and themes string.');
}
/**
* Checks that harmful protocols are stripped.
*/
function testBadProtocolStripping() {
// Ensure that check_url() strips out harmful protocols, and encodes for
// HTML.
// Ensure \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() can
// be used to return a plain-text string stripped of harmful protocols.
$url = 'javascript:http://www.example.com/?x=1&y=2';
$expected_plain = 'http://www.example.com/?x=1&y=2';
$expected_html = 'http://www.example.com/?x=1&amp;y=2';
$this->assertIdentical(check_url($url), $expected_html, 'check_url() filters a URL and encodes it for HTML.');
$this->assertIdentical(UrlHelper::filterBadProtocol($url), $expected_html, '\Drupal\Component\Utility\UrlHelper::filterBadProtocol() filters a URL and encodes it for HTML.');
$this->assertIdentical(UrlHelper::stripDangerousProtocols($url), $expected_plain, '\Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() filters a URL and returns plain text.');
}
}

View file

@ -1,49 +0,0 @@
<?php
namespace Drupal\system\Tests\Condition;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\simpletest\KernelTestBase;
/**
* Tests the CurrentThemeCondition plugin.
*
* @group Condition
*/
class CurrentThemeConditionTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = array('system', 'theme_test');
/**
* Tests the current theme condition.
*/
public function testCurrentTheme() {
\Drupal::service('theme_handler')->install(array('test_theme'));
$manager = \Drupal::service('plugin.manager.condition');
/** @var $condition \Drupal\Core\Condition\ConditionInterface */
$condition = $manager->createInstance('current_theme');
$condition->setConfiguration(array('theme' => 'test_theme'));
/** @var $condition_negated \Drupal\Core\Condition\ConditionInterface */
$condition_negated = $manager->createInstance('current_theme');
$condition_negated->setConfiguration(array('theme' => 'test_theme', 'negate' => TRUE));
$this->assertEqual($condition->summary(), SafeMarkup::format('The current theme is @theme', array('@theme' => 'test_theme')));
$this->assertEqual($condition_negated->summary(), SafeMarkup::format('The current theme is not @theme', array('@theme' => 'test_theme')));
// The expected theme has not been set up yet.
$this->assertFalse($condition->execute());
$this->assertTrue($condition_negated->execute());
// Set the expected theme to be used.
\Drupal::service('theme_handler')->setDefault('test_theme');
\Drupal::theme()->resetActiveTheme();
$this->assertTrue($condition->execute());
$this->assertFalse($condition_negated->execute());
}
}

View file

@ -1,47 +0,0 @@
<?php
namespace Drupal\system\Tests\DrupalKernel;
use Drupal\Core\Site\Settings;
use Drupal\simpletest\KernelTestBase;
/**
* Tests site-specific service overrides.
*
* @group DrupalKernel
*/
class DrupalKernelSiteTest extends KernelTestBase {
/**
* Tests services.yml in site directory.
*/
public function testServicesYml() {
$container_yamls = Settings::get('container_yamls');
$container_yamls[] = $this->siteDirectory . '/services.yml';
$this->settingsSet('container_yamls', $container_yamls);
$this->assertFalse($this->container->has('site.service.yml'));
// A service provider class always has precedence over services.yml files.
// KernelTestBase::buildContainer() swaps out many services with in-memory
// implementations already, so those cannot be tested.
$this->assertIdentical(get_class($this->container->get('cache.backend.database')), 'Drupal\Core\Cache\DatabaseBackendFactory');
$class = __CLASS__;
$doc = <<<EOD
services:
# Add a new service.
site.service.yml:
class: $class
# Swap out a core service.
cache.backend.database:
class: Drupal\Core\Cache\MemoryBackendFactory
EOD;
file_put_contents($this->siteDirectory . '/services.yml', $doc);
// Rebuild the container.
$this->container->get('kernel')->rebuildContainer();
$this->assertTrue($this->container->has('site.service.yml'));
$this->assertIdentical(get_class($this->container->get('cache.backend.database')), 'Drupal\Core\Cache\MemoryBackendFactory');
}
}

View file

@ -1,58 +0,0 @@
<?php
namespace Drupal\system\Tests\DrupalKernel;
use Drupal\simpletest\KernelTestBase;
use Symfony\Component\HttpFoundation\Response;
/**
* Tests that services are correctly destructed.
*
* @group DrupalKernel
*/
class ServiceDestructionTest extends KernelTestBase {
/**
* Verifies that services are destructed when used.
*/
public function testDestructionUsed() {
// Enable the test module to add it to the container.
$this->enableModules(array('service_provider_test'));
$request = $this->container->get('request_stack')->getCurrentRequest();
$kernel = $this->container->get('kernel');
$kernel->preHandle($request);
// The service has not been destructed yet.
$this->assertNull(\Drupal::state()->get('service_provider_test.destructed'));
// Call the class and then terminate the kernel
$this->container->get('service_provider_test_class');
$response = new Response();
$kernel->terminate($request, $response);
$this->assertTrue(\Drupal::state()->get('service_provider_test.destructed'));
}
/**
* Verifies that services are not unnecessarily destructed when not used.
*/
public function testDestructionUnused() {
// Enable the test module to add it to the container.
$this->enableModules(array('service_provider_test'));
$request = $this->container->get('request_stack')->getCurrentRequest();
$kernel = $this->container->get('kernel');
$kernel->preHandle($request);
// The service has not been destructed yet.
$this->assertNull(\Drupal::state()->get('service_provider_test.destructed'));
// Terminate the kernel. The test class has not been called, so it should not
// be destructed.
$response = new Response();
$kernel->terminate($request, $response);
$this->assertNull(\Drupal::state()->get('service_provider_test.destructed'));
}
}

View file

@ -1,205 +0,0 @@
<?php
namespace Drupal\system\Tests\Element;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\PathElement;
use Drupal\Core\Url;
use Drupal\simpletest\KernelTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
/**
* Tests PathElement validation and conversion functionality.
*
* @group Form
*/
class PathElementFormTest extends KernelTestBase implements FormInterface {
/**
* User for testing.
*
* @var \Drupal\user\UserInterface
*/
protected $testUser;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system', 'user');
/**
* Sets up the test.
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', ['sequences', 'key_value_expire']);
$this->installEntitySchema('user');
\Drupal::service('router.builder')->rebuild();
/** @var \Drupal\user\RoleInterface $role */
$role = Role::create(array(
'id' => 'admin',
'label' => 'admin',
));
$role->grantPermission('link to any page');
$role->save();
$this->testUser = User::create(array(
'name' => 'foobar',
'mail' => 'foobar@example.com',
));
$this->testUser->addRole($role->id());
$this->testUser->save();
\Drupal::service('current_user')->setAccount($this->testUser);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'test_path_element';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// A required validated path.
$form['required_validate'] = array(
'#type' => 'path',
'#required' => TRUE,
'#title' => 'required_validate',
'#convert_path' => PathElement::CONVERT_NONE,
);
// A non validated required path.
$form['required_non_validate'] = array(
'#type' => 'path',
'#required' => TRUE,
'#title' => 'required_non_validate',
'#convert_path' => PathElement::CONVERT_NONE,
'#validate_path' => FALSE,
);
// A non required validated path.
$form['optional_validate'] = array(
'#type' => 'path',
'#required' => FALSE,
'#title' => 'optional_validate',
'#convert_path' => PathElement::CONVERT_NONE,
);
// A non required converted path.
$form['optional_validate'] = array(
'#type' => 'path',
'#required' => FALSE,
'#title' => 'optional_validate',
'#convert_path' => PathElement::CONVERT_ROUTE,
);
// A converted required validated path.
$form['required_validate_route'] = array(
'#type' => 'path',
'#required' => TRUE,
'#title' => 'required_validate_route',
);
// A converted required validated path.
$form['required_validate_url'] = array(
'#type' => 'path',
'#required' => TRUE,
'#title' => 'required_validate_url',
'#convert_path' => PathElement::CONVERT_URL,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {}
/**
* Form validation handler.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public function validateForm(array &$form, FormStateInterface $form_state) {}
/**
* Tests that default handlers are added even if custom are specified.
*/
public function testPathElement() {
$form_state = (new FormState())
->setValues([
'required_validate' => 'user/' . $this->testUser->id(),
'required_non_validate' => 'magic-ponies',
'required_validate_route' => 'user/' . $this->testUser->id(),
'required_validate_url' => 'user/' . $this->testUser->id(),
]);
$form_builder = $this->container->get('form_builder');
$form_builder->submitForm($this, $form_state);
// Valid form state.
$this->assertEqual(count($form_state->getErrors()), 0);
$this->assertEqual($form_state->getValue('required_validate_route'), array(
'route_name' => 'entity.user.canonical',
'route_parameters' => array(
'user' => $this->testUser->id(),
),
));
/** @var \Drupal\Core\Url $url */
$url = $form_state->getValue('required_validate_url');
$this->assertTrue($url instanceof Url);
$this->assertEqual($url->getRouteName(), 'entity.user.canonical');
$this->assertEqual($url->getRouteParameters(), array(
'user' => $this->testUser->id(),
));
// Test #required.
$form_state = (new FormState())
->setValues([
'required_non_validate' => 'magic-ponies',
'required_validate_route' => 'user/' . $this->testUser->id(),
'required_validate_url' => 'user/' . $this->testUser->id(),
]);
$form_builder->submitForm($this, $form_state);
$errors = $form_state->getErrors();
// Should be missing 'required_validate' field.
$this->assertEqual(count($errors), 1);
$this->assertEqual($errors, array('required_validate' => t('@name field is required.', array('@name' => 'required_validate'))));
// Test invalid parameters.
$form_state = (new FormState())
->setValues([
'required_validate' => 'user/74',
'required_non_validate' => 'magic-ponies',
'required_validate_route' => 'user/74',
'required_validate_url' => 'user/74',
]);
$form_builder = $this->container->get('form_builder');
$form_builder->submitForm($this, $form_state);
// Valid form state.
$errors = $form_state->getErrors();
$this->assertEqual(count($errors), 3);
$this->assertEqual($errors, array(
'required_validate' => t('This path does not exist or you do not have permission to link to %path.', array('%path' => 'user/74')),
'required_validate_route' => t('This path does not exist or you do not have permission to link to %path.', array('%path' => 'user/74')),
'required_validate_url' => t('This path does not exist or you do not have permission to link to %path.', array('%path' => 'user/74')),
));
}
}

View file

@ -3,6 +3,7 @@
namespace Drupal\system\Tests\Entity;
use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
use Drupal\filter\Entity\FilterFormat;
use Drupal\image\Entity\ImageStyle;
use Drupal\search\Entity\SearchPage;
use Drupal\simpletest\WebTestBase;
@ -89,7 +90,7 @@ class ConfigEntityImportTest extends WebTestBase {
$name = 'filter.format.plain_text';
/** @var $entity \Drupal\filter\Entity\FilterFormat */
$entity = entity_load('filter_format', 'plain_text');
$entity = FilterFormat::load('plain_text');
$plugin_collection = $entity->getPluginCollections()['filters'];
$filters = $entity->get('filters');

View file

@ -515,7 +515,9 @@ abstract class EntityCacheTagsTestBase extends PageCacheTagsTestBase {
// cache miss for both the referencing entity, and the listing of
// referencing entities, but not for any other routes.
$this->pass("Test modification of referenced entity's bundle entity.", 'Debug');
$bundle_entity = entity_load($bundle_entity_type_id, $this->entity->bundle());
$bundle_entity = $this->container->get('entity_type.manager')
->getStorage($bundle_entity_type_id)
->load($this->entity->bundle());
$bundle_entity->save();
$this->verifyPageCache($referencing_entity_url, 'MISS');
$this->verifyPageCache($listing_url, 'MISS');

View file

@ -83,7 +83,8 @@ class EntityRevisionsTest extends WebTestBase {
$legacy_name = $entity->name->value;
$legacy_text = $entity->field_test_text->value;
$entity = entity_load($entity_type, $entity->id->value);
$entity = $this->container->get('entity_type.manager')
->getStorage($entity_type)->load($entity->id->value);
$entity->setNewRevision(TRUE);
$names[] = $entity->name->value = $this->randomMachineName(32);
$texts[] = $entity->field_test_text->value = $this->randomMachineName(32);
@ -112,7 +113,9 @@ class EntityRevisionsTest extends WebTestBase {
}
// Confirm the correct revision text appears in the edit form.
$entity = entity_load($entity_type, $entity->id->value);
$entity = $this->container->get('entity_type.manager')
->getStorage($entity_type)
->load($entity->id->value);
$this->drupalGet($entity_type . '/manage/' . $entity->id->value . '/edit');
$this->assertFieldById('edit-name-0-value', $entity->name->value, format_string('%entity_type: Name matches in UI.', array('%entity_type' => $entity_type)));
$this->assertFieldById('edit-field-test-text-0-value', $entity->field_test_text->value, format_string('%entity_type: Text matches in UI.', array('%entity_type' => $entity_type)));

View file

@ -86,7 +86,11 @@ class EntityTranslationFormTest extends WebTestBase {
$edit['body[0][value]'] = $this->randomMachineName(16);
$edit['langcode[0][value]'] = $langcode;
$this->drupalPostForm('node/add/page', $edit, t('Save'));
$this->assertRaw(t('Basic page %title has been created.', array('%title' => $edit['title[0][value]'])), 'Basic page created.');
$this->assertText(t('Basic page @title has been created.', array('@title' => $edit['title[0][value]'])), 'Basic page created.');
// Verify that the creation message contains a link to a node.
$view_link = $this->xpath('//div[@class="messages"]//a[contains(@href, :href)]', array(':href' => 'node/'));
$this->assert(isset($view_link), 'The message area contains a link to a node');
// Check to make sure the node was created.
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);

View file

@ -80,7 +80,9 @@ abstract class EntityWithUriCacheTagsTestBase extends EntityCacheTagsTestBase {
// Verify that after modifying the corresponding bundle entity, there is a
// cache miss.
$this->pass("Test modification of entity's bundle entity.", 'Debug');
$bundle_entity = entity_load($bundle_entity_type_id, $this->entity->bundle());
$bundle_entity = $this->container->get('entity_type.manager')
->getStorage($bundle_entity_type_id)
->load($this->entity->bundle());
$bundle_entity->save();
$this->verifyPageCache($entity_url, 'MISS');

View file

@ -1,395 +0,0 @@
<?php
namespace Drupal\system\Tests\Extension;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Extension\ExtensionNameLengthException;
use Drupal\simpletest\KernelTestBase;
/**
* Tests installing and uninstalling of themes.
*
* @group Extension
*/
class ThemeInstallerTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
public function containerBuild(ContainerBuilder $container) {
parent::containerBuild($container);
// Some test methods involve ModuleHandler operations, which attempt to
// rebuild and dump routes.
$container
->register('router.dumper', 'Drupal\Core\Routing\NullMatcherDumper');
}
protected function setUp() {
parent::setUp();
$this->installConfig(array('system'));
}
/**
* Verifies that no themes are installed by default.
*/
function testEmpty() {
$this->assertFalse($this->extensionConfig()->get('theme'));
$this->assertFalse(array_keys($this->themeHandler()->listInfo()));
$this->assertFalse(array_keys(system_list('theme')));
// Rebuilding available themes should always yield results though.
$this->assertTrue($this->themeHandler()->rebuildThemeData()['stark'], 'ThemeHandler::rebuildThemeData() yields all available themes.');
// theme_get_setting() should return global default theme settings.
$this->assertIdentical(theme_get_setting('features.favicon'), TRUE);
}
/**
* Tests installing a theme.
*/
function testInstall() {
$name = 'test_basetheme';
$themes = $this->themeHandler()->listInfo();
$this->assertFalse(isset($themes[$name]));
$this->themeInstaller()->install(array($name));
$this->assertIdentical($this->extensionConfig()->get("theme.$name"), 0);
$themes = $this->themeHandler()->listInfo();
$this->assertTrue(isset($themes[$name]));
$this->assertEqual($themes[$name]->getName(), $name);
$this->assertEqual(array_keys(system_list('theme')), array_keys($themes));
// Verify that test_basetheme.settings is active.
$this->assertIdentical(theme_get_setting('features.favicon', $name), FALSE);
$this->assertEqual(theme_get_setting('base', $name), 'only');
$this->assertEqual(theme_get_setting('override', $name), 'base');
}
/**
* Tests installing a sub-theme.
*/
function testInstallSubTheme() {
$name = 'test_subtheme';
$base_name = 'test_basetheme';
$themes = $this->themeHandler()->listInfo();
$this->assertFalse(array_keys($themes));
$this->themeInstaller()->install(array($name));
$themes = $this->themeHandler()->listInfo();
$this->assertTrue(isset($themes[$name]));
$this->assertTrue(isset($themes[$base_name]));
$this->themeInstaller()->uninstall(array($name));
$themes = $this->themeHandler()->listInfo();
$this->assertFalse(isset($themes[$name]));
$this->assertTrue(isset($themes[$base_name]));
}
/**
* Tests installing a non-existing theme.
*/
function testInstallNonExisting() {
$name = 'non_existing_theme';
$themes = $this->themeHandler()->listInfo();
$this->assertFalse(array_keys($themes));
try {
$message = 'ThemeHandler::install() throws InvalidArgumentException upon installing a non-existing theme.';
$this->themeInstaller()->install(array($name));
$this->fail($message);
}
catch (\InvalidArgumentException $e) {
$this->pass(get_class($e) . ': ' . $e->getMessage());
}
$themes = $this->themeHandler()->listInfo();
$this->assertFalse(array_keys($themes));
}
/**
* Tests installing a theme with a too long name.
*/
function testInstallNameTooLong() {
$name = 'test_theme_having_veery_long_name_which_is_too_long';
try {
$message = 'ThemeHandler::install() throws ExtensionNameLengthException upon installing a theme with a too long name.';
$this->themeInstaller()->install(array($name));
$this->fail($message);
}
catch (ExtensionNameLengthException $e) {
$this->pass(get_class($e) . ': ' . $e->getMessage());
}
}
/**
* Tests uninstalling the default theme.
*/
function testUninstallDefault() {
$name = 'stark';
$other_name = 'bartik';
$this->themeInstaller()->install(array($name, $other_name));
$this->themeHandler()->setDefault($name);
$themes = $this->themeHandler()->listInfo();
$this->assertTrue(isset($themes[$name]));
$this->assertTrue(isset($themes[$other_name]));
try {
$message = 'ThemeHandler::uninstall() throws InvalidArgumentException upon disabling default theme.';
$this->themeHandler()->uninstall(array($name));
$this->fail($message);
}
catch (\InvalidArgumentException $e) {
$this->pass(get_class($e) . ': ' . $e->getMessage());
}
$themes = $this->themeHandler()->listInfo();
$this->assertTrue(isset($themes[$name]));
$this->assertTrue(isset($themes[$other_name]));
}
/**
* Tests uninstalling the admin theme.
*/
function testUninstallAdmin() {
$name = 'stark';
$other_name = 'bartik';
$this->themeInstaller()->install(array($name, $other_name));
$this->config('system.theme')->set('admin', $name)->save();
$themes = $this->themeHandler()->listInfo();
$this->assertTrue(isset($themes[$name]));
$this->assertTrue(isset($themes[$other_name]));
try {
$message = 'ThemeHandler::uninstall() throws InvalidArgumentException upon disabling admin theme.';
$this->themeHandler()->uninstall(array($name));
$this->fail($message);
}
catch (\InvalidArgumentException $e) {
$this->pass(get_class($e) . ': ' . $e->getMessage());
}
$themes = $this->themeHandler()->listInfo();
$this->assertTrue(isset($themes[$name]));
$this->assertTrue(isset($themes[$other_name]));
}
/**
* Tests uninstalling a sub-theme.
*/
function testUninstallSubTheme() {
$name = 'test_subtheme';
$base_name = 'test_basetheme';
$this->themeInstaller()->install(array($name));
$this->themeInstaller()->uninstall(array($name));
$themes = $this->themeHandler()->listInfo();
$this->assertFalse(isset($themes[$name]));
$this->assertTrue(isset($themes[$base_name]));
}
/**
* Tests uninstalling a base theme before its sub-theme.
*/
function testUninstallBaseBeforeSubTheme() {
$name = 'test_basetheme';
$sub_name = 'test_subtheme';
$this->themeInstaller()->install(array($sub_name));
try {
$message = 'ThemeHandler::install() throws InvalidArgumentException upon uninstalling base theme before sub theme.';
$this->themeInstaller()->uninstall(array($name));
$this->fail($message);
}
catch (\InvalidArgumentException $e) {
$this->pass(get_class($e) . ': ' . $e->getMessage());
}
$themes = $this->themeHandler()->listInfo();
$this->assertTrue(isset($themes[$name]));
$this->assertTrue(isset($themes[$sub_name]));
// Verify that uninstalling both at the same time works.
$this->themeInstaller()->uninstall(array($name, $sub_name));
$themes = $this->themeHandler()->listInfo();
$this->assertFalse(isset($themes[$name]));
$this->assertFalse(isset($themes[$sub_name]));
}
/**
* Tests uninstalling a non-existing theme.
*/
function testUninstallNonExisting() {
$name = 'non_existing_theme';
$themes = $this->themeHandler()->listInfo();
$this->assertFalse(array_keys($themes));
try {
$message = 'ThemeHandler::uninstall() throws InvalidArgumentException upon uninstalling a non-existing theme.';
$this->themeInstaller()->uninstall(array($name));
$this->fail($message);
}
catch (\InvalidArgumentException $e) {
$this->pass(get_class($e) . ': ' . $e->getMessage());
}
$themes = $this->themeHandler()->listInfo();
$this->assertFalse(array_keys($themes));
}
/**
* Tests uninstalling a theme.
*/
function testUninstall() {
$name = 'test_basetheme';
$this->themeInstaller()->install(array($name));
$this->assertTrue($this->config("$name.settings")->get());
$this->themeInstaller()->uninstall(array($name));
$this->assertFalse(array_keys($this->themeHandler()->listInfo()));
$this->assertFalse(array_keys(system_list('theme')));
$this->assertFalse($this->config("$name.settings")->get());
// Ensure that the uninstalled theme can be installed again.
$this->themeInstaller()->install(array($name));
$themes = $this->themeHandler()->listInfo();
$this->assertTrue(isset($themes[$name]));
$this->assertEqual($themes[$name]->getName(), $name);
$this->assertEqual(array_keys(system_list('theme')), array_keys($themes));
$this->assertTrue($this->config("$name.settings")->get());
}
/**
* Tests uninstalling a theme that is not installed.
*/
function testUninstallNotInstalled() {
$name = 'test_basetheme';
try {
$message = 'ThemeHandler::uninstall() throws InvalidArgumentException upon uninstalling a theme that is not installed.';
$this->themeInstaller()->uninstall(array($name));
$this->fail($message);
}
catch (\InvalidArgumentException $e) {
$this->pass(get_class($e) . ': ' . $e->getMessage());
}
}
/**
* Tests that theme info can be altered by a module.
*
* @see module_test_system_info_alter()
*/
function testThemeInfoAlter() {
$name = 'seven';
$this->container->get('state')->set('module_test.hook_system_info_alter', TRUE);
$this->themeInstaller()->install(array($name));
$themes = $this->themeHandler()->listInfo();
$this->assertFalse(isset($themes[$name]->info['regions']['test_region']));
// Rebuild module data so we know where module_test is located.
// @todo Remove as part of https://www.drupal.org/node/2186491
system_rebuild_module_data();
$this->moduleInstaller()->install(array('module_test'), FALSE);
$this->assertTrue($this->moduleHandler()->moduleExists('module_test'));
$themes = $this->themeHandler()->listInfo();
$this->assertTrue(isset($themes[$name]->info['regions']['test_region']));
// Legacy assertions.
// @todo Remove once theme initialization/info has been modernized.
// @see https://www.drupal.org/node/2228093
$info = system_get_info('theme', $name);
$this->assertTrue(isset($info['regions']['test_region']));
$regions = system_region_list($name);
$this->assertTrue(isset($regions['test_region']));
$system_list = system_list('theme');
$this->assertTrue(isset($system_list[$name]->info['regions']['test_region']));
$this->moduleInstaller()->uninstall(array('module_test'));
$this->assertFalse($this->moduleHandler()->moduleExists('module_test'));
$themes = $this->themeHandler()->listInfo();
$this->assertFalse(isset($themes[$name]->info['regions']['test_region']));
// Legacy assertions.
// @todo Remove once theme initialization/info has been modernized.
// @see https://www.drupal.org/node/2228093
$info = system_get_info('theme', $name);
$this->assertFalse(isset($info['regions']['test_region']));
$regions = system_region_list($name);
$this->assertFalse(isset($regions['test_region']));
$system_list = system_list('theme');
$this->assertFalse(isset($system_list[$name]->info['regions']['test_region']));
}
/**
* Returns the theme handler service.
*
* @return \Drupal\Core\Extension\ThemeHandlerInterface
*/
protected function themeHandler() {
return $this->container->get('theme_handler');
}
/**
* Returns the theme installer service.
*
* @return \Drupal\Core\Extension\ThemeInstallerInterface
*/
protected function themeInstaller() {
return $this->container->get('theme_installer');
}
/**
* Returns the system.theme config object.
*
* @return \Drupal\Core\Config\Config
*/
protected function extensionConfig() {
return $this->config('core.extension');
}
/**
* 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

@ -1,32 +0,0 @@
<?php
namespace Drupal\system\Tests\Extension;
use Drupal\simpletest\KernelTestBase;
use Drupal\Core\Updater\Updater;
/**
* Tests InfoParser class and exception.
*
* Files for this test are stored in core/modules/system/tests/fixtures and end
* with .info.txt instead of info.yml in order not not be considered as real
* extensions.
*
* @group Extension
*/
class UpdaterTest extends KernelTestBase {
/**
* Tests project and child project showing correct title.
*
* @see https://drupal.org/node/2409515
*/
public function testGetProjectTitleWithChild() {
// Get the project title from it's directory. If it can't find the title
// it will choose the first project title in the directory.
$directory = \Drupal::root() . '/core/modules/system/tests/modules/module_handler_test_multiple';
$title = Updater::getProjectTitle($directory);
$this->assertEqual('module handler test multiple', $title);
}
}

View file

@ -1,163 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
use Drupal\Component\PhpStorage\FileStorage;
/**
* Tests operations dealing with directories.
*
* @group File
*/
class DirectoryTest extends FileTestBase {
/**
* Test local directory handling functions.
*/
function testFileCheckLocalDirectoryHandling() {
$site_path = $this->container->get('site.path');
$directory = $site_path . '/files';
// Check a new recursively created local directory for correct file system
// permissions.
$parent = $this->randomMachineName();
$child = $this->randomMachineName();
// Files directory already exists.
$this->assertTrue(is_dir($directory), t('Files directory already exists.'), 'File');
// Make files directory writable only.
$old_mode = fileperms($directory);
// Create the directories.
$parent_path = $directory . DIRECTORY_SEPARATOR . $parent;
$child_path = $parent_path . DIRECTORY_SEPARATOR . $child;
$this->assertTrue(drupal_mkdir($child_path, 0775, TRUE), t('No error reported when creating new local directories.'), 'File');
// Ensure new directories also exist.
$this->assertTrue(is_dir($parent_path), t('New parent directory actually exists.'), 'File');
$this->assertTrue(is_dir($child_path), t('New child directory actually exists.'), 'File');
// Check that new directory permissions were set properly.
$this->assertDirectoryPermissions($parent_path, 0775);
$this->assertDirectoryPermissions($child_path, 0775);
// Check that existing directory permissions were not modified.
$this->assertDirectoryPermissions($directory, $old_mode);
// Check creating a directory using an absolute path.
$absolute_path = drupal_realpath($directory) . DIRECTORY_SEPARATOR . $this->randomMachineName() . DIRECTORY_SEPARATOR . $this->randomMachineName();
$this->assertTrue(drupal_mkdir($absolute_path, 0775, TRUE), 'No error reported when creating new absolute directories.', 'File');
$this->assertDirectoryPermissions($absolute_path, 0775);
}
/**
* Test directory handling functions.
*/
function testFileCheckDirectoryHandling() {
// A directory to operate on.
$directory = file_default_scheme() . '://' . $this->randomMachineName() . '/' . $this->randomMachineName();
$this->assertFalse(is_dir($directory), 'Directory does not exist prior to testing.');
// Non-existent directory.
$this->assertFalse(file_prepare_directory($directory, 0), 'Error reported for non-existing directory.', 'File');
// Make a directory.
$this->assertTrue(file_prepare_directory($directory, FILE_CREATE_DIRECTORY), 'No error reported when creating a new directory.', 'File');
// Make sure directory actually exists.
$this->assertTrue(is_dir($directory), 'Directory actually exists.', 'File');
if (substr(PHP_OS, 0, 3) != 'WIN') {
// PHP on Windows doesn't support any kind of useful read-only mode for
// directories. When executing a chmod() on a directory, PHP only sets the
// read-only flag, which doesn't prevent files to actually be written
// in the directory on any recent version of Windows.
// Make directory read only.
@drupal_chmod($directory, 0444);
$this->assertFalse(file_prepare_directory($directory, 0), 'Error reported for a non-writeable directory.', 'File');
// Test directory permission modification.
$this->settingsSet('file_chmod_directory', 0777);
$this->assertTrue(file_prepare_directory($directory, FILE_MODIFY_PERMISSIONS), 'No error reported when making directory writeable.', 'File');
}
// Test that the directory has the correct permissions.
$this->assertDirectoryPermissions($directory, 0777, 'file_chmod_directory setting is respected.');
// Remove .htaccess file to then test that it gets re-created.
@drupal_unlink(file_default_scheme() . '://.htaccess');
$this->assertFalse(is_file(file_default_scheme() . '://.htaccess'), 'Successfully removed the .htaccess file in the files directory.', 'File');
file_ensure_htaccess();
$this->assertTrue(is_file(file_default_scheme() . '://.htaccess'), 'Successfully re-created the .htaccess file in the files directory.', 'File');
// Verify contents of .htaccess file.
$file = file_get_contents(file_default_scheme() . '://.htaccess');
$this->assertEqual($file, FileStorage::htaccessLines(FALSE), 'The .htaccess file contains the proper content.', 'File');
}
/**
* This will take a directory and path, and find a valid filepath that is not
* taken by another file.
*/
function testFileCreateNewFilepath() {
// First we test against an imaginary file that does not exist in a
// directory.
$basename = 'xyz.txt';
$directory = 'core/misc';
$original = $directory . '/' . $basename;
$path = file_create_filename($basename, $directory);
$this->assertEqual($path, $original, format_string('New filepath %new equals %original.', array('%new' => $path, '%original' => $original)), 'File');
// Then we test against a file that already exists within that directory.
$basename = 'druplicon.png';
$original = $directory . '/' . $basename;
$expected = $directory . '/druplicon_0.png';
$path = file_create_filename($basename, $directory);
$this->assertEqual($path, $expected, format_string('Creating a new filepath from %original equals %new (expected %expected).', array('%new' => $path, '%original' => $original, '%expected' => $expected)), 'File');
// @TODO: Finally we copy a file into a directory several times, to ensure a properly iterating filename suffix.
}
/**
* This will test the filepath for a destination based on passed flags and
* whether or not the file exists.
*
* If a file exists, file_destination($destination, $replace) will either
* return:
* - the existing filepath, if $replace is FILE_EXISTS_REPLACE
* - a new filepath if FILE_EXISTS_RENAME
* - an error (returning FALSE) if FILE_EXISTS_ERROR.
* If the file doesn't currently exist, then it will simply return the
* filepath.
*/
function testFileDestination() {
// First test for non-existent file.
$destination = 'core/misc/xyz.txt';
$path = file_destination($destination, FILE_EXISTS_REPLACE);
$this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FILE_EXISTS_REPLACE.', 'File');
$path = file_destination($destination, FILE_EXISTS_RENAME);
$this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FILE_EXISTS_RENAME.', 'File');
$path = file_destination($destination, FILE_EXISTS_ERROR);
$this->assertEqual($path, $destination, 'Non-existing filepath destination is correct with FILE_EXISTS_ERROR.', 'File');
$destination = 'core/misc/druplicon.png';
$path = file_destination($destination, FILE_EXISTS_REPLACE);
$this->assertEqual($path, $destination, 'Existing filepath destination remains the same with FILE_EXISTS_REPLACE.', 'File');
$path = file_destination($destination, FILE_EXISTS_RENAME);
$this->assertNotEqual($path, $destination, 'A new filepath destination is created when filepath destination already exists with FILE_EXISTS_RENAME.', 'File');
$path = file_destination($destination, FILE_EXISTS_ERROR);
$this->assertEqual($path, FALSE, 'An error is returned when filepath destination already exists with FILE_EXISTS_ERROR.', 'File');
}
/**
* Ensure that the file_directory_temp() function always returns a value.
*/
function testFileDirectoryTemp() {
// Start with an empty variable to ensure we have a clean slate.
$config = $this->config('system.file');
$config->set('path.temporary', '')->save();
$tmp_directory = file_directory_temp();
$this->assertEqual(empty($tmp_directory), FALSE, 'file_directory_temp() returned a non-empty value.');
$this->assertEqual($config->get('path.temporary'), $tmp_directory);
}
}

View file

@ -1,168 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
use Drupal\simpletest\KernelTestBase;
/**
* Base class for file tests that adds some additional file specific
* assertions and helper functions.
*/
abstract class FileTestBase extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
/**
* A stream wrapper scheme to register for the test.
*
* @var string
*/
protected $scheme;
/**
* A fully-qualified stream wrapper class name to register for the test.
*
* @var string
*/
protected $classname;
protected function setUp() {
parent::setUp();
$this->installConfig(array('system'));
$this->registerStreamWrapper('private', 'Drupal\Core\StreamWrapper\PrivateStream');
if (isset($this->scheme)) {
$this->registerStreamWrapper($this->scheme, $this->classname);
}
}
/**
* Helper function to test the permissions of a file.
*
* @param $filepath
* String file path.
* @param $expected_mode
* Octal integer like 0664 or 0777.
* @param $message
* Optional message.
*/
function assertFilePermissions($filepath, $expected_mode, $message = NULL) {
// Clear out PHP's file stat cache to be sure we see the current value.
clearstatcache(TRUE, $filepath);
// Mask out all but the last three octets.
$actual_mode = fileperms($filepath) & 0777;
// PHP on Windows has limited support for file permissions. Usually each of
// "user", "group" and "other" use one octal digit (3 bits) to represent the
// read/write/execute bits. On Windows, chmod() ignores the "group" and
// "other" bits, and fileperms() returns the "user" bits in all three
// positions. $expected_mode is updated to reflect this.
if (substr(PHP_OS, 0, 3) == 'WIN') {
// Reset the "group" and "other" bits.
$expected_mode = $expected_mode & 0700;
// Shift the "user" bits to the "group" and "other" positions also.
$expected_mode = $expected_mode | $expected_mode >> 3 | $expected_mode >> 6;
}
if (!isset($message)) {
$message = t('Expected file permission to be %expected, actually were %actual.', array('%actual' => decoct($actual_mode), '%expected' => decoct($expected_mode)));
}
$this->assertEqual($actual_mode, $expected_mode, $message);
}
/**
* Helper function to test the permissions of a directory.
*
* @param $directory
* String directory path.
* @param $expected_mode
* Octal integer like 0664 or 0777.
* @param $message
* Optional message.
*/
function assertDirectoryPermissions($directory, $expected_mode, $message = NULL) {
// Clear out PHP's file stat cache to be sure we see the current value.
clearstatcache(TRUE, $directory);
// Mask out all but the last three octets.
$actual_mode = fileperms($directory) & 0777;
$expected_mode = $expected_mode & 0777;
// PHP on Windows has limited support for file permissions. Usually each of
// "user", "group" and "other" use one octal digit (3 bits) to represent the
// read/write/execute bits. On Windows, chmod() ignores the "group" and
// "other" bits, and fileperms() returns the "user" bits in all three
// positions. $expected_mode is updated to reflect this.
if (substr(PHP_OS, 0, 3) == 'WIN') {
// Reset the "group" and "other" bits.
$expected_mode = $expected_mode & 0700;
// Shift the "user" bits to the "group" and "other" positions also.
$expected_mode = $expected_mode | $expected_mode >> 3 | $expected_mode >> 6;
}
if (!isset($message)) {
$message = t('Expected directory permission to be %expected, actually were %actual.', array('%actual' => decoct($actual_mode), '%expected' => decoct($expected_mode)));
}
$this->assertEqual($actual_mode, $expected_mode, $message);
}
/**
* Create a directory and assert it exists.
*
* @param $path
* Optional string with a directory path. If none is provided, a random
* name in the site's files directory will be used.
* @return
* The path to the directory.
*/
function createDirectory($path = NULL) {
// A directory to operate on.
if (!isset($path)) {
$path = file_default_scheme() . '://' . $this->randomMachineName();
}
$this->assertTrue(drupal_mkdir($path) && is_dir($path), 'Directory was created successfully.');
return $path;
}
/**
* Create a file and return the URI of it.
*
* @param $filepath
* Optional string specifying the file path. If none is provided then a
* randomly named file will be created in the site's files directory.
* @param $contents
* Optional contents to save into the file. If a NULL value is provided an
* arbitrary string will be used.
* @param $scheme
* Optional string indicating the stream scheme to use. Drupal core includes
* public, private, and temporary. The public wrapper is the default.
* @return
* File URI.
*/
function createUri($filepath = NULL, $contents = NULL, $scheme = NULL) {
if (!isset($filepath)) {
// Prefix with non-latin characters to ensure that all file-related
// tests work with international filenames.
$filepath = 'Файл для тестирования ' . $this->randomMachineName();
}
if (!isset($scheme)) {
$scheme = file_default_scheme();
}
$filepath = $scheme . '://' . $filepath;
if (!isset($contents)) {
$contents = "file_put_contents() doesn't seem to appreciate empty strings so let's put in some data.";
}
file_put_contents($filepath, $contents);
$this->assertTrue(is_file($filepath), t('The test file exists on the disk.'), 'Create test file');
return $filepath;
}
}

View file

@ -1,91 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\simpletest\KernelTestBase;
/**
* Tests .htaccess file saving.
*
* @group File
*/
class HtaccessUnitTest extends KernelTestBase {
/**
* Tests file_save_htaccess().
*/
function testHtaccessSave() {
// Prepare test directories.
$public = $this->publicFilesDirectory . '/test/public';
$private = $this->publicFilesDirectory . '/test/private';
$stream = 'public://test/stream';
// Verify that file_save_htaccess() returns FALSE if .htaccess cannot be
// written.
// Note: We cannot test the condition of a directory lacking write
// permissions, since at least on Windows file_save_htaccess() succeeds
// even when changing directory permissions to 0000.
$this->assertFalse(file_save_htaccess($public, FALSE));
// Create public .htaccess file.
mkdir($public, 0777, TRUE);
$this->assertTrue(file_save_htaccess($public, FALSE));
$content = file_get_contents($public . '/.htaccess');
$this->assertTrue(strpos($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006") !== FALSE);
$this->assertFalse(strpos($content, "Require all denied") !== FALSE);
$this->assertFalse(strpos($content, "Deny from all") !== FALSE);
$this->assertTrue(strpos($content, "Options -Indexes -ExecCGI -Includes -MultiViews") !== FALSE);
$this->assertTrue(strpos($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003") !== FALSE);
$this->assertFilePermissions($public . '/.htaccess', 0444);
$this->assertTrue(file_save_htaccess($public, FALSE));
// Create private .htaccess file.
mkdir($private, 0777, TRUE);
$this->assertTrue(file_save_htaccess($private));
$content = file_get_contents($private . '/.htaccess');
$this->assertTrue(strpos($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006") !== FALSE);
$this->assertTrue(strpos($content, "Require all denied") !== FALSE);
$this->assertTrue(strpos($content, "Deny from all") !== FALSE);
$this->assertTrue(strpos($content, "Options -Indexes -ExecCGI -Includes -MultiViews") !== FALSE);
$this->assertTrue(strpos($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003") !== FALSE);
$this->assertFilePermissions($private . '/.htaccess', 0444);
$this->assertTrue(file_save_htaccess($private));
// Create an .htaccess file using a stream URI.
mkdir($stream, 0777, TRUE);
$this->assertTrue(file_save_htaccess($stream));
$content = file_get_contents($stream . '/.htaccess');
$this->assertTrue(strpos($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006") !== FALSE);
$this->assertTrue(strpos($content, "Require all denied") !== FALSE);
$this->assertTrue(strpos($content, "Deny from all") !== FALSE);
$this->assertTrue(strpos($content, "Options -Indexes -ExecCGI -Includes -MultiViews") !== FALSE);
$this->assertTrue(strpos($content, "SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003") !== FALSE);
$this->assertFilePermissions($stream . '/.htaccess', 0444);
$this->assertTrue(file_save_htaccess($stream));
}
/**
* Asserts expected file permissions for a given file.
*
* @param string $uri
* The URI of the file to check.
* @param int $expected
* The expected file permissions; e.g., 0444.
*
* @return bool
* Whether the actual file permissions match the expected.
*/
protected function assertFilePermissions($uri, $expected) {
$actual = fileperms($uri) & 0777;
return $this->assertIdentical($actual, $expected, SafeMarkup::format('@uri file permissions @actual are identical to @expected.', array(
'@uri' => $uri,
'@actual' => 0 . decoct($actual),
'@expected' => 0 . decoct($expected),
)));
}
}

View file

@ -1,92 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests filename mimetype detection.
*
* @group File
*/
class MimeTypeTest extends FileTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
/**
* Test mapping of mimetypes from filenames.
*/
public function testFileMimeTypeDetection() {
$prefixes = ['public://', 'private://', 'temporary://', 'dummy-remote://'];
$test_case = array(
'test.jar' => 'application/java-archive',
'test.jpeg' => 'image/jpeg',
'test.JPEG' => 'image/jpeg',
'test.jpg' => 'image/jpeg',
'test.jar.jpg' => 'image/jpeg',
'test.jpg.jar' => 'application/java-archive',
'test.pcf.Z' => 'application/x-font',
'pcf.z' => 'application/octet-stream',
'jar' => 'application/octet-stream',
'some.junk' => 'application/octet-stream',
'foo.file_test_1' => 'madeup/file_test_1',
'foo.file_test_2' => 'madeup/file_test_2',
'foo.doc' => 'madeup/doc',
'test.ogg' => 'audio/ogg',
);
$guesser = $this->container->get('file.mime_type.guesser');
// Test using default mappings.
foreach ($test_case as $input => $expected) {
// Test stream [URI].
foreach ($prefixes as $prefix) {
$output = $guesser->guess($prefix . $input);
$this->assertIdentical($output, $expected, format_string('Mimetype for %input is %output (expected: %expected).', array('%input' => $prefix . $input, '%output' => $output, '%expected' => $expected)));
}
// Test normal path equivalent
$output = $guesser->guess($input);
$this->assertIdentical($output, $expected, format_string('Mimetype (using default mappings) for %input is %output (expected: %expected).', array('%input' => $input, '%output' => $output, '%expected' => $expected)));
}
// Now test the extension gusser by passing in a custom mapping.
$mapping = array(
'mimetypes' => array(
0 => 'application/java-archive',
1 => 'image/jpeg',
),
'extensions' => array(
'jar' => 0,
'jpg' => 1,
)
);
$test_case = array(
'test.jar' => 'application/java-archive',
'test.jpeg' => 'application/octet-stream',
'test.jpg' => 'image/jpeg',
'test.jar.jpg' => 'image/jpeg',
'test.jpg.jar' => 'application/java-archive',
'test.pcf.z' => 'application/octet-stream',
'pcf.z' => 'application/octet-stream',
'jar' => 'application/octet-stream',
'some.junk' => 'application/octet-stream',
'foo.file_test_1' => 'application/octet-stream',
'foo.file_test_2' => 'application/octet-stream',
'foo.doc' => 'application/octet-stream',
'test.ogg' => 'application/octet-stream',
);
$extension_guesser = $this->container->get('file.mime_type.guesser.extension');
$extension_guesser->setMapping($mapping);
foreach ($test_case as $input => $expected) {
$output = $extension_guesser->guess($input);
$this->assertIdentical($output, $expected, format_string('Mimetype (using passed-in mappings) for %input is %output (expected: %expected).', array('%input' => $input, '%output' => $output, '%expected' => $expected)));
}
}
}

View file

@ -1,87 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests filename munging and unmunging.
*
* @group File
*/
class NameMungingTest extends FileTestBase {
/**
* @var string
*/
protected $badExtension;
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $nameWithUcExt;
protected function setUp() {
parent::setUp();
$this->badExtension = 'php';
$this->name = $this->randomMachineName() . '.' . $this->badExtension . '.txt';
$this->nameWithUcExt = $this->randomMachineName() . '.' . strtoupper($this->badExtension) . '.txt';
}
/**
* Create a file and munge/unmunge the name.
*/
function testMunging() {
// Disable insecure uploads.
$this->config('system.file')->set('allow_insecure_uploads', 0)->save();
$munged_name = file_munge_filename($this->name, '', TRUE);
$messages = drupal_get_messages();
$this->assertTrue(in_array(strtr('For security reasons, your upload has been renamed to <em class="placeholder">%filename</em>.', array('%filename' => $munged_name)), $messages['status']), 'Alert properly set when a file is renamed.');
$this->assertNotEqual($munged_name, $this->name, format_string('The new filename (%munged) has been modified from the original (%original)', array('%munged' => $munged_name, '%original' => $this->name)));
}
/**
* Tests munging with a null byte in the filename.
*/
function testMungeNullByte() {
$prefix = $this->randomMachineName();
$filename = $prefix . '.' . $this->badExtension . "\0.txt";
$this->assertEqual(file_munge_filename($filename, ''), $prefix . '.' . $this->badExtension . '_.txt', 'A filename with a null byte is correctly munged to remove the null byte.');
}
/**
* If the system.file.allow_insecure_uploads setting evaluates to true, the file should
* come out untouched, no matter how evil the filename.
*/
function testMungeIgnoreInsecure() {
$this->config('system.file')->set('allow_insecure_uploads', 1)->save();
$munged_name = file_munge_filename($this->name, '');
$this->assertIdentical($munged_name, $this->name, format_string('The original filename (%original) matches the munged filename (%munged) when insecure uploads are enabled.', array('%munged' => $munged_name, '%original' => $this->name)));
}
/**
* White listed extensions are ignored by file_munge_filename().
*/
function testMungeIgnoreWhitelisted() {
// Declare our extension as whitelisted. The declared extensions should
// be case insensitive so test using one with a different case.
$munged_name = file_munge_filename($this->nameWithUcExt, $this->badExtension);
$this->assertIdentical($munged_name, $this->nameWithUcExt, format_string('The new filename (%munged) matches the original (%original) once the extension has been whitelisted.', array('%munged' => $munged_name, '%original' => $this->nameWithUcExt)));
// The allowed extensions should also be normalized.
$munged_name = file_munge_filename($this->name, strtoupper($this->badExtension));
$this->assertIdentical($munged_name, $this->name, format_string('The new filename (%munged) matches the original (%original) also when the whitelisted extension is in uppercase.', array('%munged' => $munged_name, '%original' => $this->name)));
}
/**
* Ensure that unmunge gets your name back.
*/
function testUnMunge() {
$munged_name = file_munge_filename($this->name, '', FALSE);
$unmunged_name = file_unmunge_filename($munged_name);
$this->assertIdentical($unmunged_name, $this->name, format_string('The unmunged (%unmunged) filename matches the original (%original)', array('%unmunged' => $unmunged_name, '%original' => $this->name)));
}
}

View file

@ -1,98 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\file_test\StreamWrapper\DummyReadOnlyStreamWrapper;
/**
* Tests the read-only stream wrapper write functions.
*
* @group File
*/
class ReadOnlyStreamWrapperTest extends FileTestBase {
/**
* A stream wrapper scheme to register for the test.
*
* @var string
*/
protected $scheme = 'dummy-readonly';
/**
* A fully-qualified stream wrapper class name to register for the test.
*
* @var string
*/
protected $classname = 'Drupal\file_test\StreamWrapper\DummyReadOnlyStreamWrapper';
/**
* Test read-only specific behavior.
*/
function testReadOnlyBehavior() {
$type = DummyReadOnlyStreamWrapper::getType();
// Checks that the stream wrapper type is not declared as writable.
$this->assertIdentical(0, $type & StreamWrapperInterface::WRITE);
// Checks that the stream wrapper type is declared as local.
$this->assertIdentical(1, $type & StreamWrapperInterface::LOCAL);
// Generate a test file
$filename = $this->randomMachineName();
$site_path = $this->container->get('site.path');
$filepath = $site_path . '/files/' . $filename;
file_put_contents($filepath, $filename);
// Generate a read-only stream wrapper instance
$uri = $this->scheme . '://' . $filename;
\Drupal::service('stream_wrapper_manager')->getViaScheme($this->scheme);
// Attempt to open a file in read/write mode
$handle = @fopen($uri, 'r+');
$this->assertFalse($handle, 'Unable to open a file for reading and writing with the read-only stream wrapper.');
// Attempt to open a file in binary read mode
$handle = fopen($uri, 'rb');
$this->assertTrue($handle, 'Able to open a file for reading in binary mode with the read-only stream wrapper.');
$this->assertTrue(fclose($handle), 'Able to close file opened in binary mode using the read_only stream wrapper.');
// Attempt to open a file in text read mode
$handle = fopen($uri, 'rt');
$this->assertTrue($handle, 'Able to open a file for reading in text mode with the read-only stream wrapper.');
$this->assertTrue(fclose($handle), 'Able to close file opened in text mode using the read_only stream wrapper.');
// Attempt to open a file in read mode
$handle = fopen($uri, 'r');
$this->assertTrue($handle, 'Able to open a file for reading with the read-only stream wrapper.');
// Attempt to change file permissions
$this->assertFalse(@chmod($uri, 0777), 'Unable to change file permissions when using read-only stream wrapper.');
// Attempt to acquire an exclusive lock for writing
$this->assertFalse(@flock($handle, LOCK_EX | LOCK_NB), 'Unable to acquire an exclusive lock using the read-only stream wrapper.');
// Attempt to obtain a shared lock
$this->assertTrue(flock($handle, LOCK_SH | LOCK_NB), 'Able to acquire a shared lock using the read-only stream wrapper.');
// Attempt to release a shared lock
$this->assertTrue(flock($handle, LOCK_UN | LOCK_NB), 'Able to release a shared lock using the read-only stream wrapper.');
// Attempt to truncate the file
$this->assertFalse(@ftruncate($handle, 0), 'Unable to truncate using the read-only stream wrapper.');
// Attempt to write to the file
$this->assertFalse(@fwrite($handle, $this->randomMachineName()), 'Unable to write to file using the read-only stream wrapper.');
// Attempt to flush output to the file
$this->assertFalse(@fflush($handle), 'Unable to flush output to file using the read-only stream wrapper.');
// Attempt to close the stream. (Suppress errors, as fclose triggers fflush.)
$this->assertTrue(fclose($handle), 'Able to close file using the read_only stream wrapper.');
// Test the rename() function
$this->assertFalse(@rename($uri, $this->scheme . '://newname.txt'), 'Unable to rename files using the read-only stream wrapper.');
// Test the unlink() function
$this->assertTrue(@drupal_unlink($uri), 'Able to unlink file using read-only stream wrapper.');
$this->assertTrue(file_exists($filepath), 'Unlink File was not actually deleted.');
// Test the mkdir() function by attempting to create a directory.
$dirname = $this->randomMachineName();
$dir = $site_path . '/files/' . $dirname;
$readonlydir = $this->scheme . '://' . $dirname;
$this->assertFalse(@drupal_mkdir($readonlydir, 0775, 0), 'Unable to create directory with read-only stream wrapper.');
// Create a temporary directory for testing purposes
$this->assertTrue(drupal_mkdir($dir), 'Test directory created.');
// Test the rmdir() function by attempting to remove the directory.
$this->assertFalse(@drupal_rmdir($readonlydir), 'Unable to delete directory with read-only stream wrapper.');
// Remove the temporary directory.
drupal_rmdir($dir);
}
}

View file

@ -1,38 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests operations dealing with directories.
*
* @group File
*/
class RemoteFileDirectoryTest extends DirectoryTest {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
/**
* A stream wrapper scheme to register for the test.
*
* @var string
*/
protected $scheme = 'dummy-remote';
/**
* A fully-qualified stream wrapper class name to register for the test.
*
* @var string
*/
protected $classname = 'Drupal\file_test\StreamWrapper\DummyRemoteStreamWrapper';
protected function setUp() {
parent::setUp();
$this->config('system.file')->set('default_scheme', 'dummy-remote')->save();
}
}

View file

@ -1,38 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests the file_scan_directory() function.
*
* @group File
*/
class RemoteFileScanDirectoryTest extends ScanDirectoryTest {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
/**
* A stream wrapper scheme to register for the test.
*
* @var string
*/
protected $scheme = 'dummy-remote';
/**
* A fully-qualified stream wrapper class name to register for the test.
*
* @var string
*/
protected $classname = 'Drupal\file_test\StreamWrapper\DummyRemoteStreamWrapper';
protected function setUp() {
parent::setUp();
$this->config('system.file')->set('default_scheme', 'dummy-remote')->save();
}
}

View file

@ -1,38 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests the unmanaged file copy function.
*
* @group File
*/
class RemoteFileUnmanagedCopyTest extends UnmanagedCopyTest {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
/**
* A stream wrapper scheme to register for the test.
*
* @var string
*/
protected $scheme = 'dummy-remote';
/**
* A fully-qualified stream wrapper class name to register for the test.
*
* @var string
*/
protected $classname = 'Drupal\file_test\StreamWrapper\DummyRemoteStreamWrapper';
protected function setUp() {
parent::setUp();
$this->config('system.file')->set('default_scheme', 'dummy-remote')->save();
}
}

View file

@ -1,38 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests the unmanaged file delete recursive function.
*
* @group File
*/
class RemoteFileUnmanagedDeleteRecursiveTest extends UnmanagedDeleteRecursiveTest {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
/**
* A stream wrapper scheme to register for the test.
*
* @var string
*/
protected $scheme = 'dummy-remote';
/**
* A fully-qualified stream wrapper class name to register for the test.
*
* @var string
*/
protected $classname = 'Drupal\file_test\StreamWrapper\DummyRemoteStreamWrapper';
protected function setUp() {
parent::setUp();
$this->config('system.file')->set('default_scheme', 'dummy-remote')->save();
}
}

View file

@ -1,38 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests the unmanaged file delete function.
*
* @group File
*/
class RemoteFileUnmanagedDeleteTest extends UnmanagedDeleteTest {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
/**
* A stream wrapper scheme to register for the test.
*
* @var string
*/
protected $scheme = 'dummy-remote';
/**
* A fully-qualified stream wrapper class name to register for the test.
*
* @var string
*/
protected $classname = 'Drupal\file_test\StreamWrapper\DummyRemoteStreamWrapper';
protected function setUp() {
parent::setUp();
$this->config('system.file')->set('default_scheme', 'dummy-remote')->save();
}
}

View file

@ -1,38 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests the unmanaged file move function.
*
* @group File
*/
class RemoteFileUnmanagedMoveTest extends UnmanagedMoveTest {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
/**
* A stream wrapper scheme to register for the test.
*
* @var string
*/
protected $scheme = 'dummy-remote';
/**
* A fully-qualified stream wrapper class name to register for the test.
*
* @var string
*/
protected $classname = 'Drupal\file_test\StreamWrapper\DummyRemoteStreamWrapper';
protected function setUp() {
parent::setUp();
$this->config('system.file')->set('default_scheme', 'dummy-remote')->save();
}
}

View file

@ -1,38 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests the unmanaged file save data function.
*
* @group File
*/
class RemoteFileUnmanagedSaveDataTest extends UnmanagedSaveDataTest {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
/**
* A stream wrapper scheme to register for the test.
*
* @var string
*/
protected $scheme = 'dummy-remote';
/**
* A fully-qualified stream wrapper class name to register for the test.
*
* @var string
*/
protected $classname = 'Drupal\file_test\StreamWrapper\DummyRemoteStreamWrapper';
protected function setUp() {
parent::setUp();
$this->config('system.file')->set('default_scheme', 'dummy-remote')->save();
}
}

View file

@ -1,145 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests the file_scan_directory() function.
*
* @group File
*/
class ScanDirectoryTest extends FileTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
/**
* @var string
*/
protected $path;
protected function setUp() {
parent::setUp();
// Hardcode the location of the simpletest files as it is already known
// and shouldn't change, and we don't yet have a way to retrieve their
// location from drupal_get_filename() in a cached way.
// @todo Remove as part of https://www.drupal.org/node/2186491
$this->path = 'core/modules/simpletest/files';
}
/**
* Check the format of the returned values.
*/
function testReturn() {
// Grab a listing of all the JavaScript files and check that they're
// passed to the callback.
$all_files = file_scan_directory($this->path, '/^javascript-/');
ksort($all_files);
$this->assertEqual(2, count($all_files), 'Found two, expected javascript files.');
// Check the first file.
$file = reset($all_files);
$this->assertEqual(key($all_files), $file->uri, 'Correct array key was used for the first returned file.');
$this->assertEqual($file->uri, $this->path . '/javascript-1.txt', 'First file name was set correctly.');
$this->assertEqual($file->filename, 'javascript-1.txt', 'First basename was set correctly');
$this->assertEqual($file->name, 'javascript-1', 'First name was set correctly.');
// Check the second file.
$file = next($all_files);
$this->assertEqual(key($all_files), $file->uri, 'Correct array key was used for the second returned file.');
$this->assertEqual($file->uri, $this->path . '/javascript-2.script', 'Second file name was set correctly.');
$this->assertEqual($file->filename, 'javascript-2.script', 'Second basename was set correctly');
$this->assertEqual($file->name, 'javascript-2', 'Second name was set correctly.');
}
/**
* Check that the callback function is called correctly.
*/
function testOptionCallback() {
// When nothing is matched nothing should be passed to the callback.
$all_files = file_scan_directory($this->path, '/^NONEXISTINGFILENAME/', array('callback' => 'file_test_file_scan_callback'));
$this->assertEqual(0, count($all_files), 'No files were found.');
$results = file_test_file_scan_callback();
file_test_file_scan_callback_reset();
$this->assertEqual(0, count($results), 'No files were passed to the callback.');
// Grab a listing of all the JavaScript files and check that they're
// passed to the callback.
$all_files = file_scan_directory($this->path, '/^javascript-/', array('callback' => 'file_test_file_scan_callback'));
$this->assertEqual(2, count($all_files), 'Found two, expected javascript files.');
$results = file_test_file_scan_callback();
file_test_file_scan_callback_reset();
$this->assertEqual(2, count($results), 'Files were passed to the callback.');
}
/**
* Check that the no-mask parameter is honored.
*/
function testOptionNoMask() {
// Grab a listing of all the JavaScript files.
$all_files = file_scan_directory($this->path, '/^javascript-/');
$this->assertEqual(2, count($all_files), 'Found two, expected javascript files.');
// Now use the nomask parameter to filter out the .script file.
$filtered_files = file_scan_directory($this->path, '/^javascript-/', array('nomask' => '/.script$/'));
$this->assertEqual(1, count($filtered_files), 'Filtered correctly.');
}
/**
* Check that key parameter sets the return value's key.
*/
function testOptionKey() {
// "filename", for the path starting with $dir.
$expected = array($this->path . '/javascript-1.txt', $this->path . '/javascript-2.script');
$actual = array_keys(file_scan_directory($this->path, '/^javascript-/', array('key' => 'filepath')));
sort($actual);
$this->assertEqual($expected, $actual, 'Returned the correct values for the filename key.');
// "basename", for the basename of the file.
$expected = array('javascript-1.txt', 'javascript-2.script');
$actual = array_keys(file_scan_directory($this->path, '/^javascript-/', array('key' => 'filename')));
sort($actual);
$this->assertEqual($expected, $actual, 'Returned the correct values for the basename key.');
// "name" for the name of the file without an extension.
$expected = array('javascript-1', 'javascript-2');
$actual = array_keys(file_scan_directory($this->path, '/^javascript-/', array('key' => 'name')));
sort($actual);
$this->assertEqual($expected, $actual, 'Returned the correct values for the name key.');
// Invalid option that should default back to "filename".
$expected = array($this->path . '/javascript-1.txt', $this->path . '/javascript-2.script');
$actual = array_keys(file_scan_directory($this->path, '/^javascript-/', array('key' => 'INVALID')));
sort($actual);
$this->assertEqual($expected, $actual, 'An invalid key defaulted back to the default.');
}
/**
* Check that the recurse option descends into subdirectories.
*/
function testOptionRecurse() {
$files = file_scan_directory($this->path . '/..', '/^javascript-/', array('recurse' => FALSE));
$this->assertTrue(empty($files), "Without recursion couldn't find javascript files.");
$files = file_scan_directory($this->path . '/..', '/^javascript-/', array('recurse' => TRUE));
$this->assertEqual(2, count($files), 'With recursion we found the expected javascript files.');
}
/**
* Check that the min_depth options lets us ignore files in the starting
* directory.
*/
function testOptionMinDepth() {
$files = file_scan_directory($this->path, '/^javascript-/', array('min_depth' => 0));
$this->assertEqual(2, count($files), 'No minimum-depth gets files in current directory.');
$files = file_scan_directory($this->path, '/^javascript-/', array('min_depth' => 1));
$this->assertTrue(empty($files), 'Minimum-depth of 1 successfully excludes files from current directory.');
}
}

View file

@ -1,149 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
use Drupal\Core\DrupalKernel;
use Drupal\Core\Site\Settings;
use Drupal\Core\StreamWrapper\PublicStream;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests stream wrapper functions.
*
* @group File
*/
class StreamWrapperTest extends FileTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
/**
* A stream wrapper scheme to register for the test.
*
* @var string
*/
protected $scheme = 'dummy';
/**
* A fully-qualified stream wrapper class name to register for the test.
*
* @var string
*/
protected $classname = 'Drupal\file_test\StreamWrapper\DummyStreamWrapper';
function setUp() {
// Add file_private_path setting.
$settings = Settings::getAll();
$request = Request::create('/');;
$site_path = DrupalKernel::findSitePath($request);
$settings['file_private_path'] = $site_path . '/private';
new Settings($settings + Settings::getAll());
parent::setUp();
}
/**
* Test the getClassName() function.
*/
function testGetClassName() {
// Check the dummy scheme.
$this->assertEqual($this->classname, \Drupal::service('stream_wrapper_manager')->getClass($this->scheme), 'Got correct class name for dummy scheme.');
// Check core's scheme.
$this->assertEqual('Drupal\Core\StreamWrapper\PublicStream', \Drupal::service('stream_wrapper_manager')->getClass('public'), 'Got correct class name for public scheme.');
}
/**
* Test the getViaScheme() method.
*/
function testGetInstanceByScheme() {
$instance = \Drupal::service('stream_wrapper_manager')->getViaScheme($this->scheme);
$this->assertEqual($this->classname, get_class($instance), 'Got correct class type for dummy scheme.');
$instance = \Drupal::service('stream_wrapper_manager')->getViaScheme('public');
$this->assertEqual('Drupal\Core\StreamWrapper\PublicStream', get_class($instance), 'Got correct class type for public scheme.');
}
/**
* Test the getViaUri() and getViaScheme() methods and target functions.
*/
function testUriFunctions() {
$config = $this->config('system.file');
$instance = \Drupal::service('stream_wrapper_manager')->getViaUri($this->scheme . '://foo');
$this->assertEqual($this->classname, get_class($instance), 'Got correct class type for dummy URI.');
$instance = \Drupal::service('stream_wrapper_manager')->getViaUri('public://foo');
$this->assertEqual('Drupal\Core\StreamWrapper\PublicStream', get_class($instance), 'Got correct class type for public URI.');
// Test file_uri_target().
$this->assertEqual(file_uri_target('public://foo/bar.txt'), 'foo/bar.txt', 'Got a valid stream target from public://foo/bar.txt.');
$this->assertEqual(file_uri_target('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='), 'image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==', t('Got a valid stream target from a data URI.'));
$this->assertFalse(file_uri_target('foo/bar.txt'), 'foo/bar.txt is not a valid stream.');
$this->assertFalse(file_uri_target('public://'), 'public:// has no target.');
$this->assertFalse(file_uri_target('data:'), 'data: has no target.');
// Test file_build_uri() and
// Drupal\Core\StreamWrapper\LocalStream::getDirectoryPath().
$this->assertEqual(file_build_uri('foo/bar.txt'), 'public://foo/bar.txt', 'Expected scheme was added.');
$this->assertEqual(\Drupal::service('stream_wrapper_manager')->getViaScheme('public')->getDirectoryPath(), PublicStream::basePath(), 'Expected default directory path was returned.');
$this->assertEqual(\Drupal::service('stream_wrapper_manager')->getViaScheme('temporary')->getDirectoryPath(), $config->get('path.temporary'), 'Expected temporary directory path was returned.');
$config->set('default_scheme', 'private')->save();
$this->assertEqual(file_build_uri('foo/bar.txt'), 'private://foo/bar.txt', 'Got a valid URI from foo/bar.txt.');
// Test file_create_url()
// TemporaryStream::getExternalUrl() uses Url::fromRoute(), which needs
// route information to work.
$this->container->get('router.builder')->rebuild();
$this->assertTrue(strpos(file_create_url('temporary://test.txt'), 'system/temporary?file=test.txt'), 'Temporary external URL correctly built.');
$this->assertTrue(strpos(file_create_url('public://test.txt'), Settings::get('file_public_path') . '/test.txt'), 'Public external URL correctly built.');
$this->assertTrue(strpos(file_create_url('private://test.txt'), 'system/files/test.txt'), 'Private external URL correctly built.');
}
/**
* Test some file handle functions.
*/
function testFileFunctions() {
$filename = 'public://' . $this->randomMachineName();
file_put_contents($filename, str_repeat('d', 1000));
// Open for rw and place pointer at beginning of file so select will return.
$handle = fopen($filename, 'c+');
$this->assertTrue($handle, 'Able to open a file for appending, reading and writing.');
// Attempt to change options on the file stream: should all fail.
$this->assertFalse(@stream_set_blocking($handle, 0), 'Unable to set to non blocking using a local stream wrapper.');
$this->assertFalse(@stream_set_blocking($handle, 1), 'Unable to set to blocking using a local stream wrapper.');
$this->assertFalse(@stream_set_timeout($handle, 1), 'Unable to set read time out using a local stream wrapper.');
$this->assertEqual(-1 /*EOF*/, @stream_set_write_buffer($handle, 512), 'Unable to set write buffer using a local stream wrapper.');
// This will test stream_cast().
$read = array($handle);
$write = NULL;
$except = NULL;
$this->assertEqual(1, stream_select($read, $write, $except, 0), 'Able to cast a stream via stream_select.');
// This will test stream_truncate().
$this->assertEqual(1, ftruncate($handle, 0), 'Able to truncate a stream via ftruncate().');
fclose($handle);
$this->assertEqual(0, filesize($filename), 'Able to truncate a stream.');
// Cleanup.
unlink($filename);
}
/**
* Test the scheme functions.
*/
function testGetValidStreamScheme() {
$this->assertEqual('foo', file_uri_scheme('foo://pork//chops'), 'Got the correct scheme from foo://asdf');
$this->assertEqual('data', file_uri_scheme('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='), 'Got the correct scheme from a data URI.');
$this->assertFalse(file_uri_scheme('foo/bar.txt'), 'foo/bar.txt is not a valid stream.');
$this->assertTrue(file_stream_wrapper_valid_scheme(file_uri_scheme('public://asdf')), 'Got a valid stream scheme from public://asdf');
$this->assertFalse(file_stream_wrapper_valid_scheme(file_uri_scheme('foo://asdf')), 'Did not get a valid stream scheme from foo://asdf');
}
}

View file

@ -1,89 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
use Drupal\Core\Site\Settings;
use Drupal\Core\File\FileSystem;
/**
* Tests the unmanaged file copy function.
*
* @group File
*/
class UnmanagedCopyTest extends FileTestBase {
/**
* Copy a normal file.
*/
function testNormal() {
// Create a file for testing
$uri = $this->createUri();
// Copying to a new name.
$desired_filepath = 'public://' . $this->randomMachineName();
$new_filepath = file_unmanaged_copy($uri, $desired_filepath, FILE_EXISTS_ERROR);
$this->assertTrue($new_filepath, 'Copy was successful.');
$this->assertEqual($new_filepath, $desired_filepath, 'Returned expected filepath.');
$this->assertTrue(file_exists($uri), 'Original file remains.');
$this->assertTrue(file_exists($new_filepath), 'New file exists.');
$this->assertFilePermissions($new_filepath, Settings::get('file_chmod_file', FileSystem::CHMOD_FILE));
// Copying with rename.
$desired_filepath = 'public://' . $this->randomMachineName();
$this->assertTrue(file_put_contents($desired_filepath, ' '), 'Created a file so a rename will have to happen.');
$newer_filepath = file_unmanaged_copy($uri, $desired_filepath, FILE_EXISTS_RENAME);
$this->assertTrue($newer_filepath, 'Copy was successful.');
$this->assertNotEqual($newer_filepath, $desired_filepath, 'Returned expected filepath.');
$this->assertTrue(file_exists($uri), 'Original file remains.');
$this->assertTrue(file_exists($newer_filepath), 'New file exists.');
$this->assertFilePermissions($newer_filepath, Settings::get('file_chmod_file', FileSystem::CHMOD_FILE));
// TODO: test copying to a directory (rather than full directory/file path)
// TODO: test copying normal files using normal paths (rather than only streams)
}
/**
* Copy a non-existent file.
*/
function testNonExistent() {
// Copy non-existent file
$desired_filepath = $this->randomMachineName();
$this->assertFalse(file_exists($desired_filepath), "Randomly named file doesn't exists.");
$new_filepath = file_unmanaged_copy($desired_filepath, $this->randomMachineName());
$this->assertFalse($new_filepath, 'Copying a missing file fails.');
}
/**
* Copy a file onto itself.
*/
function testOverwriteSelf() {
// Create a file for testing
$uri = $this->createUri();
// Copy the file onto itself with renaming works.
$new_filepath = file_unmanaged_copy($uri, $uri, FILE_EXISTS_RENAME);
$this->assertTrue($new_filepath, 'Copying onto itself with renaming works.');
$this->assertNotEqual($new_filepath, $uri, 'Copied file has a new name.');
$this->assertTrue(file_exists($uri), 'Original file exists after copying onto itself.');
$this->assertTrue(file_exists($new_filepath), 'Copied file exists after copying onto itself.');
$this->assertFilePermissions($new_filepath, Settings::get('file_chmod_file', FileSystem::CHMOD_FILE));
// Copy the file onto itself without renaming fails.
$new_filepath = file_unmanaged_copy($uri, $uri, FILE_EXISTS_ERROR);
$this->assertFalse($new_filepath, 'Copying onto itself without renaming fails.');
$this->assertTrue(file_exists($uri), 'File exists after copying onto itself.');
// Copy the file into same directory without renaming fails.
$new_filepath = file_unmanaged_copy($uri, drupal_dirname($uri), FILE_EXISTS_ERROR);
$this->assertFalse($new_filepath, 'Copying onto itself fails.');
$this->assertTrue(file_exists($uri), 'File exists after copying onto itself.');
// Copy the file into same directory with renaming works.
$new_filepath = file_unmanaged_copy($uri, drupal_dirname($uri), FILE_EXISTS_RENAME);
$this->assertTrue($new_filepath, 'Copying into same directory works.');
$this->assertNotEqual($new_filepath, $uri, 'Copied file has a new name.');
$this->assertTrue(file_exists($uri), 'Original file exists after copying onto itself.');
$this->assertTrue(file_exists($new_filepath), 'Copied file exists after copying onto itself.');
$this->assertFilePermissions($new_filepath, Settings::get('file_chmod_file', FileSystem::CHMOD_FILE));
}
}

View file

@ -1,74 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests the unmanaged file delete recursive function.
*
* @group File
*/
class UnmanagedDeleteRecursiveTest extends FileTestBase {
/**
* Delete a normal file.
*/
function testSingleFile() {
// Create a file for testing
$filepath = file_default_scheme() . '://' . $this->randomMachineName();
file_put_contents($filepath, '');
// Delete the file.
$this->assertTrue(file_unmanaged_delete_recursive($filepath), 'Function reported success.');
$this->assertFalse(file_exists($filepath), 'Test file has been deleted.');
}
/**
* Try deleting an empty directory.
*/
function testEmptyDirectory() {
// A directory to operate on.
$directory = $this->createDirectory();
// Delete the directory.
$this->assertTrue(file_unmanaged_delete_recursive($directory), 'Function reported success.');
$this->assertFalse(file_exists($directory), 'Directory has been deleted.');
}
/**
* Try deleting a directory with some files.
*/
function testDirectory() {
// A directory to operate on.
$directory = $this->createDirectory();
$filepathA = $directory . '/A';
$filepathB = $directory . '/B';
file_put_contents($filepathA, '');
file_put_contents($filepathB, '');
// Delete the directory.
$this->assertTrue(file_unmanaged_delete_recursive($directory), 'Function reported success.');
$this->assertFalse(file_exists($filepathA), 'Test file A has been deleted.');
$this->assertFalse(file_exists($filepathB), 'Test file B has been deleted.');
$this->assertFalse(file_exists($directory), 'Directory has been deleted.');
}
/**
* Try deleting subdirectories with some files.
*/
function testSubDirectory() {
// A directory to operate on.
$directory = $this->createDirectory();
$subdirectory = $this->createDirectory($directory . '/sub');
$filepathA = $directory . '/A';
$filepathB = $subdirectory . '/B';
file_put_contents($filepathA, '');
file_put_contents($filepathB, '');
// Delete the directory.
$this->assertTrue(file_unmanaged_delete_recursive($directory), 'Function reported success.');
$this->assertFalse(file_exists($filepathA), 'Test file A has been deleted.');
$this->assertFalse(file_exists($filepathB), 'Test file B has been deleted.');
$this->assertFalse(file_exists($subdirectory), 'Subdirectory has been deleted.');
$this->assertFalse(file_exists($directory), 'Directory has been deleted.');
}
}

View file

@ -1,43 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests the unmanaged file delete function.
*
* @group File
*/
class UnmanagedDeleteTest extends FileTestBase {
/**
* Delete a normal file.
*/
function testNormal() {
// Create a file for testing
$uri = $this->createUri();
// Delete a regular file
$this->assertTrue(file_unmanaged_delete($uri), 'Deleted worked.');
$this->assertFalse(file_exists($uri), 'Test file has actually been deleted.');
}
/**
* Try deleting a missing file.
*/
function testMissing() {
// Try to delete a non-existing file
$this->assertTrue(file_unmanaged_delete(file_default_scheme() . '/' . $this->randomMachineName()), 'Returns true when deleting a non-existent file.');
}
/**
* Try deleting a directory.
*/
function testDirectory() {
// A directory to operate on.
$directory = $this->createDirectory();
// Try to delete a directory
$this->assertFalse(file_unmanaged_delete($directory), 'Could not delete the delete directory.');
$this->assertTrue(file_exists($directory), 'Directory has not been deleted.');
}
}

View file

@ -1,73 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
use Drupal\Core\Site\Settings;
use Drupal\Core\File\FileSystem;
/**
* Tests the unmanaged file move function.
*
* @group File
*/
class UnmanagedMoveTest extends FileTestBase {
/**
* Move a normal file.
*/
function testNormal() {
// Create a file for testing
$uri = $this->createUri();
// Moving to a new name.
$desired_filepath = 'public://' . $this->randomMachineName();
$new_filepath = file_unmanaged_move($uri, $desired_filepath, FILE_EXISTS_ERROR);
$this->assertTrue($new_filepath, 'Move was successful.');
$this->assertEqual($new_filepath, $desired_filepath, 'Returned expected filepath.');
$this->assertTrue(file_exists($new_filepath), 'File exists at the new location.');
$this->assertFalse(file_exists($uri), 'No file remains at the old location.');
$this->assertFilePermissions($new_filepath, Settings::get('file_chmod_file', FileSystem::CHMOD_FILE));
// Moving with rename.
$desired_filepath = 'public://' . $this->randomMachineName();
$this->assertTrue(file_exists($new_filepath), 'File exists before moving.');
$this->assertTrue(file_put_contents($desired_filepath, ' '), 'Created a file so a rename will have to happen.');
$newer_filepath = file_unmanaged_move($new_filepath, $desired_filepath, FILE_EXISTS_RENAME);
$this->assertTrue($newer_filepath, 'Move was successful.');
$this->assertNotEqual($newer_filepath, $desired_filepath, 'Returned expected filepath.');
$this->assertTrue(file_exists($newer_filepath), 'File exists at the new location.');
$this->assertFalse(file_exists($new_filepath), 'No file remains at the old location.');
$this->assertFilePermissions($newer_filepath, Settings::get('file_chmod_file', FileSystem::CHMOD_FILE));
// TODO: test moving to a directory (rather than full directory/file path)
// TODO: test creating and moving normal files (rather than streams)
}
/**
* Try to move a missing file.
*/
function testMissing() {
// Move non-existent file.
$new_filepath = file_unmanaged_move($this->randomMachineName(), $this->randomMachineName());
$this->assertFalse($new_filepath, 'Moving a missing file fails.');
}
/**
* Try to move a file onto itself.
*/
function testOverwriteSelf() {
// Create a file for testing.
$uri = $this->createUri();
// Move the file onto itself without renaming shouldn't make changes.
$new_filepath = file_unmanaged_move($uri, $uri, FILE_EXISTS_REPLACE);
$this->assertFalse($new_filepath, 'Moving onto itself without renaming fails.');
$this->assertTrue(file_exists($uri), 'File exists after moving onto itself.');
// Move the file onto itself with renaming will result in a new filename.
$new_filepath = file_unmanaged_move($uri, $uri, FILE_EXISTS_RENAME);
$this->assertTrue($new_filepath, 'Moving onto itself with renaming works.');
$this->assertFalse(file_exists($uri), 'Original file has been removed.');
$this->assertTrue(file_exists($new_filepath), 'File exists after moving onto itself.');
}
}

View file

@ -1,32 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
/**
* Tests the file_unmanaged_save_data() function.
*
* @group File
*/
class UnmanagedSaveDataTest extends FileTestBase {
/**
* Test the file_unmanaged_save_data() function.
*/
function testFileSaveData() {
$contents = $this->randomMachineName(8);
$this->settingsSet('file_chmod_file', 0777);
// No filename.
$filepath = file_unmanaged_save_data($contents);
$this->assertTrue($filepath, 'Unnamed file saved correctly.');
$this->assertEqual(file_uri_scheme($filepath), file_default_scheme(), "File was placed in Drupal's files directory.");
$this->assertEqual($contents, file_get_contents($filepath), 'Contents of the file are correct.');
// Provide a filename.
$filepath = file_unmanaged_save_data($contents, 'public://asdf.txt', FILE_EXISTS_REPLACE);
$this->assertTrue($filepath, 'Unnamed file saved correctly.');
$this->assertEqual('asdf.txt', drupal_basename($filepath), 'File was named correctly.');
$this->assertEqual($contents, file_get_contents($filepath), 'Contents of the file are correct.');
$this->assertFilePermissions($filepath, 0777);
}
}

View file

@ -1,118 +0,0 @@
<?php
namespace Drupal\system\Tests\File;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests for file URL rewriting.
*
* @group File
*/
class UrlRewritingTest extends FileTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('file_test');
/**
* Tests the rewriting of shipped file URLs by hook_file_url_alter().
*/
function testShippedFileURL() {
// Test generating a URL to a shipped file (i.e. a file that is part of
// Drupal core, a module or a theme, for example a JavaScript file).
// Test alteration of file URLs to use a CDN.
\Drupal::state()->set('file_test.hook_file_url_alter', 'cdn');
$filepath = 'core/assets/vendor/jquery/jquery.min.js';
$url = file_create_url($filepath);
$this->assertEqual(FILE_URL_TEST_CDN_1 . '/' . $filepath, $url, 'Correctly generated a CDN URL for a shipped file.');
$filepath = 'core/misc/favicon.ico';
$url = file_create_url($filepath);
$this->assertEqual(FILE_URL_TEST_CDN_2 . '/' . $filepath, $url, 'Correctly generated a CDN URL for a shipped file.');
// Test alteration of file URLs to use root-relative URLs.
\Drupal::state()->set('file_test.hook_file_url_alter', 'root-relative');
$filepath = 'core/assets/vendor/jquery/jquery.min.js';
$url = file_create_url($filepath);
$this->assertEqual(base_path() . '/' . $filepath, $url, 'Correctly generated a root-relative URL for a shipped file.');
$filepath = 'core/misc/favicon.ico';
$url = file_create_url($filepath);
$this->assertEqual(base_path() . '/' . $filepath, $url, 'Correctly generated a root-relative URL for a shipped file.');
// Test alteration of file URLs to use protocol-relative URLs.
\Drupal::state()->set('file_test.hook_file_url_alter', 'protocol-relative');
$filepath = 'core/assets/vendor/jquery/jquery.min.js';
$url = file_create_url($filepath);
$this->assertEqual('/' . base_path() . '/' . $filepath, $url, 'Correctly generated a protocol-relative URL for a shipped file.');
$filepath = 'core/misc/favicon.ico';
$url = file_create_url($filepath);
$this->assertEqual('/' . base_path() . '/' . $filepath, $url, 'Correctly generated a protocol-relative URL for a shipped file.');
// Test alteration of file URLs with query strings and/or fragment.
\Drupal::state()->delete('file_test.hook_file_url_alter');
$filepath = 'core/misc/favicon.ico';
$url = file_create_url($filepath . '?foo');
$this->assertEqual($GLOBALS['base_url'] . '/' . $filepath . '?foo=', $url, 'Correctly generated URL. The query string is present.');
$url = file_create_url($filepath . '?foo=bar');
$this->assertEqual($GLOBALS['base_url'] . '/' . $filepath . '?foo=bar', $url, 'Correctly generated URL. The query string is present.');
$url = file_create_url($filepath . '#v1.2');
$this->assertEqual($GLOBALS['base_url'] . '/' . $filepath . '#v1.2', $url, 'Correctly generated URL. The fragment is present.');
$url = file_create_url($filepath . '?foo=bar#v1.2');
$this->assertEqual($GLOBALS['base_url'] . '/' . $filepath . '?foo=bar#v1.2', $url, 'Correctly generated URL. The query string amd fragment is present.');
}
/**
* Tests the rewriting of public managed file URLs by hook_file_url_alter().
*/
function testPublicManagedFileURL() {
// Test generating a URL to a managed file.
// Test alteration of file URLs to use a CDN.
\Drupal::state()->set('file_test.hook_file_url_alter', 'cdn');
$uri = $this->createUri();
$url = file_create_url($uri);
$public_directory_path = \Drupal::service('stream_wrapper_manager')->getViaScheme('public')->getDirectoryPath();
$this->assertEqual(FILE_URL_TEST_CDN_2 . '/' . $public_directory_path . '/' . drupal_basename($uri), $url, 'Correctly generated a CDN URL for a created file.');
// Test alteration of file URLs to use root-relative URLs.
\Drupal::state()->set('file_test.hook_file_url_alter', 'root-relative');
$uri = $this->createUri();
$url = file_create_url($uri);
$this->assertEqual(base_path() . '/' . $public_directory_path . '/' . drupal_basename($uri), $url, 'Correctly generated a root-relative URL for a created file.');
// Test alteration of file URLs to use a protocol-relative URLs.
\Drupal::state()->set('file_test.hook_file_url_alter', 'protocol-relative');
$uri = $this->createUri();
$url = file_create_url($uri);
$this->assertEqual('/' . base_path() . '/' . $public_directory_path . '/' . drupal_basename($uri), $url, 'Correctly generated a protocol-relative URL for a created file.');
}
/**
* Test file_url_transform_relative().
*/
function testRelativeFileURL() {
// Disable file_test.module's hook_file_url_alter() implementation.
\Drupal::state()->set('file_test.hook_file_url_alter', NULL);
// Create a mock Request for file_url_transform_relative().
$request = Request::create($GLOBALS['base_url']);
$this->container->get('request_stack')->push($request);
\Drupal::setContainer($this->container);
// Shipped file.
$filepath = 'core/assets/vendor/jquery/jquery.min.js';
$url = file_create_url($filepath);
$this->assertIdentical(base_path() . $filepath, file_url_transform_relative($url));
// Managed file.
$uri = $this->createUri();
$url = file_create_url($uri);
$public_directory_path = \Drupal::service('stream_wrapper_manager')->getViaScheme('public')->getDirectoryPath();
$this->assertIdentical(base_path() . $public_directory_path . '/' . rawurlencode(drupal_basename($uri)), file_url_transform_relative($url));
}
}

View file

@ -137,6 +137,20 @@ class ElementTest extends WebTestBase {
$this->assertTrue(count($elements) == 1);
}
/**
* Tests the #required property on details and fieldset elements.
*/
public function testRequiredFieldsetsAndDetails() {
$this->drupalGet('form-test/group-details');
$this->assertFalse($this->cssSelect('summary.form-required'));
$this->drupalGet('form-test/group-details/1');
$this->assertTrue($this->cssSelect('summary.form-required'));
$this->drupalGet('form-test/group-fieldset');
$this->assertFalse($this->cssSelect('span.form-required'));
$this->drupalGet('form-test/group-fieldset/1');
$this->assertTrue($this->cssSelect('span.form-required'));
}
/**
* Tests a form with a autocomplete setting..
*/

View file

@ -70,9 +70,9 @@ class ElementsVerticalTabsTest extends WebTestBase {
$this->assertFalse(isset($wrapper[0]), 'Vertical tab wrappers are not displayed to unprivileged users.');
}
/**
* Ensures that default vertical tab is correctly selected.
*/
/**
* Ensures that default vertical tab is correctly selected.
*/
function testDefaultTab() {
$this->drupalGet('form_test/vertical-tabs');
$this->assertFieldByName('vertical_tabs__active_tab', 'edit-tab3', t('The default vertical tab is correctly selected.'));

View file

@ -1,103 +0,0 @@
<?php
namespace Drupal\system\Tests\Form;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\simpletest\KernelTestBase;
use Drupal\user\Entity\User;
use Symfony\Component\HttpFoundation\Request;
/**
* Ensures that form actions can't be tricked into sending to external URLs.
*
* @group system
*/
class ExternalFormUrlTest extends KernelTestBase implements FormInterface {
/**
* {@inheritdoc}
*/
public static $modules = ['user', 'system'];
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'external_form_url_test';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['something'] = [
'#type' => 'textfield',
'#title' => 'What do you think?',
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {}
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', ['key_value_expire', 'sequences']);
$this->installEntitySchema('user');
$test_user = User::create([
'name' => 'foobar',
'mail' => 'foobar@example.com',
]);
$test_user->save();
\Drupal::service('current_user')->setAccount($test_user);
}
/**
* Tests form behaviour.
*/
public function testActionUrlBehavior() {
// Create a new request which has a request uri with multiple leading
// slashes and make it the master request.
$request_stack = \Drupal::service('request_stack');
$original_request = $request_stack->pop();
$request = Request::create($original_request->getSchemeAndHttpHost() . '//example.org');
$request_stack->push($request);
$form = \Drupal::formBuilder()->getForm($this);
$markup = \Drupal::service('renderer')->renderRoot($form);
$this->setRawContent($markup);
$elements = $this->xpath('//form/@action');
$action = (string) $elements[0];
$this->assertEqual($original_request->getSchemeAndHttpHost() . '//example.org', $action);
// Create a new request which has a request uri with a single leading slash
// and make it the master request.
$request_stack = \Drupal::service('request_stack');
$original_request = $request_stack->pop();
$request = Request::create($original_request->getSchemeAndHttpHost() . '/example.org');
$request_stack->push($request);
$form = \Drupal::formBuilder()->getForm($this);
$markup = \Drupal::service('renderer')->renderRoot($form);
$this->setRawContent($markup);
$elements = $this->xpath('//form/@action');
$action = (string) $elements[0];
$this->assertEqual('/example.org', $action);
}
}

View file

@ -1,104 +0,0 @@
<?php
namespace Drupal\system\Tests\Form;
use Drupal\Core\Form\FormState;
use Drupal\Core\Session\AnonymousUserSession;
use Drupal\Core\Session\UserSession;
use Drupal\simpletest\KernelTestBase;
/**
* Tests \Drupal::formBuilder()->setCache() and
* \Drupal::formBuilder()->getCache().
*
* @group Form
*/
class FormCacheTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system', 'user');
/**
* @var string
*/
protected $formBuildId;
/**
* @var array
*/
protected $form;
/**
* @var array
*/
protected $formState;
protected function setUp() {
parent::setUp();
$this->installSchema('system', array('key_value_expire'));
$this->formBuildId = $this->randomMachineName();
$this->form = array(
'#property' => $this->randomMachineName(),
);
$this->formState = new FormState();
$this->formState->set('example', $this->randomMachineName());
}
/**
* Tests the form cache with a logged-in user.
*/
function testCacheToken() {
\Drupal::currentUser()->setAccount(new UserSession(array('uid' => 1)));
\Drupal::formBuilder()->setCache($this->formBuildId, $this->form, $this->formState);
$cached_form_state = new FormState();
$cached_form = \Drupal::formBuilder()->getCache($this->formBuildId, $cached_form_state);
$this->assertEqual($this->form['#property'], $cached_form['#property']);
$this->assertTrue(!empty($cached_form['#cache_token']), 'Form has a cache token');
$this->assertEqual($this->formState->get('example'), $cached_form_state->get('example'));
// Test that the form cache isn't loaded when the session/token has changed.
// Change the private key. (We cannot change the session ID because this
// will break the parent site test runner batch.)
\Drupal::state()->set('system.private_key', 'invalid');
$cached_form_state = new FormState();
$cached_form = \Drupal::formBuilder()->getCache($this->formBuildId, $cached_form_state);
$this->assertFalse($cached_form, 'No form returned from cache');
$cached_form_state_example = $cached_form_state->get('example');
$this->assertTrue(empty($cached_form_state_example));
// Test that loading the cache with a different form_id fails.
$wrong_form_build_id = $this->randomMachineName(9);
$cached_form_state = new FormState();
$this->assertFalse(\Drupal::formBuilder()->getCache($wrong_form_build_id, $cached_form_state), 'No form returned from cache');
$cached_form_state_example = $cached_form_state->get('example');
$this->assertTrue(empty($cached_form_state_example), 'Cached form state was not loaded');
}
/**
* Tests the form cache without a logged-in user.
*/
function testNoCacheToken() {
// Switch to a anonymous user account.
$account_switcher = \Drupal::service('account_switcher');
$account_switcher->switchTo(new AnonymousUserSession());
$this->formState->set('example', $this->randomMachineName());
\Drupal::formBuilder()->setCache($this->formBuildId, $this->form, $this->formState);
$cached_form_state = new FormState();
$cached_form = \Drupal::formBuilder()->getCache($this->formBuildId, $cached_form_state);
$this->assertEqual($this->form['#property'], $cached_form['#property']);
$this->assertTrue(empty($cached_form['#cache_token']), 'Form has no cache token');
$this->assertEqual($this->formState->get('example'), $cached_form_state->get('example'));
// Restore user account.
$account_switcher->switchBack();
}
}

View file

@ -1,104 +0,0 @@
<?php
namespace Drupal\system\Tests\Form;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\simpletest\KernelTestBase;
/**
* Tests automatically added form handlers.
*
* @group Form
*/
class FormDefaultHandlersTest extends KernelTestBase implements FormInterface {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installSchema('system', ['key_value_expire']);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'test_form_handlers';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['#validate'][] = '::customValidateForm';
$form['#submit'][] = '::customSubmitForm';
$form['submit'] = array('#type' => 'submit', '#value' => 'Save');
return $form;
}
/**
* {@inheritdoc}
*/
public function customValidateForm(array &$form, FormStateInterface $form_state) {
$test_handlers = $form_state->get('test_handlers');
$test_handlers['validate'][] = __FUNCTION__;
$form_state->set('test_handlers', $test_handlers);
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
$test_handlers = $form_state->get('test_handlers');
$test_handlers['validate'][] = __FUNCTION__;
$form_state->set('test_handlers', $test_handlers);
}
/**
* {@inheritdoc}
*/
public function customSubmitForm(array &$form, FormStateInterface $form_state) {
$test_handlers = $form_state->get('test_handlers');
$test_handlers['submit'][] = __FUNCTION__;
$form_state->set('test_handlers', $test_handlers);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$test_handlers = $form_state->get('test_handlers');
$test_handlers['submit'][] = __FUNCTION__;
$form_state->set('test_handlers', $test_handlers);
}
/**
* Tests that default handlers are added even if custom are specified.
*/
function testDefaultAndCustomHandlers() {
$form_state = new FormState();
$form_builder = $this->container->get('form_builder');
$form_builder->submitForm($this, $form_state);
$handlers = $form_state->get('test_handlers');
$this->assertIdentical(count($handlers['validate']), 2);
$this->assertIdentical($handlers['validate'][0], 'customValidateForm');
$this->assertIdentical($handlers['validate'][1], 'validateForm');
$this->assertIdentical(count($handlers['submit']), 2);
$this->assertIdentical($handlers['submit'][0], 'customSubmitForm');
$this->assertIdentical($handlers['submit'][1], 'submitForm');
}
}

View file

@ -1,88 +0,0 @@
<?php
namespace Drupal\system\Tests\Form;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\simpletest\KernelTestBase;
/**
* Tests detection of triggering_element for programmed form submissions.
*
* @group Form
*/
class TriggeringElementProgrammedUnitTest extends KernelTestBase implements FormInterface {
public static $modules = array('system');
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'triggering_element_programmed_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['one'] = array(
'#type' => 'textfield',
'#title' => 'One',
'#required' => TRUE,
);
$form['two'] = array(
'#type' => 'textfield',
'#title' => 'Two',
'#required' => TRUE,
);
$form['actions'] = array('#type' => 'actions');
$user_input = $form_state->getUserInput();
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => 'Save',
'#limit_validation_errors' => array(
array($user_input['section']),
),
// Required for #limit_validation_errors.
'#submit' => array(array($this, 'submitForm')),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Verify that the only submit button was recognized as triggering_element.
$this->assertEqual($form['actions']['submit']['#array_parents'], $form_state->getTriggeringElement()['#array_parents']);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
}
/**
* Tests that #limit_validation_errors of the only submit button takes effect.
*/
function testLimitValidationErrors() {
// Programmatically submit the form.
$form_state = new FormState();
$form_state->setValue('section', 'one');
$form_builder = $this->container->get('form_builder');
$form_builder->submitForm($this, $form_state);
// Verify that only the specified section was validated.
$errors = $form_state->getErrors();
$this->assertTrue(isset($errors['one']), "Section 'one' was validated.");
$this->assertFalse(isset($errors['two']), "Section 'two' was not validated.");
// Verify that there are only values for the specified section.
$this->assertTrue($form_state->hasValue('one'), "Values for section 'one' found.");
$this->assertFalse($form_state->hasValue('two'), "Values for section 'two' not found.");
}
}

View file

@ -1,64 +0,0 @@
<?php
namespace Drupal\system\Tests\HttpKernel;
use Drupal\simpletest\KernelTestBase;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Tests the stacked kernel functionality.
*
* @group Routing
*/
class StackKernelIntegrationTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('httpkernel_test', 'system');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
\Drupal::service('router.builder')->rebuild();
}
/**
* Tests a request.
*/
public function testRequest() {
$request = Request::create((new Url('httpkernel_test.empty'))->toString());
/** @var \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel */
$http_kernel = \Drupal::service('http_kernel');
$http_kernel->handle($request, HttpKernelInterface::MASTER_REQUEST, FALSE);
$this->assertEqual($request->attributes->get('_hello'), 'world');
$this->assertEqual($request->attributes->get('_previous_optional_argument'), 'test_argument');
}
/**
* Tests that late middlewares are automatically flagged lazy.
*/
public function testLazyLateMiddlewares() {
$this->assertFalse($this->container->getDefinition('http_middleware.reverse_proxy')->isLazy(), 'lazy flag on http_middleware.reverse_proxy definition is not set');
$this->assertFalse($this->container->getDefinition('http_middleware.kernel_pre_handle')->isLazy(), 'lazy flag on http_middleware.kernel_pre_handle definition is not set');
$this->assertFalse($this->container->getDefinition('http_middleware.session')->isLazy(), 'lazy flag on http_middleware.session definition is not set');
$this->assertFalse($this->container->getDefinition('http_kernel.basic')->isLazy(), 'lazy flag on http_kernel.basic definition is not set');
\Drupal::service('module_installer')->install(['page_cache']);
$this->container = $this->kernel->rebuildContainer();
$this->assertFalse($this->container->getDefinition('http_middleware.reverse_proxy')->isLazy(), 'lazy flag on http_middleware.reverse_proxy definition is not set');
$this->assertFalse($this->container->getDefinition('http_middleware.page_cache')->isLazy(), 'lazy flag on http_middleware.page_cache definition is not set');
$this->assertTrue($this->container->getDefinition('http_middleware.kernel_pre_handle')->isLazy(), 'lazy flag on http_middleware.kernel_pre_handle definition is automatically set if page_cache is enabled.');
$this->assertTrue($this->container->getDefinition('http_middleware.session')->isLazy(), 'lazy flag on http_middleware.session definition is automatically set if page_cache is enabled.');
$this->assertTrue($this->container->getDefinition('http_kernel.basic')->isLazy(), 'lazy flag on http_kernel.basic definition is automatically set if page_cache is enabled.');
}
}

View file

@ -1,528 +0,0 @@
<?php
namespace Drupal\system\Tests\Image;
use Drupal\Core\Image\ImageInterface;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\simpletest\KernelTestBase;
/**
* Tests that core image manipulations work properly: scale, resize, rotate,
* crop, scale and crop, and desaturate.
*
* @group Image
*/
class ToolkitGdTest extends KernelTestBase {
/**
* The image factory service.
*
* @var \Drupal\Core\Image\ImageFactory
*/
protected $imageFactory;
// Colors that are used in testing.
protected $black = array(0, 0, 0, 0);
protected $red = array(255, 0, 0, 0);
protected $green = array(0, 255, 0, 0);
protected $blue = array(0, 0, 255, 0);
protected $yellow = array(255, 255, 0, 0);
protected $white = array(255, 255, 255, 0);
protected $transparent = array(0, 0, 0, 127);
// Used as rotate background colors.
protected $fuchsia = array(255, 0, 255, 0);
protected $rotateTransparent = array(255, 255, 255, 127);
protected $width = 40;
protected $height = 20;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system', 'simpletest');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Set the image factory service.
$this->imageFactory = $this->container->get('image.factory');
}
protected function checkRequirements() {
// GD2 support is available.
if (!function_exists('imagegd2')) {
return array(
'Image manipulations for the GD toolkit cannot run because the GD toolkit is not available.',
);
}
return parent::checkRequirements();
}
/**
* Function to compare two colors by RGBa.
*/
function colorsAreEqual($color_a, $color_b) {
// Fully transparent pixels are equal, regardless of RGB.
if ($color_a[3] == 127 && $color_b[3] == 127) {
return TRUE;
}
foreach ($color_a as $key => $value) {
if ($color_b[$key] != $value) {
return FALSE;
}
}
return TRUE;
}
/**
* Function for finding a pixel's RGBa values.
*/
function getPixelColor(ImageInterface $image, $x, $y) {
$toolkit = $image->getToolkit();
$color_index = imagecolorat($toolkit->getResource(), $x, $y);
$transparent_index = imagecolortransparent($toolkit->getResource());
if ($color_index == $transparent_index) {
return array(0, 0, 0, 127);
}
return array_values(imagecolorsforindex($toolkit->getResource(), $color_index));
}
/**
* Since PHP can't visually check that our images have been manipulated
* properly, build a list of expected color values for each of the corners and
* the expected height and widths for the final images.
*/
function testManipulations() {
// Test that the image factory is set to use the GD toolkit.
$this->assertEqual($this->imageFactory->getToolkitId(), 'gd', 'The image factory is set to use the \'gd\' image toolkit.');
// Test the list of supported extensions.
$expected_extensions = ['png', 'gif', 'jpeg', 'jpg', 'jpe'];
$supported_extensions = $this->imageFactory->getSupportedExtensions();
$this->assertEqual($expected_extensions, array_intersect($expected_extensions, $supported_extensions));
// Test that the supported extensions map to correct internal GD image
// types.
$expected_image_types = [
'png' => IMAGETYPE_PNG,
'gif' => IMAGETYPE_GIF,
'jpeg' => IMAGETYPE_JPEG,
'jpg' => IMAGETYPE_JPEG,
'jpe' => IMAGETYPE_JPEG
];
$image = $this->imageFactory->get();
foreach ($expected_image_types as $extension => $expected_image_type) {
$image_type = $image->getToolkit()->extensionToImageType($extension);
$this->assertEqual($expected_image_type, $image_type);
}
// Typically the corner colors will be unchanged. These colors are in the
// order of top-left, top-right, bottom-right, bottom-left.
$default_corners = array($this->red, $this->green, $this->blue, $this->transparent);
// A list of files that will be tested.
$files = array(
'image-test.png',
'image-test.gif',
'image-test-no-transparency.gif',
'image-test.jpg',
);
// Setup a list of tests to perform on each type.
$operations = array(
'resize' => array(
'function' => 'resize',
'arguments' => array('width' => 20, 'height' => 10),
'width' => 20,
'height' => 10,
'corners' => $default_corners,
),
'scale_x' => array(
'function' => 'scale',
'arguments' => array('width' => 20),
'width' => 20,
'height' => 10,
'corners' => $default_corners,
),
'scale_y' => array(
'function' => 'scale',
'arguments' => array('height' => 10),
'width' => 20,
'height' => 10,
'corners' => $default_corners,
),
'upscale_x' => array(
'function' => 'scale',
'arguments' => array('width' => 80, 'upscale' => TRUE),
'width' => 80,
'height' => 40,
'corners' => $default_corners,
),
'upscale_y' => array(
'function' => 'scale',
'arguments' => array('height' => 40, 'upscale' => TRUE),
'width' => 80,
'height' => 40,
'corners' => $default_corners,
),
'crop' => array(
'function' => 'crop',
'arguments' => array('x' => 12, 'y' => 4, 'width' => 16, 'height' => 12),
'width' => 16,
'height' => 12,
'corners' => array_fill(0, 4, $this->white),
),
'scale_and_crop' => array(
'function' => 'scale_and_crop',
'arguments' => array('width' => 10, 'height' => 8),
'width' => 10,
'height' => 8,
'corners' => array_fill(0, 4, $this->black),
),
'convert_jpg' => array(
'function' => 'convert',
'width' => 40,
'height' => 20,
'arguments' => array('extension' => 'jpeg'),
'corners' => $default_corners,
),
'convert_gif' => array(
'function' => 'convert',
'width' => 40,
'height' => 20,
'arguments' => array('extension' => 'gif'),
'corners' => $default_corners,
),
'convert_png' => array(
'function' => 'convert',
'width' => 40,
'height' => 20,
'arguments' => array('extension' => 'png'),
'corners' => $default_corners,
),
);
// Systems using non-bundled GD2 don't have imagerotate. Test if available.
if (function_exists('imagerotate')) {
$operations += array(
'rotate_5' => array(
'function' => 'rotate',
'arguments' => array('degrees' => 5, 'background' => '#FF00FF'), // Fuchsia background.
'width' => 41,
'height' => 23,
'corners' => array_fill(0, 4, $this->fuchsia),
),
'rotate_90' => array(
'function' => 'rotate',
'arguments' => array('degrees' => 90, 'background' => '#FF00FF'), // Fuchsia background.
'width' => 20,
'height' => 40,
'corners' => array($this->transparent, $this->red, $this->green, $this->blue),
),
'rotate_transparent_5' => array(
'function' => 'rotate',
'arguments' => array('degrees' => 5),
'width' => 41,
'height' => 23,
'corners' => array_fill(0, 4, $this->rotateTransparent),
),
'rotate_transparent_90' => array(
'function' => 'rotate',
'arguments' => array('degrees' => 90),
'width' => 20,
'height' => 40,
'corners' => array($this->transparent, $this->red, $this->green, $this->blue),
),
);
}
// Systems using non-bundled GD2 don't have imagefilter. Test if available.
if (function_exists('imagefilter')) {
$operations += array(
'desaturate' => array(
'function' => 'desaturate',
'arguments' => array(),
'height' => 20,
'width' => 40,
// Grayscale corners are a bit funky. Each of the corners are a shade of
// gray. The values of these were determined simply by looking at the
// final image to see what desaturated colors end up being.
'corners' => array(
array_fill(0, 3, 76) + array(3 => 0),
array_fill(0, 3, 149) + array(3 => 0),
array_fill(0, 3, 29) + array(3 => 0),
array_fill(0, 3, 225) + array(3 => 127)
),
),
);
}
// Prepare a directory for test file results.
$directory = $this->publicFilesDirectory . '/imagetest';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
foreach ($files as $file) {
foreach ($operations as $op => $values) {
// Load up a fresh image.
$image = $this->imageFactory->get(drupal_get_path('module', 'simpletest') . '/files/' . $file);
$toolkit = $image->getToolkit();
if (!$image->isValid()) {
$this->fail(SafeMarkup::format('Could not load image %file.', array('%file' => $file)));
continue 2;
}
$image_original_type = $image->getToolkit()->getType();
// All images should be converted to truecolor when loaded.
$image_truecolor = imageistruecolor($toolkit->getResource());
$this->assertTrue($image_truecolor, SafeMarkup::format('Image %file after load is a truecolor image.', array('%file' => $file)));
// Store the original GD resource.
$old_res = $toolkit->getResource();
// Perform our operation.
$image->apply($values['function'], $values['arguments']);
// If the operation replaced the resource, check that the old one has
// been destroyed.
$new_res = $toolkit->getResource();
if ($new_res !== $old_res) {
$this->assertFalse(is_resource($old_res), SafeMarkup::format("'%operation' destroyed the original resource.", ['%operation' => $values['function']]));
}
// To keep from flooding the test with assert values, make a general
// value for whether each group of values fail.
$correct_dimensions_real = TRUE;
$correct_dimensions_object = TRUE;
if (imagesy($toolkit->getResource()) != $values['height'] || imagesx($toolkit->getResource()) != $values['width']) {
$correct_dimensions_real = FALSE;
}
// Check that the image object has an accurate record of the dimensions.
if ($image->getWidth() != $values['width'] || $image->getHeight() != $values['height']) {
$correct_dimensions_object = FALSE;
}
$file_path = $directory . '/' . $op . image_type_to_extension($image->getToolkit()->getType());
$image->save($file_path);
$this->assertTrue($correct_dimensions_real, SafeMarkup::format('Image %file after %action action has proper dimensions.', array('%file' => $file, '%action' => $op)));
$this->assertTrue($correct_dimensions_object, SafeMarkup::format('Image %file object after %action action is reporting the proper height and width values.', array('%file' => $file, '%action' => $op)));
// JPEG colors will always be messed up due to compression. So we skip
// these tests if the original or the result is in jpeg format.
if ($image->getToolkit()->getType() != IMAGETYPE_JPEG && $image_original_type != IMAGETYPE_JPEG) {
// Now check each of the corners to ensure color correctness.
foreach ($values['corners'] as $key => $corner) {
// The test gif that does not have transparency color set is a
// special case.
if ($file === 'image-test-no-transparency.gif') {
if ($op == 'desaturate') {
// For desaturating, keep the expected color from the test
// data, but set alpha channel to fully opaque.
$corner[3] = 0;
}
elseif ($corner === $this->transparent) {
// Set expected pixel to yellow where the others have
// transparent.
$corner = $this->yellow;
}
}
// Get the location of the corner.
switch ($key) {
case 0:
$x = 0;
$y = 0;
break;
case 1:
$x = $image->getWidth() - 1;
$y = 0;
break;
case 2:
$x = $image->getWidth() - 1;
$y = $image->getHeight() - 1;
break;
case 3:
$x = 0;
$y = $image->getHeight() - 1;
break;
}
$color = $this->getPixelColor($image, $x, $y);
// We also skip the color test for transparency for gif <-> png
// conversion. The convert operation cannot handle that correctly.
if ($image->getToolkit()->getType() == $image_original_type || $corner != $this->transparent) {
$correct_colors = $this->colorsAreEqual($color, $corner);
$this->assertTrue($correct_colors, SafeMarkup::format('Image %file object after %action action has the correct color placement at corner %corner.',
array('%file' => $file, '%action' => $op, '%corner' => $key)));
}
}
}
// Check that saved image reloads without raising PHP errors.
$image_reloaded = $this->imageFactory->get($file_path);
$resource = $image_reloaded->getToolkit()->getResource();
}
}
// Test creation of image from scratch, and saving to storage.
foreach (array(IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_JPEG) as $type) {
$image = $this->imageFactory->get();
$image->createNew(50, 20, image_type_to_extension($type, FALSE), '#ffff00');
$file = 'from_null' . image_type_to_extension($type);
$file_path = $directory . '/' . $file ;
$this->assertEqual(50, $image->getWidth(), SafeMarkup::format('Image file %file has the correct width.', array('%file' => $file)));
$this->assertEqual(20, $image->getHeight(), SafeMarkup::format('Image file %file has the correct height.', array('%file' => $file)));
$this->assertEqual(image_type_to_mime_type($type), $image->getMimeType(), SafeMarkup::format('Image file %file has the correct MIME type.', array('%file' => $file)));
$this->assertTrue($image->save($file_path), SafeMarkup::format('Image %file created anew from a null image was saved.', array('%file' => $file)));
// Reload saved image.
$image_reloaded = $this->imageFactory->get($file_path);
if (!$image_reloaded->isValid()) {
$this->fail(SafeMarkup::format('Could not load image %file.', array('%file' => $file)));
continue;
}
$this->assertEqual(50, $image_reloaded->getWidth(), SafeMarkup::format('Image file %file has the correct width.', array('%file' => $file)));
$this->assertEqual(20, $image_reloaded->getHeight(), SafeMarkup::format('Image file %file has the correct height.', array('%file' => $file)));
$this->assertEqual(image_type_to_mime_type($type), $image_reloaded->getMimeType(), SafeMarkup::format('Image file %file has the correct MIME type.', array('%file' => $file)));
if ($image_reloaded->getToolkit()->getType() == IMAGETYPE_GIF) {
$this->assertEqual('#ffff00', $image_reloaded->getToolkit()->getTransparentColor(), SafeMarkup::format('Image file %file has the correct transparent color channel set.', array('%file' => $file)));
}
else {
$this->assertEqual(NULL, $image_reloaded->getToolkit()->getTransparentColor(), SafeMarkup::format('Image file %file has no color channel set.', array('%file' => $file)));
}
}
// Test failures of the 'create_new' operation.
$image = $this->imageFactory->get();
$image->createNew(-50, 20);
$this->assertFalse($image->isValid(), 'CreateNew with negative width fails.');
$image->createNew(50, 20, 'foo');
$this->assertFalse($image->isValid(), 'CreateNew with invalid extension fails.');
$image->createNew(50, 20, 'gif', '#foo');
$this->assertFalse($image->isValid(), 'CreateNew with invalid color hex string fails.');
$image->createNew(50, 20, 'gif', '#ff0000');
$this->assertTrue($image->isValid(), 'CreateNew with valid arguments validates the Image.');
}
/**
* Tests that GD resources are freed from memory.
*/
public function testResourceDestruction() {
// Test that an Image object going out of scope releases its GD resource.
$image = $this->imageFactory->get(drupal_get_path('module', 'simpletest') . '/files/image-test.png');
$res = $image->getToolkit()->getResource();
$this->assertTrue(is_resource($res), 'Successfully loaded image resource.');
$image = NULL;
$this->assertFalse(is_resource($res), 'Image resource was destroyed after losing scope.');
// Test that 'create_new' operation does not leave orphaned GD resources.
$image = $this->imageFactory->get(drupal_get_path('module', 'simpletest') . '/files/image-test.png');
$old_res = $image->getToolkit()->getResource();
// Check if resource has been created successfully.
$this->assertTrue(is_resource($old_res));
$image->createNew(20, 20);
$new_res = $image->getToolkit()->getResource();
// Check if the original resource has been destroyed.
$this->assertFalse(is_resource($old_res));
// Check if a new resource has been created successfully.
$this->assertTrue(is_resource($new_res));
}
/**
* Tests for GIF images with transparency.
*/
function testGifTransparentImages() {
// Prepare a directory for test file results.
$directory = $this->publicFilesDirectory . '/imagetest';
file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
// Test loading an indexed GIF image with transparent color set.
// Color at top-right pixel should be fully transparent.
$file = 'image-test-transparent-indexed.gif';
$image = $this->imageFactory->get(drupal_get_path('module', 'simpletest') . '/files/' . $file);
$resource = $image->getToolkit()->getResource();
$color_index = imagecolorat($resource, $image->getWidth() - 1, 0);
$color = array_values(imagecolorsforindex($resource, $color_index));
$this->assertEqual($this->rotateTransparent, $color, "Image {$file} after load has full transparent color at corner 1.");
// Test deliberately creating a GIF image with no transparent color set.
// Color at top-right pixel should be fully transparent while in memory,
// fully opaque after flushing image to file.
$file = 'image-test-no-transparent-color-set.gif';
$file_path = $directory . '/' . $file ;
// Create image.
$image = $this->imageFactory->get();
$image->createNew(50, 20, 'gif', NULL);
$resource = $image->getToolkit()->getResource();
$color_index = imagecolorat($resource, $image->getWidth() - 1, 0);
$color = array_values(imagecolorsforindex($resource, $color_index));
$this->assertEqual($this->rotateTransparent, $color, "New GIF image with no transparent color set after creation has full transparent color at corner 1.");
// Save image.
$this->assertTrue($image->save($file_path), "New GIF image {$file} was saved.");
// Reload image.
$image_reloaded = $this->imageFactory->get($file_path);
$resource = $image_reloaded->getToolkit()->getResource();
$color_index = imagecolorat($resource, $image_reloaded->getWidth() - 1, 0);
$color = array_values(imagecolorsforindex($resource, $color_index));
// Check explicitly for alpha == 0 as the rest of the color has been
// compressed and may have slight difference from full white.
$this->assertEqual(0, $color[3], "New GIF image {$file} after reload has no transparent color at corner 1.");
// Test loading an image whose transparent color index is out of range.
// This image was generated by taking an initial image with a palette size
// of 6 colors, and setting the transparent color index to 6 (one higher
// than the largest allowed index), as follows:
// @code
// $image = imagecreatefromgif('core/modules/simpletest/files/image-test.gif');
// imagecolortransparent($image, 6);
// imagegif($image, 'core/modules/simpletest/files/image-test-transparent-out-of-range.gif');
// @endcode
// This allows us to test that an image with an out-of-range color index
// can be loaded correctly.
$file = 'image-test-transparent-out-of-range.gif';
$image = $this->imageFactory->get(drupal_get_path('module', 'simpletest') . '/files/' . $file);
$toolkit = $image->getToolkit();
if (!$image->isValid()) {
$this->fail(SafeMarkup::format('Could not load image %file.', array('%file' => $file)));
}
else {
// All images should be converted to truecolor when loaded.
$image_truecolor = imageistruecolor($toolkit->getResource());
$this->assertTrue($image_truecolor, SafeMarkup::format('Image %file after load is a truecolor image.', array('%file' => $file)));
}
}
/**
* Tests calling a missing image operation plugin.
*/
function testMissingOperation() {
// Test that the image factory is set to use the GD toolkit.
$this->assertEqual($this->imageFactory->getToolkitId(), 'gd', 'The image factory is set to use the \'gd\' image toolkit.');
// An image file that will be tested.
$file = 'image-test.png';
// Load up a fresh image.
$image = $this->imageFactory->get(drupal_get_path('module', 'simpletest') . '/files/' . $file);
if (!$image->isValid()) {
$this->fail(SafeMarkup::format('Could not load image %file.', array('%file' => $file)));
}
// Try perform a missing toolkit operation.
$this->assertFalse($image->apply('missing_op', array()), 'Calling a missing image toolkit operation plugin fails.');
}
}

View file

@ -2,7 +2,7 @@
namespace Drupal\system\Tests\Installer;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Serialization\Yaml;
use Drupal\simpletest\InstallerTestBase;
/**

View file

@ -2,7 +2,7 @@
namespace Drupal\system\Tests\Installer;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Serialization\Yaml;
use Drupal\simpletest\InstallerTestBase;
/**

View file

@ -2,7 +2,7 @@
namespace Drupal\system\Tests\Installer;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Serialization\Yaml;
use Drupal\simpletest\InstallerTestBase;
/**

View file

@ -1,59 +0,0 @@
<?php
namespace Drupal\system\Tests\Installer;
use Drupal\simpletest\KernelTestBase;
use Drupal\Core\StringTranslation\Translator\FileTranslation;
/**
* Tests for installer language support.
*
* @group Installer
*/
class InstallerLanguageTest extends KernelTestBase {
/**
* Tests that the installer can find translation files.
*/
function testInstallerTranslationFiles() {
// Different translation files would be found depending on which language
// we are looking for.
$expected_translation_files = array(
NULL => array('drupal-8.0.0-beta2.hu.po', 'drupal-8.0.0.de.po'),
'de' => array('drupal-8.0.0.de.po'),
'hu' => array('drupal-8.0.0-beta2.hu.po'),
'it' => array(),
);
// Hardcode the simpletest module location as we don't yet know where it is.
// @todo Remove as part of https://www.drupal.org/node/2186491
$file_translation = new FileTranslation('core/modules/simpletest/files/translations');
foreach ($expected_translation_files as $langcode => $files_expected) {
$files_found = $file_translation->findTranslationFiles($langcode);
$this->assertTrue(count($files_found) == count($files_expected), format_string('@count installer languages found.', array('@count' => count($files_expected))));
foreach ($files_found as $file) {
$this->assertTrue(in_array($file->filename, $files_expected), format_string('@file found.', array('@file' => $file->filename)));
}
}
}
/**
* Tests profile info caching in non-English languages.
*/
function testInstallerTranslationCache() {
require_once 'core/includes/install.inc';
// 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', 'core/profiles/testing/testing.info.yml');
$info_en = install_profile_info('testing', 'en');
$info_nl = install_profile_info('testing', 'nl');
$this->assertFalse(in_array('locale', $info_en['dependencies']), 'Locale is not set when installing in English.');
$this->assertTrue(in_array('locale', $info_nl['dependencies']), 'Locale is set when installing in Dutch.');
}
}

View file

@ -74,4 +74,14 @@ class InstallerTest extends InstallerTestBase {
parent::setUpSite();
}
/**
* {@inheritdoc}
*/
protected function visitInstaller() {
parent::visitInstaller();
// Assert the title is correct and has the title suffix.
$this->assertTitle('Choose language | Drupal');
}
}

View file

@ -2,7 +2,7 @@
namespace Drupal\system\Tests\Installer;
use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Serialization\Yaml;
use Drupal\simpletest\InstallerTestBase;
/**

View file

@ -55,15 +55,15 @@ class StandardInstallerTest extends ConfigAfterInstallerTestBase {
$skipped_config = [];
// \Drupal\simpletest\WebTestBase::installParameters() uses
// simpletest@example.com as mail address.
$skipped_config['contact.form.feedback'][] = ' - simpletest@example.com';
$skipped_config['contact.form.feedback'][] = '- simpletest@example.com';
// \Drupal\filter\Entity\FilterFormat::toArray() drops the roles of filter
// formats.
$skipped_config['filter.format.basic_html'][] = 'roles:';
$skipped_config['filter.format.basic_html'][] = ' - authenticated';
$skipped_config['filter.format.basic_html'][] = '- authenticated';
$skipped_config['filter.format.full_html'][] = 'roles:';
$skipped_config['filter.format.full_html'][] = ' - administrator';
$skipped_config['filter.format.full_html'][] = '- administrator';
$skipped_config['filter.format.restricted_html'][] = 'roles:';
$skipped_config['filter.format.restricted_html'][] = ' - anonymous';
$skipped_config['filter.format.restricted_html'][] = '- anonymous';
$this->assertInstalledConfig($skipped_config);
}

View file

@ -1,158 +0,0 @@
<?php
namespace Drupal\system\Tests\KeyValueStore;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\KeyValueStore\KeyValueFactory;
/**
* Tests the key-value database storage.
*
* @group KeyValueStore
*/
class DatabaseStorageExpirableTest extends StorageTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
protected function setUp() {
parent::setUp();
$this->factory = 'keyvalue.expirable';
$this->installSchema('system', array('key_value_expire'));
}
/**
* {@inheritdoc}
*/
public function containerBuild(ContainerBuilder $container) {
parent::containerBuild($container);
$parameter[KeyValueFactory::DEFAULT_SETTING] = 'keyvalue.expirable.database';
$container->setParameter('factory.keyvalue.expirable', $parameter);
}
/**
* Tests CRUD functionality with expiration.
*/
public function testCRUDWithExpiration() {
$stores = $this->createStorage();
// Verify that an item can be stored with setWithExpire().
// Use a random expiration in each test.
$stores[0]->setWithExpire('foo', $this->objects[0], rand(500, 100000));
$this->assertIdenticalObject($this->objects[0], $stores[0]->get('foo'));
// Verify that the other collection is not affected.
$this->assertFalse($stores[1]->get('foo'));
// Verify that an item can be updated with setWithExpire().
$stores[0]->setWithExpire('foo', $this->objects[1], rand(500, 100000));
$this->assertIdenticalObject($this->objects[1], $stores[0]->get('foo'));
// Verify that the other collection is still not affected.
$this->assertFalse($stores[1]->get('foo'));
// Verify that the expirable data key is unique.
$stores[1]->setWithExpire('foo', $this->objects[2], rand(500, 100000));
$this->assertIdenticalObject($this->objects[1], $stores[0]->get('foo'));
$this->assertIdenticalObject($this->objects[2], $stores[1]->get('foo'));
// Verify that multiple items can be stored with setMultipleWithExpire().
$values = array(
'foo' => $this->objects[3],
'bar' => $this->objects[4],
);
$stores[0]->setMultipleWithExpire($values, rand(500, 100000));
$result = $stores[0]->getMultiple(array('foo', 'bar'));
foreach ($values as $j => $value) {
$this->assertIdenticalObject($value, $result[$j]);
}
// Verify that the other collection was not affected.
$this->assertIdenticalObject($stores[1]->get('foo'), $this->objects[2]);
$this->assertFalse($stores[1]->get('bar'));
// Verify that all items in a collection can be retrieved.
// Ensure that an item with the same name exists in the other collection.
$stores[1]->set('foo', $this->objects[5]);
$result = $stores[0]->getAll();
// Not using assertIdentical(), since the order is not defined for getAll().
$this->assertEqual(count($result), count($values));
foreach ($result as $key => $value) {
$this->assertEqual($values[$key], $value);
}
// Verify that all items in the other collection are different.
$result = $stores[1]->getAll();
$this->assertEqual($result, array('foo' => $this->objects[5]));
// Verify that multiple items can be deleted.
$stores[0]->deleteMultiple(array_keys($values));
$this->assertFalse($stores[0]->get('foo'));
$this->assertFalse($stores[0]->get('bar'));
$this->assertFalse($stores[0]->getMultiple(array('foo', 'bar')));
// Verify that the item in the other collection still exists.
$this->assertIdenticalObject($this->objects[5], $stores[1]->get('foo'));
// Test that setWithExpireIfNotExists() succeeds only the first time.
$key = $this->randomMachineName();
for ($i = 0; $i <= 1; $i++) {
// setWithExpireIfNotExists() should be TRUE the first time (when $i is
// 0) and FALSE the second time (when $i is 1).
$this->assertEqual(!$i, $stores[0]->setWithExpireIfNotExists($key, $this->objects[$i], rand(500, 100000)));
$this->assertIdenticalObject($this->objects[0], $stores[0]->get($key));
// Verify that the other collection is not affected.
$this->assertFalse($stores[1]->get($key));
}
// Remove the item and try to set it again.
$stores[0]->delete($key);
$stores[0]->setWithExpireIfNotExists($key, $this->objects[1], rand(500, 100000));
// This time it should succeed.
$this->assertIdenticalObject($this->objects[1], $stores[0]->get($key));
// Verify that the other collection is still not affected.
$this->assertFalse($stores[1]->get($key));
}
/**
* Tests data expiration.
*/
public function testExpiration() {
$stores = $this->createStorage();
$day = 604800;
// Set an item to expire in the past and another without an expiration.
$stores[0]->setWithExpire('yesterday', 'all my troubles seemed so far away', -1 * $day);
$stores[0]->set('troubles', 'here to stay');
// Only the non-expired item should be returned.
$this->assertFalse($stores[0]->has('yesterday'));
$this->assertFalse($stores[0]->get('yesterday'));
$this->assertTrue($stores[0]->has('troubles'));
$this->assertIdentical($stores[0]->get('troubles'), 'here to stay');
$this->assertIdentical(count($stores[0]->getMultiple(array('yesterday', 'troubles'))), 1);
// Store items set to expire in the past in various ways.
$stores[0]->setWithExpire($this->randomMachineName(), $this->objects[0], -7 * $day);
$stores[0]->setWithExpireIfNotExists($this->randomMachineName(), $this->objects[1], -5 * $day);
$stores[0]->setMultipleWithExpire(
array(
$this->randomMachineName() => $this->objects[2],
$this->randomMachineName() => $this->objects[3],
),
-3 * $day
);
$stores[0]->setWithExpireIfNotExists('yesterday', "you'd forgiven me", -1 * $day);
$stores[0]->setWithExpire('still', "'til we say we're sorry", 2 * $day);
// Ensure only non-expired items are retrieved.
$all = $stores[0]->getAll();
$this->assertIdentical(count($all), 2);
foreach (array('troubles', 'still') as $key) {
$this->assertTrue(!empty($all[$key]));
}
}
}

View file

@ -1,37 +0,0 @@
<?php
namespace Drupal\system\Tests\KeyValueStore;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\KeyValueStore\KeyValueFactory;
/**
* Tests the key-value database storage.
*
* @group KeyValueStore
*/
class DatabaseStorageTest extends StorageTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
protected function setUp() {
parent::setUp();
$this->installSchema('system', array('key_value'));
}
/**
* {@inheritdoc}
*/
public function containerBuild(ContainerBuilder $container) {
parent::containerBuild($container);
$parameter[KeyValueFactory::DEFAULT_SETTING] = 'keyvalue.database';
$container->setParameter('factory.keyvalue', $parameter);
}
}

View file

@ -1,72 +0,0 @@
<?php
namespace Drupal\system\Tests\KeyValueStore;
use Drupal\Component\Serialization\PhpSerialize;
use Drupal\Core\Database\Database;
use Drupal\Core\KeyValueStore\DatabaseStorageExpirable;
use Drupal\simpletest\KernelTestBase;
/**
* Tests garbage collection for the expirable key-value database storage.
*
* @group KeyValueStore
*/
class GarbageCollectionTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
protected function setUp() {
parent::setUp();
// These additional tables are necessary due to the call to system_cron().
$this->installSchema('system', array('key_value_expire'));
}
/**
* Tests garbage collection.
*/
public function testGarbageCollection() {
$collection = $this->randomMachineName();
$store = new DatabaseStorageExpirable($collection, new PhpSerialize(), Database::getConnection());
// Insert some items and confirm that they're set.
for ($i = 0; $i <= 3; $i++) {
$store->setWithExpire('key_' . $i, $this->randomObject(), rand(500, 100000));
}
$this->assertIdentical(sizeof($store->getAll()), 4, 'Four items were written to the storage.');
// Manually expire the data.
for ($i = 0; $i <= 3; $i++) {
db_merge('key_value_expire')
->keys(array(
'name' => 'key_' . $i,
'collection' => $collection,
))
->fields(array(
'expire' => REQUEST_TIME - 1,
))
->execute();
}
// Perform a new set operation and then trigger garbage collection.
$store->setWithExpire('autumn', 'winter', rand(500, 1000000));
system_cron();
// Query the database and confirm that the stale records were deleted.
$result = db_query(
'SELECT name, value FROM {key_value_expire} WHERE collection = :collection',
array(
':collection' => $collection,
))->fetchAll();
$this->assertIdentical(count($result), 1, 'Only one item remains after garbage collection');
}
}

View file

@ -1,160 +0,0 @@
<?php
namespace Drupal\system\Tests\KeyValueStore;
use Drupal\Core\Entity\EntityMalformedException;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\KernelTests\KernelTestBase;
use Drupal\entity_test\Entity\EntityTestLabel;
/**
* Tests KeyValueEntityStorage for content entities.
*
* @group KeyValueStore
*/
class KeyValueContentEntityStorageTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('user', 'entity_test', 'keyvalue_test');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('user');
}
/**
* Tests CRUD operations.
*/
function testCRUD() {
$default_langcode = \Drupal::languageManager()->getDefaultLanguage()->getId();
// Verify default properties on a newly created empty entity.
$empty = EntityTestLabel::create();
$this->assertIdentical($empty->id->value, NULL);
$this->assertIdentical($empty->name->value, NULL);
$this->assertTrue($empty->uuid->value);
$this->assertIdentical($empty->langcode->value, $default_langcode);
// Verify ConfigEntity properties/methods on the newly created empty entity.
$this->assertIdentical($empty->isNew(), TRUE);
$this->assertIdentical($empty->bundle(), 'entity_test_label');
$this->assertIdentical($empty->id(), NULL);
$this->assertTrue($empty->uuid());
$this->assertIdentical($empty->label(), NULL);
// Verify Entity properties/methods on the newly created empty entity.
$this->assertIdentical($empty->getEntityTypeId(), 'entity_test_label');
// The URI can only be checked after saving.
try {
$empty->urlInfo();
$this->fail('EntityMalformedException was thrown.');
}
catch (EntityMalformedException $e) {
$this->pass('EntityMalformedException was thrown.');
}
// Verify that an empty entity cannot be saved.
try {
$empty->save();
$this->fail('EntityMalformedException was thrown.');
}
catch (EntityMalformedException $e) {
$this->pass('EntityMalformedException was thrown.');
}
// Verify that an entity with an empty ID string is considered empty, too.
$empty_id = EntityTestLabel::create(array(
'id' => '',
));
$this->assertIdentical($empty_id->isNew(), TRUE);
try {
$empty_id->save();
$this->fail('EntityMalformedException was thrown.');
}
catch (EntityMalformedException $e) {
$this->pass('EntityMalformedException was thrown.');
}
// Verify properties on a newly created entity.
$entity_test = EntityTestLabel::create($expected = array(
'id' => $this->randomMachineName(),
'name' => $this->randomString(),
));
$this->assertIdentical($entity_test->id->value, $expected['id']);
$this->assertTrue($entity_test->uuid->value);
$this->assertNotEqual($entity_test->uuid->value, $empty->uuid->value);
$this->assertIdentical($entity_test->name->value, $expected['name']);
$this->assertIdentical($entity_test->langcode->value, $default_langcode);
// Verify methods on the newly created entity.
$this->assertIdentical($entity_test->isNew(), TRUE);
$this->assertIdentical($entity_test->id(), $expected['id']);
$this->assertTrue($entity_test->uuid());
$expected['uuid'] = $entity_test->uuid();
$this->assertIdentical($entity_test->label(), $expected['name']);
// Verify that the entity can be saved.
try {
$status = $entity_test->save();
$this->pass('EntityMalformedException was not thrown.');
}
catch (EntityMalformedException $e) {
$this->fail('EntityMalformedException was not thrown.');
}
// Verify that the correct status is returned and properties did not change.
$this->assertIdentical($status, SAVED_NEW);
$this->assertIdentical($entity_test->id(), $expected['id']);
$this->assertIdentical($entity_test->uuid(), $expected['uuid']);
$this->assertIdentical($entity_test->label(), $expected['name']);
$this->assertIdentical($entity_test->isNew(), FALSE);
// Save again, and verify correct status and properties again.
$status = $entity_test->save();
$this->assertIdentical($status, SAVED_UPDATED);
$this->assertIdentical($entity_test->id(), $expected['id']);
$this->assertIdentical($entity_test->uuid(), $expected['uuid']);
$this->assertIdentical($entity_test->label(), $expected['name']);
$this->assertIdentical($entity_test->isNew(), FALSE);
// Ensure that creating an entity with the same id as an existing one is not
// possible.
$same_id = EntityTestLabel::create(array(
'id' => $entity_test->id(),
));
$this->assertIdentical($same_id->isNew(), TRUE);
try {
$same_id->save();
$this->fail('Not possible to overwrite an entity entity.');
}
catch (EntityStorageException $e) {
$this->pass('Not possible to overwrite an entity entity.');
}
// Verify that renaming the ID returns correct status and properties.
$ids = array($expected['id'], 'second_' . $this->randomMachineName(4), 'third_' . $this->randomMachineName(4));
for ($i = 1; $i < 3; $i++) {
$old_id = $ids[$i - 1];
$new_id = $ids[$i];
// Before renaming, everything should point to the current ID.
$this->assertIdentical($entity_test->id(), $old_id);
// Rename.
$entity_test->id = $new_id;
$this->assertIdentical($entity_test->id(), $new_id);
$status = $entity_test->save();
$this->assertIdentical($status, SAVED_UPDATED);
$this->assertIdentical($entity_test->isNew(), FALSE);
// Verify that originalID points to new ID directly after renaming.
$this->assertIdentical($entity_test->id(), $new_id);
}
}
}

View file

@ -1,26 +0,0 @@
<?php
namespace Drupal\system\Tests\KeyValueStore;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\KeyValueStore\KeyValueFactory;
/**
* Tests the key-value memory storage.
*
* @group KeyValueStore
*/
class MemoryStorageTest extends StorageTestBase {
/**
* {@inheritdoc}
*/
public function containerBuild(ContainerBuilder $container) {
parent::containerBuild($container);
$container->register('keyvalue.memory', 'Drupal\Core\KeyValueStore\KeyValueMemoryFactory');
$parameter[KeyValueFactory::DEFAULT_SETTING] = 'keyvalue.memory';
$container->setParameter('factory.keyvalue', $parameter);
}
}

View file

@ -1,215 +0,0 @@
<?php
namespace Drupal\system\Tests\KeyValueStore;
use Drupal\simpletest\KernelTestBase;
/**
* Base class for testing key-value storages.
*/
abstract class StorageTestBase extends KernelTestBase {
/**
* An array of random stdClass objects.
*
* @var array
*/
protected $objects = array();
/**
* An array of data collection labels.
*
* @var array
*/
protected $collections = array();
/**
* Whether we are using an expirable key/value store.
*
* @var bool
*/
protected $factory = 'keyvalue';
protected function setUp() {
parent::setUp();
// Define two data collections,
$this->collections = array(0 => 'zero', 1 => 'one');
// Create several objects for testing.
for ($i = 0; $i <= 5; $i++) {
$this->objects[$i] = $this->randomObject();
}
}
/**
* Tests CRUD operations.
*/
public function testCRUD() {
$stores = $this->createStorage();
// Verify that each store returns its own collection name.
$this->assertIdentical($stores[0]->getCollectionName(), $this->collections[0]);
$this->assertIdentical($stores[1]->getCollectionName(), $this->collections[1]);
// Verify that an item can be stored.
$stores[0]->set('foo', $this->objects[0]);
$this->assertTrue($stores[0]->has('foo'));
$this->assertIdenticalObject($this->objects[0], $stores[0]->get('foo'));
// Verify that the other collection is not affected.
$this->assertFalse($stores[1]->has('foo'));
$this->assertFalse($stores[1]->get('foo'));
// Verify that an item can be updated.
$stores[0]->set('foo', $this->objects[1]);
$this->assertIdenticalObject($this->objects[1], $stores[0]->get('foo'));
// Verify that the other collection is still not affected.
$this->assertFalse($stores[1]->get('foo'));
// Verify that a collection/name pair is unique.
$stores[1]->set('foo', $this->objects[2]);
$this->assertIdenticalObject($this->objects[1], $stores[0]->get('foo'));
$this->assertIdenticalObject($this->objects[2], $stores[1]->get('foo'));
// Verify that an item can be deleted.
$stores[0]->delete('foo');
$this->assertFalse($stores[0]->has('foo'));
$this->assertFalse($stores[0]->get('foo'));
// Verify that the other collection is not affected.
$this->assertTrue($stores[1]->has('foo'));
$this->assertIdenticalObject($this->objects[2], $stores[1]->get('foo'));
$stores[1]->delete('foo');
$this->assertFalse($stores[1]->get('foo'));
// Verify that multiple items can be stored.
$values = array(
'foo' => $this->objects[3],
'bar' => $this->objects[4],
);
$stores[0]->setMultiple($values);
// Verify that multiple items can be retrieved.
$result = $stores[0]->getMultiple(array('foo', 'bar'));
foreach ($values as $j => $value) {
$this->assertIdenticalObject($value, $result[$j]);
}
// Verify that the other collection was not affected.
$this->assertFalse($stores[1]->get('foo'));
$this->assertFalse($stores[1]->get('bar'));
// Verify that all items in a collection can be retrieved.
// Ensure that an item with the same name exists in the other collection.
$stores[1]->set('foo', $this->objects[5]);
$result = $stores[0]->getAll();
// Not using assertIdentical(), since the order is not defined for getAll().
$this->assertEqual(count($result), count($values));
foreach ($result as $key => $value) {
$this->assertEqual($values[$key], $value);
}
// Verify that all items in the other collection are different.
$result = $stores[1]->getAll();
$this->assertEqual($result, array('foo' => $this->objects[5]));
// Verify that multiple items can be deleted.
$stores[0]->deleteMultiple(array_keys($values));
$this->assertFalse($stores[0]->get('foo'));
$this->assertFalse($stores[0]->get('bar'));
$this->assertFalse($stores[0]->getMultiple(array('foo', 'bar')));
// Verify that deleting no items does not cause an error.
$stores[0]->deleteMultiple(array());
// Verify that the item in the other collection still exists.
$this->assertIdenticalObject($this->objects[5], $stores[1]->get('foo'));
}
/**
* Tests expected behavior for non-existing keys.
*/
public function testNonExistingKeys() {
$stores = $this->createStorage();
// Verify that a non-existing key returns NULL as value.
$this->assertNull($stores[0]->get('foo'));
// Verify that a non-existing key with a default returns the default.
$this->assertIdentical($stores[0]->get('foo', 'bar'), 'bar');
// Verify that a FALSE value can be stored.
$stores[0]->set('foo', FALSE);
$this->assertIdentical($stores[0]->get('foo'), FALSE);
// Verify that a deleted key returns NULL as value.
$stores[0]->delete('foo');
$this->assertNull($stores[0]->get('foo'));
// Verify that a non-existing key is not returned when getting multiple keys.
$stores[0]->set('bar', 'baz');
$values = $stores[0]->getMultiple(array('foo', 'bar'));
$this->assertFalse(isset($values['foo']), "Key 'foo' not found.");
$this->assertIdentical($values['bar'], 'baz');
}
/**
* Tests the setIfNotExists() method.
*/
public function testSetIfNotExists() {
$stores = $this->createStorage();
$key = $this->randomMachineName();
// Test that setIfNotExists() succeeds only the first time.
for ($i = 0; $i <= 1; $i++) {
// setIfNotExists() should be TRUE the first time (when $i is 0) and
// FALSE the second time (when $i is 1).
$this->assertEqual(!$i, $stores[0]->setIfNotExists($key, $this->objects[$i]));
$this->assertIdenticalObject($this->objects[0], $stores[0]->get($key));
// Verify that the other collection is not affected.
$this->assertFalse($stores[1]->get($key));
}
// Remove the item and try to set it again.
$stores[0]->delete($key);
$stores[0]->setIfNotExists($key, $this->objects[1]);
// This time it should succeed.
$this->assertIdenticalObject($this->objects[1], $stores[0]->get($key));
// Verify that the other collection is still not affected.
$this->assertFalse($stores[1]->get($key));
}
/**
* Tests the rename operation.
*/
public function testRename() {
$stores = $this->createStorage();
$store = $stores[0];
$store->set('old', 'thing');
$this->assertIdentical($store->get('old'), 'thing');
$store->rename('old', 'new');
$this->assertIdentical($store->get('new'), 'thing');
$this->assertNull($store->get('old'));
}
/**
* Creates storage objects for each collection defined for this class.
*
* Storing the storage objects in a class member variable causes a fatal
* exception in DatabaseStorageExpirableTest, because in that situation
* garbage collection is not triggered until the test class itself is
* destructed, after tearDown() has deleted the database tables. Instead,
* create the storage objects locally in each test using this method.
*
* @see \Drupal\system\Tests\KeyValueStore\DatabaseStorageExpirable
* @see \Drupal\Core\KeyValueStore\DatabaseStorageExpirable::garbageCollection()
*/
protected function createStorage() {
$stores = array();
foreach ($this->collections as $i => $collection) {
$stores[$i] = $this->container->get($this->factory)->get($collection);
}
return $stores;
}
}

View file

@ -1,71 +0,0 @@
<?php
namespace Drupal\system\Tests\Lock;
use Drupal\Core\Lock\DatabaseLockBackend;
use Drupal\simpletest\KernelTestBase;
/**
* Tests the Database lock backend.
*
* @group Lock
*/
class LockUnitTest extends KernelTestBase {
/**
* Database lock backend to test.
*
* @var \Drupal\Core\Lock\DatabaseLockBackend
*/
protected $lock;
protected function setUp() {
parent::setUp();
$this->lock = new DatabaseLockBackend($this->container->get('database'));
}
/**
* Tests backend release functionality.
*/
public function testBackendLockRelease() {
$success = $this->lock->acquire('lock_a');
$this->assertTrue($success, 'Could acquire first lock.');
// This function is not part of the backend, but the default database
// backend implement it, we can here use it safely.
$is_free = $this->lock->lockMayBeAvailable('lock_a');
$this->assertFalse($is_free, 'First lock is unavailable.');
$this->lock->release('lock_a');
$is_free = $this->lock->lockMayBeAvailable('lock_a');
$this->assertTrue($is_free, 'First lock has been released.');
$success = $this->lock->acquire('lock_b');
$this->assertTrue($success, 'Could acquire second lock.');
$success = $this->lock->acquire('lock_b');
$this->assertTrue($success, 'Could acquire second lock a second time within the same request.');
$this->lock->release('lock_b');
}
/**
* Tests backend release functionality.
*/
public function testBackendLockReleaseAll() {
$success = $this->lock->acquire('lock_a');
$this->assertTrue($success, 'Could acquire first lock.');
$success = $this->lock->acquire('lock_b');
$this->assertTrue($success, 'Could acquire second lock.');
$this->lock->releaseAll();
$is_free = $this->lock->lockMayBeAvailable('lock_a');
$this->assertTrue($is_free, 'First lock has been released.');
$is_free = $this->lock->lockMayBeAvailable('lock_b');
$this->assertTrue($is_free, 'Second lock has been released.');
}
}

View file

@ -1,57 +0,0 @@
<?php
namespace Drupal\system\Tests\Menu;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\simpletest\KernelTestBase;
/**
* Tests integration of static menu links.
*
* @group Menu
*/
class MenuLinkDefaultIntegrationTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array(
'system',
'menu_test',
);
/**
* Tests moving a static menu link without a specified menu to the root.
*/
public function testMoveToRoot() {
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$menu_link_manager->rebuild();
$menu_link = $menu_link_manager->getDefinition('menu_test.child');
$this->assertEqual($menu_link['parent'], 'menu_test.parent');
$this->assertEqual($menu_link['menu_name'], 'test');
$tree = \Drupal::menuTree()->load('test', new MenuTreeParameters());
$this->assertEqual(count($tree), 1);
$this->assertEqual($tree['menu_test.parent']->link->getPluginId(), 'menu_test.parent');
$this->assertEqual($tree['menu_test.parent']->subtree['menu_test.child']->link->getPluginId(), 'menu_test.child');
// Ensure that the menu name is not forgotten.
$menu_link_manager->updateDefinition('menu_test.child', array('parent' => ''));
$menu_link = $menu_link_manager->getDefinition('menu_test.child');
$this->assertEqual($menu_link['parent'], '');
$this->assertEqual($menu_link['menu_name'], 'test');
$tree = \Drupal::menuTree()->load('test', new MenuTreeParameters());
$this->assertEqual(count($tree), 2);
$this->assertEqual($tree['menu_test.parent']->link->getPluginId(), 'menu_test.parent');
$this->assertEqual($tree['menu_test.child']->link->getPluginId(), 'menu_test.child');
$this->assertTrue(TRUE);
}
}

View file

@ -1,133 +0,0 @@
<?php
namespace Drupal\system\Tests\Menu;
use Drupal\Core\Menu\MenuLinkTreeElement;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\simpletest\KernelTestBase;
use Drupal\Tests\Core\Menu\MenuLinkMock;
/**
* Tests the menu link tree.
*
* @group Menu
*
* @see \Drupal\Core\Menu\MenuLinkTree
*/
class MenuLinkTreeTest extends KernelTestBase {
/**
* The tested menu link tree.
*
* @var \Drupal\Core\Menu\MenuLinkTree
*/
protected $linkTree;
/**
* The menu link plugin manager.
*
* @var \Drupal\Core\Menu\MenuLinkManagerInterface $menuLinkManager
*/
protected $menuLinkManager;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array(
'system',
'menu_test',
'menu_link_content',
'field',
'link',
);
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
\Drupal::service('router.builder')->rebuild();
$this->installEntitySchema('menu_link_content');
$this->linkTree = $this->container->get('menu.link_tree');
$this->menuLinkManager = $this->container->get('plugin.manager.menu.link');
}
/**
* Tests deleting all the links in a menu.
*/
public function testDeleteLinksInMenu() {
\Drupal::entityManager()->getStorage('menu')->create(array('id' => 'menu1'))->save();
\Drupal::entityManager()->getStorage('menu')->create(array('id' => 'menu2'))->save();
\Drupal::entityManager()->getStorage('menu_link_content')->create(array('link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content'))->save();
\Drupal::entityManager()->getStorage('menu_link_content')->create(array('link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu1', 'bundle' => 'menu_link_content'))->save();
\Drupal::entityManager()->getStorage('menu_link_content')->create(array('link' => ['uri' => 'internal:/menu_name_test'], 'menu_name' => 'menu2', 'bundle' => 'menu_link_content'))->save();
$output = $this->linkTree->load('menu1', new MenuTreeParameters());
$this->assertEqual(count($output), 2);
$output = $this->linkTree->load('menu2', new MenuTreeParameters());
$this->assertEqual(count($output), 1);
$this->menuLinkManager->deleteLinksInMenu('menu1');
$output = $this->linkTree->load('menu1', new MenuTreeParameters());
$this->assertEqual(count($output), 0);
$output = $this->linkTree->load('menu2', new MenuTreeParameters());
$this->assertEqual(count($output), 1);
}
/**
* Tests creating links with an expected tree structure.
*/
public function testCreateLinksInMenu() {
// 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' => '')),
2 => MenuLinkMock::create(array('id' => 'test.example2', 'route_name' => 'example2', 'title' => 'bar', 'parent' => 'test.example1', 'route_parameters' => array('foo' => 'bar'))),
3 => MenuLinkMock::create(array('id' => 'test.example3', 'route_name' => 'example3', 'title' => 'baz', 'parent' => 'test.example2', 'route_parameters' => array('baz' => 'qux'))),
4 => MenuLinkMock::create(array('id' => 'test.example4', 'route_name' => 'example4', 'title' => 'qux', 'parent' => 'test.example3')),
5 => MenuLinkMock::create(array('id' => 'test.example5', 'route_name' => 'example5', 'title' => 'foofoo', 'parent' => '')),
6 => MenuLinkMock::create(array('id' => 'test.example6', 'route_name' => '', 'url' => 'https://www.drupal.org/', 'title' => 'barbar', 'parent' => '')),
7 => MenuLinkMock::create(array('id' => 'test.example7', 'route_name' => 'example7', 'title' => 'bazbaz', 'parent' => '')),
8 => MenuLinkMock::create(array('id' => 'test.example8', 'route_name' => 'example8', 'title' => 'quxqux', 'parent' => '')),
);
foreach ($links as $instance) {
$this->menuLinkManager->addDefinition($instance->getPluginId(), $instance->getPluginDefinition());
}
$parameters = new MenuTreeParameters();
$tree = $this->linkTree->load('mock', $parameters);
$count = function(array $tree) {
$sum = function ($carry, MenuLinkTreeElement $item) {
return $carry + $item->count();
};
return array_reduce($tree, $sum);
};
$this->assertEqual($count($tree), 8);
$parameters = new MenuTreeParameters();
$parameters->setRoot('test.example2');
$tree = $this->linkTree->load($instance->getMenuName(), $parameters);
$top_link = reset($tree);
$this->assertEqual(count($top_link->subtree), 1);
$child = reset($top_link->subtree);
$this->assertEqual($child->link->getPluginId(), $links[3]->getPluginId());
$height = $this->linkTree->getSubtreeHeight('test.example2');
$this->assertEqual($height, 3);
}
}

View file

@ -1,460 +0,0 @@
<?php
namespace Drupal\system\Tests\Menu;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\Core\Menu\MenuTreeStorage;
use Drupal\simpletest\KernelTestBase;
/**
* Tests the menu tree storage.
*
* @group Menu
*
* @see \Drupal\Core\Menu\MenuTreeStorage
*/
class MenuTreeStorageTest extends KernelTestBase {
/**
* The tested tree storage.
*
* @var \Drupal\Core\Menu\MenuTreeStorage
*/
protected $treeStorage;
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system');
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->treeStorage = new MenuTreeStorage($this->container->get('database'), $this->container->get('cache.menu'), $this->container->get('cache_tags.invalidator'), 'menu_tree');
$this->connection = $this->container->get('database');
}
/**
* Tests the tree storage when no tree was built yet.
*/
public function testBasicMethods() {
$this->doTestEmptyStorage();
$this->doTestTable();
}
/**
* Ensures that there are no menu links by default.
*/
protected function doTestEmptyStorage() {
$this->assertEqual(0, $this->treeStorage->countMenuLinks());
}
/**
* Ensures that table gets created on the fly.
*/
protected function doTestTable() {
// Test that we can create a tree storage with an arbitrary table name and
// that selecting from the storage creates the table.
$tree_storage = new MenuTreeStorage($this->container->get('database'), $this->container->get('cache.menu'), $this->container->get('cache_tags.invalidator'), 'test_menu_tree');
$this->assertFalse($this->connection->schema()->tableExists('test_menu_tree'), 'Test table is not yet created');
$tree_storage->countMenuLinks();
$this->assertTrue($this->connection->schema()->tableExists('test_menu_tree'), 'Test table was created');
}
/**
* Tests with a simple linear hierarchy.
*/
public function testSimpleHierarchy() {
// Add some links with parent on the previous one and test some values.
// <tools>
// - test1
// -- test2
// --- test3
$this->addMenuLink('test1', '');
$this->assertMenuLink('test1', array('has_children' => 0, 'depth' => 1));
$this->addMenuLink('test2', 'test1');
$this->assertMenuLink('test1', array('has_children' => 1, 'depth' => 1), array(), array('test2'));
$this->assertMenuLink('test2', array('has_children' => 0, 'depth' => 2), array('test1'));
$this->addMenuLink('test3', 'test2');
$this->assertMenuLink('test1', array('has_children' => 1, 'depth' => 1), array(), array('test2', 'test3'));
$this->assertMenuLink('test2', array('has_children' => 1, 'depth' => 2), array('test1'), array('test3'));
$this->assertMenuLink('test3', array('has_children' => 0, 'depth' => 3), array('test2', 'test1'));
}
/**
* Tests the tree with moving links inside the hierarchy.
*/
public function testMenuLinkMoving() {
// Before the move.
// <tools>
// - test1
// -- test2
// --- test3
// - test4
// -- test5
// --- test6
$this->addMenuLink('test1', '');
$this->addMenuLink('test2', 'test1');
$this->addMenuLink('test3', 'test2');
$this->addMenuLink('test4', '');
$this->addMenuLink('test5', 'test4');
$this->addMenuLink('test6', 'test5');
$this->assertMenuLink('test1', array('has_children' => 1, 'depth' => 1), array(), array('test2', 'test3'));
$this->assertMenuLink('test2', array('has_children' => 1, 'depth' => 2), array('test1'), array('test3'));
$this->assertMenuLink('test4', array('has_children' => 1, 'depth' => 1), array(), array('test5', 'test6'));
$this->assertMenuLink('test5', array('has_children' => 1, 'depth' => 2), array('test4'), array('test6'));
$this->assertMenuLink('test6', array('has_children' => 0, 'depth' => 3), array('test5', 'test4'));
$this->moveMenuLink('test2', 'test5');
// After the 1st move.
// <tools>
// - test1
// - test4
// -- test5
// --- test2
// ---- test3
// --- test6
$this->assertMenuLink('test1', array('has_children' => 0, 'depth' => 1));
$this->assertMenuLink('test2', array('has_children' => 1, 'depth' => 3), array('test5', 'test4'), array('test3'));
$this->assertMenuLink('test3', array('has_children' => 0, 'depth' => 4), array('test2', 'test5', 'test4'));
$this->assertMenuLink('test4', array('has_children' => 1, 'depth' => 1), array(), array('test5', 'test2', 'test3', 'test6'));
$this->assertMenuLink('test5', array('has_children' => 1, 'depth' => 2), array('test4'), array('test2', 'test3', 'test6'));
$this->assertMenuLink('test6', array('has_children' => 0, 'depth' => 3), array('test5', 'test4'));
$this->moveMenuLink('test4', 'test1');
$this->moveMenuLink('test3', 'test1');
// After the next 2 moves.
// <tools>
// - test1
// -- test3
// -- test4
// --- test5
// ---- test2
// ---- test6
$this->assertMenuLink('test1', array('has_children' => 1, 'depth' => 1), array(), array('test4', 'test5', 'test2', 'test3', 'test6'));
$this->assertMenuLink('test2', array('has_children' => 0, 'depth' => 4), array('test5', 'test4', 'test1'));
$this->assertMenuLink('test3', array('has_children' => 0, 'depth' => 2), array('test1'));
$this->assertMenuLink('test4', array('has_children' => 1, 'depth' => 2), array('test1'), array('test2', 'test5', 'test6'));
$this->assertMenuLink('test5', array('has_children' => 1, 'depth' => 3), array('test4', 'test1'), array('test2', 'test6'));
$this->assertMenuLink('test6', array('has_children' => 0, 'depth' => 4), array('test5', 'test4', 'test1'));
// Deleting a link in the middle should re-attach child links to the parent.
$this->treeStorage->delete('test4');
// After the delete.
// <tools>
// - test1
// -- test3
// -- test5
// --- test2
// --- test6
$this->assertMenuLink('test1', array('has_children' => 1, 'depth' => 1), array(), array('test5', 'test2', 'test3', 'test6'));
$this->assertMenuLink('test2', array('has_children' => 0, 'depth' => 3), array('test5', 'test1'));
$this->assertMenuLink('test3', array('has_children' => 0, 'depth' => 2), array('test1'));
$this->assertFalse($this->treeStorage->load('test4'));
$this->assertMenuLink('test5', array('has_children' => 1, 'depth' => 2), array('test1'), array('test2', 'test6'));
$this->assertMenuLink('test6', array('has_children' => 0, 'depth' => 3), array('test5', 'test1'));
}
/**
* Tests with disabled child links.
*/
public function testMenuDisabledChildLinks() {
// Add some links with parent on the previous one and test some values.
// <tools>
// - test1
// -- test2 (disabled)
$this->addMenuLink('test1', '');
$this->assertMenuLink('test1', array('has_children' => 0, 'depth' => 1));
$this->addMenuLink('test2', 'test1', '<front>', array(), 'tools', array('enabled' => 0));
// The 1st link does not have any visible children, so has_children is 0.
$this->assertMenuLink('test1', array('has_children' => 0, 'depth' => 1));
$this->assertMenuLink('test2', array('has_children' => 0, 'depth' => 2, 'enabled' => 0), array('test1'));
// Add more links with parent on the previous one.
// <footer>
// - footerA
// ===============
// <tools>
// - test1
// -- test2 (disabled)
// --- test3
// ---- test4
// ----- test5
// ------ test6
// ------- test7
// -------- test8
// --------- test9
$this->addMenuLink('footerA', '', '<front>', array(), 'footer');
$visible_children = array();
for ($i = 3; $i <= $this->treeStorage->maxDepth(); $i++) {
$parent = $i - 1;
$this->addMenuLink("test$i", "test$parent");
$visible_children[] = "test$i";
}
// The 1st link does not have any visible children, so has_children is still
// 0. However, it has visible links below it that will be found.
$this->assertMenuLink('test1', array('has_children' => 0, 'depth' => 1), array(), $visible_children);
// This should fail since test9 would end up at greater than max depth.
try {
$this->moveMenuLink('test1', 'footerA');
$this->fail('Exception was not thrown');
}
catch (PluginException $e) {
$this->pass($e->getMessage());
}
// The opposite move should work, and change the has_children flag.
$this->moveMenuLink('footerA', 'test1');
$visible_children[] = 'footerA';
$this->assertMenuLink('test1', array('has_children' => 1, 'depth' => 1), array(), $visible_children);
}
/**
* Tests the loadTreeData method.
*/
public function testLoadTree() {
$this->addMenuLink('test1', '');
$this->addMenuLink('test2', 'test1');
$this->addMenuLink('test3', 'test2');
$this->addMenuLink('test4');
$this->addMenuLink('test5', 'test4');
$data = $this->treeStorage->loadTreeData('tools', new MenuTreeParameters());
$tree = $data['tree'];
$this->assertEqual(count($tree['test1']['subtree']), 1);
$this->assertEqual(count($tree['test1']['subtree']['test2']['subtree']), 1);
$this->assertEqual(count($tree['test1']['subtree']['test2']['subtree']['test3']['subtree']), 0);
$this->assertEqual(count($tree['test4']['subtree']), 1);
$this->assertEqual(count($tree['test4']['subtree']['test5']['subtree']), 0);
$parameters = new MenuTreeParameters();
$parameters->setActiveTrail(array('test4', 'test5'));
$data = $this->treeStorage->loadTreeData('tools', $parameters);
$tree = $data['tree'];
$this->assertEqual(count($tree['test1']['subtree']), 1);
$this->assertFalse($tree['test1']['in_active_trail']);
$this->assertEqual(count($tree['test1']['subtree']['test2']['subtree']), 1);
$this->assertFalse($tree['test1']['subtree']['test2']['in_active_trail']);
$this->assertEqual(count($tree['test1']['subtree']['test2']['subtree']['test3']['subtree']), 0);
$this->assertFalse($tree['test1']['subtree']['test2']['subtree']['test3']['in_active_trail']);
$this->assertEqual(count($tree['test4']['subtree']), 1);
$this->assertTrue($tree['test4']['in_active_trail']);
$this->assertEqual(count($tree['test4']['subtree']['test5']['subtree']), 0);
$this->assertTrue($tree['test4']['subtree']['test5']['in_active_trail']);
// Add some conditions to ensure that conditions work as expected.
$parameters = new MenuTreeParameters();
$parameters->addCondition('parent', 'test1');
$data = $this->treeStorage->loadTreeData('tools', $parameters);
$this->assertEqual(count($data['tree']), 1);
$this->assertEqual($data['tree']['test2']['definition']['id'], 'test2');
$this->assertEqual($data['tree']['test2']['subtree'], []);
// Test for only enabled links.
$link = $this->treeStorage->load('test3');
$link['enabled'] = FALSE;
$this->treeStorage->save($link);
$link = $this->treeStorage->load('test4');
$link['enabled'] = FALSE;
$this->treeStorage->save($link);
$link = $this->treeStorage->load('test5');
$link['enabled'] = FALSE;
$this->treeStorage->save($link);
$parameters = new MenuTreeParameters();
$parameters->onlyEnabledLinks();
$data = $this->treeStorage->loadTreeData('tools', $parameters);
$this->assertEqual(count($data['tree']), 1);
$this->assertEqual($data['tree']['test1']['definition']['id'], 'test1');
$this->assertEqual(count($data['tree']['test1']['subtree']), 1);
$this->assertEqual($data['tree']['test1']['subtree']['test2']['definition']['id'], 'test2');
$this->assertEqual($data['tree']['test1']['subtree']['test2']['subtree'], []);
}
/**
* Tests finding the subtree height with content menu links.
*/
public function testSubtreeHeight() {
// root
// - child1
// -- child2
// --- child3
// ---- child4
$this->addMenuLink('root');
$this->addMenuLink('child1', 'root');
$this->addMenuLink('child2', 'child1');
$this->addMenuLink('child3', 'child2');
$this->addMenuLink('child4', 'child3');
$this->assertEqual($this->treeStorage->getSubtreeHeight('root'), 5);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child1'), 4);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child2'), 3);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child3'), 2);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child4'), 1);
}
/**
* Ensure hierarchy persists after a menu rebuild.
*/
public function testMenuRebuild() {
// root
// - child1
// -- child2
// --- child3
// ---- child4
$this->addMenuLink('root');
$this->addMenuLink('child1', 'root');
$this->addMenuLink('child2', 'child1');
$this->addMenuLink('child3', 'child2');
$this->addMenuLink('child4', 'child3');
$this->assertEqual($this->treeStorage->getSubtreeHeight('root'), 5);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child1'), 4);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child2'), 3);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child3'), 2);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child4'), 1);
// Intentionally leave child3 out to mimic static or external links.
$definitions = $this->treeStorage->loadMultiple(['root', 'child1', 'child2', 'child4']);
$this->treeStorage->rebuild($definitions);
$this->assertEqual($this->treeStorage->getSubtreeHeight('root'), 5);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child1'), 4);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child2'), 3);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child3'), 2);
$this->assertEqual($this->treeStorage->getSubtreeHeight('child4'), 1);
}
/**
* Tests MenuTreeStorage::loadByProperties().
*/
public function testLoadByProperties() {
$tests = array(
array('foo' => 'bar'),
array(0 => 'wrong'),
);
$message = 'An invalid property name throws an exception.';
foreach ($tests as $properties) {
try {
$this->treeStorage->loadByProperties($properties);
$this->fail($message);
}
catch (\InvalidArgumentException $e) {
$this->assertTrue(preg_match('/^An invalid property name, .+ was specified. Allowed property names are:/', $e->getMessage()), 'Found expected exception message.');
$this->pass($message);
}
}
$this->addMenuLink('test_link.1', '', 'test', array(), 'menu1');
$properties = array('menu_name' => 'menu1');
$links = $this->treeStorage->loadByProperties($properties);
$this->assertEqual('menu1', $links['test_link.1']['menu_name']);
$this->assertEqual('test', $links['test_link.1']['route_name']);
}
/**
* Adds a link with the given ID and supply defaults.
*/
protected function addMenuLink($id, $parent = '', $route_name = 'test', $route_parameters = array(), $menu_name = 'tools', $extra = array()) {
$link = array(
'id' => $id,
'menu_name' => $menu_name,
'route_name' => $route_name,
'route_parameters' => $route_parameters,
'title' => 'test',
'parent' => $parent,
'options' => array(),
'metadata' => array(),
) + $extra;
$this->treeStorage->save($link);
}
/**
* Moves the link with the given ID so it's under a new parent.
*
* @param string $id
* The ID of the menu link to move.
* @param string $new_parent
* The ID of the new parent link.
*/
protected function moveMenuLink($id, $new_parent) {
$menu_link = $this->treeStorage->load($id);
$menu_link['parent'] = $new_parent;
$this->treeStorage->save($menu_link);
}
/**
* Tests that a link's stored representation matches the expected values.
*
* @param string $id
* The ID of the menu link to test
* @param array $expected_properties
* A keyed array of column names and values like has_children and depth.
* @param array $parents
* An ordered array of the IDs of the menu links that are the parents.
* @param array $children
* Array of child IDs that are visible (enabled == 1).
*/
protected function assertMenuLink($id, array $expected_properties, array $parents = array(), array $children = array()) {
$query = $this->connection->select('menu_tree');
$query->fields('menu_tree');
$query->condition('id', $id);
foreach ($expected_properties as $field => $value) {
$query->condition($field, $value);
}
$all = $query->execute()->fetchAll(\PDO::FETCH_ASSOC);
$this->assertEqual(count($all), 1, "Found link $id matching all the expected properties");
$raw = reset($all);
// Put the current link onto the front.
array_unshift($parents, $raw['id']);
$query = $this->connection->select('menu_tree');
$query->fields('menu_tree', array('id', 'mlid'));
$query->condition('id', $parents, 'IN');
$found_parents = $query->execute()->fetchAllKeyed(0, 1);
$this->assertEqual(count($parents), count($found_parents), 'Found expected number of parents');
$this->assertEqual($raw['depth'], count($found_parents), 'Number of parents is the same as the depth');
$materialized_path = $this->treeStorage->getRootPathIds($id);
$this->assertEqual(array_values($materialized_path), array_values($parents), 'Parents match the materialized path');
// Check that the selected mlid values of the parents are in the correct
// column, including the link's own.
for ($i = $raw['depth']; $i >= 1; $i--) {
$parent_id = array_shift($parents);
$this->assertEqual($raw["p$i"], $found_parents[$parent_id], "mlid of parent matches at column p$i");
}
for ($i = $raw['depth'] + 1; $i <= $this->treeStorage->maxDepth(); $i++) {
$this->assertEqual($raw["p$i"], 0, "parent is 0 at column p$i greater than depth");
}
if ($parents) {
$this->assertEqual($raw['parent'], end($parents), 'Ensure that the parent field is set properly');
}
$found_children = array_keys($this->treeStorage->loadAllChildren($id));
// We need both these checks since the 2nd will pass if there are extra
// IDs loaded in $found_children.
$this->assertEqual(count($children), count($found_children), "Found expected number of children for $id");
$this->assertEqual(array_intersect($children, $found_children), $children, 'Child IDs match');
}
}

Some files were not shown because too many files have changed in this diff Show more