annotate vendor/nikic/php-parser/test/PhpParser/CodeParsingTest.php @ 13:5fb285c0d0e3

Update Drupal core to 8.4.7 via Composer. Security update; I *think* we've been lucky to get away with this so far, as we don't support self-registration which seems to be used by the so-called "drupalgeddon 2" attack that 8.4.5 was vulnerable to.
author Chris Cannam
date Mon, 23 Apr 2018 09:33:26 +0100
parents 4c8ae668cc8c
children 129ea1e6d783
rev   line source
Chris@13 1 <?php declare(strict_types=1);
Chris@0 2
Chris@0 3 namespace PhpParser;
Chris@0 4
Chris@13 5 use PhpParser\Node\Expr;
Chris@13 6 use PhpParser\Node\Stmt;
Chris@13 7
Chris@0 8 require_once __DIR__ . '/CodeTestAbstract.php';
Chris@0 9
Chris@0 10 class CodeParsingTest extends CodeTestAbstract
Chris@0 11 {
Chris@0 12 /**
Chris@0 13 * @dataProvider provideTestParse
Chris@0 14 */
Chris@0 15 public function testParse($name, $code, $expected, $modeLine) {
Chris@0 16 if (null !== $modeLine) {
Chris@0 17 $modes = array_fill_keys(explode(',', $modeLine), true);
Chris@0 18 } else {
Chris@0 19 $modes = [];
Chris@0 20 }
Chris@0 21
Chris@13 22 list($parser5, $parser7) = $this->createParsers($modes);
Chris@13 23 list($stmts5, $output5) = $this->getParseOutput($parser5, $code, $modes);
Chris@13 24 list($stmts7, $output7) = $this->getParseOutput($parser7, $code, $modes);
Chris@0 25
Chris@0 26 if (isset($modes['php5'])) {
Chris@0 27 $this->assertSame($expected, $output5, $name);
Chris@0 28 $this->assertNotSame($expected, $output7, $name);
Chris@13 29 } elseif (isset($modes['php7'])) {
Chris@0 30 $this->assertNotSame($expected, $output5, $name);
Chris@0 31 $this->assertSame($expected, $output7, $name);
Chris@0 32 } else {
Chris@0 33 $this->assertSame($expected, $output5, $name);
Chris@0 34 $this->assertSame($expected, $output7, $name);
Chris@0 35 }
Chris@13 36
Chris@13 37 $this->checkAttributes($stmts5);
Chris@13 38 $this->checkAttributes($stmts7);
Chris@0 39 }
Chris@0 40
Chris@13 41 public function createParsers(array $modes) {
Chris@13 42 $lexer = new Lexer\Emulative(['usedAttributes' => [
Chris@13 43 'startLine', 'endLine',
Chris@13 44 'startFilePos', 'endFilePos',
Chris@13 45 'startTokenPos', 'endTokenPos',
Chris@13 46 'comments'
Chris@13 47 ]]);
Chris@13 48
Chris@13 49 return [
Chris@13 50 new Parser\Php5($lexer),
Chris@13 51 new Parser\Php7($lexer),
Chris@13 52 ];
Chris@13 53 }
Chris@13 54
Chris@13 55 private function getParseOutput(Parser $parser, $code, array $modes) {
Chris@13 56 $dumpPositions = isset($modes['positions']);
Chris@13 57
Chris@0 58 $errors = new ErrorHandler\Collecting;
Chris@0 59 $stmts = $parser->parse($code, $errors);
Chris@0 60
Chris@0 61 $output = '';
Chris@0 62 foreach ($errors->getErrors() as $error) {
Chris@0 63 $output .= $this->formatErrorMessage($error, $code) . "\n";
Chris@0 64 }
Chris@0 65
Chris@0 66 if (null !== $stmts) {
Chris@0 67 $dumper = new NodeDumper(['dumpComments' => true, 'dumpPositions' => $dumpPositions]);
Chris@0 68 $output .= $dumper->dump($stmts, $code);
Chris@0 69 }
Chris@0 70
Chris@13 71 return [$stmts, canonicalize($output)];
Chris@0 72 }
Chris@0 73
Chris@0 74 public function provideTestParse() {
Chris@0 75 return $this->getTests(__DIR__ . '/../code/parser', 'test');
Chris@0 76 }
Chris@0 77
Chris@0 78 private function formatErrorMessage(Error $e, $code) {
Chris@0 79 if ($e->hasColumnInfo()) {
Chris@0 80 return $e->getMessageWithColumnInfo($code);
Chris@0 81 } else {
Chris@0 82 return $e->getMessage();
Chris@0 83 }
Chris@0 84 }
Chris@13 85
Chris@13 86 private function checkAttributes($stmts) {
Chris@13 87 if ($stmts === null) {
Chris@13 88 return;
Chris@13 89 }
Chris@13 90
Chris@13 91 $traverser = new NodeTraverser();
Chris@13 92 $traverser->addVisitor(new class extends NodeVisitorAbstract {
Chris@13 93 public function enterNode(Node $node) {
Chris@13 94 $startLine = $node->getStartLine();
Chris@13 95 $endLine = $node->getEndLine();
Chris@13 96 $startFilePos = $node->getStartFilePos();
Chris@13 97 $endFilePos = $node->getEndFilePos();
Chris@13 98 $startTokenPos = $node->getStartTokenPos();
Chris@13 99 $endTokenPos = $node->getEndTokenPos();
Chris@13 100 if ($startLine < 0 || $endLine < 0 ||
Chris@13 101 $startFilePos < 0 || $endFilePos < 0 ||
Chris@13 102 $startTokenPos < 0 || $endTokenPos < 0
Chris@13 103 ) {
Chris@13 104 throw new \Exception('Missing location information on ' . $node->getType());
Chris@13 105 }
Chris@13 106
Chris@13 107 if ($endLine < $startLine ||
Chris@13 108 $endFilePos < $startFilePos ||
Chris@13 109 $endTokenPos < $startTokenPos
Chris@13 110 ) {
Chris@13 111 // Nops and error can have inverted order, if they are empty
Chris@13 112 if (!$node instanceof Stmt\Nop && !$node instanceof Expr\Error) {
Chris@13 113 throw new \Exception('End < start on ' . $node->getType());
Chris@13 114 }
Chris@13 115 }
Chris@13 116 }
Chris@13 117 });
Chris@13 118 $traverser->traverse($stmts);
Chris@13 119 }
Chris@0 120 }