annotate core/tests/Drupal/Tests/Component/Utility/HtmlTest.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 7a779792577d
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Tests\Component\Utility;
Chris@0 4
Chris@0 5 use Drupal\Component\Render\MarkupInterface;
Chris@0 6 use Drupal\Component\Render\MarkupTrait;
Chris@0 7 use Drupal\Component\Utility\Html;
Chris@0 8 use Drupal\Component\Utility\Random;
Chris@0 9 use PHPUnit\Framework\TestCase;
Chris@0 10
Chris@0 11 /**
Chris@0 12 * Tests \Drupal\Component\Utility\Html.
Chris@0 13 *
Chris@0 14 * @group Common
Chris@0 15 *
Chris@0 16 * @coversDefaultClass \Drupal\Component\Utility\Html
Chris@0 17 */
Chris@0 18 class HtmlTest extends TestCase {
Chris@0 19
Chris@0 20 /**
Chris@0 21 * {@inheritdoc}
Chris@0 22 */
Chris@0 23 protected function setUp() {
Chris@0 24 parent::setUp();
Chris@0 25
Chris@0 26 $property = new \ReflectionProperty('Drupal\Component\Utility\Html', 'seenIdsInit');
Chris@0 27 $property->setAccessible(TRUE);
Chris@0 28 $property->setValue(NULL);
Chris@0 29 }
Chris@0 30
Chris@0 31 /**
Chris@0 32 * Tests the Html::cleanCssIdentifier() method.
Chris@0 33 *
Chris@0 34 * @param string $expected
Chris@0 35 * The expected result.
Chris@0 36 * @param string $source
Chris@0 37 * The string being transformed to an ID.
Chris@0 38 * @param array|null $filter
Chris@0 39 * (optional) An array of string replacements to use on the identifier. If
Chris@0 40 * NULL, no filter will be passed and a default will be used.
Chris@0 41 *
Chris@0 42 * @dataProvider providerTestCleanCssIdentifier
Chris@0 43 *
Chris@0 44 * @covers ::cleanCssIdentifier
Chris@0 45 */
Chris@0 46 public function testCleanCssIdentifier($expected, $source, $filter = NULL) {
Chris@0 47 if ($filter !== NULL) {
Chris@0 48 $this->assertSame($expected, Html::cleanCssIdentifier($source, $filter));
Chris@0 49 }
Chris@0 50 else {
Chris@0 51 $this->assertSame($expected, Html::cleanCssIdentifier($source));
Chris@0 52 }
Chris@0 53 }
Chris@0 54
Chris@0 55 /**
Chris@0 56 * Provides test data for testCleanCssIdentifier().
Chris@0 57 *
Chris@0 58 * @return array
Chris@0 59 * Test data.
Chris@0 60 */
Chris@0 61 public function providerTestCleanCssIdentifier() {
Chris@0 62 $id1 = 'abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789';
Chris@0 63 $id2 = '¡¢£¤¥';
Chris@0 64 $id3 = 'css__identifier__with__double__underscores';
Chris@0 65 return [
Chris@0 66 // Verify that no valid ASCII characters are stripped from the identifier.
Chris@0 67 [$id1, $id1, []],
Chris@0 68 // Verify that valid UTF-8 characters are not stripped from the identifier.
Chris@0 69 [$id2, $id2, []],
Chris@0 70 // Verify that invalid characters (including non-breaking space) are stripped from the identifier.
Chris@0 71 [$id3, $id3],
Chris@0 72 // Verify that double underscores are not stripped from the identifier.
Chris@0 73 ['invalididentifier', 'invalid !"#$%&\'()*+,./:;<=>?@[\\]^`{|}~ identifier', []],
Chris@0 74 // Verify that an identifier starting with a digit is replaced.
Chris@0 75 ['_cssidentifier', '1cssidentifier', []],
Chris@0 76 // Verify that an identifier starting with a hyphen followed by a digit is
Chris@0 77 // replaced.
Chris@0 78 ['__cssidentifier', '-1cssidentifier', []],
Chris@0 79 // Verify that an identifier starting with two hyphens is replaced.
Chris@0 80 ['__cssidentifier', '--cssidentifier', []],
Chris@0 81 // Verify that passing double underscores as a filter is processed.
Chris@0 82 ['_cssidentifier', '__cssidentifier', ['__' => '_']],
Chris@0 83 ];
Chris@0 84 }
Chris@0 85
Chris@0 86 /**
Chris@0 87 * Tests that Html::getClass() cleans the class name properly.
Chris@0 88 *
Chris@0 89 * @coversDefaultClass ::getClass
Chris@0 90 */
Chris@0 91 public function testHtmlClass() {
Chris@0 92 // Verify Drupal coding standards are enforced.
Chris@0 93 $this->assertSame('class-name--ü', Html::getClass('CLASS NAME_[Ü]'), 'Enforce Drupal coding standards.');
Chris@0 94
Chris@0 95 // Test Html::getClass() handles Drupal\Component\Render\MarkupInterface
Chris@0 96 // input.
Chris@0 97 $markup = HtmlTestMarkup::create('CLASS_FROM_OBJECT');
Chris@0 98 $this->assertSame('class-from-object', Html::getClass($markup), 'Markup object is converted to CSS class.');
Chris@0 99 }
Chris@0 100
Chris@0 101 /**
Chris@0 102 * Tests the Html::getUniqueId() method.
Chris@0 103 *
Chris@0 104 * @param string $expected
Chris@0 105 * The expected result.
Chris@0 106 * @param string $source
Chris@0 107 * The string being transformed to an ID.
Chris@0 108 * @param bool $reset
Chris@0 109 * (optional) If TRUE, reset the list of seen IDs. Defaults to FALSE.
Chris@0 110 *
Chris@0 111 * @dataProvider providerTestHtmlGetUniqueId
Chris@0 112 *
Chris@0 113 * @covers ::getUniqueId
Chris@0 114 */
Chris@0 115 public function testHtmlGetUniqueId($expected, $source, $reset = FALSE) {
Chris@0 116 if ($reset) {
Chris@0 117 Html::resetSeenIds();
Chris@0 118 }
Chris@0 119 $this->assertSame($expected, Html::getUniqueId($source));
Chris@0 120 }
Chris@0 121
Chris@0 122 /**
Chris@0 123 * Provides test data for testHtmlGetId().
Chris@0 124 *
Chris@0 125 * @return array
Chris@0 126 * Test data.
Chris@0 127 */
Chris@0 128 public function providerTestHtmlGetUniqueId() {
Chris@0 129 $id = 'abcdefghijklmnopqrstuvwxyz-0123456789';
Chris@0 130 return [
Chris@0 131 // Verify that letters, digits, and hyphens are not stripped from the ID.
Chris@0 132 [$id, $id],
Chris@0 133 // Verify that invalid characters are stripped from the ID.
Chris@0 134 ['invalididentifier', 'invalid,./:@\\^`{Üidentifier'],
Chris@0 135 // Verify Drupal coding standards are enforced.
Chris@0 136 ['id-name-1', 'ID NAME_[1]'],
Chris@0 137 // Verify that a repeated ID is made unique.
Chris@0 138 ['test-unique-id', 'test-unique-id', TRUE],
Chris@0 139 ['test-unique-id--2', 'test-unique-id'],
Chris@0 140 ['test-unique-id--3', 'test-unique-id'],
Chris@0 141 ];
Chris@0 142 }
Chris@0 143
Chris@0 144 /**
Chris@0 145 * Tests the Html::getUniqueId() method.
Chris@0 146 *
Chris@0 147 * @param string $expected
Chris@0 148 * The expected result.
Chris@0 149 * @param string $source
Chris@0 150 * The string being transformed to an ID.
Chris@0 151 *
Chris@0 152 * @dataProvider providerTestHtmlGetUniqueIdWithAjaxIds
Chris@0 153 *
Chris@0 154 * @covers ::getUniqueId
Chris@0 155 */
Chris@0 156 public function testHtmlGetUniqueIdWithAjaxIds($expected, $source) {
Chris@0 157 Html::setIsAjax(TRUE);
Chris@0 158 $id = Html::getUniqueId($source);
Chris@0 159
Chris@0 160 // Note, we truncate two hyphens at the end.
Chris@0 161 // @see \Drupal\Component\Utility\Html::getId()
Chris@0 162 if (strpos($source, '--') !== FALSE) {
Chris@0 163 $random_suffix = substr($id, strlen($source) + 1);
Chris@0 164 }
Chris@0 165 else {
Chris@0 166 $random_suffix = substr($id, strlen($source) + 2);
Chris@0 167 }
Chris@0 168 $expected = $expected . $random_suffix;
Chris@0 169 $this->assertSame($expected, $id);
Chris@0 170 }
Chris@0 171
Chris@0 172 /**
Chris@0 173 * Provides test data for testHtmlGetId().
Chris@0 174 *
Chris@0 175 * @return array
Chris@0 176 * Test data.
Chris@0 177 */
Chris@0 178 public function providerTestHtmlGetUniqueIdWithAjaxIds() {
Chris@0 179 return [
Chris@0 180 ['test-unique-id1--', 'test-unique-id1'],
Chris@0 181 // Note, we truncate two hyphens at the end.
Chris@0 182 // @see \Drupal\Component\Utility\Html::getId()
Chris@0 183 ['test-unique-id1---', 'test-unique-id1--'],
Chris@0 184 ['test-unique-id2--', 'test-unique-id2'],
Chris@0 185 ];
Chris@0 186 }
Chris@0 187
Chris@0 188 /**
Chris@0 189 * Tests the Html::getUniqueId() method.
Chris@0 190 *
Chris@0 191 * @param string $expected
Chris@0 192 * The expected result.
Chris@0 193 * @param string $source
Chris@0 194 * The string being transformed to an ID.
Chris@0 195 *
Chris@0 196 * @dataProvider providerTestHtmlGetId
Chris@0 197 *
Chris@0 198 * @covers ::getId
Chris@0 199 */
Chris@0 200 public function testHtmlGetId($expected, $source) {
Chris@0 201 Html::setIsAjax(FALSE);
Chris@0 202 $this->assertSame($expected, Html::getId($source));
Chris@0 203 }
Chris@0 204
Chris@0 205 /**
Chris@0 206 * Provides test data for testHtmlGetId().
Chris@0 207 *
Chris@0 208 * @return array
Chris@0 209 * Test data.
Chris@0 210 */
Chris@0 211 public function providerTestHtmlGetId() {
Chris@0 212 $id = 'abcdefghijklmnopqrstuvwxyz-0123456789';
Chris@0 213 return [
Chris@0 214 // Verify that letters, digits, and hyphens are not stripped from the ID.
Chris@0 215 [$id, $id],
Chris@0 216 // Verify that invalid characters are stripped from the ID.
Chris@0 217 ['invalididentifier', 'invalid,./:@\\^`{Üidentifier'],
Chris@0 218 // Verify Drupal coding standards are enforced.
Chris@0 219 ['id-name-1', 'ID NAME_[1]'],
Chris@0 220 // Verify that a repeated ID is made unique.
Chris@0 221 ['test-unique-id', 'test-unique-id'],
Chris@0 222 ['test-unique-id', 'test-unique-id'],
Chris@0 223 ];
Chris@0 224 }
Chris@0 225
Chris@0 226 /**
Chris@0 227 * Tests Html::decodeEntities().
Chris@0 228 *
Chris@0 229 * @dataProvider providerDecodeEntities
Chris@0 230 * @covers ::decodeEntities
Chris@0 231 */
Chris@0 232 public function testDecodeEntities($text, $expected) {
Chris@0 233 $this->assertEquals($expected, Html::decodeEntities($text));
Chris@0 234 }
Chris@0 235
Chris@0 236 /**
Chris@0 237 * Data provider for testDecodeEntities().
Chris@0 238 *
Chris@0 239 * @see testDecodeEntities()
Chris@0 240 */
Chris@0 241 public function providerDecodeEntities() {
Chris@0 242 return [
Chris@0 243 ['Drupal', 'Drupal'],
Chris@0 244 ['<script>', '<script>'],
Chris@0 245 ['&lt;script&gt;', '<script>'],
Chris@0 246 ['&#60;script&#62;', '<script>'],
Chris@0 247 ['&amp;lt;script&amp;gt;', '&lt;script&gt;'],
Chris@0 248 ['"', '"'],
Chris@0 249 ['&#34;', '"'],
Chris@0 250 ['&amp;#34;', '&#34;'],
Chris@0 251 ['&quot;', '"'],
Chris@0 252 ['&amp;quot;', '&quot;'],
Chris@0 253 ["'", "'"],
Chris@0 254 ['&#39;', "'"],
Chris@0 255 ['&amp;#39;', '&#39;'],
Chris@0 256 ['©', '©'],
Chris@0 257 ['&copy;', '©'],
Chris@0 258 ['&#169;', '©'],
Chris@0 259 ['→', '→'],
Chris@0 260 ['&#8594;', '→'],
Chris@0 261 ['➼', '➼'],
Chris@0 262 ['&#10172;', '➼'],
Chris@0 263 ['&euro;', '€'],
Chris@0 264 ];
Chris@0 265 }
Chris@0 266
Chris@0 267 /**
Chris@0 268 * Tests Html::escape().
Chris@0 269 *
Chris@0 270 * @dataProvider providerEscape
Chris@0 271 * @covers ::escape
Chris@0 272 */
Chris@0 273 public function testEscape($expected, $text) {
Chris@0 274 $this->assertEquals($expected, Html::escape($text));
Chris@0 275 }
Chris@0 276
Chris@0 277 /**
Chris@0 278 * Data provider for testEscape().
Chris@0 279 *
Chris@0 280 * @see testEscape()
Chris@0 281 */
Chris@0 282 public function providerEscape() {
Chris@0 283 return [
Chris@0 284 ['Drupal', 'Drupal'],
Chris@0 285 ['&lt;script&gt;', '<script>'],
Chris@0 286 ['&amp;lt;script&amp;gt;', '&lt;script&gt;'],
Chris@0 287 ['&amp;#34;', '&#34;'],
Chris@0 288 ['&quot;', '"'],
Chris@0 289 ['&amp;quot;', '&quot;'],
Chris@0 290 ['&#039;', "'"],
Chris@0 291 ['&amp;#039;', '&#039;'],
Chris@0 292 ['©', '©'],
Chris@0 293 ['→', '→'],
Chris@0 294 ['➼', '➼'],
Chris@0 295 ['€', '€'],
Chris@0 296 ['Drup�al', "Drup\x80al"],
Chris@0 297 ];
Chris@0 298 }
Chris@0 299
Chris@0 300 /**
Chris@0 301 * Tests relationship between escaping and decoding HTML entities.
Chris@0 302 *
Chris@0 303 * @covers ::decodeEntities
Chris@0 304 * @covers ::escape
Chris@0 305 */
Chris@0 306 public function testDecodeEntitiesAndEscape() {
Chris@0 307 $string = "<em>répét&eacute;</em>";
Chris@0 308 $escaped = Html::escape($string);
Chris@0 309 $this->assertSame('&lt;em&gt;répét&amp;eacute;&lt;/em&gt;', $escaped);
Chris@0 310 $decoded = Html::decodeEntities($escaped);
Chris@0 311 $this->assertSame('<em>répét&eacute;</em>', $decoded);
Chris@0 312 $decoded = Html::decodeEntities($decoded);
Chris@0 313 $this->assertSame('<em>répété</em>', $decoded);
Chris@0 314 $escaped = Html::escape($decoded);
Chris@0 315 $this->assertSame('&lt;em&gt;répété&lt;/em&gt;', $escaped);
Chris@0 316 }
Chris@0 317
Chris@0 318 /**
Chris@0 319 * Tests Html::serialize().
Chris@0 320 *
Chris@0 321 * Resolves an issue by where an empty DOMDocument object sent to serialization would
Chris@0 322 * cause errors in getElementsByTagName() in the serialization function.
Chris@0 323 *
Chris@0 324 * @covers ::serialize
Chris@0 325 */
Chris@0 326 public function testSerialize() {
Chris@0 327 $document = new \DOMDocument();
Chris@0 328 $result = Html::serialize($document);
Chris@0 329 $this->assertSame('', $result);
Chris@0 330 }
Chris@0 331
Chris@0 332 /**
Chris@0 333 * @covers ::transformRootRelativeUrlsToAbsolute
Chris@0 334 * @dataProvider providerTestTransformRootRelativeUrlsToAbsolute
Chris@0 335 */
Chris@0 336 public function testTransformRootRelativeUrlsToAbsolute($html, $scheme_and_host, $expected_html) {
Chris@0 337 $this->assertSame($expected_html ?: $html, Html::transformRootRelativeUrlsToAbsolute($html, $scheme_and_host));
Chris@0 338 }
Chris@0 339
Chris@0 340 /**
Chris@0 341 * @covers ::transformRootRelativeUrlsToAbsolute
Chris@0 342 * @dataProvider providerTestTransformRootRelativeUrlsToAbsoluteAssertion
Chris@0 343 */
Chris@0 344 public function testTransformRootRelativeUrlsToAbsoluteAssertion($scheme_and_host) {
Chris@0 345 $this->setExpectedException(\AssertionError::class);
Chris@0 346 Html::transformRootRelativeUrlsToAbsolute('', $scheme_and_host);
Chris@0 347 }
Chris@0 348
Chris@0 349 /**
Chris@0 350 * Provides test data for testTransformRootRelativeUrlsToAbsolute().
Chris@0 351 *
Chris@0 352 * @return array
Chris@0 353 * Test data.
Chris@0 354 */
Chris@0 355 public function providerTestTransformRootRelativeUrlsToAbsolute() {
Chris@0 356 $data = [];
Chris@0 357
Chris@0 358 // Random generator.
Chris@0 359 $random = new Random();
Chris@0 360
Chris@0 361 // One random tag name.
Chris@0 362 $tag_name = strtolower($random->name(8, TRUE));
Chris@0 363
Chris@0 364 // A site installed either in the root of a domain or a subdirectory.
Chris@0 365 $base_paths = ['/', '/subdir/' . $random->name(8, TRUE) . '/'];
Chris@0 366
Chris@0 367 foreach ($base_paths as $base_path) {
Chris@0 368 // The only attribute that has more than just a URL as its value, is
Chris@0 369 // 'srcset', so special-case it.
Chris@0 370 $data += [
Chris@0 371 "$tag_name, srcset, $base_path: root-relative" => ["<$tag_name srcset=\"http://example.com{$base_path}already-absolute 200w, {$base_path}root-relative 300w\">root-relative test</$tag_name>", 'http://example.com', "<$tag_name srcset=\"http://example.com{$base_path}already-absolute 200w, http://example.com{$base_path}root-relative 300w\">root-relative test</$tag_name>"],
Chris@0 372 "$tag_name, srcset, $base_path: protocol-relative" => ["<$tag_name srcset=\"http://example.com{$base_path}already-absolute 200w, //example.com{$base_path}protocol-relative 300w\">protocol-relative test</$tag_name>", 'http://example.com', FALSE],
Chris@0 373 "$tag_name, srcset, $base_path: absolute" => ["<$tag_name srcset=\"http://example.com{$base_path}already-absolute 200w, http://example.com{$base_path}absolute 300w\">absolute test</$tag_name>", 'http://example.com', FALSE],
Chris@0 374 ];
Chris@0 375
Chris@0 376 foreach (['href', 'poster', 'src', 'cite', 'data', 'action', 'formaction', 'about'] as $attribute) {
Chris@0 377 $data += [
Chris@0 378 "$tag_name, $attribute, $base_path: root-relative" => ["<$tag_name $attribute=\"{$base_path}root-relative\">root-relative test</$tag_name>", 'http://example.com', "<$tag_name $attribute=\"http://example.com{$base_path}root-relative\">root-relative test</$tag_name>"],
Chris@0 379 "$tag_name, $attribute, $base_path: protocol-relative" => ["<$tag_name $attribute=\"//example.com{$base_path}protocol-relative\">protocol-relative test</$tag_name>", 'http://example.com', FALSE],
Chris@0 380 "$tag_name, $attribute, $base_path: absolute" => ["<$tag_name $attribute=\"http://example.com{$base_path}absolute\">absolute test</$tag_name>", 'http://example.com', FALSE],
Chris@0 381 ];
Chris@0 382 }
Chris@0 383 }
Chris@0 384
Chris@0 385 return $data;
Chris@0 386 }
Chris@0 387
Chris@0 388 /**
Chris@0 389 * Provides test data for testTransformRootRelativeUrlsToAbsoluteAssertion().
Chris@0 390 *
Chris@0 391 * @return array
Chris@0 392 * Test data.
Chris@0 393 */
Chris@0 394 public function providerTestTransformRootRelativeUrlsToAbsoluteAssertion() {
Chris@0 395 return [
Chris@0 396 'only relative path' => ['llama'],
Chris@0 397 'only root-relative path' => ['/llama'],
Chris@0 398 'host and path' => ['example.com/llama'],
Chris@0 399 'scheme, host and path' => ['http://example.com/llama'],
Chris@0 400 ];
Chris@0 401 }
Chris@0 402
Chris@0 403 }
Chris@0 404
Chris@0 405 /**
Chris@0 406 * Marks an object's __toString() method as returning markup.
Chris@0 407 */
Chris@0 408 class HtmlTestMarkup implements MarkupInterface {
Chris@0 409 use MarkupTrait;
Chris@0 410
Chris@0 411 }