Laravel version update

Laravel version update
This commit is contained in:
Manish Verma
2018-08-06 18:48:58 +05:30
parent d143048413
commit 126fbb0255
13678 changed files with 1031482 additions and 778530 deletions

View File

@@ -1,18 +0,0 @@
<?php
namespace PhpParser;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar;
/* The autoloader is already active at this point, so we only check effects here. */
class AutoloaderTest extends \PHPUnit_Framework_TestCase {
public function testClassExists() {
$this->assertTrue(class_exists('PhpParser\NodeVisitorAbstract'));
$this->assertFalse(class_exists('PHPParser_NodeVisitor_NameResolver'));
$this->assertFalse(class_exists('PhpParser\FooBar'));
$this->assertFalse(class_exists('PHPParser_FooBar'));
}
}

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Builder;
@@ -6,8 +6,9 @@ use PhpParser\Comment;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
use PHPUnit\Framework\TestCase;
class ClassTest extends \PHPUnit_Framework_TestCase
class ClassTest extends TestCase
{
protected function createClassBuilder($class) {
return new Class_($class);
@@ -22,15 +23,15 @@ class ClassTest extends \PHPUnit_Framework_TestCase
;
$this->assertEquals(
new Stmt\Class_('SomeLogger', array(
new Stmt\Class_('SomeLogger', [
'extends' => new Name('BaseLogger'),
'implements' => array(
'implements' => [
new Name('Namespaced\Logger'),
new Name('SomeInterface'),
new Name\FullyQualified('Fully\Qualified'),
new Name\Relative('NamespaceRelative'),
),
)),
],
]),
$node
);
}
@@ -42,9 +43,9 @@ class ClassTest extends \PHPUnit_Framework_TestCase
;
$this->assertEquals(
new Stmt\Class_('Test', array(
'type' => Stmt\Class_::MODIFIER_ABSTRACT
)),
new Stmt\Class_('Test', [
'flags' => Stmt\Class_::MODIFIER_ABSTRACT
]),
$node
);
}
@@ -56,9 +57,9 @@ class ClassTest extends \PHPUnit_Framework_TestCase
;
$this->assertEquals(
new Stmt\Class_('Test', array(
'type' => Stmt\Class_::MODIFIER_FINAL
)),
new Stmt\Class_('Test', [
'flags' => Stmt\Class_::MODIFIER_FINAL
]),
$node
);
}
@@ -67,24 +68,24 @@ class ClassTest extends \PHPUnit_Framework_TestCase
$method = new Stmt\ClassMethod('testMethod');
$property = new Stmt\Property(
Stmt\Class_::MODIFIER_PUBLIC,
array(new Stmt\PropertyProperty('testProperty'))
[new Stmt\PropertyProperty('testProperty')]
);
$const = new Stmt\ClassConst(array(
$const = new Stmt\ClassConst([
new Node\Const_('TEST_CONST', new Node\Scalar\String_('ABC'))
));
$use = new Stmt\TraitUse(array(new Name('SomeTrait')));
]);
$use = new Stmt\TraitUse([new Name('SomeTrait')]);
$node = $this->createClassBuilder('Test')
->addStmt($method)
->addStmt($property)
->addStmts(array($const, $use))
->addStmts([$const, $use])
->getNode()
;
$this->assertEquals(
new Stmt\Class_('Test', array(
'stmts' => array($use, $const, $property, $method)
)),
new Stmt\Class_('Test', [
'stmts' => [$use, $const, $property, $method]
]),
$node
);
}
@@ -100,11 +101,11 @@ DOC;
->getNode();
$this->assertEquals(
new Stmt\Class_('Test', array(), array(
'comments' => array(
new Stmt\Class_('Test', [], [
'comments' => [
new Comment\Doc($docComment)
)
)),
]
]),
$class
);
@@ -113,11 +114,11 @@ DOC;
->getNode();
$this->assertEquals(
new Stmt\Class_('Test', array(), array(
'comments' => array(
new Stmt\Class_('Test', [], [
'comments' => [
new Comment\Doc($docComment)
)
)),
]
]),
$class
);
}
@@ -128,7 +129,7 @@ DOC;
*/
public function testInvalidStmtError() {
$this->createClassBuilder('Test')
->addStmt(new Stmt\Echo_(array()))
->addStmt(new Stmt\Echo_([]))
;
}
@@ -152,10 +153,10 @@ DOC;
/**
* @expectedException \LogicException
* @expectedExceptionMessage Name must be a string or an instance of PhpParser\Node\Name
* @expectedExceptionMessage Name must be a string or an instance of Node\Name
*/
public function testInvalidName() {
$this->createClassBuilder('Test')
->extend(array('Foo'));
->extend(['Foo']);
}
}

View File

@@ -1,14 +1,16 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Builder;
use PhpParser\Comment;
use PhpParser\Node;
use PhpParser\Node\Stmt;
use PhpParser\Node\Expr\Print_;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt;
use PHPUnit\Framework\TestCase;
class FunctionTest extends \PHPUnit_Framework_TestCase
class FunctionTest extends TestCase
{
public function createFunctionBuilder($name) {
return new Function_($name);
@@ -21,28 +23,28 @@ class FunctionTest extends \PHPUnit_Framework_TestCase
;
$this->assertEquals(
new Stmt\Function_('test', array(
new Stmt\Function_('test', [
'byRef' => true
)),
]),
$node
);
}
public function testParams() {
$param1 = new Node\Param('test1');
$param2 = new Node\Param('test2');
$param3 = new Node\Param('test3');
$param1 = new Node\Param(new Variable('test1'));
$param2 = new Node\Param(new Variable('test2'));
$param3 = new Node\Param(new Variable('test3'));
$node = $this->createFunctionBuilder('test')
->addParam($param1)
->addParams(array($param2, $param3))
->addParams([$param2, $param3])
->getNode()
;
$this->assertEquals(
new Stmt\Function_('test', array(
'params' => array($param1, $param2, $param3)
)),
new Stmt\Function_('test', [
'params' => [$param1, $param2, $param3]
]),
$node
);
}
@@ -54,14 +56,18 @@ class FunctionTest extends \PHPUnit_Framework_TestCase
$node = $this->createFunctionBuilder('test')
->addStmt($stmt1)
->addStmts(array($stmt2, $stmt3))
->addStmts([$stmt2, $stmt3])
->getNode()
;
$this->assertEquals(
new Stmt\Function_('test', array(
'stmts' => array($stmt1, $stmt2, $stmt3)
)),
new Stmt\Function_('test', [
'stmts' => [
new Stmt\Expression($stmt1),
new Stmt\Expression($stmt2),
new Stmt\Expression($stmt3),
]
]),
$node
);
}
@@ -71,19 +77,27 @@ class FunctionTest extends \PHPUnit_Framework_TestCase
->setDocComment('/** Test */')
->getNode();
$this->assertEquals(new Stmt\Function_('test', array(), array(
'comments' => array(new Comment\Doc('/** Test */'))
)), $node);
$this->assertEquals(new Stmt\Function_('test', [], [
'comments' => [new Comment\Doc('/** Test */')]
]), $node);
}
public function testReturnType() {
$node = $this->createFunctionBuilder('test')
->setReturnType('bool')
->setReturnType('void')
->getNode();
$this->assertEquals(new Stmt\Function_('test', array(
'returnType' => 'bool'
), array()), $node);
$this->assertEquals(new Stmt\Function_('test', [
'returnType' => 'void'
], []), $node);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage void type cannot be nullable
*/
public function testInvalidNullableVoidType() {
$this->createFunctionBuilder('test')->setReturnType('?void');
}
/**
@@ -95,4 +109,13 @@ class FunctionTest extends \PHPUnit_Framework_TestCase
->addParam(new Node\Name('foo'))
;
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Expected statement or expression node
*/
public function testAddNonStmt() {
$this->createFunctionBuilder('test')
->addStmt(new Node\Name('Test'));
}
}

View File

@@ -1,13 +1,14 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Builder;
use PhpParser\Node;
use PhpParser\Node\Stmt;
use PhpParser\Node\Scalar\DNumber;
use PhpParser\Comment;
use PhpParser\Node;
use PhpParser\Node\Scalar\DNumber;
use PhpParser\Node\Stmt;
use PHPUnit\Framework\TestCase;
class InterfaceTest extends \PHPUnit_Framework_TestCase
class InterfaceTest extends TestCase
{
/** @var Interface_ */
protected $builder;
@@ -18,45 +19,45 @@ class InterfaceTest extends \PHPUnit_Framework_TestCase
private function dump($node) {
$pp = new \PhpParser\PrettyPrinter\Standard;
return $pp->prettyPrint(array($node));
return $pp->prettyPrint([$node]);
}
public function testEmpty() {
$contract = $this->builder->getNode();
$this->assertInstanceOf('PhpParser\Node\Stmt\Interface_', $contract);
$this->assertSame('Contract', $contract->name);
$this->assertInstanceOf(Stmt\Interface_::class, $contract);
$this->assertEquals(new Node\Identifier('Contract'), $contract->name);
}
public function testExtending() {
$contract = $this->builder->extend('Space\Root1', 'Root2')->getNode();
$this->assertEquals(
new Stmt\Interface_('Contract', array(
'extends' => array(
new Stmt\Interface_('Contract', [
'extends' => [
new Node\Name('Space\Root1'),
new Node\Name('Root2')
),
)), $contract
],
]), $contract
);
}
public function testAddMethod() {
$method = new Stmt\ClassMethod('doSomething');
$contract = $this->builder->addStmt($method)->getNode();
$this->assertSame(array($method), $contract->stmts);
$this->assertSame([$method], $contract->stmts);
}
public function testAddConst() {
$const = new Stmt\ClassConst(array(
$const = new Stmt\ClassConst([
new Node\Const_('SPEED_OF_LIGHT', new DNumber(299792458.0))
));
]);
$contract = $this->builder->addStmt($const)->getNode();
$this->assertSame(299792458.0, $contract->stmts[0]->consts[0]->value->value);
}
public function testOrder() {
$const = new Stmt\ClassConst(array(
$const = new Stmt\ClassConst([
new Node\Const_('SPEED_OF_LIGHT', new DNumber(299792458))
));
]);
$method = new Stmt\ClassMethod('doSomething');
$contract = $this->builder
->addStmt($method)
@@ -64,8 +65,8 @@ class InterfaceTest extends \PHPUnit_Framework_TestCase
->getNode()
;
$this->assertInstanceOf('PhpParser\Node\Stmt\ClassConst', $contract->stmts[0]);
$this->assertInstanceOf('PhpParser\Node\Stmt\ClassMethod', $contract->stmts[1]);
$this->assertInstanceOf(Stmt\ClassConst::class, $contract->stmts[0]);
$this->assertInstanceOf(Stmt\ClassMethod::class, $contract->stmts[1]);
}
public function testDocComment() {
@@ -73,9 +74,9 @@ class InterfaceTest extends \PHPUnit_Framework_TestCase
->setDocComment('/** Test */')
->getNode();
$this->assertEquals(new Stmt\Interface_('Contract', array(), array(
'comments' => array(new Comment\Doc('/** Test */'))
)), $node);
$this->assertEquals(new Stmt\Interface_('Contract', [], [
'comments' => [new Comment\Doc('/** Test */')]
]), $node);
}
/**
@@ -87,9 +88,9 @@ class InterfaceTest extends \PHPUnit_Framework_TestCase
}
public function testFullFunctional() {
$const = new Stmt\ClassConst(array(
$const = new Stmt\ClassConst([
new Node\Const_('SPEED_OF_LIGHT', new DNumber(299792458))
));
]);
$method = new Stmt\ClassMethod('doSomething');
$contract = $this->builder
->addStmt($method)
@@ -102,4 +103,3 @@ class InterfaceTest extends \PHPUnit_Framework_TestCase
$this->assertTrue(interface_exists('Contract', false));
}
}

View File

@@ -1,14 +1,16 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Builder;
use PhpParser\Comment;
use PhpParser\Node;
use PhpParser\Node\Expr\Print_;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt;
use PhpParser\Comment;
use PHPUnit\Framework\TestCase;
class MethodTest extends \PHPUnit_Framework_TestCase
class MethodTest extends TestCase
{
public function createMethodBuilder($name) {
return new Method($name);
@@ -23,12 +25,12 @@ class MethodTest extends \PHPUnit_Framework_TestCase
;
$this->assertEquals(
new Stmt\ClassMethod('test', array(
'type' => Stmt\Class_::MODIFIER_PUBLIC
| Stmt\Class_::MODIFIER_ABSTRACT
| Stmt\Class_::MODIFIER_STATIC,
new Stmt\ClassMethod('test', [
'flags' => Stmt\Class_::MODIFIER_PUBLIC
| Stmt\Class_::MODIFIER_ABSTRACT
| Stmt\Class_::MODIFIER_STATIC,
'stmts' => null,
)),
]),
$node
);
@@ -39,10 +41,10 @@ class MethodTest extends \PHPUnit_Framework_TestCase
;
$this->assertEquals(
new Stmt\ClassMethod('test', array(
'type' => Stmt\Class_::MODIFIER_PROTECTED
| Stmt\Class_::MODIFIER_FINAL
)),
new Stmt\ClassMethod('test', [
'flags' => Stmt\Class_::MODIFIER_PROTECTED
| Stmt\Class_::MODIFIER_FINAL
]),
$node
);
@@ -52,9 +54,9 @@ class MethodTest extends \PHPUnit_Framework_TestCase
;
$this->assertEquals(
new Stmt\ClassMethod('test', array(
new Stmt\ClassMethod('test', [
'type' => Stmt\Class_::MODIFIER_PRIVATE
)),
]),
$node
);
}
@@ -66,28 +68,28 @@ class MethodTest extends \PHPUnit_Framework_TestCase
;
$this->assertEquals(
new Stmt\ClassMethod('test', array(
new Stmt\ClassMethod('test', [
'byRef' => true
)),
]),
$node
);
}
public function testParams() {
$param1 = new Node\Param('test1');
$param2 = new Node\Param('test2');
$param3 = new Node\Param('test3');
$param1 = new Node\Param(new Variable('test1'));
$param2 = new Node\Param(new Variable('test2'));
$param3 = new Node\Param(new Variable('test3'));
$node = $this->createMethodBuilder('test')
->addParam($param1)
->addParams(array($param2, $param3))
->addParams([$param2, $param3])
->getNode()
;
$this->assertEquals(
new Stmt\ClassMethod('test', array(
'params' => array($param1, $param2, $param3)
)),
new Stmt\ClassMethod('test', [
'params' => [$param1, $param2, $param3]
]),
$node
);
}
@@ -99,14 +101,18 @@ class MethodTest extends \PHPUnit_Framework_TestCase
$node = $this->createMethodBuilder('test')
->addStmt($stmt1)
->addStmts(array($stmt2, $stmt3))
->addStmts([$stmt2, $stmt3])
->getNode()
;
$this->assertEquals(
new Stmt\ClassMethod('test', array(
'stmts' => array($stmt1, $stmt2, $stmt3)
)),
new Stmt\ClassMethod('test', [
'stmts' => [
new Stmt\Expression($stmt1),
new Stmt\Expression($stmt2),
new Stmt\Expression($stmt3),
]
]),
$node
);
}
@@ -115,18 +121,18 @@ class MethodTest extends \PHPUnit_Framework_TestCase
->setDocComment('/** Test */')
->getNode();
$this->assertEquals(new Stmt\ClassMethod('test', array(), array(
'comments' => array(new Comment\Doc('/** Test */'))
)), $node);
$this->assertEquals(new Stmt\ClassMethod('test', [], [
'comments' => [new Comment\Doc('/** Test */')]
]), $node);
}
public function testReturnType() {
$node = $this->createMethodBuilder('test')
->setReturnType('bool')
->getNode();
$this->assertEquals(new Stmt\ClassMethod('test', array(
$this->assertEquals(new Stmt\ClassMethod('test', [
'returnType' => 'bool'
), array()), $node);
], []), $node);
}
/**

View File

@@ -1,11 +1,13 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Builder;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PhpParser\Node\Stmt;
use PHPUnit\Framework\TestCase;
class NamespaceTest extends \PHPUnit_Framework_TestCase
class NamespaceTest extends TestCase
{
protected function createNamespaceBuilder($fqn) {
return new Namespace_($fqn);
@@ -15,20 +17,24 @@ class NamespaceTest extends \PHPUnit_Framework_TestCase
$stmt1 = new Stmt\Class_('SomeClass');
$stmt2 = new Stmt\Interface_('SomeInterface');
$stmt3 = new Stmt\Function_('someFunction');
$docComment = new Doc('/** Test */');
$expected = new Stmt\Namespace_(
new Node\Name('Name\Space'),
array($stmt1, $stmt2, $stmt3)
[$stmt1, $stmt2, $stmt3],
['comments' => [$docComment]]
);
$node = $this->createNamespaceBuilder('Name\Space')
->addStmt($stmt1)
->addStmts(array($stmt2, $stmt3))
->addStmts([$stmt2, $stmt3])
->setDocComment($docComment)
->getNode()
;
$this->assertEquals($expected, $node);
$node = $this->createNamespaceBuilder(new Node\Name(array('Name', 'Space')))
->addStmts(array($stmt1, $stmt2))
$node = $this->createNamespaceBuilder(new Node\Name(['Name', 'Space']))
->setDocComment($docComment)
->addStmts([$stmt1, $stmt2])
->addStmt($stmt3)
->getNode()
;

View File

