Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php declare(strict_types=1);
2
/*
3
 * This file is part of phpunit/php-code-coverage.
4
 *
5
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace SebastianBergmann\CodeCoverage\Node;
11
 
12
use function array_filter;
13
use function count;
14
use function range;
15
 
16
/**
17
 * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
18
 */
19
final class File extends AbstractNode
20
{
21
    /**
22
     * @var array
23
     */
24
    private $lineCoverageData;
25
 
26
    /**
27
     * @var array
28
     */
29
    private $functionCoverageData;
30
 
31
    /**
32
     * @var array
33
     */
34
    private $testData;
35
 
36
    /**
37
     * @var int
38
     */
39
    private $numExecutableLines = 0;
40
 
41
    /**
42
     * @var int
43
     */
44
    private $numExecutedLines = 0;
45
 
46
    /**
47
     * @var int
48
     */
49
    private $numExecutableBranches = 0;
50
 
51
    /**
52
     * @var int
53
     */
54
    private $numExecutedBranches = 0;
55
 
56
    /**
57
     * @var int
58
     */
59
    private $numExecutablePaths = 0;
60
 
61
    /**
62
     * @var int
63
     */
64
    private $numExecutedPaths = 0;
65
 
66
    /**
67
     * @var array
68
     */
69
    private $classes = [];
70
 
71
    /**
72
     * @var array
73
     */
74
    private $traits = [];
75
 
76
    /**
77
     * @var array
78
     */
79
    private $functions = [];
80
 
81
    /**
82
     * @psalm-var array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
83
     */
84
    private $linesOfCode;
85
 
86
    /**
87
     * @var int
88
     */
89
    private $numClasses;
90
 
91
    /**
92
     * @var int
93
     */
94
    private $numTestedClasses = 0;
95
 
96
    /**
97
     * @var int
98
     */
99
    private $numTraits;
100
 
101
    /**
102
     * @var int
103
     */
104
    private $numTestedTraits = 0;
105
 
106
    /**
107
     * @var int
108
     */
109
    private $numMethods;
110
 
111
    /**
112
     * @var int
113
     */
114
    private $numTestedMethods;
115
 
116
    /**
117
     * @var int
118
     */
119
    private $numTestedFunctions;
120
 
121
    /**
122
     * @var array
123
     */
124
    private $codeUnitsByLine = [];
125
 
126
    /**
127
     * @psalm-param array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int} $linesOfCode
128
     */
129
    public function __construct(string $name, AbstractNode $parent, array $lineCoverageData, array $functionCoverageData, array $testData, array $classes, array $traits, array $functions, array $linesOfCode)
130
    {
131
        parent::__construct($name, $parent);
132
 
133
        $this->lineCoverageData     = $lineCoverageData;
134
        $this->functionCoverageData = $functionCoverageData;
135
        $this->testData             = $testData;
136
        $this->linesOfCode          = $linesOfCode;
137
 
138
        $this->calculateStatistics($classes, $traits, $functions);
139
    }
140
 
141
    public function count(): int
142
    {
143
        return 1;
144
    }
145
 
146
    public function lineCoverageData(): array
147
    {
148
        return $this->lineCoverageData;
149
    }
150
 
151
    public function functionCoverageData(): array
152
    {
153
        return $this->functionCoverageData;
154
    }
155
 
156
    public function testData(): array
157
    {
158
        return $this->testData;
159
    }
160
 
161
    public function classes(): array
162
    {
163
        return $this->classes;
164
    }
165
 
166
    public function traits(): array
167
    {
168
        return $this->traits;
169
    }
170
 
171
    public function functions(): array
172
    {
173
        return $this->functions;
174
    }
175
 
176
    /**
177
     * @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int}
178
     */
179
    public function linesOfCode(): array
180
    {
181
        return $this->linesOfCode;
182
    }
183
 
184
    public function numberOfExecutableLines(): int
185
    {
186
        return $this->numExecutableLines;
187
    }
188
 
189
    public function numberOfExecutedLines(): int
190
    {
191
        return $this->numExecutedLines;
192
    }
193
 
194
    public function numberOfExecutableBranches(): int
195
    {
196
        return $this->numExecutableBranches;
197
    }
198
 
199
    public function numberOfExecutedBranches(): int
200
    {
201
        return $this->numExecutedBranches;
202
    }
203
 
204
    public function numberOfExecutablePaths(): int
205
    {
206
        return $this->numExecutablePaths;
207
    }
208
 
209
    public function numberOfExecutedPaths(): int
210
    {
211
        return $this->numExecutedPaths;
212
    }
213
 
214
    public function numberOfClasses(): int
215
    {
216
        if ($this->numClasses === null) {
217
            $this->numClasses = 0;
218
 
219
            foreach ($this->classes as $class) {
220
                foreach ($class['methods'] as $method) {
221
                    if ($method['executableLines'] > 0) {
222
                        $this->numClasses++;
223
 
224
                        continue 2;
225
                    }
226
                }
227
            }
228
        }
229
 
230
        return $this->numClasses;
231
    }
232
 
233
    public function numberOfTestedClasses(): int
234
    {
235
        return $this->numTestedClasses;
236
    }
237
 
238
    public function numberOfTraits(): int
239
    {
240
        if ($this->numTraits === null) {
241
            $this->numTraits = 0;
242
 
243
            foreach ($this->traits as $trait) {
244
                foreach ($trait['methods'] as $method) {
245
                    if ($method['executableLines'] > 0) {
246
                        $this->numTraits++;
247
 
248
                        continue 2;
249
                    }
250
                }
251
            }
252
        }
253
 
254
        return $this->numTraits;
255
    }
256
 
257
    public function numberOfTestedTraits(): int
258
    {
259
        return $this->numTestedTraits;
260
    }
261
 
262
    public function numberOfMethods(): int
263
    {
264
        if ($this->numMethods === null) {
265
            $this->numMethods = 0;
266
 
267
            foreach ($this->classes as $class) {
268
                foreach ($class['methods'] as $method) {
269
                    if ($method['executableLines'] > 0) {
270
                        $this->numMethods++;
271
                    }
272
                }
273
            }
274
 
275
            foreach ($this->traits as $trait) {
276
                foreach ($trait['methods'] as $method) {
277
                    if ($method['executableLines'] > 0) {
278
                        $this->numMethods++;
279
                    }
280
                }
281
            }
282
        }
283
 
284
        return $this->numMethods;
285
    }
286
 
287
    public function numberOfTestedMethods(): int
288
    {
289
        if ($this->numTestedMethods === null) {
290
            $this->numTestedMethods = 0;
291
 
292
            foreach ($this->classes as $class) {
293
                foreach ($class['methods'] as $method) {
294
                    if ($method['executableLines'] > 0 &&
295
                        $method['coverage'] === 100) {
296
                        $this->numTestedMethods++;
297
                    }
298
                }
299
            }
300
 
301
            foreach ($this->traits as $trait) {
302
                foreach ($trait['methods'] as $method) {
303
                    if ($method['executableLines'] > 0 &&
304
                        $method['coverage'] === 100) {
305
                        $this->numTestedMethods++;
306
                    }
307
                }
308
            }
309
        }
310
 
311
        return $this->numTestedMethods;
312
    }
313
 
314
    public function numberOfFunctions(): int
315
    {
316
        return count($this->functions);
317
    }
318
 
319
    public function numberOfTestedFunctions(): int
320
    {
321
        if ($this->numTestedFunctions === null) {
322
            $this->numTestedFunctions = 0;
323
 
324
            foreach ($this->functions as $function) {
325
                if ($function['executableLines'] > 0 &&
326
                    $function['coverage'] === 100) {
327
                    $this->numTestedFunctions++;
328
                }
329
            }
330
        }
331
 
332
        return $this->numTestedFunctions;
333
    }
334
 
335
    private function calculateStatistics(array $classes, array $traits, array $functions): void
336
    {
337
        foreach (range(1, $this->linesOfCode['linesOfCode']) as $lineNumber) {
338
            $this->codeUnitsByLine[$lineNumber] = [];
339
        }
340
 
341
        $this->processClasses($classes);
342
        $this->processTraits($traits);
343
        $this->processFunctions($functions);
344
 
345
        foreach (range(1, $this->linesOfCode['linesOfCode']) as $lineNumber) {
346
            if (isset($this->lineCoverageData[$lineNumber])) {
347
                foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
348
                    $codeUnit['executableLines']++;
349
                }
350
 
351
                unset($codeUnit);
352
 
353
                $this->numExecutableLines++;
354
 
355
                if (count($this->lineCoverageData[$lineNumber]) > 0) {
356
                    foreach ($this->codeUnitsByLine[$lineNumber] as &$codeUnit) {
357
                        $codeUnit['executedLines']++;
358
                    }
359
 
360
                    unset($codeUnit);
361
 
362
                    $this->numExecutedLines++;
363
                }
364
            }
365
        }
366
 
367
        foreach ($this->traits as &$trait) {
368
            foreach ($trait['methods'] as &$method) {
369
                $methodLineCoverage   = $method['executableLines'] ? ($method['executedLines'] / $method['executableLines']) * 100 : 100;
370
                $methodBranchCoverage = $method['executableBranches'] ? ($method['executedBranches'] / $method['executableBranches']) * 100 : 0;
371
                $methodPathCoverage   = $method['executablePaths'] ? ($method['executedPaths'] / $method['executablePaths']) * 100 : 0;
372
 
373
                $method['coverage'] = $methodBranchCoverage ?: $methodLineCoverage;
374
                $method['crap']     = (new CrapIndex($method['ccn'], $methodPathCoverage ?: $methodLineCoverage))->asString();
375
 
376
                $trait['ccn'] += $method['ccn'];
377
            }
378
 
379
            unset($method);
380
 
381
            $traitLineCoverage   = $trait['executableLines'] ? ($trait['executedLines'] / $trait['executableLines']) * 100 : 100;
382
            $traitBranchCoverage = $trait['executableBranches'] ? ($trait['executedBranches'] / $trait['executableBranches']) * 100 : 0;
383
            $traitPathCoverage   = $trait['executablePaths'] ? ($trait['executedPaths'] / $trait['executablePaths']) * 100 : 0;
384
 
385
            $trait['coverage'] = $traitBranchCoverage ?: $traitLineCoverage;
386
            $trait['crap']     = (new CrapIndex($trait['ccn'], $traitPathCoverage ?: $traitLineCoverage))->asString();
387
 
388
            if ($trait['executableLines'] > 0 && $trait['coverage'] === 100) {
389
                $this->numTestedClasses++;
390
            }
391
        }
392
 
393
        unset($trait);
394
 
395
        foreach ($this->classes as &$class) {
396
            foreach ($class['methods'] as &$method) {
397
                $methodLineCoverage   = $method['executableLines'] ? ($method['executedLines'] / $method['executableLines']) * 100 : 100;
398
                $methodBranchCoverage = $method['executableBranches'] ? ($method['executedBranches'] / $method['executableBranches']) * 100 : 0;
399
                $methodPathCoverage   = $method['executablePaths'] ? ($method['executedPaths'] / $method['executablePaths']) * 100 : 0;
400
 
401
                $method['coverage'] = $methodBranchCoverage ?: $methodLineCoverage;
402
                $method['crap']     = (new CrapIndex($method['ccn'], $methodPathCoverage ?: $methodLineCoverage))->asString();
403
 
404
                $class['ccn'] += $method['ccn'];
405
            }
406
 
407
            unset($method);
408
 
409
            $classLineCoverage   = $class['executableLines'] ? ($class['executedLines'] / $class['executableLines']) * 100 : 100;
410
            $classBranchCoverage = $class['executableBranches'] ? ($class['executedBranches'] / $class['executableBranches']) * 100 : 0;
411
            $classPathCoverage   = $class['executablePaths'] ? ($class['executedPaths'] / $class['executablePaths']) * 100 : 0;
412
 
413
            $class['coverage'] = $classBranchCoverage ?: $classLineCoverage;
414
            $class['crap']     = (new CrapIndex($class['ccn'], $classPathCoverage ?: $classLineCoverage))->asString();
415
 
416
            if ($class['executableLines'] > 0 && $class['coverage'] === 100) {
417
                $this->numTestedClasses++;
418
            }
419
        }
420
 
421
        unset($class);
422
 
423
        foreach ($this->functions as &$function) {
424
            $functionLineCoverage   = $function['executableLines'] ? ($function['executedLines'] / $function['executableLines']) * 100 : 100;
425
            $functionBranchCoverage = $function['executableBranches'] ? ($function['executedBranches'] / $function['executableBranches']) * 100 : 0;
426
            $functionPathCoverage   = $function['executablePaths'] ? ($function['executedPaths'] / $function['executablePaths']) * 100 : 0;
427
 
428
            $function['coverage'] = $functionBranchCoverage ?: $functionLineCoverage;
429
            $function['crap']     = (new CrapIndex($function['ccn'], $functionPathCoverage ?: $functionLineCoverage))->asString();
430
 
431
            if ($function['coverage'] === 100) {
432
                $this->numTestedFunctions++;
433
            }
434
        }
435
    }
