File: ParserTest.php

package info (click to toggle)
doctrine 3.5.8%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,536 kB
  • sloc: php: 109,324; xml: 1,340; makefile: 35
file content (128 lines) | stat: -rw-r--r-- 4,221 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Query;

use Doctrine\ORM\Query;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Query\TokenType;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\OrmTestCase;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\DoesNotPerformAssertions;
use PHPUnit\Framework\Attributes\Group;
use stdClass;

class ParserTest extends OrmTestCase
{
    #[Group('DDC-3715')]
    public function testAbstractSchemaNameSupportsFQCN(): void
    {
        $parser = $this->createParser(CmsUser::class);

        self::assertEquals(CmsUser::class, $parser->AbstractSchemaName());
    }

    #[Group('DDC-3715')]
    public function testAbstractSchemaNameSupportsClassnamesWithLeadingBackslash(): void
    {
        $parser = $this->createParser('\\' . CmsUser::class);

        self::assertEquals('\\' . CmsUser::class, $parser->AbstractSchemaName());
    }

    #[Group('DDC-3715')]
    public function testAbstractSchemaNameSupportsIdentifier(): void
    {
        $parser = $this->createParser(stdClass::class);

        self::assertEquals(stdClass::class, $parser->AbstractSchemaName());
    }

    #[DataProvider('validMatches')]
    #[Group('DDC-3701')]
    #[DoesNotPerformAssertions]
    public function testMatch(TokenType $expectedToken, string $inputString): void
    {
        $parser = $this->createParser($inputString);

        $parser->match($expectedToken); // throws exception if not matched
    }

    #[DataProvider('invalidMatches')]
    #[Group('DDC-3701')]
    public function testMatchFailure(TokenType $expectedToken, string $inputString): void
    {
        $this->expectException(QueryException::class);

        $parser = $this->createParser($inputString);

        $parser->match($expectedToken);
    }

    /** @phpstan-return list<array{int, string}> */
    public static function validMatches(): array
    {
        /*
         * This only covers the special case handling in the Parser that some
         * tokens that are *not* T_IDENTIFIER are accepted as well when matching
         * identifiers.
         *
         * The basic checks that tokens are classified correctly do not belong here
         * but in LexerTest.
         */
        return [
            [TokenType::T_WHERE, 'where'], // keyword
            [TokenType::T_DOT, '.'], // token that cannot be an identifier
            [TokenType::T_IDENTIFIER, 'someIdentifier'],
            [TokenType::T_IDENTIFIER, 'from'], // also a terminal string (the "FROM" keyword) as in DDC-505
            [TokenType::T_IDENTIFIER, 'comma'],
            // not even a terminal string, but the name of a constant in the Lexer (whitebox test)
        ];
    }

    /** @phpstan-return list<array{int, string}> */
    public static function invalidMatches(): array
    {
        return [
            [TokenType::T_DOT, 'ALL'], // ALL is a terminal string (reserved keyword) and also possibly an identifier
            [TokenType::T_DOT, ','], // "," is a token on its own, but cannot be used as identifier
            [TokenType::T_WHERE, 'WITH'], // as in DDC-3697
            [TokenType::T_WHERE, '.'],

            // The following are qualified or aliased names and must not be accepted where only an Identifier is expected
            [TokenType::T_IDENTIFIER, '\\Some\\Class'],
            [TokenType::T_IDENTIFIER, 'Some\\Class'],
        ];
    }

    /**
     * PHP 7.4 would fail with Notice: Trying to access array offset on value of type null.
     *
     * @see https://github.com/doctrine/orm/pull/7934
     */
    #[Group('GH7934')]
    public function testNullLookahead(): void
    {
        $query = new Query($this->getTestEntityManager());
        $query->setDQL('SELECT CURRENT_TIMESTAMP()');

        $parser = new Parser($query);

        $this->expectException(QueryException::class);
        $parser->match(TokenType::T_SELECT);
    }

    private function createParser(string $dql): Parser
    {
        $query = new Query($this->getTestEntityManager());
        $query->setDQL($dql);

        $parser = new Parser($query);
        $parser->getLexer()->moveNext();

        return $parser;
    }
}