Completed
Push — master ( d6f6df...50f391 )
by Jaap
28:46 queued 18:49
created

testResolvingMixedCompoundTypes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 27
rs 9.488
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of phpDocumentor.
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * @link      http://phpdoc.org
12
 */
13
14
namespace phpDocumentor\Reflection;
15
16
use Mockery as m;
17
use phpDocumentor\Reflection\Types\Array_;
18
use phpDocumentor\Reflection\Types\Expression_;
19
use phpDocumentor\Reflection\Types\Boolean;
20
use phpDocumentor\Reflection\Types\ClassString;
21
use phpDocumentor\Reflection\Types\Compound;
22
use phpDocumentor\Reflection\Types\Context;
23
use phpDocumentor\Reflection\Types\Iterable_;
24
use phpDocumentor\Reflection\Types\Null_;
25
use phpDocumentor\Reflection\Types\Nullable;
26
use phpDocumentor\Reflection\Types\Object_;
27
use phpDocumentor\Reflection\Types\String_;
28
use PHPUnit\Framework\TestCase;
29
use stdClass;
30
use function get_class;
31
32
/**
33
 * @coversDefaultClass \phpDocumentor\Reflection\TypeResolver
34
 */
35
class TypeResolverTest extends TestCase
36
{
37
    /**
38
     * Call Mockery::close after each test.
39
     */
40
    public function tearDown() : void
41
    {
42
        m::close();
43
    }
44
45
    /**
46
     * @uses         \phpDocumentor\Reflection\Types\Context
47
     * @uses         \phpDocumentor\Reflection\Types\Array_
48
     * @uses         \phpDocumentor\Reflection\Types\Object_
49
     *
50
     * @covers ::__construct
51
     * @covers ::resolve
52
     * @covers ::<private>
53
     *
54
     * @dataProvider provideKeywords
55
     */
56
    public function testResolvingKeywords(string $keyword, string $expectedClass) : void
57
    {
58
        $fixture = new TypeResolver();
59
60
        $resolvedType = $fixture->resolve($keyword, new Context(''));
61
62
        $this->assertInstanceOf($expectedClass, $resolvedType);
63
    }
64
65
    /**
66
     * @uses         \phpDocumentor\Reflection\Types\Context
67
     * @uses         \phpDocumentor\Reflection\Types\Object_
68
     * @uses         \phpDocumentor\Reflection\Types\String_
69
     *
70
     * @covers ::__construct
71
     * @covers ::resolve
72
     * @covers ::<private>
73
     *
74
     * @dataProvider provideClassStrings
75
     */
76
    public function testResolvingClassStrings(string $classString, bool $throwsException) : void
77
    {
78
        $fixture = new TypeResolver();
79
80
        if ($throwsException) {
81
            $this->expectException('RuntimeException');
82
        }
83
84
        $resolvedType = $fixture->resolve($classString, new Context(''));
85
86
        $this->assertInstanceOf(ClassString::class, $resolvedType);
87
    }
88
89
    /**
90
     * @uses         \phpDocumentor\Reflection\Types\Context
91
     * @uses         \phpDocumentor\Reflection\Types\Object_
92
     * @uses         \phpDocumentor\Reflection\Fqsen
93
     * @uses         \phpDocumentor\Reflection\FqsenResolver
94
     *
95
     * @covers ::__construct
96
     * @covers ::resolve
97
     * @covers ::<private>
98
     *
99
     * @dataProvider provideFqcn
100
     */
101
    public function testResolvingFQSENs(string $fqsen) : void
102
    {
103
        $fixture = new TypeResolver();
104
105
        $resolvedType = $fixture->resolve($fqsen, new Context(''));
106
107
        $this->assertInstanceOf(Object_::class, $resolvedType);
108
        $this->assertInstanceOf(Fqsen::class, $resolvedType->getFqsen());
109
        $this->assertSame($fqsen, (string) $resolvedType);
110
    }
111
112
    /**
113
     * @uses \phpDocumentor\Reflection\Types\Context
114
     * @uses \phpDocumentor\Reflection\Types\Object_
115
     * @uses \phpDocumentor\Reflection\Fqsen
116
     * @uses \phpDocumentor\Reflection\FqsenResolver
117
     *
118
     * @covers ::__construct
119
     * @covers ::resolve
120
     * @covers ::<private>
121
     */
122
    public function testResolvingRelativeQSENsBasedOnNamespace() : void
123
    {
124
        $fixture = new TypeResolver();
125
126
        $resolvedType = $fixture->resolve('DocBlock', new Context('phpDocumentor\Reflection'));
127
128
        $this->assertInstanceOf(Object_::class, $resolvedType);
129
        $this->assertInstanceOf(Fqsen::class, $resolvedType->getFqsen());
130
        $this->assertSame('\phpDocumentor\Reflection\DocBlock', (string) $resolvedType);
131
    }
132
133
    /**
134
     * @uses \phpDocumentor\Reflection\Types\Context
135
     * @uses \phpDocumentor\Reflection\Types\Object_
136
     * @uses \phpDocumentor\Reflection\Fqsen
137
     * @uses \phpDocumentor\Reflection\FqsenResolver
138
     *
139
     * @covers ::__construct
140
     * @covers ::resolve
141
     * @covers ::<private>
142
     */
143
    public function testResolvingRelativeQSENsBasedOnNamespaceAlias() : void
144
    {
145
        $fixture = new TypeResolver();
146
147
        $resolvedType = $fixture->resolve(
148
            'm\MockInterface',
149
            new Context('phpDocumentor\Reflection', ['m' => m::class])
150
        );
151
152
        $this->assertInstanceOf(Object_::class, $resolvedType);
153
        $this->assertInstanceOf(Fqsen::class, $resolvedType->getFqsen());
154
        $this->assertSame('\Mockery\MockInterface', (string) $resolvedType);
155
    }
156
157
    /**
158
     * @uses \phpDocumentor\Reflection\Types\Context
159
     * @uses \phpDocumentor\Reflection\Types\Array_
160
     * @uses \phpDocumentor\Reflection\Types\String_
161
     *
162
     * @covers ::__construct
163
     * @covers ::resolve
164
     * @covers ::<private>
165
     */
166
    public function testResolvingTypedArrays() : void
167
    {
168
        $fixture = new TypeResolver();
169
170
        $resolvedType = $fixture->resolve('string[]', new Context(''));
171
172
        $this->assertInstanceOf(Array_::class, $resolvedType);
173
        $this->assertSame('string[]', (string) $resolvedType);
174
        $this->assertInstanceOf(Compound::class, $resolvedType->getKeyType());
175
        $this->assertInstanceOf(Types\String_::class, $resolvedType->getValueType());
176
    }
177
178
    /**
179
     * @uses \phpDocumentor\Reflection\Types\Context
180
     * @uses \phpDocumentor\Reflection\Types\Nullable
181
     * @uses \phpDocumentor\Reflection\Types\String_
182
     *
183
     * @covers ::__construct
184
     * @covers ::resolve
185
     * @covers ::<private>
186
     */
187
    public function testResolvingNullableTypes() : void
188
    {
189
        $fixture = new TypeResolver();
190
191
        $resolvedType = $fixture->resolve('?string', new Context(''));
192
193
        $this->assertInstanceOf(Nullable::class, $resolvedType);
194
        $this->assertInstanceOf(String_::class, $resolvedType->getActualType());
195
        $this->assertSame('?string', (string) $resolvedType);
196
    }
197
198
    /**
199
     * @uses \phpDocumentor\Reflection\Types\Context
200
     * @uses \phpDocumentor\Reflection\Types\Array_
201
     * @uses \phpDocumentor\Reflection\Types\String_
202
     *
203
     * @covers ::__construct
204
     * @covers ::resolve
205
     * @covers ::<private>
206
     */
207
    public function testResolvingNestedTypedArrays() : void
208
    {
209
        $fixture = new TypeResolver();
210
211
        $resolvedType = $fixture->resolve('string[][]', new Context(''));
212
213
        $childValueType = $resolvedType->getValueType();
214
215
        $this->assertInstanceOf(Array_::class, $resolvedType);
216
217
        $this->assertSame('string[][]', (string) $resolvedType);
218
        $this->assertInstanceOf(Compound::class, $resolvedType->getKeyType());
219
        $this->assertInstanceOf(Array_::class, $childValueType);
220
221
        $this->assertSame('string[]', (string) $childValueType);
222
        $this->assertInstanceOf(Compound::class, $childValueType->getKeyType());
223
        $this->assertInstanceOf(Types\String_::class, $childValueType->getValueType());
224
    }
225
226
    /**
227
     * @uses \phpDocumentor\Reflection\Types\Context
228
     * @uses \phpDocumentor\Reflection\Types\Compound
229
     * @uses \phpDocumentor\Reflection\Types\String_
230
     * @uses \phpDocumentor\Reflection\Types\Object_
231
     * @uses \phpDocumentor\Reflection\Fqsen
232
     * @uses \phpDocumentor\Reflection\FqsenResolver
233
     *
234
     * @covers ::__construct
235
     * @covers ::resolve
236
     * @covers ::<private>
237
     */
238
    public function testResolvingCompoundTypes() : void
239
    {
240
        $fixture = new TypeResolver();
241
242
        $resolvedType = $fixture->resolve('string|Reflection\DocBlock', new Context('phpDocumentor'));
243
244
        $this->assertInstanceOf(Compound::class, $resolvedType);
245
        $this->assertSame('string|\phpDocumentor\Reflection\DocBlock', (string) $resolvedType);
246
247
        $firstType = $resolvedType->get(0);
248
249
        $secondType = $resolvedType->get(1);
250
251
        $this->assertInstanceOf(Types\String_::class, $firstType);
252
        $this->assertInstanceOf(Object_::class, $secondType);
253
        $this->assertInstanceOf(Fqsen::class, $secondType->getFqsen());
254
    }
255
256
    /**
257
     * @uses \phpDocumentor\Reflection\Types\Context
258
     * @uses \phpDocumentor\Reflection\Types\Compound
259
     * @uses \phpDocumentor\Reflection\Types\String_
260
     * @uses \phpDocumentor\Reflection\Types\Object_
261
     * @uses \phpDocumentor\Reflection\Fqsen
262
     * @uses \phpDocumentor\Reflection\FqsenResolver
263
     *
264
     * @covers ::__construct
265
     * @covers ::resolve
266
     * @covers ::<private>
267
     */
268
    public function testResolvingAmpersandCompoundTypes() : void
269
    {
270
        $fixture = new TypeResolver();
271
272
        $resolvedType = $fixture->resolve('Reflection\DocBlock&\PHPUnit\Framework\MockObject\MockObject ', new Context('phpDocumentor'));
273
274
        $this->assertInstanceOf(Compound::class, $resolvedType);
275
        $this->assertSame('\phpDocumentor\Reflection\DocBlock&\PHPUnit\Framework\MockObject\MockObject', (string) $resolvedType);
276
277
        $firstType = $resolvedType->get(0);
278
279
        $secondType = $resolvedType->get(1);
280
281
        $this->assertInstanceOf(Object_::class, $firstType);
282
        $this->assertInstanceOf(Fqsen::class, $firstType->getFqsen());
283
        $this->assertInstanceOf(Object_::class, $secondType);
284
        $this->assertInstanceOf(Fqsen::class, $secondType->getFqsen());
285
    }
286
287
    /**
288
     * @uses \phpDocumentor\Reflection\Types\Context
289
     * @uses \phpDocumentor\Reflection\Types\Compound
290
     * @uses \phpDocumentor\Reflection\Types\String_
291
     * @uses \phpDocumentor\Reflection\Types\Object_
292
     * @uses \phpDocumentor\Reflection\Fqsen
293
     * @uses \phpDocumentor\Reflection\FqsenResolver
294
     *
295
     * @covers ::__construct
296
     * @covers ::resolve
297
     * @covers ::<private>
298
     */
299
    public function testResolvingMixedCompoundTypes() : void
300
    {
301
        $fixture = new TypeResolver();
302
303
        $resolvedType = $fixture->resolve('(Reflection\DocBlock&\PHPUnit\Framework\MockObject\MockObject)|null', new Context('phpDocumentor'));
304
305
        $this->assertInstanceOf(Compound::class, $resolvedType);
306
        $this->assertSame('(\phpDocumentor\Reflection\DocBlock&\PHPUnit\Framework\MockObject\MockObject)|null', (string) $resolvedType);
307
308
        $firstType = $resolvedType->get(0);
309
310
        $secondType = $resolvedType->get(1);
311
312
        $this->assertInstanceOf(Expression_::class, $firstType);
313
        $this->assertSame('(\phpDocumentor\Reflection\DocBlock&\PHPUnit\Framework\MockObject\MockObject)', (string) $firstType);
314
        $this->assertInstanceOf(Null_::class, $secondType);
315
316
        $resolvedType = $firstType->getValueType();
317
318
        $firstSubType = $resolvedType->get(0);
319
        $secondSubType =  $resolvedType->get(1);
320
321
        $this->assertInstanceOf(Object_::class, $firstSubType);
322
        $this->assertInstanceOf(Fqsen::class, $secondSubType->getFqsen());
323
        $this->assertInstanceOf(Object_::class, $secondSubType);
324
        $this->assertInstanceOf(Fqsen::class, $secondSubType->getFqsen());
325
    }
326
327
    /**
328
     * @uses \phpDocumentor\Reflection\Types\Context
329
     * @uses \phpDocumentor\Reflection\Types\Compound
330
     * @uses \phpDocumentor\Reflection\Types\Array_
331
     * @uses \phpDocumentor\Reflection\Types\Object_
332
     * @uses \phpDocumentor\Reflection\Fqsen
333
     * @uses \phpDocumentor\Reflection\FqsenResolver
334
     *
335
     * @covers ::__construct
336
     * @covers ::resolve
337
     * @covers ::<private>
338
     */
339
    public function testResolvingCompoundTypedArrayTypes() : void
340
    {
341
        $fixture = new TypeResolver();
342
343
        $resolvedType = $fixture->resolve('\stdClass[]|Reflection\DocBlock[]', new Context('phpDocumentor'));
344
345
        $this->assertInstanceOf(Compound::class, $resolvedType);
346
        $this->assertSame('\stdClass[]|\phpDocumentor\Reflection\DocBlock[]', (string) $resolvedType);
347
348
        $firstType = $resolvedType->get(0);
349
350
        $secondType = $resolvedType->get(1);
351
352
        $this->assertInstanceOf(Array_::class, $firstType);
353
        $this->assertInstanceOf(Array_::class, $secondType);
354
        $this->assertInstanceOf(Object_::class, $firstType->getValueType());
355
        $this->assertInstanceOf(Object_::class, $secondType->getValueType());
356
    }
357
358
    /**
359
     * @uses \phpDocumentor\Reflection\Types\Context
360
     * @uses \phpDocumentor\Reflection\Types\Compound
361
     * @uses \phpDocumentor\Reflection\Types\String_
362
     * @uses \phpDocumentor\Reflection\Types\Nullable
363
     * @uses \phpDocumentor\Reflection\Types\Null_
364
     * @uses \phpDocumentor\Reflection\Types\Boolean
365
     * @uses \phpDocumentor\Reflection\Fqsen
366
     * @uses \phpDocumentor\Reflection\FqsenResolver
367
     *
368
     * @covers ::__construct
369
     * @covers ::resolve
370
     * @covers ::<private>
371
     */
372
    public function testResolvingNullableCompoundTypes() : void
373
    {
374
        $fixture = new TypeResolver();
375
376
        $resolvedType = $fixture->resolve('?string|null|?boolean');
377
378
        $this->assertSame('?string|null|?bool', (string) $resolvedType);
379
    }
380
381
    /**
382
     * @uses \phpDocumentor\Reflection\Types\Context
383
     * @uses \phpDocumentor\Reflection\Types\Compound
384
     * @uses \phpDocumentor\Reflection\Types\Array_
385
     * @uses \phpDocumentor\Reflection\Types\Object_
386
     * @uses \phpDocumentor\Reflection\Fqsen
387
     * @uses \phpDocumentor\Reflection\FqsenResolver
388
     *
389
     * @covers ::__construct
390
     * @covers ::resolve
391
     * @covers ::<private>
392
     */
393
    public function testResolvingArrayExpressionObjectsTypes() : void
394
    {
395
        $fixture = new TypeResolver();
396
397
        $resolvedType = $fixture->resolve('(\stdClass|Reflection\DocBlock)[]', new Context('phpDocumentor'));
398
399
        $this->assertInstanceOf(Array_::class, $resolvedType);
400
        $this->assertSame('(\stdClass|\phpDocumentor\Reflection\DocBlock)[]', (string) $resolvedType);
401
402
        $valueType = $resolvedType->getValueType();
403
404
        $this->assertInstanceOf(Compound::class, $valueType);
405
406
        $firstType = $valueType->get(0);
407
408
        $secondType = $valueType->get(1);
409
410
        $this->assertInstanceOf(Object_::class, $firstType);
411
        $this->assertInstanceOf(Object_::class, $secondType);
412
    }
413
414
    /**
415
     * @uses \phpDocumentor\Reflection\Types\Context
416
     * @uses \phpDocumentor\Reflection\Types\Compound
417
     * @uses \phpDocumentor\Reflection\Types\Array_
418
     * @uses \phpDocumentor\Reflection\Types\Object_
419
     * @uses \phpDocumentor\Reflection\Fqsen
420
     * @uses \phpDocumentor\Reflection\FqsenResolver
421
     *
422
     * @covers ::__construct
423
     * @covers ::resolve
424
     * @covers ::<private>
425
     */
426
    public function testResolvingArrayExpressionSimpleTypes() : void
427
    {
428
        $fixture = new TypeResolver();
429
430
        $resolvedType = $fixture->resolve('(string|\stdClass|boolean)[]', new Context(''));
431
432
        $this->assertInstanceOf(Array_::class, $resolvedType);
433
        $this->assertSame('(string|\stdClass|bool)[]', (string) $resolvedType);
434
435
        $valueType = $resolvedType->getValueType();
436
437
        $this->assertInstanceOf(Compound::class, $valueType);
438
439
        $firstType = $valueType->get(0);
440
441
        $secondType = $valueType->get(1);
442
443
        $thirdType = $valueType->get(2);
444
445
        $this->assertInstanceOf(String_::class, $firstType);
446
        $this->assertInstanceOf(Object_::class, $secondType);
447
        $this->assertInstanceOf(Boolean::class, $thirdType);
448
    }
449
450
    /**
451
     * @uses \phpDocumentor\Reflection\Types\Context
452
     * @uses \phpDocumentor\Reflection\Types\Compound
453
     * @uses \phpDocumentor\Reflection\Types\Array_
454
     * @uses \phpDocumentor\Reflection\Types\Object_
455
     * @uses \phpDocumentor\Reflection\Fqsen
456
     * @uses \phpDocumentor\Reflection\FqsenResolver
457
     *
458
     * @covers ::__construct
459
     * @covers ::resolve
460
     * @covers ::<private>
461
     */
462
    public function testResolvingArrayOfArrayExpressionTypes() : void
463
    {
464
        $fixture = new TypeResolver();
465
466
        $resolvedType = $fixture->resolve('(string|\stdClass)[][]', new Context(''));
467
468
        $this->assertInstanceOf(Array_::class, $resolvedType);
469
        $this->assertSame('(string|\stdClass)[][]', (string) $resolvedType);
470
471
        $parentArrayType = $resolvedType->getValueType();
472
        $this->assertInstanceOf(Array_::class, $parentArrayType);
473
474
        $valueType = $parentArrayType->getValueType();
475
        $this->assertInstanceOf(Compound::class, $valueType);
476
477
        $firstType = $valueType->get(0);
478
479
        $secondType = $valueType->get(1);
480
481
        $this->assertInstanceOf(String_::class, $firstType);
482
        $this->assertInstanceOf(Object_::class, $secondType);
483
    }
484
485
    /**
486
     * @uses \phpDocumentor\Reflection\Types\Context
487
     * @uses \phpDocumentor\Reflection\Types\Compound
488
     * @uses \phpDocumentor\Reflection\Types\Array_
489
     * @uses \phpDocumentor\Reflection\Types\Object_
490
     * @uses \phpDocumentor\Reflection\Fqsen
491
     * @uses \phpDocumentor\Reflection\FqsenResolver
492
     *
493
     * @covers ::__construct
494
     * @covers ::resolve
495
     * @covers ::<private>
496
     */
497
    public function testReturnEmptyCompoundOnAnUnclosedArrayExpressionType() : void
498
    {
499
        $fixture = new TypeResolver();
500
501
        $resolvedType = $fixture->resolve('(string|\stdClass', new Context(''));
502
503
        $this->assertInstanceOf(Compound::class, $resolvedType);
504
        $this->assertSame('', (string) $resolvedType);
505
    }
506
507
    /**
508
     * @uses \phpDocumentor\Reflection\Types\Context
509
     * @uses \phpDocumentor\Reflection\Types\Compound
510
     * @uses \phpDocumentor\Reflection\Types\Array_
511
     * @uses \phpDocumentor\Reflection\Types\Object_
512
     * @uses \phpDocumentor\Reflection\Fqsen
513
     * @uses \phpDocumentor\Reflection\FqsenResolver
514
     *
515
     * @covers ::__construct
516
     * @covers ::resolve
517
     * @covers ::<private>
518
     */
519
    public function testResolvingArrayExpressionOrCompoundTypes() : void
520
    {
521
        $fixture = new TypeResolver();
522
523
        $resolvedType = $fixture->resolve('\stdClass|(string|\stdClass)[]|bool', new Context(''));
524
525
        $this->assertInstanceOf(Compound::class, $resolvedType);
526
        $this->assertSame('\stdClass|(string|\stdClass)[]|bool', (string) $resolvedType);
527
528
        $firstType = $resolvedType->get(0);
529
        $this->assertInstanceOf(Object_::class, $firstType);
530
531
        $secondType = $resolvedType->get(1);
532
        $this->assertInstanceOf(Array_::class, $secondType);
533
534
        $thirdType = $resolvedType->get(2);
535
        $this->assertInstanceOf(Boolean::class, $thirdType);
536
537
        $valueType = $secondType->getValueType();
538
        $this->assertInstanceOf(Compound::class, $valueType);
539
540
        $firstArrayType = $valueType->get(0);
541
542
        $secondArrayType = $valueType->get(1);
543
544
        $this->assertInstanceOf(String_::class, $firstArrayType);
545
        $this->assertInstanceOf(Object_::class, $secondArrayType);
546
    }
547
548
    /**
549
     * @uses \phpDocumentor\Reflection\Types\Context
550
     * @uses \phpDocumentor\Reflection\Types\Compound
551
     * @uses \phpDocumentor\Reflection\Types\Iterable_
552
     * @uses \phpDocumentor\Reflection\Types\Object_
553
     * @uses \phpDocumentor\Reflection\Fqsen
554
     * @uses \phpDocumentor\Reflection\FqsenResolver
555
     *
556
     * @covers ::__construct
557
     * @covers ::resolve
558
     * @covers ::<private>
559
     */
560
    public function testResolvingIterableExpressionSimpleTypes() : void
561
    {
562
        $fixture = new TypeResolver();
563
564
        $resolvedType = $fixture->resolve('iterable<string|\stdClass|boolean>', new Context(''));
565
566
        $this->assertInstanceOf(Iterable_::class, $resolvedType);
567
        $this->assertSame('iterable<string|\stdClass|bool>', (string) $resolvedType);
568
569
        $valueType = $resolvedType->getValueType();
570
571
        $this->assertInstanceOf(Compound::class, $valueType);
572
573
        $firstType = $valueType->get(0);
574
575
        $secondType = $valueType->get(1);
576
577
        $thirdType = $valueType->get(2);
578
579
        $this->assertInstanceOf(String_::class, $firstType);
580
        $this->assertInstanceOf(Object_::class, $secondType);
581
        $this->assertInstanceOf(Boolean::class, $thirdType);
582
    }
583
584
    /**
585
     * This test asserts that the parameter order is correct.
586
     *
587
     * When you pass two arrays separated by the compound operator (i.e. 'integer[]|string[]') then we always split the
588
     * expression in its compound parts and then we parse the types with the array operators. If we were to switch the
589
     * order around then 'integer[]|string[]' would read as an array of string or integer array; which is something
590
     * other than what we intend.
591
     *
592
     * @uses \phpDocumentor\Reflection\Types\Context
593
     * @uses \phpDocumentor\Reflection\Types\Compound
594
     * @uses \phpDocumentor\Reflection\Types\Array_
595
     * @uses \phpDocumentor\Reflection\Types\Integer
596
     * @uses \phpDocumentor\Reflection\Types\String_
597
     *
598
     * @covers ::__construct
599
     * @covers ::resolve
600
     * @covers ::<private>
601
     */
602
    public function testResolvingCompoundTypesWithTwoArrays() : void
603
    {
604
        $fixture = new TypeResolver();
605
606
        $resolvedType = $fixture->resolve('integer[]|string[]', new Context(''));
607
608
        $this->assertInstanceOf(Compound::class, $resolvedType);
609
        $this->assertSame('int[]|string[]', (string) $resolvedType);
610
611
        $firstType = $resolvedType->get(0);
612
613
        $secondType = $resolvedType->get(1);
614
615
        $this->assertInstanceOf(Array_::class, $firstType);
616
        $this->assertInstanceOf(Types\Integer::class, $firstType->getValueType());
617
        $this->assertInstanceOf(Array_::class, $secondType);
618
        $this->assertInstanceOf(Types\String_::class, $secondType->getValueType());
619
    }
620
621
    /**
622
     * @uses \phpDocumentor\Reflection\TypeResolver::resolve
623
     * @uses \phpDocumentor\Reflection\TypeResolver::<private>
624
     * @uses \phpDocumentor\Reflection\Types\Context
625
     *
626
     * @covers ::__construct
627
     * @covers ::addKeyword
628
     */
629
    public function testAddingAKeyword() : void
630
    {
631
        // Assign
632
        $typeMock = m::mock(Type::class);
633
634
        // Act
635
        $fixture = new TypeResolver();
636
        $fixture->addKeyword('mock', get_class($typeMock));
637
638
        // Assert
639
        $result = $fixture->resolve('mock', new Context(''));
640
        $this->assertInstanceOf(get_class($typeMock), $result);
641
        $this->assertNotSame($typeMock, $result);
642
    }
643
644
    /**
645
     * @uses \phpDocumentor\Reflection\Types\Context
646
     *
647
     * @covers ::__construct
648
     * @covers ::addKeyword
649
     */
650
    public function testAddingAKeywordFailsIfTypeClassDoesNotExist() : void
651
    {
652
        $this->expectException('InvalidArgumentException');
653
        $fixture = new TypeResolver();
654
        $fixture->addKeyword('mock', 'IDoNotExist');
655
    }
656
657
    /**
658
     * @uses \phpDocumentor\Reflection\Types\Context
659
     *
660
     * @covers ::__construct
661
     * @covers ::addKeyword
662
     */
663
    public function testAddingAKeywordFailsIfTypeClassDoesNotImplementTypeInterface() : void
664
    {
665
        $this->expectException('InvalidArgumentException');
666
        $fixture = new TypeResolver();
667
        $fixture->addKeyword('mock', stdClass::class);
668
    }
669
670
    /**
671
     * @uses \phpDocumentor\Reflection\Types\Context
672
     *
673
     * @covers ::__construct
674
     * @covers ::resolve
675
     */
676
    public function testExceptionIsThrownIfTypeIsEmpty() : void
677
    {
678
        $this->expectException('InvalidArgumentException');
679
        $fixture = new TypeResolver();
680
        $fixture->resolve(' ', new Context(''));
681
    }
682
683
    /**
684
     * Returns a list of keywords and expected classes that are created from them.
685
     *
686
     * @return string[][]
687
     */
688
    public function provideKeywords() : array
689
    {
690
        return [
691
            ['string', Types\String_::class],
692
            ['class-string', Types\ClassString::class],
693
            ['int', Types\Integer::class],
694
            ['integer', Types\Integer::class],
695
            ['float', Types\Float_::class],
696
            ['double', Types\Float_::class],
697
            ['bool', Types\Boolean::class],
698
            ['boolean', Types\Boolean::class],
699
            ['resource', Types\Resource_::class],
700
            ['null', Types\Null_::class],
701
            ['callable', Types\Callable_::class],
702
            ['callback', Types\Callable_::class],
703
            ['array', Array_::class],
704
            ['scalar', Types\Scalar::class],
705
            ['object', Object_::class],
706
            ['mixed', Types\Mixed_::class],
707
            ['void', Types\Void_::class],
708
            ['$this', Types\This::class],
709
            ['static', Types\Static_::class],
710
            ['self', Types\Self_::class],
711
            ['parent', Types\Parent_::class],
712
            ['iterable', Iterable_::class],
713
        ];
714
    }
715
716
    /**
717
     * Returns a list of class string types and whether they throw an exception.
718
     *
719
     * @return (string|bool)[][]
720
     */
721
    public function provideClassStrings() : array
722
    {
723
        return [
724
            ['class-string<\phpDocumentor\Reflection>', false],
725
            ['class-string<\phpDocumentor\Reflection\DocBlock>', false],
726
            ['class-string<string>', true],
727
        ];
728
    }
729
730
    /**
731
     * Provides a list of FQSENs to test the resolution patterns with.
732
     *
733
     * @return string[][]
734
     */
735
    public function provideFqcn() : array
736
    {
737
        return [
738
            'namespace' => ['\phpDocumentor\Reflection'],
739
            'class' => ['\phpDocumentor\Reflection\DocBlock'],
740
            'class with emoji' => ['\My😁Class'],
741
        ];
742
    }
743
}
744