2016-10-06 11:01:41 +03:00
|
|
|
<?php
|
|
|
|
// TODO autoload classes
|
|
|
|
require_once(__DIR__ . "/../lexer.php");
|
|
|
|
require_once(__DIR__ . "/../parser.php");
|
|
|
|
require_once(__DIR__ . "/../Token.php");
|
2016-10-06 21:08:12 +03:00
|
|
|
require_once(__DIR__ . "/LexerInvariantsTest.php");
|
2016-10-06 11:01:41 +03:00
|
|
|
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
use PhpParser\TokenKind;
|
|
|
|
use PhpParser\Node;
|
|
|
|
|
|
|
|
class ParserInvariantsTest extends LexerInvariantsTest {
|
|
|
|
const FILENAMES = array (
|
2016-10-09 00:01:54 +03:00
|
|
|
__dir__ . "/cases/parserPocFile.php",
|
|
|
|
__dir__ . "/cases/parserPocFile2.php"
|
2016-10-06 11:01:41 +03:00
|
|
|
);
|
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
public static function sourceFileNodeProvider() {
|
|
|
|
$testFiles = array();
|
|
|
|
$parser = new \PhpParser\Parser();
|
|
|
|
foreach (self::FILENAMES as $filename) {
|
|
|
|
$testFiles[basename($filename)] = [$filename, $parser->parseSourceFile($filename)];
|
|
|
|
}
|
|
|
|
return $testFiles;
|
|
|
|
}
|
2016-10-06 11:01:41 +03:00
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
public static function tokensArrayProvider() {
|
|
|
|
$testFiles = array();
|
|
|
|
$parser = new \PhpParser\Parser();
|
2016-10-06 11:01:41 +03:00
|
|
|
foreach (self::FILENAMES as $filename) {
|
2016-10-10 02:21:14 +03:00
|
|
|
$sourceFileNode = $parser->parseSourceFile($filename);
|
2016-10-06 11:01:41 +03:00
|
|
|
$tokensArray = array();
|
|
|
|
foreach ($sourceFileNode->getAllChildren() as $child) {
|
|
|
|
if ($child instanceof \PhpParser\Token) {
|
|
|
|
array_push($tokensArray, $child);
|
|
|
|
}
|
|
|
|
}
|
2016-10-10 02:21:14 +03:00
|
|
|
$testFiles[basename($filename)] = [$filename, $tokensArray];
|
2016-10-06 11:01:41 +03:00
|
|
|
}
|
2016-10-10 02:21:14 +03:00
|
|
|
return $testFiles;
|
2016-10-06 11:01:41 +03:00
|
|
|
}
|
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
/**
|
|
|
|
* @dataProvider sourceFileNodeProvider
|
|
|
|
*/
|
|
|
|
public function testSourceFileNodeLengthEqualsDocumentLength($filename, $sourceFileNode) {
|
|
|
|
$this->assertEquals(
|
|
|
|
filesize($filename), $sourceFileNode->getLength(),
|
|
|
|
"Invariant: The tree length exactly matches the file length.");
|
2016-10-06 11:01:41 +03:00
|
|
|
}
|
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
/**
|
|
|
|
* @dataProvider sourceFileNodeProvider
|
|
|
|
*/
|
|
|
|
public function testNodesAllHaveAtLeastOneChild($filename, $sourceFileNode) {
|
|
|
|
|
|
|
|
foreach ($sourceFileNode->getAllChildren() as $child) {
|
|
|
|
if ($child instanceof Node) {
|
|
|
|
$this->assertGreaterThanOrEqual(
|
|
|
|
1, count($child->children),
|
|
|
|
"Invariant: All Nodes have at least one child."
|
|
|
|
);
|
2016-10-06 11:01:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
/**
|
|
|
|
* @dataProvider sourceFileNodeProvider
|
|
|
|
*/
|
|
|
|
public function testEveryNodeSpanIsSumOfChildSpans($filename, $sourceFileNode) {
|
|
|
|
$treeElements = $sourceFileNode->getAllChildren();
|
|
|
|
array_push($treeElements, $sourceFileNode);
|
|
|
|
|
|
|
|
foreach ($treeElements as $element) {
|
|
|
|
if ($element instanceof Node) {
|
|
|
|
$expectedLength = 0;
|
|
|
|
foreach ($element->children as $child) {
|
|
|
|
if ($child instanceof Node) {
|
|
|
|
$expectedLength += $child->getLength();
|
|
|
|
} else if ($child instanceof \PhpParser\Token) {
|
|
|
|
$expectedLength += $child->length;
|
2016-10-06 11:01:41 +03:00
|
|
|
}
|
|
|
|
}
|
2016-10-10 02:21:14 +03:00
|
|
|
$this->assertEquals(
|
|
|
|
$expectedLength, $element->getLength(),
|
|
|
|
"Invariant: Span of any Node is span of child nodes and tokens."
|
|
|
|
);
|
2016-10-06 11:01:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-10-06 21:08:12 +03:00
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
/**
|
|
|
|
* @dataProvider sourceFileNodeProvider
|
|
|
|
*/
|
|
|
|
public function testParentOfNodeHasSameChildNode($filename, $sourceFileNode) {
|
|
|
|
foreach ($sourceFileNode->getAllChildren() as $child) {
|
|
|
|
if ($child instanceof Node) {
|
|
|
|
$this->assertContains(
|
|
|
|
$child, $child->parent->children,
|
|
|
|
"Invariant: Parent of Node contains same child node."
|
|
|
|
);
|
2016-10-06 21:08:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
/**
|
|
|
|
* @dataProvider sourceFileNodeProvider
|
|
|
|
*/
|
|
|
|
public function testEachChildHasExactlyOneParent($filename, $sourceFileNode) {
|
2016-10-06 21:08:12 +03:00
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
$treeElements = $sourceFileNode->getAllChildren();
|
|
|
|
array_push($treeElements, $sourceFileNode);
|
2016-10-06 21:08:12 +03:00
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
foreach ($sourceFileNode->getAllChildren() as $child) {
|
|
|
|
$count = 0;
|
|
|
|
foreach ($treeElements as $element) {
|
|
|
|
if ($element instanceof Node) {
|
|
|
|
if (in_array($child, $element->children, true)) {
|
|
|
|
$count++;
|
2016-10-06 21:08:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$this->assertEquals(
|
2016-10-10 02:21:14 +03:00
|
|
|
1, $count,
|
|
|
|
"Invariant: each child has exactly one parent.");
|
2016-10-06 21:08:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
/**
|
|
|
|
* @dataProvider sourceFileNodeProvider
|
|
|
|
*/
|
|
|
|
public function testRootNodeHasNoParent($filename, $sourceFileNode) {
|
|
|
|
$this->assertEquals(
|
|
|
|
null, $sourceFileNode->parent,
|
|
|
|
"Invariant: Root node of tree has no parent.");
|
|
|
|
}
|
2016-10-06 21:08:12 +03:00
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
/**
|
|
|
|
* @dataProvider sourceFileNodeProvider
|
|
|
|
*/
|
|
|
|
public function testRootNodeIsNeverAChild($filename, $sourceFileNode) {
|
|
|
|
$treeElements = $sourceFileNode->getAllChildren();
|
|
|
|
array_push($treeElements, $sourceFileNode);
|
|
|
|
|
|
|
|
foreach($treeElements as $element) {
|
|
|
|
if ($element instanceof Node) {
|
|
|
|
$this->assertNotContains(
|
|
|
|
$sourceFileNode, $element->children,
|
|
|
|
"Invariant: root node of tree is never a child.");
|
2016-10-06 21:08:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-10-09 09:25:29 +03:00
|
|
|
|
2016-10-10 02:21:14 +03:00
|
|
|
/**
|
|
|
|
* @dataProvider sourceFileNodeProvider
|
|
|
|
*/
|
|
|
|
public function testEveryNodeHasAKind($filename, $sourceFileNode) {
|
|
|
|
$treeElements = $sourceFileNode->getAllChildren();
|
|
|
|
array_push($treeElements, $sourceFileNode);
|
|
|
|
|
|
|
|
foreach($treeElements as $element) {
|
|
|
|
if ($element instanceof Node) {
|
|
|
|
$this->assertNotNull(
|
|
|
|
$element->kind,
|
|
|
|
"Invariant: Every Node has a Kind");
|
2016-10-09 09:25:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-10-06 11:01:41 +03:00
|
|
|
}
|