Security update for Core, with self-updated composer
[yaffs-website] / vendor / nikic / php-parser / test / PhpParser / NodeVisitor / NameResolverTest.php
diff --git a/vendor/nikic/php-parser/test/PhpParser/NodeVisitor/NameResolverTest.php b/vendor/nikic/php-parser/test/PhpParser/NodeVisitor/NameResolverTest.php
new file mode 100644 (file)
index 0000000..0313374
--- /dev/null
@@ -0,0 +1,468 @@
+<?php
+
+namespace PhpParser\NodeVisitor;
+
+use PhpParser;
+use PhpParser\Node;
+use PhpParser\Node\Expr;
+use PhpParser\Node\Name;
+use PhpParser\Node\Stmt;
+
+class NameResolverTest extends \PHPUnit_Framework_TestCase
+{
+    private function canonicalize($string) {
+        return str_replace("\r\n", "\n", $string);
+    }
+
+    /**
+     * @covers PhpParser\NodeVisitor\NameResolver
+     */
+    public function testResolveNames() {
+        $code = <<<'EOC'
+<?php
+
+namespace Foo {
+    use Hallo as Hi;
+
+    new Bar();
+    new Hi();
+    new Hi\Bar();
+    new \Bar();
+    new namespace\Bar();
+
+    bar();
+    hi();
+    Hi\bar();
+    foo\bar();
+    \bar();
+    namespace\bar();
+}
+namespace {
+    use Hallo as Hi;
+
+    new Bar();
+    new Hi();
+    new Hi\Bar();
+    new \Bar();
+    new namespace\Bar();
+
+    bar();
+    hi();
+    Hi\bar();
+    foo\bar();
+    \bar();
+    namespace\bar();
+}
+namespace Bar {
+    use function foo\bar as baz;
+    use const foo\BAR as BAZ;
+    use foo as bar;
+
+    bar();
+    baz();
+    bar\foo();
+    baz\foo();
+    BAR();
+    BAZ();
+    BAR\FOO();
+    BAZ\FOO();
+
+    bar;
+    baz;
+    bar\foo;
+    baz\foo;
+    BAR;
+    BAZ;
+    BAR\FOO;
+    BAZ\FOO;
+}
+namespace Baz {
+    use A\T\{B\C, D\E};
+    use function X\T\{b\c, d\e};
+    use const Y\T\{B\C, D\E};
+    use Z\T\{G, function f, const K};
+
+    new C;
+    new E;
+    new C\D;
+    new E\F;
+    new G;
+
+    c();
+    e();
+    f();
+    C;
+    E;
+    K;
+}
+EOC;
+        $expectedCode = <<<'EOC'
+namespace Foo {
+    use Hallo as Hi;
+    new \Foo\Bar();
+    new \Hallo();
+    new \Hallo\Bar();
+    new \Bar();
+    new \Foo\Bar();
+    bar();
+    hi();
+    \Hallo\bar();
+    \Foo\foo\bar();
+    \bar();
+    \Foo\bar();
+}
+namespace {
+    use Hallo as Hi;
+    new \Bar();
+    new \Hallo();
+    new \Hallo\Bar();
+    new \Bar();
+    new \Bar();
+    \bar();
+    \hi();
+    \Hallo\bar();
+    \foo\bar();
+    \bar();
+    \bar();
+}
+namespace Bar {
+    use function foo\bar as baz;
+    use const foo\BAR as BAZ;
+    use foo as bar;
+    bar();
+    \foo\bar();
+    \foo\foo();
+    \Bar\baz\foo();
+    BAR();
+    \foo\bar();
+    \foo\FOO();
+    \Bar\BAZ\FOO();
+    bar;
+    baz;
+    \foo\foo;
+    \Bar\baz\foo;
+    BAR;
+    \foo\BAR;
+    \foo\FOO;
+    \Bar\BAZ\FOO;
+}
+namespace Baz {
+    use A\T\{B\C, D\E};
+    use function X\T\{b\c, d\e};
+    use const Y\T\{B\C, D\E};
+    use Z\T\{G, function f, const K};
+    new \A\T\B\C();
+    new \A\T\D\E();
+    new \A\T\B\C\D();
+    new \A\T\D\E\F();
+    new \Z\T\G();
+    \X\T\b\c();
+    \X\T\d\e();
+    \Z\T\f();
+    \Y\T\B\C;
+    \Y\T\D\E;
+    \Z\T\K;
+}
+EOC;
+
+        $parser        = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
+        $prettyPrinter = new PhpParser\PrettyPrinter\Standard;
+        $traverser     = new PhpParser\NodeTraverser;
+        $traverser->addVisitor(new NameResolver);
+
+        $stmts = $parser->parse($code);
+        $stmts = $traverser->traverse($stmts);
+
+        $this->assertSame(
+            $this->canonicalize($expectedCode),
+            $prettyPrinter->prettyPrint($stmts)
+        );
+    }
+
+    /**
+     * @covers PhpParser\NodeVisitor\NameResolver
+     */
+    public function testResolveLocations() {
+        $code = <<<'EOC'
+<?php
+namespace NS;
+
+class A extends B implements C, D {
+    use E, F, G {
+        f as private g;
+        E::h as i;
+        E::j insteadof F, G;
+    }
+}
+
+interface A extends C, D {
+    public function a(A $a) : 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;
+A::B;
+new A;
+$a instanceof A;
+
+namespace\a();
+namespace\A;
+
+try {
+    $someThing;
+} catch (A $a) {
+    $someThingElse;
+}
+EOC;
+        $expectedCode = <<<'EOC'
+namespace NS;
+
+class A extends \NS\B implements \NS\C, \NS\D
+{
+    use \NS\E, \NS\F, \NS\G {
+        f as private g;
+        \NS\E::h as i;
+        \NS\E::j insteadof \NS\F, \NS\G;
+    }
+}
+interface A extends \NS\C, \NS\D
+{
+    public function a(\NS\A $a) : \NS\A;
+}
+function fn(\NS\A $a) : \NS\A
+{
+}
+function fn2(array $a) : array
+{
+}
+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;
+new \NS\A();
+$a instanceof \NS\A;
+\NS\a();
+\NS\A;
+try {
+    $someThing;
+} catch (\NS\A $a) {
+    $someThingElse;
+}
+EOC;
+
+        $parser        = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
+        $prettyPrinter = new PhpParser\PrettyPrinter\Standard;
+        $traverser     = new PhpParser\NodeTraverser;
+        $traverser->addVisitor(new NameResolver);
+
+        $stmts = $parser->parse($code);
+        $stmts = $traverser->traverse($stmts);
+
+        $this->assertSame(
+            $this->canonicalize($expectedCode),
+            $prettyPrinter->prettyPrint($stmts)
+        );
+    }
+
+    public function testNoResolveSpecialName() {
+        $stmts = array(new Node\Expr\New_(new Name('self')));
+
+        $traverser = new PhpParser\NodeTraverser;
+        $traverser->addVisitor(new NameResolver);
+
+        $this->assertEquals($stmts, $traverser->traverse($stmts));
+    }
+
+    public function testAddDeclarationNamespacedName() {
+        $nsStmts = array(
+            new Stmt\Class_('A'),
+            new Stmt\Interface_('B'),
+            new Stmt\Function_('C'),
+            new Stmt\Const_(array(
+                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);
+
+        $stmts = $traverser->traverse([new Stmt\Namespace_(new Name('NS'), $nsStmts)]);
+        $this->assertSame('NS\\A', (string) $stmts[0]->stmts[0]->namespacedName);
+        $this->assertSame('NS\\B', (string) $stmts[0]->stmts[1]->namespacedName);
+        $this->assertSame('NS\\C', (string) $stmts[0]->stmts[2]->namespacedName);
+        $this->assertSame('NS\\D', (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
+        $this->assertSame('NS\\E', (string) $stmts[0]->stmts[4]->namespacedName);
+        $this->assertObjectNotHasAttribute('namespacedName', $stmts[0]->stmts[5]->class);
+
+        $stmts = $traverser->traverse([new Stmt\Namespace_(null, $nsStmts)]);
+        $this->assertSame('A',     (string) $stmts[0]->stmts[0]->namespacedName);
+        $this->assertSame('B',     (string) $stmts[0]->stmts[1]->namespacedName);
+        $this->assertSame('C',     (string) $stmts[0]->stmts[2]->namespacedName);
+        $this->assertSame('D',     (string) $stmts[0]->stmts[3]->consts[0]->namespacedName);
+        $this->assertSame('E',     (string) $stmts[0]->stmts[4]->namespacedName);
+        $this->assertObjectNotHasAttribute('namespacedName', $stmts[0]->stmts[5]->class);
+    }
+
+    public function testAddRuntimeResolvedNamespacedName() {
+        $stmts = array(
+            new Stmt\Namespace_(new Name('NS'), array(
+                new Expr\FuncCall(new Name('foo')),
+                new Expr\ConstFetch(new Name('FOO')),
+            )),
+            new Stmt\Namespace_(null, array(
+                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);
+
+        $traverser = new PhpParser\NodeTraverser;
+        $traverser->addVisitor(new NameResolver);
+        $traverser->traverse(array($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),
+                '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),
+                '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),
+                '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))),
+                "'\\self' is an invalid class name on line 3"
+            ),
+            array(
+                new Expr\New_(new Name\Relative('self', array('startLine' => 3))),
+                "'\\self' is an invalid class name on line 3"
+            ),
+            array(
+                new Expr\New_(new Name\FullyQualified('PARENT', array('startLine' => 3))),
+                "'\\PARENT' is an invalid class name on line 3"
+            ),
+            array(
+                new Expr\New_(new Name\Relative('STATIC', array('startLine' => 3))),
+                "'\\STATIC' is an invalid class name on line 3"
+            ),
+        );
+    }
+
+    public function testClassNameIsCaseInsensitive()
+    {
+        $source = <<<'EOC'
+<?php
+namespace Foo;
+use Bar\Baz;
+$test = new baz();
+EOC;
+
+        $parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
+        $stmts = $parser->parse($source);
+
+        $traverser = new PhpParser\NodeTraverser;
+        $traverser->addVisitor(new NameResolver);
+
+        $stmts = $traverser->traverse($stmts);
+        $stmt = $stmts[0];
+
+        $this->assertSame(array('Bar', 'Baz'), $stmt->stmts[1]->expr->class->parts);
+    }
+
+    public function testSpecialClassNamesAreCaseInsensitive() {
+        $source = <<<'EOC'
+<?php
+namespace Foo;
+
+class Bar
+{
+    public static function method()
+    {
+        SELF::method();
+        PARENT::method();
+        STATIC::method();
+    }
+}
+EOC;
+
+        $parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative);
+        $stmts = $parser->parse($source);
+
+        $traverser = new PhpParser\NodeTraverser;
+        $traverser->addVisitor(new NameResolver);
+
+        $stmts = $traverser->traverse($stmts);
+        $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);
+    }
+
+    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'));
+    }
+}