Chris@14
|
1 <?php
|
Chris@14
|
2 /*
|
Chris@14
|
3 * This file is part of the php-code-coverage package.
|
Chris@14
|
4 *
|
Chris@14
|
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
|
Chris@14
|
6 *
|
Chris@14
|
7 * For the full copyright and license information, please view the LICENSE
|
Chris@14
|
8 * file that was distributed with this source code.
|
Chris@14
|
9 */
|
Chris@14
|
10
|
Chris@14
|
11 namespace SebastianBergmann\CodeCoverage\Report\Xml;
|
Chris@14
|
12
|
Chris@14
|
13 use SebastianBergmann\CodeCoverage\CodeCoverage;
|
Chris@14
|
14 use SebastianBergmann\CodeCoverage\Node\AbstractNode;
|
Chris@14
|
15 use SebastianBergmann\CodeCoverage\Node\Directory as DirectoryNode;
|
Chris@14
|
16 use SebastianBergmann\CodeCoverage\Node\File as FileNode;
|
Chris@14
|
17 use SebastianBergmann\CodeCoverage\RuntimeException;
|
Chris@14
|
18 use SebastianBergmann\CodeCoverage\Version;
|
Chris@14
|
19 use SebastianBergmann\Environment\Runtime;
|
Chris@14
|
20
|
Chris@14
|
21 class Facade
|
Chris@14
|
22 {
|
Chris@14
|
23 /**
|
Chris@14
|
24 * @var string
|
Chris@14
|
25 */
|
Chris@14
|
26 private $target;
|
Chris@14
|
27
|
Chris@14
|
28 /**
|
Chris@14
|
29 * @var Project
|
Chris@14
|
30 */
|
Chris@14
|
31 private $project;
|
Chris@14
|
32
|
Chris@14
|
33 /**
|
Chris@14
|
34 * @var string
|
Chris@14
|
35 */
|
Chris@14
|
36 private $phpUnitVersion;
|
Chris@14
|
37
|
Chris@14
|
38 /**
|
Chris@14
|
39 * @param string $version
|
Chris@14
|
40 */
|
Chris@14
|
41 public function __construct($version)
|
Chris@14
|
42 {
|
Chris@14
|
43 $this->phpUnitVersion = $version;
|
Chris@14
|
44 }
|
Chris@14
|
45
|
Chris@14
|
46 /**
|
Chris@14
|
47 * @param CodeCoverage $coverage
|
Chris@14
|
48 * @param string $target
|
Chris@14
|
49 *
|
Chris@14
|
50 * @throws RuntimeException
|
Chris@14
|
51 */
|
Chris@14
|
52 public function process(CodeCoverage $coverage, $target)
|
Chris@14
|
53 {
|
Chris@14
|
54 if (\substr($target, -1, 1) != DIRECTORY_SEPARATOR) {
|
Chris@14
|
55 $target .= DIRECTORY_SEPARATOR;
|
Chris@14
|
56 }
|
Chris@14
|
57
|
Chris@14
|
58 $this->target = $target;
|
Chris@14
|
59 $this->initTargetDirectory($target);
|
Chris@14
|
60
|
Chris@14
|
61 $report = $coverage->getReport();
|
Chris@14
|
62
|
Chris@14
|
63 $this->project = new Project(
|
Chris@14
|
64 $coverage->getReport()->getName()
|
Chris@14
|
65 );
|
Chris@14
|
66
|
Chris@14
|
67 $this->setBuildInformation();
|
Chris@14
|
68 $this->processTests($coverage->getTests());
|
Chris@14
|
69 $this->processDirectory($report, $this->project);
|
Chris@14
|
70
|
Chris@14
|
71 $this->saveDocument($this->project->asDom(), 'index');
|
Chris@14
|
72 }
|
Chris@14
|
73
|
Chris@14
|
74 private function setBuildInformation()
|
Chris@14
|
75 {
|
Chris@14
|
76 $buildNode = $this->project->getBuildInformation();
|
Chris@14
|
77 $buildNode->setRuntimeInformation(new Runtime());
|
Chris@14
|
78 $buildNode->setBuildTime(\DateTime::createFromFormat('U', $_SERVER['REQUEST_TIME']));
|
Chris@14
|
79 $buildNode->setGeneratorVersions($this->phpUnitVersion, Version::id());
|
Chris@14
|
80 }
|
Chris@14
|
81
|
Chris@14
|
82 /**
|
Chris@14
|
83 * @param string $directory
|
Chris@14
|
84 */
|
Chris@14
|
85 protected function initTargetDirectory($directory)
|
Chris@14
|
86 {
|
Chris@14
|
87 if (\file_exists($directory)) {
|
Chris@14
|
88 if (!\is_dir($directory)) {
|
Chris@14
|
89 throw new RuntimeException(
|
Chris@14
|
90 "'$directory' exists but is not a directory."
|
Chris@14
|
91 );
|
Chris@14
|
92 }
|
Chris@14
|
93
|
Chris@14
|
94 if (!\is_writable($directory)) {
|
Chris@14
|
95 throw new RuntimeException(
|
Chris@14
|
96 "'$directory' exists but is not writable."
|
Chris@14
|
97 );
|
Chris@14
|
98 }
|
Chris@14
|
99 } elseif (!@\mkdir($directory, 0777, true)) {
|
Chris@14
|
100 throw new RuntimeException(
|
Chris@14
|
101 "'$directory' could not be created."
|
Chris@14
|
102 );
|
Chris@14
|
103 }
|
Chris@14
|
104 }
|
Chris@14
|
105
|
Chris@14
|
106 private function processDirectory(DirectoryNode $directory, Node $context)
|
Chris@14
|
107 {
|
Chris@14
|
108 $dirname = $directory->getName();
|
Chris@14
|
109 if ($this->project->getProjectSourceDirectory() === $dirname) {
|
Chris@14
|
110 $dirname = '/';
|
Chris@14
|
111 }
|
Chris@14
|
112 $dirObject = $context->addDirectory($dirname);
|
Chris@14
|
113
|
Chris@14
|
114 $this->setTotals($directory, $dirObject->getTotals());
|
Chris@14
|
115
|
Chris@14
|
116 foreach ($directory->getDirectories() as $node) {
|
Chris@14
|
117 $this->processDirectory($node, $dirObject);
|
Chris@14
|
118 }
|
Chris@14
|
119
|
Chris@14
|
120 foreach ($directory->getFiles() as $node) {
|
Chris@14
|
121 $this->processFile($node, $dirObject);
|
Chris@14
|
122 }
|
Chris@14
|
123 }
|
Chris@14
|
124
|
Chris@14
|
125 private function processFile(FileNode $file, Directory $context)
|
Chris@14
|
126 {
|
Chris@14
|
127 $fileObject = $context->addFile(
|
Chris@14
|
128 $file->getName(),
|
Chris@14
|
129 $file->getId() . '.xml'
|
Chris@14
|
130 );
|
Chris@14
|
131
|
Chris@14
|
132 $this->setTotals($file, $fileObject->getTotals());
|
Chris@14
|
133
|
Chris@14
|
134 $path = \substr(
|
Chris@14
|
135 $file->getPath(),
|
Chris@14
|
136 \strlen($this->project->getProjectSourceDirectory())
|
Chris@14
|
137 );
|
Chris@14
|
138 $fileReport = new Report($path);
|
Chris@14
|
139
|
Chris@14
|
140 $this->setTotals($file, $fileReport->getTotals());
|
Chris@14
|
141
|
Chris@14
|
142 foreach ($file->getClassesAndTraits() as $unit) {
|
Chris@14
|
143 $this->processUnit($unit, $fileReport);
|
Chris@14
|
144 }
|
Chris@14
|
145
|
Chris@14
|
146 foreach ($file->getFunctions() as $function) {
|
Chris@14
|
147 $this->processFunction($function, $fileReport);
|
Chris@14
|
148 }
|
Chris@14
|
149
|
Chris@14
|
150 foreach ($file->getCoverageData() as $line => $tests) {
|
Chris@14
|
151 if (!\is_array($tests) || \count($tests) === 0) {
|
Chris@14
|
152 continue;
|
Chris@14
|
153 }
|
Chris@14
|
154
|
Chris@14
|
155 $coverage = $fileReport->getLineCoverage($line);
|
Chris@14
|
156
|
Chris@14
|
157 foreach ($tests as $test) {
|
Chris@14
|
158 $coverage->addTest($test);
|
Chris@14
|
159 }
|
Chris@14
|
160
|
Chris@14
|
161 $coverage->finalize();
|
Chris@14
|
162 }
|
Chris@14
|
163
|
Chris@14
|
164 $fileReport->getSource()->setSourceCode(
|
Chris@14
|
165 \file_get_contents($file->getPath())
|
Chris@14
|
166 );
|
Chris@14
|
167
|
Chris@14
|
168 $this->saveDocument($fileReport->asDom(), $file->getId());
|
Chris@14
|
169 }
|
Chris@14
|
170
|
Chris@14
|
171 private function processUnit($unit, Report $report)
|
Chris@14
|
172 {
|
Chris@14
|
173 if (isset($unit['className'])) {
|
Chris@14
|
174 $unitObject = $report->getClassObject($unit['className']);
|
Chris@14
|
175 } else {
|
Chris@14
|
176 $unitObject = $report->getTraitObject($unit['traitName']);
|
Chris@14
|
177 }
|
Chris@14
|
178
|
Chris@14
|
179 $unitObject->setLines(
|
Chris@14
|
180 $unit['startLine'],
|
Chris@14
|
181 $unit['executableLines'],
|
Chris@14
|
182 $unit['executedLines']
|
Chris@14
|
183 );
|
Chris@14
|
184
|
Chris@14
|
185 $unitObject->setCrap($unit['crap']);
|
Chris@14
|
186
|
Chris@14
|
187 $unitObject->setPackage(
|
Chris@14
|
188 $unit['package']['fullPackage'],
|
Chris@14
|
189 $unit['package']['package'],
|
Chris@14
|
190 $unit['package']['subpackage'],
|
Chris@14
|
191 $unit['package']['category']
|
Chris@14
|
192 );
|
Chris@14
|
193
|
Chris@14
|
194 $unitObject->setNamespace($unit['package']['namespace']);
|
Chris@14
|
195
|
Chris@14
|
196 foreach ($unit['methods'] as $method) {
|
Chris@14
|
197 $methodObject = $unitObject->addMethod($method['methodName']);
|
Chris@14
|
198 $methodObject->setSignature($method['signature']);
|
Chris@14
|
199 $methodObject->setLines($method['startLine'], $method['endLine']);
|
Chris@14
|
200 $methodObject->setCrap($method['crap']);
|
Chris@14
|
201 $methodObject->setTotals(
|
Chris@14
|
202 $method['executableLines'],
|
Chris@14
|
203 $method['executedLines'],
|
Chris@14
|
204 $method['coverage']
|
Chris@14
|
205 );
|
Chris@14
|
206 }
|
Chris@14
|
207 }
|
Chris@14
|
208
|
Chris@14
|
209 private function processFunction($function, Report $report)
|
Chris@14
|
210 {
|
Chris@14
|
211 $functionObject = $report->getFunctionObject($function['functionName']);
|
Chris@14
|
212
|
Chris@14
|
213 $functionObject->setSignature($function['signature']);
|
Chris@14
|
214 $functionObject->setLines($function['startLine']);
|
Chris@14
|
215 $functionObject->setCrap($function['crap']);
|
Chris@14
|
216 $functionObject->setTotals($function['executableLines'], $function['executedLines'], $function['coverage']);
|
Chris@14
|
217 }
|
Chris@14
|
218
|
Chris@14
|
219 private function processTests(array $tests)
|
Chris@14
|
220 {
|
Chris@14
|
221 $testsObject = $this->project->getTests();
|
Chris@14
|
222
|
Chris@14
|
223 foreach ($tests as $test => $result) {
|
Chris@14
|
224 if ($test == 'UNCOVERED_FILES_FROM_WHITELIST') {
|
Chris@14
|
225 continue;
|
Chris@14
|
226 }
|
Chris@14
|
227
|
Chris@14
|
228 $testsObject->addTest($test, $result);
|
Chris@14
|
229 }
|
Chris@14
|
230 }
|
Chris@14
|
231
|
Chris@14
|
232 private function setTotals(AbstractNode $node, Totals $totals)
|
Chris@14
|
233 {
|
Chris@14
|
234 $loc = $node->getLinesOfCode();
|
Chris@14
|
235
|
Chris@14
|
236 $totals->setNumLines(
|
Chris@14
|
237 $loc['loc'],
|
Chris@14
|
238 $loc['cloc'],
|
Chris@14
|
239 $loc['ncloc'],
|
Chris@14
|
240 $node->getNumExecutableLines(),
|
Chris@14
|
241 $node->getNumExecutedLines()
|
Chris@14
|
242 );
|
Chris@14
|
243
|
Chris@14
|
244 $totals->setNumClasses(
|
Chris@14
|
245 $node->getNumClasses(),
|
Chris@14
|
246 $node->getNumTestedClasses()
|
Chris@14
|
247 );
|
Chris@14
|
248
|
Chris@14
|
249 $totals->setNumTraits(
|
Chris@14
|
250 $node->getNumTraits(),
|
Chris@14
|
251 $node->getNumTestedTraits()
|
Chris@14
|
252 );
|
Chris@14
|
253
|
Chris@14
|
254 $totals->setNumMethods(
|
Chris@14
|
255 $node->getNumMethods(),
|
Chris@14
|
256 $node->getNumTestedMethods()
|
Chris@14
|
257 );
|
Chris@14
|
258
|
Chris@14
|
259 $totals->setNumFunctions(
|
Chris@14
|
260 $node->getNumFunctions(),
|
Chris@14
|
261 $node->getNumTestedFunctions()
|
Chris@14
|
262 );
|
Chris@14
|
263 }
|
Chris@14
|
264
|
Chris@14
|
265 /**
|
Chris@14
|
266 * @return string
|
Chris@14
|
267 */
|
Chris@14
|
268 protected function getTargetDirectory()
|
Chris@14
|
269 {
|
Chris@14
|
270 return $this->target;
|
Chris@14
|
271 }
|
Chris@14
|
272
|
Chris@14
|
273 protected function saveDocument(\DOMDocument $document, $name)
|
Chris@14
|
274 {
|
Chris@14
|
275 $filename = \sprintf('%s/%s.xml', $this->getTargetDirectory(), $name);
|
Chris@14
|
276
|
Chris@14
|
277 $document->formatOutput = true;
|
Chris@14
|
278 $document->preserveWhiteSpace = false;
|
Chris@14
|
279 $this->initTargetDirectory(\dirname($filename));
|
Chris@14
|
280
|
Chris@14
|
281 $document->save($filename);
|
Chris@14
|
282 }
|
Chris@14
|
283 }
|