SupportHelpersTest.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. <?php
  2. namespace Illuminate\Tests\Support;
  3. use ArrayAccess;
  4. use Illuminate\Contracts\Support\Htmlable;
  5. use Illuminate\Support\Env;
  6. use Illuminate\Support\Optional;
  7. use LogicException;
  8. use Mockery as m;
  9. use PHPUnit\Framework\TestCase;
  10. use RuntimeException;
  11. use stdClass;
  12. class SupportHelpersTest extends TestCase
  13. {
  14. protected function tearDown(): void
  15. {
  16. m::close();
  17. }
  18. public function testE()
  19. {
  20. $str = 'A \'quote\' is <b>bold</b>';
  21. $this->assertSame('A &#039;quote&#039; is &lt;b&gt;bold&lt;/b&gt;', e($str));
  22. $html = m::mock(Htmlable::class);
  23. $html->shouldReceive('toHtml')->andReturn($str);
  24. $this->assertEquals($str, e($html));
  25. }
  26. public function testClassBasename()
  27. {
  28. $this->assertSame('Baz', class_basename('Foo\Bar\Baz'));
  29. $this->assertSame('Baz', class_basename('Baz'));
  30. }
  31. public function testValue()
  32. {
  33. $this->assertSame('foo', value('foo'));
  34. $this->assertSame('foo', value(function () {
  35. return 'foo';
  36. }));
  37. $this->assertSame('foo', value(function ($arg) {
  38. return $arg;
  39. }, 'foo'));
  40. }
  41. public function testObjectGet()
  42. {
  43. $class = new stdClass;
  44. $class->name = new stdClass;
  45. $class->name->first = 'Taylor';
  46. $this->assertSame('Taylor', object_get($class, 'name.first'));
  47. }
  48. public function testDataGet()
  49. {
  50. $object = (object) ['users' => ['name' => ['Taylor', 'Otwell']]];
  51. $array = [(object) ['users' => [(object) ['name' => 'Taylor']]]];
  52. $dottedArray = ['users' => ['first.name' => 'Taylor', 'middle.name' => null]];
  53. $arrayAccess = new SupportTestArrayAccess(['price' => 56, 'user' => new SupportTestArrayAccess(['name' => 'John']), 'email' => null]);
  54. $this->assertSame('Taylor', data_get($object, 'users.name.0'));
  55. $this->assertSame('Taylor', data_get($array, '0.users.0.name'));
  56. $this->assertNull(data_get($array, '0.users.3'));
  57. $this->assertSame('Not found', data_get($array, '0.users.3', 'Not found'));
  58. $this->assertSame('Not found', data_get($array, '0.users.3', function () {
  59. return 'Not found';
  60. }));
  61. $this->assertSame('Taylor', data_get($dottedArray, ['users', 'first.name']));
  62. $this->assertNull(data_get($dottedArray, ['users', 'middle.name']));
  63. $this->assertSame('Not found', data_get($dottedArray, ['users', 'last.name'], 'Not found'));
  64. $this->assertEquals(56, data_get($arrayAccess, 'price'));
  65. $this->assertSame('John', data_get($arrayAccess, 'user.name'));
  66. $this->assertSame('void', data_get($arrayAccess, 'foo', 'void'));
  67. $this->assertSame('void', data_get($arrayAccess, 'user.foo', 'void'));
  68. $this->assertNull(data_get($arrayAccess, 'foo'));
  69. $this->assertNull(data_get($arrayAccess, 'user.foo'));
  70. $this->assertNull(data_get($arrayAccess, 'email', 'Not found'));
  71. }
  72. public function testDataGetWithNestedArrays()
  73. {
  74. $array = [
  75. ['name' => 'taylor', 'email' => 'taylorotwell@gmail.com'],
  76. ['name' => 'abigail'],
  77. ['name' => 'dayle'],
  78. ];
  79. $this->assertEquals(['taylor', 'abigail', 'dayle'], data_get($array, '*.name'));
  80. $this->assertEquals(['taylorotwell@gmail.com', null, null], data_get($array, '*.email', 'irrelevant'));
  81. $array = [
  82. 'users' => [
  83. ['first' => 'taylor', 'last' => 'otwell', 'email' => 'taylorotwell@gmail.com'],
  84. ['first' => 'abigail', 'last' => 'otwell'],
  85. ['first' => 'dayle', 'last' => 'rees'],
  86. ],
  87. 'posts' => null,
  88. ];
  89. $this->assertEquals(['taylor', 'abigail', 'dayle'], data_get($array, 'users.*.first'));
  90. $this->assertEquals(['taylorotwell@gmail.com', null, null], data_get($array, 'users.*.email', 'irrelevant'));
  91. $this->assertSame('not found', data_get($array, 'posts.*.date', 'not found'));
  92. $this->assertNull(data_get($array, 'posts.*.date'));
  93. }
  94. public function testDataGetWithDoubleNestedArraysCollapsesResult()
  95. {
  96. $array = [
  97. 'posts' => [
  98. [
  99. 'comments' => [
  100. ['author' => 'taylor', 'likes' => 4],
  101. ['author' => 'abigail', 'likes' => 3],
  102. ],
  103. ],
  104. [
  105. 'comments' => [
  106. ['author' => 'abigail', 'likes' => 2],
  107. ['author' => 'dayle'],
  108. ],
  109. ],
  110. [
  111. 'comments' => [
  112. ['author' => 'dayle'],
  113. ['author' => 'taylor', 'likes' => 1],
  114. ],
  115. ],
  116. ],
  117. ];
  118. $this->assertEquals(['taylor', 'abigail', 'abigail', 'dayle', 'dayle', 'taylor'], data_get($array, 'posts.*.comments.*.author'));
  119. $this->assertEquals([4, 3, 2, null, null, 1], data_get($array, 'posts.*.comments.*.likes'));
  120. $this->assertEquals([], data_get($array, 'posts.*.users.*.name', 'irrelevant'));
  121. $this->assertEquals([], data_get($array, 'posts.*.users.*.name'));
  122. }
  123. public function testDataFill()
  124. {
  125. $data = ['foo' => 'bar'];
  126. $this->assertEquals(['foo' => 'bar', 'baz' => 'boom'], data_fill($data, 'baz', 'boom'));
  127. $this->assertEquals(['foo' => 'bar', 'baz' => 'boom'], data_fill($data, 'baz', 'noop'));
  128. $this->assertEquals(['foo' => [], 'baz' => 'boom'], data_fill($data, 'foo.*', 'noop'));
  129. $this->assertEquals(
  130. ['foo' => ['bar' => 'kaboom'], 'baz' => 'boom'],
  131. data_fill($data, 'foo.bar', 'kaboom')
  132. );
  133. }
  134. public function testDataFillWithStar()
  135. {
  136. $data = ['foo' => 'bar'];
  137. $this->assertEquals(
  138. ['foo' => []],
  139. data_fill($data, 'foo.*.bar', 'noop')
  140. );
  141. $this->assertEquals(
  142. ['foo' => [], 'bar' => [['baz' => 'original'], []]],
  143. data_fill($data, 'bar', [['baz' => 'original'], []])
  144. );
  145. $this->assertEquals(
  146. ['foo' => [], 'bar' => [['baz' => 'original'], ['baz' => 'boom']]],
  147. data_fill($data, 'bar.*.baz', 'boom')
  148. );
  149. $this->assertEquals(
  150. ['foo' => [], 'bar' => [['baz' => 'original'], ['baz' => 'boom']]],
  151. data_fill($data, 'bar.*', 'noop')
  152. );
  153. }
  154. public function testDataFillWithDoubleStar()
  155. {
  156. $data = [
  157. 'posts' => [
  158. (object) [
  159. 'comments' => [
  160. (object) ['name' => 'First'],
  161. (object) [],
  162. ],
  163. ],
  164. (object) [
  165. 'comments' => [
  166. (object) [],
  167. (object) ['name' => 'Second'],
  168. ],
  169. ],
  170. ],
  171. ];
  172. data_fill($data, 'posts.*.comments.*.name', 'Filled');
  173. $this->assertEquals([
  174. 'posts' => [
  175. (object) [
  176. 'comments' => [
  177. (object) ['name' => 'First'],
  178. (object) ['name' => 'Filled'],
  179. ],
  180. ],
  181. (object) [
  182. 'comments' => [
  183. (object) ['name' => 'Filled'],
  184. (object) ['name' => 'Second'],
  185. ],
  186. ],
  187. ],
  188. ], $data);
  189. }
  190. public function testDataSet()
  191. {
  192. $data = ['foo' => 'bar'];
  193. $this->assertEquals(
  194. ['foo' => 'bar', 'baz' => 'boom'],
  195. data_set($data, 'baz', 'boom')
  196. );
  197. $this->assertEquals(
  198. ['foo' => 'bar', 'baz' => 'kaboom'],
  199. data_set($data, 'baz', 'kaboom')
  200. );
  201. $this->assertEquals(
  202. ['foo' => [], 'baz' => 'kaboom'],
  203. data_set($data, 'foo.*', 'noop')
  204. );
  205. $this->assertEquals(
  206. ['foo' => ['bar' => 'boom'], 'baz' => 'kaboom'],
  207. data_set($data, 'foo.bar', 'boom')
  208. );
  209. $this->assertEquals(
  210. ['foo' => ['bar' => 'boom'], 'baz' => ['bar' => 'boom']],
  211. data_set($data, 'baz.bar', 'boom')
  212. );
  213. $this->assertEquals(
  214. ['foo' => ['bar' => 'boom'], 'baz' => ['bar' => ['boom' => ['kaboom' => 'boom']]]],
  215. data_set($data, 'baz.bar.boom.kaboom', 'boom')
  216. );
  217. }
  218. public function testDataSetWithStar()
  219. {
  220. $data = ['foo' => 'bar'];
  221. $this->assertEquals(
  222. ['foo' => []],
  223. data_set($data, 'foo.*.bar', 'noop')
  224. );
  225. $this->assertEquals(
  226. ['foo' => [], 'bar' => [['baz' => 'original'], []]],
  227. data_set($data, 'bar', [['baz' => 'original'], []])
  228. );
  229. $this->assertEquals(
  230. ['foo' => [], 'bar' => [['baz' => 'boom'], ['baz' => 'boom']]],
  231. data_set($data, 'bar.*.baz', 'boom')
  232. );
  233. $this->assertEquals(
  234. ['foo' => [], 'bar' => ['overwritten', 'overwritten']],
  235. data_set($data, 'bar.*', 'overwritten')
  236. );
  237. }
  238. public function testDataSetWithDoubleStar()
  239. {
  240. $data = [
  241. 'posts' => [
  242. (object) [
  243. 'comments' => [
  244. (object) ['name' => 'First'],
  245. (object) [],
  246. ],
  247. ],
  248. (object) [
  249. 'comments' => [
  250. (object) [],
  251. (object) ['name' => 'Second'],
  252. ],
  253. ],
  254. ],
  255. ];
  256. data_set($data, 'posts.*.comments.*.name', 'Filled');
  257. $this->assertEquals([
  258. 'posts' => [
  259. (object) [
  260. 'comments' => [
  261. (object) ['name' => 'Filled'],
  262. (object) ['name' => 'Filled'],
  263. ],
  264. ],
  265. (object) [
  266. 'comments' => [
  267. (object) ['name' => 'Filled'],
  268. (object) ['name' => 'Filled'],
  269. ],
  270. ],
  271. ],
  272. ], $data);
  273. }
  274. public function testHead()
  275. {
  276. $array = ['a', 'b', 'c'];
  277. $this->assertSame('a', head($array));
  278. }
  279. public function testLast()
  280. {
  281. $array = ['a', 'b', 'c'];
  282. $this->assertSame('c', last($array));
  283. }
  284. public function testClassUsesRecursiveShouldReturnTraitsOnParentClasses()
  285. {
  286. $this->assertSame(
  287. [
  288. SupportTestTraitTwo::class => SupportTestTraitTwo::class,
  289. SupportTestTraitOne::class => SupportTestTraitOne::class,
  290. ],
  291. class_uses_recursive(SupportTestClassTwo::class)
  292. );
  293. }
  294. public function testClassUsesRecursiveAcceptsObject()
  295. {
  296. $this->assertSame(
  297. [
  298. SupportTestTraitTwo::class => SupportTestTraitTwo::class,
  299. SupportTestTraitOne::class => SupportTestTraitOne::class,
  300. ],
  301. class_uses_recursive(new SupportTestClassTwo)
  302. );
  303. }
  304. public function testClassUsesRecursiveReturnParentTraitsFirst()
  305. {
  306. $this->assertSame(
  307. [
  308. SupportTestTraitTwo::class => SupportTestTraitTwo::class,
  309. SupportTestTraitOne::class => SupportTestTraitOne::class,
  310. SupportTestTraitThree::class => SupportTestTraitThree::class,
  311. ],
  312. class_uses_recursive(SupportTestClassThree::class)
  313. );
  314. }
  315. public function testTap()
  316. {
  317. $object = (object) ['id' => 1];
  318. $this->assertEquals(2, tap($object, function ($object) {
  319. $object->id = 2;
  320. })->id);
  321. $mock = m::mock();
  322. $mock->shouldReceive('foo')->once()->andReturn('bar');
  323. $this->assertEquals($mock, tap($mock)->foo());
  324. }
  325. public function testThrow()
  326. {
  327. $this->expectException(LogicException::class);
  328. throw_if(true, new LogicException);
  329. }
  330. public function testThrowDefaultException()
  331. {
  332. $this->expectException(RuntimeException::class);
  333. throw_if(true);
  334. }
  335. public function testThrowExceptionWithMessage()
  336. {
  337. $this->expectException(RuntimeException::class);
  338. $this->expectExceptionMessage('test');
  339. throw_if(true, 'test');
  340. }
  341. public function testThrowExceptionAsStringWithMessage()
  342. {
  343. $this->expectException(LogicException::class);
  344. $this->expectExceptionMessage('test');
  345. throw_if(true, LogicException::class, 'test');
  346. }
  347. public function testThrowUnless()
  348. {
  349. $this->expectException(LogicException::class);
  350. throw_unless(false, new LogicException);
  351. }
  352. public function testThrowUnlessDefaultException()
  353. {
  354. $this->expectException(RuntimeException::class);
  355. throw_unless(false);
  356. }
  357. public function testThrowUnlessExceptionWithMessage()
  358. {
  359. $this->expectException(RuntimeException::class);
  360. $this->expectExceptionMessage('test');
  361. throw_unless(false, 'test');
  362. }
  363. public function testThrowUnlessExceptionAsStringWithMessage()
  364. {
  365. $this->expectException(LogicException::class);
  366. $this->expectExceptionMessage('test');
  367. throw_unless(false, LogicException::class, 'test');
  368. }
  369. public function testThrowReturnIfNotThrown()
  370. {
  371. $this->assertSame('foo', throw_unless('foo', new RuntimeException));
  372. }
  373. public function testThrowWithString()
  374. {
  375. $this->expectException(RuntimeException::class);
  376. $this->expectExceptionMessage('Test Message');
  377. throw_if(true, RuntimeException::class, 'Test Message');
  378. }
  379. public function testOptional()
  380. {
  381. $this->assertNull(optional(null)->something());
  382. $this->assertEquals(10, optional(new class
  383. {
  384. public function something()
  385. {
  386. return 10;
  387. }
  388. })->something());
  389. }
  390. public function testOptionalWithCallback()
  391. {
  392. $this->assertNull(optional(null, function () {
  393. throw new RuntimeException(
  394. 'The optional callback should not be called for null'
  395. );
  396. }));
  397. $this->assertEquals(10, optional(5, function ($number) {
  398. return $number * 2;
  399. }));
  400. }
  401. public function testOptionalWithArray()
  402. {
  403. $this->assertSame('here', optional(['present' => 'here'])['present']);
  404. $this->assertNull(optional(null)['missing']);
  405. $this->assertNull(optional(['present' => 'here'])->missing);
  406. }
  407. public function testOptionalReturnsObjectPropertyOrNull()
  408. {
  409. $this->assertSame('bar', optional((object) ['foo' => 'bar'])->foo);
  410. $this->assertNull(optional(['foo' => 'bar'])->foo);
  411. $this->assertNull(optional((object) ['foo' => 'bar'])->bar);
  412. }
  413. public function testOptionalDeterminesWhetherKeyIsSet()
  414. {
  415. $this->assertTrue(isset(optional(['foo' => 'bar'])['foo']));
  416. $this->assertFalse(isset(optional(['foo' => 'bar'])['bar']));
  417. $this->assertFalse(isset(optional()['bar']));
  418. }
  419. public function testOptionalAllowsToSetKey()
  420. {
  421. $optional = optional([]);
  422. $optional['foo'] = 'bar';
  423. $this->assertSame('bar', $optional['foo']);
  424. $optional = optional(null);
  425. $optional['foo'] = 'bar';
  426. $this->assertFalse(isset($optional['foo']));
  427. }
  428. public function testOptionalAllowToUnsetKey()
  429. {
  430. $optional = optional(['foo' => 'bar']);
  431. $this->assertTrue(isset($optional['foo']));
  432. unset($optional['foo']);
  433. $this->assertFalse(isset($optional['foo']));
  434. $optional = optional((object) ['foo' => 'bar']);
  435. $this->assertFalse(isset($optional['foo']));
  436. $optional['foo'] = 'bar';
  437. $this->assertFalse(isset($optional['foo']));
  438. }
  439. public function testOptionalIsMacroable()
  440. {
  441. Optional::macro('present', function () {
  442. if (is_object($this->value)) {
  443. return $this->value->present();
  444. }
  445. return new Optional(null);
  446. });
  447. $this->assertNull(optional(null)->present()->something());
  448. $this->assertSame('$10.00', optional(new class
  449. {
  450. public function present()
  451. {
  452. return new class
  453. {
  454. public function something()
  455. {
  456. return '$10.00';
  457. }
  458. };
  459. }
  460. })->present()->something());
  461. }
  462. public function testRetry()
  463. {
  464. $startTime = microtime(true);
  465. $attempts = retry(2, function ($attempts) {
  466. if ($attempts > 1) {
  467. return $attempts;
  468. }
  469. throw new RuntimeException;
  470. }, 100);
  471. // Make sure we made two attempts
  472. $this->assertEquals(2, $attempts);
  473. // Make sure we waited 100ms for the first attempt
  474. $this->assertEqualsWithDelta(0.1, microtime(true) - $startTime, 0.03);
  475. }
  476. public function testRetryWithPassingSleepCallback()
  477. {
  478. $startTime = microtime(true);
  479. $attempts = retry(3, function ($attempts) {
  480. if ($attempts > 2) {
  481. return $attempts;
  482. }
  483. throw new RuntimeException;
  484. }, function ($attempt) {
  485. return $attempt * 100;
  486. });
  487. // Make sure we made three attempts
  488. $this->assertEquals(3, $attempts);
  489. // Make sure we waited 300ms for the first two attempts
  490. $this->assertEqualsWithDelta(0.3, microtime(true) - $startTime, 0.03);
  491. }
  492. public function testRetryWithPassingWhenCallback()
  493. {
  494. $startTime = microtime(true);
  495. $attempts = retry(2, function ($attempts) {
  496. if ($attempts > 1) {
  497. return $attempts;
  498. }
  499. throw new RuntimeException;
  500. }, 100, function ($ex) {
  501. return true;
  502. });
  503. // Make sure we made two attempts
  504. $this->assertEquals(2, $attempts);
  505. // Make sure we waited 100ms for the first attempt
  506. $this->assertEqualsWithDelta(0.1, microtime(true) - $startTime, 0.03);
  507. }
  508. public function testRetryWithFailingWhenCallback()
  509. {
  510. $this->expectException(RuntimeException::class);
  511. retry(2, function ($attempts) {
  512. if ($attempts > 1) {
  513. return $attempts;
  514. }
  515. throw new RuntimeException;
  516. }, 100, function ($ex) {
  517. return false;
  518. });
  519. }
  520. public function testTransform()
  521. {
  522. $this->assertEquals(10, transform(5, function ($value) {
  523. return $value * 2;
  524. }));
  525. $this->assertNull(transform(null, function () {
  526. return 10;
  527. }));
  528. }
  529. public function testTransformDefaultWhenBlank()
  530. {
  531. $this->assertSame('baz', transform(null, function () {
  532. return 'bar';
  533. }, 'baz'));
  534. $this->assertSame('baz', transform('', function () {
  535. return 'bar';
  536. }, function () {
  537. return 'baz';
  538. }));
  539. }
  540. public function testWith()
  541. {
  542. $this->assertEquals(10, with(10));
  543. $this->assertEquals(10, with(5, function ($five) {
  544. return $five + 5;
  545. }));
  546. }
  547. public function testEnv()
  548. {
  549. $_SERVER['foo'] = 'bar';
  550. $this->assertSame('bar', env('foo'));
  551. $this->assertSame('bar', Env::get('foo'));
  552. }
  553. public function testEnvTrue()
  554. {
  555. $_SERVER['foo'] = 'true';
  556. $this->assertTrue(env('foo'));
  557. $_SERVER['foo'] = '(true)';
  558. $this->assertTrue(env('foo'));
  559. }
  560. public function testEnvFalse()
  561. {
  562. $_SERVER['foo'] = 'false';
  563. $this->assertFalse(env('foo'));
  564. $_SERVER['foo'] = '(false)';
  565. $this->assertFalse(env('foo'));
  566. }
  567. public function testEnvEmpty()
  568. {
  569. $_SERVER['foo'] = '';
  570. $this->assertSame('', env('foo'));
  571. $_SERVER['foo'] = 'empty';
  572. $this->assertSame('', env('foo'));
  573. $_SERVER['foo'] = '(empty)';
  574. $this->assertSame('', env('foo'));
  575. }
  576. public function testEnvNull()
  577. {
  578. $_SERVER['foo'] = 'null';
  579. $this->assertNull(env('foo'));
  580. $_SERVER['foo'] = '(null)';
  581. $this->assertNull(env('foo'));
  582. }
  583. public function testEnvDefault()
  584. {
  585. $_SERVER['foo'] = 'bar';
  586. $this->assertSame('bar', env('foo', 'default'));
  587. $_SERVER['foo'] = '';
  588. $this->assertSame('', env('foo', 'default'));
  589. unset($_SERVER['foo']);
  590. $this->assertSame('default', env('foo', 'default'));
  591. $_SERVER['foo'] = null;
  592. $this->assertSame('default', env('foo', 'default'));
  593. }
  594. public function testEnvEscapedString()
  595. {
  596. $_SERVER['foo'] = '"null"';
  597. $this->assertSame('null', env('foo'));
  598. $_SERVER['foo'] = "'null'";
  599. $this->assertSame('null', env('foo'));
  600. $_SERVER['foo'] = 'x"null"x'; // this should not be unquoted
  601. $this->assertSame('x"null"x', env('foo'));
  602. }
  603. public function testGetFromSERVERFirst()
  604. {
  605. $_ENV['foo'] = 'From $_ENV';
  606. $_SERVER['foo'] = 'From $_SERVER';
  607. $this->assertSame('From $_SERVER', env('foo'));
  608. }
  609. public function providesPregReplaceArrayData()
  610. {
  611. $pointerArray = ['Taylor', 'Otwell'];
  612. next($pointerArray);
  613. return [
  614. ['/:[a-z_]+/', ['8:30', '9:00'], 'The event will take place between :start and :end', 'The event will take place between 8:30 and 9:00'],
  615. ['/%s/', ['Taylor'], 'Hi, %s', 'Hi, Taylor'],
  616. ['/%s/', ['Taylor', 'Otwell'], 'Hi, %s %s', 'Hi, Taylor Otwell'],
  617. ['/%s/', [], 'Hi, %s %s', 'Hi, '],
  618. ['/%s/', ['a', 'b', 'c'], 'Hi', 'Hi'],
  619. ['//', [], '', ''],
  620. ['/%s/', ['a'], '', ''],
  621. // The internal pointer of this array is not at the beginning
  622. ['/%s/', $pointerArray, 'Hi, %s %s', 'Hi, Taylor Otwell'],
  623. ];
  624. }
  625. /**
  626. * @dataProvider providesPregReplaceArrayData
  627. */
  628. public function testPregReplaceArray($pattern, $replacements, $subject, $expectedOutput)
  629. {
  630. $this->assertSame(
  631. $expectedOutput,
  632. preg_replace_array($pattern, $replacements, $subject)
  633. );
  634. }
  635. }
  636. trait SupportTestTraitOne
  637. {
  638. //
  639. }
  640. trait SupportTestTraitTwo
  641. {
  642. use SupportTestTraitOne;
  643. }
  644. class SupportTestClassOne
  645. {
  646. use SupportTestTraitTwo;
  647. }
  648. class SupportTestClassTwo extends SupportTestClassOne
  649. {
  650. //
  651. }
  652. trait SupportTestTraitThree
  653. {
  654. //
  655. }
  656. class SupportTestClassThree extends SupportTestClassTwo
  657. {
  658. use SupportTestTraitThree;
  659. }
  660. class SupportTestArrayAccess implements ArrayAccess
  661. {
  662. protected $attributes = [];
  663. public function __construct($attributes = [])
  664. {
  665. $this->attributes = $attributes;
  666. }
  667. public function offsetExists($offset): bool
  668. {
  669. return array_key_exists($offset, $this->attributes);
  670. }
  671. #[\ReturnTypeWillChange]
  672. public function offsetGet($offset)
  673. {
  674. return $this->attributes[$offset];
  675. }
  676. public function offsetSet($offset, $value): void
  677. {
  678. $this->attributes[$offset] = $value;
  679. }
  680. public function offsetUnset($offset): void
  681. {
  682. unset($this->attributes[$offset]);
  683. }
  684. }