Passed
Pull Request — master (#64)
by James
03:19
created

testAnonymousClassesAreFilteredOut()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 0
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace RoaveTest\BackwardCompatibility;
6
7
use PHPUnit\Framework\MockObject\MockObject;
8
use PHPUnit\Framework\TestCase;
9
use Roave\BackwardCompatibility\Change;
10
use Roave\BackwardCompatibility\Changes;
11
use Roave\BackwardCompatibility\CompareClasses;
12
use Roave\BackwardCompatibility\DetectChanges\BCBreak\ClassBased\ClassBased;
13
use Roave\BackwardCompatibility\DetectChanges\BCBreak\InterfaceBased\InterfaceBased;
14
use Roave\BackwardCompatibility\DetectChanges\BCBreak\TraitBased\TraitBased;
15
16
/**
17
 * @covers \Roave\BackwardCompatibility\CompareClasses
18
 */
19
final class CompareClassesTest extends TestCase
20
{
21
    /** @var StringReflectorFactory|null */
22
    private static $stringReflectorFactory;
23
24
    /** @var ClassBased|MockObject */
25
    private $classBasedComparison;
26
27
    /** @var InterfaceBased|MockObject */
28
    private $interfaceBasedComparison;
29
30
    /** @var TraitBased|MockObject */
31
    private $traitBasedComparison;
32
33
    /** @var CompareClasses */
34
    private $compareClasses;
35
36
    public static function setUpBeforeClass() : void
37
    {
38
        self::$stringReflectorFactory = new StringReflectorFactory();
39
    }
40
41
    protected function setUp() : void
42
    {
43
        parent::setUp();
44
45
        $this->classBasedComparison     = $this->createMock(ClassBased::class);
46
        $this->interfaceBasedComparison = $this->createMock(InterfaceBased::class);
47
        $this->traitBasedComparison     = $this->createMock(TraitBased::class);
48
        $this->compareClasses           = new CompareClasses(
49
            $this->classBasedComparison,
50
            $this->interfaceBasedComparison,
51
            $this->traitBasedComparison
52
        );
53
    }
54
55
    public function testWillRunSubComparators() : void
56
    {
57
        $this->classBasedComparatorWillBeCalled();
58
        $this->interfaceBasedComparatorWillNotBeCalled();
59
        $this->traitBasedComparatorWillNotBeCalled();
60
61
        self::assertEqualsIgnoringOrder(
62
            Changes::fromList(Change::changed('class change', true)),
63
            $this->compareClasses->__invoke(
64
                self::$stringReflectorFactory->__invoke('<?php class A {}'),
0 ignored issues
show
Bug introduced by
The method __invoke() does not exist on null. ( Ignorable by Annotation )

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

64
                self::$stringReflectorFactory->/** @scrutinizer ignore-call */ 
65
                                               __invoke('<?php class A {}'),

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
65
                self::$stringReflectorFactory->__invoke(
66
                    <<<'PHP'
67
<?php
68
69
class A {
70
    const A_CONSTANT = 'foo';
71
    public $aProperty;
72
    public function aMethod() {}
73
}
74
PHP
75
                ),
76
                self::$stringReflectorFactory->__invoke(
77
                    <<<'PHP'
78
<?php
79
80
class A {
81
    const A_CONSTANT = 'foo';
82
    public $aProperty;
83
    public function aMethod() {}
84
}
85
PHP
86
                )
87
            )
88
        );
89
    }
90
91
    public function testWillNotRunSubComparatorsIfSymbolsWereDeleted() : void
92
    {
93
        $this->classBasedComparatorWillBeCalled();
94
        $this->interfaceBasedComparatorWillNotBeCalled();
95
        $this->traitBasedComparatorWillNotBeCalled();
96
97
        self::assertEqualsIgnoringOrder(
98
            Changes::fromList(Change::changed('class change', true)),
99
            $this->compareClasses->__invoke(
100
                self::$stringReflectorFactory->__invoke('<?php class A {}'),
101
                self::$stringReflectorFactory->__invoke(
102
                    <<<'PHP'
103
<?php
104
105
class A {
106
    const A_CONSTANT = 'foo';
107
    public $aProperty;
108
    public function aMethod() {}
109
}
110
PHP
111
                ),
112
                self::$stringReflectorFactory->__invoke(
113
                    <<<'PHP'
114
<?php
115
116
class A {}
117
PHP
118
                )
119
            )
120
        );
121
    }
122
123
    public function testWillRunInterfaceComparators() : void
124
    {
125
        $this->classBasedComparatorWillNotBeCalled();
126
        $this->interfaceBasedComparatorWillBeCalled();
127
        $this->traitBasedComparatorWillNotBeCalled();
128
129
        self::assertEqualsIgnoringOrder(
130
            Changes::fromList(Change::changed('interface change', true)),
131
            $this->compareClasses->__invoke(
132
                self::$stringReflectorFactory->__invoke('<?php interface A {}'),
133
                self::$stringReflectorFactory->__invoke('<?php interface A {}'),
134
                self::$stringReflectorFactory->__invoke('<?php interface A {}')
135
            )
136
        );
137
    }
138
139
    public function testWillRunTraitComparators() : void
140
    {
141
        $this->classBasedComparatorWillNotBeCalled();
142
        $this->interfaceBasedComparatorWillNotBeCalled();
143
        $this->traitBasedComparatorWillBeCalled();
144
145
        self::assertEqualsIgnoringOrder(
146
            Changes::fromList(Change::changed('trait change', true)),
147
            $this->compareClasses->__invoke(
148
                self::$stringReflectorFactory->__invoke('<?php trait A {}'),
149
                self::$stringReflectorFactory->__invoke('<?php trait A {}'),
150
                self::$stringReflectorFactory->__invoke('<?php trait A {}')
151
            )
152
        );
153
    }
154
155
    public function testAnonymousClassesAreFilteredOut() : void
156
    {
157
        $this->classBasedComparatorWillNotBeCalled();
158
        $this->interfaceBasedComparatorWillNotBeCalled();
159
        $this->traitBasedComparatorWillNotBeCalled();
160
161
        self::assertEquals(
162
            Changes::empty(),
163
            $this->compareClasses->__invoke(
164
                self::$stringReflectorFactory->__invoke('<?php $x = new class () {};'),
165
                self::$stringReflectorFactory->__invoke('<?php $x = new class () {};'),
166
                self::$stringReflectorFactory->__invoke('<?php $x = new class () {};')
167
            )
168
        );
169
    }
170
171
    /**
172
     * @param mixed $expected
173
     * @param mixed $actual
174
     */
175
    private static function assertEqualsIgnoringOrder($expected, $actual) : void
176
    {
177
        self::assertEquals($expected, $actual, '', 0.0, 10, true);
178
    }
179
180
    public function testSkipsReflectingUndefinedApi() : void
181
    {
182
        $this->classBasedComparatorWillNotBeCalled();
183
184
        self::assertEqualsIgnoringOrder(
185
            Changes::empty(),
186
            $this->compareClasses->__invoke(
187
                self::$stringReflectorFactory->__invoke('<?php '),
188
                self::$stringReflectorFactory->__invoke('<?php class A { private function foo() {} }'),
189
                self::$stringReflectorFactory->__invoke('<?php ')
190
            )
191
        );
192
    }
193
194
    public function testRemovingAClassCausesABreak() : void
195
    {
196
        $this->classBasedComparatorWillNotBeCalled();
197
        $this->interfaceBasedComparatorWillNotBeCalled();
198
        $this->traitBasedComparatorWillNotBeCalled();
199
200
        self::assertEqualsIgnoringOrder(
201
            Changes::fromList(Change::removed('Class A has been deleted', true)),
202
            $this->compareClasses->__invoke(
203
                self::$stringReflectorFactory->__invoke('<?php class A { private function foo() {} }'),
204
                self::$stringReflectorFactory->__invoke('<?php class A { private function foo() {} }'),
205
                self::$stringReflectorFactory->__invoke('<?php ')
206
            )
207
        );
208
    }
209
210
    private function classBasedComparatorWillBeCalled() : void
211
    {
212
        $this
213
            ->classBasedComparison
214
            ->expects(self::atLeastOnce())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Roave\BackwardCompatibil...k\ClassBased\ClassBased. ( Ignorable by Annotation )

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

214
            ->/** @scrutinizer ignore-call */ 
215
              expects(self::atLeastOnce())

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
215
            ->method('__invoke')
216
            ->willReturn(Changes::fromList(Change::changed('class change', true)));
217
    }
218
219
    private function classBasedComparatorWillNotBeCalled() : void
220
    {
221
        $this
222
            ->classBasedComparison
223
            ->expects(self::never())
224
            ->method('__invoke');
225
    }
226
227
    private function interfaceBasedComparatorWillBeCalled() : void
228
    {
229
        $this
230
            ->interfaceBasedComparison
231
            ->expects(self::atLeastOnce())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Roave\BackwardCompatibil...aceBased\InterfaceBased. ( Ignorable by Annotation )

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

231
            ->/** @scrutinizer ignore-call */ 
232
              expects(self::atLeastOnce())

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
232
            ->method('__invoke')
233
            ->willReturn(Changes::fromList(Change::changed('interface change', true)));
234
    }
235
236
    private function interfaceBasedComparatorWillNotBeCalled() : void
237
    {
238
        $this
239
            ->interfaceBasedComparison
240
            ->expects(self::never())
241
            ->method('__invoke');
242
    }
243
244
    private function traitBasedComparatorWillBeCalled() : void
245
    {
246
        $this
247
            ->traitBasedComparison
248
            ->expects(self::atLeastOnce())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Roave\BackwardCompatibil...k\TraitBased\TraitBased. ( Ignorable by Annotation )

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

248
            ->/** @scrutinizer ignore-call */ 
249
              expects(self::atLeastOnce())

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
249
            ->method('__invoke')
250
            ->willReturn(Changes::fromList(Change::changed('trait change', true)));
251
    }
252
253
    private function traitBasedComparatorWillNotBeCalled() : void
254
    {
255
        $this
256
            ->traitBasedComparison
257
            ->expects(self::never())
258
            ->method('__invoke');
259
    }
260
}
261