Passed
Pull Request — master (#48)
by Marco
02:59
created

ComparatorTest::testSkipsReflectingUndefinedApi()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace RoaveTest\ApiCompare;
6
7
use PHPUnit\Framework\MockObject\MockObject;
8
use PHPUnit\Framework\TestCase;
9
use Roave\ApiCompare\Change;
10
use Roave\ApiCompare\Changes;
11
use Roave\ApiCompare\Comparator;
12
use Roave\ApiCompare\Comparator\BackwardsCompatibility\ClassBased\ClassBased;
13
use Roave\ApiCompare\Comparator\BackwardsCompatibility\InterfaceBased\InterfaceBased;
14
use Roave\ApiCompare\Comparator\BackwardsCompatibility\TraitBased\TraitBased;
15
16
/**
17
 * @covers \Roave\ApiCompare\Comparator
18
 */
19
final class ComparatorTest 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 Comparator */
34
    private $comparator;
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->comparator               = new Comparator(
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::fromArray([
63
                Change::changed('class change', true),
64
            ]),
65
            $this->comparator->compare(
66
                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

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

208
            ->/** @scrutinizer ignore-call */ 
209
              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...
209
            ->method('compare')
210
            ->willReturn(Changes::fromArray([
211
                Change::changed('class change', true),
212
            ]));
213
    }
214
215
    private function classBasedComparatorWillNotBeCalled() : void
216
    {
217
        $this
218
            ->classBasedComparison
219
            ->expects(self::never())
220
            ->method('compare');
221
    }
222
223
    private function interfaceBasedComparatorWillBeCalled() : void
224
    {
225
        $this
226
            ->interfaceBasedComparison
227
            ->expects(self::atLeastOnce())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Roave\ApiCompare\Compara...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

227
            ->/** @scrutinizer ignore-call */ 
228
              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...
228
            ->method('compare')
229
            ->willReturn(Changes::fromArray([
230
                Change::changed('interface change', true),
231
            ]));
232
    }
233
234
    private function interfaceBasedComparatorWillNotBeCalled() : void
235
    {
236
        $this
237
            ->interfaceBasedComparison
238
            ->expects(self::never())
239
            ->method('compare');
240
    }
241
242
    private function traitBasedComparatorWillBeCalled() : void
243
    {
244
        $this
245
            ->traitBasedComparison
246
            ->expects(self::atLeastOnce())
0 ignored issues
show
Bug introduced by
The method expects() does not exist on Roave\ApiCompare\Compara...y\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

246
            ->/** @scrutinizer ignore-call */ 
247
              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...
247
            ->method('compare')
248
            ->willReturn(Changes::fromArray([
249
                Change::changed('trait change', true),
250
            ]));
251
    }
252
253
    private function traitBasedComparatorWillNotBeCalled() : void
254
    {
255
        $this
256
            ->traitBasedComparison
257
            ->expects(self::never())
258
            ->method('compare');
259
    }
260
}
261