PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/fabpot/php-cs-fixer/Symfony/CS/Tests/Tokenizer/TokensTest.php

https://gitlab.com/yousafsyed/easternglamor
PHP | 1030 lines | 845 code | 88 blank | 97 comment | 14 complexity | 0894dbcc074dea2bd0a7d7b4345b08e3 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the PHP CS utility.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. namespace Symfony\CS\Tests\Tokenizer;
  11. use Symfony\CS\Tokenizer\Token;
  12. use Symfony\CS\Tokenizer\Tokens;
  13. /**
  14. * @author Dariusz RumiƄski <dariusz.ruminski@gmail.com>
  15. * @author Max Voloshin <voloshin.dp@gmail.com>
  16. * @author Gregor Harlan <gharlan@web.de>
  17. */
  18. class TokensTest extends \PHPUnit_Framework_TestCase
  19. {
  20. /**
  21. * @param Token[]|null $expected
  22. * @param Token[]|null $input
  23. */
  24. private function assertEqualsTokensArray(array $expected = null, array $input = null)
  25. {
  26. if (null === $expected) {
  27. $this->assertNull($input);
  28. return;
  29. }
  30. $this->assertSame(array_keys($expected), array_keys($input), 'Both arrays need to have same keys.');
  31. foreach ($expected as $index => $expectedToken) {
  32. $this->assertTrue(
  33. $expectedToken->equals($input[$index]),
  34. sprintf('The token at index %d should be %s, got %s', $index, $expectedToken->toJson(), $input[$index]->toJson())
  35. );
  36. }
  37. }
  38. public function testGetClassyElements()
  39. {
  40. $source = <<<'PHP'
  41. <?php
  42. class Foo
  43. {
  44. public $prop0;
  45. protected $prop1;
  46. private $prop2 = 1;
  47. var $prop3 = array(1,2,3);
  48. public function bar4()
  49. {
  50. $a = 5;
  51. return " ({$a})";
  52. }
  53. public function bar5($data)
  54. {
  55. $message = $data;
  56. $example = function ($arg) use ($message) {
  57. echo $arg . ' ' . $message;
  58. };
  59. $example('hello');
  60. }
  61. }
  62. PHP;
  63. $tokens = Tokens::fromCode($source);
  64. $elements = array_values($tokens->getClassyElements());
  65. $this->assertCount(6, $elements);
  66. $this->assertSame('property', $elements[0]['type']);
  67. $this->assertSame('property', $elements[1]['type']);
  68. $this->assertSame('property', $elements[2]['type']);
  69. $this->assertSame('property', $elements[3]['type']);
  70. $this->assertSame('method', $elements[4]['type']);
  71. $this->assertSame('method', $elements[5]['type']);
  72. }
  73. public function testReadFromCacheAfterClearing()
  74. {
  75. $code = '<?php echo 1;';
  76. $tokens = Tokens::fromCode($code);
  77. $countBefore = $tokens->count();
  78. for ($i = 0; $i < $countBefore; ++$i) {
  79. $tokens[$i]->clear();
  80. }
  81. $tokens = Tokens::fromCode($code);
  82. $this->assertSame($countBefore, $tokens->count());
  83. }
  84. /**
  85. * @dataProvider provideIsLambdaCases
  86. */
  87. public function testIsLambda($source, array $expected)
  88. {
  89. $tokens = Tokens::fromCode($source);
  90. foreach ($expected as $index => $expectedValue) {
  91. $this->assertSame($expectedValue, $tokens->isLambda($index));
  92. }
  93. }
  94. public function provideIsLambdaCases()
  95. {
  96. return array(
  97. array(
  98. '<?php function foo () {}',
  99. array(1 => false),
  100. ),
  101. array(
  102. '<?php function /** foo */ foo () {}',
  103. array(1 => false),
  104. ),
  105. array(
  106. '<?php $foo = function () {}',
  107. array(5 => true),
  108. ),
  109. array(
  110. '<?php $foo = function /** foo */ () {}',
  111. array(5 => true),
  112. ),
  113. array(
  114. '<?php
  115. preg_replace_callback(
  116. "/(^|[a-z])/",
  117. function (array $matches) {
  118. return "a";
  119. },
  120. $string
  121. );',
  122. array(7 => true),
  123. ),
  124. array(
  125. '<?php $foo = function &() {}',
  126. array(5 => true),
  127. ),
  128. );
  129. }
  130. /**
  131. * @dataProvider provideIsShortArrayCases
  132. */
  133. public function testIsShortArray($source, array $expected)
  134. {
  135. $tokens = Tokens::fromCode($source);
  136. foreach ($expected as $index => $expectedValue) {
  137. $this->assertSame($expectedValue, $tokens->isShortArray($index));
  138. }
  139. }
  140. public function provideIsShortArrayCases()
  141. {
  142. return array(
  143. array(
  144. '<?php [];',
  145. array(1 => true),
  146. ),
  147. array(
  148. '<?php [1, "foo"];',
  149. array(1 => true),
  150. ),
  151. array(
  152. '<?php [[]];',
  153. array(1 => true, 2 => true),
  154. ),
  155. array(
  156. '<?php ["foo", ["bar", "baz"]];',
  157. array(1 => true, 5 => true),
  158. ),
  159. array(
  160. '<?php (array) [1, 2];',
  161. array(3 => true),
  162. ),
  163. array(
  164. '<?php [1,2][$x];',
  165. array(1 => true, 6 => false),
  166. ),
  167. array(
  168. '<?php array();',
  169. array(1 => false),
  170. ),
  171. array(
  172. '<?php $x[] = 1;',
  173. array(2 => false),
  174. ),
  175. array(
  176. '<?php $x[1];',
  177. array(2 => false),
  178. ),
  179. array(
  180. '<?php $x [ 1 ];',
  181. array(3 => false),
  182. ),
  183. array(
  184. '<?php ${"x"}[1];',
  185. array(5 => false),
  186. ),
  187. array(
  188. '<?php FOO[1];',
  189. array(2 => false),
  190. ),
  191. array(
  192. '<?php array("foo")[1];',
  193. array(5 => false),
  194. ),
  195. array(
  196. '<?php foo()[1];',
  197. array(4 => false),
  198. ),
  199. array(
  200. '<?php \'foo\'[1];',
  201. array(2 => false),
  202. ),
  203. array(
  204. '<?php "foo$bar"[1];',
  205. array(5 => false),
  206. ),
  207. );
  208. }
  209. /**
  210. * @dataProvider provideIsUnarySuccessorOperator
  211. */
  212. public function testIsUnarySuccessorOperator($source, array $expected)
  213. {
  214. $tokens = Tokens::fromCode($source);
  215. foreach ($expected as $index => $expectedValue) {
  216. $this->assertSame($expectedValue, $tokens->isUnarySuccessorOperator($index));
  217. if ($expectedValue) {
  218. $this->assertFalse($tokens->isUnaryPredecessorOperator($index));
  219. $this->assertFalse($tokens->isBinaryOperator($index));
  220. }
  221. }
  222. }
  223. public function provideIsUnarySuccessorOperator()
  224. {
  225. return array(
  226. array(
  227. '<?php $a++;',
  228. array(2 => true),
  229. ),
  230. array(
  231. '<?php $a--',
  232. array(2 => true),
  233. ),
  234. array(
  235. '<?php $a ++;',
  236. array(3 => true),
  237. ),
  238. array(
  239. '<?php $a++ + 1;',
  240. array(2 => true, 4 => false),
  241. ),
  242. array(
  243. '<?php ${"a"}++',
  244. array(5 => true),
  245. ),
  246. array(
  247. '<?php $foo->bar++',
  248. array(4 => true),
  249. ),
  250. array(
  251. '<?php $foo->{"bar"}++',
  252. array(6 => true),
  253. ),
  254. array(
  255. '<?php $a["foo"]++',
  256. array(5 => true),
  257. ),
  258. );
  259. }
  260. /**
  261. * @dataProvider provideIsUnaryPredecessorOperator
  262. */
  263. public function testIsUnaryPredecessorOperator($source, array $expected)
  264. {
  265. $tokens = Tokens::fromCode($source);
  266. foreach ($expected as $index => $expectedValue) {
  267. $this->assertSame($expectedValue, $tokens->isUnaryPredecessorOperator($index));
  268. if ($expectedValue) {
  269. $this->assertFalse($tokens->isUnarySuccessorOperator($index));
  270. $this->assertFalse($tokens->isBinaryOperator($index));
  271. }
  272. }
  273. }
  274. public function provideIsUnaryPredecessorOperator()
  275. {
  276. return array(
  277. array(
  278. '<?php ++$a;',
  279. array(1 => true),
  280. ),
  281. array(
  282. '<?php --$a',
  283. array(1 => true),
  284. ),
  285. array(
  286. '<?php -- $a;',
  287. array(1 => true),
  288. ),
  289. array(
  290. '<?php $a + ++$b;',
  291. array(3 => false, 5 => true),
  292. ),
  293. array(
  294. '<?php !!$a;',
  295. array(1 => true, 2 => true),
  296. ),
  297. array(
  298. '<?php $a = &$b;',
  299. array(5 => true),
  300. ),
  301. array(
  302. '<?php function &foo() {}',
  303. array(3 => true),
  304. ),
  305. array(
  306. '<?php @foo();',
  307. array(1 => true),
  308. ),
  309. array(
  310. '<?php foo(+ $a, -$b);',
  311. array(3 => true, 8 => true),
  312. ),
  313. array(
  314. '<?php function foo(&$a, array &$b, Bar &$c) {}',
  315. array(5 => true, 11 => true, 17 => true),
  316. ),
  317. );
  318. }
  319. /**
  320. * @dataProvider provideIsUnaryPredecessorOperator56
  321. * @requires PHP 5.6
  322. */
  323. public function testIsUnaryPredecessorOperator56($source, array $expected)
  324. {
  325. $tokens = Tokens::fromCode($source);
  326. foreach ($expected as $index => $expectedValue) {
  327. $this->assertSame($expectedValue, $tokens->isUnaryPredecessorOperator($index));
  328. if ($expectedValue) {
  329. $this->assertFalse($tokens->isUnarySuccessorOperator($index));
  330. $this->assertFalse($tokens->isBinaryOperator($index));
  331. }
  332. }
  333. }
  334. public function provideIsUnaryPredecessorOperator56()
  335. {
  336. return array(
  337. array(
  338. '<?php function foo($a, ...$b);',
  339. array(8 => true),
  340. ),
  341. array(
  342. '<?php function foo(&...$b);',
  343. array(5 => true, 6 => true),
  344. ),
  345. array(
  346. '<?php function foo(array ...$b);',
  347. array(7 => true),
  348. ),
  349. array(
  350. '<?php foo(...$a);',
  351. array(3 => true),
  352. ),
  353. array(
  354. '<?php foo($a, ...$b);',
  355. array(6 => true),
  356. ),
  357. );
  358. }
  359. /**
  360. * @dataProvider provideIsBinaryOperator
  361. */
  362. public function testIsBinaryOperator($source, array $expected)
  363. {
  364. $tokens = Tokens::fromCode($source);
  365. foreach ($expected as $index => $expectedValue) {
  366. $this->assertSame($expectedValue, $tokens->isBinaryOperator($index));
  367. if ($expectedValue) {
  368. $this->assertFalse($tokens->isUnarySuccessorOperator($index));
  369. $this->assertFalse($tokens->isUnaryPredecessorOperator($index));
  370. }
  371. }
  372. }
  373. public function provideIsBinaryOperator()
  374. {
  375. $cases = array(
  376. array(
  377. '<?php $a + $b;',
  378. array(3 => true),
  379. ),
  380. array(
  381. '<?php 1 + $b;',
  382. array(3 => true),
  383. ),
  384. array(
  385. '<?php 0.2 + $b;',
  386. array(3 => true),
  387. ),
  388. array(
  389. '<?php $a[1] + $b;',
  390. array(6 => true),
  391. ),
  392. array(
  393. '<?php FOO + $b;',
  394. array(3 => true),
  395. ),
  396. array(
  397. '<?php foo() + $b;',
  398. array(5 => true),
  399. ),
  400. array(
  401. '<?php ${"foo"} + $b;',
  402. array(6 => true),
  403. ),
  404. array(
  405. '<?php $a+$b;',
  406. array(2 => true),
  407. ),
  408. array(
  409. '<?php $a /* foo */ + /* bar */ $b;',
  410. array(5 => true),
  411. ),
  412. array(
  413. '<?php $a =
  414. $b;',
  415. array(3 => true),
  416. ),
  417. array(
  418. '<?php $a
  419. = $b;',
  420. array(3 => true),
  421. ),
  422. array(
  423. '<?php $a = array("b" => "c", );',
  424. array(3 => true, 9 => true, 12 => false),
  425. ),
  426. array(
  427. '<?php $a * -$b;',
  428. array(3 => true, 5 => false),
  429. ),
  430. array(
  431. '<?php $a = -2 / +5;',
  432. array(3 => true, 5 => false, 8 => true, 10 => false),
  433. ),
  434. array(
  435. '<?php $a = &$b;',
  436. array(3 => true, 5 => false),
  437. ),
  438. array(
  439. '<?php $a++ + $b;',
  440. array(2 => false, 4 => true),
  441. ),
  442. array(
  443. '<?php $a = FOO & $bar;',
  444. array(7 => true),
  445. ),
  446. array(
  447. '<?php __LINE__ - 1;',
  448. array(3 => true),
  449. ),
  450. array(
  451. '<?php `echo 1` + 1;',
  452. array(5 => true),
  453. ),
  454. );
  455. $operators = array(
  456. '+', '-', '*', '/', '%', '<', '>', '|', '^', '&=', '&&', '||', '.=', '/=', '==', '>=', '===', '!=',
  457. '<>', '!==', '<=', 'and', 'or', 'xor', '-=', '%=', '*=', '|=', '+=', '<<', '<<=', '>>', '>>=', '^',
  458. );
  459. foreach ($operators as $operator) {
  460. $cases[] = array(
  461. '<?php $a '.$operator.' $b;',
  462. array(3 => true),
  463. );
  464. }
  465. return $cases;
  466. }
  467. /**
  468. * @dataProvider provideIsBinaryOperator56
  469. * @requires PHP 5.6
  470. */
  471. public function testIsBinaryOperator56($source, array $expected)
  472. {
  473. $tokens = Tokens::fromCode($source);
  474. foreach ($expected as $index => $expectedValue) {
  475. $this->assertSame($expectedValue, $tokens->isBinaryOperator($index));
  476. if ($expectedValue) {
  477. $this->assertFalse($tokens->isUnarySuccessorOperator($index));
  478. $this->assertFalse($tokens->isUnaryPredecessorOperator($index));
  479. }
  480. }
  481. }
  482. public function provideIsBinaryOperator56()
  483. {
  484. return array(
  485. array(
  486. '<?php $a ** $b;',
  487. array(3 => true),
  488. ),
  489. array(
  490. '<?php $a **= $b;',
  491. array(3 => true),
  492. ),
  493. );
  494. }
  495. /**
  496. * @dataProvider provideIsBinaryOperator70
  497. * @requires PHP 7.0
  498. */
  499. public function testIsBinaryOperator70($source, array $expected)
  500. {
  501. $tokens = Tokens::fromCode($source);
  502. foreach ($expected as $index => $expectedValue) {
  503. $this->assertSame($expectedValue, $tokens->isBinaryOperator($index));
  504. if ($expectedValue) {
  505. $this->assertFalse($tokens->isUnarySuccessorOperator($index));
  506. $this->assertFalse($tokens->isUnaryPredecessorOperator($index));
  507. }
  508. }
  509. }
  510. public function provideIsBinaryOperator70()
  511. {
  512. return array(
  513. array(
  514. '<?php $a <=> $b;',
  515. array(3 => true),
  516. ),
  517. array(
  518. '<?php $a ?? $b;',
  519. array(3 => true),
  520. ),
  521. );
  522. }
  523. /**
  524. * @dataProvider provideFindSequence
  525. */
  526. public function testFindSequence($source, $expected, array $params)
  527. {
  528. $tokens = Tokens::fromCode($source);
  529. $this->assertEqualsTokensArray($expected, call_user_func_array(array($tokens, 'findSequence'), $params));
  530. }
  531. public function provideFindSequence()
  532. {
  533. return array(
  534. array(
  535. '<?php $x = 1;',
  536. null,
  537. array(array(
  538. array(T_OPEN_TAG),
  539. array(T_VARIABLE, '$y'),
  540. )),
  541. ),
  542. array(
  543. '<?php $x = 1;',
  544. array(
  545. 0 => new Token(array(T_OPEN_TAG, '<?php ', 1)),
  546. 1 => new Token(array(T_VARIABLE, '$x', 1)),
  547. ),
  548. array(array(
  549. array(T_OPEN_TAG),
  550. array(T_VARIABLE, '$x'),
  551. )),
  552. ),
  553. array(
  554. '<?php $x = 1;',
  555. array(
  556. 3 => new Token('='),
  557. 5 => new Token(array(T_LNUMBER, '1', 1)),
  558. 6 => new Token(';'),
  559. ),
  560. array(array(
  561. '=',
  562. array(T_LNUMBER, '1'),
  563. ';',
  564. )),
  565. ),
  566. array(
  567. '<?php $x = 1;',
  568. array(
  569. 0 => new Token(array(T_OPEN_TAG, '<?php ', 1)),
  570. 1 => new Token(array(T_VARIABLE, '$x', 1)),
  571. ),
  572. array(array(
  573. array(T_OPEN_TAG),
  574. array(T_VARIABLE, '$x'),
  575. ), 0),
  576. ),
  577. array(
  578. '<?php $x = 1;',
  579. null,
  580. array(array(
  581. array(T_OPEN_TAG),
  582. array(T_VARIABLE, '$x'),
  583. ), 1),
  584. ),
  585. array(
  586. '<?php $x = 1;',
  587. array(
  588. 3 => new Token('='),
  589. 5 => new Token(array(T_LNUMBER, '1', 1)),
  590. 6 => new Token(';'),
  591. ),
  592. array(array(
  593. '=',
  594. array(T_LNUMBER, '1'),
  595. ';',
  596. ), 3, 6),
  597. ),
  598. array(
  599. '<?php $x = 1;',
  600. null,
  601. array(array(
  602. '=',
  603. array(T_LNUMBER, '1'),
  604. ';',
  605. ), 4, 6),
  606. ),
  607. array(
  608. '<?php $x = 1;',
  609. null,
  610. array(array(
  611. '=',
  612. array(T_LNUMBER, '1'),
  613. ';',
  614. ), 3, 5),
  615. ),
  616. array(
  617. '<?php $x = 1;',
  618. array(
  619. 0 => new Token(array(T_OPEN_TAG, '<?php ', 1)),
  620. 1 => new Token(array(T_VARIABLE, '$x', 1)),
  621. ),
  622. array(array(
  623. array(T_OPEN_TAG),
  624. array(T_VARIABLE, '$x'),
  625. ), 0, 1, true),
  626. ),
  627. array(
  628. '<?php $x = 1;',
  629. null,
  630. array(array(
  631. array(T_OPEN_TAG),
  632. array(T_VARIABLE, '$X'),
  633. ), 0, 1, true),
  634. ),
  635. array(
  636. '<?php $x = 1;',
  637. null,
  638. array(array(
  639. array(T_OPEN_TAG),
  640. array(T_VARIABLE, '$X'),
  641. ), 0, 1, array(true, true)),
  642. ),
  643. array(
  644. '<?php $x = 1;',
  645. array(
  646. 0 => new Token(array(T_OPEN_TAG, '<?php ', 1)),
  647. 1 => new Token(array(T_VARIABLE, '$x', 1)),
  648. ),
  649. array(array(
  650. array(T_OPEN_TAG),
  651. array(T_VARIABLE, '$X'),
  652. ), 0, 1, false),
  653. ),
  654. array(
  655. '<?php $x = 1;',
  656. array(
  657. 0 => new Token(array(T_OPEN_TAG, '<?php ', 1)),
  658. 1 => new Token(array(T_VARIABLE, '$x', 1)),
  659. ),
  660. array(array(
  661. array(T_OPEN_TAG),
  662. array(T_VARIABLE, '$X'),
  663. ), 0, 1, array(true, false)),
  664. ),
  665. array(
  666. '<?php $x = 1;',
  667. array(
  668. 0 => new Token(array(T_OPEN_TAG, '<?php ', 1)),
  669. 1 => new Token(array(T_VARIABLE, '$x', 1)),
  670. ),
  671. array(array(
  672. array(T_OPEN_TAG),
  673. array(T_VARIABLE, '$X'),
  674. ), 0, 1, array(1 => false)),
  675. ),
  676. array(
  677. '<?php $x = 1;',
  678. null,
  679. array(array(
  680. array(T_OPEN_TAG),
  681. array(T_VARIABLE, '$X'),
  682. ), 0, 1, array(2 => false)),
  683. ),
  684. );
  685. }
  686. /**
  687. * @expectedException \InvalidArgumentException
  688. * @dataProvider provideFindSequenceExceptions
  689. */
  690. public function testFindSequenceException($message, $sequence)
  691. {
  692. $tokens = Tokens::fromCode('<?php $x = 1;');
  693. try {
  694. $tokens->findSequence($sequence);
  695. } catch (\InvalidArgumentException $e) {
  696. $this->assertSame($message, $e->getMessage());
  697. throw $e;
  698. }
  699. }
  700. public function provideFindSequenceExceptions()
  701. {
  702. $emptyToken = new Token('!');
  703. $emptyToken->clear();
  704. return array(
  705. array('Invalid sequence', array()),
  706. array('Non-meaningful token at position: 0', array(
  707. array(T_WHITESPACE, ' '),
  708. )),
  709. array('Non-meaningful token at position: 1', array(
  710. '{', array(T_COMMENT, '// Foo'), '}',
  711. )),
  712. array('Non-meaningful token at position: 2', array(
  713. '{', '!', $emptyToken, '}',
  714. )),
  715. );
  716. }
  717. public function testClearRange()
  718. {
  719. $source = <<<'PHP'
  720. <?php
  721. class FooBar
  722. {
  723. public function foo()
  724. {
  725. return 'bar';
  726. }
  727. public function bar()
  728. {
  729. return 'foo';
  730. }
  731. }
  732. PHP;
  733. $tokens = Tokens::fromCode($source);
  734. $publicIndexes = array_keys($tokens->findGivenKind(T_PUBLIC));
  735. $fooIndex = $publicIndexes[0];
  736. $barIndex = $publicIndexes[1];
  737. $tokens->clearRange($fooIndex, $barIndex - 1);
  738. $newPublicIndexes = array_keys($tokens->findGivenKind(T_PUBLIC));
  739. $this->assertSame($barIndex, reset($newPublicIndexes));
  740. for ($i = $fooIndex; $i < $barIndex; ++$i) {
  741. $this->assertTrue($tokens[$i]->isWhitespace());
  742. }
  743. }
  744. /**
  745. * @dataProvider provideMonolithicPhpDetection
  746. *
  747. * @param string $source
  748. * @param bool $monolitic
  749. */
  750. public function testMonolithicPhpDetection($source, $monolitic)
  751. {
  752. $tokens = Tokens::fromCode($source);
  753. $this->assertSame($monolitic, $tokens->isMonolithicPhp());
  754. }
  755. public function provideMonolithicPhpDetection()
  756. {
  757. return array(
  758. array("<?php\n", true),
  759. array("<?php\n?>", true),
  760. array('', false),
  761. array(' ', false),
  762. array("#!/usr/bin/env php\n<?php\n", false),
  763. array(" <?php\n", false),
  764. array("<?php\n?> ", false),
  765. array("<?php\n?><?php\n", false),
  766. );
  767. }
  768. /**
  769. * @dataProvider provideShortOpenTagMonolithicPhpDetection
  770. *
  771. * @param string $source
  772. * @param bool $monolitic
  773. */
  774. public function testShortOpenTagMonolithicPhpDetection($source, $monolitic)
  775. {
  776. /*
  777. * short_open_tag setting is ignored by HHVM
  778. * @see https://github.com/facebook/hhvm/issues/4758
  779. */
  780. if (!ini_get('short_open_tag') && !defined('HHVM_VERSION')) {
  781. // Short open tag is parsed as T_INLINE_HTML
  782. $monolitic = false;
  783. }
  784. $tokens = Tokens::fromCode($source);
  785. $this->assertSame($monolitic, $tokens->isMonolithicPhp());
  786. }
  787. public function provideShortOpenTagMonolithicPhpDetection()
  788. {
  789. return array(
  790. array("<?\n", true),
  791. array("<?\n?>", true),
  792. array(" <?\n", false),
  793. array("<?\n?> ", false),
  794. array("<?\n?><?\n", false),
  795. array("<?\n?><?php\n", false),
  796. array("<?\n?><?=' ';\n", false),
  797. array("<?php\n?><?\n", false),
  798. array("<?=' '\n?><?\n", false),
  799. );
  800. }
  801. /**
  802. * @dataProvider provideShortOpenTagEchoMonolithicPhpDetection
  803. *
  804. * @param string $source
  805. * @param bool $monolitic
  806. */
  807. public function testShortOpenTagEchoMonolithicPhpDetection($source, $monolitic)
  808. {
  809. /*
  810. * short_open_tag setting is ignored by HHVM
  811. * @see https://github.com/facebook/hhvm/issues/4758
  812. */
  813. if (!ini_get('short_open_tag') && 50400 > PHP_VERSION_ID && !defined('HHVM_VERSION')) {
  814. // Short open tag echo is parsed as T_INLINE_HTML
  815. $monolitic = false;
  816. }
  817. $tokens = Tokens::fromCode($source);
  818. $this->assertSame($monolitic, $tokens->isMonolithicPhp());
  819. }
  820. public function provideShortOpenTagEchoMonolithicPhpDetection()
  821. {
  822. return array(
  823. array("<?=' ';\n", true),
  824. array("<?=' '?>", true),
  825. array(" <?=' ';\n", false),
  826. array("<?=' '?> ", false),
  827. array("<?php\n?><?=' ';\n", false),
  828. array("<?=' '\n?><?php\n", false),
  829. array("<?=' '\n?><?=' ';\n", false),
  830. );
  831. }
  832. /**
  833. * @dataProvider provideIsArray
  834. * @requires PHP 5.4
  835. */
  836. public function testIsArray($source, $tokenIndex, $isMultilineArray = false, $isShortArray = false)
  837. {
  838. $tokens = Tokens::fromCode($source);
  839. $this->assertTrue($tokens->isArray($tokenIndex), 'Expected to be an array.');
  840. $this->assertSame($isMultilineArray, $tokens->isArrayMultiLine($tokenIndex), sprintf('Expected %sto be a multiline array', $isMultilineArray ? '' : 'not '));
  841. $this->assertSame($isShortArray, $tokens->isShortArray($tokenIndex), sprintf('Expected %sto be a short array', $isShortArray ? '' : 'not '));
  842. }
  843. public function provideIsArray()
  844. {
  845. $cases = array(
  846. array(
  847. '<?php
  848. array("a" => 1);
  849. ',
  850. 2,
  851. ),
  852. array(
  853. // short array PHP 5.4 single line
  854. '<?php
  855. ["a" => 2];
  856. ',
  857. 2, false, true,
  858. ),
  859. array(
  860. '<?php
  861. array(
  862. "a" => 3
  863. );
  864. ',
  865. 2, true,
  866. ),
  867. array(
  868. // short array PHP 5.4 multi line
  869. '<?php
  870. [
  871. "a" => 4
  872. ];
  873. ',
  874. 2, true, true,
  875. ),
  876. array(
  877. '<?php
  878. array(
  879. "a" => array(5, 6, 7),
  880. 8 => new \Exception(\'Ellow\')
  881. );
  882. ',
  883. 2, true,
  884. ),
  885. array(
  886. // mix short array syntax
  887. '<?php
  888. array(
  889. "a" => [9, 10, 11],
  890. 12 => new \Exception(\'Ellow\')
  891. );
  892. ',
  893. 2, true,
  894. ),
  895. // Windows/Max EOL testing
  896. array(
  897. "<?php\r\narray('a' => 13);\r\n",
  898. 1,
  899. ),
  900. array(
  901. "<?php\r\n array(\r\n 'a' => 14,\r\n 'b' => 15\r\n );\r\n",
  902. 2, true,
  903. ),
  904. );
  905. return $cases;
  906. }
  907. /**
  908. * @dataProvider provideArrayExceptions
  909. */
  910. public function testIsNotArray($source, $tokenIndex)
  911. {
  912. $tokens = Tokens::fromCode($source);
  913. $this->assertFalse($tokens->isArray($tokenIndex));
  914. }
  915. /**
  916. * @dataProvider provideArrayExceptions
  917. */
  918. public function testIsNotShortArray($source, $tokenIndex)
  919. {
  920. $tokens = Tokens::fromCode($source);
  921. $this->assertFalse($tokens->isShortArray($tokenIndex));
  922. }
  923. /**
  924. * @expectedException \InvalidArgumentException
  925. * @dataProvider provideArrayExceptions
  926. */
  927. public function testIsMultiLineArrayException($source, $tokenIndex)
  928. {
  929. $tokens = Tokens::fromCode($source);
  930. $tokens->isArrayMultiLine($tokenIndex);
  931. }
  932. public function provideArrayExceptions()
  933. {
  934. $cases = array(
  935. array('<?php $a;', 1),
  936. array("<?php\n \$a = (0+1); // [0,1]", 4),
  937. array('<?php $text = "foo $bbb[0] bar";', 8),
  938. array('<?php $text = "foo ${aaa[123]} bar";', 9),
  939. );
  940. return $cases;
  941. }
  942. }