@@ -1,12 +1,13 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Builder;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar;
use PHPUnit\Framework\TestCase;
class ParamTest extends \PHPUnit_Framework_TestCase
class ParamTest extends TestCase
{
public function createParamBuilder($name) {
return new Param($name);
@@ -25,42 +26,42 @@ class ParamTest extends \PHPUnit_Framework_TestCase
}
public function provideTestDefaultValues() {
return array(
array(
return [
[
null,
new Expr\ConstFetch(new Node\Name('null'))
),
array(
],
[
true,
new Expr\ConstFetch(new Node\Name('true'))
),
array(
],
[
false,
new Expr\ConstFetch(new Node\Name('false'))
),
array(
],
[
31415,
new Scalar\LNumber(31415)
),
array(
],
[
3.1415,
new Scalar\DNumber(3.1415)
),
array(
],
[
'Hallo World',
new Scalar\String_('Hallo World')
),
array(
array(1, 2, 3),
new Expr\Array_(array(
],
[
[1, 2, 3],
new Expr\Array_([
new Expr\ArrayItem(new Scalar\LNumber(1)),
new Expr\ArrayItem(new Scalar\LNumber(2)),
new Expr\ArrayItem(new Scalar\LNumber(3)),
))
),
array(
array('foo' => 'bar', 'bar' => 'foo'),
new Expr\Array_(array(
])
],
[
['foo' => 'bar', 'bar' => 'foo'],
new Expr\Array_([
new Expr\ArrayItem(
new Scalar\String_('bar'),
new Scalar\String_('foo')
@@ -69,45 +70,79 @@ class ParamTest extends \PHPUnit_Framework_TestCase
new Scalar\String_('foo'),
new Scalar\String_('bar')
),
))
),
array(
])
],
[
new Scalar\MagicConst\Dir,
new Scalar\MagicConst\Dir
)
);
]
];
}
public function testTypeHints() {
/**
* @dataProvider provideTestTypeHints
*/
public function testTypeHints($typeHint, $expectedType) {
$node = $this->createParamBuilder('test')
->setTypeHint('array')
->setTypeHint($typeHint)
->getNode()
;
$type = $node->type;
$this->assertEquals(
new Node\Param('test', null, 'array'),
$node
);
/* Manually implement comparison to avoid __toString stupidity */
if ($expectedType instanceof Node\NullableType) {
$this->assertInstanceOf(get_class($expectedType), $type);
$expectedType = $expectedType->type;
$type = $type->type;
}
$node = $this->createParamBuilder('test')
->setTypeHint('callable')
->getNode()
;
$this->assertInstanceOf(get_class($expectedType), $type);
$this->assertEquals($expectedType, $type);
}
$this->assertEquals(
new Node\Param('test', null, 'callable'),
$node
);
public function provideTestTypeHints() {
return [
['array', new Node\Identifier('array')],
['callable', new Node\Identifier('callable')],
['bool', new Node\Identifier('bool')],
['int', new Node\Identifier('int')],
['float', new Node\Identifier('float')],
['string', new Node\Identifier('string')],
['iterable', new Node\Identifier('iterable')],
['object', new Node\Identifier('object')],
['Array', new Node\Identifier('array')],
['CALLABLE', new Node\Identifier('callable')],
['Some\Class', new Node\Name('Some\Class')],
['\Foo', new Node\Name\FullyQualified('Foo')],
['self', new Node\Name('self')],
['?array', new Node\NullableType(new Node\Identifier('array'))],
['?Some\Class', new Node\NullableType(new Node\Name('Some\Class'))],
[new Node\Name('Some\Class'), new Node\Name('Some\Class')],
[
new Node\NullableType(new Node\Identifier('int')),
new Node\NullableType(new Node\Identifier('int'))
],
[
new Node\NullableType(new Node\Name('Some\Class')),
new Node\NullableType(new Node\Name('Some\Class'))
],
];
}
$node = $this->createParamBuilder('test')
->setTypeHint('Some\Class')
->getNode()
;
/**
* @expectedException \LogicException
* @expectedExceptionMessage Parameter type cannot be void
*/
public function testVoidTypeError() {
$this->createParamBuilder('test')->setTypeHint('void');
}
$this->assertEquals(
new Node\Param('test', null, new Node\Name('Some\Class')),
$node
);
/**
* @expectedException \LogicException
* @expectedExceptionMessage Type must be a string, or an instance of Name, Identifier or NullableType
*/
public function testInvalidTypeError() {
$this->createParamBuilder('test')->setTypeHint(new \stdClass);
}
public function testByRef() {
@@ -117,7 +152,19 @@ class ParamTest extends \PHPUnit_Framework_TestCase
;
$this->assertEquals(
new Node\Param('test', null, null, true),
new Node\Param(new Expr\Variable('test'), null, null, true),
$node
);
}
public function testVariadic() {
$node = $this->createParamBuilder('test')
->makeVariadic()
->getNode()
;
$this->assertEquals(
new Node\Param(new Expr\Variable('test'), null, null, false, true),
$node
);
}

View File

@@ -1,14 +1,15 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Builder;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar;
use PhpParser\Comment;
use PhpParser\Node\Expr;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;
use PHPUnit\Framework\TestCase;
class PropertyTest extends \PHPUnit_Framework_TestCase
class PropertyTest extends TestCase
{
public function createPropertyBuilder($name) {
return new Property($name);
@@ -25,9 +26,9 @@ class PropertyTest extends \PHPUnit_Framework_TestCase
new Stmt\Property(
Stmt\Class_::MODIFIER_PRIVATE
| Stmt\Class_::MODIFIER_STATIC,
array(
[
new Stmt\PropertyProperty('test')
)
]
),
$node
);
@@ -40,9 +41,9 @@ class PropertyTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(
new Stmt\Property(
Stmt\Class_::MODIFIER_PROTECTED,
array(
[
new Stmt\PropertyProperty('test')
)
]
),
$node
);
@@ -55,9 +56,9 @@ class PropertyTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(
new Stmt\Property(
Stmt\Class_::MODIFIER_PUBLIC,
array(
[
new Stmt\PropertyProperty('test')
)
]
),
$node
);
@@ -70,12 +71,12 @@ class PropertyTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(new Stmt\Property(
Stmt\Class_::MODIFIER_PUBLIC,
array(
[
new Stmt\PropertyProperty('test')
),
array(
'comments' => array(new Comment\Doc('/** Test */'))
)
],
[
'comments' => [new Comment\Doc('/** Test */')]
]
), $node);
}
@@ -92,42 +93,42 @@ class PropertyTest extends \PHPUnit_Framework_TestCase
}
public function provideTestDefaultValues() {
return array(
array(
return [
[
null,
new Expr\ConstFetch(new Name('null'))
),
array(
],
[
true,
new Expr\ConstFetch(new Name('true'))
),
array(
],
[
false,
new Expr\ConstFetch(new Name('false'))
),
array(
],
[
31415,
new Scalar\LNumber(31415)
),
array(
],
[
3.1415,
new Scalar\DNumber(3.1415)
),
array(
],
[
'Hallo World',
new Scalar\String_('Hallo World')
),
array(
array(1, 2, 3),
new Expr\Array_(array(
],
[
[1, 2, 3],
new Expr\Array_([
new Expr\ArrayItem(new Scalar\LNumber(1)),
new Expr\ArrayItem(new Scalar\LNumber(2)),
new Expr\ArrayItem(new Scalar\LNumber(3)),
))
),
array(
array('foo' => 'bar', 'bar' => 'foo'),
new Expr\Array_(array(
])
],
[
['foo' => 'bar', 'bar' => 'foo'],
new Expr\Array_([
new Expr\ArrayItem(
new Scalar\String_('bar'),
new Scalar\String_('foo')
@@ -136,12 +137,12 @@ class PropertyTest extends \PHPUnit_Framework_TestCase
new Scalar\String_('foo'),
new Scalar\String_('bar')
),
))
),
array(
])
],
[
new Scalar\MagicConst\Dir,
new Scalar\MagicConst\Dir
)
);
]
];
}
}

View File

@@ -1,13 +1,13 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Builder;
use PhpParser\Comment;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
use PHPUnit\Framework\TestCase;
class TraitTest extends \PHPUnit_Framework_TestCase
class TraitTest extends TestCase
{
protected function createTraitBuilder($class) {
return new Trait_($class);
@@ -17,22 +17,24 @@ class TraitTest extends \PHPUnit_Framework_TestCase
$method1 = new Stmt\ClassMethod('test1');
$method2 = new Stmt\ClassMethod('test2');
$method3 = new Stmt\ClassMethod('test3');
$prop = new Stmt\Property(Stmt\Class_::MODIFIER_PUBLIC, array(
$prop = new Stmt\Property(Stmt\Class_::MODIFIER_PUBLIC, [
new Stmt\PropertyProperty('test')
));
]);
$use = new Stmt\TraitUse([new Name('OtherTrait')]);
$trait = $this->createTraitBuilder('TestTrait')
->setDocComment('/** Nice trait */')
->addStmt($method1)
->addStmts(array($method2, $method3))
->addStmts([$method2, $method3])
->addStmt($prop)
->addStmt($use)
->getNode();
$this->assertEquals(new Stmt\Trait_('TestTrait', array(
$prop, $method1, $method2, $method3
), array(
'comments' => array(
$this->assertEquals(new Stmt\Trait_('TestTrait', [
'stmts' => [$use, $prop, $method1, $method2, $method3]
], [
'comments' => [
new Comment\Doc('/** Nice trait */')
)
)), $trait);
]
]), $trait);
}
/**
@@ -41,7 +43,7 @@ class TraitTest extends \PHPUnit_Framework_TestCase
*/
public function testInvalidStmtError() {
$this->createTraitBuilder('Test')
->addStmt(new Stmt\Echo_(array()))
->addStmt(new Stmt\Echo_([]))
;
}
}

View File

