Updated to Drupal 8.6.4, which is PHP 7.3 friendly. Also updated HTMLaw library....
[yaffs-website] / web / core / tests / Drupal / Tests / Component / Utility / UnicodeTest.php
1 <?php
2
3 namespace Drupal\Tests\Component\Utility;
4
5 use Drupal\Component\Utility\Unicode;
6 use PHPUnit\Framework\TestCase;
7
8 /**
9  * Test unicode handling features implemented in Unicode component.
10  *
11  * @group Utility
12  *
13  * @coversDefaultClass \Drupal\Component\Utility\Unicode
14  */
15 class UnicodeTest extends TestCase {
16
17   /**
18    * @group legacy
19    * @expectedDeprecation \Drupal\Component\Utility\Unicode::setStatus() is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. In Drupal 9 there will be no way to set the status and in Drupal 8 this ability has been removed because mb_*() functions are supplied using Symfony's polyfill. See https://www.drupal.org/node/2850048.
20    */
21   public function testSetStatus() {
22     Unicode::setStatus(Unicode::STATUS_SINGLEBYTE);
23   }
24
25   /**
26    * Tests multibyte encoding and decoding.
27    *
28    * @dataProvider providerTestMimeHeader
29    * @covers ::mimeHeaderEncode
30    * @covers ::mimeHeaderDecode
31    */
32   public function testMimeHeader($value, $encoded) {
33     $this->assertEquals($encoded, Unicode::mimeHeaderEncode($value));
34     $this->assertEquals($value, Unicode::mimeHeaderDecode($encoded));
35   }
36
37   /**
38    * Data provider for testMimeHeader().
39    *
40    * @see testMimeHeader()
41    *
42    * @return array
43    *   An array containing a string and its encoded value.
44    */
45   public function providerTestMimeHeader() {
46     return [
47       ['tést.txt', '=?UTF-8?B?dMOpc3QudHh0?='],
48       // Simple ASCII characters.
49       ['ASCII', 'ASCII'],
50     ];
51   }
52
53   /**
54    * Tests multibyte strtolower.
55    *
56    * @dataProvider providerStrtolower
57    * @covers ::strtolower
58    * @covers ::caseFlip
59    * @group legacy
60    * @expectedDeprecation \Drupal\Component\Utility\Unicode::strtolower() is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use mb_strtolower() instead. See https://www.drupal.org/node/2850048.
61    */
62   public function testStrtolower($text, $expected) {
63     $this->assertEquals($expected, Unicode::strtolower($text));
64   }
65
66   /**
67    * Data provider for testStrtolower().
68    *
69    * @see testStrtolower()
70    *
71    * @return array
72    *   An array containing a string and its lowercase version.
73    */
74   public function providerStrtolower() {
75     return [
76       ['tHe QUIcK bRoWn', 'the quick brown'],
77       ['FrançAIS is ÜBER-åwesome', 'français is über-åwesome'],
78       ['ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΣὨ', 'αβγδεζηθικλμνξοσὠ'],
79     ];
80   }
81
82   /**
83    * Tests multibyte strtoupper.
84    *
85    * @dataProvider providerStrtoupper
86    * @covers ::strtoupper
87    * @covers ::caseFlip
88    * @group legacy
89    * @expectedDeprecation \Drupal\Component\Utility\Unicode::strtoupper() is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use mb_strtoupper() instead. See https://www.drupal.org/node/2850048.
90    */
91   public function testStrtoupper($text, $expected) {
92     $this->assertEquals($expected, Unicode::strtoupper($text));
93   }
94
95   /**
96    * Data provider for testStrtoupper().
97    *
98    * @see testStrtoupper()
99    *
100    * @return array
101    *   An array containing a string and its uppercase version.
102    */
103   public function providerStrtoupper() {
104     return [
105       ['tHe QUIcK bRoWn', 'THE QUICK BROWN'],
106       ['FrançAIS is ÜBER-åwesome', 'FRANÇAIS IS ÜBER-ÅWESOME'],
107       ['αβγδεζηθικλμνξοσὠ', 'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΣὨ'],
108     ];
109   }
110
111   /**
112    * Tests multibyte ucfirst.
113    *
114    * @dataProvider providerUcfirst
115    * @covers ::ucfirst
116    */
117   public function testUcfirst($text, $expected) {
118     $this->assertEquals($expected, Unicode::ucfirst($text));
119   }
120
121   /**
122    * Data provider for testUcfirst().
123    *
124    * @see testUcfirst()
125    *
126    * @return array
127    *   An array containing a string and its uppercase first version.
128    */
129   public function providerUcfirst() {
130     return [
131       ['tHe QUIcK bRoWn', 'THe QUIcK bRoWn'],
132       ['françAIS', 'FrançAIS'],
133       ['über', 'Über'],
134       ['åwesome', 'Åwesome'],
135       // A multibyte string.
136       ['σion', 'Σion'],
137     ];
138   }
139
140   /**
141    * Tests multibyte lcfirst.
142    *
143    * @dataProvider providerLcfirst
144    * @covers ::lcfirst
145    */
146   public function testLcfirst($text, $expected) {
147     $this->assertEquals($expected, Unicode::lcfirst($text));
148   }
149
150   /**
151    * Data provider for testLcfirst().
152    *
153    * @see testLcfirst()
154    *
155    * @return array
156    *   An array containing a string and its lowercase version.
157    */
158   public function providerLcfirst() {
159     return [
160       ['tHe QUIcK bRoWn', 'tHe QUIcK bRoWn'],
161       ['FrançAIS is ÜBER-åwesome', 'françAIS is ÜBER-åwesome'],
162       ['Über', 'über'],
163       ['Åwesome', 'åwesome'],
164       // Add a multibyte string.
165       ['ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΣὨ', 'αΒΓΔΕΖΗΘΙΚΛΜΝΞΟΣὨ'],
166     ];
167   }
168
169   /**
170    * Tests multibyte ucwords.
171    *
172    * @dataProvider providerUcwords
173    * @covers ::ucwords
174    */
175   public function testUcwords($text, $expected) {
176     $this->assertEquals($expected, Unicode::ucwords($text));
177   }
178
179   /**
180    * Data provider for testUcwords().
181    *
182    * @see testUcwords()
183    *
184    * @return array
185    *   An array containing a string and its capitalized version.
186    */
187   public function providerUcwords() {
188     return [
189       ['tHe QUIcK bRoWn', 'THe QUIcK BRoWn'],
190       ['françAIS', 'FrançAIS'],
191       ['über', 'Über'],
192       ['åwesome', 'Åwesome'],
193       // Make sure we don't mangle extra spaces.
194       ['frànçAIS is  über-åwesome', 'FrànçAIS Is  Über-Åwesome'],
195       // Add a multibyte string.
196       ['σion', 'Σion'],
197     ];
198   }
199
200   /**
201    * Tests multibyte strlen.
202    *
203    * @dataProvider providerStrlen
204    * @covers ::strlen
205    * @group legacy
206    * @expectedDeprecation \Drupal\Component\Utility\Unicode::strlen() is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use mb_strlen() instead. See https://www.drupal.org/node/2850048.
207    */
208   public function testStrlen($text, $expected) {
209     $this->assertEquals($expected, Unicode::strlen($text));
210   }
211
212   /**
213    * Data provider for testStrlen().
214    *
215    * @see testStrlen()
216    *
217    * @return array
218    *   An array containing a string and its length.
219    */
220   public function providerStrlen() {
221     return [
222       ['tHe QUIcK bRoWn', 15],
223       ['ÜBER-åwesome', 12],
224       ['以呂波耳・ほへとち。リヌルヲ。', 15],
225     ];
226   }
227
228   /**
229    * Tests multibyte substr.
230    *
231    * @dataProvider providerSubstr
232    * @covers ::substr
233    * @group legacy
234    * @expectedDeprecation \Drupal\Component\Utility\Unicode::substr() is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use mb_substr() instead. See https://www.drupal.org/node/2850048.
235    */
236   public function testSubstr($text, $start, $length, $expected) {
237     $this->assertEquals($expected, Unicode::substr($text, $start, $length));
238   }
239
240   /**
241    * Data provider for testSubstr().
242    *
243    * @see testSubstr()
244    *
245    * @return array
246    *   An array containing:
247    *     - The string to test.
248    *     - The start number to be processed by substr.
249    *     - The length number to be processed by substr.
250    *     - The expected string result.
251    */
252   public function providerSubstr() {
253     return [
254       ['frànçAIS is über-åwesome', 0, NULL, 'frànçAIS is über-åwesome'],
255       ['frànçAIS is über-åwesome', 0, 0, ''],
256       ['frànçAIS is über-åwesome', 0, 1, 'f'],
257       ['frànçAIS is über-åwesome', 0, 8, 'frànçAIS'],
258       ['frànçAIS is über-åwesome', 0, 23, 'frànçAIS is über-åwesom'],
259       ['frànçAIS is über-åwesome', 0, 24, 'frànçAIS is über-åwesome'],
260       ['frànçAIS is über-åwesome', 0, 25, 'frànçAIS is über-åwesome'],
261       ['frànçAIS is über-åwesome', 0, 100, 'frànçAIS is über-åwesome'],
262       ['frànçAIS is über-åwesome', 4, 4, 'çAIS'],
263       ['frànçAIS is über-åwesome', 1, 0, ''],
264       ['frànçAIS is über-åwesome', 100, 0, ''],
265       ['frànçAIS is über-åwesome', -4, 2, 'so'],
266       ['frànçAIS is über-åwesome', -4, 3, 'som'],
267       ['frànçAIS is über-åwesome', -4, 4, 'some'],
268       ['frànçAIS is über-åwesome', -4, 5, 'some'],
269       ['frànçAIS is über-åwesome', -7, 10, 'åwesome'],
270       ['frànçAIS is über-åwesome', 5, -10, 'AIS is üb'],
271       ['frànçAIS is über-åwesome', 0, -10, 'frànçAIS is üb'],
272       ['frànçAIS is über-åwesome', 0, -1, 'frànçAIS is über-åwesom'],
273       ['frànçAIS is über-åwesome', -7, -2, 'åweso'],
274       ['frànçAIS is über-åwesome', -7, -6, 'å'],
275       ['frànçAIS is über-åwesome', -7, -7, ''],
276       ['frànçAIS is über-åwesome', -7, -8, ''],
277       ['...', 0, 2, '..'],
278       ['以呂波耳・ほへとち。リヌルヲ。', 1, 3, '呂波耳'],
279     ];
280   }
281
282   /**
283    * Tests multibyte truncate.
284    *
285    * @dataProvider providerTruncate
286    * @covers ::truncate
287    */
288   public function testTruncate($text, $max_length, $expected, $wordsafe = FALSE, $add_ellipsis = FALSE) {
289     $this->assertEquals($expected, Unicode::truncate($text, $max_length, $wordsafe, $add_ellipsis));
290   }
291
292   /**
293    * Data provider for testTruncate().
294    *
295    * @see testTruncate()
296    *
297    * @return array
298    *   An array containing:
299    *     - The string to test.
300    *     - The max length to truncate this string to.
301    *     - The expected string result.
302    *     - (optional) Boolean for the $wordsafe flag. Defaults to FALSE.
303    *     - (optional) Boolean for the $add_ellipsis flag. Defaults to FALSE.
304    */
305   public function providerTruncate() {
306     $tests = [
307       ['frànçAIS is über-åwesome', 24, 'frànçAIS is über-åwesome'],
308       ['frànçAIS is über-åwesome', 23, 'frànçAIS is über-åwesom'],
309       ['frànçAIS is über-åwesome', 17, 'frànçAIS is über-'],
310       ['以呂波耳・ほへとち。リヌルヲ。', 6, '以呂波耳・ほ'],
311       ['frànçAIS is über-åwesome', 24, 'frànçAIS is über-åwesome', FALSE, TRUE],
312       ['frànçAIS is über-åwesome', 23, 'frànçAIS is über-åweso…', FALSE, TRUE],
313       ['frànçAIS is über-åwesome', 17, 'frànçAIS is über…', FALSE, TRUE],
314       ['123', 1, '…', TRUE, TRUE],
315       ['123', 2, '1…', TRUE, TRUE],
316       ['123', 3, '123', TRUE, TRUE],
317       ['1234', 3, '12…', TRUE, TRUE],
318       ['1234567890', 10, '1234567890', TRUE, TRUE],
319       ['12345678901', 10, '123456789…', TRUE, TRUE],
320       ['12345678901', 11, '12345678901', TRUE, TRUE],
321       ['123456789012', 11, '1234567890…', TRUE, TRUE],
322       ['12345 7890', 10, '12345 7890', TRUE, TRUE],
323       ['12345 7890', 9, '12345…', TRUE, TRUE],
324       ['123 567 90', 10, '123 567 90', TRUE, TRUE],
325       ['123 567 901', 10, '123 567…', TRUE, TRUE],
326       ['Stop. Hammertime.', 17, 'Stop. Hammertime.', TRUE, TRUE],
327       ['Stop. Hammertime.', 16, 'Stop…', TRUE, TRUE],
328       ['frànçAIS is über-åwesome', 24, 'frànçAIS is über-åwesome', TRUE, TRUE],
329       ['frànçAIS is über-åwesome', 23, 'frànçAIS is über…', TRUE, TRUE],
330       ['frànçAIS is über-åwesome', 17, 'frànçAIS is über…', TRUE, TRUE],
331       ['¿Dónde está el niño?', 20, '¿Dónde está el niño?', TRUE, TRUE],
332       ['¿Dónde está el niño?', 19, '¿Dónde está el…', TRUE, TRUE],
333       ['¿Dónde está el niño?', 13, '¿Dónde está…', TRUE, TRUE],
334       ['¿Dónde está el niño?', 10, '¿Dónde…', TRUE, TRUE],
335       ['Help! Help! Help!', 17, 'Help! Help! Help!', TRUE, TRUE],
336       ['Help! Help! Help!', 16, 'Help! Help!…', TRUE, TRUE],
337       ['Help! Help! Help!', 15, 'Help! Help!…', TRUE, TRUE],
338       ['Help! Help! Help!', 14, 'Help! Help!…', TRUE, TRUE],
339       ['Help! Help! Help!', 13, 'Help! Help!…', TRUE, TRUE],
340       ['Help! Help! Help!', 12, 'Help! Help!…', TRUE, TRUE],
341       ['Help! Help! Help!', 11, 'Help! Help…', TRUE, TRUE],
342       ['Help! Help! Help!', 10, 'Help!…', TRUE, TRUE],
343       ['Help! Help! Help!', 9, 'Help!…', TRUE, TRUE],
344       ['Help! Help! Help!', 8, 'Help!…', TRUE, TRUE],
345       ['Help! Help! Help!', 7, 'Help!…', TRUE, TRUE],
346       ['Help! Help! Help!', 6, 'Help!…', TRUE, TRUE],
347       ['Help! Help! Help!', 5, 'Help…', TRUE, TRUE],
348       ['Help! Help! Help!', 4, 'Hel…', TRUE, TRUE],
349       ['Help! Help! Help!', 3, 'He…', TRUE, TRUE],
350       ['Help! Help! Help!', 2, 'H…', TRUE, TRUE],
351     ];
352
353     // Test truncate on text with multiple lines.
354     $multi_line = <<<EOF
355 This is a text that spans multiple lines.
356 Line 2 goes here.
357 EOF;
358     $multi_line_wordsafe = <<<EOF
359 This is a text that spans multiple lines.
360 Line 2
361 EOF;
362     $multi_line_non_wordsafe = <<<EOF
363 This is a text that spans multiple lines.
364 Line 2 go
365 EOF;
366     $tests[] = [$multi_line, 51, $multi_line_wordsafe, TRUE];
367     $tests[] = [$multi_line, 51, $multi_line_non_wordsafe, FALSE];
368
369     return $tests;
370   }
371
372   /**
373    * Tests multibyte truncate bytes.
374    *
375    * @dataProvider providerTestTruncateBytes
376    * @covers ::truncateBytes
377    *
378    * @param string $text
379    *   The string to truncate.
380    * @param int $max_length
381    *   The upper limit on the returned string length.
382    * @param string $expected
383    *   The expected return from Unicode::truncateBytes().
384    */
385   public function testTruncateBytes($text, $max_length, $expected) {
386     $this->assertEquals($expected, Unicode::truncateBytes($text, $max_length), 'The string was not correctly truncated.');
387   }
388
389   /**
390    * Provides data for self::testTruncateBytes().
391    *
392    * @return array
393    *   An array of arrays, each containing the parameters to
394    *   self::testTruncateBytes().
395    */
396   public function providerTestTruncateBytes() {
397     return [
398       // String shorter than max length.
399       ['Short string', 42, 'Short string'],
400       // Simple string longer than max length.
401       ['Longer string than previous.', 10, 'Longer str'],
402       // Unicode.
403       ['以呂波耳・ほへとち。リヌルヲ。', 10, '以呂波'],
404     ];
405   }
406
407   /**
408    * Tests UTF-8 validation.
409    *
410    * @dataProvider providerTestValidateUtf8
411    * @covers ::validateUtf8
412    *
413    * @param string $text
414    *   The text to validate.
415    * @param bool $expected
416    *   The expected return value from Unicode::validateUtf8().
417    * @param string $message
418    *   The message to display on failure.
419    */
420   public function testValidateUtf8($text, $expected, $message) {
421     $this->assertEquals($expected, Unicode::validateUtf8($text), $message);
422   }
423
424   /**
425    * Provides data for self::testValidateUtf8().
426    *
427    * Invalid UTF-8 examples sourced from http://stackoverflow.com/a/11709412/109119.
428    *
429    * @return array
430    *   An array of arrays, each containing the parameters for
431    *   self::testValidateUtf8().
432    */
433   public function providerTestValidateUtf8() {
434     return [
435       // Empty string.
436       ['', TRUE, 'An empty string did not validate.'],
437       // Simple text string.
438       ['Simple text.', TRUE, 'A simple ASCII text string did not validate.'],
439       // Invalid UTF-8, overlong 5 byte encoding.
440       [chr(0xF8) . chr(0x80) . chr(0x80) . chr(0x80) . chr(0x80), FALSE, 'Invalid UTF-8 was validated.'],
441       // High code-point without trailing characters.
442       [chr(0xD0) . chr(0x01), FALSE, 'Invalid UTF-8 was validated.'],
443     ];
444   }
445
446   /**
447    * Tests UTF-8 conversion.
448    *
449    * @dataProvider providerTestConvertToUtf8
450    * @covers ::convertToUtf8
451    *
452    * @param string $data
453    *   The data to be converted.
454    * @param string $encoding
455    *   The encoding the data is in.
456    * @param string|bool $expected
457    *   The expected result.
458    */
459   public function testConvertToUtf8($data, $encoding, $expected) {
460     $this->assertEquals($expected, Unicode::convertToUtf8($data, $encoding));
461   }
462
463   /**
464    * Provides data to self::testConvertToUtf8().
465    *
466    * @return array
467    *   An array of arrays, each containing the parameters to
468    *   self::testConvertUtf8().  }
469    */
470   public function providerTestConvertToUtf8() {
471     return [
472       [chr(0x97), 'Windows-1252', '—'],
473       [chr(0x99), 'Windows-1252', '™'],
474       [chr(0x80), 'Windows-1252', '€'],
475     ];
476   }
477
478   /**
479    * Tests multibyte strpos.
480    *
481    * @dataProvider providerStrpos
482    * @covers ::strpos
483    * @group legacy
484    * @expectedDeprecation \Drupal\Component\Utility\Unicode::strpos() is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use mb_strpos() instead. See https://www.drupal.org/node/2850048.
485    */
486   public function testStrpos($haystack, $needle, $offset, $expected) {
487     $this->assertEquals($expected, Unicode::strpos($haystack, $needle, $offset));
488   }
489
490   /**
491    * Data provider for testStrpos().
492    *
493    * @see testStrpos()
494    *
495    * @return array
496    *   An array containing:
497    *     - The haystack string to be searched in.
498    *     - The needle string to search for.
499    *     - The offset integer to start at.
500    *     - The expected integer/FALSE result.
501    */
502   public function providerStrpos() {
503     return [
504       ['frànçAIS is über-åwesome', 'frànçAIS is über-åwesome', 0, 0],
505       ['frànçAIS is über-åwesome', 'rànçAIS is über-åwesome', 0, 1],
506       ['frànçAIS is über-åwesome', 'not in string', 0, FALSE],
507       ['frànçAIS is über-åwesome', 'r', 0, 1],
508       ['frànçAIS is über-åwesome', 'nçAIS', 0, 3],
509       ['frànçAIS is über-åwesome', 'nçAIS', 2, 3],
510       ['frànçAIS is über-åwesome', 'nçAIS', 3, 3],
511       ['以呂波耳・ほへとち。リヌルヲ。', '波耳', 0, 2],
512       ['以呂波耳・ほへとち。リヌルヲ。', '波耳', 1, 2],
513       ['以呂波耳・ほへとち。リヌルヲ。', '波耳', 2, 2],
514     ];
515   }
516
517 }