SlugifyTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <?php
  2. /**
  3. * This file is part of cocur/slugify.
  4. *
  5. * (c) Florian Eckerstorfer <florian@eckerstorfer.co>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Cocur\Slugify\Tests;
  11. use Cocur\Slugify\Slugify;
  12. use Mockery;
  13. use Mockery\Adapter\Phpunit\MockeryTestCase;
  14. /**
  15. * SlugifyTest
  16. *
  17. * @category test
  18. * @package org.cocur.slugify
  19. * @author Florian Eckerstorfer <florian@eckerstorfer.co>
  20. * @author Ivo Bathke <ivo.bathke@gmail.com>
  21. * @author Marchenko Alexandr
  22. * @copyright 2012-2014 Florian Eckerstorfer
  23. * @license http://www.opensource.org/licenses/MIT The MIT License
  24. */
  25. class SlugifyTest extends MockeryTestCase
  26. {
  27. /**
  28. * @var Slugify
  29. */
  30. private $slugify;
  31. /**
  32. * @var \Cocur\Slugify\RuleProvider\RuleProviderInterface|\Mockery\MockInterface
  33. */
  34. private $provider;
  35. protected function setUp(): void
  36. {
  37. $this->provider = Mockery::mock('\Cocur\Slugify\RuleProvider\RuleProviderInterface');
  38. $this->provider->shouldReceive('getRules')->andReturn([]);
  39. $this->slugify = new Slugify([], $this->provider);
  40. }
  41. /**
  42. * @dataProvider defaultRuleProvider
  43. * @covers \Cocur\Slugify\Slugify::slugify()
  44. */
  45. public function testSlugifyReturnsSlugifiedStringUsingDefaultProvider($string, $result)
  46. {
  47. $slugify = new Slugify();
  48. $this->assertEquals($result, $slugify->slugify($string));
  49. }
  50. /**
  51. * @covers \Cocur\Slugify\Slugify::addRule()
  52. * @covers \Cocur\Slugify\Slugify::slugify()
  53. */
  54. public function testAddRuleAddsRule()
  55. {
  56. $this->assertInstanceOf(
  57. 'Cocur\Slugify\Slugify',
  58. $this->slugify->addRule('X', 'y')
  59. );
  60. $this->assertSame('y', $this->slugify->slugify('X'));
  61. }
  62. /**
  63. * @covers \Cocur\Slugify\Slugify::addRules()
  64. * @covers \Cocur\Slugify\Slugify::slugify()
  65. */
  66. public function testAddRulesAddsMultipleRules()
  67. {
  68. $this->assertInstanceOf(
  69. 'Cocur\Slugify\Slugify',
  70. $this->slugify->addRules(['x' => 'y', 'a' => 'b'])
  71. );
  72. $this->assertSame('yb', $this->slugify->slugify('xa'));
  73. }
  74. /**
  75. * @covers \Cocur\Slugify\Slugify::activateRuleset()
  76. */
  77. public function testActivateRulesetActivatesTheGivenRuleset()
  78. {
  79. $provider = Mockery::mock('\Cocur\Slugify\RuleProvider\RuleProviderInterface');
  80. $provider->shouldReceive('getRules')->with('esperanto')->once()->andReturn(['ĉ' => 'cx']);
  81. $slugify = new Slugify(['rulesets' => []], $provider);
  82. $this->assertInstanceOf(
  83. 'Cocur\Slugify\Slugify',
  84. $slugify->activateRuleset('esperanto')
  85. );
  86. $this->assertSame('sercxi', $slugify->slugify('serĉi'));
  87. }
  88. /**
  89. * @covers \Cocur\Slugify\Slugify::create()
  90. */
  91. public function testCreateReturnsAnInstance()
  92. {
  93. $this->assertInstanceOf('Cocur\\Slugify\\SlugifyInterface', Slugify::create());
  94. }
  95. /**
  96. * @covers \Cocur\Slugify\Slugify::__construct()
  97. */
  98. public function testConstructWithOtherRegexp()
  99. {
  100. $this->slugify = new Slugify(['regexp' => '/([^a-z0-9.]|-)+/']);
  101. $this->assertSame('file-name.tar.gz', $this->slugify->slugify('File Name.tar.gz'));
  102. }
  103. /**
  104. * @covers \Cocur\Slugify\Slugify::__construct()
  105. * @covers \Cocur\Slugify\Slugify::slugify()
  106. */
  107. public function testDoNotConvertToLowercase()
  108. {
  109. $actual = 'File Name';
  110. $expected = 'File-Name';
  111. $this->slugify = new Slugify(['lowercase' => false]);
  112. $this->assertSame($expected, $this->slugify->slugify($actual));
  113. }
  114. /**
  115. * @dataProvider customRulesProvider
  116. */
  117. public function testCustomRules($rule, $string, $result)
  118. {
  119. $slugify = new Slugify();
  120. $slugify->activateRuleSet($rule);
  121. $this->assertSame($result, $slugify->slugify($string));
  122. }
  123. public function customRulesProvider()
  124. {
  125. return [
  126. ['azerbaijani', 'əöüğşçı', 'eougsci'],
  127. ['azerbaijani', 'Fərhad Səfərov', 'ferhad-seferov'],
  128. ['croatian', 'Č Ć Ž Š Đ č ć ž š đ', 'c-c-z-s-dj-c-c-z-s-dj'],
  129. ['danish', 'Æ æ Ø ø Å å É é', 'ae-ae-oe-oe-aa-aa-e-e'],
  130. ['romanian', 'ă î â ş ș ţ ț Ă Î Â Ş Ș Ţ Ț', 'a-i-a-s-s-t-t-a-i-a-s-s-t-t'],
  131. ['serbian', 'А Б В Г Д Ђ Е Ж З И Ј К Л Љ М Н Њ О П Р С Т Ћ У Ф Х Ц Ч Џ Ш а б в г д ђ е ж з и ј к л љ м н њ о п р с т ћ у ф х ц ч џ ш Š Đ Ž Ć Č š đ ž ć č', 'a-b-v-g-d-dj-e-z-z-i-j-k-l-lj-m-n-nj-o-p-r-s-t-c-u-f-h-c-c-dz-s-a-b-v-g-d-dj-e-z-z-i-j-k-l-lj-m-n-nj-o-p-r-s-t-c-u-f-h-c-c-dz-s-s-dj-z-c-c-s-dj-z-c-c'],
  132. ['slovak', 'Á Ä Č Ď É Í Ĺ Ľ Ň Ó Ô Ŕ Š Ť Ú Ý Ž á ä č ď é í ĺ ľ ň ó ô ŕ š ť ú ý ž', 'a-a-c-d-e-i-l-l-n-o-o-r-s-t-u-y-z-a-a-c-d-e-i-l-l-n-o-o-r-s-t-u-y-z'],
  133. ['lithuanian', 'Ą Č Ę Ė Į Š Ų Ū Ž ą č ę ė į š ų ū ž', 'a-c-e-e-i-s-u-u-z-a-c-e-e-i-s-u-u-z'],
  134. ['estonian', 'Š Ž Õ Ä Ö Ü š ž õ ä ö ü', 's-z-o-a-o-u-s-z-o-a-o-u'],
  135. ['hungarian', 'Á É Í Ó Ö Ő Ú Ü Ű á é í ó ö ő ú ü ű', 'a-e-i-o-o-o-u-u-u-a-e-i-o-o-o-u-u-u'],
  136. ['macedonian', 'Ѓезвето беше полно со црно кафе. Ѕ ѕ s', 'gjezveto-beshe-polno-so-crno-kafe-dz-dz-s'],
  137. ['chinese', '活动日起', 'huodongriqi'],
  138. ['turkmen', 'Ç Ä Ž Ň Ö Ş Ü Ý ç ä ž ň ö ş ü ý', 'c-a-z-n-o-s-u-y-c-a-z-n-o-s-u-y'],
  139. ];
  140. }
  141. /**
  142. * @covers \Cocur\Slugify\Slugify::__construct()
  143. * @covers \Cocur\Slugify\Slugify::slugify()
  144. */
  145. public function testSlugifyDefaultsToSeparatorOption()
  146. {
  147. $actual = 'file name';
  148. $expected = 'file__name';
  149. $this->slugify = new Slugify(['separator' => '__']);
  150. $this->assertSame($expected, $this->slugify->slugify($actual));
  151. }
  152. /**
  153. * @covers \Cocur\Slugify\Slugify::__construct()
  154. * @covers \Cocur\Slugify\Slugify::slugify()
  155. */
  156. public function testSlugifyHonorsSeparatorArgument()
  157. {
  158. $actual = 'file name';
  159. $expected = 'file__name';
  160. $this->slugify = new Slugify(['separator' => 'dummy']);
  161. $this->assertSame($expected, $this->slugify->slugify($actual, '__'));
  162. }
  163. /**
  164. * @covers \Cocur\Slugify\Slugify::slugify()
  165. */
  166. public function testSlugifyOptionsArray()
  167. {
  168. $this->assertSame('file-name', $this->slugify->slugify('file name'));
  169. $this->assertSame('file+name', $this->slugify->slugify('file name', ['separator' => '+']));
  170. $this->assertSame('name-1', $this->slugify->slugify('name(1)'));
  171. $this->assertSame('name(1)', $this->slugify->slugify('name(1)', ['regexp' => '/([^a-z0-9.()]|-)+/']));
  172. $this->assertSame('file-name', $this->slugify->slugify('FILE NAME'));
  173. $this->assertSame('FILE-NAME', $this->slugify->slugify('FILE NAME', ['lowercase' => false]));
  174. $this->assertSame('file-name', $this->slugify->slugify('file name '));
  175. $this->assertSame('file-name-', $this->slugify->slugify('file name ', ['trim' => false]));
  176. $this->assertSame('file-name', $this->slugify->slugify('<file name'));
  177. $this->assertSame('p-file-p-foo-a-href-bar-name-a', $this->slugify->slugify('<p>file</p><!-- foo --> <a href="#bar">name</a>'));
  178. $this->assertSame('file-name', $this->slugify->slugify('<p>file</p><!-- foo --> <a href="#bar">name</a>', ['strip_tags' => true]));
  179. }
  180. /**
  181. * @covers \Cocur\Slugify\Slugify::slugify()
  182. */
  183. public function testSlugifyCustomRuleSet()
  184. {
  185. $slugify = new Slugify();
  186. $this->assertSame('fur', $slugify->slugify('für', ['ruleset' => 'turkish']));
  187. $this->assertSame('fuer', $slugify->slugify('für'));
  188. }
  189. public function defaultRuleProvider()
  190. {
  191. return [
  192. [' a b ', 'a-b'],
  193. ['Hello', 'hello'],
  194. ['Hello World', 'hello-world'],
  195. ['Привет мир', 'privet-mir'],
  196. ['Привіт світ', 'privit-svit'],
  197. ['Hello: World', 'hello-world'],
  198. ['H+e#l1l--o/W§o r.l:d)', 'h-e-l1l-o-w-o-r-l-d'],
  199. [': World', 'world'],
  200. ['Hello World!', 'hello-world'],
  201. ['Ä ä Ö ö Ü ü ß', 'ae-ae-oe-oe-ue-ue-ss'],
  202. ['Á À á à É È é è Ó Ò ó ò Ñ ñ Ú Ù ú ù', 'a-a-a-a-e-e-e-e-o-o-o-o-n-n-u-u-u-u'],
  203. ['Â â Ê ê Ô ô Û û', 'a-a-e-e-o-o-u-u'],
  204. ['Â â Ê ê Ô ô Û 1', 'a-a-e-e-o-o-u-1'],
  205. ['°¹²³⁴⁵⁶⁷⁸⁹@₀₁₂₃₄₅₆₇₈₉', '0123456789at0123456789'],
  206. ['Mórë thån wørds', 'more-thaan-woerds'],
  207. ['Блоґ їжачка', 'blog-jizhachka'],
  208. ['фильм', 'film'],
  209. ['драма', 'drama'],
  210. ['Ύπαρξη Αυτής η Σκουληκομυρμηγκότρυπα', 'iparxi-autis-i-skoulikomirmigkotripa'],
  211. ['Français Œuf où à', 'francais-oeuf-ou-a'],
  212. ['هذه هي اللغة العربية', 'hthh-hy-llgh-laarby'],
  213. ['مرحبا العالم', 'mrhb-laa-lm'],
  214. ['Één jaar', 'een-jaar'],
  215. ['tiếng việt rất khó', 'tieng-viet-rat-kho'],
  216. ['Nguyễn Đăng Khoa', 'nguyen-dang-khoa'],
  217. ['နှစ်သစ်ကူးတွင် သတ္တဝါတွေ စိတ်ချမ်းသာ ကိုယ်ကျန်းမာ၍ ကောင်းခြင်း အနန္တနှင့် ပြည့်စုံကြပါစေ', 'nhitthitkutwin-thttwatwe-seikkhyaantha-koekyaanmaywae-kaungkhyin-anntnhin-pyisonkypase'],
  218. ['Zażółć żółcią gęślą jaźń', 'zazolc-zolcia-gesla-jazn'],
  219. ['Mężny bądź chroń pułk twój i sześć flag', 'mezny-badz-chron-pulk-twoj-i-szesc-flag'],
  220. ['ერთი ორი სამი ოთხი ხუთი', 'erti-ori-sami-otkhi-khuti'],
  221. ['अ ऒ न द', 'a-oii-na-tha'],
  222. ['Æ Ø Å æ ø å', 'ae-oe-aa-ae-oe-aa'],
  223. [str_repeat('Übergrößenträger', 1000), str_repeat('uebergroessentraeger', 1000)],
  224. [str_repeat('my🎉', 5000), substr(str_repeat('my-', 5000), 0, -1)],
  225. [str_repeat('hi🇦🇹', 5000), substr(str_repeat('hi-', 5000), 0, -1)],
  226. ['Č Ć Ž Š Đ č ć ž š đ', 'c-c-z-s-d-c-c-z-s-d'],
  227. ['Ą Č Ę Ė Į Š Ų Ū Ž ą č ę ė į š ų ū ž', 'a-c-e-e-i-s-u-u-z-a-c-e-e-i-s-u-u-z'],
  228. ];
  229. }
  230. /**
  231. * @covers \Cocur\Slugify\Slugify::slugify()
  232. */
  233. public function testSlugifyLowercaseNotAfterRegexp()
  234. {
  235. $slugify = new Slugify();
  236. // Matches any non-uppercase letter followed by an uppercase letter,
  237. // which means it must be used before lowercasing the result.
  238. $regexp = '/(?<=[[:^upper:]])(?=[[:upper:]])/';
  239. $this->assertSame('foobar', $slugify->slugify('FooBar', [
  240. 'regexp' => $regexp,
  241. 'lowercase' => true,
  242. 'lowercase_after_regexp' => false,
  243. 'separator' => '_',
  244. ]));
  245. }
  246. /**
  247. * @covers \Cocur\Slugify\Slugify::slugify()
  248. */
  249. public function testSlugifyLowercaseAfterRegexp()
  250. {
  251. $slugify = new Slugify();
  252. // Matches any non-uppercase letter followed by an uppercase letter,
  253. // which means it must be used before lowercasing the result.
  254. $regexp = '/(?<=[[:^upper:]])(?=[[:upper:]])/';
  255. $this->assertSame('foo_bar', $slugify->slugify('FooBar', [
  256. 'regexp' => $regexp,
  257. 'lowercase' => true,
  258. 'lowercase_after_regexp' => true,
  259. 'separator' => '_',
  260. ]));
  261. }
  262. }