prepare for several types of phpunit results

This commit is contained in:
SimonHeimberg 2017-07-15 02:18:07 +02:00 committed by Dmitry Khomutov
parent a77b1115a0
commit c3c103cc78
No known key found for this signature in database
GPG key ID: 7EB36C9576F9ECB9
4 changed files with 185 additions and 153 deletions

View file

@ -7,7 +7,7 @@ use PHPCensor\Builder;
use PHPCensor\Model\Build;
use PHPCensor\Model\BuildError;
use PHPCensor\Plugin\Option\PhpUnitOptions;
use PHPCensor\Plugin\Util\PhpUnitResult;
use PHPCensor\Plugin\Util\PhpUnitResultJson;
use PHPCensor\Plugin;
use PHPCensor\ZeroConfigPluginInterface;
@ -112,8 +112,8 @@ class PhpUnit extends Plugin implements ZeroConfigPluginInterface
$buildPath = $this->build->getBuildPath() . DIRECTORY_SEPARATOR;
// Save the results into a json file
$jsonFile = @tempnam($buildPath, 'jLog_');
$options->addArgument('log-json', $jsonFile);
$logFile = @tempnam($buildPath, 'jLog_');
$options->addArgument('log-json', $logFile);
// Removes any current configurations files
$options->removeArgument('configuration');
@ -126,7 +126,7 @@ class PhpUnit extends Plugin implements ZeroConfigPluginInterface
$cmd = $this->findBinary('phpunit') . ' %s %s';
$success = $this->builder->executeCommand($cmd, $arguments, $directory);
$this->processResults($jsonFile);
$this->processResults($logFile);
return $success;
}
@ -141,7 +141,7 @@ class PhpUnit extends Plugin implements ZeroConfigPluginInterface
protected function processResults($jsonFile)
{
if (file_exists($jsonFile)) {
$parser = new PhpUnitResult($jsonFile, $this->build->getBuildPath());
$parser = new PhpUnitResultJson($logFile, $this->build->getBuildPath());
$this->build->storeMeta('phpunit-data', $parser->parse()->getResults());
$this->build->storeMeta('phpunit-errors', $parser->getFailures());
@ -152,9 +152,9 @@ class PhpUnit extends Plugin implements ZeroConfigPluginInterface
$this->builder, 'php_unit', $error['message'], $severity, $error['file'], $error['line']
);
}
@unlink($jsonFile);
@unlink($logFile);
} else {
throw new \Exception('JSON output file does not exist: ' . $jsonFile);
throw new \Exception('log output file does not exist: ' . $logFile);
}
}
}

View file