436
 
437
    private function processClasses(array $classes): void
438
    {
439
        $link = $this->id() . '.html#';
440
 
441
        foreach ($classes as $className => $class) {
442
            $this->classes[$className] = [
443
                'className'          => $className,
444
                'namespace'          => $class['namespace'],
445
                'methods'            => [],
446
                'startLine'          => $class['startLine'],
447
                'executableLines'    => 0,
448
                'executedLines'      => 0,
449
                'executableBranches' => 0,
450
                'executedBranches'   => 0,
451
                'executablePaths'    => 0,
452
                'executedPaths'      => 0,
453
                'ccn'                => 0,
454
                'coverage'           => 0,
455
                'crap'               => 0,
456
                'link'               => $link . $class['startLine'],
457
            ];
458
 
459
            foreach ($class['methods'] as $methodName => $method) {
460
                $methodData                                        = $this->newMethod($className, $methodName, $method, $link);
461
                $this->classes[$className]['methods'][$methodName] = $methodData;
462
 
463
                $this->classes[$className]['executableBranches'] += $methodData['executableBranches'];
464
                $this->classes[$className]['executedBranches'] += $methodData['executedBranches'];
465
                $this->classes[$className]['executablePaths'] += $methodData['executablePaths'];
466
                $this->classes[$className]['executedPaths'] += $methodData['executedPaths'];
467
 
468
                $this->numExecutableBranches += $methodData['executableBranches'];
469
                $this->numExecutedBranches += $methodData['executedBranches'];
470
                $this->numExecutablePaths += $methodData['executablePaths'];
471
                $this->numExecutedPaths += $methodData['executedPaths'];
472
 
473
                foreach (range($method['startLine'], $method['endLine']) as $lineNumber) {
474
                    $this->codeUnitsByLine[$lineNumber] = [
475
                        &$this->classes[$className],
476
                        &$this->classes[$className]['methods'][$methodName],
477
                    ];
478
                }
479
            }
480
        }
481
    }
