UnicodeTest.php 19 KB

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