Update to Drupal 8.1.0. For more information, see https://www.drupal.org/drupal-8.1.0-release-notes

This commit is contained in:
Pantheon Automation 2016-04-20 09:56:34 -07:00 committed by Greg Anderson
parent b11a755ba8
commit c0a0d5a94c
6920 changed files with 64395 additions and 57312 deletions

View file

@ -1,5 +1,10 @@
<?php
/**
* @file
* Text fixture.
*/
$connection = Drupal\Core\Database\Database::getConnection();
$connection->insert('config')

View file

@ -1,5 +1,10 @@
<?php
/**
* @file
* Test fixture.
*/
$connection = Drupal\Core\Database\Database::getConnection();
$connection->insert('config')

View file

@ -4,6 +4,7 @@
* @file
* Contains main module functionality.
*/
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
@ -38,7 +39,7 @@ function views_entity_test_entity_field_access($operation, FieldDefinitionInterf
if ($field_definition->getName() == 'test_text_access') {
if ($items) {
if ($items->value == 'no access value') {
return AccessResult::forbidden()->cacheUntilEntityChanges($items->getEntity());
return AccessResult::forbidden()->addCacheableDependency($items->getEntity());
}
}
}

View file

@ -34,7 +34,7 @@ display:
relationship: none
group_type: group
admin_label: ''
label: 'Content Type'
label: 'Content type'
exclude: false
alter:
alter_text: false

View file

@ -0,0 +1,161 @@
langcode: en
status: true
dependencies:
module:
- entity_test
- user
id: test_field_entity_test_rendered
label: 'Test Rendered entity test'
module: views
description: ''
tag: ''
base_table: entity_test
base_field: id
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: none
options: { }
cache:
type: none
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ' Previous'
next: 'Next '
first: '« First'
last: 'Last »'
quantity: 9
style:
type: default
options:
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
row:
type: fields
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
fields:
rendered_entity:
id: rendered_entity
table: entity_test
field: rendered_entity
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
view_mode: foobar
entity_type: entity_test
plugin_id: rendered_entity
filters: { }
sorts:
id:
id: id
table: entity_test
field: id
relationship: none
group_type: group
admin_label: ''
order: ASC
exposed: false
expose:
label: ''
entity_type: entity_test
entity_field: nid
plugin_id: standard
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: 0
contexts:
- 'languages:language_interface'
- url.query_args
- user.permissions
tags: { }

View file

@ -0,0 +1,130 @@
langcode: en
status: true
dependencies:
module:
- node
id: test_form_multiple
label: ''
module: views
description: ''
tag: ''
base_table: views_test_data
base_field: nid
core: 8.x
display:
default:
display_plugin: default
display_title: Master
id: default
position: 0
display_options:
access:
type: none
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
pager:
options:
id: 0
items_per_page: 10
offset: 0
type: full
style:
type: table
options:
grouping: { }
row_class: ''
default_row_class: true
override: true
sticky: false
caption: ''
summary: ''
description: ''
columns:
id: id
field_form_button_test: field_form_button_test
info:
field_form_button_test:
sortable: false
default_sort_order: asc
align: ''
separator: ''
empty_column: false
responsive: ''
default: '-1'
empty_table: false
row:
type: fields
fields:
id:
field: id
id: id
relationship: none
table: views_test_data
plugin_id: numeric
field_form_button_test:
id: field_form_button_test
table: views_test_data
field: field_form_button_test
relationship: none
group_type: group
admin_label: ''
label: 'Field form button test'
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
plugin_id: field_form_button_test
arguments:
'null':
default_action: default
default_argument_type: fixed
field: 'null'
id: 'null'
must_not_be: false
table: views
plugin_id: 'null'

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Cache\ViewsTestCacheContext.
*/
namespace Drupal\views_test_data\Cache;
use Drupal\Core\Cache\CacheableMetadata;

View file

@ -0,0 +1,39 @@
<?php
namespace Drupal\views_test_data\Controller;
use Drupal\Core\Controller\ControllerBase;
/**
* Controller routines for views form multiple test routes.
*/
class ViewsTestFormMultipleController extends ControllerBase {
/**
* Returns a test page having test_form_multiple view embedded twice.
*/
public function testPage() {
$build = [
'view_arg1' => [
'#prefix' => '<div class="view-test-form-multiple-1">',
'#suffix' => '</div>',
'#type' => 'view',
'#name' => 'test_form_multiple',
'#display_id' => 'default',
'#arguments' => ['arg1'],
'#embed' => TRUE,
],
'view_arg2' => [
'#prefix' => '<div class="view-test-form-multiple-2">',
'#suffix' => '</div>',
'#type' => 'view',
'#name' => 'test_form_multiple',
'#display_id' => 'default',
'#arguments' => ['arg2'],
'#embed' => TRUE,
],
];
return $build;
}
}

View file

@ -1,8 +1,4 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Form\ViewsTestDataElementEmbedForm.
*/
namespace Drupal\views_test_data\Form;

View file

@ -1,8 +1,4 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Form\ViewsTestDataElementForm.
*/
namespace Drupal\views_test_data\Form;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\access\StaticTest.
*/
namespace Drupal\views_test_data\Plugin\views\access;
use Drupal\Core\Session\AccountInterface;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\area\TestExample.
*/
namespace Drupal\views_test_data\Plugin\views\area;
use Drupal\Core\Form\FormStateInterface;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\argument_default\ArgumentDefaultTest.
*/
namespace Drupal\views_test_data\Plugin\views\argument_default;
use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\argument_validator\ArgumentValidatorTest.
*/
namespace Drupal\views_test_data\Plugin\views\argument_validator;
use Drupal\views\Plugin\views\argument_validator\ArgumentValidatorPluginBase;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\display\DisplayNoAreaTest.
*/
namespace Drupal\views_test_data\Plugin\views\display;
/**

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\display\DisplayTest.
*/
namespace Drupal\views_test_data\Plugin\views\display;
use Drupal\Component\Utility\Xss;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\display_extender\DisplayExtenderTest.
*/
namespace Drupal\views_test_data\Plugin\views\display_extender;
use Drupal\Core\Form\FormStateInterface;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\display_extender\DisplayExtenderTest2.
*/
namespace Drupal\views_test_data\Plugin\views\display_extender;
/**

View file

@ -0,0 +1,87 @@
<?php
namespace Drupal\views_test_data\Plugin\views\field;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\Plugin\views\field\UncacheableFieldHandlerTrait;
use Drupal\views\ResultRow;
/**
* A handler to provide a field that is completely custom by the administrator.
*
* @ingroup views_field_handlers
*
* @ViewsField("field_form_button_test")
*/
class FieldFormButtonTest extends FieldPluginBase {
use UncacheableFieldHandlerTrait;
/**
* {@inheritdoc}
*/
public function getValue(ResultRow $row, $field = NULL) {
return '<!--form-item-' . $this->options['id'] . '--' . $row->index . '-->';
}
/**
* Form constructor for the views form.
*
* @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 viewsForm(&$form, FormStateInterface $form_state) {
// Make sure we do not accidentally cache this form.
$form['#cache']['max-age'] = 0;
// The view is empty, abort.
if (empty($this->view->result)) {
unset($form['actions']);
return;
}
$form[$this->options['id']]['#tree'] = TRUE;
foreach ($this->view->result as $row_index => $row) {
$form[$this->options['id']][$row_index] = [
'#type' => 'submit',
'#value' => t('Test Button'),
'#name' => 'test-button-' . $row_index,
'#test_button' => TRUE,
'#row_index' => $row_index,
'#attributes' => ['class' => ['test-button']],
];
}
}
/**
* Submit handler for the views form.
*
* @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 viewsFormSubmit(&$form, FormStateInterface $form_state) {
$triggering_element = $form_state->getTriggeringElement();
if (!empty($triggering_element['#test_button'])) {
$row_index = $triggering_element['#row_index'];
$view_args = !empty($this->view->args) ? implode(', ', $this->view->args) : $this->t('no arguments');
drupal_set_message($this->t('The test button at row @row_index for @view_id (@display) View with args: @args was submitted.', [
'@display' => $this->view->current_display,
'@view_id' => $this->view->id(),
'@args' => $view_args,
'@row_index' => $row_index,
]));
}
}
/**
* {@inheritdoc}
*/
public function query() {
// Do nothing.
}
}

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\field\FieldTest.
*/
namespace Drupal\views_test_data\Plugin\views\field;
use Drupal\views\Plugin\views\field\FieldPluginBase;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\filter\FilterExceptionTest.
*/
namespace Drupal\views_test_data\Plugin\views\filter;
use Drupal\views\Plugin\views\filter\FilterPluginBase;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\filter\FilterTest.
*/
namespace Drupal\views_test_data\Plugin\views\filter;
use Drupal\Core\Form\FormStateInterface;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\filter\ViewsTestCacheContextFilter.
*/
namespace Drupal\views_test_data\Plugin\views\filter;
use Drupal\views\Plugin\views\filter\FilterPluginBase;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\join\JoinTest.
*/
namespace Drupal\views_test_data\Plugin\views\join;
use Drupal\views\Plugin\views\join\JoinPluginBase;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\query\QueryTest.
*/
namespace Drupal\views_test_data\Plugin\views\query;
use Drupal\Core\Form\FormStateInterface;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\row\RowTest.
*/
namespace Drupal\views_test_data\Plugin\views\row;
use Drupal\Core\Form\FormStateInterface;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\style\MappingTest.
*/
namespace Drupal\views_test_data\Plugin\views\style;
use Drupal\views\Plugin\views\style\Mapping;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\style\StyleTemplateTest.
*/
namespace Drupal\views_test_data\Plugin\views\style;
use Drupal\views\Plugin\views\style\StylePluginBase;

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_data\Plugin\views\style\StyleTest.
*/
namespace Drupal\views_test_data\Plugin\views\style;
use Drupal\Core\Form\FormStateInterface;

View file

@ -122,3 +122,10 @@ function views_test_data_test_pre_render_function($element) {
$element['#markup'] = 'views_test_data_test_pre_render_function executed';
return $element;
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*/
function views_test_data_form_views_form_test_form_multiple_default_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
drupal_set_message(t('Test base form ID with Views forms and arguments.'));
}

View file

@ -11,3 +11,11 @@ views_test_data.element_embed:
_form: '\Drupal\views_test_data\Form\ViewsTestDataElementEmbedForm'
requirements:
_access: 'TRUE'
views_test_data.form_multiple:
path: '/views_test_form_multiple'
defaults:
_title: 'Test Views Form Multiple'
_controller: '\Drupal\views_test_data\Controller\ViewsTestFormMultipleController::testPage'
requirements:
_access: 'TRUE'

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\views_test_formatter\Plugin\Field\FieldFormatter\AttachmentTestFormatter.
*/
namespace Drupal\views_test_formatter\Plugin\Field\FieldFormatter;
use Drupal\Core\Field\FieldItemListInterface;

View file

@ -0,0 +1,137 @@
<?php
namespace Drupal\Tests\views\Kernel;
use Drupal\views\Views;
/**
* A basic query test for Views.
*
* @group views
*/
class BasicTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view', 'test_simple_argument');
/**
* Tests a trivial result set.
*/
public function testSimpleResultSet() {
$view = Views::getView('test_view');
$view->setDisplay();
// Execute the view.
$this->executeView($view);
// Verify the result.
$this->assertEqual(5, count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultset($view, $this->dataSet(), array(
'views_test_data_name' => 'name',
'views_test_data_age' => 'age',
));
}
/**
* Tests filtering of the result set.
*/
public function testSimpleFiltering() {
$view = Views::getView('test_view');
$view->setDisplay();
// Add a filter.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'age' => array(
'operator' => '<',
'value' => array(
'value' => '28',
'min' => '',
'max' => '',
),
'group' => '0',
'exposed' => FALSE,
'expose' => array(
'operator' => FALSE,
'label' => '',
),
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
),
));
// Execute the view.
$this->executeView($view);
// Build the expected result.
$dataset = array(
array(
'id' => 1,
'name' => 'John',
'age' => 25,
),
array(
'id' => 2,
'name' => 'George',
'age' => 27,
),
array(
'id' => 4,
'name' => 'Paul',
'age' => 26,
),
);
// Verify the result.
$this->assertEqual(3, count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultSet($view, $dataset, array(
'views_test_data_name' => 'name',
'views_test_data_age' => 'age',
));
}
/**
* Tests simple argument.
*/
public function testSimpleArgument() {
// Execute with a view
$view = Views::getView('test_simple_argument');
$view->setArguments(array(27));
$this->executeView($view);
// Build the expected result.
$dataset = array(
array(
'id' => 2,
'name' => 'George',
'age' => 27,
),
);
// Verify the result.
$this->assertEqual(1, count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultSet($view, $dataset, array(
'views_test_data_name' => 'name',
'views_test_data_age' => 'age',
));
// Test "show all" if no argument is present.
$view = Views::getView('test_simple_argument');
$this->executeView($view);
// Build the expected result.
$dataset = $this->dataSet();
$this->assertEqual(5, count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultSet($view, $dataset, array(
'views_test_data_name' => 'name',
'views_test_data_age' => 'age',
));
}
}

View file

@ -0,0 +1,233 @@
<?php
namespace Drupal\Tests\views\Kernel\Entity;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the entity row renderers.
*
* @group views
* @see \Drupal\views\Entity\Render\RendererBase
*/
class RowEntityRenderersTest extends ViewsKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['field', 'filter', 'text', 'node', 'user', 'language', 'views_test_language'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_entity_row_renderers');
/**
* An array of added languages.
*
* @var array
*/
protected $langcodes;
/**
* An array of titles for each node per language.
*
* @var array
*/
protected $expected;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->installEntitySchema('node');
$this->installEntitySchema('user');
$this->installSchema('node', array('node_access'));
$this->installConfig(array('node', 'language'));
// The entity.node.canonical route must exist when nodes are rendered.
$this->container->get('router.builder')->rebuild();
$this->langcodes = array(\Drupal::languageManager()->getDefaultLanguage()->getId());
for ($i = 0; $i < 2; $i++) {
$langcode = 'l' . $i;
$this->langcodes[] = $langcode;
ConfigurableLanguage::createFromLangcode($langcode)->save();
}
// Make sure we do not try to render non-existing user data.
$node_type = NodeType::create(array('type' => 'test'));
$node_type->setDisplaySubmitted(FALSE);
$node_type->save();
$this->values = array();
$controller = \Drupal::entityManager()->getStorage('node');
$langcode_index = 0;
for ($i = 0; $i < count($this->langcodes); $i++) {
// Create a node with a different default language each time.
$default_langcode = $this->langcodes[$langcode_index++];
$node = $controller->create(array('type' => 'test', 'uid' => 0, 'langcode' => $default_langcode));
// Ensure the default language is processed first.
$langcodes = array_merge(array($default_langcode), array_diff($this->langcodes, array($default_langcode)));
foreach ($langcodes as $langcode) {
// Ensure we have a predictable result order.
$this->values[$i][$langcode] = $i . '-' . $langcode . '-' . $this->randomMachineName();
if ($langcode != $default_langcode) {
$node->addTranslation($langcode, array('title' => $this->values[$i][$langcode]));
}
else {
$node->setTitle($this->values[$i][$langcode]);
}
$node->save();
}
}
}
/**
* Tests the entity row renderers.
*/
public function testEntityRenderers() {
$this->checkLanguageRenderers('page_1', $this->values);
}
/**
* Tests the field row renderers.
*/
public function testFieldRenderers() {
$this->checkLanguageRenderers('page_2', $this->values);
}
/**
* Checks that the language renderer configurations work as expected.
*
* @param string $display
* Name of display to test with.
* @param array $values
* An array of node information which are each an array of node titles
* associated with language keys appropriate for the translation of that
* node.
*/
protected function checkLanguageRenderers($display, $values) {
$expected = array(
$values[0]['en'],
$values[0]['en'],
$values[0]['en'],
$values[1]['en'],
$values[1]['en'],
$values[1]['en'],
$values[2]['en'],
$values[2]['en'],
$values[2]['en'],
);
$this->assertTranslations($display, '***LANGUAGE_language_content***', $expected, 'The current language renderer behaves as expected.');
$expected = array(
$values[0]['en'],
$values[0]['en'],
$values[0]['en'],
$values[1]['l0'],
$values[1]['l0'],
$values[1]['l0'],
$values[2]['l1'],
$values[2]['l1'],
$values[2]['l1'],
);
$this->assertTranslations($display, '***LANGUAGE_entity_default***', $expected, 'The default language renderer behaves as expected.');
$expected = array(
$values[0]['en'],
$values[0]['l0'],
$values[0]['l1'],
$values[1]['en'],
$values[1]['l0'],
$values[1]['l1'],
$values[2]['en'],
$values[2]['l0'],
$values[2]['l1'],
);
$this->assertTranslations($display, '***LANGUAGE_entity_translation***', $expected, 'The translation language renderer behaves as expected.');
$expected = array(
$values[0][$this->langcodes[0]],
$values[0][$this->langcodes[0]],
$values[0][$this->langcodes[0]],
$values[1][$this->langcodes[0]],
$values[1][$this->langcodes[0]],
$values[1][$this->langcodes[0]],
$values[2][$this->langcodes[0]],
$values[2][$this->langcodes[0]],
$values[2][$this->langcodes[0]],
);
$this->assertTranslations($display, '***LANGUAGE_site_default***', $expected, 'The site default language renderer behaves as expected.');
$expected = array(
$values[0]['l0'],
$values[0]['l0'],
$values[0]['l0'],
$values[1]['l0'],
$values[1]['l0'],
$values[1]['l0'],
$values[2]['l0'],
$values[2]['l0'],
$values[2]['l0'],
);
$this->assertTranslations($display, 'l0', $expected, 'The language specific renderer behaves as expected.');
}
/**
* Checks that the view results match the expected values.
*
* @param string $display
* Name of display to test with.
* @param string $renderer_id
* The id of the renderer to be tested.
* @param array $expected
* An array of expected title translation values, one for each result row.
* @param string $message
* (optional) A message to display with the assertion.
* @param string $group
* (optional) The group this message is in.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertTranslations($display, $renderer_id, array $expected, $message = '', $group = 'Other') {
$view = Views::getView('test_entity_row_renderers');
$view->storage->invalidateCaches();
$view->setDisplay($display);
$view->getDisplay()->setOption('rendering_language', $renderer_id);
$view->preview();
$result = FALSE;
foreach ($expected as $index => $expected_output) {
if (!empty($view->result[$index])) {
$build = $view->rowPlugin->render($view->result[$index]);
$output = \Drupal::service('renderer')->renderRoot($build);
$result = strpos($output, $expected_output) !== FALSE;
if (!$result) {
break;
}
}
else {
$result = FALSE;
break;
}
}
return $this->assertTrue($result, $message, $group);
}
}

View file

@ -0,0 +1,178 @@
<?php
namespace Drupal\Tests\views\Kernel\Entity;
use Drupal\Component\Utility\Unicode;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\node\Entity\NodeType;
use Drupal\views\Tests\ViewTestData;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
use Drupal\comment\Entity\CommentType;
/**
* Tests the calculation of dependencies for views.
*
* @group views
*/
class ViewEntityDependenciesTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_field_get_entity', 'test_relationship_dependency', 'test_plugin_dependencies', 'test_argument_dependency'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'comment', 'user', 'field', 'text', 'search'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp(FALSE);
// Install the necessary dependencies for node type creation to work.
$this->installEntitySchema('node');
$this->installConfig(array('field', 'node'));
$comment_type = CommentType::create(array(
'id' => 'comment',
'label' => 'Comment settings',
'description' => 'Comment settings',
'target_entity_type_id' => 'node',
));
$comment_type->save();
$content_type = NodeType::create([
'type' => $this->randomMachineName(),
'name' => $this->randomString(),
]);
$content_type->save();
$field_storage = FieldStorageConfig::create(array(
'field_name' => Unicode::strtolower($this->randomMachineName()),
'entity_type' => 'node',
'type' => 'comment',
));
$field_storage->save();
FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => $content_type->id(),
'label' => $this->randomMachineName() . '_label',
'description' => $this->randomMachineName() . '_description',
'settings' => array(
'comment_type' => $comment_type->id(),
),
])->save();
FieldConfig::create([
'field_storage' => FieldStorageConfig::loadByName('node', 'body'),
'bundle' => $content_type->id(),
'label' => $this->randomMachineName() . '_body',
'settings' => array('display_summary' => TRUE),
])->save();
ViewTestData::createTestViews(get_class($this), array('views_test_config'));
}
/**
* Tests the getDependencies method.
*/
public function testGetDependencies() {
$expected = [];
$expected['test_field_get_entity'] = [
'module' => [
'comment',
'node',
'user',
]
];
// Tests dependencies of relationships.
$expected['test_relationship_dependency'] = [
'module' => [
'comment',
'node',
'user',
]
];
$expected['test_plugin_dependencies'] = [
'module' => [
'comment',
'views_test_data',
],
'content' => [
'RowTest',
'StaticTest',
'StyleTest',
]
];
$expected['test_argument_dependency'] = [
'config' => [
'core.entity_view_mode.node.teaser',
'field.storage.node.body'
],
'content' => [
'ArgumentDefaultTest',
'ArgumentValidatorTest'
],
'module' => [
'node',
// The argument handler is provided by the search module.
'search',
'text',
'user'
],
];
foreach ($this::$testViews as $view_id) {
$view = Views::getView($view_id);
$dependencies = $view->getDependencies();
$this->assertEqual($expected[$view_id], $dependencies);
$config = $this->config('views.view.' . $view_id);
\Drupal::service('config.storage.sync')->write($view_id, $config->get());
}
// Ensure that dependencies are calculated on the display level.
$expected_display['default'] = [
'config' => [
'core.entity_view_mode.node.teaser',
],
'content' => [
'ArgumentDefaultTest',
'ArgumentValidatorTest'
],
'module' => [
'core',
'node',
'search',
'user',
'views'
],
];
$expected_display['page'] = [
'config' => [
'field.storage.node.body'
],
'module' => [
'core',
'text',
'views'
],
];
$view = Views::getView('test_argument_dependency');
$view->initDisplay();
foreach ($view->displayHandlers as $display) {
// Calculate the dependencies each display has.
$this->assertEqual($expected_display[$display->getPluginId()], $display->calculateDependencies());
}
}
}

View file

@ -0,0 +1,459 @@
<?php
namespace Drupal\Tests\views\Kernel\EventSubscriber;
use Drupal\Core\Entity\EntityTypeEvent;
use Drupal\Core\Entity\EntityTypeEvents;
use Drupal\system\Tests\Entity\EntityDefinitionTestTrait;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
/**
* Tests \Drupal\views\EventSubscriber\ViewsEntitySchemaSubscriber
*
* @group Views
*/
class ViewsEntitySchemaSubscriberIntegrationTest extends ViewsKernelTestBase {
use EntityDefinitionTestTrait;
/**
* The entity definition update manager.
*
* @var \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface
*/
protected $entityDefinitionUpdateManager;
/**
* {@inheritdoc}
*/
public static $modules = ['entity_test', 'user', 'text'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_view_entity_test', 'test_view_entity_test_revision', 'test_view_entity_test_data', 'test_view_entity_test_additional_base_field'];
/**
* The event dispatcher.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* The tested event subscriber of views.
*
* @var \Drupal\views\EventSubscriber\ViewsEntitySchemaSubscriber
*/
protected $eventSubscriber;
/**
* The entity manager service.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
protected $entityManager;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->eventDispatcher = $this->container->get('event_dispatcher');
$this->eventSubscriber = $this->container->get('views.entity_schema_subscriber');
$this->entityDefinitionUpdateManager = $this->container->get('entity.definition_update_manager');
$this->entityManager = $this->container->get('entity.manager');
$this->state = $this->container->get('state');
$this->database = $this->container->get('database');
// Install every entity type's schema that wasn't installed in the parent
// method.
foreach (array_diff_key($this->entityManager->getDefinitions(), array_flip(array('user', 'entity_test'))) as $entity_type_id => $entity_type) {
$this->installEntitySchema($entity_type_id);
}
}
/**
* Tests that views are disabled when an entity type is deleted.
*/
public function testDeleteEntityType() {
$entity_storage = $this->entityManager->getStorage('view');
$views = $entity_storage->loadMultiple();
// Ensure that all test views exists.
$this->assertTrue(isset($views['test_view_entity_test']));
$this->assertTrue(isset($views['test_view_entity_test_revision']));
$this->assertTrue(isset($views['test_view_entity_test_data']));
$this->assertTrue(isset($views['test_view_entity_test_additional_base_field']));
$event = new EntityTypeEvent($this->entityManager->getDefinition('entity_test_update'));
$this->eventDispatcher->dispatch(EntityTypeEvents::DELETE, $event);
// We expect that views which use 'entity_test_update' as base tables are
// disabled.
$views = $entity_storage->loadMultiple();
// Ensure that all test views still exists after the deletion of the
// entity type.
$this->assertTrue(isset($views['test_view_entity_test']));
$this->assertTrue(isset($views['test_view_entity_test_revision']));
$this->assertTrue(isset($views['test_view_entity_test_data']));
$this->assertTrue(isset($views['test_view_entity_test_additional_base_field']));
// Ensure that they are all disabled.
$this->assertFalse($views['test_view_entity_test']->status());
$this->assertFalse($views['test_view_entity_test_revision']->status());
$this->assertFalse($views['test_view_entity_test_data']->status());
$this->assertFalse($views['test_view_entity_test_additional_base_field']->status());
}
/**
* Tests that renaming base tables adapts the views.
*/
public function testBaseTableRename() {
$this->renameBaseTable();
$this->entityDefinitionUpdateManager->applyUpdates();
/** @var \Drupal\views\Entity\View $view */
$entity_storage = $this->entityManager->getStorage('view');
$view = $entity_storage->load('test_view_entity_test');
// Ensure the base table got renamed, so also the views fields.
$this->assertEqual('entity_test_update_new', $view->get('base_table'));
$display = $view->getDisplay('default');
$this->assertEqual('entity_test_update_new', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_new', $display['display_options']['fields']['name']['table']);
}
/**
* Tests that renaming data tables adapts the views.
*/
public function testDataTableRename() {
$this->updateEntityTypeToTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
$entity_storage = $this->entityManager->getStorage('view');
$view = $entity_storage->load('test_view_entity_test_data');
$this->assertEqual('entity_test_update', $view->get('base_table'));
$display = $view->getDisplay('default');
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
// Ensure that the data table is used.
$this->assertEqual('entity_test_update_data', $display['display_options']['fields']['name']['table']);
$this->renameDataTable();
$this->entityDefinitionUpdateManager->applyUpdates();
/** @var \Drupal\views\Entity\View $view */
$entity_storage = $this->entityManager->getStorage('view');
$view = $entity_storage->load('test_view_entity_test_data');
// Ensure the data table got renamed, so also the views fields.
$this->assertEqual('entity_test_update', $view->get('base_table'));
$display = $view->getDisplay('default');
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_data_new', $display['display_options']['fields']['name']['table']);
}
/**
* Tests that renaming revision tables adapts the views.
*/
public function testRevisionBaseTableRename() {
$this->updateEntityTypeToRevisionable();
$this->entityDefinitionUpdateManager->applyUpdates();
/** @var \Drupal\views\Entity\View $view */
$entity_storage = $this->entityManager->getStorage('view');
$view = $entity_storage->load('test_view_entity_test_revision');
$this->assertEqual('entity_test_update_revision', $view->get('base_table'));
$display = $view->getDisplay('default');
$this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['name']['table']);
$this->renameRevisionBaseTable();
$this->entityDefinitionUpdateManager->applyUpdates();
/** @var \Drupal\views\Entity\View $view */
$entity_storage = $this->entityManager->getStorage('view');
$view = $entity_storage->load('test_view_entity_test_revision');
// Ensure the base table got renamed, so also the views fields.
$this->assertEqual('entity_test_update_revision_new', $view->get('base_table'));
$display = $view->getDisplay('default');
$this->assertEqual('entity_test_update_revision_new', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_revision_new', $display['display_options']['fields']['name']['table']);
}
/**
* Tests that renaming revision tables adapts the views.
*/
public function testRevisionDataTableRename() {
$this->updateEntityTypeToRevisionable();
// Multiple changes, so we have to invalidate the caches, otherwise
// the second update will revert the first.
$this->entityManager->clearCachedDefinitions();
$this->updateEntityTypeToTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
/** @var \Drupal\views\Entity\View $view */
$entity_storage = $this->entityManager->getStorage('view');
$view = $entity_storage->load('test_view_entity_test_revision');
$this->assertEqual('entity_test_update_revision', $view->get('base_table'));
$display = $view->getDisplay('default');
$this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_revision_data', $display['display_options']['fields']['name']['table']);
$this->renameRevisionDataTable();
$this->entityDefinitionUpdateManager->applyUpdates();
/** @var \Drupal\views\Entity\View $view */
$entity_storage = $this->entityManager->getStorage('view');
$view = $entity_storage->load('test_view_entity_test_revision');
// Ensure the base table got renamed, so also the views fields.
$this->assertEqual('entity_test_update_revision', $view->get('base_table'));
$display = $view->getDisplay('default');
$this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_revision_data_new', $display['display_options']['fields']['name']['table']);
}
/**
* Tests that adding data tables adapts the views.
*/
public function testDataTableAddition() {
$this->updateEntityTypeToTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
/** @var \Drupal\views\Entity\View $view */
$entity_storage = $this->entityManager->getStorage('view');
$view = $entity_storage->load('test_view_entity_test');
// Ensure the data table got renamed, so also the views fields.
$this->assertEqual('entity_test_update', $view->get('base_table'));
$display = $view->getDisplay('default');
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_data', $display['display_options']['fields']['name']['table']);
}
/**
* Tests that enabling revisions doesn't do anything.
*/
public function testRevisionEnabling() {
$this->updateEntityTypeToRevisionable();
$this->entityDefinitionUpdateManager->applyUpdates();
/** @var \Drupal\views\Entity\View $view */
$entity_storage = $this->entityManager->getStorage('view');
$view = $entity_storage->load('test_view_entity_test');
// Ensure that nothing happens.
$this->assertEqual('entity_test_update', $view->get('base_table'));
$display = $view->getDisplay('default');
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update', $display['display_options']['fields']['name']['table']);
}
/**
* Tests that removing revision support disables the view.
*/
public function testRevisionDisabling() {
$this->updateEntityTypeToRevisionable();
$this->entityDefinitionUpdateManager->applyUpdates();
$this->updateEntityTypeToNotRevisionable();
$this->entityDefinitionUpdateManager->applyUpdates();
/** @var \Drupal\views\Entity\View $view */
$entity_storage = $this->entityManager->getStorage('view');
$view = $entity_storage->load('test_view_entity_test_revision');
$this->assertFalse($view->status());
}
/**
* Tests a bunch possible entity definition table updates.
*/
public function testVariousTableUpdates() {
// We want to test the following permutations of entity definition updates:
// base <-> base + translation
// base + translation <-> base + translation + revision
// base + revision <-> base + translation + revision
// base <-> base + revision
// base <-> base + translation + revision
// base <-> base + translation
$this->updateEntityTypeToTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_data', $display['display_options']['fields']['name']['table']);
$this->updateEntityTypeToNotTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update', $display['display_options']['fields']['name']['table']);
$this->resetEntityType();
// base + translation <-> base + translation + revision
$this->updateEntityTypeToTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_data', $display['display_options']['fields']['name']['table']);
$this->updateEntityTypeToRevisionable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_data', $display['display_options']['fields']['name']['table']);
$this->updateEntityTypeToNotRevisionable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_data', $display['display_options']['fields']['name']['table']);
$this->resetEntityType();
// base + revision <-> base + translation + revision
$this->updateEntityTypeToRevisionable();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update', $display['display_options']['fields']['name']['table']);
$this->updateEntityTypeToTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_data', $display['display_options']['fields']['name']['table']);
$this->updateEntityTypeToNotTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update', $display['display_options']['fields']['name']['table']);
$this->resetEntityType();
// base <-> base + revision
$this->updateEntityTypeToRevisionable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update', $display['display_options']['fields']['name']['table']);
$this->updateEntityTypeToNotRevisionable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update', $display['display_options']['fields']['name']['table']);
$this->resetEntityType();
// base <-> base + translation + revision
$this->updateEntityTypeToRevisionable();
$this->updateEntityTypeToTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_data', $display['display_options']['fields']['name']['table']);
$this->updateEntityTypeToNotRevisionable();
$this->updateEntityTypeToNotTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay();
$this->assertEqual('entity_test_update', $view->get('base_table'));
$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update', $display['display_options']['fields']['name']['table']);
}
/**
* Tests some possible entity table updates for a revision view.
*/
public function testVariousTableUpdatesForRevisionView() {
// base + revision <-> base + translation + revision
$this->updateEntityTypeToRevisionable();
// Multiple changes, so we have to invalidate the caches, otherwise
// the second update will revert the first.
$this->entityManager->clearCachedDefinitions();
list($view, $display) = $this->getUpdatedViewAndDisplay(TRUE);
$this->assertEqual('entity_test_update_revision', $view->get('base_table'));
$this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['name']['table']);
$this->updateEntityTypeToTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay(TRUE);
$this->assertEqual('entity_test_update_revision', $view->get('base_table'));
$this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_revision_data', $display['display_options']['fields']['name']['table']);
$this->updateEntityTypeToNotTranslatable();
$this->entityDefinitionUpdateManager->applyUpdates();
list($view, $display) = $this->getUpdatedViewAndDisplay(TRUE);
$this->assertEqual('entity_test_update_revision', $view->get('base_table'));
$this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['id']['table']);
$this->assertEqual('entity_test_update_revision', $display['display_options']['fields']['name']['table']);
$this->resetEntityType();
}
/**
* Gets a view and its display.
*
* @param bool $revision
* (optional) TRUE if we want to get a revision view.
*
* @return array
* An array with the view as first item, and the display as second.
*/
protected function getUpdatedViewAndDisplay($revision = FALSE) {
$entity_storage = $this->entityManager->getStorage('view');
/** @var \Drupal\views\Entity\View $view */
$view = $entity_storage->load($revision ? 'test_view_entity_test_revision' : 'test_view_entity_test');
$display = $view->getDisplay('default');
return [$view, $display];
}
}

View file

