Test Setup Failed
Push — test ( 24878d...6ecee8 )
by Jonathan
02:38
created

ParserTest   C

Complexity

Total Complexity 44

Size/Duplication

Total Lines 900
Duplicated Lines 3.67 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
dl 33
loc 900
rs 6.6415
c 0
b 0
f 0
wmc 44
lcom 1
cbo 9

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ParserTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ParserTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Kint\Test\Parser;
4
5
use Exception;
6
use Kint\Object\BasicObject;
7
use Kint\Object\BlobObject;
8
use Kint\Object\InstanceObject;
9
use Kint\Object\Representation\Representation;
10
use Kint\Object\ResourceObject;
11
use Kint\Parser\Parser;
12
use Kint\Parser\ProxyPlugin;
13
use Kint\Test\Fixtures\ChildTestClass;
14
use PHPUnit_Framework_TestCase;
15
use ReflectionMethod;
16
use ReflectionProperty;
17
use stdClass;
18
19
class ParserTest extends PHPUnit_Framework_TestCase
20
{
21
    public function testTriggerComplete()
22
    {
23
        $this->assertEquals(
24
            Parser::TRIGGER_SUCCESS |
25
            Parser::TRIGGER_DEPTH_LIMIT |
26
            Parser::TRIGGER_RECURSION,
27
            Parser::TRIGGER_COMPLETE
28
        );
29
    }
30
31
    /**
32
     * @covers \Kint\Parser\Parser::__construct
33
     * @covers \Kint\Parser\Parser::getDepthLimit
34
     * @covers \Kint\Parser\Parser::getCallerClass
35
     */
36
    public function testConstruct()
37
    {
38
        $marker = new ReflectionProperty('Kint\\Parser\\Parser', 'marker');
39
40
        $marker->setAccessible(true);
41
42
        $p1 = new Parser();
43
44
        $this->assertFalse($p1->getDepthLimit());
45
        $this->assertNull($p1->getCallerClass());
46
47
        $p2 = new Parser(123, 'asdf');
48
49
        $this->assertSame(123, $p2->getDepthLimit());
50
        $this->assertSame('asdf', $p2->getCallerClass());
51
        $this->assertNotEquals($marker->getValue($p1), $marker->getValue($p2));
52
    }
53
54
    /**
55
     * @covers \Kint\Parser\Parser::parse
56
     * @covers \Kint\Parser\Parser::parseGeneric
57
     */
58
    public function testParseInteger()
59
    {
60
        $p = new Parser();
61
        $b = BasicObject::blank('$v');
62
        $v = 1234;
63
64
        $o = $p->parse($v, clone $b);
65
66
        $this->assertEquals('$v', $o->access_path);
67
        $this->assertEquals('$v', $o->name);
68
        $this->assertEquals('integer', $o->type);
69
        $this->assertEquals('Kint\\Object\\BasicObject', get_class($o));
70
        $this->assertEquals('Kint\\Object\\Representation\\Representation', get_class($o->value));
71
        $this->assertEquals(1234, $o->value->contents);
72
        $this->assertEquals(1234, $v);
73
        $this->assertEquals(0, $o->depth);
74
    }
75
76
    /**
77
     * @covers \Kint\Parser\Parser::parse
78
     * @covers \Kint\Parser\Parser::parseGeneric
79
     */
80
    public function testParseBoolean()
81
    {
82
        $p = new Parser();
83
        $b = BasicObject::blank('$v');
84
        $v = true;
85
86
        $o = $p->parse($v, clone $b);
87
88
        $this->assertEquals('boolean', $o->type);
89
        $this->assertEquals(true, $o->value->contents);
90
91
        $v = false;
92
93
        $o = $p->parse($v, clone $b);
94
95
        $this->assertEquals(false, $o->value->contents);
96
    }
97
98
    /**
99
     * @covers \Kint\Parser\Parser::parse
100
     * @covers \Kint\Parser\Parser::parseGeneric
101
     */
102
    public function testParseDouble()
103
    {
104
        $p = new Parser();
105
        $b = BasicObject::blank('$v');
106
        $v = 1234.5678;
107
108
        $o = $p->parse($v, clone $b);
109
110
        $this->assertEquals('double', $o->type);
111
        $this->assertEquals(1234.5678, $o->value->contents);
112
    }
113
114
    /**
115
     * @covers \Kint\Parser\Parser::parse
116
     * @covers \Kint\Parser\Parser::parseGeneric
117
     */
118
    public function testParseNull()
119
    {
120
        $p = new Parser();
121
        $b = BasicObject::blank('$v');
122
        $v = null;
123
124
        $o = $p->parse($v, clone $b);
125
126
        $this->assertEquals('null', $o->type);
127
        $this->assertEquals(null, $o->value->contents);
128
    }
129
130
    /**
131
     * @covers \Kint\Parser\Parser::parse
132
     * @covers \Kint\Parser\Parser::parseString
133
     */
134
    public function testParseString()
135
    {
136
        $p = new Parser();
137
        $b = BasicObject::blank('$v');
138
        $v = 'The quick brown fox jumps over the lazy dog';
139
140
        $o = $p->parse($v, clone $b);
141
142
        $this->assertInstanceOf('Kint\\Object\\BlobObject', $o);
143
        if (!$o instanceof BlobObject) {
144
            return; // phpstan
145
        }
146
147
        $this->assertEquals('string', $o->type);
148
        $this->assertEquals($v, $o->value->contents);
149
        $this->assertEquals(true, $o->value->implicit_label);
150
        $this->assertEquals('ASCII', $o->encoding);
151
        $this->assertEquals(strlen($v), $o->size);
152
        $this->assertContains('string', $o->hints);
153
154
        // Apologies to Spanish programmers, Google made this sentence.
155
        $v = 'El zorro marrón rápido salta sobre el perro perezoso';
156
157
        $o = $p->parse($v, clone $b);
158
159
        $this->assertInstanceOf('Kint\\Object\\BlobObject', $o);
160
        if (!$o instanceof BlobObject) {
161
            return; // phpstan
162
        }
163
164
        $this->assertEquals($v, $o->value->contents);
165
        $this->assertEquals('UTF-8', $o->encoding);
166
        $this->assertEquals(mb_strlen($v, 'UTF-8'), $o->size);
167
        $this->assertNotEquals(strlen($v), $o->size);
168
    }
169
170
    /**
171
     * @covers \Kint\Parser\Parser::parse
172
     * @covers \Kint\Parser\Parser::parseResource
173
     */
174
    public function testParseResource()
175
    {
176
        $p = new Parser();
177
        $b = BasicObject::blank('$v');
178
        $v = imagecreate(1, 1);
179
180
        $o = $p->parse($v, clone $b);
181
182
        $this->assertInstanceOf('Kint\\Object\\ResourceObject', $o);
183
        if (!$o instanceof ResourceObject) {
184
            return; // phpstan
185
        }
186
187
        $this->assertEquals('resource', $o->type);
188
        $this->assertEquals(null, $o->value);
189
        $this->assertEquals('gd', $o->resource_type);
190
    }
191
192
    /**
193
     * @covers \Kint\Parser\Parser::parse
194
     * @covers \Kint\Parser\Parser::parseArray
195
     */
196
    public function testParseArray()
197
    {
198
        $p = new Parser();
199
        $b = BasicObject::blank('$v');
200
        $v = array(
201
            1234,
202
            'key' => 'value',
203
            1234 => 5678,
204
        );
205
206
        $o = $p->parse($v, clone $b);
207
208
        $this->assertEquals('array', $o->type);
209
210
        $val = array_values($o->value->contents);
211
212
        $this->assertEquals(0, $val[0]->name);
213
        $this->assertEquals(1234, $val[0]->value->contents);
214
        $this->assertEquals('$v[0]', $val[0]->access_path);
215
        $this->assertEquals(BasicObject::OPERATOR_ARRAY, $val[0]->operator);
216
        $this->assertEquals('key', $val[1]->name);
217
        $this->assertEquals('value', $val[1]->value->contents);
218
        $this->assertEquals('$v[\'key\']', $val[1]->access_path);
219
        $this->assertEquals(BasicObject::OPERATOR_ARRAY, $val[1]->operator);
220
        $this->assertEquals(1234, $val[2]->name);
221
        $this->assertEquals(5678, $val[2]->value->contents);
222
        $this->assertEquals('$v[1234]', $val[2]->access_path);
223
        $this->assertEquals(BasicObject::OPERATOR_ARRAY, $val[2]->operator);
224
225
        $v = array();
226
227
        $o = $p->parse($v, clone $b);
228
229
        $this->assertInstanceOf('Kint\\Object\\Representation\\Representation', $o->value);
230
        $this->assertCount(0, $o->value->contents);
231
    }
232
233
    /**
234
     * @covers \Kint\Parser\Parser::parse
235
     * @covers \Kint\Parser\Parser::parseObject
236
     */
237
    public function testParseObject()
238
    {
239
        $p = new Parser();
240
        $b = BasicObject::blank('$v');
241
        $v = new ChildTestClass();
242
243
        $o = $p->parse($v, clone $b);
244
245
        $this->assertInstanceOf('Kint\\Object\\InstanceObject', $o);
246
        if (!$o instanceof InstanceObject) {
247
            return; // phpstan
248
        }
249
250
        $this->assertEquals('object', $o->type);
251
        $this->assertEquals('Kint\\Test\\Fixtures\\ChildTestClass', $o->classname);
252
        $this->assertEquals(spl_object_hash($v), $o->hash);
253
        $this->assertContains('object', $o->hints);
254
255
        $val = array_values($o->value->contents);
256
257
        $this->assertEquals('pub', $val[0]->name);
258
        $this->assertEquals('array', $val[0]->type);
259
        $this->assertEquals(BasicObject::OPERATOR_OBJECT, $val[0]->operator);
260
        $this->assertEquals('$v->pub', $val[0]->access_path);
261
        $this->assertEquals('pro', $val[1]->name);
262
        $this->assertEquals('array', $val[1]->type);
263
        $this->assertEquals(BasicObject::OPERATOR_OBJECT, $val[1]->operator);
264
        $this->assertNull($val[1]->access_path);
265
        $this->assertEquals('pri', $val[2]->name);
266
        $this->assertEquals('array', $val[2]->type);
267
        $this->assertEquals(BasicObject::OPERATOR_OBJECT, $val[2]->operator);
268
        $this->assertNull($val[2]->access_path);
269
    }
270
271
    /**
272
     * @covers \Kint\Parser\Parser::parse
273
     * @covers \Kint\Parser\Parser::parseUnknown
274
     */
275
    public function testParseUnknown()
276
    {
277
        $p = new Parser();
278
        $b = BasicObject::blank('$v');
279
        $v = imagecreate(1, 1);
280
        imagedestroy($v);
281
282
        $o = $p->parse($v, clone $b);
283
284
        $this->assertEquals('unknown', $o->type);
285
        $this->assertNull($o->value);
286
    }
287
288
    /**
289
     * @covers \Kint\Parser\Parser::parseArray
290
     * @covers \Kint\Parser\Parser::parseObject
291
     */
292
    public function testParseReferences()
293
    {
294
        $p = new Parser();
295
        $b = BasicObject::blank('$v');
296
        $r = 1234;
297
        $v = array(&$r, 1234);
298
299
        $o = $p->parse($v, clone $b);
300
301
        $this->assertEquals(true, $o->value->contents[0]->reference);
302
        $this->assertEquals(false, $o->value->contents[1]->reference);
303
304
        $v = new stdClass();
305
        $v->v1 = &$r;
306
        $v->v2 = 1234;
307
308
        $o = $p->parse($v, clone $b);
309
310
        $this->assertEquals(true, $o->value->contents[0]->reference);
311
        $this->assertEquals(false, $o->value->contents[1]->reference);
312
    }
313
314
    /**
315
     * @covers \Kint\Parser\Parser::parseArray
316
     * @covers \Kint\Parser\Parser::parseObject
317
     */
318
    public function testParseRecursion()
319
    {
320
        $p = new Parser();
321
        $b = BasicObject::blank('$v');
322
        $v = array();
323
        $v[] = &$v;
324
325
        $recursed = false;
326
327
        $pl = new ProxyPlugin(
328
            array('array', 'object'),
329
            Parser::TRIGGER_RECURSION,
330
            function () use (&$recursed) {
331
                $recursed = true;
332
            }
333
        );
334
        $p->addPlugin($pl);
335
336
        $o = $p->parse($v, clone $b);
337
338
        $this->assertContains('recursion', $o->value->contents[0]->hints);
339
        $this->assertEquals(true, $recursed);
340
341
        $v = new stdClass();
342
        $v->v = $v;
343
344
        $recursed = false;
345
346
        $o = $p->parse($v, clone $b);
347
348
        $this->assertContains('recursion', $o->value->contents[0]->hints);
349
        $this->assertEquals(true, $recursed);
350
    }
351
352
    /**
353
     * @covers \Kint\Parser\Parser::parseDeep
354
     * @covers \Kint\Parser\Parser::parseArray
355
     * @covers \Kint\Parser\Parser::parseObject
356
     */
357
    public function testParseDepthLimit()
358
    {
359
        $p = new Parser(1);
360
        $b = BasicObject::blank('$v');
361
        $v = array(array(1234));
362
363
        $limit = false;
364
365
        $pl = new ProxyPlugin(
366
            array('array', 'object'),
367
            Parser::TRIGGER_DEPTH_LIMIT,
368
            function () use (&$limit) {
369
                $limit = true;
370
            }
371
        );
372
        $p->addPlugin($pl);
373
374
        $o = $p->parse($v, clone $b);
375
376
        $this->assertContains('depth_limit', $o->value->contents[0]->hints);
377
        $this->assertTrue($limit);
378
379
        $limit = false;
380
381
        $v = new stdClass();
382
        $v->v = 1234;
383
        $v = array($v);
384
385
        $o = $p->parse($v, clone $b);
386
387
        $this->assertContains('depth_limit', $o->value->contents[0]->hints);
388
        $this->assertTrue($limit);
389
390
        $limit = false;
391
392
        $o = $p->parseDeep($v, clone $b);
393
394
        $this->assertNotContains('depth_limit', $o->value->contents[0]->hints);
395
        $this->assertFalse($limit);
396
    }
397
398
    /**
399
     * @covers \Kint\Parser\Parser::parseArray
400
     * @covers \Kint\Parser\Parser::parseObject
401
     */
402
    public function testParseCastKeys()
403
    {
404
        $p = new Parser();
405
        $b = BasicObject::blank('$v');
406
407
        // Object from array
408
        $v1 = (object) array('value');
409
        $o1 = $p->parse($v1, clone $b);
410
411
        // Normal object
412
        $v2 = new stdClass();
413
        $v2->{0} = 'value';
414
        $o2 = $p->parse($v2, clone $b);
415
416
        // Array from object
417
        $v3 = new stdClass();
418
        $v3->{0} = 'value';
419
        $v3 = (array) $v3;
420
        $o3 = $p->parse($v3, clone $b);
421
422
        // Normal array
423
        $v4 = array('value');
424
        $o4 = $p->parse($v4, clone $b);
425
426
        // Object with both
427
        $v5 = (object) array('value');
428
        $v5->{0} = 'value2';
429
        $o5 = $p->parse($v5, clone $b);
430
431
        // Array with both
432
        $v6 = new stdClass();
433
        $v6->{0} = 'value';
434
        $v6 = (array) $v6;
435
        $v6['0'] = 'value2';
436
        $o6 = $p->parse($v6, clone $b);
437
438
        if (version_compare(PHP_VERSION, '7.2') >= 0) {
439
            // Object from array
440
            $this->assertEquals(1, $o1->size);
441
            $this->assertEquals('value', $o1->value->contents[0]->value->contents);
442
            $this->assertEquals('$v->{\'0\'}', $o1->value->contents[0]->access_path);
443
            $this->assertTrue(isset($v1->{'0'}));
444
            $this->assertSame('0', $o1->value->contents[0]->name);
445
446
            // Normal object
447
            $this->assertEquals(1, $o2->size);
448
            $this->assertEquals('value', $o2->value->contents[0]->value->contents);
449
            $this->assertEquals('$v->{\'0\'}', $o2->value->contents[0]->access_path);
450
            $this->assertTrue(isset($v2->{'0'}));
451
            $this->assertSame('0', $o2->value->contents[0]->name);
452
453
            // Array from object
454
            $this->assertEquals(1, $o3->size);
455
            $this->assertEquals('value', $o3->value->contents[0]->value->contents);
456
            $this->assertEquals('$v[0]', $o3->value->contents[0]->access_path);
457
            $this->assertTrue(isset($v3['0']));
458
            $this->assertSame(0, $o3->value->contents[0]->name);
459
460
            // Normal array
461
            $this->assertEquals(1, $o4->size);
462
            $this->assertEquals('value', $o4->value->contents[0]->value->contents);
463
            $this->assertEquals('$v[0]', $o4->value->contents[0]->access_path);
464
            $this->assertTrue(isset($v4['0']));
465
            $this->assertSame(0, $o4->value->contents[0]->name);
466
467
            // Object with both
468
            $this->assertEquals(1, $o5->size);
469
            $this->assertEquals('value2', $o5->value->contents[0]->value->contents);
470
            $this->assertEquals('$v->{\'0\'}', $o5->value->contents[0]->access_path);
471
            $this->assertSame('0', $o5->value->contents[0]->name);
472
473
            // Array with both
474
            $this->assertEquals(1, $o6->size);
475
            $this->assertEquals('value2', $o6->value->contents[0]->value->contents);
476
            $this->assertEquals('$v[0]', $o6->value->contents[0]->access_path);
477
            $this->assertSame(0, $o6->value->contents[0]->name);
478
479
            // Object with both and weak equality (As of PHP 7.2)
480
            $v7 = (object) array('value');
481
            $v7->{'0'} = 'value2';
482
            $v7->{''} = 'value3';
483
            $o7 = $p->parse($v7, clone $b);
484
485
            // Object with both and weak equality
486
            $this->assertEquals(2, $o7->size);
487
            foreach ($o7->value->contents as $o) {
488
                $this->assertContains($o->value->contents, array('value2', 'value3'));
489
490
                if ($o->value->contents === 'value2') {
491
                    $this->assertEquals('$v->{\'0\'}', $o->access_path);
492
                    $this->assertSame('0', $o->name);
493
                } elseif ($o->value->contents === 'value3') {
494
                    $this->assertEquals('$v->{\'\'}', $o->access_path);
495
                    $this->assertSame('', $o->name);
496
                }
497
            }
498
        } else {
499
            // Object from array
500
            $this->assertEquals(1, $o1->size);
501
            $this->assertEquals('value', $o1->value->contents[0]->value->contents);
502
            $this->assertEquals('array_values((array) $v)[0]', $o1->value->contents[0]->access_path);
503
            $this->assertFalse(isset($v1->{'0'}));
504
            $this->assertSame(0, $o1->value->contents[0]->name);
505
506
            // Normal object
507
            $this->assertEquals(1, $o2->size);
508
            $this->assertEquals('value', $o2->value->contents[0]->value->contents);
509
            $this->assertEquals('$v->{\'0\'}', $o2->value->contents[0]->access_path);
510
            $this->assertTrue(isset($v2->{'0'}));
511
            $this->assertSame('0', $o2->value->contents[0]->name);
512
513
            // Array from object
514
            $this->assertEquals(1, $o3->size);
515
            $this->assertEquals('value', $o3->value->contents[0]->value->contents);
516
            $this->assertEquals('array_values($v)[0]', $o3->value->contents[0]->access_path);
517
            $this->assertFalse(isset($v3['0']));
518
            $this->assertSame('0', $o3->value->contents[0]->name);
519
520
            // Normal array
521
            $this->assertEquals(1, $o4->size);
522
            $this->assertEquals('value', $o4->value->contents[0]->value->contents);
523
            $this->assertEquals('$v[0]', $o4->value->contents[0]->access_path);
524
            $this->assertTrue(isset($v4['0']));
525
            $this->assertSame(0, $o4->value->contents[0]->name);
526
527
            // Object with both
528
            $this->assertEquals(2, $o5->size);
529
            foreach ($o5->value->contents as $o) {
530
                $this->assertContains($o->value->contents, array('value', 'value2'));
531
532
                if ($o->value->contents === 'value') {
533
                    $this->assertEquals('array_values((array) $v)[0]', $o->access_path);
534
                    $this->assertSame(0, $o->name);
535
                } elseif ($o->value->contents === 'value2') {
536
                    $this->assertEquals('$v->{\'0\'}', $o->access_path);
537
                    $this->assertSame('0', $o->name);
538
                }
539
            }
540
541
            // Array with both
542
            $this->assertEquals(2, $o6->size);
543
            foreach ($o6->value->contents as $o) {
544
                $this->assertContains($o->value->contents, array('value', 'value2'));
545
546
                if ($o->value->contents === 'value') {
547
                    $this->assertEquals('array_values($v)[0]', $o->access_path);
548
                    $this->assertSame('0', $o->name);
549
                } elseif ($o->value->contents === 'value2') {
550
                    $this->assertEquals('$v[0]', $o->access_path);
551
                    $this->assertSame(0, $o->name);
552
                }
553
            }
554
        }
555
    }
556
557
    /**
558
     * @covers \Kint\Parser\Parser::parseObject
559
     * @covers \Kint\Parser\Parser::childHasPath
560
     */
561
    public function testParseAccessPathAvailability()
562
    {
563
        $b = BasicObject::blank('$v');
564
        $v = new ChildTestClass();
565
566
        $p = new Parser();
567
        $o = $p->parse($v, clone $b);
568
        $properties = array();
569
        foreach ($o->value->contents as $prop) {
570
            $properties[$prop->name] = $prop;
571
        }
572
        $this->assertEquals('$v->pub', $properties['pub']->access_path);
573
        $this->assertNull($properties['pro']->access_path);
574
        $this->assertNull($properties['pri']->access_path);
575
576
        $p = new Parser(false, 'Kint\\Test\\Fixtures\\ChildTestClass');
577
        $o = $p->parse($v, clone $b);
578
        $properties = array();
579
        foreach ($o->value->contents as $prop) {
580
            $properties[$prop->name] = $prop;
581
        }
582
        $this->assertEquals('$v->pub', $properties['pub']->access_path);
583
        $this->assertEquals('$v->pro', $properties['pro']->access_path);
584
        $this->assertNull($properties['pri']->access_path);
585
586
        $p = new Parser(false, 'Kint\\Test\\Fixtures\\TestClass');
587
        $o = $p->parse($v, clone $b);
588
        $properties = array();
589
        foreach ($o->value->contents as $prop) {
590
            $properties[$prop->name] = $prop;
591
        }
592
        $this->assertEquals('$v->pub', $properties['pub']->access_path);
593
        $this->assertEquals('$v->pro', $properties['pro']->access_path);
594
        $this->assertEquals('$v->pri', $properties['pri']->access_path);
595
    }
596
597
    /**
598
     * @covers \Kint\Parser\Parser::applyPlugins
599
     * @covers \Kint\Parser\Parser::addPlugin
600
     * @covers \Kint\Parser\Parser::clearPlugins
601
     */
602
    public function testPlugins()
603
    {
604
        $p = new Parser();
605
        $b = BasicObject::blank('$v');
606
        $v = 1234;
607
608
        $o = $p->parse($v, clone $b);
609
610
        $this->assertObjectNotHasAttribute('testPluginCorrectlyActivated', $o);
611
612
        $pl = new ProxyPlugin(
613
            array('integer'),
614
            Parser::TRIGGER_SUCCESS,
615
            function (&$var, &$o) {
616
                $o->testPluginCorrectlyActivated = true;
617
            }
618
        );
619
        $p->addPlugin($pl);
620
621
        $o = $p->parse($v, clone $b);
622
623
        $this->assertObjectHasAttribute('testPluginCorrectlyActivated', $o);
624
625
        $p->clearPlugins();
626
627
        $o = $p->parse($v, clone $b);
628
629
        $this->assertObjectNotHasAttribute('testPluginCorrectlyActivated', $o);
630
631
        $pl = new ProxyPlugin(
632
            array(),
633
            Parser::TRIGGER_SUCCESS,
634
            function () {}
635
        );
636
        $this->assertFalse($p->addPlugin($pl));
637
638
        $pl = new ProxyPlugin(
639
            array('integer'),
640
            Parser::TRIGGER_NONE,
641
            function () {}
642
        );
643
        $this->assertFalse($p->addPlugin($pl));
644
    }
645
646
    /**
647
     * @covers \Kint\Parser\Parser::applyPlugins
648
     * @covers \Kint\Parser\Parser::addPlugin
649
     */
650
    public function testTriggers()
651
    {
652
        $p = new Parser(1);
653
        $b = BasicObject::blank('$v');
654
        $v = array(1234, array(1234));
655
        $v[] = &$v;
656
657
        $triggers = array();
658
659
        $pl = new ProxyPlugin(
660
            array('integer', 'array'),
661
            Parser::TRIGGER_BEGIN | Parser::TRIGGER_COMPLETE,
662
            function (&$var, &$o, $trig) use (&$triggers) {
663
                $triggers[] = $trig;
664
            }
665
        );
666
        $p->addPlugin($pl);
667
668
        $o = $p->parse($v, clone $b);
669
670
        $this->assertEquals(
671
            array(
672
                Parser::TRIGGER_BEGIN,
673
                Parser::TRIGGER_BEGIN,
674
                Parser::TRIGGER_SUCCESS,
675
                Parser::TRIGGER_BEGIN,
676
                Parser::TRIGGER_DEPTH_LIMIT,
677
                Parser::TRIGGER_BEGIN,
678
                Parser::TRIGGER_RECURSION,
679
                Parser::TRIGGER_SUCCESS,
680
            ),
681
            $triggers
682
        );
683
    }
684
685
    /**
686
     * @covers \Kint\Parser\Parser::parse
687
     * @covers \Kint\Parser\Parser::applyPlugins
688
     * @covers \Kint\Parser\Parser::haltParse
689
     */
690
    public function testHaltParse()
691
    {
692
        $p = new Parser();
693
        $b = BasicObject::blank('$v');
694
        $t = clone $b;
695
        $t->type = 'integer';
696
        $v = 1234;
697
698
        $pl = new ProxyPlugin(
699
            array('integer'),
700
            Parser::TRIGGER_BEGIN,
701
            function (&$var, &$o, $trig, $parser) {
702
                $parser->haltParse();
703
            }
704
        );
705
        $p->addPlugin($pl);
706
707
        $o = $p->parse($v, $t);
708
709
        $this->assertSame($t, $o);
710
711
        $p->clearPlugins();
712
713
        $pl = new ProxyPlugin(
714
            array('integer'),
715
            Parser::TRIGGER_SUCCESS,
716
            function (&$var, &$o, $trig, $parser) {
717
                $parser->haltParse();
718
            }
719
        );
720
        $p->addPlugin($pl);
721
722
        $pl = new ProxyPlugin(
723
            array('integer'),
724
            Parser::TRIGGER_SUCCESS,
725
            function (&$var, &$o) {
726
                $o->testPluginCorrectlyActivated = true;
727
            }
728
        );
729
        $p->addPlugin($pl);
730
731
        $o = $p->parse($v, clone $b);
732
733
        $this->assertObjectNotHasAttribute('testPluginCorrectlyActivated', $o);
734
    }
735
736
    /**
737
     * @expectedException \PHPUnit_Framework_Error_Warning
738
     * @covers \Kint\Parser\Parser::applyPlugins
739
     */
740
    public function testPluginExceptionBecomesWarning()
741
    {
742
        $p = new Parser();
743
        $b = BasicObject::blank('$v');
744
        $t = clone $b;
745
        $t->type = 'integer';
746
        $v = 1234;
747
748
        $message = __FUNCTION__;
749
750
        $pl = new ProxyPlugin(
751
            array('integer'),
752
            Parser::TRIGGER_BEGIN,
753
            function (&$var, &$o, $trig, $parser) use ($message) {
754
                throw new Exception($message);
755
            }
756
        );
757
        $p->addPlugin($pl);
758
759
        $o = $p->parse($v, clone $b);
760
    }
761
762
    public function childHasPathProvider()
763
    {
764
        $data = array();
765
766
        $expected = array(
767
            'public parser' => array(
768
                new Parser(),
769
                array(
770
                    'props' => array('$v', false, true, false, false),
771
                    'statics' => array('$v', true, true, false, false),
772
                    'props without path' => array(null, false, false, false, false),
773
                    'statics without path' => array(null, true, true, false, false),
774
                ),
775
            ),
776
            'protected parser' => array(
777
                new Parser(false, 'Kint\\Test\\Fixtures\\ChildTestClass'),
778
                array(
779
                    'props' => array('$v', false, true, true, false),
780
                    'statics' => array('$v', true, true, true, false),
781
                    'props without path' => array(null, false, false, false, false),
782
                    'statics without path' => array(null, true, true, true, false),
783
                ),
784
            ),
785
            'private parser' => array(
786
                new Parser(false, 'Kint\\Test\\Fixtures\\TestClass'),
787
                array(
788
                    'props' => array('$v', false, true, true, true),
789
                    'statics' => array('$v', true, true, true, true),
790
                    'props without path' => array(null, false, false, false, false),
791
                    'statics without path' => array(null, true, true, true, true),
792
                ),
793
            ),
794
        );
795
796
        foreach ($expected as $parser_name => $params) {
797
            list($parser, $opts) = $params;
798
799
            foreach ($opts as $name => $set) {
800
                list($path, $static, $pub, $pro, $pri) = $set;
801
802
                $visibilities = array(
803
                    BasicObject::ACCESS_PUBLIC => $pub,
804
                    BasicObject::ACCESS_PROTECTED => $pro,
805
                    BasicObject::ACCESS_PRIVATE => $pri,
806
                );
807
808
                foreach ($visibilities as $visibility => $expect) {
809
                    $parent = BasicObject::blank();
810
                    $parent = $parent->transplant(new InstanceObject());
811
                    $parent->classname = 'Kint\\Test\\Fixtures\\ChildTestClass';
812
                    $parent->type = 'object';
813
814
                    $r = new Representation('Contents');
815
                    $parent->addRepresentation($r);
816
817
                    $prop = BasicObject::blank();
818
                    $r->contents = array($prop);
819
                    $prop->owner_class = 'Kint\\Test\\Fixtures\\TestClass';
820
821
                    $parent->access_path = $path;
822
                    $prop->static = $static;
823
                    $prop->access = $visibility;
824
825
                    $data[$parser_name.', '.$visibility.' '.$name] = array($parser, $parent, $prop, $expect);
826
                }
827
            }
828
        }
829
830
        return $data;
831
    }
832
833
    /**
834
     * @dataProvider childHasPathProvider
835
     * @covers \Kint\Parser\Parser::childHasPath
836
     */
837
    public function testChildHasPath($parser, $parent, $child, $expected)
838
    {
839
        $this->assertEquals($expected, $parser->childHasPath($parent, $child));
840
    }
841
842
    /**
843
     * @covers \Kint\Parser\Parser::sortObjectProperties
844
     */
845
    public function testSortObjectProperties()
846
    {
847
        $p = new Parser();
848
849
        $ctc = new ChildTestClass();
850
851
        $o = $p->parse($ctc, BasicObject::blank('$ctc'));
852
853
        $pub = $o->value->contents[0];
854
        $pro = $o->value->contents[1];
855
856
        $rm = new ReflectionMethod('Kint\\Parser\\Parser', 'sortObjectProperties');
857
        $rm->setAccessible(true);
858
859
        $this->assertEquals(0, $rm->invoke($p, $pub, $pub));
860
861
        // Sort by access first
862
        $this->assertEquals(-1, $rm->invoke($p, $pub, $pro));
863
        $this->assertEquals(1, $rm->invoke($p, $pro, $pub));
864
865
        // With the same access they go by name so they should flip
866
        $pro->access = $pub->access;
867
        $this->assertEquals(1, $rm->invoke($p, $pub, $pro));
868
        $this->assertEquals(-1, $rm->invoke($p, $pro, $pub));
869
870
        // With the same name they should go by hierarchy
871
        $pro->name = $pub->name;
872
        $pro->owner_class = 'Kint\\Test\\Fixtures\\TestClass';
873
        $this->assertEquals(-1, $rm->invoke($p, $pub, $pro));
874
        $this->assertEquals(1, $rm->invoke($p, $pro, $pub));
875
876
        // With everything the same they should be more or less equal
877
        $pro->owner_class = $pub->owner_class;
878
        $this->assertEquals(0, $rm->invoke($p, $pub, $pro));
879
        $this->assertEquals(0, $rm->invoke($p, $pro, $pub));
880
    }
881
882
    /**
883
     * @covers \Kint\Parser\Parser::getCleanArray
884
     */
885
    public function testGetCleanArray()
886
    {
887
        $p = new Parser();
888
        $b = BasicObject::blank('$v');
889
        $v = array(1234);
890
891
        $arrays = array();
892
893
        $pl = new ProxyPlugin(
894
            array('array'),
895
            Parser::TRIGGER_SUCCESS,
896
            function (&$var, &$o, $trig, $parser) use (&$arrays) {
897
                $clean = $parser->getCleanArray($var);
898
899
                // This here is exactly why you should never alter input
900
                // variables in plugins and always use getCleanArray
901
                $var[] = 4321;
902
                $clean[] = 8765;
903
904
                $arrays = array(
905
                    'var' => $var,
906
                    'clean' => $clean,
907
                );
908
            }
909
        );
910
        $p->addPlugin($pl);
911
912
        $o = $p->parse($v, clone $b);
913
914
        $this->assertEquals(array(1234, 4321), $v);
915
        $this->assertEquals(array(1234, 8765), $arrays['clean']);
916
        $this->assertEquals(count($v) + 1, count($arrays['var']));
917
    }
918
}
919