PregTest.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. <?php
  2. /*
  3. * This file is part of PHP CS Fixer.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. namespace PhpCsFixer\Tests;
  12. use PhpCsFixer\Preg;
  13. use PhpCsFixer\PregException;
  14. /**
  15. * @author Kuba Werłos <werlos@gmail.com>
  16. *
  17. * @covers \PhpCsFixer\Preg
  18. *
  19. * @internal
  20. */
  21. final class PregTest extends TestCase
  22. {
  23. public function testMatchFailing()
  24. {
  25. $this->expectException(PregException::class);
  26. $this->expectExceptionMessage('Preg::match(): Invalid PCRE pattern ""');
  27. Preg::match('', 'foo', $matches);
  28. }
  29. /**
  30. * @param string $pattern
  31. * @param string $subject
  32. *
  33. * @dataProvider provideCommonCases
  34. */
  35. public function testMatch($pattern, $subject)
  36. {
  37. $expectedResult = preg_match($pattern, $subject, $expectedMatches);
  38. $actualResult = Preg::match($pattern, $subject, $actualMatches);
  39. static::assertSame($expectedResult, $actualResult);
  40. static::assertSame($expectedMatches, $actualMatches);
  41. }
  42. public function providePatternValidationCases()
  43. {
  44. return [
  45. 'invalid_blank' => ['', null, PregException::class],
  46. 'invalid_open' => ["\1", null, PregException::class, "'\1' found"],
  47. 'valid_control_character_delimiter' => ["\1\1", 1],
  48. 'invalid_control_character_modifier' => ["\1\1\1", null, PregException::class, ' Unknown modifier '],
  49. 'valid_slate' => ['//', 1],
  50. 'valid_paired' => ['()', 1],
  51. 'null_byte_injection' => ['()'."\0", null, PregException::class, ' Null byte in regex '],
  52. 'paired_non_utf8_only' => ["((*UTF8)\xFF)", null, PregException::class, 'UTF-8'],
  53. 'valid_paired_non_utf8_only' => ["(\xFF)", 1],
  54. 'php_version_dependent' => ['([\\R])', 0, PregException::class, 'Compilation failed: escape sequence is invalid '],
  55. ];
  56. }
  57. /**
  58. * @dataProvider providePatternValidationCases
  59. *
  60. * @param string $pattern
  61. * @param null|int $expected
  62. * @param null|string $expectedException
  63. * @param null|string $expectedMessage
  64. */
  65. public function testPatternValidation($pattern, $expected = null, $expectedException = null, $expectedMessage = null)
  66. {
  67. $setup = function () use ($expectedException, $expectedMessage) {
  68. $i = 0;
  69. if (null !== $expectedException) {
  70. ++$i;
  71. $this->expectException($expectedException);
  72. }
  73. if (null !== $expectedMessage) {
  74. ++$i;
  75. $this->expectExceptionMessage($expectedMessage);
  76. }
  77. return (bool) $i;
  78. };
  79. try {
  80. $actual = Preg::match($pattern, "The quick brown \xFF\x00\\xXX jumps over the lazy dog\n");
  81. } catch (\Exception $ex) {
  82. $setup();
  83. throw $ex;
  84. }
  85. if (null !== $expected) {
  86. static::assertSame($expected, $actual);
  87. return;
  88. }
  89. $setup() || $this->addToAssertionCount(1);
  90. }
  91. /**
  92. * @dataProvider providePatternValidationCases
  93. *
  94. * @param string $pattern
  95. * @param null|int $expected
  96. * @param null|string $expectedException
  97. * @param null|string $expectedMessage
  98. */
  99. public function testPatternsValidation($pattern, $expected = null, $expectedException = null, $expectedMessage = null)
  100. {
  101. $setup = function () use ($expectedException, $expectedMessage) {
  102. $i = 0;
  103. if (null !== $expectedException) {
  104. ++$i;
  105. $this->expectException($expectedException);
  106. }
  107. if (null !== $expectedMessage) {
  108. ++$i;
  109. $this->expectExceptionMessage($expectedMessage);
  110. }
  111. return (bool) $i;
  112. };
  113. try {
  114. $buffer = "The quick brown \xFF\x00\\xXX jumps over the lazy dog\n";
  115. $actual = $buffer !== Preg::replace((array) $pattern, 'abc', $buffer);
  116. } catch (\Exception $ex) {
  117. $setup();
  118. throw $ex;
  119. }
  120. if (null !== $expected) {
  121. static::assertSame((bool) $expected, $actual);
  122. return;
  123. }
  124. $setup() || $this->addToAssertionCount(1);
  125. }
  126. public function testMatchAllFailing()
  127. {
  128. $this->expectException(PregException::class);
  129. $this->expectExceptionMessage('Preg::matchAll(): Invalid PCRE pattern ""');
  130. Preg::matchAll('', 'foo', $matches);
  131. }
  132. /**
  133. * @param string $pattern
  134. * @param string $subject
  135. *
  136. * @dataProvider provideCommonCases
  137. */
  138. public function testMatchAll($pattern, $subject)
  139. {
  140. $expectedResult = preg_match_all($pattern, $subject, $expectedMatches);
  141. $actualResult = Preg::matchAll($pattern, $subject, $actualMatches);
  142. static::assertSame($expectedResult, $actualResult);
  143. static::assertSame($expectedMatches, $actualMatches);
  144. }
  145. public function testReplaceFailing()
  146. {
  147. $this->expectException(PregException::class);
  148. $this->expectExceptionMessageRegExp('~\Q\Preg::replace()\E: Invalid PCRE pattern "": \(code: \d+\) [^(]+ \(version: \d+~');
  149. Preg::replace('', 'foo', 'bar');
  150. }
  151. /**
  152. * @param string $pattern
  153. * @param string $subject
  154. *
  155. * @dataProvider provideCommonCases
  156. * @dataProvider provideArrayOfPatternsCases
  157. */
  158. public function testReplace($pattern, $subject)
  159. {
  160. $expectedResult = preg_replace($pattern, 'foo', $subject);
  161. $actualResult = Preg::replace($pattern, 'foo', $subject);
  162. static::assertSame($expectedResult, $actualResult);
  163. }
  164. public function testReplaceCallbackFailing()
  165. {
  166. $this->expectException(PregException::class);
  167. $this->expectExceptionMessage('Preg::replaceCallback(): Invalid PCRE pattern ""');
  168. Preg::replaceCallback('', 'sort', 'foo');
  169. }
  170. /**
  171. * @param string $pattern
  172. * @param string $subject
  173. *
  174. * @dataProvider provideCommonCases
  175. * @dataProvider provideArrayOfPatternsCases
  176. */
  177. public function testReplaceCallback($pattern, $subject)
  178. {
  179. $callback = static function (array $x) { return implode('-', $x); };
  180. $expectedResult = preg_replace_callback($pattern, $callback, $subject);
  181. $actualResult = Preg::replaceCallback($pattern, $callback, $subject);
  182. static::assertSame($expectedResult, $actualResult);
  183. }
  184. public function provideCommonCases()
  185. {
  186. return [
  187. ['/u/u', 'u'],
  188. ['/u/u', 'u/u'],
  189. ['/./', \chr(224).'bc'],
  190. ['/à/', 'àbc'],
  191. ['/'.\chr(224).'|í/', 'àbc'],
  192. ];
  193. }
  194. public function provideArrayOfPatternsCases()
  195. {
  196. return [
  197. [['/à/', '/í/'], 'Tàíl'],
  198. [['/'.\chr(174).'/', '/'.\chr(224).'/'], 'foo'],
  199. ];
  200. }
  201. public function testSplitFailing()
  202. {
  203. $this->expectException(PregException::class);
  204. $this->expectExceptionMessage('Preg::split(): Invalid PCRE pattern ""');
  205. Preg::split('', 'foo');
  206. }
  207. /**
  208. * @param string $pattern
  209. * @param string $subject
  210. *
  211. * @dataProvider provideCommonCases
  212. */
  213. public function testSplit($pattern, $subject)
  214. {
  215. $expectedResult = preg_split($pattern, $subject);
  216. $actualResult = Preg::split($pattern, $subject);
  217. static::assertSame($expectedResult, $actualResult);
  218. }
  219. public function testCorrectnessForUtf8String()
  220. {
  221. $pattern = '/./';
  222. $subject = 'àbc';
  223. Preg::match($pattern, $subject, $methodMatches);
  224. preg_match($pattern, $subject, $functionMatches);
  225. static::assertSame(['à'], $methodMatches);
  226. static::assertNotSame(['à'], $functionMatches);
  227. }
  228. public function testCorrectnessForNonUtf8String()
  229. {
  230. $pattern = '/./u';
  231. $subject = \chr(224).'bc';
  232. Preg::match($pattern, $subject, $methodMatches);
  233. preg_match($pattern, $subject, $functionMatches);
  234. static::assertSame([\chr(224)], $methodMatches);
  235. static::assertNotSame([\chr(224)], $functionMatches);
  236. }
  237. }