‪TYPO3CMS  9.5
SlugHelperTest.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
3 
5 
6 /*
7  * This file is part of the TYPO3 CMS project.
8  *
9  * It is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU General Public License, either version 2
11  * of the License, or any later version.
12  *
13  * For the full copyright and license information, please read the
14  * LICENSE.txt file that was distributed with this source code.
15  *
16  * The TYPO3 project - inspiring people to share!
17  */
18 
20 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
21 
22 class ‪SlugHelperTest extends UnitTestCase
23 {
27  protected ‪$resetSingletonInstances = true;
28 
32  public function ‪sanitizeDataProvider(): array
33  {
34  return [
35  'empty string' => [
36  [],
37  '',
38  '',
39  ],
40  'existing base' => [
41  [],
42  '/',
43  '',
44  ],
45  'invalid base' => [
46  [],
47  '//',
48  '',
49  ],
50  'invalid slug' => [
51  [],
52  '/slug//',
53  'slug/',
54  ],
55  'lowercase characters' => [
56  [],
57  '1AZÄ',
58  '1azae',
59  ],
60  'strig tags' => [
61  [],
62  '<foo>bar</foo>',
63  'bar'
64  ],
65  'replace special chars to -' => [
66  [],
67  '1 2-3+4_5',
68  '1-2-3-4-5',
69  ],
70  'empty fallback character' => [
71  [
72  'fallbackCharacter' => '',
73  ],
74  '1_2',
75  '12',
76  ],
77  'different fallback character' => [
78  [
79  'fallbackCharacter' => '_',
80  ],
81  '1-2',
82  '1_2',
83  ],
84  'convert umlauts' => [
85  [],
86  'ä ß Ö',
87  'ae-ss-oe'
88  ],
89  'keep slashes' => [
90  [],
91  '1/2',
92  '1/2',
93  ],
94  'keep pending slash' => [
95  [],
96  '/1/2',
97  '1/2',
98  ],
99  'do not remove trailing slash' => [
100  [],
101  '1/2/',
102  '1/2/',
103  ],
104  'keep pending slash and remove fallback' => [
105  [],
106  '/-1/2',
107  '1/2',
108  ],
109  'do not remove trailing slash, but remove fallback' => [
110  [],
111  '1/2-/',
112  '1/2/',
113  ],
114  'reduce multiple fallback chars to one' => [
115  [],
116  '1---2',
117  '1-2',
118  ],
119  'various special chars' => [
120  [],
121  'special-chars-«-∑-€-®-†-Ω-¨-ø-π-å-‚-∂-ƒ-©-ª-º-∆-@-¥-≈-ç-√-∫-~-µ-∞-…-–',
122  'special-chars-eur-r-o-oe-p-aa-f-c-a-o-yen-c-u'
123  ],
124  'ensure colon and other http related parts are disallowed' => [
125  [],
126  'https://example.com:80/my/page/slug/',
127  'https//examplecom80/my/page/slug/'
128  ],
129  'non-ASCII characters are kept' => [
130  [],
131  'bla-arg应---用-ascii',
132  'bla-arg应-用-ascii'
133  ],
134  ];
135  }
136 
144  public function ‪sanitizeConvertsString(array $configuration, string $input, string $expected)
145  {
146  $subject = new ‪SlugHelper(
147  'dummyTable',
148  'dummyField',
149  $configuration
150  );
151  static::assertEquals(
152  $expected,
153  $subject->sanitize($input)
154  );
155  }
156 
158  {
159  return [
160  'simple title' => [
161  'Products',
162  'products'
163  ],
164  'title with spaces' => [
165  'Product Cow',
166  'product-cow'
167  ],
168  'title with invalid characters' => [
169  'Products - Cows',
170  'products-cows'
171  ],
172  'title with only invalid characters' => [
173  '!!!',
174  'default-51cf35392c'
175  ],
176  ];
177  }
178 
185  public function ‪generateNeverDeliversEmptySlug(string $input, string $expected)
186  {
187  ‪$GLOBALS['dummyTable']['ctrl'] = [];
188  $subject = new ‪SlugHelper(
189  'dummyTable',
190  'dummyField',
191  ['generatorOptions' => ['fields' => ['title']]]
192  );
193  static::assertEquals(
194  $expected,
195  $subject->generate(['title' => $input, 'uid' => 13], 13)
196  );
197  }
198 
202  public function ‪sanitizeForPagesDataProvider(): array
203  {
204  return [
205  'empty string' => [
206  [],
207  '',
208  '/',
209  ],
210  'existing base' => [
211  [],
212  '/',
213  '/',
214  ],
215  'invalid base' => [
216  [],
217  '//',
218  '/',
219  ],
220  'invalid slug' => [
221  [],
222  '/slug//',
223  '/slug/',
224  ],
225  'lowercase characters' => [
226  [],
227  '1AZÄ',
228  '/1azae',
229  ],
230  'strig tags' => [
231  [],
232  '<foo>bar</foo>',
233  '/bar'
234  ],
235  'replace special chars to -' => [
236  [],
237  '1 2-3+4_5',
238  '/1-2-3-4-5',
239  ],
240  'empty fallback character' => [
241  [
242  'fallbackCharacter' => '',
243  ],
244  '1_2',
245  '/12',
246  ],
247  'different fallback character' => [
248  [
249  'fallbackCharacter' => '_',
250  ],
251  '1-2',
252  '/1_2',
253  ],
254  'convert umlauts' => [
255  [],
256  'ä ß Ö',
257  '/ae-ss-oe'
258  ],
259  'keep slashes' => [
260  [],
261  '1/2',
262  '/1/2',
263  ],
264  'keep pending slash' => [
265  [],
266  '/1/2',
267  '/1/2',
268  ],
269  'do not remove trailing slash' => [
270  [],
271  '1/2/',
272  '/1/2/',
273  ],
274  'keep pending slash and remove fallback' => [
275  [],
276  '/-1/2',
277  '/1/2',
278  ],
279  'do not remove trailing slash, but remove fallback' => [
280  [],
281  '1/2-/',
282  '/1/2/',
283  ],
284  'reduce multiple fallback chars to one' => [
285  [],
286  '1---2',
287  '/1-2',
288  ],
289  'various special chars' => [
290  [],
291  'special-chars-«-∑-€-®-†-Ω-¨-ø-π-å-‚-∂-ƒ-©-ª-º-∆-@-¥-≈-ç-√-∫-~-µ-∞-…-–',
292  '/special-chars-eur-r-o-oe-p-aa-f-c-a-o-yen-c-u'
293  ],
294  'ensure colon and other http related parts are disallowed' => [
295  [],
296  'https://example.com:80/my/page/slug/',
297  '/https//examplecom80/my/page/slug/'
298  ],
299  'chinese' => [
300  [],
301  '应用',
302  '/应用'
303  ],
304  'hindi' => [
305  [],
306  'कंपनी',
307  '/कंपनी'
308  ],
309  'hindi with plain accent character' => [
310  [],
311  'कंपनी^',
312  '/कंपनी'
313  ],
314  'hindi with combined accent character' => [
315  [],
316  'कंपनीâ',
317  '/कंपनीa'
318  ],
319  'japanese numbers (sino-japanese)' => [
320  [],
321  'さん',
322  '/さん'
323  ],
324  'japanese numbers (kanji)' => [
325  [],
326  '三つ',
327  '/三つ'
328  ],
329  'persian numbers' => [
330  [],
331  '۴',
332  '/4'
333  ],
334  ];
335  }
336 
344  public function ‪sanitizeConvertsStringForPages(array $configuration, string $input, string $expected)
345  {
346  $subject = new SlugHelper(
347  'pages',
348  'slug',
349  $configuration
350  );
351  static::assertEquals(
352  $expected,
353  $subject->sanitize($input)
354  );
355  }
356 
358  {
359  return [
360  'simple title' => [
361  'Products',
362  '/products'
363  ],
364  'title with spaces' => [
365  'Product Cow',
366  '/product-cow'
367  ],
368  'title with invalid characters' => [
369  'Products - Cows',
370  '/products-cows'
371  ],
372  'title with only invalid characters' => [
373  '!!!',
374  '/default-51cf35392c'
375  ],
376  ];
377  }
378 
385  public function ‪generateNeverDeliversEmptySlugForPages(string $input, string $expected)
386  {
387  ‪$GLOBALS['dummyTable']['ctrl'] = [];
388  $subject = new ‪SlugHelper(
389  'pages',
390  'slug',
391  ['generatorOptions' => ['fields' => ['title']]]
392  );
393  static::assertEquals(
394  $expected,
395  $subject->generate(['title' => $input, 'uid' => 13], 13)
396  );
397  }
398 
402  public function ‪generatePrependsSlugsForPagesDataProvider(): array
403  {
404  return [
405  'simple title' => [
406  'Products',
407  '/parent-page/products',
408  [
409  'generatorOptions' => [
410  'fields' => ['title'],
411  'prefixParentPageSlug' => true,
412  ],
413  ]
414  ],
415  'title with spaces' => [
416  'Product Cow',
417  '/parent-page/product-cow',
418  [
419  'generatorOptions' => [
420  'fields' => ['title'],
421  'prefixParentPageSlug' => true,
422  ],
423  ]
424  ],
425  'title with slash' => [
426  'Product/Cow',
427  '/parent-page/product/cow',
428  [
429  'generatorOptions' => [
430  'fields' => ['title'],
431  'prefixParentPageSlug' => true,
432  ],
433  ]
434  ],
435  'title with slash and replace' => [
436  'Product/Cow',
437  '/parent-page/productcow',
438  [
439  'generatorOptions' => [
440  'fields' => ['title'],
441  'prefixParentPageSlug' => true,
442  'replacements' => [
443  '/' => ''
444  ]
445  ],
446  ]
447  ],
448  'title with slash and replace #2' => [
449  'Some Job in city1/city2 (m/w)',
450  '/parent-page/some-job-in-city1-city2',
451  [
452  'generatorOptions' => [
453  'fields' => ['title'],
454  'prefixParentPageSlug' => true,
455  'replacements' => [
456  '(m/w)' => '',
457  '/' => '-'
458  ]
459  ],
460  ]
461  ],
462  'title with invalid characters' => [
463  'Products - Cows',
464  '/parent-page/products-cows',
465  [
466  'generatorOptions' => [
467  'fields' => ['title'],
468  'prefixParentPageSlug' => true,
469  ],
470  ]
471  ],
472  'title with only invalid characters' => [
473  '!!!',
474  '/parent-page/default-51cf35392c',
475  [
476  'generatorOptions' => [
477  'fields' => ['title'],
478  'prefixParentPageSlug' => true,
479  ],
480  ]
481  ],
482  ];
483  }
484 
491  public function ‪generatePrependsSlugsForPages(string $input, string $expected, array $options)
492  {
493  ‪$GLOBALS['dummyTable']['ctrl'] = [];
494  $parentPage = [
495  'uid' => '13',
496  'pid' => '10',
497  'title' => 'Parent Page',
498  ];
499  $subject = $this->getAccessibleMock(
500  SlugHelper::class,
501  ['resolveParentPageRecord'],
502  [
503  'pages',
504  'slug',
505  $options
506  ]
507  );
508  $subject->expects(static::at(0))
509  ->method('resolveParentPageRecord')->with(13)->willReturn($parentPage);
510  $subject->expects(static::at(1))
511  ->method('resolveParentPageRecord')->with(10)->willReturn(null);
512  static::assertEquals(
513  $expected,
514  $subject->generate(['title' => $input, 'uid' => 13], 13)
515  );
516  }
517 
522  {
523  return [
524  'title and empty nav_title' => [
525  ['title' => 'Products', 'nav_title' => '', 'subtitle' => ''],
526  '/products',
527  [
528  'generatorOptions' => [
529  'fields' => [
530  ['nav_title', 'title']
531  ],
532  ],
533  ]
534  ],
535  'title and nav_title' => [
536  ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => ''],
537  '/best-products',
538  [
539  'generatorOptions' => [
540  'fields' => [
541  ['nav_title', 'title']
542  ],
543  ],
544  ]
545  ],
546  'title and nav_title and subtitle' => [
547  ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle'],
548  '/product-subtitle',
549  [
550  'generatorOptions' => [
551  'fields' => [
552  ['subtitle', 'nav_title', 'title']
553  ],
554  ],
555  ]
556  ],
557  'definition with a non existing field (misconfiguration)' => [
558  ['title' => 'Products', 'nav_title' => '', 'subtitle' => ''],
559  '/products',
560  [
561  'generatorOptions' => [
562  'fields' => [
563  ['custom_field', 'title']
564  ],
565  ],
566  ]
567  ],
568  'empty fields deliver default slug' => [
569  ['title' => '', 'nav_title' => '', 'subtitle' => ''],
570  '/default-b4dac929c2',
571  [
572  'generatorOptions' => [
573  'fields' => [
574  ['nav_title', 'title']
575  ],
576  ],
577  ]
578  ],
579  'fallback combined with a second field' => [
580  ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle'],
581  '/best-products/product-subtitle',
582  [
583  'generatorOptions' => [
584  'fields' => [
585  ['nav_title', 'title'], 'subtitle'
586  ],
587  ],
588  ]
589  ],
590  'empty config array deliver default slug' => [
591  ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle'],
592  '/default-e13d142b36',
593  [
594  'generatorOptions' => [
595  'fields' => [
596  []
597  ],
598  ],
599  ]
600  ],
601  'empty config deliver default slug' => [
602  ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle'],
603  '/default-e13d142b36',
604  [
605  'generatorOptions' => [
606  'fields' => [],
607  ],
608  ]
609  ],
610  'combine two fallbacks' => [
611  ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle', 'seo_title' => 'SEO product title'],
612  '/seo-product-title/best-products',
613  [
614  'generatorOptions' => [
615  'fields' => [
616  ['seo_title', 'title'], ['nav_title', 'subtitle']
617  ],
618  ],
619  ]
620  ],
621  ];
622  }
623 
631  public function ‪generateSlugWithNavTitleAndFallbackForPages(array $input, string $expected, array $options)
632  {
633  ‪$GLOBALS['dummyTable']['ctrl'] = [];
634  $subject = new SlugHelper(
635  'pages',
636  'slug',
637  ['generatorOptions' => $options['generatorOptions']]
638  );
639  static::assertEquals(
640  $expected,
641  $subject->generate([
642  'title' => $input['title'],
643  'nav_title' => $input['nav_title'],
644  'subtitle' => $input['subtitle'],
645  'seo_title' => $input['seo_title'] ?? '',
646  'uid' => 13
647  ], 13)
648  );
649  }
650 
654  public function ‪generateSlugWithHookModifiers()
655  {
656  $options = [];
657  $options['fallbackCharacter'] = '-';
658  $options['generatorOptions'] = [
659  'fields' => ['title'],
660  'postModifiers' => [
661  0 => function ($parameters, $subject) {
662  $slug = $parameters['slug'];
663  if ($parameters['pid'] == 13) {
664  $slug = 'prepend' . $slug;
665  }
666  return $slug;
667  }
668  ]
669  ];
670  $subject = new SlugHelper(
671  'pages',
672  'slug',
673  $options
674  );
675  $expected = '/prepend/products';
676  static::assertEquals(
677  $expected,
678  $subject->generate([
679  'title' => 'Products',
680  'nav_title' => 'Best products',
681  'subtitle' => 'Product subtitle',
682  'seo_title' => 'SEO product title',
683  'uid' => 23
684  ], 13)
685  );
686  }
687 }
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\generateNeverDeliversEmptySlugDataProvider
‪generateNeverDeliversEmptySlugDataProvider()
Definition: SlugHelperTest.php:156
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\generateNeverDeliversEmptySlug
‪generateNeverDeliversEmptySlug(string $input, string $expected)
Definition: SlugHelperTest.php:184
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\generateNeverDeliversEmptySlugForPagesDataProvider
‪generateNeverDeliversEmptySlugForPagesDataProvider()
Definition: SlugHelperTest.php:356
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\generateSlugWithHookModifiers
‪generateSlugWithHookModifiers()
Definition: SlugHelperTest.php:653
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\generateNeverDeliversEmptySlugForPages
‪generateNeverDeliversEmptySlugForPages(string $input, string $expected)
Definition: SlugHelperTest.php:384
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\sanitizeConvertsStringForPages
‪sanitizeConvertsStringForPages(array $configuration, string $input, string $expected)
Definition: SlugHelperTest.php:343
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\sanitizeDataProvider
‪array sanitizeDataProvider()
Definition: SlugHelperTest.php:31
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\generatePrependsSlugsForPagesDataProvider
‪array generatePrependsSlugsForPagesDataProvider()
Definition: SlugHelperTest.php:401
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\sanitizeConvertsString
‪sanitizeConvertsString(array $configuration, string $input, string $expected)
Definition: SlugHelperTest.php:143
‪TYPO3\CMS\Core\DataHandling\SlugHelper
Definition: SlugHelper.php:36
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\generateSlugWithNavTitleAndFallbackForPages
‪generateSlugWithNavTitleAndFallbackForPages(array $input, string $expected, array $options)
Definition: SlugHelperTest.php:630
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\sanitizeForPagesDataProvider
‪array sanitizeForPagesDataProvider()
Definition: SlugHelperTest.php:201
‪TYPO3\CMS\Core\Tests\Unit\DataHandling
Definition: DataHandlerTest.php:3
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest
Definition: SlugHelperTest.php:23
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\generatePrependsSlugsForPages
‪generatePrependsSlugsForPages(string $input, string $expected, array $options)
Definition: SlugHelperTest.php:490
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\$resetSingletonInstances
‪bool $resetSingletonInstances
Definition: SlugHelperTest.php:26
‪TYPO3\CMS\Core\Tests\Unit\DataHandling\SlugHelperTest\generateSlugWithNavTitleAndFallbackForPagesDataProvider
‪array generateSlugWithNavTitleAndFallbackForPagesDataProvider()
Definition: SlugHelperTest.php:520