@ -0,0 +1,197 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\block\Entity\Block;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormState;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Entity\View;
use Drupal\views\Views;
/**
* Tests the generic entity area handler.
*
* @group views
* @see \Drupal\views\Plugin\views\area\Entity
*/
class AreaEntityTest extends ViewsKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['entity_test', 'user', 'block'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_entity_area');
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp();
}
/**
* {@inheritdoc}
*/
protected function setUpFixtures() {
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test');
$this->installConfig(['entity_test']);
Block::create([
'id' => 'test_block',
'plugin' => 'system_main_block',
])->save();
parent::setUpFixtures();
}
/**
* Tests views data for entity area handlers.
*/
public function testEntityAreaData() {
$data = $this->container->get('views.views_data')->get('views');
$entity_types = $this->container->get('entity.manager')->getDefinitions();
$expected_entities = array_filter($entity_types, function (EntityTypeInterface $entity_type) {
return $entity_type->hasViewBuilderClass();
});
// Test that all expected entity types have data.
foreach (array_keys($expected_entities) as $entity) {
$this->assertTrue(!empty($data['entity_' . $entity]), format_string('Views entity area data found for @entity', array('@entity' => $entity)));
// Test that entity_type is set correctly in the area data.
$this->assertEqual($entity, $data['entity_' . $entity]['area']['entity_type'], format_string('Correct entity_type set for @entity', array('@entity' => $entity)));
}
$expected_entities = array_filter($entity_types, function (EntityTypeInterface $type) {
return !$type->hasViewBuilderClass();
});
// Test that no configuration entity types have data.
foreach (array_keys($expected_entities) as $entity) {
$this->assertTrue(empty($data['entity_' . $entity]), format_string('Views config entity area data not found for @entity', array('@entity' => $entity)));
}
}
/**
* Tests the area handler.
*/
public function testEntityArea() {
/** @var \Drupal\Core\Entity\EntityInterface[] $entities */
$entities = array();
for ($i = 0; $i < 3; $i++) {
$random_label = $this->randomMachineName();
$data = array('bundle' => 'entity_test', 'name' => $random_label);
$entity_test = $this->container->get('entity.manager')
->getStorage('entity_test')
->create($data);
$uuid_map[0] = 'aa0c61cb-b7bb-4795-972a-493dabcf529c';
$uuid_map[1] = '62cef0ff-6f30-4f7a-b9d6-a8ed5a3a6bf3';
$uuid_map[2] = '3161d6e9-3326-4719-b513-8fa68a731ba2';
$entity_test->uuid->value = $uuid_map[$i];
$entity_test->save();
$entities[] = $entity_test;
\Drupal::state()
->set('entity_test_entity_access.view.' . $entity_test->id(), $i != 2);
}
$this->doTestCalculateDependencies();
$this->doTestRender($entities);
}
/**
* Tests rendering the entity area handler.
*
* @param \Drupal\Core\Entity\EntityInterface[] $entities
* The entities.
*/
public function doTestRender($entities) {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$view = Views::getView('test_entity_area');
$preview = $view->preview('default', [$entities[1]->id()]);
$this->setRawContent(\Drupal::service('renderer')->renderRoot($preview));
$view_class = 'js-view-dom-id-' . $view->dom_id;
$header_xpath = '//div[@class = "' . $view_class . '"]/header[1]';
$footer_xpath = '//div[@class = "' . $view_class . '"]/footer[1]';
$result = $this->xpath($header_xpath);
$this->assertTrue(strpos(trim((string) $result[0]), $entities[0]->label()) !== FALSE, 'The rendered entity appears in the header of the view.');
$this->assertTrue(strpos(trim((string) $result[0]), 'full') !== FALSE, 'The rendered entity appeared in the right view mode.');
$result = $this->xpath($footer_xpath);
$this->assertTrue(strpos(trim((string) $result[0]), $entities[1]->label()) !== FALSE, 'The rendered entity appears in the footer of the view.');
$this->assertTrue(strpos(trim((string) $result[0]), 'full') !== FALSE, 'The rendered entity appeared in the right view mode.');
$preview = $view->preview('default', array($entities[1]->id()));
$this->setRawContent($renderer->renderRoot($preview));
$result = $this->xpath($header_xpath);
$this->assertTrue(strpos(trim((string) $result[0]), $entities[0]->label()) !== FALSE, 'The rendered entity appears in the header of the view.');
$this->assertTrue(strpos(trim((string) $result[0]), 'full') !== FALSE, 'The rendered entity appeared in the right view mode.');
$result = $this->xpath($footer_xpath);
$this->assertTrue(strpos(trim((string) $result[0]), $entities[1]->label()) !== FALSE, 'The rendered entity appears in the footer of the view.');
$this->assertTrue(strpos(trim((string) $result[0]), 'full') !== FALSE, 'The rendered entity appeared in the right view mode.');
// Mark entity_test test view_mode as customizable.
$entity_view_mode = \Drupal::entityManager()->getStorage('entity_view_mode')->load('entity_test.test');
$entity_view_mode->enable();
$entity_view_mode->save();
// Change the view mode of the area handler.
$view = Views::getView('test_entity_area');
$item = $view->getHandler('default', 'header', 'entity_entity_test');
$item['view_mode'] = 'test';
$view->setHandler('default', 'header', 'entity_entity_test', $item);
$preview = $view->preview('default', array($entities[1]->id()));
$this->setRawContent($renderer->renderRoot($preview));
$view_class = 'js-view-dom-id-' . $view->dom_id;
$result = $this->xpath('//div[@class = "' . $view_class . '"]/header[1]');
$this->assertTrue(strpos(trim((string) $result[0]), $entities[0]->label()) !== FALSE, 'The rendered entity appears in the header of the view.');
$this->assertTrue(strpos(trim((string) $result[0]), 'test') !== FALSE, 'The rendered entity appeared in the right view mode.');
// Test entity access.
$view = Views::getView('test_entity_area');
$preview = $view->preview('default', array($entities[2]->id()));
$this->setRawContent($renderer->renderRoot($preview));
$view_class = 'js-view-dom-id-' . $view->dom_id;
$result = $this->xpath('//div[@class = "' . $view_class . '"]/footer[1]');
$this->assertTrue(strpos($result[0], $entities[2]->label()) === FALSE, 'The rendered entity does not appear in the footer of the view.');
// Test the available view mode options.
$form = array();
$form_state = (new FormState())
->set('type', 'header');
$view->display_handler->getHandler('header', 'entity_entity_test')->buildOptionsForm($form, $form_state);
$this->assertTrue(isset($form['view_mode']['#options']['test']), 'Ensure that the test view mode is available.');
$this->assertTrue(isset($form['view_mode']['#options']['default']), 'Ensure that the default view mode is available.');
}
/**
* Tests the calculation of the rendered dependencies.
*/
public function doTestCalculateDependencies() {
$view = View::load('test_entity_area');
$dependencies = $view->calculateDependencies()->getDependencies();
// Ensure that both config and content entity dependencies are calculated.
$this->assertEqual([
'config' => ['block.block.test_block'],
'content' => ['entity_test:entity_test:aa0c61cb-b7bb-4795-972a-493dabcf529c'],
], $dependencies);
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the messages area handler.
*
* @group views
* @see \Drupal\views\Plugin\views\area\Messages
*/
class AreaMessagesTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_area_messages');
/**
* Tests the messages area handler.
*/
public function testMessageText() {
drupal_set_message('My drupal set message.');
$view = Views::getView('test_area_messages');
$view->setDisplay('default');
$this->executeView($view);
$output = $view->render();
$output = \Drupal::service('renderer')->renderRoot($output);
$this->setRawContent($output);
$this->assertText('My drupal set message.');
}
}

View file

@ -0,0 +1,70 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core views_handler_area_text handler.
*
* @group views
* @see \Drupal\views\Plugin\views\area\Text
*/
class AreaTextTest extends ViewsKernelTestBase {
public static $modules = array('system', 'user', 'filter');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->installConfig(array('system', 'filter'));
$this->installEntitySchema('user');
}
public function testAreaText() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$view = Views::getView('test_view');
$view->setDisplay();
// add a text header
$string = $this->randomMachineName();
$view->displayHandlers->get('default')->overrideOption('header', array(
'area' => array(
'id' => 'area',
'table' => 'views',
'field' => 'area',
'content' => array(
'value' => $string,
),
),
));
// Execute the view.
$this->executeView($view);
$view->display_handler->handlers['header']['area']->options['content']['format'] = $this->randomString();
$build = $view->display_handler->handlers['header']['area']->render();
$this->assertEqual('', $renderer->renderRoot($build), 'Nonexistent format should return empty markup.');
$view->display_handler->handlers['header']['area']->options['content']['format'] = filter_default_format();
$build = $view->display_handler->handlers['header']['area']->render();
$this->assertEqual(check_markup($string), $renderer->renderRoot($build), 'Existent format should return something');
// Empty results, and it shouldn't be displayed .
$this->assertEqual(array(), $view->display_handler->handlers['header']['area']->render(TRUE), 'No result should lead to no header');
// Empty results, and it should be displayed.
$view->display_handler->handlers['header']['area']->options['empty'] = TRUE;
$build = $view->display_handler->handlers['header']['area']->render(TRUE);
$this->assertEqual(check_markup($string), $renderer->renderRoot($build), 'No result, but empty enabled lead to a full header');
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the title area handler.
*
* @group views
* @see \Drupal\views\Plugin\views\area\Title
*/
class AreaTitleTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_area_title');
/**
* Tests the title area handler.
*/
public function testTitleText() {
$view = Views::getView('test_area_title');
$view->setDisplay('default');
$this->executeView($view);
$view->render();
$this->assertFalse($view->getTitle(), 'The title area does not override the title if the view is not empty.');
$view->destroy();
$view->setDisplay('default');
$this->executeView($view);
$view->result = array();
$view->render();
$this->assertEqual($view->getTitle(), 'test_title_empty', 'The title area should override the title if the result is empty.');
$view->destroy();
$view->setDisplay('page_1');
$this->executeView($view);
$view->render();
$this->assertEqual($view->getTitle(), 'test_title_header', 'The title area on the header should override the title if the result is not empty.');
$view->destroy();
$view->setDisplay('page_1');
$this->executeView($view);
$view->result = array();
$view->render();
$this->assertEqual($view->getTitle(), 'test_title_empty', 'The title area should override the title if the result is empty.');
$view->destroy();
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the view area handler.
*
* @group views
* @see \Drupal\views\Plugin\views\area\View
*/
class AreaViewTest extends ViewsKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('user');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_simple_argument', 'test_area_view');
/**
* Tests the view area handler.
*/
public function testViewArea() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$view = Views::getView('test_area_view');
// Tests \Drupal\views\Plugin\views\area\View::calculateDependencies().
$this->assertIdentical(['config' => ['views.view.test_simple_argument']], $view->getDependencies());
$this->executeView($view);
$output = $view->render();
$output = $renderer->renderRoot($output);
$this->assertTrue(strpos($output, 'js-view-dom-id-' . $view->dom_id) !== FALSE, 'The test view is correctly embedded.');
$view->destroy();
$view->setArguments(array(27));
$this->executeView($view);
$output = $view->render();
$output = $renderer->renderRoot($output);
$this->assertTrue(strpos($output, 'John') === FALSE, 'The test view is correctly embedded with inherited arguments.');
$this->assertTrue(strpos($output, 'George') !== FALSE, 'The test view is correctly embedded with inherited arguments.');
$view->destroy();
}
}

View file

@ -0,0 +1,318 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core date argument handlers.
*
* @group views
* @see \Drupal\views\Plugin\views\argument\Date
*/
class ArgumentDateTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_argument_date');
/**
* Stores the column map for this testCase.
*
* @var array
*/
protected $columnMap = array(
'id' => 'id',
);
/**
* {@inheritdoc}
*/
public function viewsData() {
$data = parent::viewsData();
$date_plugins = array(
'date_fulldate',
'date_day',
'date_month',
'date_week',
'date_year',
'date_year_month',
);
foreach ($date_plugins as $plugin_id) {
$data['views_test_data'][$plugin_id] = $data['views_test_data']['created'];
$data['views_test_data'][$plugin_id]['real field'] = 'created';
$data['views_test_data'][$plugin_id]['argument']['id'] = $plugin_id;
}
return $data;
}
/**
* Tests the CreatedFullDate handler.
*
* @see \Drupal\node\Plugin\views\argument\CreatedFullDate
*/
public function testCreatedFullDateHandler() {
$view = Views::getView('test_argument_date');
$view->setDisplay('default');
$this->executeView($view, array('20000102'));
$expected = array();
$expected[] = array('id' => 2);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('default');
$this->executeView($view, array('20000101'));
$expected = array();
$expected[] = array('id' => 1);
$expected[] = array('id' => 3);
$expected[] = array('id' => 4);
$expected[] = array('id' => 5);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('default');
$this->executeView($view, array('20001023'));
$expected = array();
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
}
/**
* Tests the Day handler.
*
* @see \Drupal\node\Plugin\views\argument\CreatedDay
*/
public function testDayHandler() {
$view = Views::getView('test_argument_date');
$view->setDisplay('embed_1');
$this->executeView($view, array('02'));
$expected = array();
$expected[] = array('id' => 2);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_1');
$this->executeView($view, array('01'));
$expected = array();
$expected[] = array('id' => 1);
$expected[] = array('id' => 3);
$expected[] = array('id' => 4);
$expected[] = array('id' => 5);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_1');
$this->executeView($view, array('23'));
$expected = array();
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
}
/**
* Tests the Month handler.
*
* @see \Drupal\node\Plugin\views\argument\CreatedMonth
*/
public function testMonthHandler() {
$view = Views::getView('test_argument_date');
$view->setDisplay('embed_2');
$this->executeView($view, array('01'));
$expected = array();
$expected[] = array('id' => 1);
$expected[] = array('id' => 2);
$expected[] = array('id' => 3);
$expected[] = array('id' => 4);
$expected[] = array('id' => 5);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_2');
$this->executeView($view, array('12'));
$expected = array();
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
}
/**
* Tests the Week handler.
*
* @see \Drupal\node\Plugin\views\argument\CreatedWeek
*/
public function testWeekHandler() {
$this->container->get('database')->update('views_test_data')
->fields(array('created' => gmmktime(0, 0, 0, 9, 26, 2008)))
->condition('id', 1)
->execute();
$this->container->get('database')->update('views_test_data')
->fields(array('created' => gmmktime(0, 0, 0, 2, 29, 2004)))
->condition('id', 2)
->execute();
$this->container->get('database')->update('views_test_data')
->fields(array('created' => gmmktime(0, 0, 0, 1, 1, 2000)))
->condition('id', 3)
->execute();
$this->container->get('database')->update('views_test_data')
->fields(array('created' => gmmktime(0, 0, 0, 1, 10, 2000)))
->condition('id', 4)
->execute();
$this->container->get('database')->update('views_test_data')
->fields(array('created' => gmmktime(0, 0, 0, 2, 1, 2000)))
->condition('id', 5)
->execute();
$view = Views::getView('test_argument_date');
$view->setDisplay('embed_3');
// Check the week calculation for a leap year.
// @see http://wikipedia.org/wiki/ISO_week_date#Calculation
$this->executeView($view, array('39'));
$expected = array();
$expected[] = array('id' => 1);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_3');
// Check the week calculation for the 29th of February in a leap year.
// @see http://wikipedia.org/wiki/ISO_week_date#Calculation
$this->executeView($view, array('09'));
$expected = array();
$expected[] = array('id' => 2);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_3');
// The first jan 2000 was still in the last week of the previous year.
$this->executeView($view, array('52'));
$expected = array();
$expected[] = array('id' => 3);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_3');
$this->executeView($view, array('02'));
$expected = array();
$expected[] = array('id' => 4);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_3');
$this->executeView($view, array('05'));
$expected = array();
$expected[] = array('id' => 5);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_3');
$this->executeView($view, array('23'));
$expected = array();
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
}
/**
* Tests the Year handler.
*
* @see \Drupal\node\Plugin\views\argument\CreatedYear
*/
public function testYearHandler() {
$this->container->get('database')->update('views_test_data')
->fields(array('created' => gmmktime(0, 0, 0, 1, 1, 2001)))
->condition('id', 3)
->execute();
$this->container->get('database')->update('views_test_data')
->fields(array('created' => gmmktime(0, 0, 0, 1, 1, 2002)))
->condition('id', 4)
->execute();
$this->container->get('database')->update('views_test_data')
->fields(array('created' => gmmktime(0, 0, 0, 1, 1, 2002)))
->condition('id', 5)
->execute();
$view = Views::getView('test_argument_date');
$view->setDisplay('embed_4');
$this->executeView($view, array('2000'));
$expected = array();
$expected[] = array('id' => 1);
$expected[] = array('id' => 2);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_4');
$this->executeView($view, array('2001'));
$expected = array();
$expected[] = array('id' => 3);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_4');
$this->executeView($view, array('2002'));
$expected = array();
$expected[] = array('id' => 4);
$expected[] = array('id' => 5);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_4');
$this->executeView($view, array('23'));
$expected = array();
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
}
/**
* Tests the YearMonth handler.
*
* @see \Drupal\node\Plugin\views\argument\CreatedYearMonth
*/
public function testYearMonthHandler() {
$this->container->get('database')->update('views_test_data')
->fields(array('created' => gmmktime(0, 0, 0, 1, 1, 2001)))
->condition('id', 3)
->execute();
$this->container->get('database')->update('views_test_data')
->fields(array('created' => gmmktime(0, 0, 0, 4, 1, 2001)))
->condition('id', 4)
->execute();
$this->container->get('database')->update('views_test_data')
->fields(array('created' => gmmktime(0, 0, 0, 4, 1, 2001)))
->condition('id', 5)
->execute();
$view = Views::getView('test_argument_date');
$view->setDisplay('embed_5');
$this->executeView($view, array('200001'));
$expected = array();
$expected[] = array('id' => 1);
$expected[] = array('id' => 2);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_5');
$this->executeView($view, array('200101'));
$expected = array();
$expected[] = array('id' => 3);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_5');
$this->executeView($view, array('200104'));
$expected = array();
$expected[] = array('id' => 4);
$expected[] = array('id' => 5);
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
$view->destroy();
$view->setDisplay('embed_5');
$this->executeView($view, array('201301'));
$expected = array();
$this->assertIdenticalResultset($view, $expected, $this->columnMap);
}
}

View file

@ -0,0 +1,74 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\argument\NullArgument handler.
*
* @group views
*/
class ArgumentNullTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['id']['argument']['id'] = 'null';
return $data;
}
public function testAreaText() {
// Test validation
$view = Views::getView('test_view');
$view->setDisplay();
// Add a null argument.
$view->displayHandlers->get('default')->overrideOption('arguments', array(
'null' => array(
'id' => 'null',
'table' => 'views',
'field' => 'null',
),
));
$this->executeView($view);
// Make sure that the argument is not validated yet.
unset($view->argument['null']->argument_validated);
$this->assertTrue($view->argument['null']->validateArgument(26));
// test must_not_be option.
unset($view->argument['null']->argument_validated);
$view->argument['null']->options['must_not_be'] = TRUE;
$this->assertFalse($view->argument['null']->validateArgument(26), 'must_not_be returns FALSE, if there is an argument');
unset($view->argument['null']->argument_validated);
$this->assertTrue($view->argument['null']->validateArgument(NULL), 'must_not_be returns TRUE, if there is no argument');
// Test execution.
$view->destroy();
$view->setDisplay();
// Add a argument, which has null as handler.
$view->displayHandlers->get('default')->overrideOption('arguments', array(
'id' => array(
'id' => 'id',
'table' => 'views_test_data',
'field' => 'id',
),
));
$this->executeView($view, array(26));
// The argument should be ignored, so every result should return.
$this->assertEqual(5, count($view->result));
}
}

View file

@ -0,0 +1,40 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\entity_test\Entity\EntityTest;
/**
* Tests base field access in Views for the entity_test entity.
*
* @group entity_test
*/
class EntityTestViewsFieldAccessTest extends FieldFieldAccessTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['entity_test'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->installEntitySchema('entity_test');
}
public function testEntityTestFields() {
$entity_test = EntityTest::create([
'name' => 'test entity name',
]);
$entity_test->save();
// @todo Expand the test coverage in https://www.drupal.org/node/2464635
$this->assertFieldAccess('entity_test', 'id', $entity_test->id());
$this->assertFieldAccess('entity_test', 'langcode', $entity_test->language()->getName());
$this->assertFieldAccess('entity_test', 'name', $entity_test->getName());
}
}

View file

@ -0,0 +1,79 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\field\Boolean handler.
*
* @group views
*/
class FieldBooleanTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
function dataSet() {
// Use default dataset but remove the age from john and paul
$data = parent::dataSet();
$data[0]['age'] = 0;
$data[3]['age'] = 0;
return $data;
}
function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['age']['field']['id'] = 'boolean';
return $data;
}
public function testFieldBoolean() {
$view = Views::getView('test_view');
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('fields', array(
'age' => array(
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
),
));
$this->executeView($view);
// This is john, which has no age, there are no custom formats defined, yet.
$this->assertEqual(t('No'), $view->field['age']->advancedRender($view->result[0]));
$this->assertEqual(t('Yes'), $view->field['age']->advancedRender($view->result[1]));
// Reverse the output.
$view->field['age']->options['not'] = TRUE;
$this->assertEqual(t('Yes'), $view->field['age']->advancedRender($view->result[0]));
$this->assertEqual(t('No'), $view->field['age']->advancedRender($view->result[1]));
unset($view->field['age']->options['not']);
// Use another output format.
$view->field['age']->options['type'] = 'true-false';
$this->assertEqual(t('False'), $view->field['age']->advancedRender($view->result[0]));
$this->assertEqual(t('True'), $view->field['age']->advancedRender($view->result[1]));
// test awesome unicode.
$view->field['age']->options['type'] = 'unicode-yes-no';
$this->assertEqual('✖', $view->field['age']->advancedRender($view->result[0]));
$this->assertEqual('✔', $view->field['age']->advancedRender($view->result[1]));
// Set a custom output format.
$view->field['age']->formats['test'] = array(t('Test-True'), t('Test-False'));
$view->field['age']->options['type'] = 'test';
$this->assertEqual(t('Test-False'), $view->field['age']->advancedRender($view->result[0]));
$this->assertEqual(t('Test-True'), $view->field['age']->advancedRender($view->result[1]));
}
}

View file

@ -0,0 +1,91 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the Drupal\views\Plugin\views\field\Counter handler.
*
* @group views
*/
class FieldCounterTest extends ViewsKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('user');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
function testSimple() {
$view = Views::getView('test_view');
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('fields', array(
'counter' => array(
'id' => 'counter',
'table' => 'views',
'field' => 'counter',
'relationship' => 'none',
),
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
),
));
$view->preview();
$counter = $view->style_plugin->getField(0, 'counter');
$this->assertEqual($counter, '1', format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 1, '@counter' => $counter)));
$counter = $view->style_plugin->getField(1, 'counter');
$this->assertEqual($counter, '2', format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 2, '@counter' => $counter)));
$counter = $view->style_plugin->getField(2, 'counter');
$this->assertEqual($counter, '3', format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => 3, '@counter' => $counter)));
$view->destroy();
$view->storage->invalidateCaches();
$view->setDisplay();
$rand_start = rand(5, 10);
$view->displayHandlers->get('default')->overrideOption('fields', array(
'counter' => array(
'id' => 'counter',
'table' => 'views',
'field' => 'counter',
'relationship' => 'none',
'counter_start' => $rand_start
),
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
),
));
$view->preview();
$counter = $view->style_plugin->getField(0, 'counter');
$expected_number = 0 + $rand_start;
$this->assertEqual($counter, (string) $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
$counter = $view->style_plugin->getField(1, 'counter');
$expected_number = 1 + $rand_start;
$this->assertEqual($counter, (string) $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
$counter = $view->style_plugin->getField(2, 'counter');
$expected_number = 2 + $rand_start;
$this->assertEqual($counter, (string) $expected_number, format_string('Make sure the expected number (@expected) patches with the rendered number (@counter)', array('@expected' => $expected_number, '@counter' => $counter)));
}
// @TODO: Write tests for pager.
function testPager() {
}
}

View file

@ -0,0 +1,116 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Component\Utility\Xss;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\field\Custom handler.
*
* @group views
*/
class FieldCustomTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* {@inheritdoc}
*/
function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['name']['field']['id'] = 'custom';
return $data;
}
/**
* Ensure that custom fields work and doesn't escape unnecessary markup.
*/
public function testFieldCustom() {
$view = Views::getView('test_view');
$view->setDisplay();
// Alter the text of the field to a random string.
$random = '<div>' . $this->randomMachineName() . '</div>';
$view->displayHandlers->get('default')->overrideOption('fields', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'alter' => array(
'text' => $random,
),
),
));
$this->executeView($view);
$this->assertEqual($random, $view->style_plugin->getField(0, 'name'));
}
/**
* Ensure that custom fields can use tokens.
*/
public function testFieldCustomTokens() {
$view = Views::getView('test_view');
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('fields', [
'age' => [
'id' => 'age',
'exclude' => TRUE,
'table' => 'views_test_data',
'field' => 'age',
],
'name' => [
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'alter' => [
'text' => 'Amount of kittens: {{ age }}',
],
],
]);
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$preview = $view->preview();
$output = $renderer->renderRoot($preview);
$expected_text = 'Amount of kittens: ' . $view->style_plugin->getField(0, 'age');
$this->assertTrue(strpos((string) $output, $expected_text), 'The views token has been successfully replaced.');
}
/**
* Ensure that custom field content is XSS filtered.
*/
public function testCustomFieldXss() {
$view = Views::getView('test_view');
$view->setDisplay();
// Alter the text of the field to include XSS.
$text = '<script>alert("kittens")</script>';
$view->displayHandlers->get('default')->overrideOption('fields', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'alter' => array(
'text' => $text,
),
),
));
$this->executeView($view);
$this->assertEqual(Xss::filter($text), $view->style_plugin->getField(0, 'name'));
}
}

View file

@ -0,0 +1,193 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\field\Date handler.
*
* @group views
*/
class FieldDateTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* {@inheritdoc}
*/
public function schemaDefinition() {
$schema = parent::schemaDefinition();
$schema['views_test_data']['fields']['destroyed'] = array(
'description' => "The destruction date of this record",
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
'default' => 0,
);
return $schema;
}
/**
* {@inheritdoc}
*/
public function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['created']['field']['id'] = 'date';
$data['views_test_data']['destroyed'] = array(
'title' => 'Destroyed',
'help' => 'Date in future this will be destroyed.',
'field' => array('id' => 'date'),
'argument' => array('id' => 'date'),
'filter' => array('id' => 'date'),
'sort' => array('id' => 'date'),
);
return $data;
}
/**
* {@inheritdoc}
*/
public function dataSet() {
$datas = parent::dataSet();
foreach ($datas as $i => $data) {
$datas[$i]['destroyed'] = gmmktime(0, 0, 0, 1, 1, 2050);
}
return $datas;
}
/**
* Sets up functional test of the views date field.
*/
public function testFieldDate() {
$view = Views::getView('test_view');
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('fields', array(
'created' => array(
'id' => 'created',
'table' => 'views_test_data',
'field' => 'created',
'relationship' => 'none',
// ISO 8601 format, see http://php.net/manual/function.date.php
'custom_date_format' => 'c',
),
'destroyed' => array(
'id' => 'destroyed',
'table' => 'views_test_data',
'field' => 'destroyed',
'relationship' => 'none',
'custom_date_format' => 'c',
),
));
$time = gmmktime(0, 0, 0, 1, 1, 2000);
$this->executeView($view);
$timezones = array(
NULL,
'UTC',
'America/New_York',
);
// Check each date/time in various timezones.
foreach ($timezones as $timezone) {
$dates = array(
'short' => format_date($time, 'short', '', $timezone),
'medium' => format_date($time, 'medium', '', $timezone),
'long' => format_date($time, 'long', '', $timezone),
'custom' => format_date($time, 'custom', 'c', $timezone),
'fallback' => format_date($time, 'fallback', '', $timezone),
'html_date' => format_date($time, 'html_date', '', $timezone),
'html_datetime' => format_date($time, 'html_datetime', '', $timezone),
'html_month' => format_date($time, 'html_month', '', $timezone),
'html_time' => format_date($time, 'html_time', '', $timezone),
'html_week' => format_date($time, 'html_week', '', $timezone),
'html_year' => format_date($time, 'html_year', '', $timezone),
'html_yearless_date' => format_date($time, 'html_yearless_date', '', $timezone),
);
$this->assertRenderedDatesEqual($view, $dates, $timezone);
}
// Check times in the past.
$time_since = $this->container->get('date.formatter')->formatTimeDiffSince($time);
$intervals = array(
'raw time ago' => $time_since,
'time ago' => t('%time ago', array('%time' => $time_since)),
'raw time span' => $time_since,
'inverse time span' => "-$time_since",
'time span' => t('%time ago', array('%time' => $time_since)),
);
$this->assertRenderedDatesEqual($view, $intervals);
// Check times in the future.
$time = gmmktime(0, 0, 0, 1, 1, 2050);
$formatted = $this->container->get('date.formatter')->formatTimeDiffUntil($time);
$intervals = array(
'raw time span' => "-$formatted",
'time span' => t('%time hence', array(
'%time' => $formatted,
)),
);
$this->assertRenderedFutureDatesEqual($view, $intervals);
}
/**
* Asserts properly formatted display against 'created' field in view.
*
* @param mixed $view
* View to be tested.
* @param array $map
* Data map.
* @param null $timezone
* Optional timezone.
*/
protected function assertRenderedDatesEqual($view, $map, $timezone = NULL) {
foreach ($map as $date_format => $expected_result) {
$view->field['created']->options['date_format'] = $date_format;
$t_args = array(
'%value' => $expected_result,
'%format' => $date_format,
);
if (isset($timezone)) {
$t_args['%timezone'] = $timezone;
$message = t('Value %value in %format format for timezone %timezone matches.', $t_args);
$view->field['created']->options['timezone'] = $timezone;
}
else {
$message = t('Value %value in %format format matches.', $t_args);
}
$actual_result = $view->field['created']->advancedRender($view->result[0]);
$this->assertEqual($expected_result, $actual_result, $message);
}
}
/**
* Asserts properly formatted display against 'destroyed' field in view.
*
* @param mixed $view
* View to be tested.
* @param array $map
* Data map.
*/
protected function assertRenderedFutureDatesEqual($view, $map) {
foreach ($map as $format => $result) {
$view->field['destroyed']->options['date_format'] = $format;
$view_result = $view->field['destroyed']->advancedRender($view->result[0]);
$t_args = array(
'%value' => $result,
'%format' => $format,
'%actual' => $view_result,
);
$message = t('Value %value in %format matches %actual', $t_args);
$this->assertEqual($view_result, $result, $message);
}
}
}

View file

@ -0,0 +1,126 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Core\Session\AccountInterface;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\simpletest\UserCreationTrait;
use Drupal\user\Entity\Role;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\field\EntityOperations handler.
*
* @group views
*/
class FieldEntityLinkTest extends ViewsKernelTestBase {
use UserCreationTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_entity_test_link');
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('user', 'entity_test');
/**
* An admin user account.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* {@inheritdoc}
*/
protected function setUpFixtures() {
parent::setUpFixtures();
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test');
$this->installConfig(['user']);
// Create some test entities.
for ($i = 0; $i < 5; $i++) {
EntityTest::create(['name' => $this->randomString()])->save();
}
// Create and admin user.
$this->adminUser = $this->createUser(['view test entity'], FALSE, TRUE);
Role::load(AccountInterface::ANONYMOUS_ROLE)
->grantPermission('view test entity')
->save();
}
/**
* Tests entity link fields.
*/
public function testEntityLink() {
// Anonymous users cannot see edit/delete links.
$expected_results = ['canonical' => TRUE, 'edit-form' => FALSE, 'delete-form' => FALSE];
$this->doTestEntityLink(\Drupal::currentUser(), $expected_results);
// Admin users cannot see all links.
$expected_results = ['canonical' => TRUE, 'edit-form' => TRUE, 'delete-form' => TRUE];
$this->doTestEntityLink($this->adminUser, $expected_results);
}
/**
* Tests whether entity links behave as expected.
*
* @param \Drupal\Core\Session\AccountInterface $account
* The user account to be used to run the test;
* @param bool[] $expected_results
* An associative array of expected results keyed by link template name.
*/
protected function doTestEntityLink(AccountInterface $account, $expected_results) {
\Drupal::currentUser()->setAccount($account);
$view = Views::getView('test_entity_test_link');
$view->preview();
$info = [
'canonical' => [
'label' => 'View entity test',
'field_id' => 'view_entity_test',
'destination' => FALSE,
],
'edit-form' => [
'label' => 'Edit entity test',
'field_id' => 'edit_entity_test',
'destination' => TRUE,
],
'delete-form' => [
'label' => 'Delete entity test',
'field_id' => 'delete_entity_test',
'destination' => TRUE,
],
];
$index = 0;
foreach (EntityTest::loadMultiple() as $entity) {
foreach ($expected_results as $template => $expected_result) {
$expected_link = '';
if ($expected_result) {
$path = $entity->url($template);
$destination = $info[$template]['destination'] ? '?destination=/' : '';
$expected_link = '<a href="' . $path . $destination . '" hreflang="en">' . $info[$template]['label'] . '</a>';
}
$link = $view->style_plugin->getField($index, $info[$template]['field_id']);
$this->assertEqual($link, $expected_link);
}
$index++;
}
}
}

View file

@ -0,0 +1,139 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Drupal\views\Entity\View;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Provides a base class for base field access in views.
*/
abstract class FieldFieldAccessTestBase extends ViewsKernelTestBase {
/**
* Stores an user entity with access to fields.
*
* @var \Drupal\user\UserInterface
*/
protected $userWithAccess;
/**
* Stores an user entity without access to fields.
*
* @var \Drupal\user\UserInterface
*/
protected $userWithoutAccess;
/**
* {@inheritdoc}
*/
public static $modules = ['user'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->installEntitySchema('user');
$role_with_access = Role::create([
'id' => 'with_access',
'permissions' => ['view test entity field'],
]);
$role_with_access->save();
$role_without_access = Role::create([
'id' => 'without_access',
'permissions' => [],
]);
$role_without_access->save();
$this->userWithAccess = User::create([
'name' => $this->randomMachineName(),
'roles' => [$role_with_access->id()],
]);
$this->userWithAccess->save();
$this->userWithoutAccess = User::create([
'name' => $this->randomMachineName(),
'roles' => [$role_without_access->id()],
]);
$this->userWithoutAccess->save();
}
/**
* Checks views field access for a given entity type and field name.
*
* To use this method, set up an entity of type $entity_type_id, with field
* $field_name. Create an entity instance that contains content $field_content
* in that field.
*
* This method will check that a user with permission can see the content in a
* view, and a user without access permission on that field cannot.
*
* @param string $entity_type_id
* The entity type ID.
* @param string $field_name
* The field name.
* @param string $field_content
* The expected field content.
*/
protected function assertFieldAccess($entity_type_id, $field_name, $field_content) {
\Drupal::state()->set('views_field_access_test-field', $field_name);
$entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
$view_id = $this->randomMachineName();
$data_table = $entity_type->getDataTable();
// Use the data table as long as the field is not 'uuid'. This is the only
// column that can only be obtained from the base table.
$base_table = ($data_table && ($field_name !== 'uuid')) ? $data_table : $entity_type->getBaseTable();
$entity = View::create([
'id' => $view_id,
'base_table' => $base_table,
'display' => [
'default' => [
'display_plugin' => 'default',
'id' => 'default',
'display_options' => [
'fields' => [
$field_name => [
'table' => $base_table,
'field' => $field_name,
'id' => $field_name,
'plugin_id' => 'field',
],
],
],
],
],
]);
$entity->save();
/** @var \Drupal\Core\Session\AccountSwitcherInterface $account_switcher */
$account_switcher = \Drupal::service('account_switcher');
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$account_switcher->switchTo($this->userWithAccess);
$executable = Views::getView($view_id);
$build = $executable->preview();
$this->setRawContent($renderer->renderRoot($build));
$this->assertText($field_content);
$this->assertTrue(isset($executable->field[$field_name]));
$account_switcher->switchTo($this->userWithoutAccess);
$executable = Views::getView($view_id);
$build = $executable->preview();
$this->setRawContent($renderer->renderRoot($build));
$this->assertNoText($field_content);
$this->assertFalse(isset($executable->field[$field_name]));
\Drupal::state()->delete('views_field_access_test-field');
}
}

View file

