Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: /** Chris@0: * @since Class available since Release 2.0.0 Chris@0: */ Chris@0: class PHP_CodeCoverage_Report_XML Chris@0: { Chris@0: /** Chris@0: * @var string Chris@0: */ Chris@0: private $target; Chris@0: Chris@0: /** Chris@0: * @var PHP_CodeCoverage_Report_XML_Project Chris@0: */ Chris@0: private $project; Chris@0: Chris@0: public function process(PHP_CodeCoverage $coverage, $target) Chris@0: { Chris@0: if (substr($target, -1, 1) != DIRECTORY_SEPARATOR) { Chris@0: $target .= DIRECTORY_SEPARATOR; Chris@0: } Chris@0: Chris@0: $this->target = $target; Chris@0: $this->initTargetDirectory($target); Chris@0: Chris@0: $report = $coverage->getReport(); Chris@0: Chris@0: $this->project = new PHP_CodeCoverage_Report_XML_Project( Chris@0: $coverage->getReport()->getName() Chris@0: ); Chris@0: Chris@0: $this->processTests($coverage->getTests()); Chris@0: $this->processDirectory($report, $this->project); Chris@0: Chris@0: $index = $this->project->asDom(); Chris@0: $index->formatOutput = true; Chris@0: $index->preserveWhiteSpace = false; Chris@0: $index->save($target . '/index.xml'); Chris@0: } Chris@0: Chris@0: private function initTargetDirectory($dir) Chris@0: { Chris@0: if (file_exists($dir)) { Chris@0: if (!is_dir($dir)) { Chris@0: throw new PHP_CodeCoverage_Exception( Chris@0: "'$dir' exists but is not a directory." Chris@0: ); Chris@0: } Chris@0: Chris@0: if (!is_writable($dir)) { Chris@0: throw new PHP_CodeCoverage_Exception( Chris@0: "'$dir' exists but is not writable." Chris@0: ); Chris@0: } Chris@0: } elseif (!@mkdir($dir, 0777, true)) { Chris@0: throw new PHP_CodeCoverage_Exception( Chris@0: "'$dir' could not be created." Chris@0: ); Chris@0: } Chris@0: } Chris@0: Chris@0: private function processDirectory(PHP_CodeCoverage_Report_Node_Directory $directory, PHP_CodeCoverage_Report_XML_Node $context) Chris@0: { Chris@0: $dirObject = $context->addDirectory($directory->getName()); Chris@0: Chris@0: $this->setTotals($directory, $dirObject->getTotals()); Chris@0: Chris@0: foreach ($directory as $node) { Chris@0: if ($node instanceof PHP_CodeCoverage_Report_Node_Directory) { Chris@0: $this->processDirectory($node, $dirObject); Chris@0: continue; Chris@0: } Chris@0: Chris@0: if ($node instanceof PHP_CodeCoverage_Report_Node_File) { Chris@0: $this->processFile($node, $dirObject); Chris@0: continue; Chris@0: } Chris@0: Chris@0: throw new PHP_CodeCoverage_Exception( Chris@0: 'Unknown node type for XML report' Chris@0: ); Chris@0: } Chris@0: } Chris@0: Chris@0: private function processFile(PHP_CodeCoverage_Report_Node_File $file, PHP_CodeCoverage_Report_XML_Directory $context) Chris@0: { Chris@0: $fileObject = $context->addFile( Chris@0: $file->getName(), Chris@0: $file->getId() . '.xml' Chris@0: ); Chris@0: Chris@0: $this->setTotals($file, $fileObject->getTotals()); Chris@0: Chris@0: $fileReport = new PHP_CodeCoverage_Report_XML_File_Report( Chris@0: $file->getName() Chris@0: ); Chris@0: Chris@0: $this->setTotals($file, $fileReport->getTotals()); Chris@0: Chris@0: foreach ($file->getClassesAndTraits() as $unit) { Chris@0: $this->processUnit($unit, $fileReport); Chris@0: } Chris@0: Chris@0: foreach ($file->getFunctions() as $function) { Chris@0: $this->processFunction($function, $fileReport); Chris@0: } Chris@0: Chris@0: foreach ($file->getCoverageData() as $line => $tests) { Chris@0: if (!is_array($tests) || count($tests) == 0) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $coverage = $fileReport->getLineCoverage($line); Chris@0: Chris@0: foreach ($tests as $test) { Chris@0: $coverage->addTest($test); Chris@0: } Chris@0: Chris@0: $coverage->finalize(); Chris@0: } Chris@0: Chris@0: $this->initTargetDirectory( Chris@0: $this->target . dirname($file->getId()) . '/' Chris@0: ); Chris@0: Chris@0: $fileDom = $fileReport->asDom(); Chris@0: $fileDom->formatOutput = true; Chris@0: $fileDom->preserveWhiteSpace = false; Chris@0: $fileDom->save($this->target . $file->getId() . '.xml'); Chris@0: } Chris@0: Chris@0: private function processUnit($unit, PHP_CodeCoverage_Report_XML_File_Report $report) Chris@0: { Chris@0: if (isset($unit['className'])) { Chris@0: $unitObject = $report->getClassObject($unit['className']); Chris@0: } else { Chris@0: $unitObject = $report->getTraitObject($unit['traitName']); Chris@0: } Chris@0: Chris@0: $unitObject->setLines( Chris@0: $unit['startLine'], Chris@0: $unit['executableLines'], Chris@0: $unit['executedLines'] Chris@0: ); Chris@0: Chris@0: $unitObject->setCrap($unit['crap']); Chris@0: Chris@0: $unitObject->setPackage( Chris@0: $unit['package']['fullPackage'], Chris@0: $unit['package']['package'], Chris@0: $unit['package']['subpackage'], Chris@0: $unit['package']['category'] Chris@0: ); Chris@0: Chris@0: $unitObject->setNamespace($unit['package']['namespace']); Chris@0: Chris@0: foreach ($unit['methods'] as $method) { Chris@0: $methodObject = $unitObject->addMethod($method['methodName']); Chris@0: $methodObject->setSignature($method['signature']); Chris@0: $methodObject->setLines($method['startLine'], $method['endLine']); Chris@0: $methodObject->setCrap($method['crap']); Chris@0: $methodObject->setTotals( Chris@0: $method['executableLines'], Chris@0: $method['executedLines'], Chris@0: $method['coverage'] Chris@0: ); Chris@0: } Chris@0: } Chris@0: Chris@0: private function processFunction($function, PHP_CodeCoverage_Report_XML_File_Report $report) Chris@0: { Chris@0: $functionObject = $report->getFunctionObject($function['functionName']); Chris@0: Chris@0: $functionObject->setSignature($function['signature']); Chris@0: $functionObject->setLines($function['startLine']); Chris@0: $functionObject->setCrap($function['crap']); Chris@0: $functionObject->setTotals($function['executableLines'], $function['executedLines'], $function['coverage']); Chris@0: } Chris@0: Chris@0: private function processTests(array $tests) Chris@0: { Chris@0: $testsObject = $this->project->getTests(); Chris@0: Chris@0: foreach ($tests as $test => $result) { Chris@0: if ($test == 'UNCOVERED_FILES_FROM_WHITELIST') { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $testsObject->addTest($test, $result); Chris@0: } Chris@0: } Chris@0: Chris@0: private function setTotals(PHP_CodeCoverage_Report_Node $node, PHP_CodeCoverage_Report_XML_Totals $totals) Chris@0: { Chris@0: $loc = $node->getLinesOfCode(); Chris@0: Chris@0: $totals->setNumLines( Chris@0: $loc['loc'], Chris@0: $loc['cloc'], Chris@0: $loc['ncloc'], Chris@0: $node->getNumExecutableLines(), Chris@0: $node->getNumExecutedLines() Chris@0: ); Chris@0: Chris@0: $totals->setNumClasses( Chris@0: $node->getNumClasses(), Chris@0: $node->getNumTestedClasses() Chris@0: ); Chris@0: Chris@0: $totals->setNumTraits( Chris@0: $node->getNumTraits(), Chris@0: $node->getNumTestedTraits() Chris@0: ); Chris@0: Chris@0: $totals->setNumMethods( Chris@0: $node->getNumMethods(), Chris@0: $node->getNumTestedMethods() Chris@0: ); Chris@0: Chris@0: $totals->setNumFunctions( Chris@0: $node->getNumFunctions(), Chris@0: $node->getNumTestedFunctions() Chris@0: ); Chris@0: } Chris@0: }