5 * Copyright (c) 2002-2009, Sebastian Bergmann <sb@sebastian-bergmann.de>.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
20 * * Neither the name of Sebastian Bergmann nor the names of his
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
39 * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
40 * @copyright 2002-2009 Sebastian Bergmann <sb@sebastian-bergmann.de>
41 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 * @link http://www.phpunit.de/
44 * @since File available since Release 3.3.0
47 require_once 'PHPUnit/Runner/Version.php';
48 require_once 'PHPUnit/Util/Metrics/File.php';
49 require_once 'PHPUnit/Util/Class.php';
50 require_once 'PHPUnit/Util/CodeCoverage.php';
51 require_once 'PHPUnit/Util/Filter.php';
52 require_once 'PHPUnit/Util/Printer.php';
54 PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');
57 * Generates an XML logfile with code coverage information using the
58 * Clover format "documented" at
59 * http://svn.atlassian.com/svn/public/contrib/bamboo/bamboo-coverage-plugin/trunk/src/test/resources/test-clover-report.xml
63 * @author Sebastian Bergmann <sb@sebastian-bergmann.de>
64 * @copyright 2002-2009 Sebastian Bergmann <sb@sebastian-bergmann.de>
65 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
66 * @version Release: 3.3.17
67 * @link http://www.phpunit.de/
68 * @since Class available since Release 3.1.4
70 class PHPUnit_Util_Log_CodeCoverage_XML_Clover extends PHPUnit_Util_Printer
73 * @param PHPUnit_Framework_TestResult $result
74 * @todo Count conditionals.
76 public function process(PHPUnit_Framework_TestResult $result)
80 $document = new DOMDocument('1.0', 'UTF-8');
81 $document->formatOutput = TRUE;
83 $coverage = $document->createElement('coverage');
84 $coverage->setAttribute('generated', $time);
85 $coverage->setAttribute('phpunit', PHPUnit_Runner_Version::id());
86 $document->appendChild($coverage);
88 $project = $document->createElement('project');
89 $project->setAttribute('name', $result->topTestSuite()->getName());
90 $project->setAttribute('timestamp', $time);
91 $coverage->appendChild($project);
93 $codeCoverageInformation = $result->getCodeCoverageInformation();
94 $files = PHPUnit_Util_CodeCoverage::getSummary($codeCoverageInformation);
101 $projectCoveredMethods = 0;
102 $projectConditionals = 0;
103 $projectCoveredConditionals = 0;
104 $projectStatements = 0;
105 $projectCoveredStatements = 0;
107 foreach ($files as $filename => $data) {
111 $fileConditionals = 0;
112 $fileCoveredConditionals = 0;
114 $fileCoveredStatements = 0;
116 $fileCoveredMethods = 0;
118 $file = $document->createElement('file');
119 $file->setAttribute('name', $filename);
121 $namespace = 'global';
122 $classes = PHPUnit_Util_Class::getClassesInFile($filename);
125 foreach ($classes as $class) {
126 if ($class->isInterface()) {
130 $className = $class->getName();
131 $methods = $class->getMethods();
132 $packageInformation = PHPUnit_Util_Class::getPackageInformation($className);
137 if (!empty($packageInformation['namespace'])) {
138 $namespace = $packageInformation['namespace'];
141 $classConditionals = 0;
142 $classCoveredConditionals = 0;
143 $classStatements = 0;
144 $classCoveredStatements = 0;
145 $classCoveredMethods = 0;
147 foreach ($methods as $method) {
148 if ($method->getDeclaringClass()->getName() == $class->getName()) {
149 $startLine = $method->getStartLine();
150 $endLine = $method->getEndLine();
153 for ($i = $startLine; $i <= $endLine; $i++) {
154 if (isset($files[$filename][$i])) {
155 if (is_array($files[$filename][$i])) {
156 foreach ($files[$filename][$i] as $_test) {
159 foreach ($tests as $test) {
160 if ($test === $_test) {
171 $classCoveredStatements++;
178 $count = count($tests);
180 $lines[$startLine] = array(
186 $classCoveredMethods++;
187 $fileCoveredMethods++;
188 $projectCoveredMethods++;
198 $classXML = $document->createElement('class');
199 $classXML->setAttribute('name', $className);
200 $classXML->setAttribute('namespace', $namespace);
202 if (!empty($packageInformation['fullPackage'])) {
203 $classXML->setAttribute('fullPackage', $packageInformation['fullPackage']);
206 if (!empty($packageInformation['category'])) {
207 $classXML->setAttribute('category', $packageInformation['category']);
210 if (!empty($packageInformation['package'])) {
211 $classXML->setAttribute('package', $packageInformation['package']);
214 if (!empty($packageInformation['subpackage'])) {
215 $classXML->setAttribute('subpackage', $packageInformation['subpackage']);
218 $file->appendChild($classXML);
220 $classMetricsXML = $document->createElement('metrics');
221 $classMetricsXML->setAttribute('methods', $numMethods);
222 $classMetricsXML->setAttribute('coveredmethods', $classCoveredMethods);
223 //$classMetricsXML->setAttribute('conditionals', $classConditionals);
224 //$classMetricsXML->setAttribute('coveredconditionals', $classCoveredConditionals);
225 $classMetricsXML->setAttribute('statements', $classStatements);
226 $classMetricsXML->setAttribute('coveredstatements', $classCoveredStatements);
227 $classMetricsXML->setAttribute('elements', $classConditionals + $classStatements + $numMethods);
228 $classMetricsXML->setAttribute('coveredelements', $classCoveredConditionals + $classCoveredStatements + $classCoveredMethods);
229 $classXML->appendChild($classMetricsXML);
232 foreach ($data as $_line => $_data) {
233 if (is_array($_data)) {
234 $count = count($_data);
237 else if ($_data == -1) {
241 else if ($_data == -2) {
245 $lines[$_line] = array(
253 foreach ($lines as $_line => $_data) {
254 $line = $document->createElement('line');
255 $line->setAttribute('num', $_line);
256 $line->setAttribute('type', $_data['type']);
257 $line->setAttribute('count', $_data['count']);
259 if ($_data['type'] == 'stmt') {
260 if ($_data['count'] != 0) {
261 $fileCoveredStatements++;
267 $file->appendChild($line);
270 if (file_exists($filename)) {
271 $fileMetrics = PHPUnit_Util_Metrics_File::factory($filename, $files);
272 $fileLoc = $fileMetrics->getLoc();
273 $fileNcloc = $fileMetrics->getNcloc();
275 $fileMetricsXML = $document->createElement('metrics');
276 $fileMetricsXML->setAttribute('loc', $fileLoc);
277 $fileMetricsXML->setAttribute('ncloc', $fileNcloc);
278 $fileMetricsXML->setAttribute('classes', $fileClasses);
279 $fileMetricsXML->setAttribute('methods', $fileMethods);
280 $fileMetricsXML->setAttribute('coveredmethods', $fileCoveredMethods);
281 //$fileMetricsXML->setAttribute('conditionals', $fileConditionals);
282 //$fileMetricsXML->setAttribute('coveredconditionals', $fileCoveredConditionals);
283 $fileMetricsXML->setAttribute('statements', $fileStatements);
284 $fileMetricsXML->setAttribute('coveredstatements', $fileCoveredStatements);
285 $fileMetricsXML->setAttribute('elements', $fileConditionals + $fileStatements + $fileMethods);
286 $fileMetricsXML->setAttribute('coveredelements', $fileCoveredConditionals + $fileCoveredStatements + $fileCoveredMethods);
288 $file->appendChild($fileMetricsXML);
290 if ($namespace == 'global') {
291 $project->appendChild($file);
293 if (!isset($packages[$namespace])) {
294 $packages[$namespace] = $document->createElement('package');
295 $packages[$namespace]->setAttribute('name', $namespace);
296 $project->appendChild($packages[$namespace]);
299 $packages[$namespace]->appendChild($file);
302 $projectLoc += $fileLoc;
303 $projectNcloc += $fileNcloc;
304 $projectStatements += $fileStatements;
305 $projectCoveredStatements += $fileCoveredStatements;
309 $projectMetricsXML = $document->createElement('metrics');
310 $projectMetricsXML->setAttribute('files', $projectFiles);
311 $projectMetricsXML->setAttribute('loc', $projectLoc);
312 $projectMetricsXML->setAttribute('ncloc', $projectNcloc);
313 $projectMetricsXML->setAttribute('classes', $projectClasses);
314 $projectMetricsXML->setAttribute('methods', $projectMethods);
315 $projectMetricsXML->setAttribute('coveredmethods', $projectCoveredMethods);
316 //$projectMetricsXML->setAttribute('conditionals', $projectConditionals);
317 //$projectMetricsXML->setAttribute('coveredconditionals', $projectCoveredConditionals);
318 $projectMetricsXML->setAttribute('statements', $projectStatements);
319 $projectMetricsXML->setAttribute('coveredstatements', $projectCoveredStatements);
320 $projectMetricsXML->setAttribute('elements', $projectConditionals + $projectStatements + $projectMethods);
321 $projectMetricsXML->setAttribute('coveredelements', $projectCoveredConditionals + $projectCoveredStatements + $projectCoveredMethods);
322 $project->appendChild($projectMetricsXML);
324 $this->write($document->saveXML());