@ -0,0 +1,549 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\entity_test\Entity\EntityTestRev;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\user\Entity\User;
use Drupal\views\Plugin\views\field\Field;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Provides some integration tests for the Field handler.
*
* @see \Drupal\views\Plugin\views\field\Field
* @group views
*/
class FieldFieldTest extends ViewsKernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['field', 'entity_test', 'user', 'views_test_formatter'];
/**
* {@inheritdoc}
*/
public static $testViews = ['test_field_field_test', 'test_field_alias_test', 'test_field_field_complex_test', 'test_field_field_attachment_test', 'test_field_field_revision_test', 'test_field_field_revision_complex_test'];
/**
* The stored test entities.
*
* @var \Drupal\entity_test\Entity\EntityTest[]
*/
protected $entities;
/**
* The stored revisionable test entities.
*
* @var \Drupal\entity_test\Entity\EntityTestRev[]
*/
protected $entityRevision;
/**
* Stores a couple of test users.
*
* @var \Drupal\user\UserInterface[]
*/
protected $testUsers;
/**
* The admin user.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->installEntitySchema('entity_test');
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test_rev');
// Bypass any field access.
$this->adminUser = User::create(['name' => $this->randomString()]);
$this->adminUser->save();
$this->container->get('current_user')->setAccount($this->adminUser);
$this->testUsers = [];
for ($i = 0; $i < 5; $i++) {
$this->testUsers[$i] = User::create([
'name' => 'test ' . $i,
'timezone' => User::getAllowedTimezones()[$i],
'created' => REQUEST_TIME - rand(0, 3600)
]);
$this->testUsers[$i]->save();
}
// Setup a field storage and field, but also change the views data for the
// entity_test entity type.
$field_storage = FieldStorageConfig::create([
'field_name' => 'field_test',
'type' => 'integer',
'entity_type' => 'entity_test',
]);
$field_storage->save();
$field = FieldConfig::create([
'field_name' => 'field_test',
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
]);
$field->save();
$field_storage_multiple = FieldStorageConfig::create([
'field_name' => 'field_test_multiple',
'type' => 'integer',
'entity_type' => 'entity_test',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
]);
$field_storage_multiple->save();
$field_multiple = FieldConfig::create([
'field_name' => 'field_test_multiple',
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
]);
$field_multiple->save();
$random_number = (string) 30856;
$random_number_multiple = (string) 1370359990;
for ($i = 0; $i < 5; $i++) {
$this->entities[$i] = $entity = EntityTest::create([
'bundle' => 'entity_test',
'name' => 'test ' . $i,
'field_test' => $random_number[$i],
'field_test_multiple' => [$random_number_multiple[$i * 2], $random_number_multiple[$i * 2 + 1]],
'user_id' => $this->testUsers[$i]->id(),
]);
$entity->save();
}
// Setup some test data for entities with revisions.
// We are testing both base field revisions and field config revisions.
$field_storage = FieldStorageConfig::create([
'field_name' => 'field_test',
'type' => 'integer',
'entity_type' => 'entity_test_rev',
]);
$field_storage->save();
$field = FieldConfig::create([
'field_name' => 'field_test',
'entity_type' => 'entity_test_rev',
'bundle' => 'entity_test_rev',
]);
$field->save();
$field_storage_multiple = FieldStorageConfig::create([
'field_name' => 'field_test_multiple',
'type' => 'integer',
'entity_type' => 'entity_test_rev',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
]);
$field_storage_multiple->save();
$field_multiple = FieldConfig::create([
'field_name' => 'field_test_multiple',
'entity_type' => 'entity_test_rev',
'bundle' => 'entity_test_rev',
]);
$field_multiple->save();
$this->entityRevision = [];
$this->entityRevision[0] = $entity = EntityTestRev::create([
'name' => 'base value',
'field_test' => 1,
'field_test_multiple' => [1, 3, 7],
'user_id' => $this->testUsers[0]->id(),
]);
$entity->save();
$original_entity = clone $entity;
$entity = clone $original_entity;
$entity->setNewRevision(TRUE);
$entity->name->value = 'revision value1';
$entity->field_test->value = 2;
$entity->field_test_multiple[0]->value = 0;
$entity->field_test_multiple[1]->value = 3;
$entity->field_test_multiple[2]->value = 5;
$entity->user_id->target_id = $this->testUsers[1]->id();
$entity->save();
$this->entityRevision[1] = $entity;
$entity = clone $original_entity;
$entity->setNewRevision(TRUE);
$entity->name->value = 'revision value2';
$entity->field_test->value = 3;
$entity->field_test_multiple[0]->value = 9;
$entity->field_test_multiple[1]->value = 9;
$entity->field_test_multiple[2]->value = 9;
$entity->user_id->target_id = $this->testUsers[2]->id();
$entity->save();
$this->entityRevision[2] = $entity;
$this->entityRevision[3] = $entity = EntityTestRev::create([
'name' => 'next entity value',
'field_test' => 4,
'field_test_multiple' => [2, 9, 9],
'user_id' => $this->testUsers[3]->id(),
]);
$entity->save();
\Drupal::state()->set('entity_test.views_data', [
'entity_test' => [
'id' => [
'field' => [
'id' => 'field',
],
],
],
'entity_test_rev_revision' => [
'id' => [
'field' => [
'id' => 'field',
],
],
],
]);
Views::viewsData()->clear();
}
/**
* Tests the result of a view with base fields and configurable fields.
*/
public function testSimpleExecute() {
$executable = Views::getView('test_field_field_test');
$executable->execute();
$this->assertTrue($executable->field['id'] instanceof Field);
$this->assertTrue($executable->field['field_test'] instanceof Field);
$this->assertIdenticalResultset($executable,
[
['id' => 1, 'field_test' => 3],
['id' => 2, 'field_test' => 0],
['id' => 3, 'field_test' => 8],
['id' => 4, 'field_test' => 5],
['id' => 5, 'field_test' => 6],
],
['id' => 'id', 'field_test' => 'field_test']
);
}
/**
* Tests the output of a view with base fields and configurable fields.
*/
public function testSimpleRender() {
$executable = Views::getView('test_field_field_test');
$executable->execute();
$this->assertEqual('1', $executable->getStyle()->getField(0, 'id'));
$this->assertEqual('3', $executable->getStyle()->getField(0, 'field_test'));
$this->assertEqual('2', $executable->getStyle()->getField(1, 'id'));
// @todo Switch this assertion to assertIdentical('', ...) when
// https://www.drupal.org/node/2488006 gets fixed.
$this->assertEqual('0', $executable->getStyle()->getField(1, 'field_test'));
$this->assertEqual('3', $executable->getStyle()->getField(2, 'id'));
$this->assertEqual('8', $executable->getStyle()->getField(2, 'field_test'));
$this->assertEqual('4', $executable->getStyle()->getField(3, 'id'));
$this->assertEqual('5', $executable->getStyle()->getField(3, 'field_test'));
$this->assertEqual('5', $executable->getStyle()->getField(4, 'id'));
$this->assertEqual('6', $executable->getStyle()->getField(4, 'field_test'));
}
/**
* Tests that formatter's #attached assets are correctly preserved.
*
* @see \Drupal\views_test_formatter\Plugin\Field\FieldFormatter\AttachmentTestFormatter::viewElements()
*/
public function testAttachedRender() {
$executable = Views::getView('test_field_field_attachment_test');
$executable->execute();
// Check that the attachments added by AttachmentTestFormatter have been
// preserved in the render array.
$render = $executable->display_handler->render();
$expected_attachments = [
'library' => [
'views/views.module'
]
];
foreach ($this->entities as $entity) {
$expected_attachments['library'][] = 'foo/fake_library';
$expected_attachments['drupalSettings']['AttachmentIntegerFormatter'][$entity->id()] = $entity->id();
}
$this->assertEqual($expected_attachments, $render['#attached']);
}
/**
* Tests the result of a view with complex field configuration.
*
* A complex field configuration contains multiple times the same field, with
* different delta limit / offset.
*/
public function testFieldAlias() {
$executable = Views::getView('test_field_alias_test');
$executable->execute();
$this->assertTrue($executable->field['id'] instanceof Field);
$this->assertTrue($executable->field['name'] instanceof Field);
$this->assertTrue($executable->field['name_alias'] instanceof Field);
$this->assertIdenticalResultset($executable,
[
['id' => 1, 'name' => 'test 0', 'name_alias' => 'test 0'],
['id' => 2, 'name' => 'test 1', 'name_alias' => 'test 1'],
['id' => 3, 'name' => 'test 2', 'name_alias' => 'test 2'],
['id' => 4, 'name' => 'test 3', 'name_alias' => 'test 3'],
['id' => 5, 'name' => 'test 4', 'name_alias' => 'test 4'],
],
['id' => 'id', 'name' => 'name', 'name_alias' => 'name_alias']
);
}
/**
* Tests the result of a view with complex field configuration.
*
* A complex field configuration contains multiple times the same field, with
* different delta limit / offset.
*/
public function testFieldAliasRender() {
$executable = Views::getView('test_field_alias_test');
$executable->execute();
for ($i = 0; $i < 5; $i++) {
$this->assertEqual((string) ($i + 1), $executable->getStyle()->getField($i, 'id'));
$this->assertEqual('test ' . $i, $executable->getStyle()->getField($i, 'name'));
$entity = EntityTest::load($i + 1);
$this->assertEqual('<a href="' . $entity->url() . '" hreflang="' . $entity->language()->getId() . '">test ' . $i . '</a>', (string) $executable->getStyle()->getField($i, 'name_alias'));
}
}
/**
* Tests the result of a view with complex field configuration.
*
* A complex field configuration contains multiple times the same field, with
* different delta limit / offset.
*/
public function testComplexExecute() {
$executable = Views::getView('test_field_field_complex_test');
$executable->execute();
$timezones = [];
foreach ($this->testUsers as $user) {
$timezones[] = $user->getTimeZone();
}
$this->assertTrue($executable->field['field_test_multiple'] instanceof Field);
$this->assertTrue($executable->field['field_test_multiple_1'] instanceof Field);
$this->assertTrue($executable->field['field_test_multiple_2'] instanceof Field);
$this->assertTrue($executable->field['timezone'] instanceof Field);
$this->assertIdenticalResultset($executable,
[
['timezone' => $timezones[0], 'field_test_multiple' => [1, 3], 'field_test_multiple_1' => [1, 3], 'field_test_multiple_2' => [1, 3]],
['timezone' => $timezones[1], 'field_test_multiple' => [7, 0], 'field_test_multiple_1' => [7, 0], 'field_test_multiple_2' => [7, 0]],
['timezone' => $timezones[2], 'field_test_multiple' => [3, 5], 'field_test_multiple_1' => [3, 5], 'field_test_multiple_2' => [3, 5]],
['timezone' => $timezones[3], 'field_test_multiple' => [9, 9], 'field_test_multiple_1' => [9, 9], 'field_test_multiple_2' => [9, 9]],
['timezone' => $timezones[4], 'field_test_multiple' => [9, 0], 'field_test_multiple_1' => [9, 0], 'field_test_multiple_2' => [9, 0]],
],
['timezone' => 'timezone', 'field_test_multiple' => 'field_test_multiple', 'field_test_multiple_1' => 'field_test_multiple_1', 'field_test_multiple_2' => 'field_test_multiple_2']
);
}
/**
* Tests the output of a view with complex field configuration.
*/
public function testComplexRender() {
$executable = Views::getView('test_field_field_complex_test');
$executable->execute();
$date_formatter = \Drupal::service('date.formatter');
$this->assertEqual($this->testUsers[0]->getTimeZone(), $executable->getStyle()->getField(0, 'timezone'));
$this->assertEqual("1, 3", $executable->getStyle()->getField(0, 'field_test_multiple'));
$this->assertEqual("1", $executable->getStyle()->getField(0, 'field_test_multiple_1'));
$this->assertEqual("3", $executable->getStyle()->getField(0, 'field_test_multiple_2'));
$this->assertEqual($date_formatter->format($this->testUsers[0]->getCreatedTime(), 'custom', 'Y'), $executable->getStyle()->getField(0, 'created'));
$this->assertEqual($date_formatter->format($this->testUsers[0]->getCreatedTime(), 'custom', 'H:i:s'), $executable->getStyle()->getField(0, 'created_1'));
$this->assertEqual($date_formatter->format($this->testUsers[0]->getCreatedTime(), 'fallback'), $executable->getStyle()->getField(0, 'created_2'));
$this->assertEqual($this->testUsers[1]->getTimeZone(), $executable->getStyle()->getField(1, 'timezone'));
$this->assertEqual("7, 0", $executable->getStyle()->getField(1, 'field_test_multiple'));
$this->assertEqual("7", $executable->getStyle()->getField(1, 'field_test_multiple_1'));
$this->assertEqual("0", $executable->getStyle()->getField(1, 'field_test_multiple_2'));
$this->assertEqual($date_formatter->format($this->testUsers[1]->getCreatedTime(), 'custom', 'Y'), $executable->getStyle()->getField(1, 'created'));
$this->assertEqual($date_formatter->format($this->testUsers[1]->getCreatedTime(), 'custom', 'H:i:s'), $executable->getStyle()->getField(1, 'created_1'));
$this->assertEqual($date_formatter->format($this->testUsers[1]->getCreatedTime(), 'fallback'), $executable->getStyle()->getField(1, 'created_2'));
$this->assertEqual($this->testUsers[2]->getTimeZone(), $executable->getStyle()->getField(2, 'timezone'));
$this->assertEqual("3, 5", $executable->getStyle()->getField(2, 'field_test_multiple'));
$this->assertEqual("3", $executable->getStyle()->getField(2, 'field_test_multiple_1'));
$this->assertEqual("5", $executable->getStyle()->getField(2, 'field_test_multiple_2'));
$this->assertEqual($date_formatter->format($this->testUsers[2]->getCreatedTime(), 'custom', 'Y'), $executable->getStyle()->getField(2, 'created'));
$this->assertEqual($date_formatter->format($this->testUsers[2]->getCreatedTime(), 'custom', 'H:i:s'), $executable->getStyle()->getField(2, 'created_1'));
$this->assertEqual($date_formatter->format($this->testUsers[2]->getCreatedTime(), 'fallback'), $executable->getStyle()->getField(2, 'created_2'));
$this->assertEqual($this->testUsers[3]->getTimeZone(), $executable->getStyle()->getField(3, 'timezone'));
$this->assertEqual("9, 9", $executable->getStyle()->getField(3, 'field_test_multiple'));
$this->assertEqual("9", $executable->getStyle()->getField(3, 'field_test_multiple_1'));
$this->assertEqual("9", $executable->getStyle()->getField(3, 'field_test_multiple_2'));
$this->assertEqual($date_formatter->format($this->testUsers[3]->getCreatedTime(), 'custom', 'Y'), $executable->getStyle()->getField(3, 'created'));
$this->assertEqual($date_formatter->format($this->testUsers[3]->getCreatedTime(), 'custom', 'H:i:s'), $executable->getStyle()->getField(3, 'created_1'));
$this->assertEqual($date_formatter->format($this->testUsers[3]->getCreatedTime(), 'fallback'), $executable->getStyle()->getField(3, 'created_2'));
$this->assertEqual($this->testUsers[4]->getTimeZone(), $executable->getStyle()->getField(4, 'timezone'));
$this->assertEqual("9, 0", $executable->getStyle()->getField(4, 'field_test_multiple'));
$this->assertEqual("9", $executable->getStyle()->getField(4, 'field_test_multiple_1'));
$this->assertEqual("0", $executable->getStyle()->getField(4, 'field_test_multiple_2'));
$this->assertEqual($date_formatter->format($this->testUsers[4]->getCreatedTime(), 'custom', 'Y'), $executable->getStyle()->getField(4, 'created'));
$this->assertEqual($date_formatter->format($this->testUsers[4]->getCreatedTime(), 'custom', 'H:i:s'), $executable->getStyle()->getField(4, 'created_1'));
$this->assertEqual($date_formatter->format($this->testUsers[4]->getCreatedTime(), 'fallback'), $executable->getStyle()->getField(4, 'created_2'));
}
/**
* Tests the revision result.
*/
public function testRevisionExecute() {
$executable = Views::getView('test_field_field_revision_test');
$executable->execute();
$this->assertTrue($executable->field['name'] instanceof Field);
$this->assertTrue($executable->field['field_test'] instanceof Field);
$this->assertIdenticalResultset($executable,
[
['id' => 1, 'field_test' => 1, 'revision_id' => 1, 'name' => 'base value'],
['id' => 1, 'field_test' => 2, 'revision_id' => 2, 'name' => 'revision value1'],
['id' => 1, 'field_test' => 3, 'revision_id' => 3, 'name' => 'revision value2'],
['id' => 2, 'field_test' => 4, 'revision_id' => 4, 'name' => 'next entity value'],
],
['entity_test_rev_revision_id' => 'id', 'revision_id' => 'revision_id', 'name' => 'name', 'field_test' => 'field_test']
);
}
/**
* Tests the output of a revision view with base and configurable fields.
*/
public function testRevisionRender() {
$executable = Views::getView('test_field_field_revision_test');
$executable->execute();
$this->assertEqual('1', $executable->getStyle()->getField(0, 'id'));
$this->assertEqual('1', $executable->getStyle()->getField(0, 'revision_id'));
$this->assertEqual('1', $executable->getStyle()->getField(0, 'field_test'));
$this->assertEqual('base value', $executable->getStyle()->getField(0, 'name'));
$this->assertEqual('1', $executable->getStyle()->getField(1, 'id'));
$this->assertEqual('2', $executable->getStyle()->getField(1, 'revision_id'));
$this->assertEqual('2', $executable->getStyle()->getField(1, 'field_test'));
$this->assertEqual('revision value1', $executable->getStyle()->getField(1, 'name'));
$this->assertEqual('1', $executable->getStyle()->getField(2, 'id'));
$this->assertEqual('3', $executable->getStyle()->getField(2, 'revision_id'));
$this->assertEqual('3', $executable->getStyle()->getField(2, 'field_test'));
$this->assertEqual('revision value2', $executable->getStyle()->getField(2, 'name'));
$this->assertEqual('2', $executable->getStyle()->getField(3, 'id'));
$this->assertEqual('4', $executable->getStyle()->getField(3, 'revision_id'));
$this->assertEqual('4', $executable->getStyle()->getField(3, 'field_test'));
$this->assertEqual('next entity value', $executable->getStyle()->getField(3, 'name'));
}
/**
* Tests the result set of a complex revision view.
*/
public function testRevisionComplexExecute() {
$executable = Views::getView('test_field_field_revision_complex_test');
$executable->execute();
$timezones = [];
foreach ($this->testUsers as $user) {
$timezones[] = $user->getTimeZone();
}
$this->assertTrue($executable->field['id'] instanceof Field);
$this->assertTrue($executable->field['revision_id'] instanceof Field);
$this->assertTrue($executable->field['timezone'] instanceof Field);
$this->assertTrue($executable->field['field_test_multiple'] instanceof Field);
$this->assertTrue($executable->field['field_test_multiple_1'] instanceof Field);
$this->assertTrue($executable->field['field_test_multiple_2'] instanceof Field);
$this->assertIdenticalResultset($executable,
[
['id' => 1, 'field_test' => 1, 'revision_id' => 1, 'uid' => $this->testUsers[0]->id(), 'timezone' => $timezones[0], 'field_test_multiple' => [1, 3, 7], 'field_test_multiple_1' => [1, 3, 7], 'field_test_multiple_2' => [1, 3, 7]],
['id' => 1, 'field_test' => 2, 'revision_id' => 2, 'uid' => $this->testUsers[1]->id(), 'timezone' => $timezones[1], 'field_test_multiple' => [0, 3, 5], 'field_test_multiple_1' => [0, 3, 5], 'field_test_multiple_2' => [0, 3, 5]],
['id' => 1, 'field_test' => 3, 'revision_id' => 3, 'uid' => $this->testUsers[2]->id(), 'timezone' => $timezones[2], 'field_test_multiple' => [9, 9, 9], 'field_test_multiple_1' => [9, 9, 9], 'field_test_multiple_2' => [9, 9, 9]],
['id' => 2, 'field_test' => 4, 'revision_id' => 4, 'uid' => $this->testUsers[3]->id(), 'timezone' => $timezones[3], 'field_test_multiple' => [2, 9, 9], 'field_test_multiple_1' => [2, 9, 9], 'field_test_multiple_2' => [2, 9, 9]],
],
['entity_test_rev_revision_id' => 'id', 'revision_id' => 'revision_id', 'users_field_data_entity_test_rev_revision_uid' => 'uid', 'timezone' => 'timezone', 'field_test_multiple' => 'field_test_multiple', 'field_test_multiple_1' => 'field_test_multiple_1', 'field_test_multiple_2' => 'field_test_multiple_2']
);
}
/**
* Tests the output of a revision view with base fields and configurable fields.
*/
public function testRevisionComplexRender() {
$executable = Views::getView('test_field_field_revision_complex_test');
$executable->execute();
$this->assertEqual('1', $executable->getStyle()->getField(0, 'id'));
$this->assertEqual('1', $executable->getStyle()->getField(0, 'revision_id'));
$this->assertEqual($this->testUsers[0]->getTimeZone(), $executable->getStyle()->getField(0, 'timezone'));
$this->assertEqual('1, 3, 7', $executable->getStyle()->getField(0, 'field_test_multiple'));
$this->assertEqual('1', $executable->getStyle()->getField(0, 'field_test_multiple_1'));
$this->assertEqual('3, 7', $executable->getStyle()->getField(0, 'field_test_multiple_2'));
$this->assertEqual('1', $executable->getStyle()->getField(1, 'id'));
$this->assertEqual('2', $executable->getStyle()->getField(1, 'revision_id'));
$this->assertEqual($this->testUsers[1]->getTimeZone(), $executable->getStyle()->getField(1, 'timezone'));
$this->assertEqual('0, 3, 5', $executable->getStyle()->getField(1, 'field_test_multiple'));
$this->assertEqual('0', $executable->getStyle()->getField(1, 'field_test_multiple_1'));
$this->assertEqual('3, 5', $executable->getStyle()->getField(1, 'field_test_multiple_2'));
$this->assertEqual('1', $executable->getStyle()->getField(2, 'id'));
$this->assertEqual('3', $executable->getStyle()->getField(2, 'revision_id'));
$this->assertEqual($this->testUsers[2]->getTimeZone(), $executable->getStyle()->getField(2, 'timezone'));
$this->assertEqual('9, 9, 9', $executable->getStyle()->getField(2, 'field_test_multiple'));
$this->assertEqual('9', $executable->getStyle()->getField(2, 'field_test_multiple_1'));
$this->assertEqual('9, 9', $executable->getStyle()->getField(2, 'field_test_multiple_2'));
$this->assertEqual('2', $executable->getStyle()->getField(3, 'id'));
$this->assertEqual('4', $executable->getStyle()->getField(3, 'revision_id'));
$this->assertEqual($this->testUsers[3]->getTimeZone(), $executable->getStyle()->getField(3, 'timezone'));
$this->assertEqual('2, 9, 9', $executable->getStyle()->getField(3, 'field_test_multiple'));
$this->assertEqual('2', $executable->getStyle()->getField(3, 'field_test_multiple_1'));
$this->assertEqual('9, 9', $executable->getStyle()->getField(3, 'field_test_multiple_2'));
}
/**
* Tests that a field not available for every bundle is rendered as empty.
*/
public function testMissingBundleFieldRender() {
// Create a new bundle not having the test field attached.
$bundle = $this->randomMachineName();
entity_test_create_bundle($bundle);
$entity = EntityTest::create([
'type' => $bundle,
'name' => $this->randomString(),
'user_id' => $this->testUsers[0]->id(),
]);
$entity->save();
$executable = Views::getView('test_field_field_test');
$executable->execute();
$this->assertEqual('', $executable->getStyle()->getField(6, 'field_test'));
}
}

View file

@ -0,0 +1,67 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\field\FileSize handler.
*
* @group views
* @see CommonXssUnitTest
*/
class FieldFileSizeTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
function dataSet() {
$data = parent::dataSet();
$data[0]['age'] = 0;
$data[1]['age'] = 10;
$data[2]['age'] = 1000;
$data[3]['age'] = 10000;
return $data;
}
function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['age']['field']['id'] = 'file_size';
return $data;
}
public function testFieldFileSize() {
$view = Views::getView('test_view');
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('fields', array(
'age' => array(
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
),
));
$this->executeView($view);
// Test with the formatted option.
$this->assertEqual($view->field['age']->advancedRender($view->result[0]), '');
$this->assertEqual($view->field['age']->advancedRender($view->result[1]), '10 bytes');
$this->assertEqual($view->field['age']->advancedRender($view->result[2]), '1000 bytes');
$this->assertEqual($view->field['age']->advancedRender($view->result[3]), '9.77 KB');
// Test with the bytes option.
$view->field['age']->options['file_size_display'] = 'bytes';
$this->assertEqual($view->field['age']->advancedRender($view->result[0]), '');
$this->assertEqual($view->field['age']->advancedRender($view->result[1]), '10');
$this->assertEqual($view->field['age']->advancedRender($view->result[2]), '1000');
$this->assertEqual($view->field['age']->advancedRender($view->result[3]), '10000');
}
}

View file

@ -0,0 +1,792 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Core\Render\RenderContext;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\Views;
/**
* Tests the generic field handler.
*
* @group views
* @see \Drupal\views\Plugin\views\field\FieldPluginBase
*/
class FieldKernelTest extends ViewsKernelTestBase {
public static $modules = array('user');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view', 'test_field_tokens', 'test_field_argument_tokens', 'test_field_output');
/**
* Map column names.
*
* @var array
*/
protected $columnMap = array(
'views_test_data_name' => 'name',
);
/**
* {@inheritdoc}
*/
protected function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['job']['field']['id'] = 'test_field';
$data['views_test_data']['job']['field']['click sortable'] = FALSE;
$data['views_test_data']['id']['field']['click sortable'] = TRUE;
return $data;
}
/**
* Tests that the render function is called.
*/
public function testRender() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$view = Views::getView('test_field_tokens');
$this->executeView($view);
$random_text = $this->randomMachineName();
$view->field['job']->setTestValue($random_text);
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['job']->theme($view->result[0]);
});
$this->assertEqual($output, $random_text, 'Make sure the render method rendered the manual set value.');
}
/**
* Tests all things related to the query.
*/
public function testQuery() {
// Tests adding additional fields to the query.
$view = Views::getView('test_view');
$view->initHandlers();
$id_field = $view->field['id'];
$id_field->additional_fields['job'] = 'job';
// Choose also a field alias key which doesn't match to the table field.
$id_field->additional_fields['created_test'] = array('table' => 'views_test_data', 'field' => 'created');
$view->build();
// Make sure the field aliases have the expected value.
$this->assertEqual($id_field->aliases['job'], 'views_test_data_job');
$this->assertEqual($id_field->aliases['created_test'], 'views_test_data_created');
$this->executeView($view);
// Tests the getValue method with and without a field aliases.
foreach ($this->dataSet() as $key => $row) {
$id = $key + 1;
$result = $view->result[$key];
$this->assertEqual($id_field->getValue($result), $id);
$this->assertEqual($id_field->getValue($result, 'job'), $row['job']);
$this->assertEqual($id_field->getValue($result, 'created_test'), $row['created']);
}
}
/**
* Asserts that a string is part of another string.
*
* @param string $haystack
* The value to search in.
* @param string $needle
* The value to search for.
* @param string $message
* (optional) A message to display with the assertion. Do not translate
* messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
* variables in the message text, not t(). If left blank, a default message
* will be displayed.
* @param string $group
* (optional) The group this message is in, which is displayed in a column
* in test output. Use 'Debug' to indicate this is debugging output. Do not
* translate this string. Defaults to 'Other'; most tests do not override
* this default.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertSubString($haystack, $needle, $message = '', $group = 'Other') {
return $this->assertTrue(strpos($haystack, $needle) !== FALSE, $message, $group);
}
/**
* Asserts that a string is not part of another string.
*
* @param string $haystack
* The value to search in.
* @param string $needle
* The value to search for.
* @param string $message
* (optional) A message to display with the assertion. Do not translate
* messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
* variables in the message text, not t(). If left blank, a default message
* will be displayed.
* @param string $group
* (optional) The group this message is in, which is displayed in a column
* in test output. Use 'Debug' to indicate this is debugging output. Do not
* translate this string. Defaults to 'Other'; most tests do not override
* this default.
*
* @return bool
* TRUE if the assertion succeeded, FALSE otherwise.
*/
protected function assertNotSubString($haystack, $needle, $message = '', $group = 'Other') {
return $this->assertTrue(strpos($haystack, $needle) === FALSE, $message, $group);
}
/**
* Tests general rewriting of the output.
*/
public function testRewrite() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$view = Views::getView('test_view');
$view->initHandlers();
$this->executeView($view);
$row = $view->result[0];
$id_field = $view->field['id'];
// Don't check the rewrite checkbox, so the text shouldn't appear.
$id_field->options['alter']['text'] = $random_text = $this->randomMachineName();
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertNotSubString($output, $random_text);
$id_field->options['alter']['alter_text'] = TRUE;
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($id_field, $row) {
return $id_field->theme($row);
});
$this->assertSubString($output, $random_text);
}
/**
* Tests the arguments tokens on field level.
*/
public function testArgumentTokens() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$view = Views::getView('test_field_argument_tokens');
$this->executeView($view, ['{{ { "#pre_render": ["views_test_data_test_pre_render_function"]} }}']);
$name_field_0 = $view->field['name'];
// Test the old style tokens.
$name_field_0->options['alter']['alter_text'] = TRUE;
$name_field_0->options['alter']['text'] = '%1 !1';
$row = $view->result[0];
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_0, $row) {
return $name_field_0->advancedRender($row);
});
$this->assertFalse(strpos((string) $output, 'views_test_data_test_pre_render_function executed') !== FALSE, 'Ensure that the pre_render function was not executed');
$this->assertEqual('%1 !1', (string) $output, "Ensure that old style placeholders aren't replaced");
// This time use new style tokens but ensure that we still don't allow
// arbitrary code execution.
$name_field_0->options['alter']['alter_text'] = TRUE;
$name_field_0->options['alter']['text'] = '{{ arguments.null }} {{ raw_arguments.null }}';
$row = $view->result[0];
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_0, $row) {
return $name_field_0->advancedRender($row);
});
$this->assertFalse(strpos((string) $output, 'views_test_data_test_pre_render_function executed') !== FALSE, 'Ensure that the pre_render function was not executed');
$this->assertEqual('{{ { &quot;#pre_render&quot;: [&quot;views_test_data_test_pre_render_function&quot;]} }} {{ { &quot;#pre_render&quot;: [&quot;views_test_data_test_pre_render_function&quot;]} }}', (string) $output, 'Ensure that new style placeholders are replaced');
}
/**
* Tests the field tokens, row level and field level.
*/
public function testFieldTokens() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$view = Views::getView('test_field_tokens');
$this->executeView($view);
$name_field_0 = $view->field['name'];
$name_field_1 = $view->field['name_1'];
$name_field_2 = $view->field['name_2'];
$row = $view->result[0];
$name_field_0->options['alter']['alter_text'] = TRUE;
$name_field_0->options['alter']['text'] = '{{ name }}';
$name_field_1->options['alter']['alter_text'] = TRUE;
$name_field_1->options['alter']['text'] = '{{ name_1 }} {{ name }}';
$name_field_2->options['alter']['alter_text'] = TRUE;
$name_field_2->options['alter']['text'] = '{% if name_2|length > 3 %}{{ name_2 }} {{ name_1 }}{% endif %}';
foreach ($view->result as $row) {
$expected_output_0 = $row->views_test_data_name;
$expected_output_1 = "$row->views_test_data_name $row->views_test_data_name";
$expected_output_2 = "$row->views_test_data_name $row->views_test_data_name $row->views_test_data_name";
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_0, $row) {
return $name_field_0->advancedRender($row);
});
$this->assertEqual($output, $expected_output_0, format_string('Test token replacement: "@token" gave "@output"', [
'@token' => $name_field_0->options['alter']['text'],
'@output' => $output,
]));
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_1, $row) {
return $name_field_1->advancedRender($row);
});
$this->assertEqual($output, $expected_output_1, format_string('Test token replacement: "@token" gave "@output"', [
'@token' => $name_field_1->options['alter']['text'],
'@output' => $output,
]));
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($name_field_2, $row) {
return $name_field_2->advancedRender($row);
});
$this->assertEqual($output, $expected_output_2, format_string('Test token replacement: "@token" gave "@output"', [
'@token' => $name_field_2->options['alter']['text'],
'@output' => $output,
]));
}
$job_field = $view->field['job'];
$job_field->options['alter']['alter_text'] = TRUE;
$job_field->options['alter']['text'] = '{{ job }}';
$random_text = $this->randomMachineName();
$job_field->setTestValue($random_text);
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($job_field, $row) {
return $job_field->advancedRender($row);
});
$this->assertSubString($output, $random_text, format_string('Make sure the self token (@token => @value) appears in the output (@output)', [
'@value' => $random_text,
'@output' => $output,
'@token' => $job_field->options['alter']['text'],
]));
// Verify the token format used in D7 and earlier does not get substituted.
$old_token = '[job]';
$job_field->options['alter']['text'] = $old_token;
$random_text = $this->randomMachineName();
$job_field->setTestValue($random_text);
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($job_field, $row) {
return $job_field->advancedRender($row);
});
$this->assertEqual($output, $old_token, format_string('Make sure the old token style (@token => @value) is not changed in the output (@output)', [
'@value' => $random_text,
'@output' => $output,
'@token' => $job_field->options['alter']['text'],
]));
// Verify HTML tags are allowed in rewrite templates while token
// replacements are escaped.
$job_field->options['alter']['text'] = '<h1>{{ job }}</h1>';
$random_text = $this->randomMachineName();
$job_field->setTestValue('<span>' . $random_text . '</span>');
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($job_field, $row) {
return $job_field->advancedRender($row);
});
$this->assertEqual($output, '<h1>&lt;span&gt;' . $random_text . '&lt;/span&gt;</h1>', 'Valid tags are allowed in rewrite templates and token replacements.');
// Verify <script> tags are correctly removed from rewritten text.
$rewrite_template = '<script>alert("malicious");</script>';
$job_field->options['alter']['text'] = $rewrite_template;
$random_text = $this->randomMachineName();
$job_field->setTestValue($random_text);
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($job_field, $row) {
return $job_field->advancedRender($row);
});
$this->assertNotSubString($output, '<script>', 'Ensure a script tag in the rewrite template is removed.');
$rewrite_template = '<script>{{ job }}</script>';
$job_field->options['alter']['text'] = $rewrite_template;
$random_text = $this->randomMachineName();
$job_field->setTestValue($random_text);
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($job_field, $row) {
return $job_field->advancedRender($row);
});
$this->assertEqual($output, $random_text, format_string('Make sure a script tag in the template (@template) is removed, leaving only the replaced token in the output (@output)', [
'@output' => $output,
'@template' => $rewrite_template,
]));
}
/**
* Tests the exclude setting.
*/
public function testExclude() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$view = Views::getView('test_field_output');
$view->initHandlers();
// Hide the field and see whether it's rendered.
$view->field['name']->options['exclude'] = TRUE;
$output = $view->preview();
$output = $renderer->renderRoot($output);
foreach ($this->dataSet() as $entry) {
$this->assertNotSubString($output, $entry['name']);
}
// Show and check the field.
$view->field['name']->options['exclude'] = FALSE;
$output = $view->preview();
$output = $renderer->renderRoot($output);
foreach ($this->dataSet() as $entry) {
$this->assertSubString($output, $entry['name']);
}
}
/**
* Tests everything related to empty output of a field.
*/
function testEmpty() {
$this->_testHideIfEmpty();
$this->_testEmptyText();
}
/**
* Tests the hide if empty functionality.
*
* This tests alters the result to get easier and less coupled results. It is
* important that assertIdentical() is used in this test since in PHP 0 == ''.
*/
function _testHideIfEmpty() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$view = Views::getView('test_view');
$view->initDisplay();
$this->executeView($view);
$column_map_reversed = array_flip($this->columnMap);
$view->row_index = 0;
$random_name = $this->randomMachineName();
$random_value = $this->randomMachineName();
// Test when results are not rewritten and empty values are not hidden.
$view->field['name']->options['hide_alter_empty'] = FALSE;
$view->field['name']->options['hide_empty'] = FALSE;
$view->field['name']->options['empty_zero'] = FALSE;
// Test a valid string.
$view->result[0]->{$column_map_reversed['name']} = $random_name;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $random_name, 'By default, a string should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical($render, "", 'By default, "" should not be treated as empty.');
// Test zero as an integer.
$view->result[0]->{$column_map_reversed['name']} = 0;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, '0', 'By default, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, "0", 'By default, "0" should not be treated as empty.');
// Test when results are not rewritten and non-zero empty values are hidden.
$view->field['name']->options['hide_alter_empty'] = TRUE;
$view->field['name']->options['hide_empty'] = TRUE;
$view->field['name']->options['empty_zero'] = FALSE;
// Test a valid string.
$view->result[0]->{$column_map_reversed['name']} = $random_name;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $random_name, 'If hide_empty is checked, a string should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical($render, "", 'If hide_empty is checked, "" should be treated as empty.');
// Test zero as an integer.
$view->result[0]->{$column_map_reversed['name']} = 0;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, '0', 'If hide_empty is checked, but not empty_zero, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, "0", 'If hide_empty is checked, but not empty_zero, "0" should not be treated as empty.');
// Test when results are not rewritten and all empty values are hidden.
$view->field['name']->options['hide_alter_empty'] = TRUE;
$view->field['name']->options['hide_empty'] = TRUE;
$view->field['name']->options['empty_zero'] = TRUE;
// Test zero as an integer.
$view->result[0]->{$column_map_reversed['name']} = 0;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical($render, "", 'If hide_empty and empty_zero are checked, 0 should be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical($render, "", 'If hide_empty and empty_zero are checked, "0" should be treated as empty.');
// Test when results are rewritten to a valid string and non-zero empty
// results are hidden.
$view->field['name']->options['hide_alter_empty'] = FALSE;
$view->field['name']->options['hide_empty'] = TRUE;
$view->field['name']->options['empty_zero'] = FALSE;
$view->field['name']->options['alter']['alter_text'] = TRUE;
$view->field['name']->options['alter']['text'] = $random_name;
// Test a valid string.
$view->result[0]->{$column_map_reversed['name']} = $random_value;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $random_name, 'If the rewritten string is not empty, it should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $random_name, 'If the rewritten string is not empty, "" should not be treated as empty.');
// Test zero as an integer.
$view->result[0]->{$column_map_reversed['name']} = 0;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $random_name, 'If the rewritten string is not empty, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $random_name, 'If the rewritten string is not empty, "0" should not be treated as empty.');
// Test when results are rewritten to an empty string and non-zero empty results are hidden.
$view->field['name']->options['hide_alter_empty'] = TRUE;
$view->field['name']->options['hide_empty'] = TRUE;
$view->field['name']->options['empty_zero'] = FALSE;
$view->field['name']->options['alter']['alter_text'] = TRUE;
$view->field['name']->options['alter']['text'] = "";
// Test a valid string.
$view->result[0]->{$column_map_reversed['name']} = $random_name;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $random_name, 'If the rewritten string is empty, it should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical($render, "", 'If the rewritten string is empty, "" should be treated as empty.');
// Test zero as an integer.
$view->result[0]->{$column_map_reversed['name']} = 0;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, '0', 'If the rewritten string is empty, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, "0", 'If the rewritten string is empty, "0" should not be treated as empty.');
// Test when results are rewritten to zero as a string and non-zero empty
// results are hidden.
$view->field['name']->options['hide_alter_empty'] = FALSE;
$view->field['name']->options['hide_empty'] = TRUE;
$view->field['name']->options['empty_zero'] = FALSE;
$view->field['name']->options['alter']['alter_text'] = TRUE;
$view->field['name']->options['alter']['text'] = "0";
// Test a valid string.
$view->result[0]->{$column_map_reversed['name']} = $random_name;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, "0", 'If the rewritten string is zero and empty_zero is not checked, the string rewritten as 0 should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, "0", 'If the rewritten string is zero and empty_zero is not checked, "" rewritten as 0 should not be treated as empty.');
// Test zero as an integer.
$view->result[0]->{$column_map_reversed['name']} = 0;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, "0", 'If the rewritten string is zero and empty_zero is not checked, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, "0", 'If the rewritten string is zero and empty_zero is not checked, "0" should not be treated as empty.');
// Test when results are rewritten to a valid string and non-zero empty
// results are hidden.
$view->field['name']->options['hide_alter_empty'] = TRUE;
$view->field['name']->options['hide_empty'] = TRUE;
$view->field['name']->options['empty_zero'] = FALSE;
$view->field['name']->options['alter']['alter_text'] = TRUE;
$view->field['name']->options['alter']['text'] = $random_value;
// Test a valid string.
$view->result[0]->{$column_map_reversed['name']} = $random_name;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $random_value, 'If the original and rewritten strings are valid, it should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical($render, "", 'If either the original or rewritten string is invalid, "" should be treated as empty.');
// Test zero as an integer.
$view->result[0]->{$column_map_reversed['name']} = 0;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $random_value, 'If the original and rewritten strings are valid, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $random_value, 'If the original and rewritten strings are valid, "0" should not be treated as empty.');
// Test when results are rewritten to zero as a string and all empty
// original values and results are hidden.
$view->field['name']->options['hide_alter_empty'] = TRUE;
$view->field['name']->options['hide_empty'] = TRUE;
$view->field['name']->options['empty_zero'] = TRUE;
$view->field['name']->options['alter']['alter_text'] = TRUE;
$view->field['name']->options['alter']['text'] = "0";
// Test a valid string.
$view->result[0]->{$column_map_reversed['name']} = $random_name;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, "", 'If the rewritten string is zero, it should be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical($render, "", 'If the rewritten string is zero, "" should be treated as empty.');
// Test zero as an integer.
$view->result[0]->{$column_map_reversed['name']} = 0;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical($render, "", 'If the rewritten string is zero, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical($render, "", 'If the rewritten string is zero, "0" should not be treated as empty.');
}
/**
* Tests the usage of the empty text.
*/
function _testEmptyText() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$view = Views::getView('test_view');
$view->initDisplay();
$this->executeView($view);
$column_map_reversed = array_flip($this->columnMap);
$view->row_index = 0;
$empty_text = $view->field['name']->options['empty'] = $this->randomMachineName();
$view->result[0]->{$column_map_reversed['name']} = "";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $empty_text, 'If a field is empty, the empty text should be used for the output.');
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, "0", 'If a field is 0 and empty_zero is not checked, the empty text should not be used for the output.');
$view->result[0]->{$column_map_reversed['name']} = "0";
$view->field['name']->options['empty_zero'] = TRUE;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $empty_text, 'If a field is 0 and empty_zero is checked, the empty text should be used for the output.');
$view->result[0]->{$column_map_reversed['name']} = "";
$view->field['name']->options['alter']['alter_text'] = TRUE;
$alter_text = $view->field['name']->options['alter']['text'] = $this->randomMachineName();
$view->field['name']->options['hide_alter_empty'] = FALSE;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $alter_text, 'If a field is empty, some rewrite text exists, but hide_alter_empty is not checked, render the rewrite text.');
$view->field['name']->options['hide_alter_empty'] = TRUE;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertIdentical((string) $render, $empty_text, 'If a field is empty, some rewrite text exists, and hide_alter_empty is checked, use the empty text.');
}
/**
* Tests views_handler_field::isValueEmpty().
*/
function testIsValueEmpty() {
$view = Views::getView('test_view');
$view->initHandlers();
$field = $view->field['name'];
$this->assertFalse($field->isValueEmpty("not empty", TRUE), 'A normal string is not empty.');
$this->assertTrue($field->isValueEmpty("not empty", TRUE, FALSE), 'A normal string which skips empty() can be seen as empty.');
$this->assertTrue($field->isValueEmpty("", TRUE), '"" is considered as empty.');
$this->assertTrue($field->isValueEmpty('0', TRUE), '"0" is considered as empty if empty_zero is TRUE.');
$this->assertTrue($field->isValueEmpty(0, TRUE), '0 is considered as empty if empty_zero is TRUE.');
$this->assertFalse($field->isValueEmpty('0', FALSE), '"0" is considered not as empty if empty_zero is FALSE.');
$this->assertFalse($field->isValueEmpty(0, FALSE), '0 is considered not as empty if empty_zero is FALSE.');
$this->assertTrue($field->isValueEmpty(NULL, TRUE, TRUE), 'Null should be always seen as empty, regardless of no_skip_empty.');
$this->assertTrue($field->isValueEmpty(NULL, TRUE, FALSE), 'Null should be always seen as empty, regardless of no_skip_empty.');
}
/**
* Tests whether the filters are click sortable as expected.
*/
public function testClickSortable() {
// Test that clickSortable is TRUE by default.
$item = array(
'table' => 'views_test_data',
'field' => 'name',
);
$plugin = $this->container->get('plugin.manager.views.field')->getHandler($item);
$this->assertTrue($plugin->clickSortable(), 'TRUE as a default value is correct.');
// Test that clickSortable is TRUE by when set TRUE in the data.
$item['field'] = 'id';
$plugin = $this->container->get('plugin.manager.views.field')->getHandler($item);
$this->assertTrue($plugin->clickSortable(), 'TRUE as a views data value is correct.');
// Test that clickSortable is FALSE by when set FALSE in the data.
$item['field'] = 'job';
$plugin = $this->container->get('plugin.manager.views.field')->getHandler($item);
$this->assertFalse($plugin->clickSortable(), 'FALSE as a views data value is correct.');
}
/**
* Tests the trimText method.
*/
public function testTrimText() {
// Test unicode. See https://www.drupal.org/node/513396#comment-2839416.
$text = array(
'Tuy nhiên, những hi vọng',
'Giả sử chúng tôi có 3 Apple',
'siêu nhỏ này là bộ xử lý',
'Di động của nhà sản xuất Phần Lan',
'khoảng cách từ đại lí đến',
'của hãng bao gồm ba dòng',
'сд асд асд ас',
'асд асд асд ас'
);
// Just test maxlength without word boundary.
$alter = array(
'max_length' => 10,
);
$expect = array(
'Tuy nhiên,',
'Giả sử chú',
'siêu nhỏ n',
'Di động củ',
'khoảng các',
'của hãng b',
'сд асд асд',
'асд асд ас',
);
foreach ($text as $key => $line) {
$result_text = FieldPluginBase::trimText($alter, $line);
$this->assertEqual($result_text, $expect[$key]);
}
// Test also word_boundary
$alter['word_boundary'] = TRUE;
$expect = array(
'Tuy nhiên',
'Giả sử',
'siêu nhỏ',
'Di động',
'khoảng',
'của hãng',
'сд асд',
'асд асд',
);
foreach ($text as $key => $line) {
$result_text = FieldPluginBase::trimText($alter, $line);
$this->assertEqual($result_text, $expect[$key]);
}
}
}

