1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-09 14:38:37 +01:00
psalm/src/Psalm/Report/JunitReport.php

176 lines
4.9 KiB
PHP
Raw Normal View History

<?php
namespace Psalm\Report;
2020-03-07 03:46:29 +01:00
use ArrayObject;
use DOMDocument;
use DOMElement;
use Psalm\Config;
use Psalm\Report;
2020-03-07 03:46:29 +01:00
use Psalm\Internal\Analyzer\IssueData;
use function count;
use function trim;
/**
* based on https://github.com/m50/psalm-json-to-junit
* Copyright (c) Marisa Clardy marisa@clardy.eu
*
* with a few modifications
*/
class JunitReport extends Report
{
/**
* {@inheritdoc}
*/
public function create(): string
{
$errors = 0;
$warnings = 0;
$tests = 0;
$ndata = [];
foreach ($this->issues_data as $error) {
2020-02-17 00:24:40 +01:00
$is_error = $error->severity === Config::REPORT_ERROR;
$is_warning = $error->severity === Config::REPORT_INFO;
if ($is_error) {
$errors++;
} elseif ($is_warning) {
$warnings++;
} else {
// currently this never happens
continue;
}
$tests++;
2020-02-17 00:24:40 +01:00
$fname = $error->file_name;
if (!isset($ndata[$fname])) {
$ndata[$fname] = [
'errors' => $is_error ? 1 : 0,
'warnings' => $is_warning ? 1 : 0,
2020-03-07 03:46:29 +01:00
'failures' => [],
];
} else {
if ($is_error) {
$ndata[$fname]['errors']++;
} else {
$ndata[$fname]['warnings']++;
}
2020-03-07 03:46:29 +01:00
}
2020-03-07 03:46:29 +01:00
if ($is_error || ($this->show_info && $is_warning)) {
$ndata[$fname]['failures'][] = $error;
}
}
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$schema = 'https://raw.githubusercontent.com/junit-team/'.
'junit5/r5.5.1/platform-tests/src/test/resources/jenkins-junit.xsd';
$suites = $dom->createElement('testsuites');
2020-03-05 05:05:11 +01:00
$suites->setAttribute('failures', (string) $errors);
$suites->setAttribute('errors', '0');
2020-03-05 05:05:11 +01:00
$suites->setAttribute('name', 'psalm');
$suites->setAttribute('tests', (string) $tests);
$suites->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$suites->setAttribute('xsi:noNamespaceSchemaLocation', $schema);
$dom->appendChild($suites);
if (!count($ndata)) {
$testcase = $dom->createElement('testcase');
$testcase->setAttribute('name', 'psalm');
2020-03-05 05:05:11 +01:00
$suites->appendChild($testcase);
} else {
foreach ($ndata as $file => $report) {
2020-03-05 05:05:11 +01:00
$this->createTestSuite($dom, $suites, $file, $report);
}
}
return $dom->saveXML();
}
/**
* @param array{
* errors: int,
* warnings: int,
2020-03-07 03:46:29 +01:00
* failures: list<IssueData>
* } $report
*/
private function createTestSuite(DOMDocument $dom, DOMElement $parent, string $file, array $report): void
{
$totalTests = $report['errors'] + $report['warnings'];
if ($totalTests < 1) {
$totalTests = 1;
}
$testsuite = $dom->createElement('testsuite');
$testsuite->setAttribute('name', $file);
2020-03-07 03:46:29 +01:00
$testsuite->setAttribute('tests', (string) $totalTests);
$testsuite->setAttribute('failures', (string) $report['errors']);
$testsuite->setAttribute('errors', '0');
$failuresByType = $this->groupByType($report['failures']);
foreach ($failuresByType as $type => $data) {
foreach ($data as $d) {
$testcase = $dom->createElement('testcase');
2020-03-07 03:46:29 +01:00
$testcase->setAttribute('name', "{$file}:{$d->line_from}");
$testcase->setAttribute('classname', $type);
$testcase->setAttribute('assertions', (string) count($data));
$failure = $dom->createElement('failure');
$failure->setAttribute('type', $type);
$failure->nodeValue = $this->dataToOutput($d);
$testcase->appendChild($failure);
$testsuite->appendChild($testcase);
}
}
$parent->appendChild($testsuite);
}
/**
2020-03-07 03:46:29 +01:00
* @param list<IssueData> $failures
*
2020-03-07 03:46:29 +01:00
* @return array<string, list<IssueData>>
*/
private function groupByType(array $failures)
{
$nfailures = [];
foreach ($failures as $failure) {
2020-03-07 03:46:29 +01:00
$nfailures[$failure->type][] = $failure;
}
return $nfailures;
}
/**
2020-03-07 03:46:29 +01:00
* @param IssueData $data
*/
2020-03-07 03:46:29 +01:00
private function dataToOutput(IssueData $data): string
{
$ret = '';
2020-03-07 03:46:29 +01:00
if ($this->show_snippet) {
$ret = "snippet: {$data->snippet}\n";
}
2020-03-07 03:46:29 +01:00
$ret .= <<<SNIPPET
message : {$data->message}
type : {$data->type}
selected_text : {$data->selected_text}
line : {$data->line_from}
column_from : {$data->column_from}
column_to : {$data->column_to}
SNIPPET;
return $ret;
}
}