PageRenderTime 52ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

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

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