View file

@ -0,0 +1,195 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\user\Entity\User;
use Drupal\views\Entity\View;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
use Drupal\Core\Entity\Entity\EntityViewMode;
/**
* Tests the core Drupal\views\Plugin\views\field\RenderedEntity handler.
*
* @group views
*/
class FieldRenderedEntityTest extends ViewsKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['entity_test', 'field'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_field_entity_test_rendered'];
/**
* The logged in user.
*
* @var \Drupal\user\UserInterface
*/
protected $user;
/**
* {@inheritdoc}
*/
protected function setUpFixtures() {
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test');
$this->installConfig(['entity_test']);
EntityViewMode::create([
'id' => 'entity_test.foobar',
'targetEntityType' => 'entity_test',
'status' => TRUE,
'enabled' => TRUE,
'label' => 'My view mode',
])->save();
$display = EntityViewDisplay::create([
'targetEntityType' => 'entity_test',
'bundle' => 'entity_test',
'mode' => 'foobar',
'label' => 'My view mode',
'status' => TRUE,
]);
$display->save();
$field_storage = FieldStorageConfig::create([
'field_name' => 'test_field',
'entity_type' => 'entity_test',
'type' => 'string',
]);
$field_storage->save();
$field_config = FieldConfig::create([
'field_name' => 'test_field',
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
]);
$field_config->save();
// Create some test entities.
for ($i = 1; $i <= 3; $i++) {
EntityTest::create([
'name' => "Article title $i",
'test_field' => "Test $i",
])->save();
}
$this->user = User::create([
'name' => 'test user',
]);
$this->user->save();
parent::setUpFixtures();
}
/**
* Tests the default rendered entity output.
*/
public function testRenderedEntityWithoutField() {
\Drupal::currentUser()->setAccount($this->user);
EntityViewDisplay::load('entity_test.entity_test.foobar')
->removeComponent('test_field')
->save();
$view = Views::getView('test_field_entity_test_rendered');
$build = [
'#type' => 'view',
'#name' => 'test_field_entity_test_rendered',
'#view' => $view,
'#display_id' => 'default',
];
$renderer = \Drupal::service('renderer');
$renderer->renderPlain($build);
for ($i = 1; $i <= 3; $i++) {
$view_field = $view->style_plugin->getField($i - 1, 'rendered_entity');
$search_result = strpos($view_field, "Test $i") !== FALSE;
$this->assertFalse($search_result, "The text 'Test $i' not found in the view.");
}
$this->assertConfigDependencies($view->storage);
$this->assertCacheabilityMetadata($build);
}
/**
* Ensures that the expected cacheability metadata is applied.
*
* @param array $build
* The render array
*/
protected function assertCacheabilityMetadata($build) {
$this->assertEqual([
'config:core.entity_view_display.entity_test.entity_test.foobar',
'config:views.view.test_field_entity_test_rendered',
'entity_test:1',
'entity_test:2',
'entity_test:3',
'entity_test_list',
'entity_test_view',
], $build['#cache']['tags']);
$this->assertEqual([
'entity_test_view_grants',
'languages:language_interface',
'theme',
'url.query_args',
'user.permissions',
], $build['#cache']['contexts']);
}
/**
* Ensures that the config dependencies are calculated the right way.
*
* @param \Drupal\views\Entity\View $storage
*/
protected function assertConfigDependencies(View $storage) {
$storage->calculateDependencies();
$this->assertEqual([
'config' => ['core.entity_view_mode.entity_test.foobar'],
'module' => ['entity_test'],
], $storage->getDependencies());
}
/**
* Tests the rendered entity output with the test field configured to show.
*/
public function testRenderedEntityWithField() {
\Drupal::currentUser()->setAccount($this->user);
// Show the test_field on the entity_test.entity_test.foobar view display.
EntityViewDisplay::load('entity_test.entity_test.foobar')->setComponent('test_field', ['type' => 'string', 'label' => 'above'])->save();
$view = Views::getView('test_field_entity_test_rendered');
$build = [
'#type' => 'view',
'#name' => 'test_field_entity_test_rendered',
'#view' => $view,
'#display_id' => 'default',
];
$renderer = \Drupal::service('renderer');
$renderer->renderPlain($build);
for ($i = 1; $i <= 3; $i++) {
$view_field = $view->style_plugin->getField($i - 1, 'rendered_entity');
$search_result = strpos($view_field, "Test $i") !== FALSE;
$this->assertTrue($search_result, "The text 'Test $i' found in the view.");
}
$this->assertConfigDependencies($view->storage);
$this->assertCacheabilityMetadata($build);
}
}

View file

@ -0,0 +1,67 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Core\Url;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\field\Url handler.
*
* @group views
*/
class FieldUrlTest extends ViewsKernelTestBase {
public static $modules = array('system');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['name']['field']['id'] = 'url';
return $data;
}
public function testFieldUrl() {
$view = Views::getView('test_view');
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('fields', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'display_as_link' => FALSE,
),
));
$this->executeView($view);
$this->assertEqual('John', $view->field['name']->advancedRender($view->result[0]));
// Make the url a link.
$view->destroy();
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('fields', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
),
));
$this->executeView($view);
$this->assertEqual(\Drupal::l('John', Url::fromUri('base:John'))->getGeneratedLink(), $view->field['name']->advancedRender($view->result[0]));
}
}

View file

@ -0,0 +1,216 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\filter\BooleanOperatorString
* handler.
*
* @group views
* @see \Drupal\views\Plugin\views\filter\BooleanOperatorString
*/
class FilterBooleanOperatorStringTest extends ViewsKernelTestBase {
/**
* The modules to enable for this test.
*
* @var array
*/
public static $modules = array('system');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* Map column names.
*
* @var array
*/
protected $columnMap = array(
'views_test_data_id' => 'id',
);
/**
* {@inheritdoc}
*/
protected function schemaDefinition() {
$schema = parent::schemaDefinition();
$schema['views_test_data']['fields']['status'] = array(
'description' => 'The status of this record',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
);
return $schema;
}
/**
* {@inheritdoc}
*/
protected function viewsData() {
$views_data = parent::viewsData();
$views_data['views_test_data']['status']['filter']['id'] = 'boolean_string';
return $views_data;
}
/**
* {@inheritdoc}
*/
protected function dataSet() {
$data = parent::dataSet();
foreach ($data as &$row) {
if ($row['status']) {
$row['status'] = 'Enabled';
}
else {
$row['status'] = '';
}
}
return $data;
}
/**
* Tests the BooleanOperatorString filter.
*/
public function testFilterBooleanOperatorString() {
$view = Views::getView('test_view');
$view->setDisplay();
// Add a the status boolean filter.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'status' => array(
'id' => 'status',
'field' => 'status',
'table' => 'views_test_data',
'value' => 0,
),
));
$this->executeView($view);
$expected_result = array(
array('id' => 2),
array('id' => 4),
);
$this->assertEqual(2, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
$view->setDisplay();
// Add the status boolean filter.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'status' => array(
'id' => 'status',
'field' => 'status',
'table' => 'views_test_data',
'value' => 1,
),
));
$this->executeView($view);
$expected_result = array(
array('id' => 1),
array('id' => 3),
array('id' => 5),
);
$this->assertEqual(3, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
}
/**
* Tests the Boolean filter with grouped exposed form enabled.
*/
public function testFilterGroupedExposed() {
$filters = $this->getGroupedExposedFilters();
$view = Views::getView('test_view');
$view->setExposedInput(array('status' => 1));
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('filters', $filters);
$this->executeView($view);
$expected_result = array(
array('id' => 1),
array('id' => 3),
array('id' => 5),
);
$this->assertEqual(3, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
$view->setExposedInput(array('status' => 2));
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('filters', $filters);
$this->executeView($view);
$expected_result = array(
array('id' => 2),
array('id' => 4),
);
$this->assertEqual(2, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
}
/**
* Provides grouped exposed filter configuration.
*
* @return array
* Returns the filter configuration for exposed filters.
*/
protected function getGroupedExposedFilters() {
$filters = array(
'status' => array(
'id' => 'status',
'table' => 'views_test_data',
'field' => 'status',
'relationship' => 'none',
'exposed' => TRUE,
'expose' => array(
'operator' => 'status_op',
'label' => 'status',
'identifier' => 'status',
),
'is_grouped' => TRUE,
'group_info' => array(
'label' => 'status',
'identifier' => 'status',
'default_group' => 'All',
'group_items' => array(
1 => array(
'title' => 'Active',
'operator' => '=',
'value' => '1',
),
2 => array(
'title' => 'Blocked',
'operator' => '=',
'value' => '0',
),
),
),
),
);
return $filters;
}
}

View file

@ -0,0 +1,218 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\filter\BooleanOperator handler.
*
* @group views
* @see \Drupal\views\Plugin\views\filter\BooleanOperator
*/
class FilterBooleanOperatorTest extends ViewsKernelTestBase {
/**
* The modules to enable for this test.
*
* @var array
*/
public static $modules = array('system');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* Map column names.
*
* @var array
*/
protected $columnMap = array(
'views_test_data_id' => 'id',
);
/**
* Tests the BooleanOperator filter.
*/
public function testFilterBooleanOperator() {
$view = Views::getView('test_view');
$view->setDisplay();
// Add a the status boolean filter.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'status' => array(
'id' => 'status',
'field' => 'status',
'table' => 'views_test_data',
'value' => 0,
),
));
$this->executeView($view);
$expected_result = array(
array('id' => 2),
array('id' => 4),
);
$this->assertEqual(2, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
$view->setDisplay();
// Add the status boolean filter.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'status' => array(
'id' => 'status',
'field' => 'status',
'table' => 'views_test_data',
'value' => 1,
),
));
$this->executeView($view);
$expected_result = array(
array('id' => 1),
array('id' => 3),
array('id' => 5),
);
$this->assertEqual(3, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
$view->setDisplay();
// Testing the same scenario but using the reverse status and operation.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'status' => array(
'id' => 'status',
'field' => 'status',
'table' => 'views_test_data',
'value' => 0,
'operator' => '!=',
),
));
$this->executeView($view);
$expected_result = array(
array('id' => 1),
array('id' => 3),
array('id' => 5),
);
$this->assertEqual(3, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
}
/**
* Tests the boolean filter with grouped exposed form enabled.
*/
public function testFilterGroupedExposed() {
$filters = $this->getGroupedExposedFilters();
$view = Views::getView('test_view');
$view->setExposedInput(array('status' => 1));
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('filters', $filters);
$this->executeView($view);
$expected_result = array(
array('id' => 1),
array('id' => 3),
array('id' => 5),
);
$this->assertEqual(3, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
$view->setExposedInput(array('status' => 2));
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('filters', $filters);
$this->executeView($view);
$expected_result = array(
array('id' => 2),
array('id' => 4),
);
$this->assertEqual(2, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
// Expecting the same results as for ['status' => 1].
$view->setExposedInput(['status' => 3]);
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('filters', $filters);
$this->executeView($view);
$expected_result = array(
array('id' => 1),
array('id' => 3),
array('id' => 5),
);
$this->assertEqual(3, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
}
/**
* Provides grouped exposed filter configuration.
*
* @return array
*/
protected function getGroupedExposedFilters() {
$filters = array(
'status' => array(
'id' => 'status',
'table' => 'views_test_data',
'field' => 'status',
'relationship' => 'none',
'exposed' => TRUE,
'expose' => array(
'operator' => 'status_op',
'label' => 'status',
'identifier' => 'status',
),
'is_grouped' => TRUE,
'group_info' => array(
'label' => 'status',
'identifier' => 'status',
'default_group' => 'All',
'group_items' => array(
1 => array(
'title' => 'Active',
'operator' => '=',
'value' => '1',
),
2 => array(
'title' => 'Blocked',
'operator' => '=',
'value' => '0',
),
// This group should return the same results as group 1, because it
// is the negation of group 2.
3 => array(
'title' => 'Active (reverse)',
'operator' => '!=',
'value' => '0',
),
),
),
),
);
return $filters;
}
}

View file

@ -0,0 +1,156 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the combine filter handler.
*
* @group views
*/
class FilterCombineTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* Map column names.
*
* @var array
*/
protected $columnMap = array(
'views_test_data_name' => 'name',
'views_test_data_job' => 'job',
);
public function testFilterCombineContains() {
$view = Views::getView('test_view');
$view->setDisplay();
$fields = $view->displayHandlers->get('default')->getOption('fields');
$view->displayHandlers->get('default')->overrideOption('fields', $fields + array(
'job' => array(
'id' => 'job',
'table' => 'views_test_data',
'field' => 'job',
'relationship' => 'none',
),
));
// Change the filtering.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'age' => array(
'id' => 'combine',
'table' => 'views',
'field' => 'combine',
'relationship' => 'none',
'operator' => 'contains',
'fields' => array(
'name',
'job',
),
'value' => 'ing',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
'job' => 'Singer',
),
array(
'name' => 'George',
'job' => 'Singer',
),
array(
'name' => 'Ringo',
'job' => 'Drummer',
),
array(
'name' => 'Ginger',
'job' => NULL,
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
/**
* Tests if the filter can handle removed fields.
*
* Tests the combined filter handler when a field overwrite is done
* and fields set in the combine filter are removed from the display
* but not from the combined filter settings.
*/
public function testFilterCombineContainsFieldsOverwritten() {
$view = Views::getView('test_view');
$view->setDisplay();
$fields = $view->displayHandlers->get('default')->getOption('fields');
$view->displayHandlers->get('default')->overrideOption('fields', $fields + array(
'job' => array(
'id' => 'job',
'table' => 'views_test_data',
'field' => 'job',
'relationship' => 'none',
),
));
// Change the filtering.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'age' => array(
'id' => 'combine',
'table' => 'views',
'field' => 'combine',
'relationship' => 'none',
'operator' => 'contains',
'fields' => array(
'name',
'job',
// Add a dummy field to the combined fields to simulate
// a removed or deleted field.
'dummy',
),
'value' => 'ing',
),
));
$this->executeView($view);
// Make sure this view will not get displayed.
$this->assertTrue($view->build_info['fail'], "View build has been marked as failed.");
// Make sure this view does not pass validation with the right error.
$errors = $view->validate();
$this->assertEqual(reset($errors['default']), t('Field %field set in %filter is not set in this display.', array('%field' => 'dummy', '%filter' => 'Global: Combine fields filter')));
}
/**
* Additional data to test the NULL issue.
*/
protected function dataSet() {
$data_set = parent::dataSet();
$data_set[] = array(
'name' => 'Ginger',
'age' => 25,
'job' => NULL,
'created' => gmmktime(0, 0, 0, 1, 2, 2000),
'status' => 1,
);
return $data_set;
}
/**
* Allow {views_test_data}.job to be NULL.
*/
protected function schemaDefinition() {
$schema = parent::schemaDefinition();
unset($schema['views_test_data']['fields']['job']['not null']);
return $schema;
}
}

View file

@ -0,0 +1,188 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\filter\Equality handler.
*
* @group views
*/
class FilterEqualityTest extends ViewsKernelTestBase {
public static $modules = array('system');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* Map column names.
*
* @var array
*/
protected $columnMap = array(
'views_test_data_name' => 'name',
);
function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['name']['filter']['id'] = 'equality';
return $data;
}
function testEqual() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'operator' => '=',
'value' => 'Ringo',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
public function testEqualGroupedExposed() {
$filters = $this->getGroupedExposedFilters();
$view = Views::getView('test_view');
$view->newDisplay('page', 'Page', 'page_1');
// Filter: Name, Operator: =, Value: Ringo
$filters['name']['group_info']['default_group'] = 1;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testNotEqual() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'operator' => '!=',
'value' => 'Ringo',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'George',
),
array(
'name' => 'Paul',
),
array(
'name' => 'Meredith',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
public function testEqualGroupedNotExposed() {
$filters = $this->getGroupedExposedFilters();
$view = Views::getView('test_view');
$view->newDisplay('page', 'Page', 'page_1');
// Filter: Name, Operator: !=, Value: Ringo
$filters['name']['group_info']['default_group'] = 2;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'George',
),
array(
'name' => 'Paul',
),
array(
'name' => 'Meredith',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
protected function getGroupedExposedFilters() {
$filters = array(
'name' => array(
'id' => 'name',
'plugin_id' => 'equality',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'group' => 1,
'exposed' => TRUE,
'expose' => array(
'operator' => 'name_op',
'label' => 'name',
'identifier' => 'name',
),
'is_grouped' => TRUE,
'group_info' => array(
'label' => 'name',
'identifier' => 'name',
'default_group' => 'All',
'group_items' => array(
1 => array(
'title' => 'Name is equal to Ringo',
'operator' => '=',
'value' => 'Ringo',
),
2 => array(
'title' => 'Name is not equal to Ringo',
'operator' => '!=',
'value' => 'Ringo',
),
),
),
),
);
return $filters;
}
}

View file

@ -0,0 +1,198 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\filter\InOperator handler.
*
* @group views
*/
class FilterInOperatorTest extends ViewsKernelTestBase {
public static $modules = array('system');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* Map column names.
*
* @var array
*/
protected $columnMap = array(
'views_test_data_name' => 'name',
'views_test_data_age' => 'age',
);
function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['age']['filter']['id'] = 'in_operator';
return $data;
}
public function testFilterInOperatorSimple() {
$view = Views::getView('test_view');
$view->setDisplay();
// Add a in_operator ordering.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'age' => array(
'id' => 'age',
'field' => 'age',
'table' => 'views_test_data',
'value' => array(26, 30),
'operator' => 'in',
),
));
$this->executeView($view);
$expected_result = array(
array(
'name' => 'Paul',
'age' => 26,
),
array(
'name' => 'Meredith',
'age' => 30,
),
);
$this->assertEqual(2, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
$view->setDisplay();
// Add a in_operator ordering.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'age' => array(
'id' => 'age',
'field' => 'age',
'table' => 'views_test_data',
'value' => array(26, 30),
'operator' => 'not in',
),
));
$this->executeView($view);
$expected_result = array(
array(
'name' => 'John',
'age' => 25,
),
array(
'name' => 'George',
'age' => 27,
),
array(
'name' => 'Ringo',
'age' => 28,
),
);
$this->assertEqual(3, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
}
public function testFilterInOperatorGroupedExposedSimple() {
$filters = $this->getGroupedExposedFilters();
$view = Views::getView('test_view');
// Filter: Age, Operator: in, Value: 26, 30
$filters['age']['group_info']['default_group'] = 1;
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('filters', $filters);
$this->executeView($view);
$expected_result = array(
array(
'name' => 'Paul',
'age' => 26,
),
array(
'name' => 'Meredith',
'age' => 30,
),
);
$this->assertEqual(2, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
}
public function testFilterNotInOperatorGroupedExposedSimple() {
$filters = $this->getGroupedExposedFilters();
$view = Views::getView('test_view');
// Filter: Age, Operator: in, Value: 26, 30
$filters['age']['group_info']['default_group'] = 2;
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('filters', $filters);
$this->executeView($view);
$expected_result = array(
array(
'name' => 'John',
'age' => 25,
),
array(
'name' => 'George',
'age' => 27,
),
array(
'name' => 'Ringo',
'age' => 28,
),
);
$this->assertEqual(3, count($view->result));
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
}
protected function getGroupedExposedFilters() {
$filters = array(
'age' => array(
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
'exposed' => TRUE,
'expose' => array(
'operator' => 'age_op',
'label' => 'age',
'identifier' => 'age',
),
'is_grouped' => TRUE,
'group_info' => array(
'label' => 'age',
'identifier' => 'age',
'default_group' => 'All',
'group_items' => array(
1 => array(
'title' => 'Age is one of 26, 30',
'operator' => 'in',
'value' => array(26, 30),
),
2 => array(
'title' => 'Age is not one of 26, 30',
'operator' => 'not in',
'value' => array(26, 30),
),
),
),
),
);
return $filters;
}
}

View file