482
 
483
    private function processTraits(array $traits): void
484
    {
485
        $link = $this->id() . '.html#';
486
 
487
        foreach ($traits as $traitName => $trait) {
488
            $this->traits[$traitName] = [
489
                'traitName'          => $traitName,
490
                'namespace'          => $trait['namespace'],
491
                'methods'            => [],
492
                'startLine'          => $trait['startLine'],
493
                'executableLines'    => 0,
494
                'executedLines'      => 0,
495
                'executableBranches' => 0,
496
                'executedBranches'   => 0,
497
                'executablePaths'    => 0,
498
                'executedPaths'      => 0,
499
                'ccn'                => 0,
500
                'coverage'           => 0,
501
                'crap'               => 0,
502
                'link'               => $link . $trait['startLine'],
503
            ];
504
 
505
            foreach ($trait['methods'] as $methodName => $method) {
506
                $methodData                                       = $this->newMethod($traitName, $methodName, $method, $link);
507
                $this->traits[$traitName]['methods'][$methodName] = $methodData;
508
 
509
                $this->traits[$traitName]['executableBranches'] += $methodData['executableBranches'];
510
                $this->traits[$traitName]['executedBranches'] += $methodData['executedBranches'];
511
                $this->traits[$traitName]['executablePaths'] += $methodData['executablePaths'];
512
                $this->traits[$traitName]['executedPaths'] += $methodData['executedPaths'];
513
 
514
                $this->numExecutableBranches += $methodData['executableBranches'];
515
                $this->numExecutedBranches += $methodData['executedBranches'];
516
                $this->numExecutablePaths += $methodData['executablePaths'];
517
                $this->numExecutedPaths += $methodData['executedPaths'];
518
 
519
                foreach (range($method['startLine'], $method['endLine']) as $lineNumber) {
520
                    $this->codeUnitsByLine[$lineNumber] = [
521
                        &$this->traits[$traitName],
522
                        &$this->traits[$traitName]['methods'][$methodName],
523
                    ];
524
                }
525
            }
526
        }
527
    }
