subNode1 = $subNode1; $this->subNode2 = $subNode2; } public function getSubNodeNames() : array { return ['subNode1', 'subNode2']; } // This method is only overwritten because the node is located in an unusual namespace public function getType() : string { return 'Dummy'; } } class NodeAbstractTest extends \PHPUnit\Framework\TestCase { public function provideNodes() { $attributes = [ 'startLine' => 10, 'endLine' => 11, 'startTokenPos' => 12, 'endTokenPos' => 13, 'startFilePos' => 14, 'endFilePos' => 15, 'comments' => [ new Comment('// Comment 1' . "\n"), new Comment\Doc('/** doc comment */'), new Comment('// Comment 2' . "\n"), ], ]; $node = new DummyNode('value1', 'value2', $attributes); $node->notSubNode = 'value3'; return [ [$attributes, $node], ]; } /** * @dataProvider provideNodes */ public function testConstruct(array $attributes, Node $node) { $this->assertSame('Dummy', $node->getType()); $this->assertSame(['subNode1', 'subNode2'], $node->getSubNodeNames()); $this->assertSame(10, $node->getLine()); $this->assertSame(10, $node->getStartLine()); $this->assertSame(11, $node->getEndLine()); $this->assertSame(12, $node->getStartTokenPos()); $this->assertSame(13, $node->getEndTokenPos()); $this->assertSame(14, $node->getStartFilePos()); $this->assertSame(15, $node->getEndFilePos()); $this->assertSame('/** doc comment */', $node->getDocComment()->getText()); $this->assertSame('value1', $node->subNode1); $this->assertSame('value2', $node->subNode2); $this->assertObjectHasAttribute('subNode1', $node); $this->assertObjectHasAttribute('subNode2', $node); $this->assertObjectNotHasAttribute('subNode3', $node); $this->assertSame($attributes, $node->getAttributes()); $this->assertSame($attributes['comments'], $node->getComments()); return $node; } /** * @dataProvider provideNodes */ public function testGetDocComment(array $attributes, Node $node) { $this->assertSame('/** doc comment */', $node->getDocComment()->getText()); $comments = $node->getComments(); array_splice($comments, 1, 1, []); // remove doc comment $node->setAttribute('comments', $comments); $this->assertNull($node->getDocComment()); // Remove all comments. $node->setAttribute('comments', []); $this->assertNull($node->getDocComment()); } public function testSetDocComment() { $node = new DummyNode(null, null, []); // Add doc comment to node without comments $docComment = new Comment\Doc('/** doc */'); $node->setDocComment($docComment); $this->assertSame($docComment, $node->getDocComment()); // Replace it $docComment = new Comment\Doc('/** doc 2 */'); $node->setDocComment($docComment); $this->assertSame($docComment, $node->getDocComment()); // Add docmment to node with other comments $c1 = new Comment('/* foo */'); $c2 = new Comment('/* bar */'); $docComment = new Comment\Doc('/** baz */'); $node->setAttribute('comments', [$c1, $c2]); $node->setDocComment($docComment); $this->assertSame([$c1, $c2, $docComment], $node->getAttribute('comments')); // Replace doc comment that is not at the end. $newDocComment = new Comment\Doc('/** new baz */'); $node->setAttribute('comments', [$c1, $docComment, $c2]); $node->setDocComment($newDocComment); $this->assertSame([$c1, $newDocComment, $c2], $node->getAttribute('comments')); } /** * @dataProvider provideNodes */ public function testChange(array $attributes, Node $node) { // direct modification $node->subNode = 'newValue'; $this->assertSame('newValue', $node->subNode); // indirect modification $subNode =& $node->subNode; $subNode = 'newNewValue'; $this->assertSame('newNewValue', $node->subNode); // removal unset($node->subNode); $this->assertObjectNotHasAttribute('subNode', $node); } /** * @dataProvider provideNodes */ public function testIteration(array $attributes, Node $node) { // Iteration is simple object iteration over properties, // not over subnodes $i = 0; foreach ($node as $key => $value) { if ($i === 0) { $this->assertSame('subNode1', $key); $this->assertSame('value1', $value); } elseif ($i === 1) { $this->assertSame('subNode2', $key); $this->assertSame('value2', $value); } elseif ($i === 2) { $this->assertSame('notSubNode', $key); $this->assertSame('value3', $value); } else { throw new \Exception; } $i++; } $this->assertSame(3, $i); } public function testAttributes() { /** @var $node Node */ $node = $this->getMockForAbstractClass(NodeAbstract::class); $this->assertEmpty($node->getAttributes()); $node->setAttribute('key', 'value'); $this->assertTrue($node->hasAttribute('key')); $this->assertSame('value', $node->getAttribute('key')); $this->assertFalse($node->hasAttribute('doesNotExist')); $this->assertNull($node->getAttribute('doesNotExist')); $this->assertSame('default', $node->getAttribute('doesNotExist', 'default')); $node->setAttribute('null', null); $this->assertTrue($node->hasAttribute('null')); $this->assertNull($node->getAttribute('null')); $this->assertNull($node->getAttribute('null', 'default')); $this->assertSame( [ 'key' => 'value', 'null' => null, ], $node->getAttributes() ); $node->setAttributes( [ 'a' => 'b', 'c' => null, ] ); $this->assertSame( [ 'a' => 'b', 'c' => null, ], $node->getAttributes() ); } public function testJsonSerialization() { $code = <<<'PHP' parse(canonicalize($code)); $json = json_encode($stmts, JSON_PRETTY_PRINT); $this->assertEquals(canonicalize($expected), canonicalize($json)); } }