From 3380c46533cac4e6007ec88eb27581545e8ebb93 Mon Sep 17 00:00:00 2001 From: dereine <dereine@99340.no-reply.drupal.org> Date: Sat, 8 Sep 2012 22:08:52 +0200 Subject: [PATCH] Issue #1754244 by dawehner: Add a generic testcase for the field base. --- .../Plugin/views/field/FieldPluginBase.php | 1 + lib/Drupal/views/Tests/Handler/FieldTest.php | 664 +++++++++++++++++- .../config/views.view.test_field_tokens.yml | 43 ++ .../config/views.view.test_click_sort.yml | 51 ++ .../config/views.view.test_field_classes.yml | 32 + .../config/views.view.test_field_output.yml | 25 + .../Plugin/views/field/FieldTest.php | 64 ++ tests/views_test_data/views_test_data.install | 24 + views.module | 2 +- 9 files changed, 901 insertions(+), 5 deletions(-) create mode 100644 tests/views_test_config/config/views.view.test_field_tokens.yml create mode 100644 tests/views_test_data/config/views.view.test_click_sort.yml create mode 100644 tests/views_test_data/config/views.view.test_field_classes.yml create mode 100644 tests/views_test_data/config/views.view.test_field_output.yml create mode 100644 tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/field/FieldTest.php diff --git a/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php b/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php index 96519d33ecbf..1c83039a3d79 100644 --- a/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php +++ b/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php @@ -268,6 +268,7 @@ function element_wrapper_type($none_supported = FALSE, $default_empty = FALSE) { function get_elements() { static $elements = NULL; if (!isset($elements)) { + // @todo Add possible html5 elements. $elements = variable_get('views_field_rewrite_elements', array( '' => t('- Use default -'), '0' => t('- None -'), diff --git a/lib/Drupal/views/Tests/Handler/FieldTest.php b/lib/Drupal/views/Tests/Handler/FieldTest.php index c5cf037c39c8..43ffc09861f4 100644 --- a/lib/Drupal/views/Tests/Handler/FieldTest.php +++ b/lib/Drupal/views/Tests/Handler/FieldTest.php @@ -8,16 +8,18 @@ namespace Drupal\views\Tests\Handler; /** - * Tests the generic field handler + * Tests the generic field handler. * - * @see views_handler_field + * @see Drupal\views\Plugin\views\field\FieldPluginBase */ +use DOMDocument; + class FieldTest extends HandlerTestBase { public static function getInfo() { return array( - 'name' => 'Field', - 'description' => 'Test the core views_handler_field handler.', + 'name' => 'Field: Base', + 'description' => 'Tests the generic field handler.', 'group' => 'Views Handlers', ); } @@ -32,6 +34,660 @@ protected function setUp() { ); } + /** + * Overrides Drupal\views\Tests\ViewTestBase::viewsData(). + */ + protected function viewsData() { + $data = parent::viewsData(); + $data['views_test']['job']['field']['id'] = 'test_field'; + + return $data; + } + + /** + * Tests that the render function is called. + */ + public function testRender() { + $view = views_get_view('test_field_tokens'); + $this->executeView($view); + + $random_text = $this->randomName(); + $view->field['job']->setTestValue($random_text); + $this->assertEqual($view->field['job']->theme($view->result[0]), $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 = $this->getBasicView(); + $view->initDisplay(); + $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', 'field' => 'created'); + $view->build(); + + // Make sure the field aliases have the expected value. + $this->assertEqual($id_field->aliases['job'], 'views_test_job'); + $this->assertEqual($id_field->aliases['created_test'], 'views_test_created'); + + $this->executeView($view); + // Tests the get_value method with and without a field aliases. + foreach ($this->dataSet() as $key => $row) { + $id = $key + 1; + $result = $view->result[$key]; + $this->assertEqual($id_field->get_value($result), $id); + $this->assertEqual($id_field->get_value($result, 'job'), $row['job']); + $this->assertEqual($id_field->get_value($result, 'created_test'), $row['created']); + } + + } + + /** + * Tests the click sorting functionality. + */ + public function testClickSorting() { + $this->drupalGet('test_click_sort'); + // Only the id and name should be click sortable, but not the name. + $this->assertLinkByHref(url('test_click_sort', array('query' => array('order' => 'id', 'sort' => 'asc')))); + $this->assertLinkByHref(url('test_click_sort', array('query' => array('order' => 'name', 'sort' => 'desc')))); + $this->assertNoLinkByHref(url('test_click_sort', array('query' => array('order' => 'created')))); + + // Clicking a click sort should change the order. + $this->clickLink(t('ID')); + $this->assertLinkByHref(url('test_click_sort', array('query' => array('order' => 'id', 'sort' => 'desc')))); + // Check that the output has the expected order (asc). + $ids = $this->clickSortLoadIdsFromOutput(); + $this->assertEqual($ids, range(1, 5)); + + $this->clickLink(t('ID')); + // Check that the output has the expected order (desc). + $ids = $this->clickSortLoadIdsFromOutput(); + $this->assertEqual($ids, range(5, 1, -1)); + } + + /** + * Small helper function to get all ids in the output. + * + * @return array + * A list of beatle ids. + */ + protected function clickSortLoadIdsFromOutput() { + $fields = $this->xpath("//td[contains(@class, 'views-field-id')]"); + $ids = array(); + foreach ($fields as $field) { + $ids[] = (int) $field[0]; + } + return $ids; + } + + /** + * Assertion helper which checks whether 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 + * The message to display along with the assertion. + * @param string $group + * The type of assertion - examples are "Browser", "PHP". + * @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); + } + + /** + * Assertion helper which checks whether 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 + * The message to display along with the assertion. + * @param string $group + * The type of assertion - examples are "Browser", "PHP". + * @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); + } + + /** + * Parse a content and return the html element. + * + * @param string $content + * The html to parse. + * + * @return array + * An array containing simplexml objects. + */ + protected function parseContent($content) { + $htmlDom = new DOMDocument(); + @$htmlDom->loadHTML('<?xml encoding="UTF-8">' . $content); + $elements = simplexml_import_dom($htmlDom); + + return $elements; + } + + /** + * Performs an xpath search on a certain content. + * + * The search is relative to the root element of the $content variable. + * + * @param string $content + * The html to parse. + * @param string $xpath + * The xpath string to use in the search. + * @param array $arguments + * Some arguments for the xpath. + * + * @return array|FALSE + * The return value of the xpath search. For details on the xpath string + * format and return values see the SimpleXML documentation, + * http://php.net/manual/function.simplexml-element-xpath.php. + */ + protected function xpathContent($content, $xpath, array $arguments = array()) { + if ($elements = $this->parseContent($content)) { + $xpath = $this->buildXPathQuery($xpath, $arguments); + $result = $elements->xpath($xpath); + // Some combinations of PHP / libxml versions return an empty array + // instead of the documented FALSE. Forcefully convert any falsish values + // to an empty array to allow foreach(...) constructions. + return $result ? $result : array(); + } + else { + return FALSE; + } + } + + /** + * Tests rewriting the output to a link. + */ + public function testAlterUrl() { + $view = $this->getBasicView(); + $view->initDisplay(); + $view->initHandlers(); + $this->executeView($view); + $row = $view->result[0]; + $id_field = $view->field['id']; + + // Setup the general settings required to build a link. + $id_field->options['alter']['make_link'] = TRUE; + $id_field->options['alter']['path'] = $path = $this->randomName(); + + // Tests that the suffix/prefix appears on the output. + $id_field->options['alter']['prefix'] = $prefix = $this->randomName(); + $id_field->options['alter']['suffix'] = $suffix = $this->randomName(); + $output = $id_field->theme($row); + $this->assertSubString($output, $prefix); + $this->assertSubString($output, $suffix); + unset($id_field->options['alter']['prefix']); + unset($id_field->options['alter']['suffix']); + + $output = $id_field->theme($row); + $this->assertSubString($output, $path, 'Make sure that the path is part of the output'); + + // Some generic test code adapted from the UrlTest class, which tests + // mostly the different options for the path. + global $base_url, $script_path; + + foreach (array(FALSE, TRUE) as $absolute) { + // Get the expected start of the path string. + $base = ($absolute ? $base_url . '/' : base_path()) . $script_path; + $absolute_string = $absolute ? 'absolute' : NULL; + $alter =& $id_field->options['alter']; + $alter['path'] = 'node/123'; + + $expected_result = url('node/123', array('absolute' => $absolute)); + $alter['absolute'] = $absolute; + $result = $id_field->theme($row); + $this->assertSubString($result, $expected_result); + + $expected_result = url('node/123', array('fragment' => 'foo', 'absolute' => $absolute)); + $alter['path'] = 'node/123#foo'; + $result = $id_field->theme($row); + $this->assertSubString($result, $expected_result); + + $expected_result = url('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute)); + $alter['path'] = 'node/123?foo'; + $result = $id_field->theme($row); + $this->assertSubString($result, $expected_result); + + $expected_result = url('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute)); + $alter['path'] = 'node/123?foo=bar&bar=baz'; + $result = $id_field->theme($row); + $this->assertSubString(decode_entities($result), decode_entities($expected_result)); + + $expected_result = url('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute)); + $alter['path'] = 'node/123?foo#bar'; + $result = $id_field->theme($row); + // @fixme: The actual result is node/123?foo#bar so views has a bug here. + // $this->assertSubStringExists(decode_entities($result), decode_entities($expected_result)); + + $expected_result = url('<front>', array('absolute' => $absolute)); + $alter['path'] = '<front>'; + $result = $id_field->theme($row); + $this->assertSubString($result, $expected_result); + } + + // Tests the replace spaces with dashes feature. + $id_field->options['alter']['replace_spaces'] = TRUE; + $id_field->options['alter']['path'] = $path = $this->randomName() . ' ' . $this->randomName(); + $output = $id_field->theme($row); + $this->assertSubString($output, str_replace(' ', '-', $path)); + $id_field->options['alter']['replace_spaces'] = FALSE; + $output = $id_field->theme($row); + // The url has a space in it, so to check we have to decode the url output. + $this->assertSubString(urldecode($output), $path); + + // Tests the external flag. + // Switch on the external flag should output an external url as well. + $id_field->options['alter']['external'] = TRUE; + $id_field->options['alter']['path'] = $path = 'drupal.org'; + $output = $id_field->theme($row); + $this->assertSubString($output, 'http://drupal.org'); + + // Setup a not external url, which shouldn't lead to an external url. + $id_field->options['alter']['external'] = FALSE; + $id_field->options['alter']['path'] = $path = 'drupal.org'; + $output = $id_field->theme($row); + $this->assertNotSubString($output, 'http://drupal.org'); + + // Tests the transforming of the case setting. + $id_field->options['alter']['path'] = $path = $this->randomName(); + $id_field->options['alter']['path_case'] = 'none'; + $output = $id_field->theme($row); + $this->assertSubString($output, $path); + + // Switch to uppercase and lowercase. + $id_field->options['alter']['path_case'] = 'upper'; + $output = $id_field->theme($row); + $this->assertSubString($output, strtoupper($path)); + $id_field->options['alter']['path_case'] = 'lower'; + $output = $id_field->theme($row); + $this->assertSubString($output, strtolower($path)); + + // Switch to ucfirst and ucwords. + $id_field->options['alter']['path_case'] = 'ucfirst'; + $id_field->options['alter']['path'] = 'drupal has a great community'; + $output = $id_field->theme($row); + $this->assertSubString($output, drupal_encode_path('Drupal has a great community')); + + $id_field->options['alter']['path_case'] = 'ucwords'; + $output = $id_field->theme($row); + $this->assertSubString($output, drupal_encode_path('Drupal Has A Great Community')); + unset($id_field->options['alter']['path_case']); + + // Tests the linkclass setting and see whether it actuall exists in the output. + $id_field->options['alter']['link_class'] = $class = $this->randomName(); + $output = $id_field->theme($row); + $elements = $this->xpathContent($output, '//a[contains(@class, :class)]', array(':class' => $class)); + $this->assertTrue($elements); + // @fixme link_class, alt, rel cannot be unset, which should be fixed. + $id_field->options['alter']['link_class'] = ''; + + // Tests the alt setting. + $id_field->options['alter']['alt'] = $rel = $this->randomName(); + $output = $id_field->theme($row); + $elements = $this->xpathContent($output, '//a[contains(@title, :alt)]', array(':alt' => $rel)); + $this->assertTrue($elements); + $id_field->options['alter']['alt'] = ''; + + // Tests the rel setting. + $id_field->options['alter']['rel'] = $rel = $this->randomName(); + $output = $id_field->theme($row); + $elements = $this->xpathContent($output, '//a[contains(@rel, :rel)]', array(':rel' => $rel)); + $this->assertTrue($elements); + $id_field->options['alter']['rel'] = ''; + + // Tests the target setting. + $id_field->options['alter']['target'] = $target = $this->randomName(); + $output = $id_field->theme($row); + $elements = $this->xpathContent($output, '//a[contains(@target, :target)]', array(':target' => $target)); + $this->assertTrue($elements); + unset($id_field->options['alter']['target']); + } + + + /** + * Tests general rewriting of the output. + */ + public function testRewrite() { + $view = $this->getBasicView(); + $view->initDisplay(); + $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->randomString(); + $output = $id_field->theme($row); + $this->assertNotSubString($output, $random_text); + + $id_field->options['alter']['alter_text'] = TRUE; + $output = $id_field->theme($row); + $this->assertSubString($output, $random_text); + } + + /** + * Tests the field/label/wrapper classes. + */ + public function testFieldClasses() { + $view = views_get_view('test_field_classes'); + $view->initDisplay(); + $view->initHandlers(); + + // Tests whether the default field classes are added. + $id_field = $view->field['id']; + + $id_field->options['element_default_classes'] = FALSE; + $output = $view->preview(); + $this->assertFalse($this->xpathContent($output, '//div[contains(@class, :class)]', array(':class' => 'field-content'))); + $this->assertFalse($this->xpathContent($output, '//div[contains(@class, :class)]', array(':class' => 'field-label'))); + + $id_field->options['element_default_classes'] = TRUE; + $output = $view->preview(); + // Per default the label and the element of the field are spans. + $this->assertTrue($this->xpathContent($output, '//span[contains(@class, :class)]', array(':class' => 'field-content'))); + $this->assertTrue($this->xpathContent($output, '//span[contains(@class, :class)]', array(':class' => 'views-label'))); + $this->assertTrue($this->xpathContent($output, '//div[contains(@class, :class)]', array(':class' => 'views-field'))); + + // Tests the element wrapper classes/element. + $random_class = $this->randomName(); + + // Set some common wrapper element types and see whether they appear with and without a custom class set. + foreach (array('h1', 'span', 'p', 'div') as $element_type) { + $id_field->options['element_wrapper_type'] = $element_type; + + // Set a custom wrapper element css class. + $id_field->options['element_wrapper_class'] = $random_class; + $output = $view->preview(); + $this->assertTrue($this->xpathContent($output, "//{$element_type}[contains(@class, :class)]", array(':class' => $random_class))); + + // Set no custom css class. + $id_field->options['element_wrapper_class'] = ''; + $output = $view->preview(); + $this->assertFalse($this->xpathContent($output, "//{$element_type}[contains(@class, :class)]", array(':class' => $random_class))); + $this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]/{$element_type}")); + } + + // Tests the label class/element. + + // Set some common label element types and see whether they appear with and without a custom class set. + foreach (array('h1', 'span', 'p', 'div') as $element_type) { + $id_field->options['element_label_type'] = $element_type; + + // Set a custom label element css class. + $id_field->options['element_label_class'] = $random_class; + $output = $view->preview(); + $this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//{$element_type}[contains(@class, :class)]", array(':class' => $random_class))); + + // Set no custom css class. + $id_field->options['element_label_class'] = ''; + $output = $view->preview(); + $this->assertFalse($this->xpathContent($output, "//li[contains(@class, views-row)]//{$element_type}[contains(@class, :class)]", array(':class' => $random_class))); + $this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//{$element_type}")); + } + + // Tests the element classes/element. + + // Set some common element element types and see whether they appear with and without a custom class set. + foreach (array('h1', 'span', 'p', 'div') as $element_type) { + $id_field->options['element_type'] = $element_type; + + // Set a custom label element css class. + $id_field->options['element_class'] = $random_class; + $output = $view->preview(); + $this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//div[contains(@class, views-field)]//{$element_type}[contains(@class, :class)]", array(':class' => $random_class))); + + // Set no custom css class. + $id_field->options['element_class'] = ''; + $output = $view->preview(); + $this->assertFalse($this->xpathContent($output, "//li[contains(@class, views-row)]//div[contains(@class, views-field)]//{$element_type}[contains(@class, :class)]", array(':class' => $random_class))); + $this->assertTrue($this->xpathContent($output, "//li[contains(@class, views-row)]//div[contains(@class, views-field)]//{$element_type}")); + } + + // Tests the available html elements. + $element_types = $id_field->get_elements(); + $expected_elements = array( + '', + '0', + 'div', + 'span', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'p', + 'strong', + 'em', + 'marquee' + ); + $this->assertEqual(array_keys($element_types), $expected_elements); + } + + /** + * Tests the field tokens, row level and field level. + */ + public function testFieldTokens() { + $view = views_get_view('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'] = '[name_2] [name_1]'; + + foreach ($view->result as $row) { + $expected_output_0 = $row->views_test_name; + $expected_output_1 = "$row->views_test_name $row->views_test_name"; + $expected_output_2 = "$row->views_test_name $row->views_test_name $row->views_test_name"; + + $output = $name_field_0->advanced_render($row); + $this->assertEqual($output, $expected_output_0); + + $output = $name_field_1->advanced_render($row); + $this->assertEqual($output, $expected_output_1); + + $output = $name_field_2->advanced_render($row); + $this->assertEqual($output, $expected_output_2); + } + + $job_field = $view->field['job']; + $job_field->options['alter']['alter_text'] = TRUE; + $job_field->options['alter']['text'] = '[test-token]'; + + $random_text = $this->randomName(); + $job_field->setTestValue($random_text); + $output = $job_field->advanced_render($row); + $this->assertSubString($output, $random_text, format_string('Make sure the self token (!value) appears in the output (!output)'. array('!value' => $random_text, '!output' => $output))); + } + + /** + * Tests the exclude setting. + */ + public function testExclude() { + $view = views_get_view('test_field_output'); + $view->initDisplay(); + $view->initHandlers(); + // Hide the field and see whether it's rendered. + $view->field['name']->options['exclude'] = TRUE; + + $output = $view->preview(); + foreach ($this->dataSet() as $entry) { + $this->assertNotSubString($output, $entry['name']); + } + + // Show and check the field. + $view->field['name']->options['exclude'] = FALSE; + + $output = $view->preview(); + foreach ($this->dataSet() as $entry) { + $this->assertSubString($output, $entry['name']); + } + } + + /** + * Tests trimming/read-more/ellipses. + */ + public function testTextRendering() { + $view = views_get_view('test_field_output'); + $view->initDisplay(); + $view->initHandlers(); + $name_field = $view->field['name']; + + // Tests stripping of html elements. + $this->executeView($view); + $random_text = $this->randomName(); + $name_field->options['alter']['alter_text'] = TRUE; + $name_field->options['alter']['text'] = $html_text = '<div class="views-test">' . $random_text . '</div>'; + $row = $view->result[0]; + + $name_field->options['alter']['strip_tags'] = TRUE; + $output = $name_field->advanced_render($row); + $this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is enabled.'); + $this->assertNotSubString($output, $html_text, 'Find no text with the html if stripping of views field output is enabled.'); + + // Tests preserving of html tags. + $name_field->options['alter']['preserve_tags'] = '<div>'; + $output = $name_field->advanced_render($row); + $this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is enabled but a div is allowed.'); + $this->assertSubString($output, $html_text, 'Find text with the html if stripping of views field output is enabled but a div is allowed.'); + + $name_field->options['alter']['strip_tags'] = FALSE; + $output = $name_field->advanced_render($row); + $this->assertSubString($output, $random_text, 'Find text without html if stripping of views field output is disabled.'); + $this->assertSubString($output, $html_text, 'Find text with the html if stripping of views field output is disabled.'); + + // Tests for removing whitespace and the beginning and the end. + $name_field->options['alter']['alter_text'] = FALSE; + $views_test_name = $row->views_test_name; + $row->views_test_name = ' ' . $views_test_name . ' '; + $name_field->options['alter']['trim_whitespace'] = TRUE; + $output = $name_field->advanced_render($row); + + $this->assertSubString($output, $views_test_name, 'Make sure the trimmed text can be found if trimming is enabled.'); + $this->assertNotSubString($output, $row->views_test_name, 'Make sure the untrimmed text can be found if trimming is enabled.'); + + $name_field->options['alter']['trim_whitespace'] = FALSE; + $output = $name_field->advanced_render($row); + $this->assertSubString($output, $views_test_name, 'Make sure the trimmed text can be found if trimming is disabled.'); + $this->assertSubString($output, $row->views_test_name, 'Make sure the untrimmed text can be found if trimming is disabled.'); + + + // Tests for trimming to a maximum length. + $name_field->options['alter']['trim'] = TRUE; + $name_field->options['alter']['word_boundary'] = FALSE; + + // Tests for simple trimming by string length. + $row->views_test_name = $this->randomName(8); + $name_field->options['alter']['max_length'] = 5; + $trimmed_name = drupal_substr($row->views_test_name, 0, 5); + + $output = $name_field->advanced_render($row); + $this->assertSubString($output, $trimmed_name, format_string('Make sure the trimmed output (!trimmed) appears in the rendered output (!output).', array('!trimmed' => $trimmed_name, '!output' => $output))); + $this->assertNotSubString($output, $row->views_test_name, format_string("Make sure the untrimmed value (!untrimmed) shouldn't appear in the rendered output (!output).", array('!untrimmed' => $row->views_test_name, '!output' => $output))); + + $name_field->options['alter']['max_length'] = 9; + $output = $name_field->advanced_render($row); + $this->assertSubString($output, $trimmed_name, format_string('Make sure the untrimmed (!untrimmed) output appears in the rendered output (!output).', array('!trimmed' => $trimmed_name, '!output' => $output))); + + // Take word_boundary into account for the tests. + $name_field->options['alter']['max_length'] = 5; + $name_field->options['alter']['word_boundary'] = TRUE; + $random_text_2 = $this->randomName(2); + $random_text_4 = $this->randomName(4); + $random_text_8 = $this->randomName(8); + $touples = array( + // Create one string which doesn't fit at all into the limit. + array( + 'value' => $random_text_8, + 'trimmed_value' => '', + 'trimmed' => TRUE + ), + // Create one string with two words which doesn't fit both into the limit. + array( + 'value' => $random_text_8 . ' ' . $random_text_8, + 'trimmed_value' => '', + 'trimmed' => TRUE + ), + // Create one string which contains of two words, of which only the first + // fits into the limit. + array( + 'value' => $random_text_4 . ' ' . $random_text_8, + 'trimmed_value' => $random_text_4, + 'trimmed' => TRUE + ), + // Create one string which contains of two words, of which both fits into + // the limit. + array( + 'value' => $random_text_2 . ' ' . $random_text_2, + 'trimmed_value' => $random_text_2 . ' ' . $random_text_2, + 'trimmed' => FALSE + ) + ); + + foreach ($touples as $touple) { + $row->views_test_name = $touple['value']; + $output = $name_field->advanced_render($row); + + if ($touple['trimmed']) { + $this->assertNotSubString($output, $touple['value'], format_string('The untrimmed value (!untrimmed) should not appear in the trimmed output (!output).', array('!untrimmed' => $touple['value'], '!output' => $output))); + } + if (!empty($touble['trimmed_value'])) { + $this->assertSubString($output, $touple['trimmed_value'], format_string('The trimmed value (!trimmed) should appear in the trimmed output (!output).', array('!trimmed' => $touple['trimmed_value'], '!output' => $output))); + } + } + + // Tests for displaying a readmore link when the output got trimmed. + $row->views_test_name = $this->randomName(8); + $name_field->options['alter']['max_length'] = 5; + $name_field->options['alter']['more_link'] = TRUE; + $name_field->options['alter']['more_link_text'] = $more_text = $this->randomName(); + $name_field->options['alter']['more_link_path'] = $more_path = $this->randomName(); + + $output = $name_field->advanced_render($row); + $this->assertSubString($output, $more_text, 'Make sure a read more text is displayed if the output got trimmed'); + $this->assertTrue($this->xpathContent($output, '//a[contains(@href, :path)]', array(':path' => $more_path)), 'Make sure the read more link points to the right destination.'); + + $name_field->options['alter']['more_link'] = FALSE; + $output = $name_field->advanced_render($row); + $this->assertNotSubString($output, $more_text, 'Make sure no read more text appears.'); + $this->assertFalse($this->xpathContent($output, '//a[contains(@href, :path)]', array(':path' => $more_path)), 'Make sure no read more link appears.'); + + // Check for the ellipses. + $row->views_test_name = $this->randomName(8); + $name_field->options['alter']['max_length'] = 5; + $output = $name_field->advanced_render($row); + $this->assertSubString($output, '...', 'An ellipsis should appear if the output is trimmed'); + $name_field->options['alter']['max_length'] = 10; + $output = $name_field->advanced_render($row); + $this->assertNotSubString($output, '...', 'No ellipsis should appear if the output is not trimmed'); + } + + /** + * Tests everything related to empty output of a field. + */ function testEmpty() { $this->_testHideIfEmpty(); $this->_testEmptyText(); diff --git a/tests/views_test_config/config/views.view.test_field_tokens.yml b/tests/views_test_config/config/views.view.test_field_tokens.yml new file mode 100644 index 000000000000..a1470b058ba2 --- /dev/null +++ b/tests/views_test_config/config/views.view.test_field_tokens.yml @@ -0,0 +1,43 @@ +api_version: '3.0' +base_table: views_test +core: '8' +description: '' +disabled: '0' +display: + default: + display_options: + access: + type: none + cache: + type: none + exposed_form: + type: basic + pager: + type: full + query: + type: views_query + row_plugin: fields + style_plugin: default + fields: + name: + id: name + table: views_test + field: name + name_1: + id: name_1 + table: views_test + field: name + name_2: + id: name_2 + table: views_test + field: name + job: + id: job + table: views_test + field: job + display_plugin: default + display_title: Defaults + id: default + position: '0' +name: test_field_tokens +tag: '' diff --git a/tests/views_test_data/config/views.view.test_click_sort.yml b/tests/views_test_data/config/views.view.test_click_sort.yml new file mode 100644 index 000000000000..05bcc2c9cfee --- /dev/null +++ b/tests/views_test_data/config/views.view.test_click_sort.yml @@ -0,0 +1,51 @@ +api_version: '3.0' +base_table: views_test +core: '8' +description: '' +disabled: '0' +display: + default: + display_options: + fields: + id: + id: id + table: views_test + field: id + name: + id: name + table: views_test + field: name + created: + id: created + table: views_test + field: created + display_options: + access: + type: none + cache: + type: none + style_plugin: table + style_options: + info: + id: + sortable: 1 + default_sort_order: asc + name: + sortable: 1 + default_sort_order: desc + created: + sortable: 0 + display_plugin: default + display_title: Master + id: default + position: '0' + page_1: + display_options: + path: test_click_sort + display_plugin: page + display_title: Page + id: page_1 + position: '0' +human_name: { } +name: test_click_sort +tag: '' diff --git a/tests/views_test_data/config/views.view.test_field_classes.yml b/tests/views_test_data/config/views.view.test_field_classes.yml new file mode 100644 index 000000000000..4eb3931e6275 --- /dev/null +++ b/tests/views_test_data/config/views.view.test_field_classes.yml @@ -0,0 +1,32 @@ +api_version: '3.0' +base_table: views_test +core: '8' +description: '' +disabled: '0' +display: + default: + display_options: + access: + type: none + cache: + type: none + fields: + id: + id: id + table: views_test + field: id + style_plugin: html_list + display_plugin: default + display_title: Master + id: default + position: '0' + page_1: + display_options: + path: test_field_classes + display_plugin: page + display_title: Page + id: page_1 + position: '0' +human_name: { } +name: test_field_classes +tag: '' diff --git a/tests/views_test_data/config/views.view.test_field_output.yml b/tests/views_test_data/config/views.view.test_field_output.yml new file mode 100644 index 000000000000..e7539d4b5973 --- /dev/null +++ b/tests/views_test_data/config/views.view.test_field_output.yml @@ -0,0 +1,25 @@ +api_version: '3.0' +base_table: views_test +core: '8' +description: '' +disabled: '0' +display: + default: + display_options: + access: + type: none + cache: + type: none + fields: + name: + id: name + table: views_test + field: name + style_plugin: html_list + display_plugin: default + display_title: Master + id: default + position: '0' +human_name: "" +name: test_field_output +tag: '' diff --git a/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/field/FieldTest.php b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/field/FieldTest.php new file mode 100644 index 000000000000..434f80edb9f5 --- /dev/null +++ b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/field/FieldTest.php @@ -0,0 +1,64 @@ +<?php + +/** + * @file + * Definition of Drupal\views_test_data\Plugin\views\field\FieldTest. + */ + +namespace Drupal\views_test_data\Plugin\views\field; + +use Drupal\Core\Annotation\Plugin; +use Drupal\Core\Annotation\Translation; +use Drupal\views\Plugin\views\field\FieldPluginBase; + +/** + * @Plugin( + * id = "test_field", + * title = @Translation("Test field plugin"), + * help = @Translation("Provides a generic field test plugin.") + * ) + */ +class FieldTest extends FieldPluginBase { + + + /** + * A temporary stored test value for the test. + * + * @var string + */ + protected $testValue; + + /** + * Sets the testValue property. + * + * @param string $value + * The test value to set. + */ + public function setTestValue($value) { + $this->testValue = $value; + } + + /** + * Returns the testValue property. + * + * @return string + */ + public function getTestValue() { + return $this->testValue; + } + + /** + * Overrides Drupal\views\Plugin\views\field\FieldPluginBase::add_self_tokens(). + */ + function add_self_tokens(&$tokens, $item) { + $tokens['[test-token]'] = $this->getTestValue(); + } + + /** + * Overrides Drupal\views\Plugin\views\field\FieldPluginBase::render(). + */ + function render($values) { + return $this->sanitizeValue($this->getTestValue()); + } + +} diff --git a/tests/views_test_data/views_test_data.install b/tests/views_test_data/views_test_data.install index c4153cfe1de6..94fc419d16e6 100644 --- a/tests/views_test_data/views_test_data.install +++ b/tests/views_test_data/views_test_data.install @@ -11,3 +11,27 @@ function views_test_data_schema() { return variable_get('views_test_schema', array()); } + +/** + * Implements hook_install(). + */ +function views_test_data_install() { + // Add the marquee tag to possible html elements to test the field handler. + $default_values = array( + '' => t('- Use default -'), + '0' => t('- None -'), + 'div' => 'DIV', + 'span' => 'SPAN', + 'h1' => 'H1', + 'h2' => 'H2', + 'h3' => 'H3', + 'h4' => 'H4', + 'h5' => 'H5', + 'h6' => 'H6', + 'p' => 'P', + 'strong' => 'STRONG', + 'em' => 'EM', + ); + $default_values['marquee'] = 'MARQUEE'; + variable_set('views_field_rewrite_elements', $default_values); +} diff --git a/views.module b/views.module index f5ecc5b0b427..77ef90c46a05 100644 --- a/views.module +++ b/views.module @@ -2382,7 +2382,6 @@ function _field_view_formatter_options($field_type = NULL) { function views_trim_text($alter, $value) { if (drupal_strlen($value) > $alter['max_length']) { $value = drupal_substr($value, 0, $alter['max_length']); - // TODO: replace this with cleanstring of ctools if (!empty($alter['word_boundary'])) { $regex = "(.*)\b.+"; if (function_exists('mb_ereg')) { @@ -2400,6 +2399,7 @@ function views_trim_text($alter, $value) { $value = rtrim(preg_replace('/(?:<(?!.+>)|&(?!.+;)).*$/us', '', $value)); if (!empty($alter['ellipsis'])) { + // @todo: What about changing this to a real ellipsis? $value .= t('...'); } } -- GitLab