@ -7,19 +7,15 @@ namespace PHPCensor\Plugin\Util;
*
* @author Pablo Tejada <pablo@ptejada.com>
*/
class PhpUnitResult
abstract class PhpUnitResult
{
const EVENT_TEST = 'test';
const EVENT_TEST_START = 'testStart';
const EVENT_SUITE_START = 'suiteStart';
const SEVERITY_PASS = 'success';
const SEVERITY_FAIL = 'fail';
const SEVERITY_ERROR = 'error';
const SEVERITY_SKIPPED = 'skipped';
protected $options;
protected $arguments = [];
protected $outputFile;
protected $buildPath;
protected $results;
protected $failures = 0;
protected $errors = [];
@ -36,158 +32,48 @@ class PhpUnitResult
* @return $this
* @throws \Exception If fails to parse the output
*/
public function parse()
abstract public function parse();
abstract protected function getSeverity($testcase);
abstract protected function buildMessage($testcase);
abstract protected function buildTrace($testcase);
protected function getFileAndLine($testcase)
{
$rawResults = file_get_contents($this->outputFile);
$events = [];
if ($rawResults && $rawResults[0] == '{') {
$fixedJson = '[' . str_replace('}{', '},{', $rawResults) . ']';
$events = json_decode($fixedJson, true);
} elseif ($rawResults) {
$events = json_decode($rawResults, true);
}
// Reset the parsing variables
$this->results = [];
$this->errors = [];
$this->failures = 0;
if ($events) {
foreach ($events as $event) {
if (isset($event['event']) && $event['event'] == self::EVENT_TEST) {
$this->results[] = $this->parseEvent($event);
}
}
}
return $this;
return $testcase;
}
/**
* Parse a test event
*
* @param array $event
*
* @return string[]
*/
protected function parseEvent($event)
protected function getOutput($testcase)
{
list($pass, $severity) = $this->getStatus($event);
return $testcase['output'];
}
protected function parseTestcase($testcase)
{
$severity = $this->getSeverity($testcase);
$pass = isset(array_fill_keys([self::SEVERITY_PASS, self::SEVERITY_SKIPPED], true)[$severity]);
$data = [
'pass' => $pass,
'severity' => $severity,
'message' => $this->buildMessage($event),
'trace' => $pass ? [] : $this->buildTrace($event),
'output' => $event['output'],
'message' => $this->buildMessage($testcase),
'trace' => $pass ? [] : $this->buildTrace($testcase),
'output' => $this->getOutput($testcase),
];
if (!$pass) {
$this->failures++;
$this->addError($data, $event);
$info = $this->getFileAndLine($testcase);
$this->errors[] = [
'message' => $data['message'],
'severity' => $severity,
'file' => $info['file'],
'line' => $info['line'],
];
}
return $data;
}
/**
* Build the status of the event
*
* @param $event
*
* @return mixed[bool,string] - The pass and severity flags
* @throws \Exception
*/
protected function getStatus($event)
{
$status = $event['status'];
switch ($status) {
case 'fail':
$pass = false;
$severity = self::SEVERITY_FAIL;
break;
case 'error':
if (strpos($event['message'], 'Skipped') === 0 || strpos($event['message'], 'Incomplete') === 0) {
$pass = true;
$severity = self::SEVERITY_SKIPPED;
} else {
$pass = false;
$severity = self::SEVERITY_ERROR;
}
break;
case 'pass':
$pass = true;
$severity = self::SEVERITY_PASS;
break;
case 'warning':
$pass = true;
$severity = self::SEVERITY_PASS;
break;
default:
throw new \Exception("Unexpected PHPUnit test status: {$status}");
break;
}
return [$pass, $severity];
}
/**
* Build the message string for an event
*
* @param array $event
*
* @return string
*/
protected function buildMessage($event)
{
$message = $event['test'];
if ($event['message']) {
$message .= PHP_EOL . $event ['message'];
}
return $message;
}
/**
* Build a string base trace of the failure
*
* @param array $event
*
* @return string[]
*/
protected function buildTrace($event)
{
$formattedTrace = [];
if (!empty($event['trace'])) {
foreach ($event['trace'] as $step){
$line = str_replace($this->buildPath, '', $step['file']) . ':' . $step['line'];
$formattedTrace[] = $line;
}
}
return $formattedTrace;
}
/**
* Saves additional info for a failing test
*
* @param array $data
* @param array $event
*/
protected function addError($data, $event)
{
$firstTrace = end($event['trace']);
reset($event['trace']);
$this->errors[] = [
'message' => $data['message'],
'severity' => $data['severity'],
'file' => str_replace($this->buildPath, '', $firstTrace['file']),
'line' => $firstTrace['line'],
];
$this->results[] = $data;
}
/**

View file

@ -0,0 +1,145 @@
<?php
namespace PHPCensor\Plugin\Util;
/**
* Class PhpUnitResult parses the results for the PhpUnitV2 plugin
*
* @author Pablo Tejada <pablo@ptejada.com>
*/
class PhpUnitResultJson extends PhpUnitResult
{
const EVENT_TEST = 'test';
const EVENT_TEST_START = 'testStart';
const EVENT_SUITE_START = 'suiteStart';
protected $options;
protected $arguments = [];
/**
* Parse the results
*
* @return $this
* @throws \Exception If fails to parse the output
*/
public function parse()
{
$rawResults = file_get_contents($this->outputFile);
$events = [];
if ($rawResults && $rawResults[0] == '{') {
$fixedJson = '[' . str_replace('}{', '},{', $rawResults) . ']';
$events = json_decode($fixedJson, true);
} elseif ($rawResults) {
$events = json_decode($rawResults, true);
}
// Reset the parsing variables
$this->results = [];
$this->errors = [];
$this->failures = 0;
if ($events) {
foreach ($events as $event) {
if (isset($event['event']) && $event['event'] == self::EVENT_TEST) {
$this->parseTestcase($event);
}
}
}
return $this;
}
/**
* Build the severity of the event
*
* @param $event
*
* @return string The severity flags
* @throws \Exception
*/
protected function getSeverity($event)
{
$status = $event['status'];
switch ($status) {
case 'fail':
$severity = self::SEVERITY_FAIL;
break;
case 'error':
if (strpos($event['message'], 'Skipped') === 0 || strpos($event['message'], 'Incomplete') === 0) {
$severity = self::SEVERITY_SKIPPED;
} else {
$severity = self::SEVERITY_ERROR;
}
break;
case 'pass':
$severity = self::SEVERITY_PASS;
break;
case 'warning':
$severity = self::SEVERITY_PASS;
break;
default:
throw new \Exception("Unexpected PHPUnit test status: {$status}");
break;
}
return $severity;
}
/**
* Build the message string for an event
*
* @param array $event
*
* @return string
*/
protected function buildMessage($event)
{
$message = $event['test'];
if ($event['message']) {
$message .= PHP_EOL . $event ['message'];
}
return $message;
}
/**
* Build a string base trace of the failure
*
* @param array $event
*
* @return string[]
*/
protected function buildTrace($event)
{
$formattedTrace = [];
if (!empty($event['trace'])) {
foreach ($event['trace'] as $step){
$line = str_replace($this->buildPath, '', $step['file']) . ':' . $step['line'];
$formattedTrace[] = $line;
}
}
return $formattedTrace;
}
/**
* Saves additional info for a failing test
*
* @param array $data
* @param array $event
*/
protected function getFileAndLine($event)
{
$firstTrace = end($event['trace']);
reset($event['trace']);
return [
'file' => str_replace($this->buildPath, '', $firstTrace['file']),
'line' => $firstTrace['line']
];
}
}

View file

@ -3,6 +3,7 @@
namespace Tests\PHPCensor\Plugin\Util;
use PHPCensor\Plugin\Util\PhpUnitResult;
use PHPCensor\Plugin\Util\PhpUnitResultJson;
/**
* Class PhpUnitResultTest parses the results for the PhpUnitV2 plugin
@ -16,7 +17,7 @@ class PhpUnitResultTest extends \PHPUnit_Framework_TestCase
public function testInitParse()
{
$buildPath = '/path/to/build';
$parser = new PhpUnitResult(ROOT_DIR . 'tests/PHPCensor/Plugin/SampleFiles/phpunit_money.txt', $buildPath);
$parser = new PhpUnitResultJson(ROOT_DIR . 'tests/PHPCensor/Plugin/SampleFiles/phpunit_money.txt', $buildPath);
$output = $parser->parse()->getResults();
$errors = $parser->getErrors();