CloverFile::fromFile()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 13
nc 3
nop 2
1
<?php
2
declare(strict_types=1);
3
4
namespace TheCodingMachine\WashingMachine\Clover;
5
6
use TheCodingMachine\WashingMachine\Clover\Analysis\Method;
7
8
final class CloverFile implements CrapMethodFetcherInterface, CoverageDetectorInterface
9
{
10
11
    /**
12
     * @var string
13
     */
14
    private $fileName;
15
16
    /**
17
     * @var \SimpleXMLElement
18
     */
19
    private $root;
20
21
    /**
22
     * @var string
23
     */
24
    private $rootDirectory;
25
26
    private function __construct()
27
    {
28
    }
29
30
    public static function fromFile(string $fileName, string $rootDirectory) : CloverFile
31
    {
32
        if (!file_exists($fileName)) {
33
            throw new \RuntimeException('Could not find file "'.$fileName.'". The unit tests did not run or broke before the end, or the file path is incorrect.');
34
        }
35
36
        $cloverFile = new self();
37
        $cloverFile->fileName = $fileName;
38
        $errorReporting = error_reporting();
39
        $oldErrorReporting = error_reporting($errorReporting & ~E_WARNING);
40
        $cloverFile->root = simplexml_load_file($fileName);
41
        error_reporting($oldErrorReporting);
42
        if ($cloverFile->root === false) {
43
            throw new \RuntimeException('Invalid XML file passed or unable to load file: "'.$fileName.'": '.error_get_last()['message']);
44
        }
45
        $cloverFile->rootDirectory = rtrim($rootDirectory, '/').'/';
46
        return $cloverFile;
47
    }
48
49
    public static function fromString(string $string, string $rootDirectory) : CloverFile
50
    {
51
        $cloverFile = new self();
52
        $errorReporting = error_reporting();
53
        $oldErrorReporting = error_reporting($errorReporting & ~E_WARNING);
54
        $cloverFile->root = simplexml_load_string($string);
55
        error_reporting($oldErrorReporting);
56
        if ($cloverFile->root === false) {
57
            throw new \RuntimeException('Invalid XML file passed or unable to load string: '.error_get_last()['message']);
58
        }
59
        $cloverFile->rootDirectory = rtrim($rootDirectory, '/').'/';
60
        return $cloverFile;
61
    }
62
63
    /**
64
     * @return float
65
     */
66
    public function getCoveragePercentage() : float
67
    {
68
        $metrics = $this->root->xpath("/coverage/project/metrics");
69
70
        if (count($metrics) !== 1) {
71
            throw new \RuntimeException('Unexpected number of metrics element in XML file. Found '.count($metrics).' elements."');
72
        }
73
74
        $statements = (float) $metrics[0]['statements'];
75
        $coveredStatements = (float) $metrics[0]['coveredstatements'];
76
77
        if ($statements === 0.0) {
78
            return 0.0;
79
        }
80
81
        return $coveredStatements/$statements;
82
    }
83
84
    /**
85
     * Returns an array of method objects, indexed by method full name.
86
     *
87
     * @return Method[]
88
     */
89
    public function getMethods() : array
90
    {
91
        $methods = [];
92
        $files = $this->root->xpath('//file');
93
94
        $currentClass = null;
95
        $currentNamespace = null;
96
97
        foreach ($files as $file) {
98
            foreach ($file as $item) {
99
                if ($item->getName() === 'class') {
100
                    $currentClass = (string) $item['name'];
101
                    $currentNamespace = (string) $item['namespace'];
102
                } elseif ($item->getName() === 'line') {
103
                    // <line num="19" type="method" name="__construct" visibility="public" complexity="2" crap="2.03" count="1"/>
104
                    $type = (string) $item['type'];
105
                    if ($type === 'method' && $currentClass !== null) {
106
                        $methodName = (string) $item['name'];
107
                        $visibility = (string) $item['visibility'];
108
                        $complexity = (float) $item['complexity'];
109
                        $crap = (float) $item['crap'];
110
                        $count = (int) $item['count'];
111
                        $line = (int) $item['num'];
112
                        $fileName = (string) $file['name'];
113
114
                        if (strpos($fileName, $this->rootDirectory) === 0) {
115
                            $fileName = substr($fileName, strlen($this->rootDirectory));
116
                        }
117
118
                        $method = new Method($methodName, $currentClass, $currentNamespace, $complexity, $crap, $visibility, $count, $fileName, $line);
119
                        $methods[$method->getFullName()] = $method;
120
121
                    }
122
                }
123
            }
124
        }
125
126
        return $methods;
127
    }
128
}
129