Chris@0
|
1 <?php
|
Chris@0
|
2 /*
|
Chris@0
|
3 * This file is part of the PHP_CodeCoverage package.
|
Chris@0
|
4 *
|
Chris@0
|
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
|
Chris@0
|
6 *
|
Chris@0
|
7 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
8 * file that was distributed with this source code.
|
Chris@0
|
9 */
|
Chris@0
|
10
|
Chris@0
|
11 /**
|
Chris@0
|
12 * @since Class available since Release 2.0.0
|
Chris@0
|
13 */
|
Chris@0
|
14 class PHP_CodeCoverage_Report_XML
|
Chris@0
|
15 {
|
Chris@0
|
16 /**
|
Chris@0
|
17 * @var string
|
Chris@0
|
18 */
|
Chris@0
|
19 private $target;
|
Chris@0
|
20
|
Chris@0
|
21 /**
|
Chris@0
|
22 * @var PHP_CodeCoverage_Report_XML_Project
|
Chris@0
|
23 */
|
Chris@0
|
24 private $project;
|
Chris@0
|
25
|
Chris@0
|
26 public function process(PHP_CodeCoverage $coverage, $target)
|
Chris@0
|
27 {
|
Chris@0
|
28 if (substr($target, -1, 1) != DIRECTORY_SEPARATOR) {
|
Chris@0
|
29 $target .= DIRECTORY_SEPARATOR;
|
Chris@0
|
30 }
|
Chris@0
|
31
|
Chris@0
|
32 $this->target = $target;
|
Chris@0
|
33 $this->initTargetDirectory($target);
|
Chris@0
|
34
|
Chris@0
|
35 $report = $coverage->getReport();
|
Chris@0
|
36
|
Chris@0
|
37 $this->project = new PHP_CodeCoverage_Report_XML_Project(
|
Chris@0
|
38 $coverage->getReport()->getName()
|
Chris@0
|
39 );
|
Chris@0
|
40
|
Chris@0
|
41 $this->processTests($coverage->getTests());
|
Chris@0
|
42 $this->processDirectory($report, $this->project);
|
Chris@0
|
43
|
Chris@0
|
44 $index = $this->project->asDom();
|
Chris@0
|
45 $index->formatOutput = true;
|
Chris@0
|
46 $index->preserveWhiteSpace = false;
|
Chris@0
|
47 $index->save($target . '/index.xml');
|
Chris@0
|
48 }
|
Chris@0
|
49
|
Chris@0
|
50 private function initTargetDirectory($dir)
|
Chris@0
|
51 {
|
Chris@0
|
52 if (file_exists($dir)) {
|
Chris@0
|
53 if (!is_dir($dir)) {
|
Chris@0
|
54 throw new PHP_CodeCoverage_Exception(
|
Chris@0
|
55 "'$dir' exists but is not a directory."
|
Chris@0
|
56 );
|
Chris@0
|
57 }
|
Chris@0
|
58
|
Chris@0
|
59 if (!is_writable($dir)) {
|
Chris@0
|
60 throw new PHP_CodeCoverage_Exception(
|
Chris@0
|
61 "'$dir' exists but is not writable."
|
Chris@0
|
62 );
|
Chris@0
|
63 }
|
Chris@0
|
64 } elseif (!@mkdir($dir, 0777, true)) {
|
Chris@0
|
65 throw new PHP_CodeCoverage_Exception(
|
Chris@0
|
66 "'$dir' could not be created."
|
Chris@0
|
67 );
|
Chris@0
|
68 }
|
Chris@0
|
69 }
|
Chris@0
|
70
|
Chris@0
|
71 private function processDirectory(PHP_CodeCoverage_Report_Node_Directory $directory, PHP_CodeCoverage_Report_XML_Node $context)
|
Chris@0
|
72 {
|
Chris@0
|
73 $dirObject = $context->addDirectory($directory->getName());
|
Chris@0
|
74
|
Chris@0
|
75 $this->setTotals($directory, $dirObject->getTotals());
|
Chris@0
|
76
|
Chris@0
|
77 foreach ($directory as $node) {
|
Chris@0
|
78 if ($node instanceof PHP_CodeCoverage_Report_Node_Directory) {
|
Chris@0
|
79 $this->processDirectory($node, $dirObject);
|
Chris@0
|
80 continue;
|
Chris@0
|
81 }
|
Chris@0
|
82
|
Chris@0
|
83 if ($node instanceof PHP_CodeCoverage_Report_Node_File) {
|
Chris@0
|
84 $this->processFile($node, $dirObject);
|
Chris@0
|
85 continue;
|
Chris@0
|
86 }
|
Chris@0
|
87
|
Chris@0
|
88 throw new PHP_CodeCoverage_Exception(
|
Chris@0
|
89 'Unknown node type for XML report'
|
Chris@0
|
90 );
|
Chris@0
|
91 }
|
Chris@0
|
92 }
|
Chris@0
|
93
|
Chris@0
|
94 private function processFile(PHP_CodeCoverage_Report_Node_File $file, PHP_CodeCoverage_Report_XML_Directory $context)
|
Chris@0
|
95 {
|
Chris@0
|
96 $fileObject = $context->addFile(
|
Chris@0
|
97 $file->getName(),
|
Chris@0
|
98 $file->getId() . '.xml'
|
Chris@0
|
99 );
|
Chris@0
|
100
|
Chris@0
|
101 $this->setTotals($file, $fileObject->getTotals());
|
Chris@0
|
102
|
Chris@0
|
103 $fileReport = new PHP_CodeCoverage_Report_XML_File_Report(
|
Chris@0
|
104 $file->getName()
|
Chris@0
|
105 );
|
Chris@0
|
106
|
Chris@0
|
107 $this->setTotals($file, $fileReport->getTotals());
|
Chris@0
|
108
|
Chris@0
|
109 foreach ($file->getClassesAndTraits() as $unit) {
|
Chris@0
|
110 $this->processUnit($unit, $fileReport);
|
Chris@0
|
111 }
|
Chris@0
|
112
|
Chris@0
|
113 foreach ($file->getFunctions() as $function) {
|
Chris@0
|
114 $this->processFunction($function, $fileReport);
|
Chris@0
|
115 }
|
Chris@0
|
116
|
Chris@0
|
117 foreach ($file->getCoverageData() as $line => $tests) {
|
Chris@0
|
118 if (!is_array($tests) || count($tests) == 0) {
|
Chris@0
|
119 continue;
|
Chris@0
|
120 }
|
Chris@0
|
121
|
Chris@0
|
122 $coverage = $fileReport->getLineCoverage($line);
|
Chris@0
|
123
|
Chris@0
|
124 foreach ($tests as $test) {
|
Chris@0
|
125 $coverage->addTest($test);
|
Chris@0
|
126 }
|
Chris@0
|
127
|
Chris@0
|
128 $coverage->finalize();
|
Chris@0
|
129 }
|
Chris@0
|
130
|
Chris@0
|
131 $this->initTargetDirectory(
|
Chris@0
|
132 $this->target . dirname($file->getId()) . '/'
|
Chris@0
|
133 );
|
Chris@0
|
134
|
Chris@0
|
135 $fileDom = $fileReport->asDom();
|
Chris@0
|
136 $fileDom->formatOutput = true;
|
Chris@0
|
137 $fileDom->preserveWhiteSpace = false;
|
Chris@0
|
138 $fileDom->save($this->target . $file->getId() . '.xml');
|
Chris@0
|
139 }
|
Chris@0
|
140
|
Chris@0
|
141 private function processUnit($unit, PHP_CodeCoverage_Report_XML_File_Report $report)
|
Chris@0
|
142 {
|
Chris@0
|
143 if (isset($unit['className'])) {
|
Chris@0
|
144 $unitObject = $report->getClassObject($unit['className']);
|
Chris@0
|
145 } else {
|
Chris@0
|
146 $unitObject = $report->getTraitObject($unit['traitName']);
|
Chris@0
|
147 }
|
Chris@0
|
148
|
Chris@0
|
149 $unitObject->setLines(
|
Chris@0
|
150 $unit['startLine'],
|
Chris@0
|
151 $unit['executableLines'],
|
Chris@0
|
152 $unit['executedLines']
|
Chris@0
|
153 );
|
Chris@0
|
154
|
Chris@0
|
155 $unitObject->setCrap($unit['crap']);
|
Chris@0
|
156
|
Chris@0
|
157 $unitObject->setPackage(
|
Chris@0
|
158 $unit['package']['fullPackage'],
|
Chris@0
|
159 $unit['package']['package'],
|
Chris@0
|
160 $unit['package']['subpackage'],
|
Chris@0
|
161 $unit['package']['category']
|
Chris@0
|
162 );
|
Chris@0
|
163
|
Chris@0
|
164 $unitObject->setNamespace($unit['package']['namespace']);
|
Chris@0
|
165
|
Chris@0
|
166 foreach ($unit['methods'] as $method) {
|
Chris@0
|
167 $methodObject = $unitObject->addMethod($method['methodName']);
|
Chris@0
|
168 $methodObject->setSignature($method['signature']);
|
Chris@0
|
169 $methodObject->setLines($method['startLine'], $method['endLine']);
|
Chris@0
|
170 $methodObject->setCrap($method['crap']);
|
Chris@0
|
171 $methodObject->setTotals(
|
Chris@0
|
172 $method['executableLines'],
|
Chris@0
|
173 $method['executedLines'],
|
Chris@0
|
174 $method['coverage']
|
Chris@0
|
175 );
|
Chris@0
|
176 }
|
Chris@0
|
177 }
|
Chris@0
|
178
|
Chris@0
|
179 private function processFunction($function, PHP_CodeCoverage_Report_XML_File_Report $report)
|
Chris@0
|
180 {
|
Chris@0
|
181 $functionObject = $report->getFunctionObject($function['functionName']);
|
Chris@0
|
182
|
Chris@0
|
183 $functionObject->setSignature($function['signature']);
|
Chris@0
|
184 $functionObject->setLines($function['startLine']);
|
Chris@0
|
185 $functionObject->setCrap($function['crap']);
|
Chris@0
|
186 $functionObject->setTotals($function['executableLines'], $function['executedLines'], $function['coverage']);
|
Chris@0
|
187 }
|
Chris@0
|
188
|
Chris@0
|
189 private function processTests(array $tests)
|
Chris@0
|
190 {
|
Chris@0
|
191 $testsObject = $this->project->getTests();
|
Chris@0
|
192
|
Chris@0
|
193 foreach ($tests as $test => $result) {
|
Chris@0
|
194 if ($test == 'UNCOVERED_FILES_FROM_WHITELIST') {
|
Chris@0
|
195 continue;
|
Chris@0
|
196 }
|
Chris@0
|
197
|
Chris@0
|
198 $testsObject->addTest($test, $result);
|
Chris@0
|
199 }
|
Chris@0
|
200 }
|
Chris@0
|
201
|
Chris@0
|
202 private function setTotals(PHP_CodeCoverage_Report_Node $node, PHP_CodeCoverage_Report_XML_Totals $totals)
|
Chris@0
|
203 {
|
Chris@0
|
204 $loc = $node->getLinesOfCode();
|
Chris@0
|
205
|
Chris@0
|
206 $totals->setNumLines(
|
Chris@0
|
207 $loc['loc'],
|
Chris@0
|
208 $loc['cloc'],
|
Chris@0
|
209 $loc['ncloc'],
|
Chris@0
|
210 $node->getNumExecutableLines(),
|
Chris@0
|
211 $node->getNumExecutedLines()
|
Chris@0
|
212 );
|
Chris@0
|
213
|
Chris@0
|
214 $totals->setNumClasses(
|
Chris@0
|
215 $node->getNumClasses(),
|
Chris@0
|
216 $node->getNumTestedClasses()
|
Chris@0
|
217 );
|
Chris@0
|
218
|
Chris@0
|
219 $totals->setNumTraits(
|
Chris@0
|
220 $node->getNumTraits(),
|
Chris@0
|
221 $node->getNumTestedTraits()
|
Chris@0
|
222 );
|
Chris@0
|
223
|
Chris@0
|
224 $totals->setNumMethods(
|
Chris@0
|
225 $node->getNumMethods(),
|
Chris@0
|
226 $node->getNumTestedMethods()
|
Chris@0
|
227 );
|
Chris@0
|
228
|
Chris@0
|
229 $totals->setNumFunctions(
|
Chris@0
|
230 $node->getNumFunctions(),
|
Chris@0
|
231 $node->getNumTestedFunctions()
|
Chris@0
|
232 );
|
Chris@0
|
233 }
|
Chris@0
|
234 }
|