@@ -1,10 +1,11 @@
<?php
<?php declare(strict_types=1);
use PhpParser\Builder;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
use PHPUnit\Framework\TestCase;
class UseTest extends \PHPUnit_Framework_TestCase
class UseTest extends TestCase
{
protected function createUseBuilder($name, $type = Stmt\Use_::TYPE_NORMAL) {
return new Builder\Use_($name, $type);
@@ -12,24 +13,18 @@ class UseTest extends \PHPUnit_Framework_TestCase
public function testCreation() {
$node = $this->createUseBuilder('Foo\Bar')->getNode();
$this->assertEquals(new Stmt\Use_(array(
new Stmt\UseUse(new Name('Foo\Bar'), 'Bar')
)), $node);
$this->assertEquals(new Stmt\Use_([
new Stmt\UseUse(new Name('Foo\Bar'), null)
]), $node);
$node = $this->createUseBuilder(new Name('Foo\Bar'))->as('XYZ')->getNode();
$this->assertEquals(new Stmt\Use_(array(
$this->assertEquals(new Stmt\Use_([
new Stmt\UseUse(new Name('Foo\Bar'), 'XYZ')
)), $node);
]), $node);
$node = $this->createUseBuilder('foo\bar', Stmt\Use_::TYPE_FUNCTION)->as('foo')->getNode();
$this->assertEquals(new Stmt\Use_(array(
$this->assertEquals(new Stmt\Use_([
new Stmt\UseUse(new Name('foo\bar'), 'foo')
), Stmt\Use_::TYPE_FUNCTION), $node);
}
public function testNonExistingMethod() {
$this->setExpectedException('LogicException', 'Method "foo" does not exist');
$builder = $this->createUseBuilder('Test');
$builder->foo();
], Stmt\Use_::TYPE_FUNCTION), $node);
}
}

View File

@@ -1,10 +1,19 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
use PhpParser\Builder;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\BinaryOp\Concat;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Tests\A;
class BuilderFactoryTest extends \PHPUnit_Framework_TestCase
class BuilderFactoryTest extends TestCase
{
/**
* @dataProvider provideTestFactory
@@ -15,23 +24,192 @@ class BuilderFactoryTest extends \PHPUnit_Framework_TestCase
}
public function provideTestFactory() {
return array(
array('namespace', 'PhpParser\Builder\Namespace_'),
array('class', 'PhpParser\Builder\Class_'),
array('interface', 'PhpParser\Builder\Interface_'),
array('trait', 'PhpParser\Builder\Trait_'),
array('method', 'PhpParser\Builder\Method'),
array('function', 'PhpParser\Builder\Function_'),
array('property', 'PhpParser\Builder\Property'),
array('param', 'PhpParser\Builder\Param'),
array('use', 'PhpParser\Builder\Use_'),
return [
['namespace', Builder\Namespace_::class],
['class', Builder\Class_::class],
['interface', Builder\Interface_::class],
['trait', Builder\Trait_::class],
['method', Builder\Method::class],
['function', Builder\Function_::class],
['property', Builder\Property::class],
['param', Builder\Param::class],
['use', Builder\Use_::class],
];
}
public function testVal() {
// This method is a wrapper around BuilderHelpers::normalizeValue(),
// which is already tested elsewhere
$factory = new BuilderFactory();
$this->assertEquals(
new String_("foo"),
$factory->val("foo")
);
}
public function testNonExistingMethod() {
$this->setExpectedException('LogicException', 'Method "foo" does not exist');
public function testConcat() {
$factory = new BuilderFactory();
$factory->foo();
$varA = new Expr\Variable('a');
$varB = new Expr\Variable('b');
$varC = new Expr\Variable('c');
$this->assertEquals(
new Concat($varA, $varB),
$factory->concat($varA, $varB)
);
$this->assertEquals(
new Concat(new Concat($varA, $varB), $varC),
$factory->concat($varA, $varB, $varC)
);
$this->assertEquals(
new Concat(new Concat(new String_("a"), $varB), new String_("c")),
$factory->concat("a", $varB, "c")
);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Expected at least two expressions
*/
public function testConcatOneError() {
(new BuilderFactory())->concat("a");
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Expected string or Expr
*/
public function testConcatInvalidExpr() {
(new BuilderFactory())->concat("a", 42);
}
public function testArgs() {
$factory = new BuilderFactory();
$unpack = new Arg(new Expr\Variable('c'), false, true);
$this->assertEquals(
[
new Arg(new Expr\Variable('a')),
new Arg(new String_('b')),
$unpack
],
$factory->args([new Expr\Variable('a'), 'b', $unpack])
);
}
public function testCalls() {
$factory = new BuilderFactory();
// Simple function call
$this->assertEquals(
new Expr\FuncCall(
new Name('var_dump'),
[new Arg(new String_('str'))]
),
$factory->funcCall('var_dump', ['str'])
);
// Dynamic function call
$this->assertEquals(
new Expr\FuncCall(new Expr\Variable('fn')),
$factory->funcCall(new Expr\Variable('fn'))
);
// Simple method call
$this->assertEquals(
new Expr\MethodCall(
new Expr\Variable('obj'),
new Identifier('method'),
[new Arg(new LNumber(42))]
),
$factory->methodCall(new Expr\Variable('obj'), 'method', [42])
);
// Explicitly pass Identifier node
$this->assertEquals(
new Expr\MethodCall(
new Expr\Variable('obj'),
new Identifier('method')
),
$factory->methodCall(new Expr\Variable('obj'), new Identifier('method'))
);
// Dynamic method call
$this->assertEquals(
new Expr\MethodCall(
new Expr\Variable('obj'),
new Expr\Variable('method')
),
$factory->methodCall(new Expr\Variable('obj'), new Expr\Variable('method'))
);
// Simple static method call
$this->assertEquals(
new Expr\StaticCall(
new Name\FullyQualified('Foo'),
new Identifier('bar'),
[new Arg(new Expr\Variable('baz'))]
),
$factory->staticCall('\Foo', 'bar', [new Expr\Variable('baz')])
);
// Dynamic static method call
$this->assertEquals(
new Expr\StaticCall(
new Expr\Variable('foo'),
new Expr\Variable('bar')
),
$factory->staticCall(new Expr\Variable('foo'), new Expr\Variable('bar'))
);
// Simple new call
$this->assertEquals(
new Expr\New_(new Name\FullyQualified('stdClass')),
$factory->new('\stdClass')
);
// Dynamic new call
$this->assertEquals(
new Expr\New_(
new Expr\Variable('foo'),
[new Arg(new String_('bar'))]
),
$factory->new(new Expr\Variable('foo'), ['bar'])
);
}
public function testConstFetches() {
$factory = new BuilderFactory();
$this->assertEquals(
new Expr\ConstFetch(new Name('FOO')),
$factory->constFetch('FOO')
);
$this->assertEquals(
new Expr\ClassConstFetch(new Name('Foo'), new Identifier('BAR')),
$factory->classConstFetch('Foo', 'BAR')
);
$this->assertEquals(
new Expr\ClassConstFetch(new Expr\Variable('foo'), new Identifier('BAR')),
$factory->classConstFetch(new Expr\Variable('foo'), 'BAR')
);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Expected string or instance of Node\Identifier
*/
public function testInvalidIdentifier() {
(new BuilderFactory())->classConstFetch('Foo', new Expr\Variable('foo'));
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Expected string or instance of Node\Identifier or Node\Expr
*/
public function testInvalidIdentifierOrExpr() {
(new BuilderFactory())->staticCall('Foo', new Name('bar'));
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Name must be a string or an instance of Node\Name or Node\Expr
*/
public function testInvalidNameOrExpr() {
(new BuilderFactory())->funcCall(new Node\Stmt\Return_());
}
public function testIntegration() {
@@ -65,7 +243,7 @@ class BuilderFactoryTest extends \PHPUnit_Framework_TestCase
->addStmt($factory->property('someProperty')->makeProtected())
->addStmt($factory->property('anotherProperty')
->makePrivate()
->setDefault(array(1, 2, 3))))
->setDefault([1, 2, 3])))
->getNode()
;
@@ -96,7 +274,7 @@ abstract class SomeClass extends SomeOtherClass implements A\Few, \Interfaces
}
EOC;
$stmts = array($node);
$stmts = [$node];
$prettyPrinter = new PrettyPrinter\Standard();
$generated = $prettyPrinter->prettyPrintFile($stmts);

View File

@@ -1,8 +1,9 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
use PhpParser\Comment;
use PhpParser\Node\Expr;
use PhpParser\Node\Stmt;
require_once __DIR__ . '/CodeTestAbstract.php';
@@ -11,47 +12,63 @@ class CodeParsingTest extends CodeTestAbstract
/**
* @dataProvider provideTestParse
*/
public function testParse($name, $code, $expected, $mode) {
$lexer = new Lexer\Emulative(array('usedAttributes' => array(
'startLine', 'endLine', 'startFilePos', 'endFilePos', 'comments'
)));
$parser5 = new Parser\Php5($lexer, array(
'throwOnError' => false,
));
$parser7 = new Parser\Php7($lexer, array(
'throwOnError' => false,
));
public function testParse($name, $code, $expected, $modeLine) {
if (null !== $modeLine) {
$modes = array_fill_keys(explode(',', $modeLine), true);
} else {
$modes = [];
}
$output5 = $this->getParseOutput($parser5, $code);
$output7 = $this->getParseOutput($parser7, $code);
list($parser5, $parser7) = $this->createParsers($modes);
list($stmts5, $output5) = $this->getParseOutput($parser5, $code, $modes);
list($stmts7, $output7) = $this->getParseOutput($parser7, $code, $modes);
if ($mode === 'php5') {
if (isset($modes['php5'])) {
$this->assertSame($expected, $output5, $name);
$this->assertNotSame($expected, $output7, $name);
} else if ($mode === 'php7') {
} elseif (isset($modes['php7'])) {
$this->assertNotSame($expected, $output5, $name);
$this->assertSame($expected, $output7, $name);
} else {
$this->assertSame($expected, $output5, $name);
$this->assertSame($expected, $output7, $name);
}
$this->checkAttributes($stmts5);
$this->checkAttributes($stmts7);
}
private function getParseOutput(Parser $parser, $code) {
$stmts = $parser->parse($code);
$errors = $parser->getErrors();
public function createParsers(array $modes) {
$lexer = new Lexer\Emulative(['usedAttributes' => [
'startLine', 'endLine',
'startFilePos', 'endFilePos',
'startTokenPos', 'endTokenPos',
'comments'
]]);
return [
new Parser\Php5($lexer),
new Parser\Php7($lexer),
];
}
private function getParseOutput(Parser $parser, $code, array $modes) {
$dumpPositions = isset($modes['positions']);
$errors = new ErrorHandler\Collecting;
$stmts = $parser->parse($code, $errors);
$output = '';
foreach ($errors as $error) {
foreach ($errors->getErrors() as $error) {
$output .= $this->formatErrorMessage($error, $code) . "\n";
}
if (null !== $stmts) {
$dumper = new NodeDumper(['dumpComments' => true]);
$output .= $dumper->dump($stmts);
$dumper = new NodeDumper(['dumpComments' => true, 'dumpPositions' => $dumpPositions]);
$output .= $dumper->dump($stmts, $code);
}
return canonicalize($output);
return [$stmts, canonicalize($output)];
}
public function provideTestParse() {
@@ -60,10 +77,44 @@ class CodeParsingTest extends CodeTestAbstract
private function formatErrorMessage(Error $e, $code) {
if ($e->hasColumnInfo()) {
return $e->getRawMessage() . ' from ' . $e->getStartLine() . ':' . $e->getStartColumn($code)
. ' to ' . $e->getEndLine() . ':' . $e->getEndColumn($code);
return $e->getMessageWithColumnInfo($code);
} else {
return $e->getMessage();
}
}
private function checkAttributes($stmts) {
if ($stmts === null) {
return;
}
$traverser = new NodeTraverser();
$traverser->addVisitor(new class extends NodeVisitorAbstract {
public function enterNode(Node $node) {
$startLine = $node->getStartLine();
$endLine = $node->getEndLine();
$startFilePos = $node->getStartFilePos();
$endFilePos = $node->getEndFilePos();
$startTokenPos = $node->getStartTokenPos();
$endTokenPos = $node->getEndTokenPos();
if ($startLine < 0 || $endLine < 0 ||
$startFilePos < 0 || $endFilePos < 0 ||
$startTokenPos < 0 || $endTokenPos < 0
) {
throw new \Exception('Missing location information on ' . $node->getType());
}
if ($endLine < $startLine ||
$endFilePos < $startFilePos ||
$endTokenPos < $startTokenPos
) {
// Nops and error can have inverted order, if they are empty
if (!$node instanceof Stmt\Nop && !$node instanceof Expr\Error) {
throw new \Exception('End < start on ' . $node->getType());
}
}
}
});
$traverser->traverse($stmts);
}
}

View File

@@ -1,61 +1,30 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
abstract class CodeTestAbstract extends \PHPUnit_Framework_TestCase
use PHPUnit\Framework\TestCase;
require_once __DIR__ . '/CodeTestParser.php';
abstract class CodeTestAbstract extends TestCase
{
protected function getTests($directory, $fileExtension) {
$directory = realpath($directory);
$it = new \RecursiveDirectoryIterator($directory);
$it = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::LEAVES_ONLY);
$it = new \RegexIterator($it, '(\.' . preg_quote($fileExtension) . '$)');
$tests = array();
foreach ($it as $file) {
$fileName = $file->getPathname();
$fileContents = file_get_contents($fileName);
$fileContents = canonicalize($fileContents);
// evaluate @@{expr}@@ expressions
$fileContents = preg_replace_callback(
'/@@\{(.*?)\}@@/',
function($matches) {
return eval('return ' . $matches[1] . ';');
},
$fileContents
);
// parse sections
$parts = preg_split("/\n-----(?:\n|$)/", $fileContents);
protected function getTests($directory, $fileExtension, $chunksPerTest = 2) {
$parser = new CodeTestParser;
$allTests = [];
foreach (filesInDir($directory, $fileExtension) as $fileName => $fileContents) {
list($name, $tests) = $parser->parseTest($fileContents, $chunksPerTest);
// first part is the name
$name = array_shift($parts) . ' (' . $fileName . ')';
$name .= ' (' . $fileName . ')';
$shortName = ltrim(str_replace($directory, '', $fileName), '/\\');
// multiple sections possible with always two forming a pair
$chunks = array_chunk($parts, 2);
foreach ($chunks as $i => $chunk) {
$dataSetName = $shortName . (count($chunks) > 1 ? '#' . $i : '');
list($expected, $mode) = $this->extractMode($chunk[1]);
$tests[$dataSetName] = array($name, $chunk[0], $expected, $mode);
foreach ($tests as $i => list($mode, $parts)) {
$dataSetName = $shortName . (count($parts) > 1 ? '#' . $i : '');
$allTests[$dataSetName] = array_merge([$name], $parts, [$mode]);
}
}
return $tests;
}
private function extractMode($expected) {
$firstNewLine = strpos($expected, "\n");
if (false === $firstNewLine) {
$firstNewLine = strlen($expected);
}
$firstLine = substr($expected, 0, $firstNewLine);
if (0 !== strpos($firstLine, '!!')) {
return [$expected, null];
}
$expected = (string) substr($expected, $firstNewLine + 1);
return [$expected, substr($firstLine, 2)];
return $allTests;
}
}

View File

@@ -0,0 +1,68 @@
<?php declare(strict_types=1);
namespace PhpParser;
class CodeTestParser
{
public function parseTest($code, $chunksPerTest) {
$code = canonicalize($code);
// evaluate @@{expr}@@ expressions
$code = preg_replace_callback(
'/@@\{(.*?)\}@@/',
function($matches) {
return eval('return ' . $matches[1] . ';');
},
$code
);
// parse sections
$parts = preg_split("/\n-----(?:\n|$)/", $code);
// first part is the name
$name = array_shift($parts);
// multiple sections possible with always two forming a pair
$chunks = array_chunk($parts, $chunksPerTest);
$tests = [];
foreach ($chunks as $i => $chunk) {
$lastPart = array_pop($chunk);
list($lastPart, $mode) = $this->extractMode($lastPart);
$tests[] = [$mode, array_merge($chunk, [$lastPart])];
}
return [$name, $tests];
}
public function reconstructTest($name, array $tests) {
$result = $name;
foreach ($tests as list($mode, $parts)) {
$lastPart = array_pop($parts);
foreach ($parts as $part) {
$result .= "\n-----\n$part";
}
$result .= "\n-----\n";
if (null !== $mode) {
$result .= "!!$mode\n";
}
$result .= $lastPart;
}
return $result;
}
private function extractMode($expected) {
$firstNewLine = strpos($expected, "\n");
if (false === $firstNewLine) {
$firstNewLine = strlen($expected);
}
$firstLine = substr($expected, 0, $firstNewLine);
if (0 !== strpos($firstLine, '!!')) {
return [$expected, null];
}
$expected = (string) substr($expected, $firstNewLine + 1);
return [$expected, substr($firstLine, 2)];
}
}

View File

@@ -1,23 +1,19 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
class CommentTest extends \PHPUnit_Framework_TestCase
use PHPUnit\Framework\TestCase;
class CommentTest extends TestCase
{
public function testGetSet() {
$comment = new Comment('/* Some comment */', 1, 10);
$comment = new Comment('/* Some comment */', 1, 10, 2);
$this->assertSame('/* Some comment */', $comment->getText());
$this->assertSame('/* Some comment */', (string) $comment);
$this->assertSame(1, $comment->getLine());
$this->assertSame(10, $comment->getFilePos());
$comment->setText('/* Some other comment */');
$comment->setLine(10);
$this->assertSame('/* Some other comment */', $comment->getText());
$this->assertSame('/* Some other comment */', (string) $comment);
$this->assertSame(10, $comment->getLine());
$this->assertSame(2, $comment->getTokenPos());
}
/**
@@ -29,10 +25,10 @@ class CommentTest extends \PHPUnit_Framework_TestCase
}
public function provideTestReformatting() {
return array(
array('// Some text' . "\n", '// Some text'),
array('/* Some text */', '/* Some text */'),
array(
return [
['// Some text' . "\n", '// Some text'],
['/* Some text */', '/* Some text */'],
[
'/**
* Some text.
* Some more text.
@@ -41,8 +37,8 @@ class CommentTest extends \PHPUnit_Framework_TestCase
* Some text.
* Some more text.
*/'
),
array(
],
[
'/*
Some text.
Some more text.
@@ -51,30 +47,30 @@ class CommentTest extends \PHPUnit_Framework_TestCase
Some text.
Some more text.
*/'
),
array(
],
[
'/* Some text.
More text.
Even more text. */',
'/* Some text.
More text.
Even more text. */'
),
array(
],
[
'/* Some text.
More text.
Indented text. */',
'/* Some text.
More text.
Indented text. */',
),
],
// invalid comment -> no reformatting
array(
[
'hallo
world',
'hallo
world',
),
);
],
];
}
}
}

View File

@@ -0,0 +1,133 @@
<?php declare(strict_types=1);
namespace PhpParser;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar;
use PHPUnit\Framework\TestCase;
class ConstExprEvaluatorTest extends TestCase
{
/** @dataProvider provideTestEvaluate */
public function testEvaluate($exprString, $expected) {
$parser = new Parser\Php7(new Lexer());
$expr = $parser->parse('<?php ' . $exprString . ';')[0]->expr;
$evaluator = new ConstExprEvaluator();
$this->assertSame($expected, $evaluator->evaluateDirectly($expr));
}
public function provideTestEvaluate() {
return [
['1', 1],
['1.0', 1.0],
['"foo"', "foo"],
['[0, 1]', [0, 1]],
['["foo" => "bar"]', ["foo" => "bar"]],
['NULL', null],
['False', false],
['true', true],
['+1', 1],
['-1', -1],
['~0', -1],
['!true', false],
['[0][0]', 0],
['"a"[0]', "a"],
['true ? 1 : (1/0)', 1],
['false ? (1/0) : 1', 1],
['42 ?: (1/0)', 42],
['false ?: 42', 42],
['false ?? 42', false],
['null ?? 42', 42],
['[0][0] ?? 42', 0],
['[][0] ?? 42', 42],
['0b11 & 0b10', 0b10],
['0b11 | 0b10', 0b11],
['0b11 ^ 0b10', 0b01],
['1 << 2', 4],
['4 >> 2', 1],
['"a" . "b"', "ab"],
['4 + 2', 6],
['4 - 2', 2],
['4 * 2', 8],
['4 / 2', 2],
['4 % 2', 0],
['4 ** 2', 16],
['1 == 1.0', true],
['1 != 1.0', false],
['1 < 2.0', true],
['1 <= 2.0', true],
['1 > 2.0', false],
['1 >= 2.0', false],
['1 <=> 2.0', -1],
['1 === 1.0', false],
['1 !== 1.0', true],
['true && true', true],
['true and true', true],
['false && (1/0)', false],
['false and (1/0)', false],
['false || false', false],
['false or false', false],
['true || (1/0)', true],
['true or (1/0)', true],
['true xor false', true],
];
}
/**
* @expectedException \PhpParser\ConstExprEvaluationException
* @expectedExceptionMessage Expression of type Expr_Variable cannot be evaluated
*/
public function testEvaluateFails() {
$evaluator = new ConstExprEvaluator();
$evaluator->evaluateDirectly(new Expr\Variable('a'));
}
public function testEvaluateFallback() {
$evaluator = new ConstExprEvaluator(function(Expr $expr) {
if ($expr instanceof Scalar\MagicConst\Line) {
return 42;
}
throw new ConstExprEvaluationException();
});
$expr = new Expr\BinaryOp\Plus(
new Scalar\LNumber(8),
new Scalar\MagicConst\Line()
);
$this->assertSame(50, $evaluator->evaluateDirectly($expr));
}
/**
* @dataProvider provideTestEvaluateSilently
*/
public function testEvaluateSilently($expr, $exception, $msg) {
$evaluator = new ConstExprEvaluator();
try {
$evaluator->evaluateSilently($expr);
} catch (ConstExprEvaluationException $e) {
$this->assertSame(
'An error occurred during constant expression evaluation',
$e->getMessage()
);
$prev = $e->getPrevious();
$this->assertInstanceOf($exception, $prev);
$this->assertSame($msg, $prev->getMessage());
}
}
public function provideTestEvaluateSilently() {
return [
[
new Expr\BinaryOp\Mod(new Scalar\LNumber(42), new Scalar\LNumber(0)),
\Error::class,
'Modulo by zero'
],
[
new Expr\BinaryOp\Div(new Scalar\LNumber(42), new Scalar\LNumber(0)),
\ErrorException::class,
'Division by zero'
],
];
}
}

View File

@@ -0,0 +1,24 @@
<?php declare(strict_types=1);
namespace PhpParser\ErrorHandler;
use PhpParser\Error;
use PHPUnit\Framework\TestCase;
class CollectingTest extends TestCase
{
public function testHandleError() {
$errorHandler = new Collecting();
$this->assertFalse($errorHandler->hasErrors());
$this->assertEmpty($errorHandler->getErrors());
$errorHandler->handleError($e1 = new Error('Test 1'));
$errorHandler->handleError($e2 = new Error('Test 2'));
$this->assertTrue($errorHandler->hasErrors());
$this->assertSame([$e1, $e2], $errorHandler->getErrors());
$errorHandler->clearErrors();
$this->assertFalse($errorHandler->hasErrors());
$this->assertEmpty($errorHandler->getErrors());
}
}

View File

@@ -0,0 +1,18 @@
<?php declare(strict_types=1);
namespace PhpParser\ErrorHandler;
use PhpParser\Error;
use PHPUnit\Framework\TestCase;
class ThrowingTest extends TestCase
{
/**
* @expectedException \PhpParser\Error
* @expectedExceptionMessage Test
*/
public function testHandleError() {
$errorHandler = new Throwing();
$errorHandler->handleError(new Error('Test'));
}
}

View File

@@ -1,21 +1,22 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
class ErrorTest extends \PHPUnit_Framework_TestCase
use PHPUnit\Framework\TestCase;
class ErrorTest extends TestCase
{
public function testConstruct() {
$attributes = array(
$attributes = [
'startLine' => 10,
'endLine' => 11,
);
];
$error = new Error('Some error', $attributes);
$this->assertSame('Some error', $error->getRawMessage());
$this->assertSame($attributes, $error->getAttributes());
$this->assertSame(10, $error->getStartLine());
$this->assertSame(11, $error->getEndLine());
$this->assertSame(10, $error->getRawLine());
$this->assertSame('Some error on line 10', $error->getMessage());
return $error;
@@ -31,10 +32,6 @@ class ErrorTest extends \PHPUnit_Framework_TestCase
$error->setStartLine(15);
$this->assertSame(15, $error->getStartLine());
$this->assertSame('Some other error on line 15', $error->getMessage());
$error->setRawLine(17);
$this->assertSame(17, $error->getRawLine());
$this->assertSame('Some other error on line 17', $error->getMessage());
}
public function testUnknownLine() {
@@ -42,48 +39,47 @@ class ErrorTest extends \PHPUnit_Framework_TestCase
$this->assertSame(-1, $error->getStartLine());
$this->assertSame(-1, $error->getEndLine());
$this->assertSame(-1, $error->getRawLine());
$this->assertSame('Some error on unknown line', $error->getMessage());
}
/** @dataProvider provideTestColumnInfo */
public function testColumnInfo($code, $startPos, $endPos, $startColumn, $endColumn) {
$error = new Error('Some error', array(
$error = new Error('Some error', [
'startFilePos' => $startPos,
'endFilePos' => $endPos,
));
]);
$this->assertSame(true, $error->hasColumnInfo());
$this->assertTrue($error->hasColumnInfo());
$this->assertSame($startColumn, $error->getStartColumn($code));
$this->assertSame($endColumn, $error->getEndColumn($code));
}
public function provideTestColumnInfo() {
return array(
return [
// Error at "bar"
array("<?php foo bar baz", 10, 12, 11, 13),
array("<?php\nfoo bar baz", 10, 12, 5, 7),
array("<?php foo\nbar baz", 10, 12, 1, 3),
array("<?php foo bar\nbaz", 10, 12, 11, 13),
array("<?php\r\nfoo bar baz", 11, 13, 5, 7),
["<?php foo bar baz", 10, 12, 11, 13],
["<?php\nfoo bar baz", 10, 12, 5, 7],
["<?php foo\nbar baz", 10, 12, 1, 3],
["<?php foo bar\nbaz", 10, 12, 11, 13],
["<?php\r\nfoo bar baz", 11, 13, 5, 7],
// Error at "baz"
array("<?php foo bar baz", 14, 16, 15, 17),
array("<?php foo bar\nbaz", 14, 16, 1, 3),
["<?php foo bar baz", 14, 16, 15, 17],
["<?php foo bar\nbaz", 14, 16, 1, 3],
// Error at string literal
array("<?php foo 'bar\nbaz' xyz", 10, 18, 11, 4),
array("<?php\nfoo 'bar\nbaz' xyz", 10, 18, 5, 4),
array("<?php foo\n'\nbarbaz\n'\nxyz", 10, 19, 1, 1),
["<?php foo 'bar\nbaz' xyz", 10, 18, 11, 4],
["<?php\nfoo 'bar\nbaz' xyz", 10, 18, 5, 4],
["<?php foo\n'\nbarbaz\n'\nxyz", 10, 19, 1, 1],
// Error over full string
array("<?php", 0, 4, 1, 5),
array("<?\nphp", 0, 5, 1, 3),
);
["<?php", 0, 4, 1, 5],
["<?\nphp", 0, 5, 1, 3],
];
}
public function testNoColumnInfo() {
$error = new Error('Some error', 3);
$this->assertSame(false, $error->hasColumnInfo());
$this->assertFalse($error->hasColumnInfo());
try {
$error->getStartColumn('');
$this->fail('Expected RuntimeException');
@@ -103,10 +99,10 @@ class ErrorTest extends \PHPUnit_Framework_TestCase
* @expectedExceptionMessage Invalid position information
*/
public function testInvalidPosInfo() {
$error = new Error('Some error', array(
$error = new Error('Some error', [
'startFilePos' => 10,
'endFilePos' => 11,
));
]);
$error->getStartColumn('code');
}
}

View File

@@ -0,0 +1,67 @@
<?php declare(strict_types=1);
namespace PhpParser\Internal;
use PHPUnit\Framework\TestCase;
class DifferTest extends TestCase
{
private function formatDiffString(array $diff) {
$diffStr = '';
foreach ($diff as $diffElem) {
switch ($diffElem->type) {
case DiffElem::TYPE_KEEP:
$diffStr .= $diffElem->old;
break;
case DiffElem::TYPE_REMOVE:
$diffStr .= '-' . $diffElem->old;
break;
case DiffElem::TYPE_ADD:
$diffStr .= '+' . $diffElem->new;
break;
case DiffElem::TYPE_REPLACE:
$diffStr .= '/' . $diffElem->old . $diffElem->new;
break;
default:
assert(false);
break;
}
}
return $diffStr;
}
/** @dataProvider provideTestDiff */
public function testDiff($oldStr, $newStr, $expectedDiffStr) {
$differ = new Differ(function($a, $b) { return $a === $b; });
$diff = $differ->diff(str_split($oldStr), str_split($newStr));
$this->assertSame($expectedDiffStr, $this->formatDiffString($diff));
}
public function provideTestDiff() {
return [
['abc', 'abc', 'abc'],
['abc', 'abcdef', 'abc+d+e+f'],
['abcdef', 'abc', 'abc-d-e-f'],
['abcdef', 'abcxyzdef', 'abc+x+y+zdef'],
['axyzb', 'ab', 'a-x-y-zb'],
['abcdef', 'abxyef', 'ab-c-d+x+yef'],
['abcdef', 'cdefab', '-a-bcdef+a+b'],
];
}
/** @dataProvider provideTestDiffWithReplacements */
public function testDiffWithReplacements($oldStr, $newStr, $expectedDiffStr) {
$differ = new Differ(function($a, $b) { return $a === $b; });
$diff = $differ->diffWithReplacements(str_split($oldStr), str_split($newStr));
$this->assertSame($expectedDiffStr, $this->formatDiffString($diff));
}
public function provideTestDiffWithReplacements() {
return [
['abcde', 'axyze', 'a/bx/cy/dze'],
['abcde', 'xbcdy', '/axbcd/ey'],
['abcde', 'axye', 'a-b-c-d+x+ye'],
['abcde', 'axyzue', 'a-b-c-d+x+y+z+ue'],
];
}
}

View File

@@ -0,0 +1,45 @@
<?php declare(strict_types=1);
namespace PhpParser;
use PHPUnit\Framework\TestCase;
class JsonDecoderTest extends TestCase
{
public function testRoundTrip() {
$code = <<<'PHP'
<?php
// comment
/** doc comment */
function functionName(&$a = 0, $b = 1.0) {
echo 'Foo';
}
PHP;
$parser = new Parser\Php7(new Lexer());
$stmts = $parser->parse($code);
$json = json_encode($stmts);
$jsonDecoder = new JsonDecoder();
$decodedStmts = $jsonDecoder->decode($json);
$this->assertEquals($stmts, $decodedStmts);
}
/** @dataProvider provideTestDecodingError */
public function testDecodingError($json, $expectedMessage) {
$jsonDecoder = new JsonDecoder();
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage($expectedMessage);
$jsonDecoder->decode($json);
}
public function provideTestDecodingError() {
return [
['???', 'JSON decoding error: Syntax error'],
['{"nodeType":123}', 'Node type must be a string'],
['{"nodeType":"Name","attributes":123}', 'Attributes must be an array'],
['{"nodeType":"Comment"}', 'Comment must have text'],
['{"nodeType":"xxx"}', 'Unknown node type "xxx"'],
];
}
}

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Lexer;
@@ -9,7 +9,7 @@ require_once __DIR__ . '/../LexerTest.php';
class EmulativeTest extends LexerTest
{
protected function getLexer(array $options = array()) {
protected function getLexer(array $options = []) {
return new Emulative($options);
}
@@ -37,23 +37,23 @@ class EmulativeTest extends LexerTest
}
public function provideTestReplaceKeywords() {
return array(
return [
// PHP 5.5
array('finally', Tokens::T_FINALLY),
array('yield', Tokens::T_YIELD),
['finally', Tokens::T_FINALLY],
['yield', Tokens::T_YIELD],
// PHP 5.4
array('callable', Tokens::T_CALLABLE),
array('insteadof', Tokens::T_INSTEADOF),
array('trait', Tokens::T_TRAIT),
array('__TRAIT__', Tokens::T_TRAIT_C),
['callable', Tokens::T_CALLABLE],
['insteadof', Tokens::T_INSTEADOF],
['trait', Tokens::T_TRAIT],
['__TRAIT__', Tokens::T_TRAIT_C],
// PHP 5.3
array('__DIR__', Tokens::T_DIR),
array('goto', Tokens::T_GOTO),
array('namespace', Tokens::T_NAMESPACE),
array('__NAMESPACE__', Tokens::T_NS_C),
);
['__DIR__', Tokens::T_DIR],
['goto', Tokens::T_GOTO],
['namespace', Tokens::T_NAMESPACE],
['__NAMESPACE__', Tokens::T_NS_C],
];
}
/**
@@ -86,48 +86,48 @@ class EmulativeTest extends LexerTest
}
public function provideTestLexNewFeatures() {
return array(
array('yield from', array(
array(Tokens::T_YIELD_FROM, 'yield from'),
)),
array("yield\r\nfrom", array(
array(Tokens::T_YIELD_FROM, "yield\r\nfrom"),
)),
array('...', array(
array(Tokens::T_ELLIPSIS, '...'),
)),
array('**', array(
array(Tokens::T_POW, '**'),
)),
array('**=', array(
array(Tokens::T_POW_EQUAL, '**='),
)),
array('??', array(
array(Tokens::T_COALESCE, '??'),
)),
array('<=>', array(
array(Tokens::T_SPACESHIP, '<=>'),
)),
array('0b1010110', array(
array(Tokens::T_LNUMBER, '0b1010110'),
)),
array('0b1011010101001010110101010010101011010101010101101011001110111100', array(
array(Tokens::T_DNUMBER, '0b1011010101001010110101010010101011010101010101101011001110111100'),
)),
array('\\', array(
array(Tokens::T_NS_SEPARATOR, '\\'),
)),
array("<<<'NOWDOC'\nNOWDOC;\n", array(
array(Tokens::T_START_HEREDOC, "<<<'NOWDOC'\n"),
array(Tokens::T_END_HEREDOC, 'NOWDOC'),
array(ord(';'), ';'),
)),
array("<<<'NOWDOC'\nFoobar\nNOWDOC;\n", array(
array(Tokens::T_START_HEREDOC, "<<<'NOWDOC'\n"),
array(Tokens::T_ENCAPSED_AND_WHITESPACE, "Foobar\n"),
array(Tokens::T_END_HEREDOC, 'NOWDOC'),
array(ord(';'), ';'),
)),
);
return [
['yield from', [
[Tokens::T_YIELD_FROM, 'yield from'],
]],
["yield\r\nfrom", [
[Tokens::T_YIELD_FROM, "yield\r\nfrom"],
]],
['...', [
[Tokens::T_ELLIPSIS, '...'],
]],
['**', [
[Tokens::T_POW, '**'],
]],
['**=', [
[Tokens::T_POW_EQUAL, '**='],
]],
['??', [
[Tokens::T_COALESCE, '??'],
]],
['<=>', [
[Tokens::T_SPACESHIP, '<=>'],
]],
['0b1010110', [
[Tokens::T_LNUMBER, '0b1010110'],
]],
['0b1011010101001010110101010010101011010101010101101011001110111100', [
[Tokens::T_DNUMBER, '0b1011010101001010110101010010101011010101010101101011001110111100'],
]],
['\\', [
[Tokens::T_NS_SEPARATOR, '\\'],
]],
["<<<'NOWDOC'\nNOWDOC;\n", [
[Tokens::T_START_HEREDOC, "<<<'NOWDOC'\n"],
[Tokens::T_END_HEREDOC, 'NOWDOC'],
[ord(';'), ';'],
]],
["<<<'NOWDOC'\nFoobar\nNOWDOC;\n", [
[Tokens::T_START_HEREDOC, "<<<'NOWDOC'\n"],
[Tokens::T_ENCAPSED_AND_WHITESPACE, "Foobar\n"],
[Tokens::T_END_HEREDOC, 'NOWDOC'],
[ord(';'), ';'],
]],
];
}
}

View File

@@ -1,42 +1,51 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
use PhpParser\Parser\Tokens;
use PHPUnit\Framework\TestCase;
class LexerTest extends \PHPUnit_Framework_TestCase
class LexerTest extends TestCase
{
/* To allow overwriting in parent class */
protected function getLexer(array $options = array()) {
protected function getLexer(array $options = []) {
return new Lexer($options);
}
/**
* @dataProvider provideTestError
*/
public function testError($code, $message) {
public function testError($code, $messages) {
if (defined('HHVM_VERSION')) {
$this->markTestSkipped('HHVM does not throw warnings from token_get_all()');
}
$lexer = $this->getLexer();
try {
$lexer->startLexing($code);
} catch (Error $e) {
$this->assertSame($message, $e->getMessage());
$errorHandler = new ErrorHandler\Collecting();
$lexer = $this->getLexer(['usedAttributes' => [
'comments', 'startLine', 'endLine', 'startFilePos', 'endFilePos'
]]);
$lexer->startLexing($code, $errorHandler);
$errors = $errorHandler->getErrors();
return;
$this->assertCount(count($messages), $errors);
for ($i = 0; $i < count($messages); $i++) {
$this->assertSame($messages[$i], $errors[$i]->getMessageWithColumnInfo($code));
}
$this->fail('Expected PhpParser\Error');
}
public function provideTestError() {
return array(
array('<?php /*', 'Unterminated comment on line 1'),
array('<?php ' . "\1", 'Unexpected character "' . "\1" . '" (ASCII 1) on unknown line'),
array('<?php ' . "\0", 'Unexpected null byte on unknown line'),
);
return [
["<?php /*", ["Unterminated comment from 1:7 to 1:9"]],
["<?php \1", ["Unexpected character \"\1\" (ASCII 1) from 1:7 to 1:7"]],
["<?php \0", ["Unexpected null byte from 1:7 to 1:7"]],
// Error with potentially emulated token
["<?php ?? \0", ["Unexpected null byte from 1:10 to 1:10"]],
["<?php\n\0\1 foo /* bar", [
"Unexpected null byte from 2:1 to 2:1",
"Unexpected character \"\1\" (ASCII 1) from 2:2 to 2:2",
"Unterminated comment from 2:8 to 2:14"
]],
];
}
/**
@@ -56,144 +65,151 @@ class LexerTest extends \PHPUnit_Framework_TestCase
}
public function provideTestLex() {
return array(
return [
// tests conversion of closing PHP tag and drop of whitespace and opening tags
array(
[
'<?php tokens ?>plaintext',
array(),
array(
array(
[],
[
[
Tokens::T_STRING, 'tokens',
array('startLine' => 1), array('endLine' => 1)
),
array(
['startLine' => 1], ['endLine' => 1]
],
[
ord(';'), '?>',
array('startLine' => 1), array('endLine' => 1)
),
array(
['startLine' => 1], ['endLine' => 1]
],
[
Tokens::T_INLINE_HTML, 'plaintext',
array('startLine' => 1), array('endLine' => 1)
),
)
),
['startLine' => 1, 'hasLeadingNewline' => false],
['endLine' => 1]
],
]
],
// tests line numbers
array(
[
'<?php' . "\n" . '$ token /** doc' . "\n" . 'comment */ $',
array(),
array(
array(
[],
[
[
ord('$'), '$',
array('startLine' => 2), array('endLine' => 2)
),
array(
['startLine' => 2], ['endLine' => 2]
],
[
Tokens::T_STRING, 'token',
array('startLine' => 2), array('endLine' => 2)
),
array(
['startLine' => 2], ['endLine' => 2]
],
[
ord('$'), '$',
array(
[
'startLine' => 3,
'comments' => array(
new Comment\Doc('/** doc' . "\n" . 'comment */', 2, 14),
)
),
array('endLine' => 3)
),
)
),
'comments' => [
new Comment\Doc('/** doc' . "\n" . 'comment */', 2, 14, 5),
]
],
['endLine' => 3]
],
]
],
// tests comment extraction
array(
[
'<?php /* comment */ // comment' . "\n" . '/** docComment 1 *//** docComment 2 */ token',
array(),
array(
array(
[],
[
[
Tokens::T_STRING, 'token',
array(
[
'startLine' => 2,
'comments' => array(
new Comment('/* comment */', 1, 6),
new Comment('// comment' . "\n", 1, 20),
new Comment\Doc('/** docComment 1 */', 2, 31),
new Comment\Doc('/** docComment 2 */', 2, 50),
),
),
array('endLine' => 2)
),
)
),
'comments' => [
new Comment('/* comment */', 1, 6, 1),
new Comment('// comment' . "\n", 1, 20, 3),
new Comment\Doc('/** docComment 1 */', 2, 31, 4),
new Comment\Doc('/** docComment 2 */', 2, 50, 5),
],
],
['endLine' => 2]
],
]
],
// tests differing start and end line
array(
[
'<?php "foo' . "\n" . 'bar"',
array(),
array(
array(
[],
[
[
Tokens::T_CONSTANT_ENCAPSED_STRING, '"foo' . "\n" . 'bar"',
array('startLine' => 1), array('endLine' => 2)
),
)
),
['startLine' => 1], ['endLine' => 2]
],
]
],
// tests exact file offsets
array(
[
'<?php "a";' . "\n" . '// foo' . "\n" . '"b";',
array('usedAttributes' => array('startFilePos', 'endFilePos')),
array(
array(
['usedAttributes' => ['startFilePos', 'endFilePos']],
[
[
Tokens::T_CONSTANT_ENCAPSED_STRING, '"a"',
array('startFilePos' => 6), array('endFilePos' => 8)
),
array(
['startFilePos' => 6], ['endFilePos' => 8]
],
[
ord(';'), ';',
array('startFilePos' => 9), array('endFilePos' => 9)
),
array(
['startFilePos' => 9], ['endFilePos' => 9]
],
[
Tokens::T_CONSTANT_ENCAPSED_STRING, '"b"',
array('startFilePos' => 18), array('endFilePos' => 20)
),
array(
['startFilePos' => 18], ['endFilePos' => 20]
],
[
ord(';'), ';',
array('startFilePos' => 21), array('endFilePos' => 21)
),
)
),
['startFilePos' => 21], ['endFilePos' => 21]
],
]
],
// tests token offsets
array(
[
'<?php "a";' . "\n" . '// foo' . "\n" . '"b";',
array('usedAttributes' => array('startTokenPos', 'endTokenPos')),
array(
array(
['usedAttributes' => ['startTokenPos', 'endTokenPos']],
[
[
Tokens::T_CONSTANT_ENCAPSED_STRING, '"a"',
array('startTokenPos' => 1), array('endTokenPos' => 1)
),
array(
['startTokenPos' => 1], ['endTokenPos' => 1]
],
[
ord(';'), ';',
array('startTokenPos' => 2), array('endTokenPos' => 2)
),
array(
['startTokenPos' => 2], ['endTokenPos' => 2]
],
[
Tokens::T_CONSTANT_ENCAPSED_STRING, '"b"',
array('startTokenPos' => 5), array('endTokenPos' => 5)
),
array(
['startTokenPos' => 5], ['endTokenPos' => 5]
],
[
ord(';'), ';',
array('startTokenPos' => 6), array('endTokenPos' => 6)
),
)
),
['startTokenPos' => 6], ['endTokenPos' => 6]
],
]
],
// tests all attributes being disabled
array(
[
'<?php /* foo */ $bar;',
array('usedAttributes' => array()),
array(
array(
['usedAttributes' => []],
[
[
Tokens::T_VARIABLE, '$bar',
array(), array()
),
array(
[], []
],
[
ord(';'), ';',
array(), array()
)
)
)
);
[], []
]
]
],
// tests no tokens
[
'',
[],
[]
],
];
}
/**
@@ -210,13 +226,13 @@ class LexerTest extends \PHPUnit_Framework_TestCase
}
public function provideTestHaltCompiler() {
return array(
array('<?php ... __halt_compiler();Remaining Text', 'Remaining Text'),
array('<?php ... __halt_compiler ( ) ;Remaining Text', 'Remaining Text'),
array('<?php ... __halt_compiler() ?>Remaining Text', 'Remaining Text'),
return [
['<?php ... __halt_compiler();Remaining Text', 'Remaining Text'],
['<?php ... __halt_compiler ( ) ;Remaining Text', 'Remaining Text'],
['<?php ... __halt_compiler() ?>Remaining Text', 'Remaining Text'],
//array('<?php ... __halt_compiler();' . "\0", "\0"),
//array('<?php ... __halt_compiler /* */ ( ) ;Remaining Text', 'Remaining Text'),
);
];
}
/**
@@ -233,15 +249,15 @@ class LexerTest extends \PHPUnit_Framework_TestCase
public function testGetTokens() {
$code = '<?php "a";' . "\n" . '// foo' . "\n" . '"b";';
$expectedTokens = array(
array(T_OPEN_TAG, '<?php ', 1),
array(T_CONSTANT_ENCAPSED_STRING, '"a"', 1),
$expectedTokens = [
[T_OPEN_TAG, '<?php ', 1],
[T_CONSTANT_ENCAPSED_STRING, '"a"', 1],
';',
array(T_WHITESPACE, "\n", 1),
array(T_COMMENT, '// foo' . "\n", 2),
array(T_CONSTANT_ENCAPSED_STRING, '"b"', 3),
[T_WHITESPACE, "\n", 1],
[T_COMMENT, '// foo' . "\n", 2],
[T_CONSTANT_ENCAPSED_STRING, '"b"', 3],
';',
);
];
$lexer = $this->getLexer();
$lexer->startLexing($code);

View File

@@ -0,0 +1,66 @@
<?php declare(strict_types=1);
namespace PhpParser;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Use_;
use PHPUnit\Framework\TestCase;
class NameContextTest extends TestCase
{
/**
* @dataProvider provideTestGetPossibleNames
*/
public function testGetPossibleNames($type, $name, $expectedPossibleNames) {
$nameContext = new NameContext(new ErrorHandler\Throwing());
$nameContext->startNamespace(new Name('NS'));
$nameContext->addAlias(new Name('Foo'), 'Foo', Use_::TYPE_NORMAL);
$nameContext->addAlias(new Name('Foo\Bar'), 'Alias', Use_::TYPE_NORMAL);
$nameContext->addAlias(new Name('Foo\fn'), 'fn', Use_::TYPE_FUNCTION);
$nameContext->addAlias(new Name('Foo\CN'), 'CN', Use_::TYPE_CONSTANT);
$possibleNames = $nameContext->getPossibleNames($name, $type);
$possibleNames = array_map(function (Name $name) {
return $name->toCodeString();
}, $possibleNames);
$this->assertSame($expectedPossibleNames, $possibleNames);
// Here the last name is always the shortest one
$expectedShortName = $expectedPossibleNames[count($expectedPossibleNames) - 1];
$this->assertSame(
$expectedShortName,
$nameContext->getShortName($name, $type)->toCodeString()
);
}
public function provideTestGetPossibleNames() {
return [
[Use_::TYPE_NORMAL, 'Test', ['\Test']],
[Use_::TYPE_NORMAL, 'Test\Namespaced', ['\Test\Namespaced']],
[Use_::TYPE_NORMAL, 'NS\Test', ['\NS\Test', 'Test']],
[Use_::TYPE_NORMAL, 'ns\Test', ['\ns\Test', 'Test']],
[Use_::TYPE_NORMAL, 'NS\Foo\Bar', ['\NS\Foo\Bar']],
[Use_::TYPE_NORMAL, 'ns\foo\Bar', ['\ns\foo\Bar']],
[Use_::TYPE_NORMAL, 'Foo', ['\Foo', 'Foo']],
[Use_::TYPE_NORMAL, 'Foo\Bar', ['\Foo\Bar', 'Foo\Bar', 'Alias']],
[Use_::TYPE_NORMAL, 'Foo\Bar\Baz', ['\Foo\Bar\Baz', 'Foo\Bar\Baz', 'Alias\Baz']],
[Use_::TYPE_NORMAL, 'Foo\fn\Bar', ['\Foo\fn\Bar', 'Foo\fn\Bar']],
[Use_::TYPE_FUNCTION, 'Foo\fn\bar', ['\Foo\fn\bar', 'Foo\fn\bar']],
[Use_::TYPE_FUNCTION, 'Foo\fn', ['\Foo\fn', 'Foo\fn', 'fn']],
[Use_::TYPE_FUNCTION, 'Foo\FN', ['\Foo\FN', 'Foo\FN', 'fn']],
[Use_::TYPE_CONSTANT, 'Foo\CN\BAR', ['\Foo\CN\BAR', 'Foo\CN\BAR']],
[Use_::TYPE_CONSTANT, 'Foo\CN', ['\Foo\CN', 'Foo\CN', 'CN']],
[Use_::TYPE_CONSTANT, 'foo\CN', ['\foo\CN', 'Foo\CN', 'CN']],
[Use_::TYPE_CONSTANT, 'foo\cn', ['\foo\cn', 'Foo\cn']],
// self/parent/static must not be fully qualified
[Use_::TYPE_NORMAL, 'self', ['self']],
[Use_::TYPE_NORMAL, 'parent', ['parent']],
[Use_::TYPE_NORMAL, 'static', ['static']],
// true/false/null do not need to be fully qualified, even in namespaces
[Use_::TYPE_CONSTANT, 'true', ['\true', 'true']],
[Use_::TYPE_CONSTANT, 'false', ['\false', 'false']],
[Use_::TYPE_CONSTANT, 'null', ['\null', 'null']],
];
}
}

View File

@@ -0,0 +1,31 @@
<?php declare(strict_types=1);
namespace PhpParser\Node;
use PHPUnit\Framework\TestCase;
class IdentifierTest extends TestCase
{
public function testToString() {
$identifier = new Identifier('Foo');
$this->assertSame('Foo', (string) $identifier);
$this->assertSame('Foo', $identifier->toString());
$this->assertSame('foo', $identifier->toLowerString());
}
/** @dataProvider provideTestIsSpecialClassName */
public function testIsSpecialClassName($identifier, $expected) {
$identifier = new Identifier($identifier);
$this->assertSame($expected, $identifier->isSpecialClassName());
}
public function provideTestIsSpecialClassName() {
return [
['self', true],
['PARENT', true],
['Static', true],
['other', false],
];
}
}

View File

@@ -1,15 +1,20 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Node;
class NameTest extends \PHPUnit_Framework_TestCase
use PHPUnit\Framework\TestCase;
class NameTest extends TestCase
{
public function testConstruct() {
$name = new Name(array('foo', 'bar'));
$this->assertSame(array('foo', 'bar'), $name->parts);
$name = new Name(['foo', 'bar']);
$this->assertSame(['foo', 'bar'], $name->parts);
$name = new Name('foo\bar');
$this->assertSame(array('foo', 'bar'), $name->parts);
$this->assertSame(['foo', 'bar'], $name->parts);
$name = new Name($name);
$this->assertSame(['foo', 'bar'], $name->parts);
}
public function testGet() {
@@ -23,93 +28,61 @@ class NameTest extends \PHPUnit_Framework_TestCase
}
public function testToString() {
$name = new Name('foo\bar');
$name = new Name('Foo\Bar');
$this->assertSame('foo\bar', (string) $name);
$this->assertSame('foo\bar', $name->toString());
$this->assertSame('foo_bar', $name->toString('_'));
}
public function testSet() {
$name = new Name('foo');
$name->set('foo\bar');
$this->assertSame('foo\bar', $name->toString());
$name->set(array('foo', 'bar'));
$this->assertSame('foo\bar', $name->toString());
$name->set(new Name('foo\bar'));
$this->assertSame('foo\bar', $name->toString());
}
public function testSetFirst() {
$name = new Name('foo');
$name->setFirst('bar');
$this->assertSame('bar', $name->toString());
$name->setFirst('A\B');
$this->assertSame('A\B', $name->toString());
$name->setFirst('C');
$this->assertSame('C\B', $name->toString());
$name->setFirst('D\E');
$this->assertSame('D\E\B', $name->toString());
}
public function testSetLast() {
$name = new Name('foo');
$name->setLast('bar');
$this->assertSame('bar', $name->toString());
$name->setLast('A\B');
$this->assertSame('A\B', $name->toString());
$name->setLast('C');
$this->assertSame('A\C', $name->toString());
$name->setLast('D\E');
$this->assertSame('A\D\E', $name->toString());
}
public function testAppend() {
$name = new Name('foo');
$name->append('bar');
$this->assertSame('foo\bar', $name->toString());
$name->append('bar\foo');
$this->assertSame('foo\bar\bar\foo', $name->toString());
}
public function testPrepend() {
$name = new Name('foo');
$name->prepend('bar');
$this->assertSame('bar\foo', $name->toString());
$name->prepend('foo\bar');
$this->assertSame('foo\bar\bar\foo', $name->toString());
$this->assertSame('Foo\Bar', (string) $name);
$this->assertSame('Foo\Bar', $name->toString());
$this->assertSame('foo\bar', $name->toLowerString());
}
public function testSlice() {
$name = new Name('foo\bar');
$this->assertEquals(new Name('foo\bar'), $name->slice(0));
$this->assertEquals(new Name('bar'), $name->slice(1));
$this->assertEquals(new Name([]), $name->slice(2));
$name = new Name('foo\bar\baz');
$this->assertEquals(new Name('foo\bar\baz'), $name->slice(0));
$this->assertEquals(new Name('bar\baz'), $name->slice(1));
$this->assertNull($name->slice(3));
$this->assertEquals(new Name('foo\bar\baz'), $name->slice(-3));
$this->assertEquals(new Name('bar\baz'), $name->slice(-2));
$this->assertEquals(new Name('foo\bar'), $name->slice(0, -1));
$this->assertNull($name->slice(0, -3));
$this->assertEquals(new Name('bar'), $name->slice(1, -1));
$this->assertNull($name->slice(1, -2));
$this->assertEquals(new Name('bar'), $name->slice(-2, 1));
$this->assertEquals(new Name('bar'), $name->slice(-2, -1));
$this->assertNull($name->slice(-2, -2));
}
/**
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Offset 4 is out of bounds
*/
public function testSliceException() {
public function testSliceOffsetTooLarge() {
(new Name('foo\bar\baz'))->slice(4);
}
/**
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Offset -4 is out of bounds
*/
public function testSliceOffsetTooSmall() {
(new Name('foo\bar\baz'))->slice(-4);
}
/**
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Length 4 is out of bounds
*/
public function testSliceLengthTooLarge() {
(new Name('foo\bar\baz'))->slice(0, 4);
}
/**
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Length -4 is out of bounds
*/
public function testSliceLengthTooSmall() {
(new Name('foo\bar\baz'))->slice(0, -4);
}
public function testConcat() {
$this->assertEquals(new Name('foo\bar\baz'), Name::concat('foo', 'bar\baz'));
$this->assertEquals(
@@ -123,42 +96,78 @@ class NameTest extends \PHPUnit_Framework_TestCase
Name\Relative::concat(new Name\FullyQualified('foo\bar'), 'baz', $attributes)
);
$this->assertEquals(new Name('foo'), Name::concat([], 'foo'));
$this->assertEquals(new Name([]), Name::concat([], []));
$this->assertEquals(new Name('foo'), Name::concat(null, 'foo'));
$this->assertEquals(new Name('foo'), Name::concat('foo', null));
$this->assertNull(Name::concat(null, null));
}
public function testIs() {
public function testNameTypes() {
$name = new Name('foo');
$this->assertTrue ($name->isUnqualified());
$this->assertTrue($name->isUnqualified());
$this->assertFalse($name->isQualified());
$this->assertFalse($name->isFullyQualified());
$this->assertFalse($name->isRelative());
$this->assertSame('foo', $name->toCodeString());
$name = new Name('foo\bar');
$this->assertFalse($name->isUnqualified());
$this->assertTrue ($name->isQualified());
$this->assertTrue($name->isQualified());
$this->assertFalse($name->isFullyQualified());
$this->assertFalse($name->isRelative());
$this->assertSame('foo\bar', $name->toCodeString());
$name = new Name\FullyQualified('foo');
$this->assertFalse($name->isUnqualified());
$this->assertFalse($name->isQualified());
$this->assertTrue ($name->isFullyQualified());
$this->assertTrue($name->isFullyQualified());
$this->assertFalse($name->isRelative());
$this->assertSame('\foo', $name->toCodeString());
$name = new Name\Relative('foo');
$this->assertFalse($name->isUnqualified());
$this->assertFalse($name->isQualified());
$this->assertFalse($name->isFullyQualified());
$this->assertTrue ($name->isRelative());
$this->assertTrue($name->isRelative());
$this->assertSame('namespace\foo', $name->toCodeString());
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage When changing a name you need to pass either a string, an array or a Name node
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Expected string, array of parts or Name instance
*/
public function testInvalidArg() {
$name = new Name('foo');
$name->set(new \stdClass);
Name::concat('foo', new \stdClass);
}
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Name cannot be empty
*/
public function testInvalidEmptyString() {
new Name('');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Name cannot be empty
*/
public function testInvalidEmptyArray() {
new Name([]);
}
/** @dataProvider provideTestIsSpecialClassName */
public function testIsSpecialClassName($name, $expected) {
$name = new Name($name);
$this->assertSame($expected, $name->isSpecialClassName());
}
public function provideTestIsSpecialClassName() {
return [
['self', true],
['PARENT', true],
['Static', true],
['self\not', false],
['not\self', false],
];
}
}

View File

@@ -1,8 +1,11 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Node\Scalar;
class MagicConstTest extends \PHPUnit_Framework_TestCase {
use PHPUnit\Framework\TestCase;
class MagicConstTest extends TestCase
{
/**
* @dataProvider provideTestGetName
*/
@@ -11,15 +14,15 @@ class MagicConstTest extends \PHPUnit_Framework_TestCase {
}
public function provideTestGetName() {
return array(
array(new MagicConst\Class_, '__CLASS__'),
array(new MagicConst\Dir, '__DIR__'),
array(new MagicConst\File, '__FILE__'),
array(new MagicConst\Function_, '__FUNCTION__'),
array(new MagicConst\Line, '__LINE__'),
array(new MagicConst\Method, '__METHOD__'),
array(new MagicConst\Namespace_, '__NAMESPACE__'),
array(new MagicConst\Trait_, '__TRAIT__'),
);
return [
[new MagicConst\Class_, '__CLASS__'],
[new MagicConst\Dir, '__DIR__'],
[new MagicConst\File, '__FILE__'],
[new MagicConst\Function_, '__FUNCTION__'],
[new MagicConst\Line, '__LINE__'],
[new MagicConst\Method, '__METHOD__'],
[new MagicConst\Namespace_, '__NAMESPACE__'],
[new MagicConst\Trait_, '__TRAIT__'],
];
}
}
}

View File

@@ -1,8 +1,10 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Node\Scalar;
class StringTest extends \PHPUnit_Framework_TestCase
use PHPUnit\Framework\TestCase;
class StringTest extends TestCase
{
/**
* @dataProvider provideTestParseEscapeSequences
@@ -25,34 +27,34 @@ class StringTest extends \PHPUnit_Framework_TestCase
}
public function provideTestParseEscapeSequences() {
return array(
array('"', '\\"', '"'),
array('\\"', '\\"', '`'),
array('\\"\\`', '\\"\\`', null),
array("\\\$\n\r\t\f\v", '\\\\\$\n\r\t\f\v', null),
array("\x1B", '\e', null),
array(chr(255), '\xFF', null),
array(chr(255), '\377', null),
array(chr(0), '\400', null),
array("\0", '\0', null),
array('\xFF', '\\\\xFF', null),
);
return [
['"', '\\"', '"'],
['\\"', '\\"', '`'],
['\\"\\`', '\\"\\`', null],
["\\\$\n\r\t\f\v", '\\\\\$\n\r\t\f\v', null],
["\x1B", '\e', null],
[chr(255), '\xFF', null],
[chr(255), '\377', null],
[chr(0), '\400', null],
["\0", '\0', null],
['\xFF', '\\\\xFF', null],
];
}
public function provideTestParse() {
$tests = array(
array('A', '\'A\''),
array('A', 'b\'A\''),
array('A', '"A"'),
array('A', 'b"A"'),
array('\\', '\'\\\\\''),
array('\'', '\'\\\'\''),
);
$tests = [
['A', '\'A\''],
['A', 'b\'A\''],
['A', '"A"'],
['A', 'b"A"'],
['\\', '\'\\\\\''],
['\'', '\'\\\'\''],
];
foreach ($this->provideTestParseEscapeSequences() as $i => $test) {
// skip second and third tests, they aren't for double quotes
if ($i != 1 && $i != 2) {
$tests[] = array($test[0], '"' . $test[1] . '"');
if ($i !== 1 && $i !== 2) {
$tests[] = [$test[0], '"' . $test[1] . '"'];
}
}

View File

@@ -0,0 +1,36 @@
<?php declare(strict_types=1);
namespace PhpParser\Node\Stmt;
use PHPUnit\Framework\TestCase;
class ClassConstTest extends TestCase
{
/**
* @dataProvider provideModifiers
*/
public function testModifiers($modifier) {
$node = new ClassConst(
[], // invalid
constant('PhpParser\Node\Stmt\Class_::MODIFIER_' . strtoupper($modifier))
);
$this->assertTrue($node->{'is' . $modifier}());
}
public function testNoModifiers() {
$node = new ClassConst([], 0);
$this->assertTrue($node->isPublic());
$this->assertFalse($node->isProtected());
$this->assertFalse($node->isPrivate());
}
public function provideModifiers() {
return [
['public'],
['protected'],
['private'],
];
}
}

View File

@@ -1,22 +1,27 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Node\Stmt;
class ClassMethodTest extends \PHPUnit_Framework_TestCase
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name;
use PhpParser\Node\Param;
use PHPUnit\Framework\TestCase;
class ClassMethodTest extends TestCase
{
/**
* @dataProvider provideModifiers
*/
public function testModifiers($modifier) {
$node = new ClassMethod('foo', array(
$node = new ClassMethod('foo', [
'type' => constant('PhpParser\Node\Stmt\Class_::MODIFIER_' . strtoupper($modifier))
));
]);
$this->assertTrue($node->{'is' . $modifier}());
}
public function testNoModifiers() {
$node = new ClassMethod('foo', array('type' => 0));
$node = new ClassMethod('foo', ['type' => 0]);
$this->assertTrue($node->isPublic());
$this->assertFalse($node->isProtected());
@@ -24,17 +29,18 @@ class ClassMethodTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($node->isAbstract());
$this->assertFalse($node->isFinal());
$this->assertFalse($node->isStatic());
$this->assertFalse($node->isMagic());
}
public function provideModifiers() {
return array(
array('public'),
array('protected'),
array('private'),
array('abstract'),
array('final'),
array('static'),
);
return [
['public'],
['protected'],
['private'],
['abstract'],
['final'],
['static'],
];
}
/**
@@ -42,22 +48,77 @@ class ClassMethodTest extends \PHPUnit_Framework_TestCase
*
* @dataProvider implicitPublicModifiers
*
* @param integer $modifier Node type modifier
* @param string $modifier Node type modifier
*/
public function testImplicitPublic($modifier)
public function testImplicitPublic(string $modifier)
{
$node = new ClassMethod('foo', array(
$node = new ClassMethod('foo', [
'type' => constant('PhpParser\Node\Stmt\Class_::MODIFIER_' . strtoupper($modifier))
));
]);
$this->assertTrue($node->isPublic(), 'Node should be implicitly public');
}
public function implicitPublicModifiers() {
return array(
array('abstract'),
array('final'),
array('static'),
);
return [
['abstract'],
['final'],
['static'],
];
}
/**
* @dataProvider provideMagics
*
* @param string $name Node name
*/
public function testMagic(string $name) {
$node = new ClassMethod($name);
$this->assertTrue($node->isMagic(), 'Method should be magic');
}
public function provideMagics() {
return [
['__construct'],
['__DESTRUCT'],
['__caLL'],
['__callstatic'],
['__get'],
['__set'],
['__isset'],
['__unset'],
['__sleep'],
['__wakeup'],
['__tostring'],
['__set_state'],
['__clone'],
['__invoke'],
['__debuginfo'],
];
}
public function testFunctionLike() {
$param = new Param(new Variable('a'));
$type = new Name('Foo');
$return = new Return_(new Variable('a'));
$method = new ClassMethod('test', [
'byRef' => false,
'params' => [$param],
'returnType' => $type,
'stmts' => [$return],
]);
$this->assertFalse($method->returnsByRef());
$this->assertSame([$param], $method->getParams());
$this->assertSame($type, $method->getReturnType());
$this->assertSame([$return], $method->getStmts());
$method = new ClassMethod('test', [
'byRef' => true,
'stmts' => null,
]);
$this->assertTrue($method->returnsByRef());
$this->assertNull($method->getStmts());
}
}

View File

@@ -1,11 +1,13 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Node\Stmt;
class ClassTest extends \PHPUnit_Framework_TestCase
use PHPUnit\Framework\TestCase;
class ClassTest extends TestCase
{
public function testIsAbstract() {
$class = new Class_('Foo', array('type' => Class_::MODIFIER_ABSTRACT));
$class = new Class_('Foo', ['type' => Class_::MODIFIER_ABSTRACT]);
$this->assertTrue($class->isAbstract());
$class = new Class_('Foo');
@@ -13,7 +15,7 @@ class ClassTest extends \PHPUnit_Framework_TestCase
}
public function testIsFinal() {
$class = new Class_('Foo', array('type' => Class_::MODIFIER_FINAL));
$class = new Class_('Foo', ['type' => Class_::MODIFIER_FINAL]);
$this->assertTrue($class->isFinal());
$class = new Class_('Foo');
@@ -21,21 +23,21 @@ class ClassTest extends \PHPUnit_Framework_TestCase
}
public function testGetMethods() {
$methods = array(
$methods = [
new ClassMethod('foo'),
new ClassMethod('bar'),
new ClassMethod('fooBar'),
);
$class = new Class_('Foo', array(
'stmts' => array(
new TraitUse(array()),
];
$class = new Class_('Foo', [
'stmts' => [
new TraitUse([]),
$methods[0],
new ClassConst(array()),
new ClassConst([]),
$methods[1],
new Property(0, array()),
new Property(0, []),
$methods[2],
)
));
]
]);
$this->assertSame($methods, $class->getMethods());
}
@@ -43,14 +45,14 @@ class ClassTest extends \PHPUnit_Framework_TestCase
public function testGetMethod() {
$methodConstruct = new ClassMethod('__CONSTRUCT');
$methodTest = new ClassMethod('test');
$class = new Class_('Foo', array(
'stmts' => array(
new ClassConst(array()),
$class = new Class_('Foo', [
'stmts' => [
new ClassConst([]),
$methodConstruct,
new Property(0, array()),
new Property(0, []),
$methodTest,
)
));
]
]);
$this->assertSame($methodConstruct, $class->getMethod('__construct'));
$this->assertSame($methodTest, $class->getMethod('test'));

View File

@@ -1,25 +1,26 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Node\Stmt;
use PhpParser\Node;
use PHPUnit\Framework\TestCase;
class InterfaceTest extends \PHPUnit_Framework_TestCase
class InterfaceTest extends TestCase
{
public function testGetMethods() {
$methods = array(
$methods = [
new ClassMethod('foo'),
new ClassMethod('bar'),
);
$interface = new Class_('Foo', array(
'stmts' => array(
new Node\Stmt\ClassConst(array(new Node\Const_('C1', new Node\Scalar\String_('C1')))),
];
$interface = new Class_('Foo', [
'stmts' => [
new Node\Stmt\ClassConst([new Node\Const_('C1', new Node\Scalar\String_('C1'))]),
$methods[0],
new Node\Stmt\ClassConst(array(new Node\Const_('C2', new Node\Scalar\String_('C2')))),
new Node\Stmt\ClassConst([new Node\Const_('C2', new Node\Scalar\String_('C2'))]),
$methods[1],
new Node\Stmt\ClassConst(array(new Node\Const_('C3', new Node\Scalar\String_('C3')))),
)
));
new Node\Stmt\ClassConst([new Node\Const_('C3', new Node\Scalar\String_('C3'))]),
]
]);
$this->assertSame($methods, $interface->getMethods());
}

View File

@@ -1,8 +1,10 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Node\Stmt;
class PropertyTest extends \PHPUnit_Framework_TestCase
use PHPUnit\Framework\TestCase;
class PropertyTest extends TestCase
{
/**
* @dataProvider provideModifiers
@@ -10,14 +12,14 @@ class PropertyTest extends \PHPUnit_Framework_TestCase
public function testModifiers($modifier) {
$node = new Property(
constant('PhpParser\Node\Stmt\Class_::MODIFIER_' . strtoupper($modifier)),
array() // invalid
[] // invalid
);
$this->assertTrue($node->{'is' . $modifier}());
}
public function testNoModifiers() {
$node = new Property(0, array());
$node = new Property(0, []);
$this->assertTrue($node->isPublic());
$this->assertFalse($node->isProtected());
@@ -26,7 +28,7 @@ class PropertyTest extends \PHPUnit_Framework_TestCase
}
public function testStaticImplicitlyPublic() {
$node = new Property(Class_::MODIFIER_STATIC, array());
$node = new Property(Class_::MODIFIER_STATIC, []);
$this->assertTrue($node->isPublic());
$this->assertFalse($node->isProtected());
$this->assertFalse($node->isPrivate());
@@ -34,11 +36,11 @@ class PropertyTest extends \PHPUnit_Framework_TestCase
}
public function provideModifiers() {
return array(
array('public'),
array('protected'),
array('private'),
array('static'),
);
return [
['public'],
['protected'],
['private'],
['static'],
];
}
}

View File

@@ -1,8 +1,11 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
class DummyNode extends NodeAbstract {
use PHPUnit\Framework\TestCase;
class DummyNode extends NodeAbstract
{
public $subNode1;
public $subNode2;
@@ -12,33 +15,38 @@ class DummyNode extends NodeAbstract {
$this->subNode2 = $subNode2;
}
public function getSubNodeNames() {
return array('subNode1', '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() {
public function getType() : string {
return 'Dummy';
}
}
class NodeAbstractTest extends \PHPUnit_Framework_TestCase
class NodeAbstractTest extends TestCase
{
public function provideNodes() {
$attributes = array(
$attributes = [
'startLine' => 10,
'comments' => array(
'endLine' => 11,
'startTokenPos' => 12,
'endTokenPos' => 13,
'startFilePos' => 14,
'endFilePos' => 15,
'comments' => [
new Comment('// Comment' . "\n"),
new Comment\Doc('/** doc comment */'),
),
);
],
];
$node = new DummyNode('value1', 'value2', $attributes);
$node->notSubNode = 'value3';
return array(
array($attributes, $node),
);
return [
[$attributes, $node],
];
}
/**
@@ -46,15 +54,22 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
*/
public function testConstruct(array $attributes, Node $node) {
$this->assertSame('Dummy', $node->getType());
$this->assertSame(array('subNode1', 'subNode2'), $node->getSubNodeNames());
$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->assertTrue(isset($node->subNode1));
$this->assertTrue(isset($node->subNode2));
$this->assertFalse(isset($node->subNode3));
$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;
}
@@ -64,20 +79,43 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
*/
public function testGetDocComment(array $attributes, Node $node) {
$this->assertSame('/** doc comment */', $node->getDocComment()->getText());
array_pop($node->getAttribute('comments')); // remove doc comment
$comments = $node->getComments();
array_pop($comments); // remove doc comment
$node->setAttribute('comments', $comments);
$this->assertNull($node->getDocComment());
array_pop($node->getAttribute('comments')); // remove comment
array_pop($comments); // remove comment
$node->setAttribute('comments', $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'));
}
/**
* @dataProvider provideNodes
*/
public function testChange(array $attributes, Node $node) {
// change of line
$node->setLine(15);
$this->assertSame(15, $node->getLine());
// direct modification
$node->subNode = 'newValue';
$this->assertSame('newValue', $node->subNode);
@@ -89,7 +127,7 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
// removal
unset($node->subNode);
$this->assertFalse(isset($node->subNode));
$this->assertObjectNotHasAttribute('subNode', $node);
}
/**
@@ -103,10 +141,10 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
if ($i === 0) {
$this->assertSame('subNode1', $key);
$this->assertSame('value1', $value);
} else if ($i === 1) {
} elseif ($i === 1) {
$this->assertSame('subNode2', $key);
$this->assertSame('value2', $value);
} else if ($i === 2) {
} elseif ($i === 2) {
$this->assertSame('notSubNode', $key);
$this->assertSame('value3', $value);
} else {
@@ -119,7 +157,7 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
public function testAttributes() {
/** @var $node Node */
$node = $this->getMockForAbstractClass('PhpParser\NodeAbstract');
$node = $this->getMockForAbstractClass(NodeAbstract::class);
$this->assertEmpty($node->getAttributes());
@@ -137,11 +175,153 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
$this->assertNull($node->getAttribute('null', 'default'));
$this->assertSame(
array(
[
'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'
<?php
// comment
/** doc comment */
function functionName(&$a = 0, $b = 1.0) {
echo 'Foo';
}
PHP;
$expected = <<<'JSON'
[
{
"nodeType": "Stmt_Function",
"byRef": false,
"name": {
"nodeType": "Identifier",
"name": "functionName",
"attributes": {
"startLine": 4,
"endLine": 4
}
},
"params": [
{
"nodeType": "Param",
"type": null,
"byRef": true,
"variadic": false,
"var": {
"nodeType": "Expr_Variable",
"name": "a",
"attributes": {
"startLine": 4,
"endLine": 4
}
},
"default": {
"nodeType": "Scalar_LNumber",
"value": 0,
"attributes": {
"startLine": 4,
"endLine": 4,
"kind": 10
}
},
"attributes": {
"startLine": 4,
"endLine": 4
}
},
{
"nodeType": "Param",
"type": null,
"byRef": false,
"variadic": false,
"var": {
"nodeType": "Expr_Variable",
"name": "b",
"attributes": {
"startLine": 4,
"endLine": 4
}
},
"default": {
"nodeType": "Scalar_DNumber",
"value": 1,
"attributes": {
"startLine": 4,
"endLine": 4
}
},
"attributes": {
"startLine": 4,
"endLine": 4
}
}
],
"returnType": null,
"stmts": [
{
"nodeType": "Stmt_Echo",
"exprs": [
{
"nodeType": "Scalar_String",
"value": "Foo",
"attributes": {
"startLine": 5,
"endLine": 5,
"kind": 1
}
}
],
"attributes": {
"startLine": 5,
"endLine": 5
}
}
],
"attributes": {
"startLine": 4,
"comments": [
{
"nodeType": "Comment",
"text": "\/\/ comment\n",
"line": 2,
"filePos": 6,
"tokenPos": 1
},
{
"nodeType": "Comment_Doc",
"text": "\/** doc comment *\/",
"line": 3,
"filePos": 17,
"tokenPos": 2
}
],
"endLine": 6
}
}
]
JSON;
$parser = new Parser\Php7(new Lexer());
$stmts = $parser->parse(canonicalize($code));
$json = json_encode($stmts, JSON_PRETTY_PRINT);
$this->assertEquals(canonicalize($expected), canonicalize($json));
}
}

View File

@@ -1,8 +1,10 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
class NodeDumperTest extends \PHPUnit_Framework_TestCase
use PHPUnit\Framework\TestCase;
class NodeDumperTest extends TestCase
{
private function canonicalize($string) {
return str_replace("\r\n", "\n", $string);
@@ -10,7 +12,6 @@ class NodeDumperTest extends \PHPUnit_Framework_TestCase
/**
* @dataProvider provideTestDump
* @covers PhpParser\NodeDumper::dump
*/
public function testDump($node, $dump) {
$dumper = new NodeDumper;
@@ -19,33 +20,33 @@ class NodeDumperTest extends \PHPUnit_Framework_TestCase
}
public function provideTestDump() {
return array(
array(
array(),
return [
[
[],
'array(
)'
),
array(
array('Foo', 'Bar', 'Key' => 'FooBar'),
],
[
['Foo', 'Bar', 'Key' => 'FooBar'],
'array(
0: Foo
1: Bar
Key: FooBar
)'
),
array(
new Node\Name(array('Hallo', 'World')),
],
[
new Node\Name(['Hallo', 'World']),
'Name(
parts: array(
0: Hallo
1: World
)
)'
),
array(
new Node\Expr\Array_(array(
],
[
new Node\Expr\Array_([
new Node\Expr\ArrayItem(new Node\Scalar\String_('Foo'))
)),
]),
'Expr_Array(
items: array(
0: Expr_ArrayItem(
@@ -57,8 +58,44 @@ class NodeDumperTest extends \PHPUnit_Framework_TestCase
)
)
)'
),
],
];
}
public function testDumpWithPositions() {
$parser = (new ParserFactory)->create(
ParserFactory::ONLY_PHP7,
new Lexer(['usedAttributes' => ['startLine', 'endLine', 'startFilePos', 'endFilePos']])
);
$dumper = new NodeDumper(['dumpPositions' => true]);
$code = "<?php\n\$a = 1;\necho \$a;";
$expected = <<<'OUT'
array(
0: Stmt_Expression[2:1 - 2:7](
expr: Expr_Assign[2:1 - 2:6](
var: Expr_Variable[2:1 - 2:2](
name: a
)
expr: Scalar_LNumber[2:6 - 2:6](
value: 1
)
)
)
1: Stmt_Echo[3:1 - 3:8](
exprs: array(
0: Expr_Variable[3:6 - 3:7](
name: a
)
)
)
)
OUT;
$stmts = $parser->parse($code);
$dump = $dumper->dump($stmts, $code);
$this->assertSame($this->canonicalize($expected), $this->canonicalize($dump));
}
/**

View File

@@ -0,0 +1,60 @@
<?php declare(strict_types=1);
namespace PhpParser;
use PhpParser\Node\Expr;
use PHPUnit\Framework\TestCase;
class NodeFinderTest extends TestCase
{
private function getStmtsAndVars() {
$assign = new Expr\Assign(new Expr\Variable('a'), new Expr\BinaryOp\Concat(
new Expr\Variable('b'), new Expr\Variable('c')
));
$stmts = [new Node\Stmt\Expression($assign)];
$vars = [$assign->var, $assign->expr->left, $assign->expr->right];
return [$stmts, $vars];
}
public function testFind() {
$finder = new NodeFinder;
list($stmts, $vars) = $this->getStmtsAndVars();
$varFilter = function(Node $node) {
return $node instanceof Expr\Variable;
};
$this->assertSame($vars, $finder->find($stmts, $varFilter));
$this->assertSame($vars, $finder->find($stmts[0], $varFilter));
$noneFilter = function () { return false; };
$this->assertSame([], $finder->find($stmts, $noneFilter));
}
public function testFindInstanceOf() {
$finder = new NodeFinder;
list($stmts, $vars) = $this->getStmtsAndVars();
$this->assertSame($vars, $finder->findInstanceOf($stmts, Expr\Variable::class));
$this->assertSame($vars, $finder->findInstanceOf($stmts[0], Expr\Variable::class));
$this->assertSame([], $finder->findInstanceOf($stmts, Expr\BinaryOp\Mul::class));
}
public function testFindFirst() {
$finder = new NodeFinder;
list($stmts, $vars) = $this->getStmtsAndVars();
$varFilter = function(Node $node) {
return $node instanceof Expr\Variable;
};
$this->assertSame($vars[0], $finder->findFirst($stmts, $varFilter));
$this->assertSame($vars[0], $finder->findFirst($stmts[0], $varFilter));
$noneFilter = function () { return false; };
$this->assertNull($finder->findFirst($stmts, $noneFilter));
}
public function testFindFirstInstanceOf() {
$finder = new NodeFinder;
list($stmts, $vars) = $this->getStmtsAndVars();
$this->assertSame($vars[0], $finder->findFirstInstanceOf($stmts, Expr\Variable::class));
$this->assertSame($vars[0], $finder->findFirstInstanceOf($stmts[0], Expr\Variable::class));
$this->assertNull($finder->findFirstInstanceOf($stmts, Expr\BinaryOp\Mul::class));
}
}

View File

@@ -1,19 +1,21 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar\String_;
use PhpParser\NodeVisitor;
use PHPUnit\Framework\TestCase;
class NodeTraverserTest extends \PHPUnit_Framework_TestCase
class NodeTraverserTest extends TestCase
{
public function testNonModifying() {
$str1Node = new String_('Foo');
$str2Node = new String_('Bar');
$echoNode = new Node\Stmt\Echo_(array($str1Node, $str2Node));
$stmts = array($echoNode);
$echoNode = new Node\Stmt\Echo_([$str1Node, $str2Node]);
$stmts = [$echoNode];
$visitor = $this->getMock('PhpParser\NodeVisitor');
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor->expects($this->at(0))->method('beforeTraverse')->with($stmts);
$visitor->expects($this->at(1))->method('enterNode')->with($echoNode);
@@ -36,13 +38,13 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
$printNode = new Expr\Print_($str1Node);
// first visitor changes the node, second verifies the change
$visitor1 = $this->getMock('PhpParser\NodeVisitor');
$visitor2 = $this->getMock('PhpParser\NodeVisitor');
$visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock();
// replace empty statements with string1 node
$visitor1->expects($this->at(0))->method('beforeTraverse')->with(array())
->will($this->returnValue(array($str1Node)));
$visitor2->expects($this->at(0))->method('beforeTraverse')->with(array($str1Node));
$visitor1->expects($this->at(0))->method('beforeTraverse')->with([])
->will($this->returnValue([$str1Node]));
$visitor2->expects($this->at(0))->method('beforeTraverse')->with([$str1Node]);
// replace string1 node with print node
$visitor1->expects($this->at(1))->method('enterNode')->with($str1Node)
@@ -65,32 +67,32 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
$visitor2->expects($this->at(4))->method('leaveNode')->with($str1Node);
// replace string1 node with empty statements again
$visitor1->expects($this->at(5))->method('afterTraverse')->with(array($str1Node))
->will($this->returnValue(array()));
$visitor2->expects($this->at(5))->method('afterTraverse')->with(array());
$visitor1->expects($this->at(5))->method('afterTraverse')->with([$str1Node])
->will($this->returnValue([]));
$visitor2->expects($this->at(5))->method('afterTraverse')->with([]);
$traverser = new NodeTraverser;
$traverser->addVisitor($visitor1);
$traverser->addVisitor($visitor2);
// as all operations are reversed we end where we start
$this->assertEquals(array(), $traverser->traverse(array()));
$this->assertEquals([], $traverser->traverse([]));
}
public function testRemove() {
$str1Node = new String_('Foo');
$str2Node = new String_('Bar');
$visitor = $this->getMock('PhpParser\NodeVisitor');
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
// remove the string1 node, leave the string2 node
$visitor->expects($this->at(2))->method('leaveNode')->with($str1Node)
->will($this->returnValue(false));
->will($this->returnValue(NodeTraverser::REMOVE_NODE));
$traverser = new NodeTraverser;
$traverser->addVisitor($visitor);
$this->assertEquals(array($str2Node), $traverser->traverse(array($str1Node, $str2Node)));
$this->assertEquals([$str2Node], $traverser->traverse([$str1Node, $str2Node]));
}
public function testMerge() {
@@ -100,31 +102,30 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
$strR1 = new String_('Replacement 1');
$strR2 = new String_('Replacement 2');
$visitor = $this->getMock('PhpParser\NodeVisitor');
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
// replace strMiddle with strR1 and strR2 by merge
$visitor->expects($this->at(4))->method('leaveNode')->with($strMiddle)
->will($this->returnValue(array($strR1, $strR2)));
->will($this->returnValue([$strR1, $strR2]));
$traverser = new NodeTraverser;
$traverser->addVisitor($visitor);
$this->assertEquals(
array($strStart, $strR1, $strR2, $strEnd),
$traverser->traverse(array($strStart, $strMiddle, $strEnd))
[$strStart, $strR1, $strR2, $strEnd],
$traverser->traverse([$strStart, $strMiddle, $strEnd])
);
}
public function testDeepArray() {
/**
* @expectedException \LogicException
* @expectedExceptionMessage Invalid node structure: Contains nested arrays
*/
public function testInvalidDeepArray() {
$strNode = new String_('Foo');
$stmts = array(array(array($strNode)));
$visitor = $this->getMock('PhpParser\NodeVisitor');
$visitor->expects($this->at(1))->method('enterNode')->with($strNode);
$stmts = [[[$strNode]]];
$traverser = new NodeTraverser;
$traverser->addVisitor($visitor);
$this->assertEquals($stmts, $traverser->traverse($stmts));
}
@@ -134,10 +135,10 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
$varNode = new Expr\Variable('foo');
$mulNode = new Expr\BinaryOp\Mul($varNode, $varNode);
$negNode = new Expr\UnaryMinus($mulNode);
$stmts = array($printNode, $negNode);
$stmts = [$printNode, $negNode];
$visitor1 = $this->getMock('PhpParser\NodeVisitor');
$visitor2 = $this->getMock('PhpParser\NodeVisitor');
$visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor1->expects($this->at(1))->method('enterNode')->with($printNode)
->will($this->returnValue(NodeTraverser::DONT_TRAVERSE_CHILDREN));
@@ -166,35 +167,84 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($stmts, $traverser->traverse($stmts));
}
public function testStopTraversal() {
$varNode1 = new Expr\Variable('a');
$varNode2 = new Expr\Variable('b');
$varNode3 = new Expr\Variable('c');
$mulNode = new Expr\BinaryOp\Mul($varNode1, $varNode2);
$printNode = new Expr\Print_($varNode3);
$stmts = [$mulNode, $printNode];
// From enterNode() with array parent
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor->expects($this->at(1))->method('enterNode')->with($mulNode)
->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL));
$visitor->expects($this->at(2))->method('afterTraverse');
$traverser = new NodeTraverser;
$traverser->addVisitor($visitor);
$this->assertEquals($stmts, $traverser->traverse($stmts));
// From enterNode with Node parent
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor->expects($this->at(2))->method('enterNode')->with($varNode1)
->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL));
$visitor->expects($this->at(3))->method('afterTraverse');
$traverser = new NodeTraverser;
$traverser->addVisitor($visitor);
$this->assertEquals($stmts, $traverser->traverse($stmts));
// From leaveNode with Node parent
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor->expects($this->at(3))->method('leaveNode')->with($varNode1)
->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL));
$visitor->expects($this->at(4))->method('afterTraverse');
$traverser = new NodeTraverser;
$traverser->addVisitor($visitor);
$this->assertEquals($stmts, $traverser->traverse($stmts));
// From leaveNode with array parent
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor->expects($this->at(6))->method('leaveNode')->with($mulNode)
->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL));
$visitor->expects($this->at(7))->method('afterTraverse');
$traverser = new NodeTraverser;
$traverser->addVisitor($visitor);
$this->assertEquals($stmts, $traverser->traverse($stmts));
// Check that pending array modifications are still carried out
$visitor = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor->expects($this->at(6))->method('leaveNode')->with($mulNode)
->will($this->returnValue(NodeTraverser::REMOVE_NODE));
$visitor->expects($this->at(7))->method('enterNode')->with($printNode)
->will($this->returnValue(NodeTraverser::STOP_TRAVERSAL));
$visitor->expects($this->at(8))->method('afterTraverse');
$traverser = new NodeTraverser;
$traverser->addVisitor($visitor);
$this->assertEquals([$printNode], $traverser->traverse($stmts));
}
public function testRemovingVisitor() {
$visitor1 = $this->getMock('PhpParser\NodeVisitor');
$visitor2 = $this->getMock('PhpParser\NodeVisitor');
$visitor3 = $this->getMock('PhpParser\NodeVisitor');
$visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor3 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$traverser = new NodeTraverser;
$traverser->addVisitor($visitor1);
$traverser->addVisitor($visitor2);
$traverser->addVisitor($visitor3);
$preExpected = array($visitor1, $visitor2, $visitor3);
$preExpected = [$visitor1, $visitor2, $visitor3];
$this->assertAttributeSame($preExpected, 'visitors', $traverser, 'The appropriate visitors have not been added');
$traverser->removeVisitor($visitor2);
$postExpected = array(0 => $visitor1, 2 => $visitor3);
$postExpected = [0 => $visitor1, 2 => $visitor3];
$this->assertAttributeSame($postExpected, 'visitors', $traverser, 'The appropriate visitors are not present after removal');
}
public function testCloneNodes() {
$stmts = array(new Node\Stmt\Echo_(array(new String_('Foo'), new String_('Bar'))));
$traverser = new NodeTraverser(true);
$this->assertNotSame($stmts, $traverser->traverse($stmts));
}
public function testNoCloneNodesByDefault() {
$stmts = array(new Node\Stmt\Echo_(array(new String_('Foo'), new String_('Bar'))));
public function testNoCloneNodes() {
$stmts = [new Node\Stmt\Echo_([new String_('Foo'), new String_('Bar')])];
$traverser = new NodeTraverser;
@@ -202,17 +252,61 @@ class NodeTraverserTest extends \PHPUnit_Framework_TestCase
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage leaveNode() may only return an array if the parent structure is an array
* @dataProvider provideTestInvalidReturn
*/
public function testReplaceByArrayOnlyAllowedIfParentIsArray() {
$stmts = array(new Node\Expr\UnaryMinus(new Node\Scalar\LNumber(42)));
public function testInvalidReturn($visitor, $message) {
$this->expectException(\LogicException::class);
$this->expectExceptionMessage($message);
$visitor = $this->getMock('PhpParser\NodeVisitor');
$visitor->method('leaveNode')->willReturn(array(new Node\Scalar\DNumber(42.0)));
$stmts = [new Node\Stmt\Expression(new Node\Scalar\LNumber(42))];
$traverser = new NodeTraverser();
$traverser->addVisitor($visitor);
$traverser->traverse($stmts);
}
public function provideTestInvalidReturn() {
$visitor1 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor1->expects($this->at(1))->method('enterNode')
->willReturn('foobar');
$visitor2 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor2->expects($this->at(2))->method('enterNode')
->willReturn('foobar');
$visitor3 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor3->expects($this->at(3))->method('leaveNode')
->willReturn('foobar');
$visitor4 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor4->expects($this->at(4))->method('leaveNode')
->willReturn('foobar');
$visitor5 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor5->expects($this->at(3))->method('leaveNode')
->willReturn([new Node\Scalar\DNumber(42.0)]);
$visitor6 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor6->expects($this->at(4))->method('leaveNode')
->willReturn(false);
$visitor7 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor7->expects($this->at(1))->method('enterNode')
->willReturn(new Node\Scalar\LNumber(42));
$visitor8 = $this->getMockBuilder(NodeVisitor::class)->getMock();
$visitor8->expects($this->at(2))->method('enterNode')
->willReturn(new Node\Stmt\Return_());
return [
[$visitor1, 'enterNode() returned invalid value of type string'],
[$visitor2, 'enterNode() returned invalid value of type string'],
[$visitor3, 'leaveNode() returned invalid value of type string'],
[$visitor4, 'leaveNode() returned invalid value of type string'],
[$visitor5, 'leaveNode() may only return an array if the parent structure is an array'],
[$visitor6, 'bool(false) return from leaveNode() no longer supported. Return NodeTraverser::REMOVE_NODE instead'],
[$visitor7, 'Trying to replace statement (Stmt_Expression) with expression (Scalar_LNumber). Are you missing a Stmt_Expression wrapper?'],
[$visitor8, 'Trying to replace expression (Scalar_LNumber) with statement (Stmt_Return)'],
];
}
}

View File

@@ -0,0 +1,54 @@
<?php declare(strict_types=1);
namespace PhpParser\NodeVisitor;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\NodeTraverser;
use PHPUnit\Framework\TestCase;
class FindingVisitorTest extends TestCase
{
public function testFindVariables() {
$traverser = new NodeTraverser();
$visitor = new FindingVisitor(function(Node $node) {
return $node instanceof Node\Expr\Variable;
});
$traverser->addVisitor($visitor);
$assign = new Expr\Assign(new Expr\Variable('a'), new Expr\BinaryOp\Concat(
new Expr\Variable('b'), new Expr\Variable('c')
));
$stmts = [new Node\Stmt\Expression($assign)];
$traverser->traverse($stmts);
$this->assertSame([
$assign->var,
$assign->expr->left,
$assign->expr->right,
], $visitor->getFoundNodes());
}
public function testFindAll() {
$traverser = new NodeTraverser();
$visitor = new FindingVisitor(function(Node $node) {
return true; // All nodes
});
$traverser->addVisitor($visitor);
$assign = new Expr\Assign(new Expr\Variable('a'), new Expr\BinaryOp\Concat(
new Expr\Variable('b'), new Expr\Variable('c')
));
$stmts = [new Node\Stmt\Expression($assign)];
$traverser->traverse($stmts);
$this->assertSame([
$stmts[0],
$assign,
$assign->var,
$assign->expr,
$assign->expr->left,
$assign->expr->right,
], $visitor->getFoundNodes());
}
}

View File

@@ -0,0 +1,39 @@
<?php declare(strict_types=1);
namespace PhpParser\NodeVisitor;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\NodeTraverser;
use PHPUnit\Framework\TestCase;
class FirstFindingVisitorTest extends TestCase
{
public function testFindFirstVariable() {
$traverser = new NodeTraverser();
$visitor = new FirstFindingVisitor(function(Node $node) {
return $node instanceof Node\Expr\Variable;
});
$traverser->addVisitor($visitor);
$assign = new Expr\Assign(new Expr\Variable('a'), new Expr\Variable('b'));
$stmts = [new Node\Stmt\Expression($assign)];
$traverser->traverse($stmts);
$this->assertSame($assign->var, $visitor->getFoundNode());
}
public function testFindNone() {
$traverser = new NodeTraverser();
$visitor = new FirstFindingVisitor(function(Node $node) {
return $node instanceof Node\Expr\BinaryOp;
});
$traverser->addVisitor($visitor);
$assign = new Expr\Assign(new Expr\Variable('a'), new Expr\Variable('b'));
$stmts = [new Node\Stmt\Expression($assign)];
$traverser->traverse($stmts);
$this->assertNull($visitor->getFoundNode());
}
}

View File

@@ -1,14 +1,15 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\NodeVisitor;
use PhpParser;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
use PhpParser\Node\Expr;
use PHPUnit\Framework\TestCase;
class NameResolverTest extends \PHPUnit_Framework_TestCase
class NameResolverTest extends TestCase
{
private function canonicalize($string) {
return str_replace("\r\n", "\n", $string);
@@ -118,8 +119,8 @@ namespace {
new \Hallo\Bar();
new \Bar();
new \Bar();
bar();
hi();
\bar();
\hi();
\Hallo\bar();
\foo\bar();
\bar();
@@ -199,9 +200,12 @@ interface A extends C, D {
public function a(A $a) : A;
}
function fn() : A {}
function fn2() : array {}
function() : A {};
function fn(A $a) : A {}
function fn2(array $a) : array {}
function(A $a) : A {};
function fn3(?A $a) : ?A {}
function fn4(?array $a) : ?array {}
A::b();
A::$b;
@@ -233,14 +237,20 @@ interface A extends \NS\C, \NS\D
{
public function a(\NS\A $a) : \NS\A;
}
function fn() : \NS\A
function fn(\NS\A $a) : \NS\A
{
}
function fn2() : array
function fn2(array $a) : array
{
}
function () : \NS\A {
function (\NS\A $a) : \NS\A {
};
function fn3(?\NS\A $a) : ?\NS\A
{
}
function fn4(?array $a) : ?array
{
}
\NS\A::b();
\NS\A::$b;
\NS\A::B;
@@ -270,7 +280,7 @@ EOC;
}
public function testNoResolveSpecialName() {
$stmts = array(new Node\Expr\New_(new Name('self')));
$stmts = [new Node\Expr\New_(new Name('self'))];
$traverser = new PhpParser\NodeTraverser;
$traverser->addVisitor(new NameResolver);
@@ -278,17 +288,17 @@ EOC;
$this->assertEquals($stmts, $traverser->traverse($stmts));
}
public function testAddNamespacedName() {
$nsStmts = array(
public function testAddDeclarationNamespacedName() {
$nsStmts = [
new Stmt\Class_('A'),
new Stmt\Interface_('B'),
new Stmt\Function_('C'),
new Stmt\Const_(array(
new Stmt\Const_([
new Node\Const_('D', new Node\Scalar\LNumber(42))
)),
]),
new Stmt\Trait_('E'),
new Expr\New_(new Stmt\Class_(null)),
);
];
$traverser = new PhpParser\NodeTraverser;
$traverser->addVisitor(new NameResolver);
@@ -310,57 +320,81 @@ EOC;
$this->assertObjectNotHasAttribute('namespacedName', $stmts[0]->stmts[5]->class);
}
public function testAddRuntimeResolvedNamespacedName() {
$stmts = [
new Stmt\Namespace_(new Name('NS'), [
new Expr\FuncCall(new Name('foo')),
new Expr\ConstFetch(new Name('FOO')),
]),
new Stmt\Namespace_(null, [
new Expr\FuncCall(new Name('foo')),
new Expr\ConstFetch(new Name('FOO')),
]),
];
$traverser = new PhpParser\NodeTraverser;
$traverser->addVisitor(new NameResolver);
$stmts = $traverser->traverse($stmts);
$this->assertSame('NS\\foo', (string) $stmts[0]->stmts[0]->name->getAttribute('namespacedName'));
$this->assertSame('NS\\FOO', (string) $stmts[0]->stmts[1]->name->getAttribute('namespacedName'));
$this->assertFalse($stmts[1]->stmts[0]->name->hasAttribute('namespacedName'));
$this->assertFalse($stmts[1]->stmts[1]->name->hasAttribute('namespacedName'));
}
/**
* @dataProvider provideTestError
*/
public function testError(Node $stmt, $errorMsg) {
$this->setExpectedException('PhpParser\Error', $errorMsg);
$this->expectException(\PhpParser\Error::class);
$this->expectExceptionMessage($errorMsg);
$traverser = new PhpParser\NodeTraverser;
$traverser->addVisitor(new NameResolver);
$traverser->traverse(array($stmt));
$traverser->traverse([$stmt]);
}
public function provideTestError() {
return array(
array(
new Stmt\Use_(array(
new Stmt\UseUse(new Name('A\B'), 'B', 0, array('startLine' => 1)),
new Stmt\UseUse(new Name('C\D'), 'B', 0, array('startLine' => 2)),
), Stmt\Use_::TYPE_NORMAL),
return [
[
new Stmt\Use_([
new Stmt\UseUse(new Name('A\B'), 'B', 0, ['startLine' => 1]),
new Stmt\UseUse(new Name('C\D'), 'B', 0, ['startLine' => 2]),
], Stmt\Use_::TYPE_NORMAL),
'Cannot use C\D as B because the name is already in use on line 2'
),
array(
new Stmt\Use_(array(
new Stmt\UseUse(new Name('a\b'), 'b', 0, array('startLine' => 1)),
new Stmt\UseUse(new Name('c\d'), 'B', 0, array('startLine' => 2)),
), Stmt\Use_::TYPE_FUNCTION),
],
[
new Stmt\Use_([
new Stmt\UseUse(new Name('a\b'), 'b', 0, ['startLine' => 1]),
new Stmt\UseUse(new Name('c\d'), 'B', 0, ['startLine' => 2]),
], Stmt\Use_::TYPE_FUNCTION),
'Cannot use function c\d as B because the name is already in use on line 2'
),
array(
new Stmt\Use_(array(
new Stmt\UseUse(new Name('A\B'), 'B', 0, array('startLine' => 1)),
new Stmt\UseUse(new Name('C\D'), 'B', 0, array('startLine' => 2)),
), Stmt\Use_::TYPE_CONSTANT),
],
[
new Stmt\Use_([
new Stmt\UseUse(new Name('A\B'), 'B', 0, ['startLine' => 1]),
new Stmt\UseUse(new Name('C\D'), 'B', 0, ['startLine' => 2]),
], Stmt\Use_::TYPE_CONSTANT),
'Cannot use const C\D as B because the name is already in use on line 2'
),
array(
new Expr\New_(new Name\FullyQualified('self', array('startLine' => 3))),
],
[
new Expr\New_(new Name\FullyQualified('self', ['startLine' => 3])),
"'\\self' is an invalid class name on line 3"
),
array(
new Expr\New_(new Name\Relative('self', array('startLine' => 3))),
],
[
new Expr\New_(new Name\Relative('self', ['startLine' => 3])),
"'\\self' is an invalid class name on line 3"
),
array(
new Expr\New_(new Name\FullyQualified('PARENT', array('startLine' => 3))),
],
[
new Expr\New_(new Name\FullyQualified('PARENT', ['startLine' => 3])),
"'\\PARENT' is an invalid class name on line 3"
),
array(
new Expr\New_(new Name\Relative('STATIC', array('startLine' => 3))),
],
[
new Expr\New_(new Name\Relative('STATIC', ['startLine' => 3])),
"'\\STATIC' is an invalid class name on line 3"
),
);
],
];
}
public function testClassNameIsCaseInsensitive()
@@ -381,7 +415,8 @@ EOC;
$stmts = $traverser->traverse($stmts);
$stmt = $stmts[0];
$this->assertSame(array('Bar', 'Baz'), $stmt->stmts[1]->expr->class->parts);
$assign = $stmt->stmts[1]->expr;
$this->assertSame(['Bar', 'Baz'], $assign->expr->class->parts);
}
public function testSpecialClassNamesAreCaseInsensitive() {
@@ -410,8 +445,49 @@ EOC;
$classStmt = $stmts[0];
$methodStmt = $classStmt->stmts[0]->stmts[0];
$this->assertSame('SELF', (string)$methodStmt->stmts[0]->class);
$this->assertSame('PARENT', (string)$methodStmt->stmts[1]->class);
$this->assertSame('STATIC', (string)$methodStmt->stmts[2]->class);
$this->assertSame('SELF', (string) $methodStmt->stmts[0]->expr->class);
$this->assertSame('PARENT', (string) $methodStmt->stmts[1]->expr->class);
$this->assertSame('STATIC', (string) $methodStmt->stmts[2]->expr->class);
}
public function testAddOriginalNames() {
$traverser = new PhpParser\NodeTraverser;
$traverser->addVisitor(new NameResolver(null, ['preserveOriginalNames' => true]));
$n1 = new Name('Bar');
$n2 = new Name('bar');
$origStmts = [
new Stmt\Namespace_(new Name('Foo'), [
new Expr\ClassConstFetch($n1, 'FOO'),
new Expr\FuncCall($n2),
])
];
$stmts = $traverser->traverse($origStmts);
$this->assertSame($n1, $stmts[0]->stmts[0]->class->getAttribute('originalName'));
$this->assertSame($n2, $stmts[0]->stmts[1]->name->getAttribute('originalName'));
}
public function testAttributeOnlyMode() {
$traverser = new PhpParser\NodeTraverser;
$traverser->addVisitor(new NameResolver(null, ['replaceNodes' => false]));
$n1 = new Name('Bar');
$n2 = new Name('bar');
$origStmts = [
new Stmt\Namespace_(new Name('Foo'), [
new Expr\ClassConstFetch($n1, 'FOO'),
new Expr\FuncCall($n2),
])
];
$traverser->traverse($origStmts);
$this->assertEquals(
new Name\FullyQualified('Foo\Bar'), $n1->getAttribute('resolvedName'));
$this->assertFalse($n2->hasAttribute('resolvedName'));
$this->assertEquals(
new Name\FullyQualified('Foo\bar'), $n2->getAttribute('namespacedName'));
}
}

View File

@@ -1,17 +1,18 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Parser;
use PhpParser\Error;
use PhpParser\Lexer;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\ParserTest;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Stmt;
use PhpParser\ParserTest;
require_once __DIR__ . '/../ParserTest.php';
class MultipleTest extends ParserTest {
class MultipleTest extends ParserTest
{
// This provider is for the generic parser tests, just pick an arbitrary order here
protected function getParser(Lexer $lexer) {
return new Multiple([new Php5($lexer), new Php7($lexer)]);
@@ -30,7 +31,6 @@ class MultipleTest extends ParserTest {
/** @dataProvider provideTestParse */
public function testParse($code, Multiple $parser, $expected) {
$this->assertEquals($expected, $parser->parse($code));
$this->assertSame([], $parser->getErrors());
}
public function provideTestParse() {
@@ -60,9 +60,9 @@ class MultipleTest extends ParserTest {
'<?php $$a[0];',
$this->getPrefer5(),
[
new Expr\Variable(
new Stmt\Expression(new Expr\Variable(
new Expr\ArrayDimFetch(new Expr\Variable('a'), LNumber::fromString('0'))
)
))
]
],
[
@@ -70,44 +70,27 @@ class MultipleTest extends ParserTest {
'<?php $$a[0];',
$this->getPrefer7(),
[
new Expr\ArrayDimFetch(
new Stmt\Expression(new Expr\ArrayDimFetch(
new Expr\Variable(new Expr\Variable('a')), LNumber::fromString('0')
)
))
]
],
];
}
public function testThrownError() {
$this->setExpectedException('PhpParser\Error', 'FAIL A');
$this->expectException(Error::class);
$this->expectExceptionMessage('FAIL A');
$parserA = $this->getMockBuilder('PhpParser\Parser')->getMock();
$parserA = $this->getMockBuilder(\PhpParser\Parser::class)->getMock();
$parserA->expects($this->at(0))
->method('parse')->will($this->throwException(new Error('FAIL A')));
$parserB = $this->getMockBuilder('PhpParser\Parser')->getMock();
$parserB = $this->getMockBuilder(\PhpParser\Parser::class)->getMock();
$parserB->expects($this->at(0))
->method('parse')->will($this->throwException(new Error('FAIL B')));
$parser = new Multiple([$parserA, $parserB]);
$parser->parse('dummy');
}
public function testGetErrors() {
$errorsA = [new Error('A1'), new Error('A2')];
$parserA = $this->getMockBuilder('PhpParser\Parser')->getMock();
$parserA->expects($this->at(0))->method('parse');
$parserA->expects($this->at(1))
->method('getErrors')->will($this->returnValue($errorsA));
$errorsB = [new Error('B1'), new Error('B2')];
$parserB = $this->getMockBuilder('PhpParser\Parser')->getMock();
$parserB->expects($this->at(0))->method('parse');
$parserB->expects($this->at(1))
->method('getErrors')->will($this->returnValue($errorsB));
$parser = new Multiple([$parserA, $parserB]);
$parser->parse('dummy');
$this->assertSame($errorsA, $parser->getErrors());
}
}
}

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Parser;
@@ -7,7 +7,8 @@ use PhpParser\ParserTest;
require_once __DIR__ . '/../ParserTest.php';
class Php5Test extends ParserTest {
class Php5Test extends ParserTest
{
protected function getParser(Lexer $lexer) {
return new Php5($lexer);
}

View File

@@ -1,4 +1,4 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser\Parser;
@@ -7,7 +7,8 @@ use PhpParser\ParserTest;
require_once __DIR__ . '/../ParserTest.php';
class Php7Test extends ParserTest {
class Php7Test extends ParserTest
{
protected function getParser(Lexer $lexer) {
return new Php7($lexer);
}

View File

@@ -1,10 +1,13 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
/* This test is very weak, because PHPUnit's assertEquals assertion is way too slow dealing with the
* large objects involved here. So we just do some basic instanceof tests instead. */
class ParserFactoryTest extends \PHPUnit_Framework_TestCase {
use PHPUnit\Framework\TestCase;
class ParserFactoryTest extends TestCase
{
/** @dataProvider provideTestCreate */
public function testCreate($kind, $lexer, $expected) {
$this->assertInstanceOf($expected, (new ParserFactory)->create($kind, $lexer));
@@ -15,20 +18,20 @@ class ParserFactoryTest extends \PHPUnit_Framework_TestCase {
return [
[
ParserFactory::PREFER_PHP7, $lexer,
'PhpParser\Parser\Multiple'
Parser\Multiple::class
],
[
ParserFactory::PREFER_PHP5, null,
'PhpParser\Parser\Multiple'
Parser\Multiple::class
],
[
ParserFactory::ONLY_PHP7, null,
'PhpParser\Parser\Php7'
Parser\Php7::class
],
[
ParserFactory::ONLY_PHP5, $lexer,
'PhpParser\Parser\Php5'
Parser\Php5::class
]
];
}
}
}

View File

@@ -1,13 +1,14 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
use PhpParser\Comment;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt;
use PHPUnit\Framework\TestCase;
abstract class ParserTest extends \PHPUnit_Framework_TestCase
abstract class ParserTest extends TestCase
{
/** @returns Parser */
abstract protected function getParser(Lexer $lexer);
@@ -30,13 +31,22 @@ abstract class ParserTest extends \PHPUnit_Framework_TestCase
$parser->parse('<?php use foo as self;');
}
/**
* @expectedException \PhpParser\Error
* @expectedExceptionMessage Unterminated comment on line 1
*/
public function testParserThrowsLexerError() {
$parser = $this->getParser(new Lexer());
$parser->parse('<?php /*');
}
public function testAttributeAssignment() {
$lexer = new Lexer(array(
'usedAttributes' => array(
$lexer = new Lexer([
'usedAttributes' => [
'comments', 'startLine', 'endLine',
'startTokenPos', 'endTokenPos',
)
));
]
]);
$code = <<<'EOC'
<?php
@@ -52,51 +62,51 @@ EOC;
$parser = $this->getParser($lexer);
$stmts = $parser->parse($code);
/** @var \PhpParser\Node\Stmt\Function_ $fn */
/** @var Stmt\Function_ $fn */
$fn = $stmts[0];
$this->assertInstanceOf('PhpParser\Node\Stmt\Function_', $fn);
$this->assertEquals(array(
'comments' => array(
new Comment\Doc('/** Doc comment */', 2, 6),
),
$this->assertInstanceOf(Stmt\Function_::class, $fn);
$this->assertEquals([
'comments' => [
new Comment\Doc('/** Doc comment */', 2, 6, 1),
],
'startLine' => 3,
'endLine' => 7,
'startTokenPos' => 3,
'endTokenPos' => 21,
), $fn->getAttributes());
], $fn->getAttributes());
$param = $fn->params[0];
$this->assertInstanceOf('PhpParser\Node\Param', $param);
$this->assertEquals(array(
$this->assertInstanceOf(Node\Param::class, $param);
$this->assertEquals([
'startLine' => 3,
'endLine' => 3,
'startTokenPos' => 7,
'endTokenPos' => 7,
), $param->getAttributes());
], $param->getAttributes());
/** @var \PhpParser\Node\Stmt\Echo_ $echo */
/** @var Stmt\Echo_ $echo */
$echo = $fn->stmts[0];
$this->assertInstanceOf('PhpParser\Node\Stmt\Echo_', $echo);
$this->assertEquals(array(
'comments' => array(
new Comment("// Line\n", 4, 49),
new Comment("// Comments\n", 5, 61),
),
$this->assertInstanceOf(Stmt\Echo_::class, $echo);
$this->assertEquals([
'comments' => [
new Comment("// Line\n", 4, 49, 12),
new Comment("// Comments\n", 5, 61, 14),
],
'startLine' => 6,
'endLine' => 6,
'startTokenPos' => 16,
'endTokenPos' => 19,
), $echo->getAttributes());
], $echo->getAttributes());
/** @var \PhpParser\Node\Expr\Variable $var */
$var = $echo->exprs[0];
$this->assertInstanceOf('PhpParser\Node\Expr\Variable', $var);
$this->assertEquals(array(
$this->assertInstanceOf(Expr\Variable::class, $var);
$this->assertEquals([
'startLine' => 6,
'endLine' => 6,
'startTokenPos' => 18,
'endTokenPos' => 18,
), $var->getAttributes());
], $var->getAttributes());
}
/**
@@ -110,60 +120,65 @@ EOC;
}
/**
* @dataProvider provideTestKindAttributes
* @dataProvider provideTestExtraAttributes
*/
public function testKindAttributes($code, $expectedAttributes) {
public function testExtraAttributes($code, $expectedAttributes) {
$parser = $this->getParser(new Lexer);
$stmts = $parser->parse("<?php $code;");
$attributes = $stmts[0]->getAttributes();
$node = $stmts[0] instanceof Stmt\Expression ? $stmts[0]->expr : $stmts[0];
$attributes = $node->getAttributes();
foreach ($expectedAttributes as $name => $value) {
$this->assertSame($value, $attributes[$name]);
}
}
public function provideTestKindAttributes() {
return array(
array('0', ['kind' => Scalar\LNumber::KIND_DEC]),
array('9', ['kind' => Scalar\LNumber::KIND_DEC]),
array('07', ['kind' => Scalar\LNumber::KIND_OCT]),
array('0xf', ['kind' => Scalar\LNumber::KIND_HEX]),
array('0XF', ['kind' => Scalar\LNumber::KIND_HEX]),
array('0b1', ['kind' => Scalar\LNumber::KIND_BIN]),
array('0B1', ['kind' => Scalar\LNumber::KIND_BIN]),
array('[]', ['kind' => Expr\Array_::KIND_SHORT]),
array('array()', ['kind' => Expr\Array_::KIND_LONG]),
array("'foo'", ['kind' => String_::KIND_SINGLE_QUOTED]),
array("b'foo'", ['kind' => String_::KIND_SINGLE_QUOTED]),
array("B'foo'", ['kind' => String_::KIND_SINGLE_QUOTED]),
array('"foo"', ['kind' => String_::KIND_DOUBLE_QUOTED]),
array('b"foo"', ['kind' => String_::KIND_DOUBLE_QUOTED]),
array('B"foo"', ['kind' => String_::KIND_DOUBLE_QUOTED]),
array('"foo$bar"', ['kind' => String_::KIND_DOUBLE_QUOTED]),
array('b"foo$bar"', ['kind' => String_::KIND_DOUBLE_QUOTED]),
array('B"foo$bar"', ['kind' => String_::KIND_DOUBLE_QUOTED]),
array("<<<'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR']),
array("<<<STR\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']),
array("<<<\"STR\"\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']),
array("b<<<'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR']),
array("B<<<'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR']),
array("<<< \t 'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR']),
// HHVM doesn't support this due to a lexer bug
// (https://github.com/facebook/hhvm/issues/6970)
// array("<<<'\xff'\n\xff\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => "\xff"]),
array("<<<\"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']),
array("b<<<\"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']),
array("B<<<\"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']),
array("<<< \t \"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']),
array("die", ['kind' => Expr\Exit_::KIND_DIE]),
array("die('done')", ['kind' => Expr\Exit_::KIND_DIE]),
array("exit", ['kind' => Expr\Exit_::KIND_EXIT]),
array("exit(1)", ['kind' => Expr\Exit_::KIND_EXIT]),
);
public function provideTestExtraAttributes() {
return [
['0', ['kind' => Scalar\LNumber::KIND_DEC]],
['9', ['kind' => Scalar\LNumber::KIND_DEC]],
['07', ['kind' => Scalar\LNumber::KIND_OCT]],
['0xf', ['kind' => Scalar\LNumber::KIND_HEX]],
['0XF', ['kind' => Scalar\LNumber::KIND_HEX]],
['0b1', ['kind' => Scalar\LNumber::KIND_BIN]],
['0B1', ['kind' => Scalar\LNumber::KIND_BIN]],
['[]', ['kind' => Expr\Array_::KIND_SHORT]],
['array()', ['kind' => Expr\Array_::KIND_LONG]],
["'foo'", ['kind' => String_::KIND_SINGLE_QUOTED]],
["b'foo'", ['kind' => String_::KIND_SINGLE_QUOTED]],
["B'foo'", ['kind' => String_::KIND_SINGLE_QUOTED]],
['"foo"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
['b"foo"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
['B"foo"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
['"foo$bar"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
['b"foo$bar"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
['B"foo$bar"', ['kind' => String_::KIND_DOUBLE_QUOTED]],
["<<<'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR']],
["<<<STR\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']],
["<<<\"STR\"\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']],
["b<<<'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR']],
["B<<<'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR']],
["<<< \t 'STR'\nSTR\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => 'STR']],
["<<<'\xff'\n\xff\n", ['kind' => String_::KIND_NOWDOC, 'docLabel' => "\xff"]],
["<<<\"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']],
["b<<<\"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']],
["B<<<\"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']],
["<<< \t \"STR\"\n\$a\nSTR\n", ['kind' => String_::KIND_HEREDOC, 'docLabel' => 'STR']],
["die", ['kind' => Expr\Exit_::KIND_DIE]],
["die('done')", ['kind' => Expr\Exit_::KIND_DIE]],
["exit", ['kind' => Expr\Exit_::KIND_EXIT]],
["exit(1)", ['kind' => Expr\Exit_::KIND_EXIT]],
["?>Foo", ['hasLeadingNewline' => false]],
["?>\nFoo", ['hasLeadingNewline' => true]],
["namespace Foo;", ['kind' => Stmt\Namespace_::KIND_SEMICOLON]],
["namespace Foo {}", ['kind' => Stmt\Namespace_::KIND_BRACED]],
["namespace {}", ['kind' => Stmt\Namespace_::KIND_BRACED]],
];
}
}
class InvalidTokenLexer extends Lexer {
public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) {
class InvalidTokenLexer extends Lexer
{
public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) : int {
$value = 'foobar';
return 999;
}

View File

@@ -1,11 +1,13 @@
<?php
<?php declare(strict_types=1);
namespace PhpParser;
use PhpParser\Comment;
use PhpParser\Node\Expr;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\DNumber;
use PhpParser\Node\Scalar\Encapsed;
use PhpParser\Node\Scalar\EncapsedStringPart;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt;
use PhpParser\PrettyPrinter\Standard;
@@ -43,7 +45,7 @@ class PrettyPrinterTest extends CodeTestAbstract
if ('php5' === $version) {
$this->assertSame($expected, $output5, $name);
$this->assertNotSame($expected, $output7, $name);
} else if ('php7' === $version) {
} elseif ('php7' === $version) {
$this->assertSame($expected, $output7, $name);
$this->assertNotSame($expected, $output5, $name);
} else {
@@ -54,7 +56,7 @@ class PrettyPrinterTest extends CodeTestAbstract
/**
* @dataProvider provideTestPrettyPrint
* @covers PhpParser\PrettyPrinter\Standard<extended>
* @covers \PhpParser\PrettyPrinter\Standard<extended>
*/
public function testPrettyPrint($name, $code, $expected, $mode) {
$this->doTestPrettyPrintMethod('prettyPrint', $name, $code, $expected, $mode);
@@ -62,7 +64,7 @@ class PrettyPrinterTest extends CodeTestAbstract
/**
* @dataProvider provideTestPrettyPrintFile
* @covers PhpParser\PrettyPrinter\Standard<extended>
* @covers \PhpParser\PrettyPrinter\Standard<extended>
*/
public function testPrettyPrintFile($name, $code, $expected, $mode) {
$this->doTestPrettyPrintMethod('prettyPrintFile', $name, $code, $expected, $mode);
@@ -84,9 +86,9 @@ class PrettyPrinterTest extends CodeTestAbstract
);
$this->assertEquals('($a + $b) * $c', $prettyPrinter->prettyPrintExpr($expr));
$expr = new Expr\Closure(array(
'stmts' => array(new Stmt\Return_(new String_("a\nb")))
));
$expr = new Expr\Closure([
'stmts' => [new Stmt\Return_(new String_("a\nb"))]
]);
$this->assertEquals("function () {\n return 'a\nb';\n}", $prettyPrinter->prettyPrintExpr($expr));
}
@@ -99,8 +101,8 @@ class PrettyPrinterTest extends CodeTestAbstract
}
private function parseModeLine($modeLine) {
$parts = explode(' ', $modeLine, 2);
$version = isset($parts[0]) ? $parts[0] : 'both';
$parts = explode(' ', (string) $modeLine, 2);
$version = $parts[0] ?? 'both';
$options = isset($parts[1]) ? json_decode($parts[1], true) : [];
return [$version, $options];
}
@@ -161,4 +163,153 @@ class PrettyPrinterTest extends CodeTestAbstract
[new Encapsed([new EncapsedStringPart("STR")], $heredoc), '"STR"'],
];
}
/** @dataProvider provideTestUnnaturalLiterals */
public function testUnnaturalLiterals($node, $expected) {
$prttyPrinter = new PrettyPrinter\Standard;
$result = $prttyPrinter->prettyPrintExpr($node);
$this->assertSame($expected, $result);
}
public function provideTestUnnaturalLiterals() {
return [
[new LNumber(-1), '-1'],
[new LNumber(-PHP_INT_MAX - 1), '(-' . PHP_INT_MAX . '-1)'],
[new LNumber(-1, ['kind' => LNumber::KIND_BIN]), '-0b1'],
[new LNumber(-1, ['kind' => LNumber::KIND_OCT]), '-01'],
[new LNumber(-1, ['kind' => LNumber::KIND_HEX]), '-0x1'],
[new DNumber(\INF), '\INF'],
[new DNumber(-\INF), '-\INF'],
[new DNumber(-\NAN), '\NAN'],
];
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot pretty-print AST with Error nodes
*/
public function testPrettyPrintWithError() {
$stmts = [new Stmt\Expression(
new Expr\PropertyFetch(new Expr\Variable('a'), new Expr\Error())
)];
$prettyPrinter = new PrettyPrinter\Standard;
$prettyPrinter->prettyPrint($stmts);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot pretty-print AST with Error nodes
*/
public function testPrettyPrintWithErrorInClassConstFetch() {
$stmts = [new Stmt\Expression(
new Expr\ClassConstFetch(new Name('Foo'), new Expr\Error())
)];
$prettyPrinter = new PrettyPrinter\Standard;
$prettyPrinter->prettyPrint($stmts);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot directly print EncapsedStringPart
*/
public function testPrettyPrintEncapsedStringPart() {
$expr = new Node\Scalar\EncapsedStringPart('foo');
$prettyPrinter = new PrettyPrinter\Standard;
$prettyPrinter->prettyPrintExpr($expr);
}
/**
* @dataProvider provideTestFormatPreservingPrint
* @covers \PhpParser\PrettyPrinter\Standard<extended>
*/
public function testFormatPreservingPrint($name, $code, $modification, $expected, $modeLine) {
$lexer = new Lexer\Emulative([
'usedAttributes' => [
'comments',
'startLine', 'endLine',
'startTokenPos', 'endTokenPos',
],
]);
$parser = new Parser\Php7($lexer);
$traverser = new NodeTraverser();
$traverser->addVisitor(new NodeVisitor\CloningVisitor());
$printer = new PrettyPrinter\Standard();
$oldStmts = $parser->parse($code);
$oldTokens = $lexer->getTokens();
$newStmts = $traverser->traverse($oldStmts);
/** @var callable $fn */
eval(<<<CODE
use PhpParser\Comment;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;
\$fn = function(&\$stmts) { $modification };
CODE
);
$fn($newStmts);
$newCode = $printer->printFormatPreserving($newStmts, $oldStmts, $oldTokens);
$this->assertSame(canonicalize($expected), canonicalize($newCode), $name);
}
public function provideTestFormatPreservingPrint() {
return $this->getTests(__DIR__ . '/../code/formatPreservation', 'test', 3);
}
/**
* @dataProvider provideTestRoundTripPrint
* @covers \PhpParser\PrettyPrinter\Standard<extended>
*/
public function testRoundTripPrint($name, $code, $expected, $modeLine) {
/**
* This test makes sure that the format-preserving pretty printer round-trips for all
* the pretty printer tests (i.e. returns the input if no changes occurred).
*/
list($version) = $this->parseModeLine($modeLine);
$lexer = new Lexer\Emulative([
'usedAttributes' => [
'comments',
'startLine', 'endLine',
'startTokenPos', 'endTokenPos',
],
]);
$parserClass = $version === 'php5' ? Parser\Php5::class : Parser\Php7::class;
/** @var Parser $parser */
$parser = new $parserClass($lexer);
$traverser = new NodeTraverser();
$traverser->addVisitor(new NodeVisitor\CloningVisitor());
$printer = new PrettyPrinter\Standard();
try {
$oldStmts = $parser->parse($code);
} catch (Error $e) {
// Can't do a format-preserving print on a file with errors
return;
}
$oldTokens = $lexer->getTokens();
$newStmts = $traverser->traverse($oldStmts);
$newCode = $printer->printFormatPreserving($newStmts, $oldStmts, $oldTokens);
$this->assertSame(canonicalize($code), canonicalize($newCode), $name);
}
public function provideTestRoundTripPrint() {
return array_merge(
$this->getTests(__DIR__ . '/../code/prettyPrinter', 'test'),
$this->getTests(__DIR__ . '/../code/parser', 'test')
);
}
}

View File

@@ -1,172 +0,0 @@
<?php
namespace PhpParser\Serializer;
use PhpParser;
class XMLTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers PhpParser\Serializer\XML<extended>
*/
public function testSerialize() {
$code = <<<CODE
<?php
// comment
/** doc comment */
function functionName(&\$a = 0, \$b = 1.0) {
echo 'Foo';
}
CODE;
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<AST xmlns:node="http://nikic.github.com/PHPParser/XML/node" xmlns:subNode="http://nikic.github.com/PHPParser/XML/subNode" xmlns:attribute="http://nikic.github.com/PHPParser/XML/attribute" xmlns:scalar="http://nikic.github.com/PHPParser/XML/scalar">
<scalar:array>
<node:Stmt_Function>
<attribute:startLine>
<scalar:int>4</scalar:int>
</attribute:startLine>
<attribute:comments>
<scalar:array>
<comment isDocComment="false" line="2">// comment
</comment>
<comment isDocComment="true" line="3">/** doc comment */</comment>
</scalar:array>
</attribute:comments>
<attribute:endLine>
<scalar:int>6</scalar:int>
</attribute:endLine>
<subNode:byRef>
<scalar:false/>
</subNode:byRef>
<subNode:name>
<scalar:string>functionName</scalar:string>
</subNode:name>
<subNode:params>
<scalar:array>
<node:Param>
<attribute:startLine>
<scalar:int>4</scalar:int>
</attribute:startLine>
<attribute:endLine>
<scalar:int>4</scalar:int>
</attribute:endLine>
<subNode:type>
<scalar:null/>
</subNode:type>
<subNode:byRef>
<scalar:true/>
</subNode:byRef>
<subNode:variadic>
<scalar:false/>
</subNode:variadic>
<subNode:name>
<scalar:string>a</scalar:string>
</subNode:name>
<subNode:default>
<node:Scalar_LNumber>
<attribute:startLine>
<scalar:int>4</scalar:int>
</attribute:startLine>
<attribute:endLine>
<scalar:int>4</scalar:int>
</attribute:endLine>
<attribute:kind>
<scalar:int>10</scalar:int>
</attribute:kind>
<subNode:value>
<scalar:int>0</scalar:int>
</subNode:value>
</node:Scalar_LNumber>
</subNode:default>
</node:Param>
<node:Param>
<attribute:startLine>
<scalar:int>4</scalar:int>
</attribute:startLine>
<attribute:endLine>
<scalar:int>4</scalar:int>
</attribute:endLine>
<subNode:type>
<scalar:null/>
</subNode:type>
<subNode:byRef>
<scalar:false/>
</subNode:byRef>
<subNode:variadic>
<scalar:false/>
</subNode:variadic>
<subNode:name>
<scalar:string>b</scalar:string>
</subNode:name>
<subNode:default>
<node:Scalar_DNumber>
<attribute:startLine>
<scalar:int>4</scalar:int>
</attribute:startLine>
<attribute:endLine>
<scalar:int>4</scalar:int>
</attribute:endLine>
<subNode:value>
<scalar:float>1</scalar:float>
</subNode:value>
</node:Scalar_DNumber>
</subNode:default>
</node:Param>
</scalar:array>
</subNode:params>
<subNode:returnType>
<scalar:null/>
</subNode:returnType>
<subNode:stmts>
<scalar:array>
<node:Stmt_Echo>
<attribute:startLine>
<scalar:int>5</scalar:int>
</attribute:startLine>
<attribute:endLine>
<scalar:int>5</scalar:int>
</attribute:endLine>
<subNode:exprs>
<scalar:array>
<node:Scalar_String>
<attribute:startLine>
<scalar:int>5</scalar:int>
</attribute:startLine>
<attribute:endLine>
<scalar:int>5</scalar:int>
</attribute:endLine>
<attribute:kind>
<scalar:int>1</scalar:int>
</attribute:kind>
<subNode:value>
<scalar:string>Foo</scalar:string>
</subNode:value>
</node:Scalar_String>
</scalar:array>
</subNode:exprs>
</node:Stmt_Echo>
</scalar:array>
</subNode:stmts>
</node:Stmt_Function>
</scalar:array>
</AST>
XML;
$parser = new PhpParser\Parser\Php7(new PhpParser\Lexer);
$serializer = new XML;
$code = str_replace("\r\n", "\n", $code);
$stmts = $parser->parse($code);
$this->assertXmlStringEqualsXmlString($xml, $serializer->serialize($stmts));
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Unexpected node type
*/
public function testError() {
$serializer = new XML;
$serializer->serialize(array(new \stdClass));
}
}

View File

@@ -1,150 +0,0 @@
<?php
namespace PhpParser\Unserializer;
use PhpParser\Node\Scalar;
use PhpParser\Comment;
class XMLTest extends \PHPUnit_Framework_TestCase
{
public function testNode() {
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<AST xmlns:node="http://nikic.github.com/PHPParser/XML/node" xmlns:subNode="http://nikic.github.com/PHPParser/XML/subNode" xmlns:attribute="http://nikic.github.com/PHPParser/XML/attribute" xmlns:scalar="http://nikic.github.com/PHPParser/XML/scalar">
<node:Scalar_String line="1" docComment="/** doc comment */">
<attribute:startLine>
<scalar:int>1</scalar:int>
</attribute:startLine>
<attribute:comments>
<scalar:array>
<comment isDocComment="false" line="2">// comment
</comment>
<comment isDocComment="true" line="3">/** doc comment */</comment>
</scalar:array>
</attribute:comments>
<subNode:value>
<scalar:string>Test</scalar:string>
</subNode:value>
</node:Scalar_String>
</AST>
XML;
$unserializer = new XML;
$this->assertEquals(
new Scalar\String_('Test', array(
'startLine' => 1,
'comments' => array(
new Comment('// comment' . "\n", 2),
new Comment\Doc('/** doc comment */', 3),
),
)),
$unserializer->unserialize($xml)
);
}
public function testEmptyNode() {
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<AST xmlns:node="http://nikic.github.com/PHPParser/XML/node">
<node:Scalar_MagicConst_Class />
</AST>
XML;
$unserializer = new XML;
$this->assertEquals(
new Scalar\MagicConst\Class_,
$unserializer->unserialize($xml)
);
}
public function testScalars() {
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<AST xmlns:scalar="http://nikic.github.com/PHPParser/XML/scalar">
<scalar:array>
<scalar:array></scalar:array>
<scalar:array/>
<scalar:string>test</scalar:string>
<scalar:string></scalar:string>
<scalar:string/>
<scalar:int>1</scalar:int>
<scalar:float>1</scalar:float>
<scalar:float>1.5</scalar:float>
<scalar:true/>
<scalar:false/>
<scalar:null/>
</scalar:array>
</AST>
XML;
$result = array(
array(), array(),
'test', '', '',
1,
1, 1.5,
true, false, null
);
$unserializer = new XML;
$this->assertEquals($result, $unserializer->unserialize($xml));
}
/**
* @expectedException \DomainException
* @expectedExceptionMessage AST root element not found
*/
public function testWrongRootElementError() {
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<notAST/>
XML;
$unserializer = new XML;
$unserializer->unserialize($xml);
}
/**
* @dataProvider provideTestErrors
*/
public function testErrors($xml, $errorMsg) {
$this->setExpectedException('DomainException', $errorMsg);
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<AST xmlns:scalar="http://nikic.github.com/PHPParser/XML/scalar"
xmlns:node="http://nikic.github.com/PHPParser/XML/node"
xmlns:subNode="http://nikic.github.com/PHPParser/XML/subNode"
xmlns:foo="http://nikic.github.com/PHPParser/XML/foo">
$xml
</AST>
XML;
$unserializer = new XML;
$unserializer->unserialize($xml);
}
public function provideTestErrors() {
return array(
array('<scalar:true>test</scalar:true>', '"true" scalar must be empty'),
array('<scalar:false>test</scalar:false>', '"false" scalar must be empty'),
array('<scalar:null>test</scalar:null>', '"null" scalar must be empty'),
array('<scalar:foo>bar</scalar:foo>', 'Unknown scalar type "foo"'),
array('<scalar:int>x</scalar:int>', '"x" is not a valid int'),
array('<scalar:float>x</scalar:float>', '"x" is not a valid float'),
array('', 'Expected node or scalar'),
array('<foo:bar>test</foo:bar>', 'Unexpected node of type "foo:bar"'),
array(
'<node:Scalar_String><foo:bar>test</foo:bar></node:Scalar_String>',
'Expected sub node or attribute, got node of type "foo:bar"'
),
array(
'<node:Scalar_String><subNode:value/></node:Scalar_String>',
'Expected node or scalar'
),
array(
'<node:Foo><subNode:value/></node:Foo>',
'Unknown node type "Foo"'
),
);
}
}