/vendor/phpunit/php-code-coverage/src/Report/Clover.php

https://gitlab.com/jjpa2018/dashboard · PHP · 255 lines · 196 code · 47 blank · 12 comment · 24 complexity · 467e6d6bd8576fe8dd7ac91fa2d9730c MD5 · raw file

  1. <?php declare(strict_types=1);
  2. /*
  3. * This file is part of phpunit/php-code-coverage.
  4. *
  5. * (c) Sebastian Bergmann <sebastian@phpunit.de>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace SebastianBergmann\CodeCoverage\Report;
  11. use function count;
  12. use function dirname;
  13. use function file_put_contents;
  14. use function is_string;
  15. use function ksort;
  16. use function max;
  17. use function range;
  18. use function time;
  19. use DOMDocument;
  20. use SebastianBergmann\CodeCoverage\CodeCoverage;
  21. use SebastianBergmann\CodeCoverage\Directory;
  22. use SebastianBergmann\CodeCoverage\Driver\WriteOperationFailedException;
  23. use SebastianBergmann\CodeCoverage\Node\File;
  24. final class Clover
  25. {
  26. /**
  27. * @throws WriteOperationFailedException
  28. */
  29. public function process(CodeCoverage $coverage, ?string $target = null, ?string $name = null): string
  30. {
  31. $time = (string) time();
  32. $xmlDocument = new DOMDocument('1.0', 'UTF-8');
  33. $xmlDocument->formatOutput = true;
  34. $xmlCoverage = $xmlDocument->createElement('coverage');
  35. $xmlCoverage->setAttribute('generated', $time);
  36. $xmlDocument->appendChild($xmlCoverage);
  37. $xmlProject = $xmlDocument->createElement('project');
  38. $xmlProject->setAttribute('timestamp', $time);
  39. if (is_string($name)) {
  40. $xmlProject->setAttribute('name', $name);
  41. }
  42. $xmlCoverage->appendChild($xmlProject);
  43. $packages = [];
  44. $report = $coverage->getReport();
  45. foreach ($report as $item) {
  46. if (!$item instanceof File) {
  47. continue;
  48. }
  49. /* @var File $item */
  50. $xmlFile = $xmlDocument->createElement('file');
  51. $xmlFile->setAttribute('name', $item->pathAsString());
  52. $classes = $item->classesAndTraits();
  53. $coverageData = $item->lineCoverageData();
  54. $lines = [];
  55. $namespace = 'global';
  56. foreach ($classes as $className => $class) {
  57. $classStatements = 0;
  58. $coveredClassStatements = 0;
  59. $coveredMethods = 0;
  60. $classMethods = 0;
  61. foreach ($class['methods'] as $methodName => $method) {
  62. if ($method['executableLines'] == 0) {
  63. continue;
  64. }
  65. $classMethods++;
  66. $classStatements += $method['executableLines'];
  67. $coveredClassStatements += $method['executedLines'];
  68. if ($method['coverage'] == 100) {
  69. $coveredMethods++;
  70. }
  71. $methodCount = 0;
  72. foreach (range($method['startLine'], $method['endLine']) as $line) {
  73. if (isset($coverageData[$line]) && ($coverageData[$line] !== null)) {
  74. $methodCount = max($methodCount, count($coverageData[$line]));
  75. }
  76. }
  77. $lines[$method['startLine']] = [
  78. 'ccn' => $method['ccn'],
  79. 'count' => $methodCount,
  80. 'crap' => $method['crap'],
  81. 'type' => 'method',
  82. 'visibility' => $method['visibility'],
  83. 'name' => $methodName,
  84. ];
  85. }
  86. if (!empty($class['package']['namespace'])) {
  87. $namespace = $class['package']['namespace'];
  88. }
  89. $xmlClass = $xmlDocument->createElement('class');
  90. $xmlClass->setAttribute('name', $className);
  91. $xmlClass->setAttribute('namespace', $namespace);
  92. if (!empty($class['package']['fullPackage'])) {
  93. $xmlClass->setAttribute(
  94. 'fullPackage',
  95. $class['package']['fullPackage']
  96. );
  97. }
  98. if (!empty($class['package']['category'])) {
  99. $xmlClass->setAttribute(
  100. 'category',
  101. $class['package']['category']
  102. );
  103. }
  104. if (!empty($class['package']['package'])) {
  105. $xmlClass->setAttribute(
  106. 'package',
  107. $class['package']['package']
  108. );
  109. }
  110. if (!empty($class['package']['subpackage'])) {
  111. $xmlClass->setAttribute(
  112. 'subpackage',
  113. $class['package']['subpackage']
  114. );
  115. }
  116. $xmlFile->appendChild($xmlClass);
  117. $xmlMetrics = $xmlDocument->createElement('metrics');
  118. $xmlMetrics->setAttribute('complexity', (string) $class['ccn']);
  119. $xmlMetrics->setAttribute('methods', (string) $classMethods);
  120. $xmlMetrics->setAttribute('coveredmethods', (string) $coveredMethods);
  121. $xmlMetrics->setAttribute('conditionals', (string) $class['executableBranches']);
  122. $xmlMetrics->setAttribute('coveredconditionals', (string) $class['executedBranches']);
  123. $xmlMetrics->setAttribute('statements', (string) $classStatements);
  124. $xmlMetrics->setAttribute('coveredstatements', (string) $coveredClassStatements);
  125. $xmlMetrics->setAttribute('elements', (string) ($classMethods + $classStatements + $class['executableBranches']));
  126. $xmlMetrics->setAttribute('coveredelements', (string) ($coveredMethods + $coveredClassStatements + $class['executedBranches']));
  127. $xmlClass->appendChild($xmlMetrics);
  128. }
  129. foreach ($coverageData as $line => $data) {
  130. if ($data === null || isset($lines[$line])) {
  131. continue;
  132. }
  133. $lines[$line] = [
  134. 'count' => count($data), 'type' => 'stmt',
  135. ];
  136. }
  137. ksort($lines);
  138. foreach ($lines as $line => $data) {
  139. $xmlLine = $xmlDocument->createElement('line');
  140. $xmlLine->setAttribute('num', (string) $line);
  141. $xmlLine->setAttribute('type', $data['type']);
  142. if (isset($data['name'])) {
  143. $xmlLine->setAttribute('name', $data['name']);
  144. }
  145. if (isset($data['visibility'])) {
  146. $xmlLine->setAttribute('visibility', $data['visibility']);
  147. }
  148. if (isset($data['ccn'])) {
  149. $xmlLine->setAttribute('complexity', (string) $data['ccn']);
  150. }
  151. if (isset($data['crap'])) {
  152. $xmlLine->setAttribute('crap', (string) $data['crap']);
  153. }
  154. $xmlLine->setAttribute('count', (string) $data['count']);
  155. $xmlFile->appendChild($xmlLine);
  156. }
  157. $linesOfCode = $item->linesOfCode();
  158. $xmlMetrics = $xmlDocument->createElement('metrics');
  159. $xmlMetrics->setAttribute('loc', (string) $linesOfCode->linesOfCode());
  160. $xmlMetrics->setAttribute('ncloc', (string) $linesOfCode->nonCommentLinesOfCode());
  161. $xmlMetrics->setAttribute('classes', (string) $item->numberOfClassesAndTraits());
  162. $xmlMetrics->setAttribute('methods', (string) $item->numberOfMethods());
  163. $xmlMetrics->setAttribute('coveredmethods', (string) $item->numberOfTestedMethods());
  164. $xmlMetrics->setAttribute('conditionals', (string) $item->numberOfExecutableBranches());
  165. $xmlMetrics->setAttribute('coveredconditionals', (string) $item->numberOfExecutedBranches());
  166. $xmlMetrics->setAttribute('statements', (string) $item->numberOfExecutableLines());
  167. $xmlMetrics->setAttribute('coveredstatements', (string) $item->numberOfExecutedLines());
  168. $xmlMetrics->setAttribute('elements', (string) ($item->numberOfMethods() + $item->numberOfExecutableLines() + $item->numberOfExecutableBranches()));
  169. $xmlMetrics->setAttribute('coveredelements', (string) ($item->numberOfTestedMethods() + $item->numberOfExecutedLines() + $item->numberOfExecutedBranches()));
  170. $xmlFile->appendChild($xmlMetrics);
  171. if ($namespace === 'global') {
  172. $xmlProject->appendChild($xmlFile);
  173. } else {
  174. if (!isset($packages[$namespace])) {
  175. $packages[$namespace] = $xmlDocument->createElement(
  176. 'package'
  177. );
  178. $packages[$namespace]->setAttribute('name', $namespace);
  179. $xmlProject->appendChild($packages[$namespace]);
  180. }
  181. $packages[$namespace]->appendChild($xmlFile);
  182. }
  183. }
  184. $linesOfCode = $report->linesOfCode();
  185. $xmlMetrics = $xmlDocument->createElement('metrics');
  186. $xmlMetrics->setAttribute('files', (string) count($report));
  187. $xmlMetrics->setAttribute('loc', (string) $linesOfCode->linesOfCode());
  188. $xmlMetrics->setAttribute('ncloc', (string) $linesOfCode->nonCommentLinesOfCode());
  189. $xmlMetrics->setAttribute('classes', (string) $report->numberOfClassesAndTraits());
  190. $xmlMetrics->setAttribute('methods', (string) $report->numberOfMethods());
  191. $xmlMetrics->setAttribute('coveredmethods', (string) $report->numberOfTestedMethods());
  192. $xmlMetrics->setAttribute('conditionals', (string) $report->numberOfExecutableBranches());
  193. $xmlMetrics->setAttribute('coveredconditionals', (string) $report->numberOfExecutedBranches());
  194. $xmlMetrics->setAttribute('statements', (string) $report->numberOfExecutableLines());
  195. $xmlMetrics->setAttribute('coveredstatements', (string) $report->numberOfExecutedLines());
  196. $xmlMetrics->setAttribute('elements', (string) ($report->numberOfMethods() + $report->numberOfExecutableLines() + $report->numberOfExecutableBranches()));
  197. $xmlMetrics->setAttribute('coveredelements', (string) ($report->numberOfTestedMethods() + $report->numberOfExecutedLines() + $report->numberOfExecutedBranches()));
  198. $xmlProject->appendChild($xmlMetrics);
  199. $buffer = $xmlDocument->saveXML();
  200. if ($target !== null) {
  201. Directory::create(dirname($target));
  202. if (@file_put_contents($target, $buffer) === false) {
  203. throw new WriteOperationFailedException($target);
  204. }
  205. }
  206. return $buffer;
  207. }
  208. }