JunitReporter.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. namespace PhpCsFixer\Console\Report\FixReport;
  13. use PhpCsFixer\Console\Application;
  14. use PhpCsFixer\Preg;
  15. use Symfony\Component\Console\Formatter\OutputFormatter;
  16. /**
  17. * @author Boris Gorbylev <ekho@ekho.name>
  18. *
  19. * @internal
  20. */
  21. final class JunitReporter implements ReporterInterface
  22. {
  23. public function getFormat(): string
  24. {
  25. return 'junit';
  26. }
  27. public function generate(ReportSummary $reportSummary): string
  28. {
  29. if (!\extension_loaded('dom')) {
  30. throw new \RuntimeException('Cannot generate report! `ext-dom` is not available!');
  31. }
  32. $dom = new \DOMDocument('1.0', 'UTF-8');
  33. $testsuites = $dom->appendChild($dom->createElement('testsuites'));
  34. /** @var \DOMElement $testsuite */
  35. $testsuite = $testsuites->appendChild($dom->createElement('testsuite'));
  36. $testsuite->setAttribute('name', 'PHP CS Fixer');
  37. $properties = $dom->createElement('properties');
  38. $property = $dom->createElement('property');
  39. $property->setAttribute('name', 'about');
  40. $property->setAttribute('value', Application::getAbout());
  41. $properties->appendChild($property);
  42. $testsuite->appendChild($properties);
  43. if (\count($reportSummary->getChanged()) > 0) {
  44. $this->createFailedTestCases($dom, $testsuite, $reportSummary);
  45. } else {
  46. $this->createSuccessTestCase($dom, $testsuite);
  47. }
  48. if ($reportSummary->getTime() > 0) {
  49. $testsuite->setAttribute(
  50. 'time',
  51. sprintf(
  52. '%.3f',
  53. $reportSummary->getTime() / 1_000
  54. )
  55. );
  56. }
  57. $dom->formatOutput = true;
  58. return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($dom->saveXML()) : $dom->saveXML();
  59. }
  60. private function createSuccessTestCase(\DOMDocument $dom, \DOMElement $testsuite): void
  61. {
  62. $testcase = $dom->createElement('testcase');
  63. $testcase->setAttribute('name', 'All OK');
  64. $testcase->setAttribute('assertions', '1');
  65. $testsuite->appendChild($testcase);
  66. $testsuite->setAttribute('tests', '1');
  67. $testsuite->setAttribute('assertions', '1');
  68. $testsuite->setAttribute('failures', '0');
  69. $testsuite->setAttribute('errors', '0');
  70. }
  71. private function createFailedTestCases(\DOMDocument $dom, \DOMElement $testsuite, ReportSummary $reportSummary): void
  72. {
  73. $assertionsCount = 0;
  74. foreach ($reportSummary->getChanged() as $file => $fixResult) {
  75. $testcase = $this->createFailedTestCase(
  76. $dom,
  77. $file,
  78. $fixResult,
  79. $reportSummary->shouldAddAppliedFixers()
  80. );
  81. $testsuite->appendChild($testcase);
  82. $assertionsCount += (int) $testcase->getAttribute('assertions');
  83. }
  84. $testsuite->setAttribute('tests', (string) \count($reportSummary->getChanged()));
  85. $testsuite->setAttribute('assertions', (string) $assertionsCount);
  86. $testsuite->setAttribute('failures', (string) $assertionsCount);
  87. $testsuite->setAttribute('errors', '0');
  88. }
  89. /**
  90. * @param array{appliedFixers: list<string>, diff: string} $fixResult
  91. */
  92. private function createFailedTestCase(\DOMDocument $dom, string $file, array $fixResult, bool $shouldAddAppliedFixers): \DOMElement
  93. {
  94. $appliedFixersCount = \count($fixResult['appliedFixers']);
  95. $testName = str_replace('.', '_DOT_', Preg::replace('@\.'.pathinfo($file, PATHINFO_EXTENSION).'$@', '', $file));
  96. $testcase = $dom->createElement('testcase');
  97. $testcase->setAttribute('name', $testName);
  98. $testcase->setAttribute('file', $file);
  99. $testcase->setAttribute('assertions', (string) $appliedFixersCount);
  100. $failure = $dom->createElement('failure');
  101. $failure->setAttribute('type', 'code_style');
  102. $testcase->appendChild($failure);
  103. if ($shouldAddAppliedFixers) {
  104. $failureContent = "applied fixers:\n---------------\n";
  105. foreach ($fixResult['appliedFixers'] as $appliedFixer) {
  106. $failureContent .= "* {$appliedFixer}\n";
  107. }
  108. } else {
  109. $failureContent = "Wrong code style\n";
  110. }
  111. if ('' !== $fixResult['diff']) {
  112. $failureContent .= "\nDiff:\n---------------\n\n".$fixResult['diff'];
  113. }
  114. $failure->appendChild($dom->createCDATASection(trim($failureContent)));
  115. return $testcase;
  116. }
  117. }