528
 
529
    private function processFunctions(array $functions): void
530
    {
531
        $link = $this->id() . '.html#';
532
 
533
        foreach ($functions as $functionName => $function) {
534
            $this->functions[$functionName] = [
535
                'functionName'       => $functionName,
536
                'namespace'          => $function['namespace'],
537
                'signature'          => $function['signature'],
538
                'startLine'          => $function['startLine'],
539
                'endLine'            => $function['endLine'],
540
                'executableLines'    => 0,
541
                'executedLines'      => 0,
542
                'executableBranches' => 0,
543
                'executedBranches'   => 0,
544
                'executablePaths'    => 0,
545
                'executedPaths'      => 0,
546
                'ccn'                => $function['ccn'],
547
                'coverage'           => 0,
548
                'crap'               => 0,
549
                'link'               => $link . $function['startLine'],
550
            ];
551
 
552
            foreach (range($function['startLine'], $function['endLine']) as $lineNumber) {
553
                $this->codeUnitsByLine[$lineNumber] = [&$this->functions[$functionName]];
554
            }
555
 
556
            if (isset($this->functionCoverageData[$functionName]['branches'])) {
557
                $this->functions[$functionName]['executableBranches'] = count(
558
                    $this->functionCoverageData[$functionName]['branches']
559
                );
560
 
561
                $this->functions[$functionName]['executedBranches'] = count(
562
                    array_filter(
563
                        $this->functionCoverageData[$functionName]['branches'],
564
                        static function (array $branch)
565
                        {
566
                            return (bool) $branch['hit'];
567
                        }
568
                    )
569
                );
570
            }
571
 
572
            if (isset($this->functionCoverageData[$functionName]['paths'])) {
573
                $this->functions[$functionName]['executablePaths'] = count(
574
                    $this->functionCoverageData[$functionName]['paths']
575
                );
576
 
577
                $this->functions[$functionName]['executedPaths'] = count(
578
                    array_filter(
579
                        $this->functionCoverageData[$functionName]['paths'],
580
                        static function (array $path)
581
                        {
582
                            return (bool) $path['hit'];
583
                        }
584
                    )
585
                );
586
            }
587
 
588
            $this->numExecutableBranches += $this->functions[$functionName]['executableBranches'];
589
            $this->numExecutedBranches += $this->functions[$functionName]['executedBranches'];
590
            $this->numExecutablePaths += $this->functions[$functionName]['executablePaths'];
591
            $this->numExecutedPaths += $this->functions[$functionName]['executedPaths'];
592
        }
593
    }
