DefinedSymbolCollectorFunctionalTest   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 128
Duplicated Lines 0 %

Importance

Changes 8
Bugs 0 Features 1
Metric Value
wmc 12
eloc 46
c 8
b 0
f 1
dl 0
loc 128
rs 10

12 Methods

Rating   Name   Duplication   Size   Complexity  
A testTraitAdaptionDefinition() 0 7 1
A testWillCollectSymbolsDefinedInThisFile() 0 7 1
A traverseStringAST() 0 3 1
A testWillNotCollectNamespacedDefineCalls() 0 7 1
A testWillCollectNamespacedConstDefinition() 0 7 1
A testWillCollectNamespacedFunctionDefinition() 0 7 1
A setUp() 0 8 1
A testWillCollectDefinedConstDefinition() 0 7 1
A traverseClassAST() 0 5 1
A assertSameCollectedSymbols() 0 3 1
A testWillCollectConstDefinition() 0 7 1
A testWillCollectFunctionDefinition() 0 7 1
1
<?php
2
3
namespace ComposerRequireCheckerTest\NodeVisitor;
4
5
use ComposerRequireChecker\NodeVisitor\DefinedSymbolCollector;
6
use PhpParser\NodeTraverser;
7
use PhpParser\NodeTraverserInterface;
8
use PhpParser\NodeVisitor\NameResolver;
9
use PhpParser\Parser;
10
use PhpParser\ParserFactory;
11
use PHPUnit\Framework\TestCase;
12
13
/**
14
 * @coversNothing
15
 *
16
 * @group functional
17
 */
18
final class DefinedSymbolCollectorFunctionalTest extends TestCase
19
{
20
    /**
21
     * @var DefinedSymbolCollector
22
     */
23
    private $collector;
24
25
    /**
26
     * @var Parser
27
     */
28
    private $parser;
29
30
    /**
31
     * @var NodeTraverserInterface
32
     */
33
    private $traverser;
34
35
    /**
36
     * {@inheritDoc}
37
     */
38
    protected function setUp(): void
39
    {
40
        $this->collector = new DefinedSymbolCollector();
41
        $this->parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
42
        $this->traverser = new NodeTraverser();
43
44
        $this->traverser->addVisitor(new NameResolver());
45
        $this->traverser->addVisitor($this->collector);
46
    }
47
48
    public function testWillCollectSymbolsDefinedInThisFile(): void
49
    {
50
        $this->traverseClassAST(self::class);
51
52
        self::assertSameCollectedSymbols(
53
            ['ComposerRequireCheckerTest\NodeVisitor\DefinedSymbolCollectorFunctionalTest'],
54
            $this->collector->getDefinedSymbols()
55
        );
56
    }
57
58
    public function testWillCollectFunctionDefinition(): void
59
    {
60
        $this->traverseStringAST('function foo() {}');
61
62
        self::assertSameCollectedSymbols(
63
            ['foo'],
64
            $this->collector->getDefinedSymbols()
65
        );
66
    }
67
68
    public function testWillCollectNamespacedFunctionDefinition(): void
69
    {
70
        $this->traverseStringAST('namespace Foo; function foo() {}');
71
72
        self::assertSameCollectedSymbols(
73
            ['Foo\foo'],
74
            $this->collector->getDefinedSymbols()
75
        );
76
    }
77
78
    public function testWillCollectConstDefinition(): void
79
    {
80
        $this->traverseStringAST('const foo = "bar", baz = "tab";');
81
82
        self::assertSameCollectedSymbols(
83
            ['foo', 'baz'],
84
            $this->collector->getDefinedSymbols()
85
        );
86
    }
87
88
    public function testWillCollectNamespacedConstDefinition(): void
89
    {
90
        $this->traverseStringAST('namespace Foo; const foo = "bar", baz = "tab";');
91
92
        self::assertSameCollectedSymbols(
93
            ['Foo\foo', 'Foo\baz'],
94
            $this->collector->getDefinedSymbols()
95
        );
96
    }
97
98
    public function testWillCollectDefinedConstDefinition(): void
99
    {
100
        $this->traverseStringAST('define("CONST_A", "MY_VALUE"); define("FooSpace\CONST_A", "BAR"); define($foo, "BAR");');
101
102
        self::assertSameCollectedSymbols(
103
            ['CONST_A', 'FooSpace\CONST_A'],
104
            $this->collector->getDefinedSymbols()
105
        );
106
    }
107
108
    public function testWillNotCollectNamespacedDefineCalls(): void
109
    {
110
        $this->traverseStringAST('namespace Foo { function define($bar, $baz) {return;} define("NOT_A_CONST", "NOT_SOMETHING"); }');
111
112
        self::assertNotContains(
113
            'NOT_A_CONST',
114
            $this->collector->getDefinedSymbols()
115
        );
116
    }
117
118
    public function testTraitAdaptionDefinition(): void
119
    {
120
        $this->traverseStringAST('namespace Foo; trait BarTrait { protected function test(){}} class UseTrait { use BarTrait {test as public;} }');
121
122
        self::assertSameCollectedSymbols(
123
            ['Foo\BarTrait', 'Foo\UseTrait'],
124
            $this->collector->getDefinedSymbols()
125
        );
126
    }
127
128
129
    private function traverseStringAST(string $phpSource): array
130
    {
131
        return $this->traverser->traverse($this->parser->parse('<?php ' . $phpSource));
0 ignored issues
show
Bug introduced by
It seems like $this->parser->parse('<?php ' . $phpSource) can also be of type null; however, parameter $nodes of PhpParser\NodeTraverserInterface::traverse() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

131
        return $this->traverser->traverse(/** @scrutinizer ignore-type */ $this->parser->parse('<?php ' . $phpSource));
Loading history...
132
    }
133
134
    private function traverseClassAST(string $className): array
135
    {
136
        return $this->traverser->traverse(
137
            $this->parser->parse(
0 ignored issues
show
Bug introduced by
It seems like $this->parser->parse(fil...sName)->getFileName())) can also be of type null; however, parameter $nodes of PhpParser\NodeTraverserInterface::traverse() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

137
            /** @scrutinizer ignore-type */ $this->parser->parse(
Loading history...
138
                file_get_contents((new \ReflectionClass($className))->getFileName())
139
            )
140
        );
141
    }
142
143
    private static function assertSameCollectedSymbols(array $expected, array $actual): void
144
    {
145
        self::assertSame(array_diff($expected, $actual), array_diff($actual, $expected));
146
    }
147
}
148