@ -0,0 +1,425 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the numeric filter handler.
*
* @group views
*/
class FilterNumericTest extends ViewsKernelTestBase {
public static $modules = array('system');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* Map column names.
*
* @var array
*/
protected $columnMap = array(
'views_test_data_name' => 'name',
'views_test_data_age' => 'age',
);
function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['age']['filter']['allow empty'] = TRUE;
$data['views_test_data']['id']['filter']['allow empty'] = FALSE;
return $data;
}
public function testFilterNumericSimple() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'age' => array(
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
'operator' => '=',
'value' => array('value' => 28),
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'Ringo',
'age' => 28,
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
public function testFilterNumericExposedGroupedSimple() {
$filters = $this->getGroupedExposedFilters();
$view = Views::getView('test_view');
$view->newDisplay('page', 'Page', 'page_1');
// Filter: Age, Operator: =, Value: 28
$filters['age']['group_info']['default_group'] = 1;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'Ringo',
'age' => 28,
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
public function testFilterNumericBetween() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'age' => array(
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
'operator' => 'between',
'value' => array(
'min' => 26,
'max' => 29,
),
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'George',
'age' => 27,
),
array(
'name' => 'Ringo',
'age' => 28,
),
array(
'name' => 'Paul',
'age' => 26,
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
// test not between
$view->destroy();
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'age' => array(
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
'operator' => 'not between',
'value' => array(
'min' => 26,
'max' => 29,
),
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
'age' => 25,
),
array(
'name' => 'Paul',
'age' => 26,
),
array(
'name' => 'Meredith',
'age' => 30,
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
public function testFilterNumericExposedGroupedBetween() {
$filters = $this->getGroupedExposedFilters();
$view = Views::getView('test_view');
$view->newDisplay('page', 'Page', 'page_1');
// Filter: Age, Operator: between, Value: 26 and 29
$filters['age']['group_info']['default_group'] = 2;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'George',
'age' => 27,
),
array(
'name' => 'Ringo',
'age' => 28,
),
array(
'name' => 'Paul',
'age' => 26,
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
public function testFilterNumericExposedGroupedNotBetween() {
$filters = $this->getGroupedExposedFilters();
$view = Views::getView('test_view');
$view->newDisplay('page', 'Page', 'page_1');
// Filter: Age, Operator: between, Value: 26 and 29
$filters['age']['group_info']['default_group'] = 3;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
'age' => 25,
),
array(
'name' => 'Paul',
'age' => 26,
),
array(
'name' => 'Meredith',
'age' => 30,
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
public function testFilterNumericEmpty() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'age' => array(
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
'operator' => 'empty',
),
));
$this->executeView($view);
$resultset = array(
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
$view->destroy();
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'age' => array(
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
'operator' => 'not empty',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
'age' => 25,
),
array(
'name' => 'George',
'age' => 27,
),
array(
'name' => 'Ringo',
'age' => 28,
),
array(
'name' => 'Paul',
'age' => 26,
),
array(
'name' => 'Meredith',
'age' => 30,
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
public function testFilterNumericExposedGroupedEmpty() {
$filters = $this->getGroupedExposedFilters();
$view = Views::getView('test_view');
$view->newDisplay('page', 'Page', 'page_1');
// Filter: Age, Operator: empty, Value:
$filters['age']['group_info']['default_group'] = 4;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
public function testFilterNumericExposedGroupedNotEmpty() {
$filters = $this->getGroupedExposedFilters();
$view = Views::getView('test_view');
$view->newDisplay('page', 'Page', 'page_1');
// Filter: Age, Operator: empty, Value:
$filters['age']['group_info']['default_group'] = 5;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
'age' => 25,
),
array(
'name' => 'George',
'age' => 27,
),
array(
'name' => 'Ringo',
'age' => 28,
),
array(
'name' => 'Paul',
'age' => 26,
),
array(
'name' => 'Meredith',
'age' => 30,
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
public function testAllowEmpty() {
$view = Views::getView('test_view');
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('filters', array(
'id' => array(
'id' => 'id',
'table' => 'views_test_data',
'field' => 'id',
'relationship' => 'none',
),
'age' => array(
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
),
));
$view->initHandlers();
$id_operators = $view->filter['id']->operators();
$age_operators = $view->filter['age']->operators();
$this->assertFalse(isset($id_operators['empty']));
$this->assertFalse(isset($id_operators['not empty']));
$this->assertTrue(isset($age_operators['empty']));
$this->assertTrue(isset($age_operators['not empty']));
}
protected function getGroupedExposedFilters() {
$filters = array(
'age' => array(
'id' => 'age',
'plugin_id' => 'numeric',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
'exposed' => TRUE,
'expose' => array(
'operator' => 'age_op',
'label' => 'age',
'identifier' => 'age',
),
'is_grouped' => TRUE,
'group_info' => array(
'label' => 'age',
'identifier' => 'age',
'default_group' => 'All',
'group_items' => array(
1 => array(
'title' => 'Age is 28',
'operator' => '=',
'value' => array('value' => 28),
),
2 => array(
'title' => 'Age is between 26 and 29',
'operator' => 'between',
'value' => array(
'min' => 26,
'max' => 29,
),
),
3 => array(
'title' => 'Age is not between 26 and 29',
'operator' => 'not between',
'value' => array(
'min' => 26,
'max' => 29,
),
),
4 => array(
'title' => 'Age is empty',
'operator' => 'empty',
),
5 => array(
'title' => 'Age is not empty',
'operator' => 'not empty',
),
),
),
),
);
return $filters;
}
}

View file

@ -0,0 +1,858 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the core Drupal\views\Plugin\views\filter\StringFilter handler.
*
* @group views
*/
class FilterStringTest extends ViewsKernelTestBase {
public static $modules = array('system');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* Map column names.
*
* @var array
*/
protected $columnMap = array(
'views_test_data_name' => 'name',
);
function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['name']['filter']['allow empty'] = TRUE;
$data['views_test_data']['job']['filter']['allow empty'] = FALSE;
$data['views_test_data']['description'] = $data['views_test_data']['name'];
return $data;
}
protected function schemaDefinition() {
$schema = parent::schemaDefinition();
$schema['views_test_data']['fields']['description'] = array(
'description' => "A person's description",
'type' => 'text',
'not null' => FALSE,
'size' => 'big',
);
return $schema;
}
/**
* An extended test dataset.
*/
protected function dataSet() {
$dataset = parent::dataSet();
$dataset[0]['description'] = 'John Winston Ono Lennon, MBE (9 October 1940 8 December 1980) was an English musician and singer-songwriter who rose to worldwide fame as one of the founding members of The Beatles, one of the most commercially successful and critically acclaimed acts in the history of popular music. Along with fellow Beatle Paul McCartney, he formed one of the most successful songwriting partnerships of the 20th century.';
$dataset[1]['description'] = 'George Harrison,[1] MBE (25 February 1943 29 November 2001)[2] was an English rock guitarist, singer-songwriter, actor and film producer who achieved international fame as lead guitarist of The Beatles.';
$dataset[2]['description'] = 'Richard Starkey, MBE (born 7 July 1940), better known by his stage name Ringo Starr, is an English musician, singer-songwriter, and actor who gained worldwide fame as the drummer for The Beatles.';
$dataset[3]['description'] = 'Sir James Paul McCartney, MBE (born 18 June 1942) is an English musician, singer-songwriter and composer. Formerly of The Beatles (19601970) and Wings (19711981), McCartney is the most commercially successful songwriter in the history of popular music, according to Guinness World Records.[1]';
$dataset[4]['description'] = NULL;
return $dataset;
}
/**
* Build and return a Page view of the views_test_data table.
*
* @return view
*/
protected function getBasicPageView() {
$view = Views::getView('test_view');
// In order to test exposed filters, we have to disable
// the exposed forms cache.
\Drupal::service('views.exposed_form_cache')->reset();
$view->newDisplay('page', 'Page', 'page_1');
return $view;
}
function testFilterStringEqual() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'operator' => '=',
'value' => 'Ringo',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedEqual() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Name, Operator: =, Value: Ringo
$filters['name']['group_info']['default_group'] = 1;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringNotEqual() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'operator' => '!=',
'value' => 'Ringo',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'George',
),
array(
'name' => 'Paul',
),
array(
'name' => 'Meredith',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedNotEqual() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Name, Operator: !=, Value: Ringo
$filters['name']['group_info']['default_group'] = '2';
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'George',
),
array(
'name' => 'Paul',
),
array(
'name' => 'Meredith',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringContains() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'operator' => 'contains',
'value' => 'ing',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedContains() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Name, Operator: contains, Value: ing
$filters['name']['group_info']['default_group'] = '3';
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringWord() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'description' => array(
'id' => 'description',
'table' => 'views_test_data',
'field' => 'description',
'relationship' => 'none',
'operator' => 'word',
'value' => 'actor',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'George',
),
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
$view->destroy();
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'description' => array(
'id' => 'description',
'table' => 'views_test_data',
'field' => 'description',
'relationship' => 'none',
'operator' => 'allwords',
'value' => 'Richard Starkey',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedWord() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Name, Operator: contains, Value: ing
$filters['name']['group_info']['default_group'] = '3';
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
$view->destroy();
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Description, Operator: contains, Value: actor
$filters['description']['group_info']['default_group'] = '1';
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$this->executeView($view);
$resultset = array(
array(
'name' => 'George',
),
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringStarts() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'description' => array(
'id' => 'description',
'table' => 'views_test_data',
'field' => 'description',
'relationship' => 'none',
'operator' => 'starts',
'value' => 'George',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'George',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedStarts() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Name, Operator: starts, Value: George
$filters['description']['group_info']['default_group'] = 2;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'George',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringNotStarts() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'description' => array(
'id' => 'description',
'table' => 'views_test_data',
'field' => 'description',
'relationship' => 'none',
'operator' => 'not_starts',
'value' => 'George',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'Ringo',
),
array(
'name' => 'Paul',
),
// There is no Meredith returned because his description is empty
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedNotStarts() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Name, Operator: not_starts, Value: George
$filters['description']['group_info']['default_group'] = 3;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'Ringo',
),
array(
'name' => 'Paul',
),
// There is no Meredith returned because his description is empty
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringEnds() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'description' => array(
'id' => 'description',
'table' => 'views_test_data',
'field' => 'description',
'relationship' => 'none',
'operator' => 'ends',
'value' => 'Beatles.',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'George',
),
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedEnds() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Description, Operator: ends, Value: Beatles
$filters['description']['group_info']['default_group'] = 4;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'George',
),
array(
'name' => 'Ringo',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringNotEnds() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'description' => array(
'id' => 'description',
'table' => 'views_test_data',
'field' => 'description',
'relationship' => 'none',
'operator' => 'not_ends',
'value' => 'Beatles.',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'Paul',
),
// There is no Meredith returned because his description is empty
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedNotEnds() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Description, Operator: not_ends, Value: Beatles
$filters['description']['group_info']['default_group'] = 5;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'Paul',
),
// There is no Meredith returned because his description is empty
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringNot() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'description' => array(
'id' => 'description',
'table' => 'views_test_data',
'field' => 'description',
'relationship' => 'none',
'operator' => 'not',
'value' => 'Beatles.',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'Paul',
),
// There is no Meredith returned because his description is empty
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedNot() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Description, Operator: not (does not contains), Value: Beatles
$filters['description']['group_info']['default_group'] = 6;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'Paul',
),
// There is no Meredith returned because his description is empty
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringShorter() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'operator' => 'shorterthan',
'value' => 5,
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'Paul',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedShorter() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Name, Operator: shorterthan, Value: 5
$filters['name']['group_info']['default_group'] = 4;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'John',
),
array(
'name' => 'Paul',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringLonger() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'operator' => 'longerthan',
'value' => 7,
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'Meredith',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedLonger() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Name, Operator: longerthan, Value: 4
$filters['name']['group_info']['default_group'] = 5;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'Meredith',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringEmpty() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the filtering
$view->displayHandlers->get('default')->overrideOption('filters', array(
'description' => array(
'id' => 'description',
'table' => 'views_test_data',
'field' => 'description',
'relationship' => 'none',
'operator' => 'empty',
),
));
$this->executeView($view);
$resultset = array(
array(
'name' => 'Meredith',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
function testFilterStringGroupedExposedEmpty() {
$filters = $this->getGroupedExposedFilters();
$view = $this->getBasicPageView();
// Filter: Description, Operator: empty, Value:
$filters['description']['group_info']['default_group'] = 7;
$view->setDisplay('page_1');
$view->displayHandlers->get('page_1')->overrideOption('filters', $filters);
$view->save();
$this->container->get('router.builder')->rebuild();
$this->executeView($view);
$resultset = array(
array(
'name' => 'Meredith',
),
);
$this->assertIdenticalResultset($view, $resultset, $this->columnMap);
}
protected function getGroupedExposedFilters() {
$filters = array(
'name' => array(
'id' => 'name',
'plugin_id' => 'string',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
'exposed' => TRUE,
'expose' => array(
'operator' => 'name_op',
'label' => 'name',
'identifier' => 'name',
),
'is_grouped' => TRUE,
'group_info' => array(
'label' => 'name',
'identifier' => 'name',
'default_group' => 'All',
'group_items' => array(
1 => array(
'title' => 'Is Ringo',
'operator' => '=',
'value' => 'Ringo',
),
2 => array(
'title' => 'Is not Ringo',
'operator' => '!=',
'value' => 'Ringo',
),
3 => array(
'title' => 'Contains ing',
'operator' => 'contains',
'value' => 'ing',
),
4 => array(
'title' => 'Shorter than 5 letters',
'operator' => 'shorterthan',
'value' => 5,
),
5 => array(
'title' => 'Longer than 7 letters',
'operator' => 'longerthan',
'value' => 7,
),
),
),
),
'description' => array(
'id' => 'description',
'plugin_id' => 'string',
'table' => 'views_test_data',
'field' => 'description',
'relationship' => 'none',
'exposed' => TRUE,
'expose' => array(
'operator' => 'description_op',
'label' => 'description',
'identifier' => 'description',
),
'is_grouped' => TRUE,
'group_info' => array(
'label' => 'description',
'identifier' => 'description',
'default_group' => 'All',
'group_items' => array(
1 => array(
'title' => 'Contains the word: Actor',
'operator' => 'word',
'value' => 'actor',
),
2 => array(
'title' => 'Starts with George',
'operator' => 'starts',
'value' => 'George',
),
3 => array(
'title' => 'Not Starts with: George',
'operator' => 'not_starts',
'value' => 'George',
),
4 => array(
'title' => 'Ends with: Beatles',
'operator' => 'ends',
'value' => 'Beatles.',
),
5 => array(
'title' => 'Not Ends with: Beatles',
'operator' => 'not_ends',
'value' => 'Beatles.',
),
6 => array(
'title' => 'Does not contain: Beatles',
'operator' => 'not',
'value' => 'Beatles.',
),
7 => array(
'title' => 'Empty description',
'operator' => 'empty',
'value' => '',
),
),
),
),
);
return $filters;
}
}

View file

@ -0,0 +1,84 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests handler table and field aliases.
*
* @group views
*/
class HandlerAliasTest extends ViewsKernelTestBase {
public static $modules = array('user');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_filter', 'test_alias');
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->installEntitySchema('user');
}
/**
* {@inheritdoc}
*/
protected function viewsData() {
$data = parent::viewsData();
// User the existing test_filter plugin.
$data['views_test_data_alias']['table']['real table'] = 'views_test_data';
$data['views_test_data_alias']['name_alias']['filter']['id'] = 'test_filter';
$data['views_test_data_alias']['name_alias']['filter']['real field'] = 'name';
return $data;
}
public function testPluginAliases() {
$view = Views::getView('test_filter');
$view->initDisplay();
// Change the filtering.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'test_filter' => array(
'id' => 'test_filter',
'table' => 'views_test_data_alias',
'field' => 'name_alias',
'operator' => '=',
'value' => 'John',
'group' => 0,
),
));
$this->executeView($view);
$filter = $view->filter['test_filter'];
// Check the definition values are present.
$this->assertIdentical($filter->definition['real table'], 'views_test_data');
$this->assertIdentical($filter->definition['real field'], 'name');
$this->assertIdentical($filter->table, 'views_test_data');
$this->assertIdentical($filter->realField, 'name');
// Test an existing user uid field.
$view = Views::getView('test_alias');
$view->initDisplay();
$this->executeView($view);
$filter = $view->filter['uid_raw'];
$this->assertIdentical($filter->definition['real field'], 'uid');
$this->assertIdentical($filter->field, 'uid_raw');
$this->assertIdentical($filter->table, 'users_field_data');
$this->assertIdentical($filter->realField, 'uid');
}
}

View file

@ -0,0 +1,203 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests for core Drupal\views\Plugin\views\sort\Date handler.
*
* @group views
*/
class SortDateTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
protected function expectedResultSet($granularity, $reverse = TRUE) {
$expected = array();
if (!$reverse) {
switch ($granularity) {
case 'second':
$expected = array(
array('name' => 'John'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
array('name' => 'Ringo'),
array('name' => 'George'),
);
break;
case 'minute':
$expected = array(
array('name' => 'John'),
array('name' => 'Paul'),
array('name' => 'Ringo'),
array('name' => 'Meredith'),
array('name' => 'George'),
);
break;
case 'hour':
$expected = array(
array('name' => 'John'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
array('name' => 'George'),
);
break;
case 'day':
$expected = array(
array('name' => 'John'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
array('name' => 'George'),
);
break;
case 'month':
$expected = array(
array('name' => 'John'),
array('name' => 'George'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
);
break;
case 'year':
$expected = array(
array('name' => 'John'),
array('name' => 'George'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
);
break;
}
}
else {
switch ($granularity) {
case 'second':
$expected = array(
array('name' => 'George'),
array('name' => 'Ringo'),
array('name' => 'Meredith'),
array('name' => 'Paul'),
array('name' => 'John'),
);
break;
case 'minute':
$expected = array(
array('name' => 'George'),
array('name' => 'Ringo'),
array('name' => 'Meredith'),
array('name' => 'Paul'),
array('name' => 'John'),
);
break;
case 'hour':
$expected = array(
array('name' => 'George'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
array('name' => 'John'),
);
break;
case 'day':
$expected = array(
array('name' => 'George'),
array('name' => 'John'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
);
break;
case 'month':
$expected = array(
array('name' => 'John'),
array('name' => 'George'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
);
break;
case 'year':
$expected = array(
array('name' => 'John'),
array('name' => 'George'),
array('name' => 'Ringo'),
array('name' => 'Paul'),
array('name' => 'Meredith'),
);
break;
}
}
return $expected;
}
/**
* Tests numeric ordering of the result set.
*/
public function testDateOrdering() {
foreach (array('second', 'minute', 'hour', 'day', 'month', 'year') as $granularity) {
foreach (array(FALSE, TRUE) as $reverse) {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the fields.
$view->displayHandlers->get('default')->overrideOption('fields', array(
'name' => array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
),
'created' => array(
'id' => 'created',
'table' => 'views_test_data',
'field' => 'created',
'relationship' => 'none',
),
));
// Change the ordering
$view->displayHandlers->get('default')->overrideOption('sorts', array(
'created' => array(
'id' => 'created',
'table' => 'views_test_data',
'field' => 'created',
'relationship' => 'none',
'granularity' => $granularity,
'order' => $reverse ? 'DESC' : 'ASC',
),
'id' => array(
'id' => 'id',
'table' => 'views_test_data',
'field' => 'id',
'relationship' => 'none',
'order' => 'ASC',
),
));
// Execute the view.
$this->executeView($view);
// Verify the result.
$this->assertEqual(count($this->dataSet()), count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultset($view, $this->expectedResultSet($granularity, $reverse), array(
'views_test_data_name' => 'name',
), SafeMarkup::format('Result is returned correctly when ordering by granularity @granularity, @reverse.', array('@granularity' => $granularity, '@reverse' => $reverse ? 'reverse' : 'forward')));
$view->destroy();
unset($view);
}
}
}
}

View file

@ -0,0 +1,139 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Core\Cache\Cache;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests for core Drupal\views\Plugin\views\sort\Random handler.
*
* @group views
*/
class SortRandomTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* Add more items to the test set, to make the order tests more robust.
*
* In total we have then 60 entries, which makes a probability of a collision
* of 1/60!, which is around 1/1E80, which is higher than the estimated amount
* of protons / electrons in the observable universe, also called the
* eddington number.
*
* @see http://wikipedia.org/wiki/Eddington_number
*/
protected function dataSet() {
$data = parent::dataSet();
for ($i = 0; $i < 55; $i++) {
$data[] = array(
'name' => 'name_' . $i,
'age' => $i,
'job' => 'job_' . $i,
'created' => rand(0, time()),
'status' => 1,
);
}
return $data;
}
/**
* Return a basic view with random ordering.
*/
protected function getBasicRandomView() {
$view = Views::getView('test_view');
$view->setDisplay();
// Add a random ordering.
$view->displayHandlers->get('default')->overrideOption('sorts', array(
'random' => array(
'id' => 'random',
'field' => 'random',
'table' => 'views',
),
));
return $view;
}
/**
* Tests random ordering of the result set.
*
* @see DatabaseSelectTestCase::testRandomOrder()
*/
public function testRandomOrdering() {
// Execute a basic view first.
$view = Views::getView('test_view');
$this->executeView($view);
// Verify the result.
$this->assertEqual(count($this->dataSet()), count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultset($view, $this->dataSet(), array(
'views_test_data_name' => 'name',
'views_test_data_age' => 'age',
));
// Execute a random view, we expect the result set to be different.
$view_random = $this->getBasicRandomView();
$this->executeView($view_random);
$this->assertEqual(count($this->dataSet()), count($view_random->result), 'The number of returned rows match.');
$this->assertNotIdenticalResultset($view_random, $view->result, array(
'views_test_data_name' => 'views_test_data_name',
'views_test_data_age' => 'views_test_data_name',
));
// Execute a second random view, we expect the result set to be different again.
$view_random_2 = $this->getBasicRandomView();
$this->executeView($view_random_2);
$this->assertEqual(count($this->dataSet()), count($view_random_2->result), 'The number of returned rows match.');
$this->assertNotIdenticalResultset($view_random, $view->result, array(
'views_test_data_name' => 'views_test_data_name',
'views_test_data_age' => 'views_test_data_name',
));
}
/**
* Tests random ordering with tags based caching.
*
* The random sorting should opt out of caching by defining a max age of 0.
* At the same time, the row render caching still works.
*/
public function testRandomOrderingWithRenderCaching() {
$view_random = $this->getBasicRandomView();
$display = &$view_random->storage->getDisplay('default');
$display['display_options']['cache'] = [
'type' => 'tag',
];
$view_random->storage->save();
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
/** @var \Drupal\Core\Render\RenderCacheInterface $render_cache */
$render_cache = \Drupal::service('render_cache');
$original = $build = DisplayPluginBase::buildBasicRenderable($view_random->id(), 'default');
$result = $renderer->renderPlain($build);
$original['#cache'] += ['contexts' => []];
$original['#cache']['contexts'] = Cache::mergeContexts($original['#cache']['contexts'], $this->container->getParameter('renderer.config')['required_cache_contexts']);
$this->assertFalse($render_cache->get($original), 'Ensure there is no render cache entry.');
$build = DisplayPluginBase::buildBasicRenderable($view_random->id(), 'default');
$result2 = $renderer->renderPlain($build);
// Ensure that the random ordering works and don't produce the same result.
$this->assertNotEqual($result, $result2);
}
}

View file

@ -0,0 +1,128 @@
<?php
namespace Drupal\Tests\views\Kernel\Handler;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests for core Drupal\views\Plugin\views\sort\SortPluginBase handler.
*
* @group views
*/
class SortTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* Tests numeric ordering of the result set.
*/
public function testNumericOrdering() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the ordering
$view->displayHandlers->get('default')->overrideOption('sorts', array(
'age' => array(
'order' => 'ASC',
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
),
));
// Execute the view.
$this->executeView($view);
// Verify the result.
$this->assertEqual(count($this->dataSet()), count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultset($view, $this->orderResultSet($this->dataSet(), 'age'), array(
'views_test_data_name' => 'name',
'views_test_data_age' => 'age',
));
$view->destroy();
$view->setDisplay();
// Reverse the ordering
$view->displayHandlers->get('default')->overrideOption('sorts', array(
'age' => array(
'order' => 'DESC',
'id' => 'age',
'table' => 'views_test_data',
'field' => 'age',
'relationship' => 'none',
),
));
// Execute the view.
$this->executeView($view);
// Verify the result.
$this->assertEqual(count($this->dataSet()), count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultset($view, $this->orderResultSet($this->dataSet(), 'age', TRUE), array(
'views_test_data_name' => 'name',
'views_test_data_age' => 'age',
));
}
/**
* Tests string ordering of the result set.
*/
public function testStringOrdering() {
$view = Views::getView('test_view');
$view->setDisplay();
// Change the ordering
$view->displayHandlers->get('default')->overrideOption('sorts', array(
'name' => array(
'order' => 'ASC',
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
),
));
// Execute the view.
$this->executeView($view);
// Verify the result.
$this->assertEqual(count($this->dataSet()), count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultset($view, $this->orderResultSet($this->dataSet(), 'name'), array(
'views_test_data_name' => 'name',
'views_test_data_age' => 'age',
));
$view->destroy();
$view->setDisplay();
// Reverse the ordering
$view->displayHandlers->get('default')->overrideOption('sorts', array(
'name' => array(
'order' => 'DESC',
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'relationship' => 'none',
),
));
// Execute the view.
$this->executeView($view);
// Verify the result.
$this->assertEqual(count($this->dataSet()), count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultset($view, $this->orderResultSet($this->dataSet(), 'name', TRUE), array(
'views_test_data_name' => 'name',
'views_test_data_age' => 'age',
));
}
}

View file

@ -0,0 +1,369 @@
<?php
namespace Drupal\Tests\views\Kernel;
/**
* Tests basic functions from the Views module.
*
* @group views
*/
use Drupal\views\Plugin\views\filter\Standard;
use Drupal\views\Views;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
class ModuleTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view_status', 'test_view', 'test_argument');
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['field', 'user', 'block'];
/**
* Stores the last triggered error, for example via debug().
*
* @var string
*
* @see \Drupal\views\Tests\ModuleTest::errorHandler()
*/
protected $lastErrorMessage;
/**
* Tests the views_get_handler method.
*
* @see views_get_handler()
*/
public function testViewsGetHandler() {
$types = array('field', 'area', 'filter');
foreach ($types as $type) {
$item = array(
'table' => $this->randomMachineName(),
'field' => $this->randomMachineName(),
);
$handler = $this->container->get('plugin.manager.views.' . $type)->getHandler($item);
$this->assertEqual('Drupal\views\Plugin\views\\' . $type . '\Broken', get_class($handler), new FormattableMarkup('Make sure that a broken handler of type: @type is created.', ['@type' => $type]));
}
$views_data = $this->viewsData();
$test_tables = array('views_test_data' => array('id', 'name'));
foreach ($test_tables as $table => $fields) {
foreach ($fields as $field) {
$data = $views_data[$table][$field];
$item = array(
'table' => $table,
'field' => $field,
);
foreach ($data as $id => $field_data) {
if (!in_array($id, array('title', 'help'))) {
$handler = $this->container->get('plugin.manager.views.' . $id)->getHandler($item);
$this->assertInstanceHandler($handler, $table, $field, $id);
}
}
}
}
// Test the override handler feature.
$item = array(
'table' => 'views_test_data',
'field' => 'job',
);
$handler = $this->container->get('plugin.manager.views.filter')->getHandler($item, 'standard');
$this->assertTrue($handler instanceof Standard);
// @todo Reinstate these tests when the debug() in views_get_handler() is
// restored.
return;
// Test non-existent tables/fields.
set_error_handler(array($this, 'customErrorHandler'));
$item = array(
'table' => 'views_test_data',
'field' => 'field_invalid',
);
$this->container->get('plugin.manager.views.field')->getHandler($item);
$this->assertTrue(strpos($this->lastErrorMessage, format_string("Missing handler: @table @field @type", array('@table' => 'views_test_data', '@field' => 'field_invalid', '@type' => 'field'))) !== FALSE, 'An invalid field name throws a debug message.');
unset($this->lastErrorMessage);
$item = array(
'table' => 'table_invalid',
'field' => 'id',
);
$this->container->get('plugin.manager.views.filter')->getHandler($item);
$this->assertEqual(strpos($this->lastErrorMessage, format_string("Missing handler: @table @field @type", array('@table' => 'table_invalid', '@field' => 'id', '@type' => 'filter'))) !== FALSE, 'An invalid table name throws a debug message.');
unset($this->lastErrorMessage);
$item = array(
'table' => 'table_invalid',
'field' => 'id',
);
$this->container->get('plugin.manager.views.filter')->getHandler($item);
$this->assertEqual(strpos($this->lastErrorMessage, format_string("Missing handler: @table @field @type", array('@table' => 'table_invalid', '@field' => 'id', '@type' => 'filter'))) !== FALSE, 'An invalid table name throws a debug message.');
unset($this->lastErrorMessage);
restore_error_handler();
}
/**
* Defines an error handler which is used in the test.
*
* @param int $error_level
* The level of the error raised.
* @param string $message
* The error message.
* @param string $filename
* The filename that the error was raised in.
* @param int $line
* The line number the error was raised at.
* @param array $context
* An array that points to the active symbol table at the point the error
* occurred.
*
* Because this is registered in set_error_handler(), it has to be public.
* @see set_error_handler()
*/
public function customErrorHandler($error_level, $message, $filename, $line, $context) {
$this->lastErrorMessage = $message;
}
/**
* Tests the load wrapper/helper functions.
*/
public function testLoadFunctions() {
$this->enableModules(array('text', 'node'));
$this->installConfig(array('node'));
$storage = $this->container->get('entity.manager')->getStorage('view');
// Test views_view_is_enabled/disabled.
$archive = $storage->load('archive');
$this->assertTrue(views_view_is_disabled($archive), 'views_view_is_disabled works as expected.');
// Enable the view and check this.
$archive->enable();
$this->assertTrue(views_view_is_enabled($archive), ' views_view_is_enabled works as expected.');
// We can store this now, as we have enabled/disabled above.
$all_views = $storage->loadMultiple();
// Test Views::getAllViews().
ksort($all_views);
$this->assertEquals(array_keys($all_views), array_keys(Views::getAllViews()), 'Views::getAllViews works as expected.');
// Test Views::getEnabledViews().
$expected_enabled = array_filter($all_views, function($view) {
return views_view_is_enabled($view);
});
$this->assertEquals(array_keys($expected_enabled), array_keys(Views::getEnabledViews()), 'Expected enabled views returned.');
// Test Views::getDisabledViews().
$expected_disabled = array_filter($all_views, function($view) {
return views_view_is_disabled($view);
});
$this->assertEquals(array_keys($expected_disabled), array_keys(Views::getDisabledViews()), 'Expected disabled views returned.');
// Test Views::getViewsAsOptions().
// Test the $views_only parameter.
$this->assertIdentical(array_keys($all_views), array_keys(Views::getViewsAsOptions(TRUE)), 'Expected option keys for all views were returned.');
$expected_options = array();
foreach ($all_views as $id => $view) {
$expected_options[$id] = $view->label();
}
$this->assertIdentical($expected_options, $this->castSafeStrings(Views::getViewsAsOptions(TRUE)), 'Expected options array was returned.');
// Test the default.
$this->assertIdentical($this->formatViewOptions($all_views), $this->castSafeStrings(Views::getViewsAsOptions()), 'Expected options array for all views was returned.');
// Test enabled views.
$this->assertIdentical($this->formatViewOptions($expected_enabled), $this->castSafeStrings(Views::getViewsAsOptions(FALSE, 'enabled')), 'Expected enabled options array was returned.');
// Test disabled views.
$this->assertIdentical($this->formatViewOptions($expected_disabled), $this->castSafeStrings(Views::getViewsAsOptions(FALSE, 'disabled')), 'Expected disabled options array was returned.');
// Test the sort parameter.
$all_views_sorted = $all_views;
ksort($all_views_sorted);
$this->assertIdentical(array_keys($all_views_sorted), array_keys(Views::getViewsAsOptions(TRUE, 'all', NULL, FALSE, TRUE)), 'All view id keys returned in expected sort order');
// Test $exclude_view parameter.
$this->assertFalse(array_key_exists('archive', Views::getViewsAsOptions(TRUE, 'all', 'archive')), 'View excluded from options based on name');
$this->assertFalse(array_key_exists('archive:default', Views::getViewsAsOptions(FALSE, 'all', 'archive:default')), 'View display excluded from options based on name');
$this->assertFalse(array_key_exists('archive', Views::getViewsAsOptions(TRUE, 'all', $archive->getExecutable())), 'View excluded from options based on object');
// Test the $opt_group parameter.
$expected_opt_groups = array();
foreach ($all_views as $view) {
foreach ($view->get('display') as $display) {
$expected_opt_groups[$view->id()][$view->id() . ':' . $display['id']] = (string) t('@view : @display', array('@view' => $view->id(), '@display' => $display['id']));
}
}
$this->assertIdentical($expected_opt_groups, $this->castSafeStrings(Views::getViewsAsOptions(FALSE, 'all', NULL, TRUE)), 'Expected option array for an option group returned.');
}
/**
* Tests view enable and disable procedural wrapper functions.
*/
function testStatusFunctions() {
$view = Views::getView('test_view_status')->storage;
$this->assertFalse($view->status(), 'The view status is disabled.');
views_enable_view($view);
$this->assertTrue($view->status(), 'A view has been enabled.');
$this->assertEqual($view->status(), views_view_is_enabled($view), 'views_view_is_enabled is correct.');
views_disable_view($view);
$this->assertFalse($view->status(), 'A view has been disabled.');
$this->assertEqual(!$view->status(), views_view_is_disabled($view), 'views_view_is_disabled is correct.');
}
/**
* Tests the \Drupal\views\Views::fetchPluginNames() method.
*/
public function testViewsFetchPluginNames() {
// All style plugins should be returned, as we have not specified a type.
$plugins = Views::fetchPluginNames('style');
$definitions = $this->container->get('plugin.manager.views.style')->getDefinitions();
$expected = array();
foreach ($definitions as $id =>$definition) {
$expected[$id] = $definition['title'];
}
asort($expected);
$this->assertIdentical(array_keys($plugins), array_keys($expected));
// Test using the 'test' style plugin type only returns the test_style and
// mapping_test plugins.
$plugins = Views::fetchPluginNames('style', 'test');
$this->assertIdentical(array_keys($plugins), array('mapping_test', 'test_style', 'test_template_style'));
// Test a non existent style plugin type returns no plugins.
$plugins = Views::fetchPluginNames('style', $this->randomString());
$this->assertIdentical($plugins, array());
}
/**
* Tests the \Drupal\views\Views::pluginList() method.
*/
public function testViewsPluginList() {
$plugin_list = Views::pluginList();
// Only plugins used by 'test_view' should be in the plugin list.
foreach (array('display:default', 'pager:none') as $key) {
list($plugin_type, $plugin_id) = explode(':', $key);
$plugin_def = $this->container->get("plugin.manager.views.$plugin_type")->getDefinition($plugin_id);
$this->assertTrue(isset($plugin_list[$key]), SafeMarkup::format('The expected @key plugin list key was found.', array('@key' => $key)));
$plugin_details = $plugin_list[$key];
$this->assertEqual($plugin_details['type'], $plugin_type, 'The expected plugin type was found.');
$this->assertEqual($plugin_details['title'], $plugin_def['title'], 'The expected plugin title was found.');
$this->assertEqual($plugin_details['provider'], $plugin_def['provider'], 'The expected plugin provider was found.');
$this->assertTrue(in_array('test_view', $plugin_details['views']), 'The test_view View was found in the list of views using this plugin.');
}
}
/**
* Tests views.module: views_embed_view().
*/
public function testViewsEmbedView() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$result = views_embed_view('test_argument');
$renderer->renderPlain($result);
$this->assertEqual(count($result['view_build']['#view']->result), 5);
$result = views_embed_view('test_argument', 'default', 1);
$renderer->renderPlain($result);
$this->assertEqual(count($result['view_build']['#view']->result), 1);
$result = views_embed_view('test_argument', 'default', '1,2');
$renderer->renderPlain($result);
$this->assertEqual(count($result['view_build']['#view']->result), 2);
$result = views_embed_view('test_argument', 'default', '1,2', 'John');
$renderer->renderPlain($result);
$this->assertEqual(count($result['view_build']['#view']->result), 1);
$result = views_embed_view('test_argument', 'default', '1,2', 'John,George');
$renderer->renderPlain($result);
$this->assertEqual(count($result['view_build']['#view']->result), 2);
}
/**
* Tests the \Drupal\views\ViewsExecutable::preview() method.
*/
public function testViewsPreview() {
$view = Views::getView('test_argument');
$result = $view->preview('default');
$this->assertEqual(count($result['#view']->result), 5);
$view = Views::getView('test_argument');
$result = $view->preview('default', array('0' => 1));
$this->assertEqual(count($result['#view']->result), 1);
$view = Views::getView('test_argument');
$result = $view->preview('default', array('3' => 1));
$this->assertEqual(count($result['#view']->result), 1);
$view = Views::getView('test_argument');
$result = $view->preview('default', array('0' => '1,2'));
$this->assertEqual(count($result['#view']->result), 2);
$view = Views::getView('test_argument');
$result = $view->preview('default', array('3' => '1,2'));
$this->assertEqual(count($result['#view']->result), 2);
$view = Views::getView('test_argument');
$result = $view->preview('default', array('0' => '1,2', '1' => 'John'));
$this->assertEqual(count($result['#view']->result), 1);
$view = Views::getView('test_argument');
$result = $view->preview('default', array('3' => '1,2', '4' => 'John'));
$this->assertEqual(count($result['#view']->result), 1);
$view = Views::getView('test_argument');
$result = $view->preview('default', array('0' => '1,2', '1' => 'John,George'));
$this->assertEqual(count($result['#view']->result), 2);
$view = Views::getView('test_argument');
$result = $view->preview('default', array('3' => '1,2', '4' => 'John,George'));
$this->assertEqual(count($result['#view']->result), 2);
}
/**
* Helper to return an expected views option array.
*
* @param array $views
* An array of Drupal\views\Entity\View objects for which to
* create an options array.
*
* @return array
* A formatted options array that matches the expected output.
*/
protected function formatViewOptions(array $views = array()) {
$expected_options = array();
foreach ($views as $view) {
foreach ($view->get('display') as $display) {
$expected_options[$view->id() . ':' . $display['id']] = (string) t('View: @view - Display: @display',
array('@view' => $view->id(), '@display' => $display['id']));
}
}
return $expected_options;
}
/**
* Ensure that a certain handler is a instance of a certain table/field.
*/
function assertInstanceHandler($handler, $table, $field, $id) {
$table_data = $this->container->get('views.views_data')->get($table);
$field_data = $table_data[$field][$id];
$this->assertEqual($field_data['id'], $handler->getPluginId());
}
}

View file

@ -0,0 +1,65 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
use Drupal\views_test_data\Plugin\views\argument_validator\ArgumentValidatorTest as ArgumentValidatorTestPlugin;
/**
* Tests Views argument validators.
*
* @group views
*/
class ArgumentValidatorTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_view_argument_validate_numeric', 'test_view'];
function testArgumentValidateNumeric() {
$view = Views::getView('test_view_argument_validate_numeric');
$view->initHandlers();
$this->assertFalse($view->argument['null']->validateArgument($this->randomString()));
// Reset safed argument validation.
$view->argument['null']->argument_validated = NULL;
$this->assertTrue($view->argument['null']->validateArgument(12));
}
/**
* Tests the argument validator test plugin.
*
* @see Drupal\views_test_data\Plugin\views\argument_validator\ArgumentValidatorTest
*/
public function testArgumentValidatorPlugin() {
$view = Views::getView('test_view');
// Add a new argument and set the test plugin for the argument_validator.
$options = [
'specify_validation' => TRUE,
'validate' => [
'type' => 'argument_validator_test'
]
];
$id = $view->addHandler('default', 'argument', 'views_test_data', 'name', $options);
$view->initHandlers();
$test_value = $this->randomMachineName();
$argument = $view->argument[$id];
$argument->options['validate_options']['test_value'] = $test_value;
$this->assertFalse($argument->validateArgument($this->randomMachineName()), 'A random value does not validate.');
// Reset internal flag.
$argument->argument_validated = NULL;
$this->assertTrue($argument->validateArgument($test_value), 'The right argument validates.');
$plugin = $argument->getPlugin('argument_validator');
$this->assertTrue($plugin instanceof ArgumentValidatorTestPlugin, 'The correct argument validator plugin is used.');
$this->assertFalse($plugin->validateArgument($this->randomMachineName()), 'A random value does not validate.');
$this->assertTrue($plugin->validateArgument($test_value), 'The right argument validates.');
}
}

View file

@ -0,0 +1,110 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\block\Entity\Block;
/**
* Tests views block config dependencies functionality.
*
* @group views
*/
class BlockDependenciesTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_exposed_block');
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('node', 'block', 'user', 'field');
/**
* Tests that exposed filter blocks have the correct dependencies.
*
* @see \Drupal\views\Plugin\Derivative\ViewsExposedFilterBlock::getDerivativeDefinitions()
*/
public function testExposedBlock() {
$block = $this->createBlock('views_exposed_filter_block:test_exposed_block-page_1');
$dependencies = $block->calculateDependencies()->getDependencies();
$expected = array(
'config' => array('views.view.test_exposed_block'),
'module' => array('views'),
'theme' => array('stark')
);
$this->assertIdentical($expected, $dependencies);
}
/**
* Tests that exposed filter blocks have the correct dependencies.
*
* @see \Drupal\views\Plugin\Derivative\ViewsBlock::getDerivativeDefinitions()
*/
public function testViewsBlock() {
$block = $this->createBlock('views_block:content_recent-block_1');
$dependencies = $block->calculateDependencies()->getDependencies();
$expected = array(
'config' => array('views.view.content_recent'),
'module' => array('views'),
'theme' => array('stark')
);
$this->assertIdentical($expected, $dependencies);
}
/**
* Creates a block instance based on default settings.
*
* @param string $plugin_id
* The plugin ID of the block type for this block instance.
* @param array $settings
* (optional) An associative array of settings for the block entity.
* Override the defaults by specifying the key and value in the array, for
* example:
* @code
* $this->createBlock('system_powered_by_block', array(
* 'label' => t('Hello, world!'),
* ));
* @endcode
* The following defaults are provided:
* - label: Random string.
* - id: Random string.
* - region: 'sidebar_first'.
* - theme: The default theme.
* - visibility: Empty array.
*
* @return \Drupal\block\Entity\Block
* The block entity.
*/
protected function createBlock($plugin_id, array $settings = array()) {
$settings += array(
'plugin' => $plugin_id,
'region' => 'sidebar_first',
'id' => strtolower($this->randomMachineName(8)),
'theme' => $this->config('system.theme')->get('default'),
'label' => $this->randomMachineName(8),
'visibility' => array(),
'weight' => 0,
);
$values = [];
foreach (array('region', 'id', 'theme', 'plugin', 'weight', 'visibility') as $key) {
$values[$key] = $settings[$key];
// Remove extra values that do not belong in the settings array.
unset($settings[$key]);
}
foreach ($values['visibility'] as $id => $visibility) {
$values['visibility'][$id]['id'] = $id;
}
$values['settings'] = $settings;
$block = Block::create($values);
$block->save();
return $block;
}
}

View file

@ -0,0 +1,386 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\Core\Render\RenderContext;
use Drupal\node\Entity\Node;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
use Drupal\views_test_data\Plugin\views\filter\FilterTest as FilterPlugin;
/**
* Tests pluggable caching for views.
*
* @group views
* @see views_plugin_cache
*/
class CacheTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view', 'test_cache', 'test_groupwise_term_ui', 'test_display', 'test_filter');
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('taxonomy', 'text', 'user', 'node');
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->installEntitySchema('node');
$this->installEntitySchema('taxonomy_term');
$this->installEntitySchema('user');
// Setup the current time properly.
\Drupal::request()->server->set('REQUEST_TIME', time());
}
/**
* {@inheritdoc}
*/
protected function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['test_cache_context'] = [
'real field' => 'name',
'title' => 'Test cache context',
'filter' => [
'id' => 'views_test_test_cache_context',
],
];
return $data;
}
/**
* Tests time based caching.
*
* @see views_plugin_cache_time
*/
public function testTimeResultCaching() {
$view = Views::getView('test_cache');
$view->setDisplay();
$view->display_handler->overrideOption('cache', array(
'type' => 'time',
'options' => array(
'results_lifespan' => '3600',
'output_lifespan' => '3600',
)
));
// Test the default (non-paged) display.
$this->executeView($view);
// Verify the result.
$this->assertEqual(5, count($view->result), 'The number of returned rows match.');
// Add another man to the beatles.
$record = array(
'name' => 'Rod Davis',
'age' => 29,
'job' => 'Banjo',
);
db_insert('views_test_data')->fields($record)->execute();
// The result should be the same as before, because of the caching. (Note
// that views_test_data records don't have associated cache tags, and hence
// the results cache items aren't invalidated.)
$view->destroy();
$this->executeView($view);
// Verify the result.
$this->assertEqual(5, count($view->result), 'The number of returned rows match.');
}
/**
* Tests result caching with filters.
*
* @see views_plugin_cache_time
*/
public function testTimeResultCachingWithFilter() {
// Check that we can find the test filter plugin.
$plugin = $this->container->get('plugin.manager.views.filter')->createInstance('test_filter');
$this->assertTrue($plugin instanceof FilterPlugin, 'Test filter plugin found.');
$view = Views::getView('test_filter');
$view->initDisplay();
$view->display_handler->overrideOption('cache', array(
'type' => 'time',
'options' => array(
'results_lifespan' => '3600',
'output_lifespan' => '3600',
),
));
// Change the filtering.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'test_filter' => array(
'id' => 'test_filter',
'table' => 'views_test_data',
'field' => 'name',
'operator' => '=',
'value' => 'John',
'group' => 0,
),
));
$this->executeView($view);
// Get the cache item.
$cid1 = $view->display_handler->getPlugin('cache')->generateResultsKey();
// Build the expected result.
$dataset = array(array('name' => 'John'));
// Verify the result.
$this->assertEqual(1, count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultSet($view, $dataset, array(
'views_test_data_name' => 'name',
));
$view->destroy();
$view->initDisplay();
// Change the filtering.
$view->displayHandlers->get('default')->overrideOption('filters', array(
'test_filter' => array(
'id' => 'test_filter',
'table' => 'views_test_data',
'field' => 'name',
'operator' => '=',
'value' => 'Ringo',
'group' => 0,
),
));
$this->executeView($view);
// Get the cache item.
$cid2 = $view->display_handler->getPlugin('cache')->generateResultsKey();
$this->assertNotEqual($cid1, $cid2, "Results keys are different.");
// Build the expected result.
$dataset = array(array('name' => 'Ringo'));
// Verify the result.
$this->assertEqual(1, count($view->result), 'The number of returned rows match.');
$this->assertIdenticalResultSet($view, $dataset, array(
'views_test_data_name' => 'name',
));
}
/**
* Tests result caching with a pager.
*/
public function testTimeResultCachingWithPager() {
$view = Views::getView('test_cache');
$view->setDisplay();
$view->display_handler->overrideOption('cache', array(
'type' => 'time',
'options' => array(
'results_lifespan' => '3600',
'output_lifespan' => '3600',
)
));
$mapping = ['views_test_data_name' => 'name'];
$view->setDisplay('page_1');
$view->setCurrentPage(0);
$this->executeView($view);
$this->assertIdenticalResultset($view, [['name' => 'John'], ['name' => 'George']], $mapping);
$view->destroy();
$view->setDisplay('page_1');
$view->setCurrentPage(1);
$this->executeView($view);
$this->assertIdenticalResultset($view, [['name' => 'Ringo'], ['name' => 'Paul']], $mapping);
$view->destroy();
$view->setDisplay('page_1');
$view->setCurrentPage(0);
$this->executeView($view);
$this->assertIdenticalResultset($view, [['name' => 'John'], ['name' => 'George']], $mapping);
$view->destroy();
$view->setDisplay('page_1');
$view->setCurrentPage(2);
$this->executeView($view);
$this->assertIdenticalResultset($view, [['name' => 'Meredith']], $mapping);
$view->destroy();
}
/**
* Tests no caching.
*
* @see views_plugin_cache_time
*/
function testNoneResultCaching() {
// Create a basic result which just 2 results.
$view = Views::getView('test_cache');
$view->setDisplay();
$view->display_handler->overrideOption('cache', array(
'type' => 'none',
'options' => array(),
));
$this->executeView($view);
// Verify the result.
$this->assertEqual(5, count($view->result), 'The number of returned rows match.');
// Add another man to the beatles.
$record = array(
'name' => 'Rod Davis',
'age' => 29,
'job' => 'Banjo',
);
db_insert('views_test_data')->fields($record)->execute();
// The Result changes, because the view is not cached.
$view = Views::getView('test_cache');
$view->setDisplay();
$view->display_handler->overrideOption('cache', array(
'type' => 'none',
'options' => array(),
));
$this->executeView($view);
// Verify the result.
$this->assertEqual(6, count($view->result), 'The number of returned rows match.');
}
/**
* Tests css/js storage and restoring mechanism.
*/
function testHeaderStorage() {
// Create a view with output caching enabled.
// Some hook_views_pre_render in views_test_data.module adds the test css/js file.
// so they should be added to the css/js storage.
$view = Views::getView('test_view');
$view->setDisplay();
$view->storage->set('id', 'test_cache_header_storage');
$view->display_handler->overrideOption('cache', array(
'type' => 'time',
'options' => array(
'output_lifespan' => '3600',
)
));
$output = $view->buildRenderable();
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$renderer->executeInRenderContext(new RenderContext(), function () use (&$output, $renderer) {
return $renderer->render($output);
});
unset($view->pre_render_called);
$view->destroy();
$view->setDisplay();
$output = $view->buildRenderable();
$renderer->executeInRenderContext(new RenderContext(), function () use (&$output, $renderer) {
return $renderer->render($output);
});
$this->assertTrue(in_array('views_test_data/test', $output['#attached']['library']), 'Make sure libraries are added for cached views.');
$this->assertEqual(['foo' => 'bar'], $output['#attached']['drupalSettings'], 'Make sure drupalSettings are added for cached views.');
// Note: views_test_data_views_pre_render() adds some cache tags.
$this->assertEqual(['config:views.view.test_cache_header_storage', 'views_test_data:1'], $output['#cache']['tags']);
$this->assertEqual(['non-existing-placeholder-just-for-testing-purposes' => ['#lazy_builder' => ['views_test_data_placeholders', ['bar']]]], $output['#attached']['placeholders']);
$this->assertFalse(!empty($view->build_info['pre_render_called']), 'Make sure hook_views_pre_render is not called for the cached view.');
}
/**
* Tests that Subqueries are cached as expected.
*/
public function testSubqueryStringCache() {
// Execute the view.
$view = Views::getView('test_groupwise_term_ui');
$view->setDisplay();
$this->executeView($view);
// Request for the cache.
$cid = 'views_relationship_groupwise_max:test_groupwise_term_ui:default:tid_representative';
$cache = \Drupal::cache('data')->get($cid);
$this->assertEqual($cid, $cache->cid, 'Subquery String cached as expected.');
}
/**
* Tests the data contained in cached items.
*/
public function testCacheData() {
for ($i = 1; $i <= 5; $i++) {
Node::create([
'title' => $this->randomMachineName(8),
'type' => 'page',
])->save();
}
$view = Views::getView('test_display');
$view->setDisplay();
$view->display_handler->overrideOption('cache', array(
'type' => 'time',
'options' => array(
'results_lifespan' => '3600',
'output_lifespan' => '3600',
)
));
$this->executeView($view);
// Get the cache item.
$cid = $view->display_handler->getPlugin('cache')->generateResultsKey();
$cache = \Drupal::cache('data')->get($cid);
// Assert there are results, empty results would mean this test case would
// pass otherwise.
$this->assertTrue(count($cache->data['result']), 'Results saved in cached data.');
// Assert each row doesn't contain '_entity' or '_relationship_entities'
// items.
foreach ($cache->data['result'] as $row) {
$this->assertIdentical($row->_entity, NULL, 'Cached row "_entity" property is NULL');
$this->assertIdentical($row->_relationship_entities, [], 'Cached row "_relationship_entities" property is empty');
}
}
/**
* Tests the cache context integration for views result cache.
*/
public function testCacheContextIntegration() {
$view = Views::getView('test_cache');
$view->setDisplay('page_2');
\Drupal::state()->set('views_test_cache_context', 'George');
$this->executeView($view);
$map = ['views_test_data_name' => 'name'];
$this->assertIdenticalResultset($view, [['name' => 'George']], $map);
// Update the entry in the DB to ensure that result caching works.
\Drupal::database()->update('views_test_data')
->condition('name', 'George')
->fields(['name' => 'egroeG'])
->execute();
$view = Views::getView('test_cache');
$view->setDisplay('page_2');
$this->executeView($view);
$this->assertIdenticalResultset($view, [['name' => 'George']], $map);
// Now change the cache context value, a different query should be executed.
$view = Views::getView('test_cache');
$view->setDisplay('page_2');
\Drupal::state()->set('views_test_cache_context', 'Paul');
$this->executeView($view);
$this->assertIdenticalResultset($view, [['name' => 'Paul']], $map);
}
}

View file

@ -0,0 +1,118 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\views\Views;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Plugin\views\style\StylePluginBase;
use Drupal\views\Plugin\views\access\AccessPluginBase;
use Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase;
use Drupal\views\Plugin\views\pager\PagerPluginBase;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\views\Plugin\views\cache\CachePluginBase;
use Drupal\views\Plugin\views\row\RowPluginBase;
/**
* Drupal unit tests for the DisplayPluginBase class.
*
* @group views
*/
class DisplayKernelTest extends ViewsKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('block', 'node', 'field', 'user');
/**
* Views plugin types to test.
*
* @var array
*/
protected $pluginTypes = array(
'access',
'cache',
'query',
'exposed_form',
'pager',
'style',
'row',
);
/**
* Views handler types to test.
*
* @var array
*/
protected $handlerTypes = array(
'fields',
'sorts',
);
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_display_defaults');
/**
* Tests the default display options.
*/
public function testDefaultOptions() {
// Save the view.
$view = Views::getView('test_display_defaults');
$view->mergeDefaults();
$view->save();
// Reload to get saved storage values.
$view = Views::getView('test_display_defaults');
$view->initDisplay();
$display_data = $view->storage->get('display');
foreach ($view->displayHandlers as $id => $display) {
// Test the view plugin options against the storage.
foreach ($this->pluginTypes as $type) {
$options = $display->getOption($type);
$this->assertIdentical($display_data[$id]['display_options'][$type]['options'], $options['options']);
}
// Test the view handler options against the storage.
foreach ($this->handlerTypes as $type) {
$options = $display->getOption($type);
$this->assertIdentical($display_data[$id]['display_options'][$type], $options);
}
}
}
/**
* Tests the \Drupal\views\Plugin\views\display\DisplayPluginBase::getPlugin() method.
*/
public function testGetPlugin() {
$view = Views::getView('test_display_defaults');
$view->initDisplay();
$display_handler = $view->display_handler;
$this->assertTrue($display_handler->getPlugin('access') instanceof AccessPluginBase, 'An access plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('cache') instanceof CachePluginBase, 'A cache plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('exposed_form') instanceof ExposedFormPluginBase, 'An exposed_form plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('pager') instanceof PagerPluginBase, 'A pager plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('query') instanceof QueryPluginBase, 'A query plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('row') instanceof RowPluginBase, 'A row plugin instance was returned.');
$this->assertTrue($display_handler->getPlugin('style') instanceof StylePluginBase, 'A style plugin instance was returned.');
// Test that nothing is returned when an invalid type is requested.
$this->assertNull($display_handler->getPlugin('invalid'), 'NULL was returned for an invalid instance');
// Test that nothing was returned for an instance with no 'type' in options.
unset($display_handler->options['access']);
$this->assertNull($display_handler->getPlugin('access'), 'NULL was returned for a plugin type with no "type" option');
// Get a plugin twice, and make sure the same instance is returned.
$view->destroy();
$view->initDisplay();
$first = spl_object_hash($display_handler->getPlugin('style'));
$second = spl_object_hash($display_handler->getPlugin('style'));
$this->assertIdentical($first, $second, 'The same plugin instance was returned.');
}
}

View file

@ -0,0 +1,152 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\Core\Session\AnonymousUserSession;
use Drupal\views\Views;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Tests the page display plugin.
*
* @group views
* @see \Drupal\views\Plugin\display\Page
*/
class DisplayPageTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_page_display', 'test_page_display_route', 'test_page_display_menu');
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system', 'user', 'field');
/**
* The router dumper to get all routes.
*
* @var \Drupal\Core\Routing\MatcherDumper
*/
protected $routerDumper;
/**
* Checks the behavior of the page for access denied/not found behaviors.
*/
public function testPageResponses() {
\Drupal::currentUser()->setAccount(new AnonymousUserSession());
$subrequest = Request::create('/test_page_display_403', 'GET');
$response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
$this->assertEqual($response->getStatusCode(), 403);
$subrequest = Request::create('/test_page_display_404', 'GET');
$response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
$this->assertEqual($response->getStatusCode(), 404);
$subrequest = Request::create('/test_page_display_200', 'GET');
$response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
$this->assertEqual($response->getStatusCode(), 200);
$subrequest = Request::create('/test_page_display_200', 'GET');
\Drupal::getContainer()->get('request_stack')->push($subrequest);
// Test accessing a disabled page for a view.
$view = Views::getView('test_page_display');
// Disable the view, rebuild menu, and request the page again.
$view->storage->disable()->save();
// Router rebuild would occur in a kernel terminate event so we need to
// simulate that here.
\Drupal::service('router.builder')->rebuild();
$response = $this->container->get('http_kernel')->handle($subrequest, HttpKernelInterface::SUB_REQUEST);
$this->assertEqual($response->getStatusCode(), 404);
}
/**
* Checks that the router items are properly registered
*/
public function testPageRouterItems() {
$collection = \Drupal::service('views.route_subscriber')->routes();
// Check the controller defaults.
foreach ($collection as $id => $route) {
$this->assertEqual($route->getDefault('_controller'), 'Drupal\views\Routing\ViewPageController::handle');
$id_parts = explode('.', $id);
$this->assertEqual($route->getDefault('view_id'), $id_parts[1]);
$this->assertEqual($route->getDefault('display_id'), $id_parts[2]);
}
// Check the generated patterns and default values.
$route = $collection->get('view.test_page_display_route.page_1');
$this->assertEqual($route->getPath(), '/test_route_without_arguments');
$route = $collection->get('view.test_page_display_route.page_2');
$this->assertEqual($route->getPath(), '/test_route_with_argument/{arg_0}');
$this->assertTrue($route->hasDefault('arg_0'), 'A default value is set for the optional argument id.');
$route = $collection->get('view.test_page_display_route.page_3');
$this->assertEqual($route->getPath(), '/test_route_with_argument/{arg_0}/suffix');
$this->assertFalse($route->hasDefault('arg_0'), 'No default value is set for the required argument id.');
$route = $collection->get('view.test_page_display_route.page_4');
$this->assertEqual($route->getPath(), '/test_route_with_argument/{arg_0}/suffix/{arg_1}');
$this->assertFalse($route->hasDefault('arg_0'), 'No default value is set for the required argument id.');
$this->assertTrue($route->hasDefault('arg_1'), 'A default value is set for the optional argument id_2.');
$route = $collection->get('view.test_page_display_route.page_5');
$this->assertEqual($route->getPath(), '/test_route_with_argument/{arg_0}/{arg_1}');
$this->assertTrue($route->hasDefault('arg_0'), 'A default value is set for the optional argument id.');
$this->assertTrue($route->hasDefault('arg_1'), 'A default value is set for the optional argument id_2.');
$route = $collection->get('view.test_page_display_route.page_6');
$this->assertEqual($route->getPath(), '/test_route_with_argument/{arg_0}/{arg_1}');
$this->assertFalse($route->hasDefault('arg_0'), 'No default value is set for the required argument id.');
$this->assertFalse($route->hasDefault('arg_1'), 'No default value is set for the required argument id_2.');
}
/**
* Tests the generated menu links of views.
*/
public function testMenuLinks() {
\Drupal::service('plugin.manager.menu.link')->rebuild();
$tree = \Drupal::menuTree()->load('admin', new MenuTreeParameters());
$this->assertTrue(isset($tree['system.admin']->subtree['views_view:views.test_page_display_menu.page_4']));
$menu_link = $tree['system.admin']->subtree['views_view:views.test_page_display_menu.page_4']->link;
$this->assertEqual($menu_link->getTitle(), 'Test child (with parent)');
$this->assertEqual($menu_link->isExpanded(), TRUE);
$this->assertEqual($menu_link->getDescription(), 'Sample description.');
}
/**
* Tests the calculated dependencies for various views using Page displays.
*/
public function testDependencies() {
$view = Views::getView('test_page_display');
$this->assertIdentical([], $view->getDependencies());
$view = Views::getView('test_page_display_route');
$expected = [
'content' => ['StaticTest'],
'module' => ['views_test_data'],
];
$this->assertIdentical($expected, $view->getDependencies());
$view = Views::getView('test_page_display_menu');
$expected = [
'config' => [
'system.menu.admin',
'system.menu.tools',
],
];
$this->assertIdentical($expected, $view->getDependencies());
}
}

View file

@ -0,0 +1,206 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\views_test_data\Plugin\views\join\JoinTest as JoinTestPlugin;
use Drupal\views\Plugin\views\join\JoinPluginBase;
use Drupal\views\Views;
/**
* Tests the join plugin.
*
* @group views
* @see \Drupal\views_test_data\Plugin\views\join\JoinTest
* @see \Drupal\views\Plugin\views\join\JoinPluginBase
*/
class JoinTest extends RelationshipJoinTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* A plugin manager which handlers the instances of joins.
*
* @var \Drupal\views\Plugin\ViewsPluginManager
*/
protected $manager;
protected function setUp($import_test_views = TRUE) {
parent::setUp();
// Add a join plugin manager which can be used in all of the tests.
$this->manager = $this->container->get('plugin.manager.views.join');
}
/**
* Tests an example join plugin.
*/
public function testExamplePlugin() {
// Setup a simple join and test the result sql.
$view = Views::getView('test_view');
$view->initDisplay();
$view->initQuery();
$configuration = array(
'left_table' => 'views_test_data',
'left_field' => 'uid',
'table' => 'users_field_data',
'field' => 'uid',
);
$join = $this->manager->createInstance('join_test', $configuration);
$this->assertTrue($join instanceof JoinTestPlugin, 'The correct join class got loaded.');
$rand_int = rand(0, 1000);
$join->setJoinValue($rand_int);
$query = db_select('views_test_data');
$table = array('alias' => 'users_field_data');
$join->buildJoin($query, $table, $view->query);
$tables = $query->getTables();
$join_info = $tables['users_field_data'];
$this->assertTrue(strpos($join_info['condition'], "views_test_data.uid = $rand_int") !== FALSE, 'Make sure that the custom join plugin can extend the join base and alter the result.');
}
/**
* Tests the join plugin base.
*/
public function testBasePlugin() {
// Setup a simple join and test the result sql.
$view = Views::getView('test_view');
$view->initDisplay();
$view->initQuery();
// First define a simple join without an extra condition.
// Set the various options on the join object.
$configuration = array(
'left_table' => 'views_test_data',
'left_field' => 'uid',
'table' => 'users_field_data',
'field' => 'uid',
'adjusted' => TRUE,
);
$join = $this->manager->createInstance('standard', $configuration);
$this->assertTrue($join instanceof JoinPluginBase, 'The correct join class got loaded.');
$this->assertNull($join->extra, 'The field extra was not overridden.');
$this->assertTrue($join->adjusted, 'The field adjusted was set correctly.');
// Build the actual join values and read them back from the dbtng query
// object.
$query = db_select('views_test_data');
$table = array('alias' => 'users_field_data');
$join->buildJoin($query, $table, $view->query);
$tables = $query->getTables();
$join_info = $tables['users_field_data'];
$this->assertEqual($join_info['join type'], 'LEFT', 'Make sure the default join type is LEFT');
$this->assertEqual($join_info['table'], $configuration['table']);
$this->assertEqual($join_info['alias'], 'users_field_data');
$this->assertEqual($join_info['condition'], 'views_test_data.uid = users_field_data.uid');
// Set a different alias and make sure table info is as expected.
$join = $this->manager->createInstance('standard', $configuration);
$table = array('alias' => 'users1');
$join->buildJoin($query, $table, $view->query);
$tables = $query->getTables();
$join_info = $tables['users1'];
$this->assertEqual($join_info['alias'], 'users1');
// Set a different join type (INNER) and make sure it is used.
$configuration['type'] = 'INNER';
$join = $this->manager->createInstance('standard', $configuration);
$table = array('alias' => 'users2');
$join->buildJoin($query, $table, $view->query);
$tables = $query->getTables();
$join_info = $tables['users2'];
$this->assertEqual($join_info['join type'], 'INNER');
// Setup addition conditions and make sure it is used.
$random_name_1 = $this->randomMachineName();
$random_name_2 = $this->randomMachineName();
$configuration['extra'] = array(
array(
'field' => 'name',
'value' => $random_name_1
),
array(
'field' => 'name',
'value' => $random_name_2,
'operator' => '<>'
),
);
$join = $this->manager->createInstance('standard', $configuration);
$table = array('alias' => 'users3');
$join->buildJoin($query, $table, $view->query);
$tables = $query->getTables();
$join_info = $tables['users3'];
$this->assertTrue(strpos($join_info['condition'], "views_test_data.uid = users3.uid") !== FALSE, 'Make sure the join condition appears in the query.');
$this->assertTrue(strpos($join_info['condition'], "users3.name = :views_join_condition_0") !== FALSE, 'Make sure the first extra join condition appears in the query and uses the first placeholder.');
$this->assertTrue(strpos($join_info['condition'], "users3.name <> :views_join_condition_1") !== FALSE, 'Make sure the second extra join condition appears in the query and uses the second placeholder.');
$this->assertEqual(array_values($join_info['arguments']), array($random_name_1, $random_name_2), 'Make sure the arguments are in the right order');
// Test that 'IN' conditions are properly built.
$random_name_1 = $this->randomMachineName();
$random_name_2 = $this->randomMachineName();
$random_name_3 = $this->randomMachineName();
$random_name_4 = $this->randomMachineName();
$configuration['extra'] = array(
array(
'field' => 'name',
'value' => $random_name_1
),
array(
'field' => 'name',
'value' => array($random_name_2, $random_name_3, $random_name_4),
),
);
$join = $this->manager->createInstance('standard', $configuration);
$table = array('alias' => 'users4');
$join->buildJoin($query, $table, $view->query);
$tables = $query->getTables();
$join_info = $tables['users4'];
$this->assertTrue(strpos($join_info['condition'], "views_test_data.uid = users4.uid") !== FALSE, 'Make sure the join condition appears in the query.');
$this->assertTrue(strpos($join_info['condition'], "users4.name = :views_join_condition_2") !== FALSE, 'Make sure the first extra join condition appears in the query.');
$this->assertTrue(strpos($join_info['condition'], "users4.name IN ( :views_join_condition_3, :views_join_condition_4, :views_join_condition_5 )") !== FALSE, 'The IN condition for the join is properly formed.');
// Test that all the conditions are properly built.
$configuration['extra'] = array(
array(
'field' => 'langcode',
'value' => 'en'
),
array(
'left_field' => 'status',
'value' => 0,
'numeric' => TRUE,
),
array(
'field' => 'name',
'left_field' => 'name'
),
);
$join = $this->manager->createInstance('standard', $configuration);
$table = array('alias' => 'users5');
$join->buildJoin($query, $table, $view->query);
$tables = $query->getTables();
$join_info = $tables['users5'];
$this->assertTrue(strpos($join_info['condition'], "views_test_data.uid = users5.uid") !== FALSE, 'Make sure the join condition appears in the query.');
$this->assertTrue(strpos($join_info['condition'], "users5.langcode = :views_join_condition_6") !== FALSE, 'Make sure the first extra join condition appears in the query.');
$this->assertTrue(strpos($join_info['condition'], "views_test_data.status = :views_join_condition_7") !== FALSE, 'Make sure the second extra join condition appears in the query.');
$this->assertTrue(strpos($join_info['condition'], "users5.name = views_test_data.name") !== FALSE, 'Make sure the third extra join condition appears in the query.');
$this->assertEqual(array_values($join_info['arguments']), array('en', 0), 'Make sure the arguments are in the right order');
}
}

View file

@ -0,0 +1,69 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests pager-related APIs.
*
* @group views
*/
class PagerKernelTest extends ViewsKernelTestBase {
/**
* {@inheritdoc}
*/
public static $testViews = ['test_pager_full'];
/**
* {@inheritdoc}
*/
public static $modules = ['user', 'node'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->installEntitySchema('node');
$this->installEntitySchema('user');
}
/**
* Tests pager-related setter methods on ViewExecutable.
*
* @see \Drupal\views\ViewExecutable::setItemsPerPage
* @see \Drupal\views\ViewExecutable::setOffset
* @see \Drupal\views\ViewExecutable::setCurrentPage
*/
public function testSetPagerMethods() {
$view = Views::getView('test_pager_full');
// Mark the view as cacheable in order have the cache checking working
// below.
$display = &$view->storage->getDisplay('default');
$display['display_options']['cache']['type'] = 'tag';
$view->storage->save();
$output = $view->preview();
\Drupal::service('renderer')->renderPlain($output);
$this->assertIdentical(CacheBackendInterface::CACHE_PERMANENT, $output['#cache']['max-age']);
foreach (['setItemsPerPage', 'setOffset', 'setCurrentPage'] as $method) {
$view = Views::getView('test_pager_full');
$view->setDisplay('default');
$view->{$method}(1);
$output = $view->preview();
\Drupal::service('renderer')->renderPlain($output);
$this->assertIdentical(CacheBackendInterface::CACHE_PERMANENT, $output['#cache']['max-age'], 'Max age kept.');
}
}
}

View file

@ -0,0 +1,12 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
/**
* Base test class for views plugin unit tests.
*/
abstract class PluginKernelTestBase extends ViewsKernelTestBase {
}

View file

@ -0,0 +1,77 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\views\Views;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views_test_data\Plugin\views\query\QueryTest as QueryTestPlugin;
/**
* Tests query plugins.
*
* @group views
*/
class QueryTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
protected function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['table']['base']['query_id'] = 'query_test';
return $data;
}
/**
* Tests query plugins.
*/
public function testQuery() {
$this->_testInitQuery();
$this->_testQueryExecute();
$this->queryMethodsTests();
}
/**
* Tests the ViewExecutable::initQuery method.
*/
public function _testInitQuery() {
$view = Views::getView('test_view');
$view->setDisplay();
$view->initQuery();
$this->assertTrue($view->query instanceof QueryTestPlugin, 'Make sure the right query plugin got instantiated.');
}
public function _testQueryExecute() {
$view = Views::getView('test_view');
$view->setDisplay();
$view->initQuery();
$view->query->setAllItems($this->dataSet());
$this->executeView($view);
$this->assertTrue($view->result, 'Make sure the view result got filled');
}
/**
* Test methods provided by the QueryPluginBase.
*
* @see \Drupal\views\Plugin\views\query\QueryPluginBase
*/
protected function queryMethodsTests() {
$view = Views::getView('test_view');
$view->setDisplay();
$view->initQuery();
$this->assertFalse($view->query->getLimit(), 'Default to an empty limit.');
$rand_number = rand(5, 10);
$view->query->setLimit($rand_number);
$this->assertEqual($view->query->getLimit(), $rand_number, 'set_limit adapts the amount of items.');
}
}