594
 
595
    private function newMethod(string $className, string $methodName, array $method, string $link): array
596
    {
597
        $methodData = [
598
            'methodName'         => $methodName,
599
            'visibility'         => $method['visibility'],
600
            'signature'          => $method['signature'],
601
            'startLine'          => $method['startLine'],
602
            'endLine'            => $method['endLine'],
603
            'executableLines'    => 0,
604
            'executedLines'      => 0,
605
            'executableBranches' => 0,
606
            'executedBranches'   => 0,
607
            'executablePaths'    => 0,
608
            'executedPaths'      => 0,
609
            'ccn'                => $method['ccn'],
610
            'coverage'           => 0,
611
            'crap'               => 0,
612
            'link'               => $link . $method['startLine'],
613
        ];
614
 
615
        $key = $className . '->' . $methodName;
616
 
617
        if (isset($this->functionCoverageData[$key]['branches'])) {
618
            $methodData['executableBranches'] = count(
619
                $this->functionCoverageData[$key]['branches']
620
            );
621
 
622
            $methodData['executedBranches'] = count(
623
                array_filter(
624
                    $this->functionCoverageData[$key]['branches'],
625
                    static function (array $branch)
626
                    {
627
                        return (bool) $branch['hit'];
628
                    }
629
                )
630
            );
631
        }
632
 
633
        if (isset($this->functionCoverageData[$key]['paths'])) {
634
            $methodData['executablePaths'] = count(
635
                $this->functionCoverageData[$key]['paths']
636
            );
637
 
638
            $methodData['executedPaths'] = count(
639
                array_filter(
640
                    $this->functionCoverageData[$key]['paths'],
641
                    static function (array $path)
642
                    {
643
                        return (bool) $path['hit'];
644
                    }
645
                )
646
            );
647
        }
648
 
649
        return $methodData;
650
    }
651
}