Passed
Push — master ( 99eb2c...97f0a9 )
by Gerhard
09:45
created

testRegisterExtensionWithNotExistingExtendedType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: gseidel
5
 * Date: 2020-06-08
6
 * Time: 09:49
7
 */
8
9
namespace Enhavo\Component\Type\Tests;
10
11
use Enhavo\Component\Type\AbstractTypeExtension;
12
use Enhavo\Component\Type\AbstractType;
13
use Enhavo\Component\Type\Exception\TypeNotFoundException;
14
use Enhavo\Component\Type\Exception\TypeNotValidException;
15
use Enhavo\Component\Type\Registry;
16
use Enhavo\Component\Type\TypeInterface;
17
use PHPUnit\Framework\TestCase;
18
use Symfony\Component\DependencyInjection\ContainerInterface;
19
use Symfony\Component\OptionsResolver\OptionsResolver;
20
21
class RegistryTest extends TestCase
22
{
23
    private function createDependencies()
24
    {
25
        $dependencies = new RegistryDependencies();
26
        $dependencies->container = $this->getMockBuilder(ContainerInterface::class)->getMock();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getMockBuilder(Sy...face::class)->getMock() of type PHPUnit\Framework\MockObject\MockObject is incompatible with the declared type PHPUnit_Framework_MockOb...tion\ContainerInterface of property $container.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
27
        $dependencies->namespace = 'Test';
28
        return $dependencies;
29
    }
30
31
    private function createInstance(RegistryDependencies $dependencies): Registry
32
    {
33
        $registry = new Registry($dependencies->namespace);
34
        $registry->setContainer($dependencies->container);
35
        return $registry;
36
    }
37
38
    public function testGetTypeByFQCN()
39
    {
40
        $dependencies = $this->createDependencies();
41
        $dependencies->container->method('get')->willReturnCallback(function($id) {
0 ignored issues
show
Bug introduced by
The method method() does not exist on Symfony\Component\Depend...tion\ContainerInterface. ( Ignorable by Annotation )

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

41
        $dependencies->container->/** @scrutinizer ignore-call */ 
42
                                  method('get')->willReturnCallback(function($id) {

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...
42
            $services = [
43
                'test_type_id' => new TestType(),
44
                'parent_test_type_id' => new ParentTestType(),
45
                'root_type_id' => new RootType(),
46
            ];
47
            return $services[$id];
48
        });
49
50
        $registry = $this->createInstance($dependencies);
51
        $registry->register(TestType::class, 'test_type_id');
52
        $registry->register(ParentTestType::class, 'parent_test_type_id');
53
        $registry->register(RootType::class, 'root_type_id');
54
55
        $type = $registry->getType(TestType::class);
56
57
        $this->assertEquals('test', $type::getName());
58
        $this->assertEquals('parent_test', $type->getParent()::getName());
0 ignored issues
show
Bug introduced by
The method getParent() does not exist on Enhavo\Component\Type\TypeInterface. Did you maybe mean getParentType()? ( Ignorable by Annotation )

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

58
        $this->assertEquals('parent_test', $type->/** @scrutinizer ignore-call */ getParent()::getName());

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...
59
        $this->assertEquals('root', $type->getParent()->getParent()::getName());
60
    }
61
62
    public function testGetTypeByName()
63
    {
64
        $dependencies = $this->createDependencies();
65
        $dependencies->container->method('get')->willReturnCallback(function($id) {
66
            $services = [
67
                'root_type_id' => new RootType(),
68
            ];
69
            return $services[$id];
70
        });
71
72
        $registry = $this->createInstance($dependencies);
73
        $registry->register(RootType::class, 'root_type_id');
74
75
        $type = $registry->getType('root');
76
77
        $this->assertEquals('root', $type::getName());
78
    }
79
80
    public function testNotFound()
81
    {
82
        $this->expectException(TypeNotFoundException::class);
83
84
        $dependencies = $this->createDependencies();
85
        $registry = $this->createInstance($dependencies);
86
        $registry->register(RootType::class, 'root_type_id');
87
        $registry->getType('type_not_exists');
88
    }
89
90
    public function testCircularDetection()
91
    {
92
        $this->expectException(TypeNotValidException::class);
93
94
        $dependencies = $this->createDependencies();
95
        $registry = $this->createInstance($dependencies);
96
        $registry->register(CircularTypeOne::class, CircularTypeOne::class);
97
        $registry->register(CircularTypeTwo::class, CircularTypeTwo::class);
98
        $registry->register(CircularTypeThree::class, CircularTypeThree::class);
99
    }
100
101
    public function testSelfCircularDetection()
102
    {
103
        $this->expectException(TypeNotValidException::class);
104
105
        $dependencies = $this->createDependencies();
106
        $registry = $this->createInstance($dependencies);
107
        $registry->register(SelfReference::class, SelfReference::class);
108
    }
109
110
    public function testMissingInterface()
111
    {
112
        $this->expectException(TypeNotValidException::class);
113
114
        $dependencies = $this->createDependencies();
115
        $registry = $this->createInstance($dependencies);
116
        $registry->register(NoInterface::class, NoInterface::class);
117
    }
118
119
    /**
120
     * @doesNotPerformAssertions
121
     */
122
    public function testIndirectInterface()
123
    {
124
        $dependencies = $this->createDependencies();
125
        $registry = $this->createInstance($dependencies);
126
        $registry->register(IndirectClass::class, IndirectClass::class);
127
    }
128
129
    public function testParentClassInterface()
130
    {
131
        $this->expectException(TypeNotValidException::class);
132
133
        $dependencies = $this->createDependencies();
134
        $registry = $this->createInstance($dependencies);
135
        $registry->register(ParentNotExitsType::class, ParentNotExitsType::class);
136
    }
137
138
    public function testInvalidParent()
139
    {
140
        $this->expectException(TypeNotValidException::class);
141
142
        $dependencies = $this->createDependencies();
143
        $registry = $this->createInstance($dependencies);
144
        $registry->register(InvalidParentType::class, InvalidParentType::class);
145
    }
146
147
    public function testDoubleClassNames()
148
    {
149
        $this->expectException(TypeNotValidException::class);
150
151
        $dependencies = $this->createDependencies();
152
        $registry = $this->createInstance($dependencies);
153
        $registry->register(TestType::class, TestType::class);
154
        $registry->register(TestType::class, TestType::class);
155
    }
156
157
    public function testDoubleNames()
158
    {
159
        $this->expectException(TypeNotValidException::class);
160
161
        $dependencies = $this->createDependencies();
162
        $registry = $this->createInstance($dependencies);
163
        $registry->register(TestType::class, TestType::class);
164
        $registry->register(OtherTestType::class, OtherTestType::class);
165
    }
166
167
    public function testRegisterExtension()
168
    {
169
        $dependencies = $this->createDependencies();
170
        $testExtensionType = new TestExtensionType();
171
        $testOtherExtensionType = new TestOtherExtensionType();
172
        $dependencies->container->method('get')->willReturnCallback(function($id) use ($testExtensionType, $testOtherExtensionType) {
173
            return match ($id) {
174
                $testExtensionType::class => $testExtensionType,
175
                $testOtherExtensionType::class => $testOtherExtensionType,
176
                default => null,
177
            };
178
        });
179
180
        $registry = $this->createInstance($dependencies);
181
        $registry->register(TestType::class, TestType::class);
182
        $registry->registerExtension(TestExtensionType::class, TestExtensionType::class, 1);
183
        $registry->registerExtension(TestOtherExtensionType::class, TestOtherExtensionType::class, 3);
184
185
        $testType = new TestType();
186
        $extensions = $registry->getExtensions($testType);
187
188
        $this->assertCount(2, $extensions);
189
        $this->assertTrue($extensions[0] instanceof TestOtherExtensionType);
190
        $this->assertTrue($extensions[1] instanceof TestExtensionType);
191
    }
192
193
    public function testRegisterExtensionWithWrongInterface()
194
    {
195
        $this->expectException(TypeNotValidException::class);
196
197
        $dependencies = $this->createDependencies();
198
        $registry = $this->createInstance($dependencies);
199
        $registry->registerExtension(TestType::class, TestType::class);
200
    }
201
202
    public function testRegisterExtensionWithNotExistingExtendedType()
203
    {
204
        $this->expectException(TypeNotValidException::class);
205
206
        $dependencies = $this->createDependencies();
207
        $registry = $this->createInstance($dependencies);
208
        $registry->registerExtension(TestExtensionType::class, TestExtensionType::class);
209
    }
210
}
211
212
class RegistryDependencies
213
{
214
    /** @var ContainerInterface|\PHPUnit_Framework_MockObject_MockObject */
215
    public $container;
216
    /** @var String */
217
    public $namespace;
218
}
219
220
class TestType extends AbstractType
221
{
222
    public function getParent()
223
    {
224
        return $this->parent;
225
    }
226
227
    public static function getParentType(): ?string
228
    {
229
        return ParentTestType::class;
230
    }
231
232
    public static function getName(): ?string
233
    {
234
        return 'test';
235
    }
236
}
237
238
class TestExtensionType extends AbstractTypeExtension
239
{
240
    public static function getExtendedTypes(): array
241
    {
242
        return [TestType::class];
243
    }
244
}
245
246
class TestOtherExtensionType extends AbstractTypeExtension
247
{
248
    public static function getExtendedTypes(): array
249
    {
250
        return [TestType::class];
251
    }
252
}
253
254
class ParentTestType extends AbstractType
255
{
256
    public function getParent()
257
    {
258
        return $this->parent;
259
    }
260
261
    public static function getParentType(): ?string
262
    {
263
        return RootType::class;
264
    }
265
266
    public static function getName(): ?string
267
    {
268
        return 'parent_test';
269
    }
270
}
271
272
class RootType extends AbstractType
273
{
274
    public function getParent()
275
    {
276
        return $this->parent;
277
    }
278
279
    public static function getName(): ?string
280
    {
281
        return 'root';
282
    }
283
}
284
285
class CircularTypeOne extends AbstractType
286
{
287
    public static function getParentType(): ?string
288
    {
289
        return CircularTypeTwo::class;
290
    }
291
}
292
293
class CircularTypeTwo extends AbstractType
294
{
295
    public static function getParentType(): ?string
296
    {
297
        return CircularTypeTwo::class;
298
    }
299
}
300
301
class CircularTypeThree extends AbstractType
302
{
303
    public static function getParentType(): ?string
304
    {
305
        return CircularTypeOne::class;
306
    }
307
}
308
309
class SelfReference extends AbstractType
310
{
311
    public static function getParentType(): ?string
312
    {
313
        return self::class;
314
    }
315
}
316
317
class InvalidParentType extends AbstractType
318
{
319
    public static function getParentType(): ?string
320
    {
321
        return NoInterface::class;
322
    }
323
}
324
325
class ParentNotExitsType extends AbstractType
326
{
327
    public static function getParentType(): ?string
328
    {
329
        return 'Something\But\NotValidAClass';
330
    }
331
}
332
333
class OtherTestType extends AbstractType
334
{
335
    public static function getName(): ?string
336
    {
337
        return 'test';
338
    }
339
}
340
341
class NoInterface
342
{
343
344
}
345
346
interface IndirectInterface extends TypeInterface
347
{
348
349
}
350
351
class IndirectClass implements IndirectInterface
352
{
353
    public function setKey(?string $key)
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

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

353
    public function setKey(/** @scrutinizer ignore-unused */ ?string $key)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
354
    {
355
356
    }
357
358
    public static function getName(): ?string
359
    {
360
        return null;
361
    }
362
363
    public static function getParentType(): ?string
364
    {
365
        return null;
366
    }
367
368
    public function setParent(TypeInterface $parent)
369
    {
370
371
    }
372
373
    public function configureOptions(OptionsResolver $resolver)
374
    {
375
376
    }
377
}
378