View file

@ -0,0 +1,82 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\user\Entity\User;
use Drupal\views\Views;
/**
* Provides a base class for a testing a relationship.
*
* @see \Drupal\views\Tests\Handler\JoinTest
* @see \Drupal\views\Tests\Plugin\RelationshipTest
*/
abstract class RelationshipJoinTestBase extends PluginKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('system', 'user', 'field');
/**
* @var \Drupal\user\Entity\User
*/
protected $rootUser;
/**
* {@inheritdoc}
*/
protected function setUpFixtures() {
$this->installEntitySchema('user');
$this->installConfig(array('user'));
parent::setUpFixtures();
// Create a record for uid 1.
$this->rootUser = User::create(['name' => $this->randomMachineName()]);
$this->rootUser->save();
Views::viewsData()->clear();
}
/**
* Overrides \Drupal\views\Tests\ViewTestBase::schemaDefinition().
*
* Adds a uid column to test the relationships.
*/
protected function schemaDefinition() {
$schema = parent::schemaDefinition();
$schema['views_test_data']['fields']['uid'] = array(
'description' => "The {users_field_data}.uid of the author of the beatle entry.",
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0
);
return $schema;
}
/**
* Overrides \Drupal\views\Tests\ViewTestBase::viewsData().
*
* Adds a relationship for the uid column.
*/
protected function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['uid'] = array(
'title' => t('UID'),
'help' => t('The test data UID'),
'relationship' => array(
'id' => 'standard',
'base' => 'users_field_data',
'base field' => 'uid'
)
);
return $data;
}
}

View file

@ -0,0 +1,178 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\simpletest\UserCreationTrait;
use Drupal\views\Views;
/**
* Tests the base relationship handler.
*
* @group views
* @see \Drupal\views\Plugin\views\relationship\RelationshipPluginBase
*/
class RelationshipTest extends RelationshipJoinTestBase {
use UserCreationTrait;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* Maps between the key in the expected result and the query result.
*
* @var array
*/
protected $columnMap = array(
'views_test_data_name' => 'name',
'users_field_data_views_test_data_uid' => 'uid',
);
/**
* Tests the query result of a view with a relationship.
*/
public function testRelationshipQuery() {
// Set the first entry to have the admin as author.
db_query("UPDATE {views_test_data} SET uid = 1 WHERE id = 1");
db_query("UPDATE {views_test_data} SET uid = 2 WHERE id <> 1");
$view = Views::getView('test_view');
$view->setDisplay();
$view->displayHandlers->get('default')->overrideOption('relationships', array(
'uid' => array(
'id' => 'uid',
'table' => 'views_test_data',
'field' => 'uid',
),
));
$view->displayHandlers->get('default')->overrideOption('filters', array(
'uid' => array(
'id' => 'uid',
'table' => 'users_field_data',
'field' => 'uid',
'relationship' => 'uid',
),
));
$fields = $view->displayHandlers->get('default')->getOption('fields');
$view->displayHandlers->get('default')->overrideOption('fields', $fields + array(
'uid' => array(
'id' => 'uid',
'table' => 'users_field_data',
'field' => 'uid',
'relationship' => 'uid',
),
));
$view->initHandlers();
// Check for all beatles created by admin.
$view->filter['uid']->value = array(1);
$this->executeView($view);
$expected_result = array(
array(
'name' => 'John',
'uid' => 1
)
);
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
// Check for all beatles created by another user, which so doesn't exist.
$view->initHandlers();
$view->filter['uid']->value = array(3);
$this->executeView($view);
$expected_result = array();
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
// Set the relationship to required, so only results authored by the admin
// should return.
$view->initHandlers();
$view->relationship['uid']->options['required'] = TRUE;
$this->executeView($view);
$expected_result = array(
array(
'name' => 'John',
'uid' => 1
)
);
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
$view->destroy();
// Set the relationship to optional should cause to return all beatles.
$view->initHandlers();
$view->relationship['uid']->options['required'] = FALSE;
$this->executeView($view);
$expected_result = $this->dataSet();
// Alter the expected result to contain the right uids.
foreach ($expected_result as &$row) {
// Only John has an existing author.
if ($row['name'] == 'John') {
$row['uid'] = 1;
}
else {
// The LEFT join should set an empty {users}.uid field.
$row['uid'] = NULL;
}
}
$this->assertIdenticalResultset($view, $expected_result, $this->columnMap);
}
/**
* Tests rendering of a view with a relationship.
*/
public function testRelationshipRender() {
$author1 = $this->createUser();
db_query("UPDATE {views_test_data} SET uid = :uid WHERE id = 1", [':uid' => $author1->id()]);
$author2 = $this->createUser();
db_query("UPDATE {views_test_data} SET uid = :uid WHERE id = 2", [':uid' => $author2->id()]);
// Set uid to non-existing author uid for row 3.
db_query("UPDATE {views_test_data} SET uid = :uid WHERE id = 3", [':uid' => $author2->id() + 123]);
$view = Views::getView('test_view');
// Add a relationship for authors.
$view->getDisplay()->overrideOption('relationships', [
'uid' => [
'id' => 'uid',
'table' => 'views_test_data',
'field' => 'uid',
],
]);
// Add fields for {views_test_data}.id and author name.
$view->getDisplay()->overrideOption('fields', [
'id' => [
'id' => 'id',
'table' => 'views_test_data',
'field' => 'id',
],
'author' => [
'id' => 'author',
'table' => 'users_field_data',
'field' => 'name',
'relationship' => 'uid',
],
]);
// Render the view.
$output = $view->preview();
$html = $this->container->get('renderer')->renderRoot($output);
$this->setRawContent($html);
// Check that the output contains correct values.
$xpath = '//div[@class="views-row" and div[@class="views-field views-field-id"]=:id and div[@class="views-field views-field-author"]=:author]';
$this->assertEqual(1, count($this->xpath($xpath, [':id' => 1, ':author' => $author1->getUsername()])));
$this->assertEqual(1, count($this->xpath($xpath, [':id' => 2, ':author' => $author2->getUsername()])));
$this->assertEqual(1, count($this->xpath($xpath, [':id' => 3, ':author' => ''])));
}
}

View file

@ -0,0 +1,68 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\Core\Form\FormState;
use Drupal\views\Views;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\taxonomy\Entity\Term;
/**
* Tests the generic entity row plugin.
*
* @group views
* @see \Drupal\views\Plugin\views\row\EntityRow
*/
class RowEntityTest extends ViewsKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['taxonomy', 'text', 'filter', 'field', 'system', 'node', 'user'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_entity_row');
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->installEntitySchema('taxonomy_term');
$this->installConfig(array('taxonomy'));
\Drupal::service('router.builder')->rebuild();
}
/**
* Tests the entity row handler.
*/
public function testEntityRow() {
$vocab = Vocabulary::create(['name' => $this->randomMachineName(), 'vid' => strtolower($this->randomMachineName())]);
$vocab->save();
$term = Term::create(['name' => $this->randomMachineName(), 'vid' => $vocab->id() ]);
$term->save();
$view = Views::getView('test_entity_row');
$build = $view->preview();
$this->render($build);
$this->assertText($term->getName(), 'The rendered entity appears as row in the view.');
// Tests the available view mode options.
$form = array();
$form_state = new FormState();
$form_state->set('view', $view->storage);
$view->rowPlugin->buildOptionsForm($form, $form_state);
$this->assertTrue(isset($form['view_mode']['#options']['default']), 'Ensure that the default view mode is available');
}
}

View file

@ -0,0 +1,172 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\Core\Session\AccountInterface;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\node\NodeInterface;
use Drupal\simpletest\UserCreationTrait;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests row render caching.
*
* @group views
*/
class RowRenderCacheTest extends ViewsKernelTestBase {
use UserCreationTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('user', 'node');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_row_render_cache');
/**
* An editor user account.
*
* @var \Drupal\user\UserInterface
*/
protected $editorUser;
/**
* A power user account.
*
* @var \Drupal\user\UserInterface
*/
protected $powerUser;
/**
* A regular user account.
*
* @var \Drupal\user\UserInterface
*/
protected $regularUser;
/**
* {@inheritdoc}
*/
protected function setUpFixtures() {
parent::setUpFixtures();
$this->installEntitySchema('user');
$this->installEntitySchema('node');
$this->installSchema('node', 'node_access');
$type = NodeType::create(['type' => 'test']);
$type->save();
$this->editorUser = $this->createUser(['bypass node access']);
$this->powerUser = $this->createUser(['access content', 'create test content', 'edit own test content', 'delete own test content']);
$this->regularUser = $this->createUser(['access content']);
// Create some test entities.
for ($i = 0; $i < 5; $i++) {
Node::create(['title' => 'b' . $i . $this->randomMachineName(), 'type' => 'test'])->save();
}
// Create a power user node.
Node::create(['title' => 'z' . $this->randomMachineName(), 'uid' => $this->powerUser->id(), 'type' => 'test'])->save();
}
/**
* Test complex field rewriting and uncacheable field handlers.
*/
public function testAdvancedCaching() {
// Test that row field output is actually cached and with the proper cache
// contexts.
$this->doTestRenderedOutput($this->editorUser);
$this->doTestRenderedOutput($this->editorUser, TRUE);
$this->doTestRenderedOutput($this->powerUser);
$this->doTestRenderedOutput($this->powerUser, TRUE);
$this->doTestRenderedOutput($this->regularUser);
$this->doTestRenderedOutput($this->regularUser, TRUE);
// Alter the result set order and check that counter is still working
// correctly.
$this->doTestRenderedOutput($this->editorUser);
/** @var \Drupal\node\NodeInterface $node */
$node = Node::load(6);
$node->setTitle('a' . $this->randomMachineName());
$node->save();
$this->doTestRenderedOutput($this->editorUser);
}
/**
* Check whether the rendered output matches expectations.
*
* @param \Drupal\Core\Session\AccountInterface $account
* The user account to tests rendering with.
* @param bool $check_cache
* (optional) Whether explicitly test render cache entries.
*/
protected function doTestRenderedOutput(AccountInterface $account, $check_cache = FALSE) {
$this->setCurrentUser($account);
$view = Views::getView('test_row_render_cache');
$view->setDisplay();
$view->preview();
/** @var \Drupal\Core\Render\RenderCacheInterface $render_cache */
$render_cache = $this->container->get('render_cache');
/** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache_plugin */
$cache_plugin = $view->display_handler->getPlugin('cache');
// Retrieve nodes and sort them in alphabetical order to match view results.
$nodes = Node::loadMultiple();
usort($nodes, function (NodeInterface $a, NodeInterface $b) {
return strcmp($a->label(), $b->label());
});
$index = 0;
foreach ($nodes as $node) {
$nid = $node->id();
$access = $node->access('update');
$counter = $index + 1;
$expected = "$nid: $counter (just in case: $nid)";
$counter_output = $view->style_plugin->getField($index, 'counter');
$this->assertEqual($counter_output, $expected);
$node_url = $node->url();
$expected = "<a href=\"$node_url\"><span class=\"da-title\">{$node->label()}</span> <span class=\"counter\">$counter_output</span></a>";
$output = $view->style_plugin->getField($index, 'title');
$this->assertEqual($output, $expected);
$expected = $access ? "<a href=\"$node_url/edit?destination=/\" hreflang=\"en\">edit</a>" : "";
$output = $view->style_plugin->getField($index, 'edit_node');
$this->assertEqual($output, $expected);
$expected = $access ? "<a href=\"$node_url/delete?destination=/\" hreflang=\"en\">delete</a>" : "";
$output = $view->style_plugin->getField($index, 'delete_node');
$this->assertEqual($output, $expected);
$expected = $access ? ' <div class="dropbutton-wrapper"><div class="dropbutton-widget"><ul class="dropbutton">' .
'<li><a href="' . $node_url . '/edit?destination=/" hreflang="en">Edit</a></li>' .
'<li><a href="' . $node_url . '/delete?destination=/" hreflang="en">Delete</a></li>' .
'</ul></div></div>' : '';
$output = $view->style_plugin->getField($index, 'operations');
$this->assertEqual($output, $expected);
if ($check_cache) {
$keys = $cache_plugin->getRowCacheKeys($view->result[$index]);
$user_context = !$account->hasPermission('edit any test content') ? 'user' : 'user.permissions';
$element = $render_cache->get(['#cache' => ['keys' => $keys, 'contexts' => ['languages:language_interface', 'theme', $user_context]]]);
$this->assertTrue($element);
}
$index++;
}
}
}

View file

@ -0,0 +1,82 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the sql query plugin.
*
* @group views
* @see \Drupal\views\Plugin\views\query\Sql
*/
class SqlQueryTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* {@inheritdoc}
*/
protected function viewsData() {
$data = parent::viewsData();
$data['views_test_data']['table']['base']['access query tag'] = 'test_tag';
$data['views_test_data']['table']['base']['query metadata'] = array('key1' => 'test_metadata', 'key2' => 'test_metadata2');
return $data;
}
/**
* Tests adding some metadata/tags to the views query.
*/
public function testExecuteMetadata() {
$view = Views::getView('test_view');
$view->setDisplay();
$view->initQuery();
$view->execute();
/** @var \Drupal\Core\Database\Query\Select $query */
$main_query = $view->build_info['query'];
/** @var \Drupal\Core\Database\Query\Select $count_query */
$count_query = $view->build_info['count_query'];
foreach (array($main_query, $count_query) as $query) {
// Check query access tags.
$this->assertTrue($query->hasTag('test_tag'));
// Check metadata.
$this->assertIdentical($query->getMetaData('key1'), 'test_metadata');
$this->assertIdentical($query->getMetaData('key2'), 'test_metadata2');
}
$query_options = $view->display_handler->getOption('query');
$query_options['options']['disable_sql_rewrite'] = TRUE;
$view->display_handler->setOption('query', $query_options);
$view->save();
$view->destroy();
$view = Views::getView('test_view');
$view->setDisplay();
$view->initQuery();
$view->execute();
/** @var \Drupal\Core\Database\Query\Select $query */
$main_query = $view->build_info['query'];
/** @var \Drupal\Core\Database\Query\Select $count_query */
$count_query = $view->build_info['count_query'];
foreach (array($main_query, $count_query) as $query) {
// Check query access tags.
$this->assertFalse($query->hasTag('test_tag'));
// Check metadata.
$this->assertIdentical($query->getMetaData('key1'), NULL);
$this->assertIdentical($query->getMetaData('key2'), NULL);
}
}
}

View file

@ -0,0 +1,53 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Views;
/**
* Tests the HTML list style plugin.
*
* @group views
* @see \Drupal\views\Plugin\views\style\HtmlList
*/
class StyleHtmlListTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_style_html_list');
/**
* Make sure that the HTML list style markup is correct.
*/
function testDefaultRowClasses() {
$view = Views::getView('test_style_html_list');
$output = $view->preview();
$output = \Drupal::service('renderer')->renderRoot($output);
// Check that an empty class attribute is not added if the wrapper class is
// not set.
$this->assertTrue(strpos($output, '<div>') !== FALSE, 'Empty class is not added to DIV when class is not set');
// Check that an empty class attribute is not added if the list class is
// not set.
$this->assertTrue(strpos($output, '<ul>') !== FALSE, 'Empty class is not added to UL when class is not set');
// Set wrapper class and list class in style options.
$view->style_plugin->options['class'] = 'class';
$view->style_plugin->options['wrapper_class'] = 'wrapper-class';
$output = $view->preview();
$output = \Drupal::service('renderer')->renderRoot($output);
// Check that class attribute is present if the wrapper class is set.
$this->assertTrue(strpos($output, '<div class="wrapper-class">') !== FALSE, 'Class is added to DIV');
// Check that class attribute is present if the list class is set.
$this->assertTrue(strpos($output, '<ul class="class">') !== FALSE, 'Class is added to UL');
}
}

View file

@ -0,0 +1,80 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\views\Views;
/**
* Tests mapping style functionality.
*
* @group views
*/
class StyleMappingTest extends StyleTestBase {
public static $modules = array('system');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_style_mapping');
/**
* Verifies that the fields were mapped correctly.
*/
public function testMappedOutput() {
$view = Views::getView('test_style_mapping');
$output = $this->mappedOutputHelper($view);
$this->assertTrue(strpos($output, 'job') === FALSE, 'The job field is added to the view but not in the mapping.');
$view->destroy();
$view->setDisplay();
$view->displayHandlers->get('default')->options['style']['options']['mapping']['name_field'] = 'job';
$output = $this->mappedOutputHelper($view);
$this->assertTrue(strpos($output, 'job') !== FALSE, 'The job field is added to the view and is in the mapping.');
}
/**
* Tests the mapping of fields.
*
* @param \Drupal\views\ViewExecutable $view
* The view to test.
*
* @return string
* The view rendered as HTML.
*/
protected function mappedOutputHelper($view) {
$output = $view->preview();
$rendered_output = \Drupal::service('renderer')->renderRoot($output);
$this->storeViewPreview($rendered_output);
$rows = $this->elements->body->div->div;
$data_set = $this->dataSet();
$count = 0;
foreach ($rows as $row) {
$attributes = $row->attributes();
$class = (string) $attributes['class'][0];
$this->assertTrue(strpos($class, 'views-row-mapping-test') !== FALSE, 'Make sure that each row has the correct CSS class.');
foreach ($row->div as $field) {
// Split up the field-level class, the first part is the mapping name
// and the second is the field ID.
$field_attributes = $field->attributes();
$name = strtok((string) $field_attributes['class'][0], '-');
$field_id = strtok('-');
// The expected result is the mapping name and the field value,
// separated by ':'.
$expected_result = $name . ':' . $data_set[$count][$field_id];
$actual_result = (string) $field;
$this->assertIdentical($expected_result, $actual_result, format_string('The fields were mapped successfully: %name => %field_id', array('%name' => $name, '%field_id' => $field_id)));
}
$count++;
}
return $rendered_output;
}
}

View file

@ -0,0 +1,156 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\views\Views;
use Drupal\views\ViewExecutable;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests the table style plugin.
*
* @group views
* @see \Drupal\views\Plugin\views\style\Table
*/
class StyleTableUnitTest extends PluginKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_table');
/**
* Tests the table style.
*/
public function testTable() {
$view = Views::getView('test_table');
$view->setDisplay('default');
$view->initStyle();
$view->initHandlers();
$view->initQuery();
$style_plugin = $view->style_plugin;
// Test the buildSort() method.
$request = new Request();
$view->setRequest($request);
$style_plugin->options['override'] = FALSE;
$style_plugin->options['default'] = '';
$this->assertTrue($style_plugin->buildSort(), 'If no order and no default order is specified, the normal sort should be used.');
$style_plugin->options['default'] = 'id';
$this->assertTrue($style_plugin->buildSort(), 'If no order but a default order is specified, the normal sort should be used.');
$request->attributes->set('order', $this->randomMachineName());
$this->assertTrue($style_plugin->buildSort(), 'If no valid field is chosen for order, the normal sort should be used.');
$request->attributes->set('order', 'id');
$this->assertTrue($style_plugin->buildSort(), 'If a valid order is specified but the table is configured to not override, the normal sort should be used.');
$style_plugin->options['override'] = TRUE;
$this->assertFalse($style_plugin->buildSort(), 'If a valid order is specified and the table is configured to override, the normal sort should not be used.');
// Test the buildSortPost() method.
$request = new Request();
$view->setRequest($request);
// Setup no valid default.
$this->prepareView($view);
$style_plugin = $view->style_plugin;
$style_plugin->options['default'] = '';
$style_plugin->buildSortPost();
$this->assertIdentical($style_plugin->order, NULL, 'No sort order was set, when no order was specified and no default column was selected.');
$this->assertIdentical($style_plugin->active, NULL, 'No sort field was set, when no order was specified and no default column was selected.');
$view->destroy();
// Setup a valid default + column specific default sort order.
$this->prepareView($view);
$style_plugin = $view->style_plugin;
$style_plugin->options['default'] = 'id';
$style_plugin->options['info']['id']['default_sort_order'] = 'desc';
$style_plugin->buildSortPost();
$this->assertIdentical($style_plugin->order, 'desc', 'Fallback to the right default sort order.');
$this->assertIdentical($style_plugin->active, 'id', 'Fallback to the right default sort field.');
$view->destroy();
// Setup a valid default + table default sort order.
$this->prepareView($view);
$style_plugin = $view->style_plugin;
$style_plugin->options['default'] = 'id';
$style_plugin->options['info']['id']['default_sort_order'] = NULL;
$style_plugin->options['order'] = 'asc';
$style_plugin->buildSortPost();
$this->assertIdentical($style_plugin->order, 'asc', 'Fallback to the right default sort order.');
$this->assertIdentical($style_plugin->active, 'id', 'Fallback to the right default sort field.');
$view->destroy();
// Use an invalid field.
$this->prepareView($view);
$style_plugin = $view->style_plugin;
$request->query->set('sort', 'asc');
$random_name = $this->randomMachineName();
$request->query->set('order', $random_name);
$style_plugin->buildSortPost();
$this->assertIdentical($style_plugin->order, 'asc', 'No sort order was set, when invalid sort order was specified.');
$this->assertIdentical($style_plugin->active, NULL, 'No sort field was set, when invalid sort order was specified.');
$view->destroy();
// Use a existing field, and sort both ascending and descending.
foreach (array('asc', 'desc') as $order) {
$this->prepareView($view);
$style_plugin = $view->style_plugin;
$request->query->set('sort', $order);
$request->query->set('order', 'id');
$style_plugin->buildSortPost();
$this->assertIdentical($style_plugin->order, $order, 'Ensure the right sort order was set.');
$this->assertIdentical($style_plugin->active, 'id', 'Ensure the right order was set.');
$view->destroy();
}
$view->destroy();
// Excluded field to make sure its wrapping td doesn't show.
$this->prepareView($view);
$view->field['name']->options['exclude'] = TRUE;
$output = $view->preview();
$output = \Drupal::service('renderer')->renderRoot($output);
$this->assertFalse(strpos($output, 'views-field-name') !== FALSE, "Excluded field's wrapper was not rendered.");
$view->destroy();
// Render a non empty result, and ensure that the empty area handler is not
// rendered.
$this->executeView($view);
$output = $view->preview();
$output = \Drupal::service('renderer')->renderRoot($output);
$this->assertFalse(strpos($output, 'custom text') !== FALSE, 'Empty handler was not rendered on a non empty table.');
// Render an empty result, and ensure that the area handler is rendered.
$view->setDisplay('default');
$view->executed = TRUE;
$view->result = array();
$output = $view->preview();
$output = \Drupal::service('renderer')->renderRoot($output);
$this->assertTrue(strpos($output, 'custom text') !== FALSE, 'Empty handler got rendered on an empty table.');
}
/**
* Prepares a view executable by initializing everything which is needed.
*
* @param \Drupal\views\ViewExecutable $view
* The executable to prepare.
*/
protected function prepareView(ViewExecutable $view) {
$view->setDisplay();
$view->initStyle();
$view->initHandlers();
$view->initQuery();
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Masterminds\HTML5;
/**
* Tests some general style plugin related functionality.
*/
abstract class StyleTestBase extends ViewsKernelTestBase {
/**
* Stores the SimpleXML representation of the output.
*
* @var \SimpleXMLElement
*/
protected $elements;
/**
* Stores a view output in the elements.
*/
function storeViewPreview($output) {
$html5 = new HTML5();
$htmlDom = $html5->loadHTML('<html><body>' . $output . '</body></html>');
if ($htmlDom) {
// It's much easier to work with simplexml than DOM, luckily enough
// we can just simply import our DOM tree.
$this->elements = simplexml_import_dom($htmlDom);
}
}
}

View file

@ -0,0 +1,42 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\views\Views;
/**
* Tests unformatted style functionality.
*
* @group views
*/
class StyleUnformattedTest extends StyleTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* Make sure that the default css classes works as expected.
*/
function testDefaultRowClasses() {
$view = Views::getView('test_view');
$view->setDisplay();
$output = $view->preview();
$this->storeViewPreview(\Drupal::service('renderer')->renderRoot($output));
$rows = $this->elements->body->div->div;
$count = 0;
$count_result = count($view->result);
foreach ($rows as $row) {
$count++;
$attributes = $row->attributes();
$class = (string) $attributes['class'][0];
$this->assertTrue(strpos($class, 'views-row') !== FALSE, 'Make sure that the views row class is set right.');
}
$this->assertIdentical($count, $count_result);
}
}

View file

@ -0,0 +1,54 @@
<?php
namespace Drupal\Tests\views\Kernel\Plugin;
use Drupal\views\Plugin\Block\ViewsBlock;
use Drupal\views\Tests\ViewTestData;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
/**
* Tests native behaviors of the block views plugin.
*
* @group views
*/
class ViewsBlockTest extends ViewsKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('block', 'block_test_views');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view_block');
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp();
ViewTestData::createTestViews(get_class($this), array('block_test_views'));
}
/**
* Tests that ViewsBlock::getMachineNameSuggestion() produces the right value.
*
* @see \Drupal\views\Plugin\Block::getmachineNameSuggestion().
*/
public function testMachineNameSuggestion() {
$plugin_definition = array(
'provider' => 'views',
);
$plugin_id = 'views_block:test_view_block-block_1';
$views_block = ViewsBlock::create($this->container, array(), $plugin_id, $plugin_definition);
$this->assertEqual($views_block->getMachineNameSuggestion(), 'views_block__test_view_block_block_1');
}
}

View file

@ -0,0 +1,96 @@
<?php
namespace Drupal\Tests\views\Kernel;
use Drupal\views\Views;
/**
* Tests that an instance of all views plugins can be created.
*
* @group views
*/
class PluginInstanceTest extends ViewsKernelTestBase {
/**
* All views plugin types.
*
* @var array
*/
protected $pluginTypes = array(
'access',
'area',
'argument',
'argument_default',
'argument_validator',
'cache',
'display_extender',
'display',
'exposed_form',
'field',
'filter',
'join',
'pager',
'query',
'relationship',
'row',
'sort',
'style',
'wizard',
);
/**
* An array of plugin definitions, keyed by plugin type.
*
* @var array
*/
protected $definitions;
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->definitions = Views::getPluginDefinitions();
}
/**
* Confirms that there is plugin data for all views plugin types.
*/
public function testPluginData() {
// Check that we have an array of data.
$this->assertTrue(is_array($this->definitions), 'Plugin data is an array.');
// Check all plugin types.
foreach ($this->pluginTypes as $type) {
$this->assertTrue(array_key_exists($type, $this->definitions), format_string('Key for plugin type @type found.', array('@type' => $type)));
$this->assertTrue(is_array($this->definitions[$type]) && !empty($this->definitions[$type]), format_string('Plugin type @type has an array of plugins.', array('@type' => $type)));
}
// Tests that the plugin list has not missed any types.
$diff = array_diff(array_keys($this->definitions), $this->pluginTypes);
$this->assertTrue(empty($diff), 'All plugins were found and matched.');
}
/**
* Tests creating instances of every views plugin.
*
* This will iterate through all plugins from _views_fetch_plugin_data().
*/
public function testPluginInstances() {
foreach ($this->definitions as $type => $plugins) {
// Get a plugin manager for this type.
$manager = $this->container->get("plugin.manager.views.$type");
foreach ($plugins as $id => $definition) {
// Get a reflection class for this plugin.
// We only want to test true plugins, i.e. They extend PluginBase.
$reflection = new \ReflectionClass($definition['class']);
if ($reflection->isSubclassOf('Drupal\views\Plugin\views\PluginBase')) {
// Create a plugin instance and check what it is. This is not just
// good to check they can be created but for throwing any notices for
// method signatures etc. too.
$instance = $manager->createInstance($id);
$this->assertTrue($instance instanceof $definition['class'], format_string('Instance of @type:@id created', array('@type' => $type, '@id' => $id)));
}
}
}
}
}

View file

@ -0,0 +1,334 @@
<?php
namespace Drupal\Tests\views\Kernel;
use Drupal\entity_test\Entity\EntityTestMul;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\views\Views;
/**
* Tests aggregate functionality of views, for example count.
*
* @group views
*/
class QueryGroupByTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_group_by_in_filters', 'test_aggregate_count', 'test_group_by_count', 'test_group_by_count_multicardinality', 'test_group_by_field_not_within_bundle');
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('entity_test', 'system', 'field', 'user', 'language');
/**
* The storage for the test entity type.
*
* @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage
*/
public $storage;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test');
$this->installEntitySchema('entity_test_mul');
$this->storage = $this->container->get('entity.manager')->getStorage('entity_test');
ConfigurableLanguage::createFromLangcode('it')->save();
}
/**
* Tests aggregate count feature.
*/
public function testAggregateCount() {
$this->setupTestEntities();
$view = Views::getView('test_aggregate_count');
$this->executeView($view);
$this->assertEqual(count($view->result), 2, 'Make sure the count of items is right.');
$types = array();
foreach ($view->result as $item) {
// num_records is a alias for id.
$types[$item->entity_test_name] = $item->num_records;
}
$this->assertEqual($types['name1'], 4, 'Groupby the name: name1 returned the expected amount of results.');
$this->assertEqual($types['name2'], 3, 'Groupby the name: name2 returned the expected amount of results.');
}
/**
* Provides a test helper which runs a view with some aggregation function.
*
* @param string|null $aggregation_function
* Which aggregation function should be used, for example sum or count. If
* NULL is passed the aggregation will be tested with no function.
* @param array $values
* The expected views result.
*/
public function groupByTestHelper($aggregation_function, $values) {
$this->setupTestEntities();
$view = Views::getView('test_group_by_count');
$view->setDisplay();
// There is no need for a function in order to have aggregation.
if (empty($aggregation_function)) {
// The test table has 2 fields ('id' and 'name'). We'll remove 'id'
// because it's unique and will test aggregation on 'name'.
unset($view->displayHandlers->get('default')->options['fields']['id']);
}
else {
$view->displayHandlers->get('default')->options['fields']['id']['group_type'] = $aggregation_function;
}
$this->executeView($view);
$this->assertEqual(count($view->result), 2, 'Make sure the count of items is right.');
// Group by name to identify the right count.
$results = array();
foreach ($view->result as $item) {
$results[$item->entity_test_name] = $item->id;
}
$this->assertEqual($results['name1'], $values[0], format_string('Aggregation with @aggregation_function and groupby name: name1 returned the expected amount of results', array('@aggregation_function' => $aggregation_function)));
$this->assertEqual($results['name2'], $values[1], format_string('Aggregation with @aggregation_function and groupby name: name2 returned the expected amount of results', array('@aggregation_function' => $aggregation_function)));
}
/**
* Helper method that creates some test entities.
*/
protected function setupTestEntities() {
// Create 4 entities with name1 and 3 entities with name2.
$entity_1 = array(
'name' => 'name1',
);
$this->storage->create($entity_1)->save();
$this->storage->create($entity_1)->save();
$this->storage->create($entity_1)->save();
$this->storage->create($entity_1)->save();
$entity_2 = array(
'name' => 'name2',
);
$this->storage->create($entity_2)->save();
$this->storage->create($entity_2)->save();
$this->storage->create($entity_2)->save();
}
/**
* Tests the count aggregation function.
*/
public function testGroupByCount() {
$this->groupByTestHelper('count', array(4, 3));
}
/**
* Tests the sum aggregation function.
*/
public function testGroupBySum() {
$this->groupByTestHelper('sum', array(10, 18));
}
/**
* Tests the average aggregation function.
*/
public function testGroupByAverage() {
$this->groupByTestHelper('avg', array(2.5, 6));
}
/**
* Tests the min aggregation function.
*/
public function testGroupByMin() {
$this->groupByTestHelper('min', array(1, 5));
}
/**
* Tests the max aggregation function.
*/
public function testGroupByMax() {
$this->groupByTestHelper('max', array(4, 7));
}
/**
* Tests aggregation with no specific function.
*/
public function testGroupByNone() {
$this->groupByTestHelper(NULL, array(1, 5));
}
/**
* Tests groupby with filters.
*/
public function testGroupByCountOnlyFilters() {
// Check if GROUP BY and HAVING are included when a view
// doesn't display SUM, COUNT, MAX, etc. functions in SELECT statement.
for ($x = 0; $x < 10; $x++) {
$this->storage->create(array('name' => 'name1'))->save();
}
$view = Views::getView('test_group_by_in_filters');
$this->executeView($view);
$this->assertTrue(strpos($view->build_info['query'], 'GROUP BY'), 'Make sure that GROUP BY is in the query');
$this->assertTrue(strpos($view->build_info['query'], 'HAVING'), 'Make sure that HAVING is in the query');
}
/**
* Tests grouping on base field.
*/
public function testGroupByBaseField() {
$this->setupTestEntities();
$view = Views::getView('test_group_by_count');
$view->setDisplay();
// This tests that the GROUP BY portion of the query is properly formatted
// to include the base table to avoid ambiguous field errors.
$view->displayHandlers->get('default')->options['fields']['name']['group_type'] = 'min';
unset($view->displayHandlers->get('default')->options['fields']['id']['group_type']);
$this->executeView($view);
$this->assertTrue(strpos($view->build_info['query'], 'GROUP BY entity_test.id'), 'GROUP BY field includes the base table name when grouping on the base field.');
}
/**
* Tests grouping a field with cardinality > 1.
*/
public function testGroupByFieldWithCardinality() {
$field_storage = FieldStorageConfig::create([
'type' => 'integer',
'field_name' => 'field_test',
'cardinality' => 4,
'entity_type' => 'entity_test_mul',
]);
$field_storage->save();
$field = FieldConfig::create([
'field_name' => 'field_test',
'entity_type' => 'entity_test_mul',
'bundle' => 'entity_test_mul',
]);
$field->save();
$entities = [];
$entity = EntityTestMul::create([
'field_test' => [1, 1, 1],
]);
$entity->save();
$entities[] = $entity;
$entity = EntityTestMul::create([
'field_test' => [2, 2, 2],
]);
$entity->save();
$entities[] = $entity;
$entity = EntityTestMul::create([
'field_test' => [2, 2, 2],
]);
$entity->save();
$entities[] = $entity;
$view = Views::getView('test_group_by_count_multicardinality');
$this->executeView($view);
$this->assertEqual(2, count($view->result));
$this->assertEqual('3', $view->getStyle()->getField(0, 'id'));
$this->assertEqual('1', $view->getStyle()->getField(0, 'field_test'));
$this->assertEqual('6', $view->getStyle()->getField(1, 'id'));
$this->assertEqual('2', $view->getStyle()->getField(1, 'field_test'));
$entities[2]->field_test[0]->value = 3;
$entities[2]->field_test[1]->value = 4;
$entities[2]->field_test[2]->value = 5;
$entities[2]->save();
$view = Views::getView('test_group_by_count_multicardinality');
$this->executeView($view);
$this->assertEqual(5, count($view->result));
$this->assertEqual('3', $view->getStyle()->getField(0, 'id'));
$this->assertEqual('1', $view->getStyle()->getField(0, 'field_test'));
$this->assertEqual('3', $view->getStyle()->getField(1, 'id'));
$this->assertEqual('2', $view->getStyle()->getField(1, 'field_test'));
$this->assertEqual('1', $view->getStyle()->getField(2, 'id'));
$this->assertEqual('3', $view->getStyle()->getField(2, 'field_test'));
$this->assertEqual('1', $view->getStyle()->getField(3, 'id'));
$this->assertEqual('4', $view->getStyle()->getField(3, 'field_test'));
$this->assertEqual('1', $view->getStyle()->getField(4, 'id'));
$this->assertEqual('5', $view->getStyle()->getField(4, 'field_test'));
// Check that translated values are correctly retrieved and are not grouped
// into the original entity.
$translation = $entity->addTranslation('it');
$translation->field_test = [6, 6, 6];
$translation->save();
$view = Views::getView('test_group_by_count_multicardinality');
$this->executeView($view);
$this->assertEqual(6, count($view->result));
$this->assertEqual('3', $view->getStyle()->getField(5, 'id'));
$this->assertEqual('6', $view->getStyle()->getField(5, 'field_test'));
}
/**
* Tests groupby with a field not existing on some bundle.
*/
public function testGroupByWithFieldsNotExistingOnBundle() {
$field_storage = FieldStorageConfig::create([
'type' => 'integer',
'field_name' => 'field_test',
'cardinality' => 4,
'entity_type' => 'entity_test_mul',
]);
$field_storage->save();
$field = FieldConfig::create([
'field_name' => 'field_test',
'entity_type' => 'entity_test_mul',
'bundle' => 'entity_test_mul',
]);
$field->save();
$entities = [];
$entity = EntityTestMul::create([
'field_test' => [1],
'type' => 'entity_test_mul',
]);
$entity->save();
$entities[] = $entity;
$entity = EntityTestMul::create([
'type' => 'entity_test_mul2',
]);
$entity->save();
$entities[] = $entity;
$view = Views::getView('test_group_by_field_not_within_bundle');
$this->executeView($view);
$this->assertEqual(2, count($view->result));
// The first result is coming from entity_test_mul2, so no field could be
// rendered.
$this->assertEqual('', $view->getStyle()->getField(0, 'field_test'));
// The second result is coming from entity_test_mul, so its field value
// could be rendered.
$this->assertEqual('1', $view->getStyle()->getField(1, 'field_test'));
}
}

View file

@ -0,0 +1,303 @@
<?php
namespace Drupal\Tests\views\Kernel;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\views\Tests\AssertViewsCacheTagsTrait;
use Drupal\views\Views;
use Drupal\views\Entity\View;
/**
* Tests the general integration between views and the render cache.
*
* @group views
*/
class RenderCacheIntegrationTest extends ViewsKernelTestBase {
use AssertViewsCacheTagsTrait;
/**
* {@inheritdoc}
*/
public static $testViews = ['test_view', 'test_display', 'entity_test_fields', 'entity_test_row'];
/**
* {@inheritdoc}
*/
public static $modules = ['entity_test', 'user', 'node'];
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->installEntitySchema('entity_test');
$this->installEntitySchema('user');
}
/**
* Tests a field-based view's cache tags when using the "none" cache plugin.
*/
public function testFieldBasedViewCacheTagsWithCachePluginNone() {
$view = Views::getview('entity_test_fields');
$view->getDisplay()->overrideOption('cache', [
'type' => 'none',
]);
$view->save();
$this->assertCacheTagsForFieldBasedView(FALSE);
}
/**
* Tests a field-based view's cache tags when using the "tag" cache plugin.
*/
public function testFieldBasedViewCacheTagsWithCachePluginTag() {
$view = Views::getview('entity_test_fields');
$view->getDisplay()->overrideOption('cache', [
'type' => 'tag',
]);
$view->save();
$this->assertCacheTagsForFieldBasedView(TRUE);
}
/**
* Tests a field-based view's cache tags when using the "time" cache plugin.
*/
public function testFieldBasedViewCacheTagsWithCachePluginTime() {
$view = Views::getview('entity_test_fields');
$view->getDisplay()->overrideOption('cache', [
'type' => 'time',
'options' => [
'results_lifespan' => 3600,
'output_lifespan' => 3600,
],
]);
$view->save();
$this->assertCacheTagsForFieldBasedView(TRUE);
}
/**
* Tests cache tags on output & result cache items for a field-based view.
*
* @param bool $do_assert_views_caches
* Whether to check Views' result & output caches.
*/
protected function assertCacheTagsForFieldBasedView($do_assert_views_caches) {
$this->pass('Checking cache tags for field-based view.');
$view = Views::getview('entity_test_fields');
// Empty result (no entities yet).
$this->pass('Test without entities');
$base_tags = ['config:views.view.entity_test_fields', 'entity_test_list'];
$this->assertViewsCacheTags($view, $base_tags, $do_assert_views_caches, $base_tags);
$this->assertViewsCacheTagsFromStaticRenderArray($view, $base_tags, $do_assert_views_caches);
// Non-empty result (1 entity).
/** @var \Drupal\Core\Entity\EntityInterface[] $entities */
$entities[] = $entity = EntityTest::create();
$entity->save();
$this->pass('Test with entities');
$tags_with_entity = Cache::mergeTags($base_tags, $entities[0]->getCacheTags());
$this->assertViewsCacheTags($view, $tags_with_entity, $do_assert_views_caches, $tags_with_entity);
$this->assertViewsCacheTagsFromStaticRenderArray($view, $tags_with_entity, $do_assert_views_caches);
// Paged result (more entities than the items-per-page limit).
for ($i = 0; $i < 5; $i++) {
$entities[] = $entity = EntityTest::create();
$entity->save();
}
// Page 1.
$this->pass('Test pager');
$this->pass('Page 1');
\Drupal::request()->query->set('page', 0);
$tags_page_1 = Cache::mergeTags($base_tags, $entities[1]->getCacheTags());
$tags_page_1 = Cache::mergeTags($tags_page_1, $entities[2]->getCacheTags());
$tags_page_1 = Cache::mergeTags($tags_page_1, $entities[3]->getCacheTags());
$tags_page_1 = Cache::mergeTags($tags_page_1, $entities[4]->getCacheTags());
$tags_page_1 = Cache::mergeTags($tags_page_1, $entities[5]->getCacheTags());
$this->assertViewsCacheTags($view, $tags_page_1, $do_assert_views_caches, $tags_page_1);
$this->assertViewsCacheTagsFromStaticRenderArray($view, $tags_page_1, $do_assert_views_caches);
$view->destroy();
// Page 2.
$this->pass('Page 2');
$view->setCurrentPage(1);
\Drupal::request()->query->set('page', 1);
$tags_page_2 = Cache::mergeTags($base_tags, $entities[0]->getCacheTags());
$this->assertViewsCacheTags($view, $tags_page_2, $do_assert_views_caches, $tags_page_2);
$view->destroy();
// Ensure that invalidation works on both pages.
$this->pass('Page invalidations');
$this->pass('Page 2');
$view->setCurrentPage(1);
\Drupal::request()->query->set('page', 1);
$entities[0]->name->value = $random_name = $this->randomMachineName();
$entities[0]->save();
$build = $this->assertViewsCacheTags($view, $tags_page_2, $do_assert_views_caches, $tags_page_2);
// @todo Static render arrays don't support different pages yet, see
// https://www.drupal.org/node/2500701.
// $this->assertViewsCacheTagsFromStaticRenderArray($view, $tags_page_2, $do_assert_views_caches);
$this->assertTrue(strpos($build['#markup'], $random_name) !== FALSE);
$view->destroy();
$this->pass('Page 1');
$view->setCurrentPage(0);
\Drupal::request()->query->set('page', 0);
$entities[1]->name->value = $random_name = $this->randomMachineName();
$entities[1]->save();
$build = $this->assertViewsCacheTags($view, $tags_page_1, $do_assert_views_caches, $tags_page_1);
$this->assertViewsCacheTagsFromStaticRenderArray($view, $tags_page_1, $do_assert_views_caches);
$this->assertTrue(strpos($build['#markup'], $random_name) !== FALSE);
$view->destroy();
// Setup arguments to ensure that render caching also varies by them.
$this->pass('Test arguments');
// Custom assert for a single result row.
$single_entity_assertions = function(array $build, EntityInterface $entity) {
$this->setRawContent($build['#markup']);
$result = $this->cssSelect('div.views-row');
$count = count($result);
$this->assertEqual($count, 1);
$this->assertEqual((string) $result[0]->div->span, (string) $entity->id());
};
// Execute the view once with a static renderable and one with a full
// prepared render array.
$tags_argument = Cache::mergeTags($base_tags, $entities[0]->getCacheTags());
$view->setArguments([$entities[0]->id()]);
$build = $this->assertViewsCacheTags($view, $tags_argument, $do_assert_views_caches, $tags_argument);
$single_entity_assertions($build, $entities[0]);
$view->setArguments([$entities[0]->id()]);
$build = $this->assertViewsCacheTagsFromStaticRenderArray($view, $tags_argument, $do_assert_views_caches);
$single_entity_assertions($build, $entities[0]);
// Set a different argument and ensure that the result is different.
$tags2_argument = Cache::mergeTags($base_tags, $entities[1]->getCacheTags());
$view->setArguments([$entities[1]->id()]);
$build = $this->assertViewsCacheTagsFromStaticRenderArray($view, $tags2_argument, $do_assert_views_caches);
$single_entity_assertions($build, $entities[1]);
$view->destroy();
}
/**
* Tests a entity-based view's cache tags when using the "none" cache plugin.
*/
public function testEntityBasedViewCacheTagsWithCachePluginNone() {
$view = Views::getview('entity_test_row');
$view->getDisplay()->overrideOption('cache', [
'type' => 'none',
]);
$view->save();
$this->assertCacheTagsForEntityBasedView(FALSE);
}
/**
* Tests a entity-based view's cache tags when using the "tag" cache plugin.
*/
public function testEntityBasedViewCacheTagsWithCachePluginTag() {
$view = Views::getview('entity_test_row');
$view->getDisplay()->overrideOption('cache', [
'type' => 'tag',
]);
$view->save();
$this->assertCacheTagsForEntityBasedView(TRUE);
}
/**
* Tests a entity-based view's cache tags when using the "time" cache plugin.
*/
public function testEntityBasedViewCacheTagsWithCachePluginTime() {
$view = Views::getview('entity_test_row');
$view->getDisplay()->overrideOption('cache', [
'type' => 'time',
'options' => [
'results_lifespan' => 3600,
'output_lifespan' => 3600,
],
]);
$view->save();
$this->assertCacheTagsForEntityBasedView(TRUE);
}
/**
* Tests cache tags on output & result cache items for an entity-based view.
*/
protected function assertCacheTagsForEntityBasedView($do_assert_views_caches) {
$this->pass('Checking cache tags for entity-based view.');
$view = Views::getview('entity_test_row');
// Empty result (no entities yet).
$base_tags = $base_render_tags = ['config:views.view.entity_test_row', 'entity_test_list'];
$this->assertViewsCacheTags($view, $base_tags, $do_assert_views_caches, $base_tags);
$this->assertViewsCacheTagsFromStaticRenderArray($view, $base_tags, $do_assert_views_caches);
// Non-empty result (1 entity).
$entities[] = $entity = EntityTest::create();
$entity->save();
$result_tags_with_entity = Cache::mergeTags($base_tags, $entities[0]->getCacheTags());
$render_tags_with_entity = Cache::mergeTags($base_render_tags, $entities[0]->getCacheTags());
$render_tags_with_entity = Cache::mergeTags($render_tags_with_entity, ['entity_test_view']);
$this->assertViewsCacheTags($view, $result_tags_with_entity, $do_assert_views_caches, $render_tags_with_entity);
$this->assertViewsCacheTagsFromStaticRenderArray($view, $render_tags_with_entity, $do_assert_views_caches);
// Paged result (more entities than the items-per-page limit).
for ($i = 0; $i < 5; $i++) {
$entities[] = $entity = EntityTest::create();
$entity->save();
}
$new_entities_cache_tags = Cache::mergeTags($entities[1]->getCacheTags(), $entities[2]->getCacheTags());
$new_entities_cache_tags = Cache::mergeTags($new_entities_cache_tags, $entities[3]->getCacheTags());
$new_entities_cache_tags = Cache::mergeTags($new_entities_cache_tags, $entities[4]->getCacheTags());
$new_entities_cache_tags = Cache::mergeTags($new_entities_cache_tags, $entities[5]->getCacheTags());
$result_tags_page_1 = Cache::mergeTags($base_tags, $new_entities_cache_tags);
$render_tags_page_1 = Cache::mergeTags($base_render_tags, $new_entities_cache_tags);
$render_tags_page_1 = Cache::mergeTags($render_tags_page_1, ['entity_test_view']);
$this->assertViewsCacheTags($view, $result_tags_page_1, $do_assert_views_caches, $render_tags_page_1);
$this->assertViewsCacheTagsFromStaticRenderArray($view, $render_tags_page_1, $do_assert_views_caches);
}
/**
* Ensure that the view renderable contains the cache contexts.
*/
public function testBuildRenderableWithCacheContexts() {
$view = View::load('test_view');
$display =& $view->getDisplay('default');
$display['cache_metadata']['contexts'] = ['views_test_cache_context'];
$executable = $view->getExecutable();
$build = $executable->buildRenderable();
$this->assertEqual(['views_test_cache_context'], $build['#cache']['contexts']);
}
/**
* Ensures that saving a view calculates the cache contexts.
*/
public function testViewAddCacheMetadata() {
$view = View::load('test_display');
$view->save();
$this->assertEqual(['languages:' . LanguageInterface::TYPE_CONTENT, 'languages:' . LanguageInterface::TYPE_INTERFACE, 'url.query_args', 'user.node_grants:view', 'user.permissions'], $view->getDisplay('default')['cache_metadata']['contexts']);
}
}

View file

@ -0,0 +1,93 @@
<?php
namespace Drupal\Tests\views\Kernel;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\views\Views;
/**
* Tests core view token replacement.
*
* @group views
*/
class TokenReplaceTest extends ViewsKernelTestBase {
public static $modules = array('system');
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_tokens');
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->container->get('router.builder')->rebuild();
}
/**
* Tests core token replacements generated from a view.
*/
function testTokenReplacement() {
$token_handler = \Drupal::token();
$view = Views::getView('test_tokens');
$view->setDisplay('page_1');
$this->executeView($view);
$expected = array(
'[view:label]' => 'Test tokens',
'[view:description]' => 'Test view to token replacement tests.',
'[view:id]' => 'test_tokens',
'[view:title]' => 'Test token page',
'[view:url]' => $view->getUrl(NULL, 'page_1')->setAbsolute(TRUE)->toString(),
'[view:total-rows]' => (string) $view->total_rows,
'[view:base-table]' => 'views_test_data',
'[view:base-field]' => 'id',
'[view:items-per-page]' => '10',
'[view:current-page]' => '1',
'[view:page-count]' => '1',
);
$base_bubbleable_metadata = BubbleableMetadata::createFromObject($view->storage);
$metadata_tests = [];
$metadata_tests['[view:label]'] = $base_bubbleable_metadata;
$metadata_tests['[view:description]'] = $base_bubbleable_metadata;
$metadata_tests['[view:id]'] = $base_bubbleable_metadata;
$metadata_tests['[view:title]'] = $base_bubbleable_metadata;
$metadata_tests['[view:url]'] = $base_bubbleable_metadata;
$metadata_tests['[view:total-rows]'] = $base_bubbleable_metadata;
$metadata_tests['[view:base-table]'] = $base_bubbleable_metadata;
$metadata_tests['[view:base-field]'] = $base_bubbleable_metadata;
$metadata_tests['[view:items-per-page]'] = $base_bubbleable_metadata;
$metadata_tests['[view:current-page]'] = $base_bubbleable_metadata;
$metadata_tests['[view:page-count]'] = $base_bubbleable_metadata;
foreach ($expected as $token => $expected_output) {
$bubbleable_metadata = new BubbleableMetadata();
$output = $token_handler->replace($token, array('view' => $view), [], $bubbleable_metadata);
$this->assertIdentical($output, $expected_output, format_string('Token %token replaced correctly.', array('%token' => $token)));
$this->assertEqual($bubbleable_metadata, $metadata_tests[$token]);
}
}
/**
* Tests core token replacements generated from a view without results.
*/
function testTokenReplacementNoResults() {
$token_handler = \Drupal::token();
$view = Views::getView('test_tokens');
$view->setDisplay('page_2');
$this->executeView($view);
$expected = array(
'[view:page-count]' => '1',
);
foreach ($expected as $token => $expected_output) {
$output = $token_handler->replace($token, array('view' => $view));
$this->assertIdentical($output, $expected_output, format_string('Token %token replaced correctly.', array('%token' => $token)));
}
}
}

View file

@ -0,0 +1,486 @@
<?php
namespace Drupal\Tests\views\Kernel;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Component\Utility\Xss;
use Drupal\node\Entity\NodeType;
use Drupal\views\Entity\View;
use Drupal\views\Views;
use Drupal\views\ViewExecutable;
use Drupal\views\ViewExecutableFactory;
use Drupal\views\DisplayPluginCollection;
use Drupal\views\Plugin\views\display\DefaultDisplay;
use Drupal\views\Plugin\views\display\Page;
use Drupal\views\Plugin\views\style\DefaultStyle;
use Drupal\views\Plugin\views\style\Grid;
use Drupal\views\Plugin\views\row\Fields;
use Drupal\views\Plugin\views\query\Sql;
use Drupal\views\Plugin\views\pager\PagerPluginBase;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\views_test_data\Plugin\views\display\DisplayTest;
use Symfony\Component\HttpFoundation\Response;
/**
* Tests the ViewExecutable class.
*
* @group views
* @see \Drupal\views\ViewExecutable
*/
class ViewExecutableTest extends ViewsKernelTestBase {
use CommentTestTrait;
public static $modules = ['system', 'node', 'comment', 'user', 'filter', 'field', 'text'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_destroy', 'test_executable_displays');
/**
* Properties that should be stored in the configuration.
*
* @var array
*/
protected $configProperties = array(
'disabled',
'name',
'description',
'tag',
'base_table',
'label',
'core',
'display',
);
/**
* Properties that should be stored in the executable.
*
* @var array
*/
protected $executableProperties = array(
'storage',
'built',
'executed',
'args',
'build_info',
'result',
'attachment_before',
'attachment_after',
'exposed_data',
'exposed_raw_input',
'old_view',
'parent_views',
);
protected function setUpFixtures() {
$this->installEntitySchema('user');
$this->installEntitySchema('node');
$this->installEntitySchema('comment');
$this->installSchema('comment', array('comment_entity_statistics'));
$this->installConfig(array('system', 'field', 'node', 'comment'));
NodeType::create([
'type' => 'page',
'name' => 'Page',
])->save();
$this->addDefaultCommentField('node', 'page');
parent::setUpFixtures();
$this->installConfig(array('filter'));
}
/**
* Tests the views.executable container service.
*/
public function testFactoryService() {
$factory = $this->container->get('views.executable');
$this->assertTrue($factory instanceof ViewExecutableFactory, 'A ViewExecutableFactory instance was returned from the container.');
$view = entity_load('view', 'test_executable_displays');
$this->assertTrue($factory->get($view) instanceof ViewExecutable, 'A ViewExecutable instance was returned from the factory.');
}
/**
* Tests the initDisplay() and initHandlers() methods.
*/
public function testInitMethods() {
$view = Views::getView('test_destroy');
$view->initDisplay();
$this->assertTrue($view->display_handler instanceof DefaultDisplay, 'Make sure a reference to the current display handler is set.');
$this->assertTrue($view->displayHandlers->get('default') instanceof DefaultDisplay, 'Make sure a display handler is created for each display.');
$view->destroy();
$view->initHandlers();
// Check for all handler types.
$handler_types = array_keys(ViewExecutable::getHandlerTypes());
foreach ($handler_types as $type) {
// The views_test integration doesn't have relationships.
if ($type == 'relationship') {
continue;
}
$this->assertTrue(count($view->$type), format_string('Make sure a %type instance got instantiated.', array('%type' => $type)));
}
// initHandlers() should create display handlers automatically as well.
$this->assertTrue($view->display_handler instanceof DefaultDisplay, 'Make sure a reference to the current display handler is set.');
$this->assertTrue($view->displayHandlers->get('default') instanceof DefaultDisplay, 'Make sure a display handler is created for each display.');
$view_hash = spl_object_hash($view);
$display_hash = spl_object_hash($view->display_handler);
// Test the initStyle() method.
$view->initStyle();
$this->assertTrue($view->style_plugin instanceof DefaultStyle, 'Make sure a reference to the style plugin is set.');
// Test the plugin has been inited and view have references to the view and
// display handler.
$this->assertEqual(spl_object_hash($view->style_plugin->view), $view_hash);
$this->assertEqual(spl_object_hash($view->style_plugin->displayHandler), $display_hash);
// Test the initQuery method().
$view->initQuery();
$this->assertTrue($view->query instanceof Sql, 'Make sure a reference to the query is set');
$this->assertEqual(spl_object_hash($view->query->view), $view_hash);
$this->assertEqual(spl_object_hash($view->query->displayHandler), $display_hash);
$view->destroy();
// Test the plugin get methods.
$display_plugin = $view->getDisplay();
$this->assertTrue($display_plugin instanceof DefaultDisplay, 'An instance of DefaultDisplay was returned.');
$this->assertTrue($view->display_handler instanceof DefaultDisplay, 'The display_handler property has been set.');
$this->assertIdentical($display_plugin, $view->getDisplay(), 'The same display plugin instance was returned.');
$style_plugin = $view->getStyle();
$this->assertTrue($style_plugin instanceof DefaultStyle, 'An instance of DefaultStyle was returned.');
$this->assertTrue($view->style_plugin instanceof DefaultStyle, 'The style_plugin property has been set.');
$this->assertIdentical($style_plugin, $view->getStyle(), 'The same style plugin instance was returned.');
$pager_plugin = $view->getPager();
$this->assertTrue($pager_plugin instanceof PagerPluginBase, 'An instance of PagerPluginBase was returned.');
$this->assertTrue($view->pager instanceof PagerPluginBase, 'The pager property has been set.');
$this->assertIdentical($pager_plugin, $view->getPager(), 'The same pager plugin instance was returned.');
$query_plugin = $view->getQuery();
$this->assertTrue($query_plugin instanceof QueryPluginBase, 'An instance of QueryPluginBase was returned.');
$this->assertTrue($view->query instanceof QueryPluginBase, 'The query property has been set.');
$this->assertIdentical($query_plugin, $view->getQuery(), 'The same query plugin instance was returned.');
}
/**
* Tests the generation of the executable object.
*/
public function testConstructing() {
Views::getView('test_destroy');
}
/**
* Tests the accessing of values on the object.
*/
public function testProperties() {
$view = Views::getView('test_destroy');
foreach ($this->executableProperties as $property) {
$this->assertTrue(isset($view->{$property}));
}
// Per default exposed input should fall back to an empty array.
$this->assertEqual($view->getExposedInput(), []);
}
public function testSetDisplayWithInvalidDisplay() {
$view = Views::getView('test_executable_displays');
$view->initDisplay();
// Error is triggered while calling the wrong display.
$this->setExpectedException(\PHPUnit_Framework_Error::class);
$view->setDisplay('invalid');
$this->assertEqual($view->current_display, 'default', 'If setDisplay is called with an invalid display id the default display should be used.');
$this->assertEqual(spl_object_hash($view->display_handler), spl_object_hash($view->displayHandlers->get('default')));
}
/**
* Tests the display related methods and properties.
*/
public function testDisplays() {
$view = Views::getView('test_executable_displays');
// Tests Drupal\views\ViewExecutable::initDisplay().
$view->initDisplay();
$this->assertTrue($view->displayHandlers instanceof DisplayPluginCollection, 'The displayHandlers property has the right class.');
// Tests the classes of the instances.
$this->assertTrue($view->displayHandlers->get('default') instanceof DefaultDisplay);
$this->assertTrue($view->displayHandlers->get('page_1') instanceof Page);
$this->assertTrue($view->displayHandlers->get('page_2') instanceof Page);
// After initializing the default display is the current used display.
$this->assertEqual($view->current_display, 'default');
$this->assertEqual(spl_object_hash($view->display_handler), spl_object_hash($view->displayHandlers->get('default')));
// All handlers should have a reference to the default display.
$this->assertEqual(spl_object_hash($view->displayHandlers->get('page_1')->default_display), spl_object_hash($view->displayHandlers->get('default')));
$this->assertEqual(spl_object_hash($view->displayHandlers->get('page_2')->default_display), spl_object_hash($view->displayHandlers->get('default')));
// Tests Drupal\views\ViewExecutable::setDisplay().
$view->setDisplay();
$this->assertEqual($view->current_display, 'default', 'If setDisplay is called with no parameter the default display should be used.');
$this->assertEqual(spl_object_hash($view->display_handler), spl_object_hash($view->displayHandlers->get('default')));
// Set two different valid displays.
$view->setDisplay('page_1');
$this->assertEqual($view->current_display, 'page_1', 'If setDisplay is called with a valid display id the appropriate display should be used.');
$this->assertEqual(spl_object_hash($view->display_handler), spl_object_hash($view->displayHandlers->get('page_1')));
$view->setDisplay('page_2');
$this->assertEqual($view->current_display, 'page_2', 'If setDisplay is called with a valid display id the appropriate display should be used.');
$this->assertEqual(spl_object_hash($view->display_handler), spl_object_hash($view->displayHandlers->get('page_2')));
// Destroy the view, so we can start again and test an invalid display.
$view->destroy();
// Test the style and row plugins are replaced correctly when setting the
// display.
$view->setDisplay('page_1');
$view->initStyle();
$this->assertTrue($view->style_plugin instanceof DefaultStyle);
$this->assertTrue($view->rowPlugin instanceof Fields);
$view->setDisplay('page_2');
$view->initStyle();
$this->assertTrue($view->style_plugin instanceof Grid);
// @todo Change this rowPlugin type too.
$this->assertTrue($view->rowPlugin instanceof Fields);
// Test the newDisplay() method.
$view = $this->container->get('entity.manager')->getStorage('view')->create(array('id' => 'test_executable_displays'));
$executable = $view->getExecutable();
$executable->newDisplay('page');
$executable->newDisplay('page');
$executable->newDisplay('display_test');
$this->assertTrue($executable->displayHandlers->get('default') instanceof DefaultDisplay);
$this->assertFalse(isset($executable->displayHandlers->get('default')->default_display));
$this->assertTrue($executable->displayHandlers->get('page_1') instanceof Page);
$this->assertTrue($executable->displayHandlers->get('page_1')->default_display instanceof DefaultDisplay);
$this->assertTrue($executable->displayHandlers->get('page_2') instanceof Page);
$this->assertTrue($executable->displayHandlers->get('page_2')->default_display instanceof DefaultDisplay);
$this->assertTrue($executable->displayHandlers->get('display_test_1') instanceof DisplayTest);
$this->assertTrue($executable->displayHandlers->get('display_test_1')->default_display instanceof DefaultDisplay);
}
/**
* Tests the setting/getting of properties.
*/
public function testPropertyMethods() {
$view = Views::getView('test_executable_displays');
// Test the setAjaxEnabled() method.
$this->assertFalse($view->ajaxEnabled());
$view->setAjaxEnabled(TRUE);
$this->assertTrue($view->ajaxEnabled());
$view->setDisplay();
// There should be no pager set initially.
$this->assertNull($view->usePager());
// Add a pager, initialize, and test.
$view->displayHandlers->get('default')->overrideOption('pager', array(
'type' => 'full',
'options' => array('items_per_page' => 10),
));
$view->initPager();
$this->assertTrue($view->usePager());
// Test setting and getting the offset.
$rand = rand();
$view->setOffset($rand);
$this->assertEqual($view->getOffset(), $rand);
// Test the getBaseTable() method.
$expected = array(
'views_test_data' => TRUE,
'#global' => TRUE,
);
$this->assertIdentical($view->getBaseTables(), $expected);
// Test response methods.
$this->assertTrue($view->getResponse() instanceof Response, 'New response object returned.');
$new_response = new Response();
$view->setResponse($new_response);
$this->assertIdentical(spl_object_hash($view->getResponse()), spl_object_hash($new_response), 'New response object correctly set.');
// Test the getPath() method.
$path = $this->randomMachineName();
$view->displayHandlers->get('page_1')->overrideOption('path', $path);
$view->setDisplay('page_1');
$this->assertEqual($view->getPath(), $path);
// Test the override_path property override.
$override_path = $this->randomMachineName();
$view->override_path = $override_path;
$this->assertEqual($view->getPath(), $override_path);
// Test the title methods.
$title = $this->randomString();
$view->setTitle($title);
$this->assertEqual($view->getTitle(), Xss::filterAdmin($title));
}
/**
* Tests the deconstructor to be sure that necessary objects are removed.
*/
public function testDestroy() {
$view = Views::getView('test_destroy');
$view->preview();
$view->destroy();
$this->assertViewDestroy($view);
}
/**
* Asserts that expected view properties have been unset by destroy().
*
* @param \Drupal\views\ViewExecutable $view
*/
protected function assertViewDestroy($view) {
$reflection = new \ReflectionClass($view);
$defaults = $reflection->getDefaultProperties();
// The storage and user should remain.
unset($defaults['storage'], $defaults['user'], $defaults['request'], $defaults['routeProvider']);
foreach ($defaults as $property => $default) {
$this->assertIdentical($this->getProtectedProperty($view, $property), $default);
}
}
/**
* Returns a protected property from a class instance.
*
* @param object $instance
* The class instance to return the property from.
* @param string $property
* The name of the property to return.
*
* @return mixed
* The instance property value.
*/
protected function getProtectedProperty($instance, $property) {
$reflection = new \ReflectionProperty($instance, $property);
$reflection->setAccessible(TRUE);
return $reflection->getValue($instance);
}
/**
* Tests ViewExecutable::getHandlerTypes().
*/
public function testGetHandlerTypes() {
$types = ViewExecutable::getHandlerTypes();
foreach (array('field', 'filter', 'argument', 'sort', 'header', 'footer', 'empty') as $type) {
$this->assertTrue(isset($types[$type]));
// @todo The key on the display should be footers, headers and empties
// or something similar instead of the singular, but so long check for
// this special case.
if (isset($types[$type]['type']) && $types[$type]['type'] == 'area') {
$this->assertEqual($types[$type]['plural'], $type);
}
else {
$this->assertEqual($types[$type]['plural'], $type . 's');
}
}
}
/**
* Tests ViewExecutable::getHandlers().
*/
public function testGetHandlers() {
$view = Views::getView('test_executable_displays');
$view->setDisplay('page_1');
$view->getHandlers('field', 'page_2');
// getHandlers() shouldn't change the active display.
$this->assertEqual('page_1', $view->current_display, "The display shouldn't change after getHandlers()");
}
/**
* Tests the validation of display handlers.
*/
public function testValidate() {
$view = Views::getView('test_executable_displays');
$view->setDisplay('page_1');
$validate = $view->validate();
// Validating a view shouldn't change the active display.
$this->assertEqual('page_1', $view->current_display, "The display should be constant while validating");
$count = 0;
foreach ($view->displayHandlers as $id => $display) {
$match = function($value) use ($display) {
return strpos($value, $display->display['display_title']) !== false;
};
$this->assertTrue(array_filter($validate[$id], $match), format_string('Error message found for @id display', array('@id' => $id)));
$count++;
}
$this->assertEqual(count($view->displayHandlers), $count, 'Error messages from all handlers merged.');
// Test that a deleted display is not included.
$display = &$view->storage->getDisplay('default');
$display['deleted'] = TRUE;
$validate_deleted = $view->validate();
$this->assertNotIdentical($validate, $validate_deleted, 'Master display has not been validated.');
}
/**
* Tests that nested loops of the display handlers won't break validation.
*/
public function testValidateNestedLoops() {
$view = View::create(['id' => 'test_validate_nested_loops']);
$executable = $view->getExecutable();
$executable->newDisplay('display_test');
$executable->newDisplay('display_test');
$errors = $executable->validate();
$total_error_count = array_reduce($errors, function ($carry, $item) {
$carry += count($item);
return $carry;
});
// Assert that there were 9 total errors across 3 displays.
$this->assertIdentical(9, $total_error_count);
$this->assertIdentical(3, count($errors));
}
/**
* Tests serialization of the ViewExecutable object.
*/
public function testSerialization() {
$view = Views::getView('test_executable_displays');
$view->setDisplay('page_1');
$view->setArguments(['test']);
$view->setCurrentPage(2);
$serialized = serialize($view);
// Test the view storage object is not present in the actual serialized
// string.
$this->assertIdentical(strpos($serialized, '"Drupal\views\Entity\View"'), FALSE, 'The Drupal\views\Entity\View class was not found in the serialized string.');
/** @var \Drupal\views\ViewExecutable $unserialized */
$unserialized = unserialize($serialized);
$this->assertTrue($unserialized instanceof ViewExecutable);
$this->assertIdentical($view->storage->id(), $unserialized->storage->id(), 'The expected storage entity was loaded on the unserialized view.');
$this->assertIdentical($unserialized->current_display, 'page_1', 'The expected display was set on the unserialized view.');
$this->assertIdentical($unserialized->args, ['test'], 'The expected argument was set on the unserialized view.');
$this->assertIdentical($unserialized->getCurrentPage(), 2, 'The expected current page was set on the unserialized view.');
}
}

View file

@ -0,0 +1,351 @@
<?php
namespace Drupal\Tests\views\Kernel;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\views\Entity\View;
use Drupal\views\Plugin\views\display\Page;
use Drupal\views\Views;
/**
* Tests the CRUD functionality for a view.
*
* @group views
* @see \Drupal\views\Entity\View
* @see \Drupal\Core\Config\Entity\ConfigEntityStorage
*/
class ViewStorageTest extends ViewsKernelTestBase {
/**
* Properties that should be stored in the configuration.
*
* @var array
*/
protected $configProperties = array(
'status',
'module',
'id',
'description',
'tag',
'base_table',
'label',
'core',
'display',
);
/**
* The entity type definition.
*
* @var \Drupal\Core\Entity\EntityTypeInterface
*/
protected $entityType;
/**
* The configuration entity storage.
*
* @var \Drupal\Core\Config\Entity\ConfigEntityStorage
*/
protected $controller;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view_storage');
/**
* Tests CRUD operations.
*/
function testConfigurationEntityCRUD() {
// Get the configuration entity type and controller.
$this->entityType = \Drupal::entityManager()->getDefinition('view');
$this->controller = $this->container->get('entity.manager')->getStorage('view');
// Confirm that an info array has been returned.
$this->assertTrue($this->entityType instanceof EntityTypeInterface, 'The View info array is loaded.');
// CRUD tests.
$this->loadTests();
$this->createTests();
$this->displayTests();
// Helper method tests
$this->displayMethodTests();
}
/**
* Tests loading configuration entities.
*/
protected function loadTests() {
$view = entity_load('view', 'test_view_storage');
$data = $this->config('views.view.test_view_storage')->get();
// Confirm that an actual view object is loaded and that it returns all of
// expected properties.
$this->assertTrue($view instanceof View, 'Single View instance loaded.');
foreach ($this->configProperties as $property) {
$this->assertTrue($view->get($property) !== NULL, format_string('Property: @property loaded onto View.', array('@property' => $property)));
}
// Check the displays have been loaded correctly from config display data.
$expected_displays = array('default', 'block_1', 'page_1');
$this->assertEqual(array_keys($view->get('display')), $expected_displays, 'The correct display names are present.');
// Check each ViewDisplay object and confirm that it has the correct key and
// property values.
foreach ($view->get('display') as $key => $display) {
$this->assertEqual($key, $display['id'], 'The display has the correct ID assigned.');
// Get original display data and confirm that the display options array
// exists.
$original_options = $data['display'][$key];
foreach ($original_options as $orig_key => $value) {
$this->assertIdentical($display[$orig_key], $value, format_string('@key is identical to saved data', array('@key' => $key)));
}
}
// Make sure that loaded default views get a UUID.
$view = Views::getView('test_view_storage');
$this->assertTrue($view->storage->uuid());
}
/**
* Tests creating configuration entities.
*/
protected function createTests() {
// Create a new View instance with empty values.
$created = $this->controller->create(array());
$this->assertTrue($created instanceof View, 'Created object is a View.');
// Check that the View contains all of the properties.
foreach ($this->configProperties as $property) {
$this->assertTrue(property_exists($created, $property), format_string('Property: @property created on View.', array('@property' => $property)));
}
// Create a new View instance with config values.
$values = $this->config('views.view.test_view_storage')->get();
$values['id'] = 'test_view_storage_new';
unset($values['uuid']);
$created = $this->controller->create($values);
$this->assertTrue($created instanceof View, 'Created object is a View.');
// Check that the View contains all of the properties.
$properties = $this->configProperties;
// Remove display from list.
array_pop($properties);
// Test all properties except displays.
foreach ($properties as $property) {
$this->assertTrue($created->get($property) !== NULL, format_string('Property: @property created on View.', array('@property' => $property)));
$this->assertIdentical($values[$property], $created->get($property), format_string('Property value: @property matches configuration value.', array('@property' => $property)));
}
// Check the UUID of the loaded View.
$created->save();
$created_loaded = entity_load('view', 'test_view_storage_new');
$this->assertIdentical($created->uuid(), $created_loaded->uuid(), 'The created UUID has been saved correctly.');
}
/**
* Tests adding, saving, and loading displays on configuration entities.
*/
protected function displayTests() {
// Check whether a display can be added and saved to a View.
$view = entity_load('view', 'test_view_storage_new');
$new_id = $view->addDisplay('page', 'Test', 'test');
$display = $view->get('display');
// Ensure the right display_plugin is created/instantiated.
$this->assertEqual($display[$new_id]['display_plugin'], 'page', 'New page display "test" uses the right display plugin.');
$executable = $view->getExecutable();
$executable->initDisplay();
$this->assertTrue($executable->displayHandlers->get($new_id) instanceof Page, 'New page display "test" uses the right display plugin.');
// To save this with a new ID, we should use createDuplicate().
$view = $view->createDuplicate();
$view->set('id', 'test_view_storage_new_new2');
$view->save();
$values = $this->config('views.view.test_view_storage_new_new2')->get();
$this->assertTrue(isset($values['display']['test']) && is_array($values['display']['test']), 'New display was saved.');
}
/**
* Tests the display related functions like getDisplaysList().
*/
protected function displayMethodTests() {
$config['display'] = array(
'page_1' => array(
'display_options' => array('path' => 'test'),
'display_plugin' => 'page',
'id' => 'page_2',
'display_title' => 'Page 1',
'position' => 1
),
'feed_1' => array(
'display_options' => array('path' => 'test.xml'),
'display_plugin' => 'feed',
'id' => 'feed',
'display_title' => 'Feed',
'position' => 2
),
'page_2' => array(
'display_options' => array('path' => 'test/%/extra'),
'display_plugin' => 'page',
'id' => 'page_2',
'display_title' => 'Page 2',
'position' => 3
)
);
$view = $this->controller->create($config);
// Tests Drupal\views\Entity\View::addDisplay()
$view = $this->controller->create(array());
$random_title = $this->randomMachineName();
$id = $view->addDisplay('page', $random_title);
$this->assertEqual($id, 'page_1', format_string('Make sure the first display (%id_new) has the expected ID (%id)', array('%id_new' => $id, '%id' => 'page_1')));
$display = $view->get('display');
$this->assertEqual($display[$id]['display_title'], $random_title);
$random_title = $this->randomMachineName();
$id = $view->addDisplay('page', $random_title);
$display = $view->get('display');
$this->assertEqual($id, 'page_2', format_string('Make sure the second display (%id_new) has the expected ID (%id)', array('%id_new' => $id, '%id' => 'page_2')));
$this->assertEqual($display[$id]['display_title'], $random_title);
$id = $view->addDisplay('page');
$display = $view->get('display');
$this->assertEqual($display[$id]['display_title'], 'Page 3');
// Ensure the 'default' display always has position zero, regardless of when
// it was set relative to other displays. Even if the 'default' display
// exists, adding it again will overwrite it, which is asserted with the new
// title.
$view->addDisplay('default', $random_title);
$displays = $view->get('display');
$this->assertEqual($displays['default']['display_title'], $random_title, 'Default display is defined with the new title');
$this->assertEqual($displays['default']['position'], 0, 'Default displays are always in position zero');
// Tests Drupal\views\Entity\View::generateDisplayId(). Since
// generateDisplayId() is protected, we have to use reflection to unit-test
// it.
$view = $this->controller->create(array());
$ref_generate_display_id = new \ReflectionMethod($view, 'generateDisplayId');
$ref_generate_display_id->setAccessible(TRUE);
$this->assertEqual(
$ref_generate_display_id->invoke($view, 'default'),
'default',
'The plugin ID for default is always default.'
);
$this->assertEqual(
$ref_generate_display_id->invoke($view, 'feed'),
'feed_1',
'The generated ID for the first instance of a plugin type should have an suffix of _1.'
);
$view->addDisplay('feed', 'feed title');
$this->assertEqual(
$ref_generate_display_id->invoke($view, 'feed'),
'feed_2',
'The generated ID for the first instance of a plugin type should have an suffix of _2.'
);
// Tests item related methods().
$view = $this->controller->create(array('base_table' => 'views_test_data'));
$view->addDisplay('default');
$view = $view->getExecutable();
$display_id = 'default';
$expected_items = array();
// Tests addHandler with getItem.
// Therefore add one item without any options and one item with some
// options.
$id1 = $view->addHandler($display_id, 'field', 'views_test_data', 'id');
$item1 = $view->getHandler($display_id, 'field', 'id');
$expected_items[$id1] = $expected_item = array(
'id' => 'id',
'table' => 'views_test_data',
'field' => 'id',
'plugin_id' => 'numeric',
);
$this->assertEqual($item1, $expected_item);
$options = array(
'alter' => array(
'text' => $this->randomMachineName()
)
);
$id2 = $view->addHandler($display_id, 'field', 'views_test_data', 'name', $options);
$item2 = $view->getHandler($display_id, 'field', 'name');
$expected_items[$id2] = $expected_item = array(
'id' => 'name',
'table' => 'views_test_data',
'field' => 'name',
'plugin_id' => 'standard',
) + $options;
$this->assertEqual($item2, $expected_item);
// Tests the expected fields from the previous additions.
$this->assertEqual($view->getHandlers('field', $display_id), $expected_items);
// Alter an existing item via setItem and check the result via getItem
// and getItems.
$item = array(
'alter' => array(
'text' => $this->randomMachineName(),
)
) + $item1;
$expected_items[$id1] = $item;
$view->setHandler($display_id, 'field', $id1, $item);
$this->assertEqual($view->getHandler($display_id, 'field', 'id'), $item);
$this->assertEqual($view->getHandlers('field', $display_id), $expected_items);
// Test removeItem method.
unset($expected_items[$id2]);
$view->removeHandler($display_id, 'field', $id2);
$this->assertEqual($view->getHandlers('field', $display_id), $expected_items);
}
/**
* Tests the createDuplicate() View method.
*/
public function testCreateDuplicate() {
$view = Views::getView('test_view_storage');
$copy = $view->storage->createDuplicate();
$this->assertTrue($copy instanceof View, 'The copied object is a View.');
// Check that the original view and the copy have different UUIDs.
$this->assertNotIdentical($view->storage->uuid(), $copy->uuid(), 'The copied view has a new UUID.');
// Check the 'name' (ID) is using the View objects default value (NULL) as it
// gets unset.
$this->assertIdentical($copy->id(), NULL, 'The ID has been reset.');
// Check the other properties.
// @todo Create a reusable property on the base test class for these?
$config_properties = array(
'disabled',
'description',
'tag',
'base_table',
'label',
'core',
);
foreach ($config_properties as $property) {
$this->assertIdentical($view->storage->get($property), $copy->get($property), format_string('@property property is identical.', array('@property' => $property)));
}
// Check the displays are the same.
$copy_display = $copy->get('display');
foreach ($view->storage->get('display') as $id => $display) {
// assertIdentical will not work here.
$this->assertEqual($display, $copy_display[$id], format_string('The @display display has been copied correctly.', array('@display' => $id)));
}
}
}

View file

@ -0,0 +1,76 @@
<?php
namespace Drupal\Tests\views\Kernel;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\image\Entity\ImageStyle;
use Drupal\views\Entity\View;
/**
* Tests integration of views with other modules.
*
* @group views
*/
class ViewsConfigDependenciesIntegrationTest extends ViewsKernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['field', 'file', 'image', 'entity_test'];
/**
* {@inheritdoc}
*/
public static $testViews = ['entity_test_fields'];
/**
* Tests integration with image module.
*/
public function testImage() {
/** @var \Drupal\image\ImageStyleInterface $style */
$style = ImageStyle::create(['name' => 'foo']);
$style->save();
// Create a new image field 'bar' to be used in 'entity_test_fields' view.
FieldStorageConfig::create([
'entity_type' => 'entity_test',
'field_name' => 'bar',
'type' => 'image',
])->save();
FieldConfig::create([
'entity_type' => 'entity_test',
'bundle' => 'entity_test',
'field_name' => 'bar',
])->save();
/** @var \Drupal\views\ViewEntityInterface $view */
$view = View::load('entity_test_fields');
$display =& $view->getDisplay('default');
// Add the 'bar' image field to 'entity_test_fields' view.
$display['display_options']['fields']['bar'] = [
'id' => 'bar',
'field' => 'bar',
'plugin_id' => 'field',
'table' => 'entity_test__bar',
'entity_type' => 'entity_test',
'entity_field' => 'bar',
'type' => 'image',
'settings' => ['image_style' => 'foo', 'image_link' => ''],
];
$view->save();
$dependencies = $view->getDependencies() + ['config' => []];
// Checks that style 'foo' is a dependency of view 'entity_test_fields'.
$this->assertTrue(in_array('image.style.foo', $dependencies['config']));
// Delete the 'foo' image style.
$style->delete();
// Checks that the view has been deleted too.
$this->assertNull(View::load('entity_test_fields'));
}
}

View file

@ -0,0 +1,117 @@
<?php
namespace Drupal\Tests\views\Kernel;
use Drupal\Core\Render\RenderContext;
use Drupal\views\Views;
/**
* Tests that views hooks are registered when defined in $module.views.inc.
*
* @group views
* @see views_hook_info().
* @see field_hook_info().
*/
class ViewsHooksTest extends ViewsKernelTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_view');
/**
* An array of available views hooks to test.
*
* @var array
*/
protected static $hooks = array (
'views_data' => 'all',
'views_data_alter' => 'alter',
'views_query_substitutions' => 'view',
'views_form_substitutions' => 'view',
'views_analyze' => 'view',
'views_pre_view' => 'view',
'views_pre_build' => 'view',
'views_post_build' => 'view',
'views_pre_execute' => 'view',
'views_post_execute' => 'view',
'views_pre_render' => 'view',
'views_post_render' => 'view',
'views_query_alter' => 'view',
'views_invalidate_cache' => 'all',
);
/**
* The module handler to use for invoking hooks.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->moduleHandler = $this->container->get('module_handler');
}
/**
* Tests the hooks.
*/
public function testHooks() {
$view = Views::getView('test_view');
$view->setDisplay();
// Test each hook is found in the implementations array and is invoked.
foreach (static::$hooks as $hook => $type) {
$this->assertTrue($this->moduleHandler->implementsHook('views_test_data', $hook), format_string('The hook @hook was registered.', array('@hook' => $hook)));
if ($hook == 'views_post_render') {
$this->moduleHandler->invoke('views_test_data', $hook, array($view, &$view->display_handler->output, $view->display_handler->getPlugin('cache')));
continue;
}
switch ($type) {
case 'view':
$this->moduleHandler->invoke('views_test_data', $hook, array($view));
break;
case 'alter':
$data = array();
$this->moduleHandler->invoke('views_test_data', $hook, array($data));
break;
default:
$this->moduleHandler->invoke('views_test_data', $hook);
}
$this->assertTrue($this->container->get('state')->get('views_hook_test_' . $hook), format_string('The %hook hook was invoked.', array('%hook' => $hook)));
// Reset the module implementations cache, so we ensure that the
// .views.inc file is loaded actively.
$this->moduleHandler->resetImplementations();
}
}
/**
* Tests how hook_views_form_substitutions() makes substitutions.
*
* @see views_test_data_views_form_substitutions()
* @see views_pre_render_views_form_views_form()
*/
public function testViewsPreRenderViewsFormViewsForm() {
$element = [
'output' => [
'#plain_text' => '<!--will-be-escaped--><!--will-be-not-escaped-->',
],
'#substitutions' => ['#value' => []],
];
$element = \Drupal::service('renderer')->executeInRenderContext(new RenderContext(), function() use ($element) {
return views_pre_render_views_form_views_form($element);
});
$this->setRawContent((string) $element['output']['#markup']);
$this->assertEscaped('<em>escaped</em>');
$this->assertRaw('<em>unescaped</em>');
}
}

View file

@ -0,0 +1,151 @@
<?php
namespace Drupal\Tests\views\Kernel;
use Drupal\Core\Database\Database;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\views\Tests\ViewResultAssertionTrait;
use Drupal\views\Tests\ViewTestData;
/**
* Defines a base class for Views kernel testing.
*/
class ViewsKernelTestBase extends KernelTestBase {
use ViewResultAssertionTrait;
/**
* Views to be enabled.
*
* Test classes should override this property and provide the list of testing
* views.
*
* @var array
*/
public static $testViews = [];
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'views', 'views_test_config', 'views_test_data', 'user'];
/**
* {@inheritdoc}
*
* @param bool $import_test_views
* Should the views specified on the test class be imported. If you need
* to setup some additional stuff, like fields, you need to call false and
* then call createTestViews for your own.
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->installSchema('system', ['router', 'sequences', 'key_value_expire']);
$this->setUpFixtures();
if ($import_test_views) {
ViewTestData::createTestViews(get_class($this), ['views_test_config']);
}
}
/**
* Sets up the configuration and schema of views and views_test_data modules.
*
* Because the schema of views_test_data.module is dependent on the test
* using it, it cannot be enabled normally.
*/
protected function setUpFixtures() {
// First install the system module. Many Views have Page displays have menu
// links, and for those to work, the system menus must already be present.
$this->installConfig(['system']);
/** @var \Drupal\Core\State\StateInterface $state */
$state = $this->container->get('state');
// Define the schema and views data variable before enabling the test module.
$state->set('views_test_data_schema', $this->schemaDefinition());
$state->set('views_test_data_views_data', $this->viewsData());
$this->installConfig(['views', 'views_test_config', 'views_test_data']);
foreach ($this->schemaDefinition() as $table => $schema) {
$this->installSchema('views_test_data', $table);
}
$this->container->get('router.builder')->rebuild();
// Load the test dataset.
$data_set = $this->dataSet();
$query = Database::getConnection()->insert('views_test_data')
->fields(array_keys($data_set[0]));
foreach ($data_set as $record) {
$query->values($record);
}
$query->execute();
}
/**
* Orders a nested array containing a result set based on a given column.
*
* @param array $result_set
* An array of rows from a result set, with each row as an associative
* array keyed by column name.
* @param string $column
* The column name by which to sort the result set.
* @param bool $reverse
* (optional) Boolean indicating whether to sort the result set in reverse
* order. Defaults to FALSE.
*
* @return array
* The sorted result set.
*/
protected function orderResultSet($result_set, $column, $reverse = FALSE) {
$order = $reverse ? -1 : 1;
usort($result_set, function ($a, $b) use ($column, $order) {
if ($a[$column] == $b[$column]) {
return 0;
}
return $order * (($a[$column] < $b[$column]) ? -1 : 1);
});
return $result_set;
}
/**
* Executes a view with debugging.
*
* @param \Drupal\views\ViewExecutable $view
* The view object.
* @param array $args
* (optional) An array of the view arguments to use for the view.
*/
protected function executeView($view, array $args = []) {
$view->setDisplay();
$view->preExecute($args);
$view->execute();
$verbose_message = '<pre>Executed view: ' . ((string) $view->build_info['query']). '</pre>';
if ($view->build_info['query'] instanceof SelectInterface) {
$verbose_message .= '<pre>Arguments: ' . print_r($view->build_info['query']->getArguments(), TRUE) . '</pre>';
}
$this->verbose($verbose_message);
}
/**
* Returns the schema definition.
*/
protected function schemaDefinition() {
return ViewTestData::schemaDefinition();
}
/**
* Returns the views data definition.
*/
protected function viewsData() {
return ViewTestData::viewsData();
}
/**
* Returns a very simple test dataset.
*/
protected function dataSet() {
return ViewTestData::dataSet();
}
}

View file

@ -0,0 +1,74 @@
<?php
namespace Drupal\Tests\views\Kernel\Wizard;
use Drupal\Core\Form\FormState;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views_ui\ViewUI;
/**
* Tests the wizard base plugin class.
*
* @group views
* @see \Drupal\views\Plugin\views\wizard\WizardPluginBase
*/
class WizardPluginBaseKernelTest extends ViewsKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('language', 'system', 'user', 'views_ui');
/**
* Contains thw wizard plugin manager.
*
* @var \Drupal\views\Plugin\views\wizard\WizardPluginBase
*/
protected $wizard;
protected function setUp($import_test_views = TRUE) {
parent::setUp();
$this->installConfig(array('language'));
$this->wizard = $this->container->get('plugin.manager.views.wizard')->createInstance('standard:views_test_data', array());
}
/**
* Tests the creating of a view.
*
* @see \Drupal\views\Plugin\views\wizard\WizardPluginBase
*/
public function testCreateView() {
$form = array();
$form_state = new FormState();
$form = $this->wizard->buildForm($form, $form_state);
$random_id = strtolower($this->randomMachineName());
$random_label = $this->randomMachineName();
$random_description = $this->randomMachineName();
// Add a new language and mark it as default.
ConfigurableLanguage::createFromLangcode('it')->save();
$this->config('system.site')->set('default_langcode', 'it')->save();
$form_state->setValues([
'id' => $random_id,
'label' => $random_label,
'description' => $random_description,
'base_table' => 'views_test_data',
]);
$this->wizard->validateView($form, $form_state);
$view = $this->wizard->createView($form, $form_state);
$this->assertTrue($view instanceof ViewUI, 'The created view is a ViewUI object.');
$this->assertEqual($view->get('id'), $random_id);
$this->assertEqual($view->get('label'), $random_label);
$this->assertEqual($view->get('description'), $random_description);
$this->assertEqual($view->get('base_table'), 'views_test_data');
$this->assertEqual($view->get('langcode'), 'it');
}
}

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\Tests\views\Unit\Controller\ViewAjaxControllerTest.
*/
namespace Drupal\Tests\views\Unit\Controller {
use Drupal\Core\Render\RenderContext;

View file

@ -94,6 +94,7 @@ class EntityViewsDataTest extends UnitTestCase {
'id' => 'entity_test',
'label' => 'Entity test',
'entity_keys' => [
'uuid' => 'uuid',
'id' => 'id',
'langcode' => 'langcode',
'bundle' => 'type',
@ -991,4 +992,3 @@ namespace Drupal\entity_test\Entity {
}
}
}

View file

@ -1,10 +1,5 @@
<?php
/**
* @file
* Contains \Drupal\Tests\views\Unit\Plugin\Block\ViewsBlockTest.
*/
namespace Drupal\Tests\views\Unit\Plugin\Block {
use Drupal\Core\DependencyInjection\ContainerBuilder;

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